MP4ファイルを連結する。

2つあるいは3つのMP4ファイルを連結する必要が出てきました。たとえばビデオカメラで撮影した2本の動画だったり、ごにょごにょだったり、もにょもにょだったりしますが。


テキストファイルなどなら、コマンドプロンプトからcopy a.txt+b.txt c.txtでできますが、MP4ファイルの場合にはコンテナの中にビデオストリームとオーディオストリームが格納されていて、撮影情報とかメモとかいろんなタグが含まれていて、そのまま連結してもうまくいきません。

ビデオ編集には、PegasysのTMPGEnc MPEG Smart Renderer5(6にするメリットが今のところないので)を使っていますが、これで連結出力すると連結部分があまり良くない画質で再エンコードされてしまいます。いろいろとオプションなどを見てみたのですが、再エンコードせずに連結することはできないようです。
AviutlでMP4Pluginを使用すると、追加ファイルを読み込んだ上でMP4エクスポートすればいい、という記事も見つかりましたが、連結部分で止まってしまい、うまくいきませんでした。

ああ、そういえばffmpegをインストールしてたんだっけ、と、困ったときのffmpeg頼りで調べてみたら、できる方法がありました。
ffmpegのWikiよりConcatenate。 簡単に言えば二通りの方法があります。

リストファイルを作って作業する

連結したいMP4ファイルのリストを作成して、それをffmpegに処理させます。

以下のようなファイルを作ります。
file dir/input1.mp4
file dir/input2.mp4
file dir/input3.mp4
その上で、以下のコマンドで連結します。
ffmpeg -f concat -c copy -i listfile.lst outfile.mp4
もしもファイル名にスペースを含むようなら、''(シングルクォーテーション)でくくります。""(ダブルクォーテーション)ではエラーになります。

この方法では、中間ファイルを作らずに直接出力ファイルを作りますが、リストファイルを作成する手間がかかります。

中間ファイルを経由してmuxする

連結したいMP4ファイルからストリームを抜き出して、それを連結して新しいコンテナに収めます。

この方法では、エンコーダが異なったりFPSが異なったりフレームサイズが異なった場合には、取り出したストリームをエンコードし直すことで連結できる可能性があります。

ストリームがH264ビデオストリームの場合:
ffmpeg -i input1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts input1.ts
ffmpeg -i input2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts input2.ts
ffmpeg -i "concat:input1.ts|input2.ts" -c copy -bsf:a aac_adtstoasc output.mp4
上の2行のコマンドでそれぞれH264ストリームを抜き出して input1.ts、input2.ts という中間ファイルを作成します。

ストリームがHEVC(H265)の場合:
ffmpeg -i input1.mp4 -c copy -bsf:v hevc_mp4toannexb -f mpegts input1.ts
ffmpeg -i input2.mp4 -c copy -bsf:v hevc_mp4toannexb -f mpegts input2.ts
ffmpeg -i "concat:input1.ts|input2.ts" -c copy -bsf:a aac_adtstoasc output.mp4
コーデックが異なったりする場合には再エンコードが必要になるので、その分時間がかかりますが、詳細はこちらに。 ちなみにうちで使用しているffmpegはこちらからダウンロードしています。

Vimの補完プラグインをインストール。その4

Vimの補完プラグインをインストール。その3 で、 ddc-tabnine が使えそうです、などと書いたのですが、早速やってみました。 まず、tabnineのバイナリを用意しないといけません。がどうにもTabNineのサイトがわかりにくいので、 tabnine-nvim にあるダ...