前提
- 再エンコードしない
- どのストリームも保持する(
-map 0
)
再エンコードなしでの動画の切り出しでは、P/Bフレームは前のフレームを必要とするので切り出しの開始はIフレーム、Bフレームは後のフレームを必要とするので切り出しの終了はI/Pフレームにする必要がある。
[謎] 2つにカットする場合、オープンGOPではどうやってもIフレームの重複を必要とするが、BDレコーダーではどうしているのだろう? 重複させると再連結する際に面倒。あるいは、末端のBフレームを再エンコードしている? 余力があれば調べる。
[追記 2020/11/01] 調べた。SonyのBDレコーダーではカット点に対し前の動画を「カット点を含むGOPの1つ後のGOPの最後のPフレームまで」、後の動画を「カット点を含むGOPの2つ前のGOPの最後のPフレームの次フレームから」出力していた。つまり、この記事の1文目の表記は絶対ではなかった。後の動画はBフレームから始まるが、当然表示はできない。だが、データ上は存在しているようで、他の動画と連結させると表示できるようになる。BDレコーダーによる再連結の際は、タイムスタンプを見ているのか重複することなくつながった。
オープンGOP:デコード画像の順でB→Iを含むもの→参考
Macの画面収録では、IBBPだが末端のBフレームをPフレームにしている。
[追記 2020/11/01] -map 0
としたいところだが、字幕を含むとFFmpeg 4.2以降では-codec copy
でmuxできない。ARIB Captionのデコードに対応したがエンコードには対応していないためである。libaribb24を有効化すればいい?
切り出し手順
1. Avidemuxでフレームタイプを確認しながら開始時間、終了時間を決める。
ffmpeg -ss 00:35.213 -to 00:45.322 -i in.m2ts -copyts -map 0 -c copy out.m2ts
-c copy
とすると入力オプション(-i
より前)の-to
は無視されるが、-copyts
をつけると可能になる。
“AAC bitstream not in ADTS format and extradata missing”が出る場合は-copyts
の代わりに出力オプション(-i
より後ろ)として-ss 0
を(もう一度)つける。
[追記 2020/11/01] -copyts
だけでなく-mpegts_copyts 1
もつけないとptsがソースとずれる。これはmuxerにタイムスタンプをコピーするよう伝えるコードらしい。
2. 出力結果(out.m2ts)の端を確認する。必要に応じて、開始時間、終了時間を調整して再トライ。
両端のフレームを眼で確認。フレーム単位戻し/送りは、Avidemux、QuickTime Player:←/→キー、IINA:,/.キー。
両端のフレームタイプを確認(Avidemuxだと終端付近のBフレームが表示されない場合があった)。
ffprobe -read_intervals 01:00.000%03:00.000 -show_frames -select_streams 0 -show_entries frame=pkt_pts_time,pict_type:side_data= -of csv=p=0 out.m2ts | grep , | less
[補遺] タイムスタンプ/フレームタイプの確認は時間はかかるがこれでも可(画像、タイムスタンプ、フレームタイプを同時に確認できる)。
ffmpeg -i in.m2ts -vf "drawtext=fontfile=/System/Library/Fonts/HelveticaNeue.ttc:x=(w-tw)/2:y=(h-th)/2:fontsize=64:box=1:text='%{pts\:hms} %{pict_type}'" -q 5 -c:a copy pts.m2ts
[追記 2020/11/01] これも。
ffplay -v quiet -vf "drawtext=fontfile=/System/Library/Fonts/HelveticaNeue.ttc:fontsize=48:box=1:text='%{pts} %{pict_type}'"
結合
ffmpeg -f concat -i in.txt -map 0 -c copy out.m2ts
in.txtの内容は以下。
# This is comment
file 'path/to/00001.m2ts'
outpoint 73558.878144
file 'path/to/00002.m2ts'
inpoint 73558.878144
outpoint
とinpoint
で同じ時刻を指定すると重複しない(inpoint
は指定時刻を含むがoutpoint
は含まない)。
あるいはワンライナー(同じ処理を表したものではない)。
ffmpeg -f concat -safe 0 -i <(printf "file '%s'\ninpoint 10:00.000" /absolute/path/to/in.m2ts) -map 0 -c copy out.m2ts
この場合、-safe 0
と絶対パスであることが求められる。
質問
FFmpegでプログラム番号とPIDをキープ(設定)する方法