Ubuntu Linuxでtsファイルをffmpegでmp4に変換する際にmov_text字幕ファイルをsrt形式で埋め込む方法(シェルスクリプトで自動化対応)
最近は字幕付きの放送も増えてきた。[字」と記載されている場合は字幕ファイルが放送波のなかに埋め込まれていて、これを抽出してmp4の中に入れ込むと、字幕の有無を選択するような形でmp4の内部に字幕ファイルを挿入することが出来る。
今回は、その方法を簡単に説明することとしたい。
使用するツール
- wine(使用するいくつかのツールはWineを用いて動作させる)
- TsSplitter
- Caption2AssC.exe
- ffmpeg
シェルスクリプト記載の留意点
以下で記載しているシェルスクリプトは、下記のような形でファイルを配置している。
- 放送生TS: /media/rec
- 各種ツール: /media/batch
- 処理時に用いるtempファイル: /media/temp
- 完成版の格納場所: /media/mp4
- 放送生TSの名称: ${BASENAME}
また、以下に関しては考慮していない。
- エラーハンドリング
- ログ出力
TsSplitterで分割する際に、必要な情報を残す
TsSplitterでワンセグやSD画質を消去しつつ、必要な情報を残すようにしてtsファイルを整形する。
下記の場合、 /media/recに録画済みの元データが入っており、分割済みファイルを/media/temp/splitted/の中に格納する 設定としている。
コマンドラインでの操作方法
こんな感じ。
$TsSplitter.exe -EIT -ECM -SD -1SEG -SEP2 -SEPA -OUT "出力先フォルダ" "元ファイル(放送生TS)"
シェルスクリプトでの記載方法
sudo -H /media/batch/TsSplitter.exe -EIT -ECM -SD -1SEG -SEP2 -SEPA -OUT "/media/temp/splitted/${BASENAME}" "/media/rec/${BASENAME}.m2ts"
これで、tempディレクトリのsplittedの内部に、TSSplitterが処理したファイルが格納される。
メインの動画を取得する
TsSplitteで分割したあとには、メインのファイル(本編)と余計なファイル(前後にあるCMなど)に分かれて出力される。これらのうち、本編動画を取得する。
コマンドラインでの操作方法
目視で確認が一番早い。
シェルスクリプトでの記載方法
最も容量が大きいファイルをメインのファイルとみなし、そのファイル名称を取得する。
SPLIT=`ls -S "/media/temp/splitted/${BASENAME}" | head -n 1`
これで、${SPLIT}に、メインのファイルの名称が格納される。
字幕ファイルの生成
下記よりCaption2AssCをダウンロードする。wineで動作可能。
コマンドラインでの操作方法
wine Caption2AssC.exe -format srt "[メイン(本編)のファイル]"
同じディレクトリ内に「メインのファイル名.m2ts.srt」が出力される。これが字幕ファイルだ。
シェルスクリプトでの記載方法
今回は/media/batch/caption内にCaption2AssCを配置した。また、Caption2AssCは日本語ファイルをうまく読み込めない時があるので、事前にメイン(本編)動画の名称を変更する。
mv "/media/temp/splitted/${BASENAME}/${SPLIT}" "/media/temp/base.m2ts" #ファイル移動
wine /media/batch/caption/Caption2AssC.exe -format srt "/media/temp/base.m2ts" #字幕生成
字幕は/media/temp内にbase.m2tssrtとして出力される。
ffmpegでエンコード&字幕の埋め込み
ffmpegを用いてエンコードを行う。 この際は字幕ファイルのことは考えず、単純にmp4ファイルを生成する点がポイント。
ffmpegのパラメータはお好きに。
コマンドラインでの操作方法
ffmpeg -y -vsync 1 -i [入力ファイル] -f mp4 -vcodec libx264 -map 0:a -map 0:v -fpre [プリセットファイル] -filter:v bwdif=0:-1:0 -s 1280x720 -aspect 16:9 -acodec ac3 -b:a 192k [出力ファイル]
シェルスクリプトでの記載方法
実は私はエンコードの進捗状況を確認するためにこの点のみ外部のPHPファイルを読み込む設定にしているのだが、シェルスクリプトで操作するならこんな感じだろう。
ffmpeg -y -vsync 1 -i /media/temp/base.m2ts -f mp4 -vcodec libx264 -map 0:a -map 0:v -fpre '/media/rec/batch/h264.ffpreset' -filter:v bwdif=0:-1:0 -s 1280x720 -aspect 16:9 -acodec ac3 -b:a 192k /media/temp/middle.mp4
中間ファイルがいくつもできてしまってうっとうしいが、まずはmp4ファイルが/media/temp/middle.mp4という名称で生成された。
字幕挿入
字幕の挿入もffmpegで実施する。なぜ上記のエンコードの際に一緒に行わないかというと、 二カ国語放送の際に字幕ファイルがうまく挿入されない ためである。従って、動画のエンコードと字幕の埋め込みは分割して実施する。
今回は、mapを使いまくることによってこれらを回避する。
コマンドラインでの記載方法
ffmpeg -i [先ほど出力したmp4] -i [字幕ファイル] -c:s mov_text -c:v copy -c:a copy -map 0:v -map 0:a -map 1:0 -metadata:s:s:0 language=jpn [出力ファイル]
シェルスクリプトでの記載方法
ffmpeg -i /media/temp/temp.mp4 -i "/media/temp/base.m2ts.srt" -c:s mov_text -c:v copy -c:a copy -map 0:v -map 0:a -map 1:0 -metadata:s:s:0 language=jpn "/media/mp4/${BASENAME}.mp4"
上記を実施することで、/media/mp4に字幕付きのmp4を生成することが出来た。
動作
VLCを例に出すと、「字幕」という欄で日本語字幕が選択出来るようになる。
実際に表示すると、次のような形で字幕が映像に出力される。
オマケ
Comskipで最初にvdrファイル(チャプタファイル)を生成し、これを使ってmp4ファイルのCMをカット、最後にffmpegでconcatを使うことで 字幕付きのCMカットファイル を作ることも可能。これは別途改めて紹介することとしたい。