mkvmergeでHEVC(H.265)の録画ファイルを結合する

DTV・ffmpegffmpeg,エンコード,mkvmerge

 

これまで、ffmpegでH264(HEVCではない)のファイルを結合していたのだが、エンコードにHEVC(H265)を用いるようになってから、この結合がうまくいかなくなってしまった。具体的には、シークバーが固まってしまい、ファイルの切れ目で映像が止まってしまうのである。どうも動作がうまくいかないため、ffmpegで行っていたファイルの結合を、mkvmergeで置き換えることにした。

mkvmergeのファイル結合オプション

mkvmergeでは、ファイルの結合は次のコマンドで行うことが出来る。

mkvmerge-ofull.mkvfile1.mkv + file2.mkv

outputファイルは-oで指定をし、その後に連結するファイルを+で結合してあげればOK。ということで、結合するファイルのリストを作成し、これらを全て+で指定してあげれば良い。

(なお、このオプション以外に、連番のファイルを自動的に認識し連結するオプションも存在しているのだが、当方の環境ではうまく動作しなかった)

mkvmergeでファイルを結合する

例えば、tmp.*.mkvというファイルが次のような形で存在したとする。

$ ls -a tmp.*.mkv
tmp.0.mkv  tmp.1.mkv  tmp.2.mkv

このファイルを連結する場合、mkvmerge -o output.mkv tmp.0.mkv + tmp.1.mkv + tmp.2.mkvとしてあげれば問題ない。

$ mkvmerge -o output.mkv tmp.0.mkv + tmp.1.mkv + tmp.2.mkv
mkvmerge v22.0.0 ('At The End Of The World') 64-bit
'tmp.0.mkv':フォーマット'Matroska'のデマルチプレクサを使用しています。
'tmp.1.mkv':フォーマット'Matroska'のデマルチプレクサを使用しています。
'tmp.2.mkv':フォーマット'Matroska'のデマルチプレクサを使用しています。
'tmp.0.mkv'トラック0:フォーマット'HEVC/h.265'の出力モジュールを使用しています。
'tmp.0.mkv'トラック1:フォーマット'AAC'の出力モジュールを使用しています。
'tmp.0.mkv'トラック2:フォーマット'AAC'の出力モジュールを使用しています。
'tmp.0.mkv'トラック3:フォーマット'テキスト字幕'の出力モジュールを使用しています。
'tmp.1.mkv'トラック0:フォーマット'HEVC/h.265'の出力モジュールを使用しています。
'tmp.1.mkv'トラック1:フォーマット'AAC'の出力モジュールを使用しています。
'tmp.1.mkv'トラック2:フォーマット'AAC'の出力モジュールを使用しています。
'tmp.1.mkv'トラック3:フォーマット'テキスト字幕'の出力モジュールを使用しています。
'tmp.2.mkv'トラック0:フォーマット'HEVC/h.265'の出力モジュールを使用しています。
'tmp.2.mkv'トラック1:フォーマット'AAC'の出力モジュールを使用しています。
'tmp.2.mkv'トラック2:フォーマット'AAC'の出力モジュールを使用しています。
'tmp.2.mkv'トラック3:フォーマット'テキスト字幕'の出力モジュールを使用しています。
ファイル番号1のファイル('tmp.1.mkv')に追加結合のマッピングが指定されていません。デフォルトのマッピング1:0:0:0,1:1:0:1,1:2:0:2,1:3:0:3が代わりに使用されます。もしmkvmergeが無効な'--append-to'オプションに関するエラーメッセージを出して中断した場合はこのことを覚えておいてください。
ファイル番号2のファイル('tmp.2.mkv')に追加結合のマッピングが指定されていません。デフォルトのマッピング2:0:1:0,2:1:1:1,2:2:1:2,2:3:1:3が代わりに使用されます。もしmkvmergeが無効な'--append-to'オプションに関するエラーメッセージを出して中断した場合はこのことを覚えておいてください。
ファイル'output.mkv'を開いて書き込んでいます。
ファイル番号1('tmp.1.mkv')のトラック3を、ファイル番号0('tmp.0.mkv')のトラック3に追加しています。
ファイル番号1('tmp.1.mkv')のトラック1を、ファイル番号0('tmp.0.mkv')のトラック1に追加しています。
ファイル番号1('tmp.1.mkv')のトラック2を、ファイル番号0('tmp.0.mkv')のトラック2に追加しています。
ファイル番号1('tmp.1.mkv')のトラック0を、ファイル番号0('tmp.0.mkv')のトラック0に追加しています。
ファイル番号2('tmp.2.mkv')のトラック3を、ファイル番号1('tmp.1.mkv')のトラック3に追加しています。
ファイル番号2('tmp.2.mkv')のトラック2を、ファイル番号1('tmp.1.mkv')のトラック2に追加しています。
ファイル番号2('tmp.2.mkv')のトラック1を、ファイル番号1('tmp.1.mkv')のトラック1に追加しています。
ファイル番号2('tmp.2.mkv')のトラック0を、ファイル番号1('tmp.1.mkv')のトラック0に追加しています。
進行状況: 100%
キューエントリ(インデックス)が書き込まれています...
Multiplexing took 1秒.

こんな形で結合をすることが出来た。

シェルスクリプトで自動化する

同じディレクトリ内にあるtmp.*.mkvを探し、それらを連番に連結していく場合、こんな形でシェルスクリプトを記述することができる。もっとスマートな書き方もあるのだろうけれど……。

MKVFILES=($(ls -1 tmp.*.mkv))
CONCAT_MKVFILES=$(IFS='+'; shift; echo "${MKVFILES[*]}")
MKVLIST=`echo ${CONCAT_MKVFILES} | sed -e "s/+/ + /g"`
mkvmerge -o "${TEMPDIR}/mkvfull.mkv" ${MKVLIST}

Posted by webnetforce