■debian stretch+ffmpegで字幕ファイルsrt/assをなるべく簡単に作成してみる。
$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 9.1 (stretch)
Release: 9.1
Codename: stretch
■assよりもsrtの方が書きやすそうだと感じたので、srtをベースにする。
No行の単位で、表示文字について、
表示開始時間と表示終了時間を除くと以下で書ける。
サブリミナル効果のような感知出来ない文字は必要としていないので、
秒以下の単位はすべて「,000」で共通とする。
No
表示開始時間(HH:MM:SS,000) --> 表示終了時間(HH:MM:SS,000)
表示文字
<改行>
■srtの形式について
字幕ファイル (.srt) の書き方
http://d.hatena.ne.jp/uogiawi/20150319/1426738108
■assの形式について
ASSの仕組みと書き方
http://www.geocities.co.jp/bancodesrt/tool/ass.html
■変換に関してエディタを必要としないようにする。
なるべく簡単にという条件を満たすように、
等間隔時間の表示を前提条件としているので、
歌詞やコード、翻訳字幕の埋め込みなどには多くの修正が必要となる。
srtからassに変換する方式を方針として、なんとなく表示出来れば良いというレベルまで。
気になればそれに応じて修正するという方針で。(例えば改行コードはソースではなくsrtやassを編集して行う)
結果としてゼロから書くより、修正すれば良いというだけでやる気になったという点が大きい。
■ffmpegのバージョンは以下。
$ ffmpeg -version | sed -e 's/ --/\n\t&/g'
ffmpeg version 3.2.5-1 Copyright (c) 2000-2017 the FFmpeg developers
built with gcc 6.3.0 (Debian 6.3.0-18) 20170516
configuration:
--prefix=/usr
--extra-version=1
--toolchain=hardened
--libdir=/usr/lib/x86_64-linux-gnu
--incdir=/usr/include/x86_64-linux-gnu
--enable-gpl
--disable-stripping
--enable-avresample
--enable-avisynth
--enable-gnutls
--enable-ladspa
--enable-libass
--enable-libbluray
--enable-libbs2b
--enable-libcaca
--enable-libcdio
--enable-libebur128
--enable-libflite
--enable-libfontconfig
--enable-libfreetype
--enable-libfribidi
--enable-libgme
--enable-libgsm
--enable-libmp3lame
--enable-libopenjpeg
--enable-libopenmpt
--enable-libopus
--enable-libpulse
--enable-librubberband
--enable-libshine
--enable-libsnappy
--enable-libsoxr
--enable-libspeex
--enable-libssh
--enable-libtheora
--enable-libtwolame
--enable-libvorbis
--enable-libvpx
--enable-libwavpack
--enable-libwebp
--enable-libx265
--enable-libxvid
--enable-libzmq
--enable-libzvbi
--enable-omx
--enable-openal
--enable-opengl
--enable-sdl2
--enable-libdc1394
--enable-libiec61883
--enable-chromaprint
--enable-frei0r
--enable-libopencv
--enable-libx264
--enable-shared
libavutil 55. 34.101 / 55. 34.101
libavcodec 57. 64.101 / 57. 64.101
libavformat 57. 56.101 / 57. 56.101
libavdevice 57. 1.100 / 57. 1.100
libavfilter 6. 65.100 / 6. 65.100
libavresample 3. 1. 0 / 3. 1. 0
libswscale 4. 2.100 / 4. 2.100
libswresample 2. 3.100 / 2. 3.100
libpostproc 54. 1.100 / 54. 1.100
■動画の全体再生時間の取得
以下のうち「-show_entries」を使う。
再生時間=字幕表示時間とすると、平均8秒間隔で埋め込んでいけば良さそう。
$ ffprobe -hide_banner target.mp4 2>&1 | awk -F\. '/Duration/{gsub(",","",$2);print $2}'
00:06:17.90
$ ffprobe -hide_banner target.mp4 2>&1 | awk -F\. '/Duration/{gsub(" Duration: ","",$1);print $1}'
00:06:17
$ ffprobe -hide_banner -show_entries format=duration target.mp4 2>&1 | awk -F = '/duration/{print $2}'
377.903333
$ echo $(ffprobe -hide_banner -show_entries format=duration target.mp4 2>&1 | awk -F = '/duration/{print $2}') \
$(awk 'BEGIN{count=0}/./{count+=1}END{print count}' source.txt) | awk '{print $1/$2}'
8.78845
■マージ用ファイルを作成してsrtを出力、assに変換
ここでは単純にsrt形式が使用出来るかの確認を目的にしているが、
出来たassを編集しても良い。
$ t=$(ffprobe -hide_banner target.mp4 2>&1 | awk -F\. '/Duration/{gsub(" Duration: ","",$1);print $1}')
d="$(date +%F) $t"; \
alltime=$(ffprobe -hide_banner -show_entries format=duration target.mp4 2>&1 | awk -F = '/duration/{print $2}'); \
line=$(awk '/./{cnt+=1}END{print cnt}' source.txt); \
interval=$(echo $alltime $line | awk '{print $1/$2}'); \
for n in $(seq 1 $line);do \
echo $d;d=$(date '+%F %H:%M:%S' -d "$d $interval seconds ago"); \
done | sort -n | \
awk 'BEGIN{a="00:00:00"}($2!="00:00:00"){print a",000 --> "$2",000";a=$2}' | \
awk 'BEGIN{count=0}/./{count+=1;print count,$0}' > mergetime.txt
$ awk 'BEGIN{count=0}/./{count+=1;print count,$0}' source.txt > mergesource.txt
$ join -j 1 mergetime.txt mergesource.txt | \
sed -e 's/^\([0-9]*\) /\n\1\n/' -e 's/\(--> .*,000\) /\1\n/' | \
awk '(NR!=1){print}END{print ""}' > target.srt
$ ffmpeg -i target.srt output.ass 2>&1 | awk '!/built with|configuration/'
ffmpeg version 3.2.5-1 Copyright (c) 2000-2017 the FFmpeg developers
libavutil 55. 34.101 / 55. 34.101
libavcodec 57. 64.101 / 57. 64.101
libavformat 57. 56.101 / 57. 56.101
libavdevice 57. 1.100 / 57. 1.100
libavfilter 6. 65.100 / 6. 65.100
libavresample 3. 1. 0 / 3. 1. 0
libswscale 4. 2.100 / 4. 2.100
libswresample 2. 3.100 / 2. 3.100
libpostproc 54. 1.100 / 54. 1.100
Input
Duration: N/A, bitrate: N/A
Stream
■動画と字幕をマージする。
以下2つはsrt、assの変換。動画変換も行われるので特にassファイルの統合に時間がかかる。
3つ目は動画の変換は不要という場合はsrtなら以下で出来る。ただし、assではエラーになって字幕の無い動画が出来てしまう。
$ ffmpeg -i target.mp4 -vf subtitles=target.srt output.mp4
$ ffmpeg -i target.mp4 -vf ass=output.ass output_ass.mp4
$ ffmpeg -i target.mp4 -i target.srt -c copy -c:s mov_text output_cp.mp4
■assで作ってしまった人は以下でsrtに変換出来る。
$ ffmpeg -i output.ass output.srt 2>&1 | awk '!/built with|configuration/'
ffmpeg version 3.2.5-1 Copyright (c) 2000-2017 the FFmpeg developers
libavutil 55. 34.101 / 55. 34.101
libavcodec 57. 64.101 / 57. 64.101
libavformat 57. 56.101 / 57. 56.101
libavdevice 57. 1.100 / 57. 1.100
libavfilter 6. 65.100 / 6. 65.100
libavresample 3. 1. 0 / 3. 1. 0
libswscale 4. 2.100 / 4. 2.100
libswresample 2. 3.100 / 2. 3.100
libpostproc 54. 1.100 / 54. 1.100
Input
Duration: N/A, bitrate: N/A
Stream
Output
Metadata:
encoder : Lavf57.56.101
Stream
Metadata:
encoder : Lavc57.64.101 srt
Stream mapping:
Stream
Press [q] to stop, [?] for help
size= 3kB time=00:06:09.00 bitrate= 0.1kbits/s speed=6.65e+04x
video:0kB audio:0kB subtitle:2kB other streams:0kB global headers:0kB muxing overhead: 72.375420%
■3つ目の「output_cp.mp4」がすぐに出来て楽なので、後は動画を見ながらエディタ編集で調整する。
target.srtから表示開始や終了時間と、1行内の文字列の修正の両方を修正した。
$ test -f target.srt.org || cp target.{srt,srt.org};vlc output_cp.mp4 &
$ ffmpeg -i target.mp4 -i target.srt -c copy -c:s mov_text output_cp.mp4
■ハードサブ
「-c copy」では動画再生時にフォント読み込みが行われるので「-vf」オプションで行う。
このための処理に時間がかかってたのか。
$ ffmpeg -i target.srt output.ass 2>&1 | awk '!/built with|configuration/'
$ ffmpeg -i target.mp4 -vf ass=output.ass output_ass.mp4
...
[Parsed_ass_0 @ 0x5613be5abda0] fontselect: (Arial, 400, 0) -> /usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf, 0, LiberationSans
[Parsed_ass_0 @ 0x5613be5abda0] Glyph 0x30D4 not found, selecting one more font for (Arial, 400, 0)
[Parsed_ass_0 @ 0x5613be5abda0] fontselect: (Arial, 400, 0) -> /usr/share/fonts/truetype/vlgothic/VL-Gothic-Regular.ttf, 0, VL-Gothic-Regular
...
$ ffmpeg -i target.mp4 -vf subtitles=target.srt output.mp4
...
[Parsed_subtitles_0 @ 0x556737f2ada0] fontselect: (Arial, 400, 0) -> /usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf, 0, LiberationSans
[Parsed_subtitles_0 @ 0x556737f2ada0] Glyph 0x30D4 not found, selecting one more font for (Arial, 400, 0)
[Parsed_subtitles_0 @ 0x556737f2ada0] fontselect: (Arial, 400, 0) -> /usr/share/fonts/truetype/vlgothic/VL-Gothic-Regular.ttf, 0, VL-Gothic-Regular
...
■埋め込みフォントの分、元のファイルよりも大きくなる。
srtの追加だけなら微々たる変化。
srtとassにファイルサイズの違いは無い。
$ du *.mp4
53508 output.mp4
53508 output_ass.mp4
34236 output_cp.mp4
34068 target.mp4