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はこちらからダウンロードしています。

Windowsでシンボリックリンクを試してみる。

きっかけは、1つのファイルを別の名前で起動したら違う動きになるようなスクリプトを書く、でした。  busybox なんかでは、同じ実行形式ファイルの名前を、lsにすればlsと同じ、cpとすればcpと同じ動作をするようにしてますが、Pythonスクリプトでそれと同じように argv...