ffmpeg では素材を時間単位、フレーム単位でカットする方法が幾つかあり、それらの使い方とベンチマークのまとめ。
等分割する場合には HLS や Segment のオプションを使う。
ffmpeg で Apple HTTP Live Streaming(HLS)を扱う詳細な分割設定ができる Segment関連記事
ffmpeg で指定秒ごとに分割する方法修正(2016年7月14日)
Main options の内容を挙動に即した説明に直し曖昧な部分は削除した。
挙動の確認動画サンプル
ffmpeg -f lavfi -i testsrc2=r=30000/1001:d=30 -g 1 30p-g1.mp4
ffprobe -of csv -show_packets -i 30p-g1.mp4 -show_data_hash adler32 -select_streams v > 30p-g1.mp4.csv
ffmpeg -f lavfi -i testsrc2=r=30000/1001:d=30 -g 5 30p-g5.mp4
ffprobe -of csv -show_packets -i 30p-g5.mp4 -show_data_hash adler32 -select_streams v > 30p-g5.mp4.csv
Main options
- -ss position (input/output)
入力開始時点を指定する。入力ファイルの前に指定する入力オプションと、入力ファイルの後に指定する出力オプションがある。入力オプションとして使うとキーフレームを参照するので高速である。一方で出力オプションとして使うと全フレームを参照するのでとても遅くなる。コーデックコピーする場合には入力オプションと出力オプションとでは挙動が異なり、入力オプションは指定した時間の前のキーフレームから、出力オプションは指定した時間の後のキーフレームから入力を開始する。つまりどちらも指定時間がキーフレームの場合はその時間を含まずに1キーフレーム分ずれる。
入力オプションと出力オプションを併用した場合には合計時間分で入力開始時間を指定する。ただしコーデックコピーする場合は合計時間の後のキーフレームから入力を開始する。入力オプションと出力オプションを併用してフィルタで出力フレーム、または時間を指定する場合は合計時間から入力するが、出力時間は入力オプションの指定時間を起点とする。秒指定と、hh:mm:ss[.xxx] 形式が使える。 - -sseof position (input)
マイナス時間指定で最後からの指定秒から出力する。コーデックコピーする場合は指定した時間の前のキーフレームから入力を開始する。秒指定と、hh:mm:ss[.xxx] 形式が使える。 - -itsoffset offset (input)
入力ファイルのオフセット秒(マイナスも可能)を指定する。このオフセットはタイムスタンプを挿入し、指定したオフセット秒はそれだけ遅延(マイナスの場合はカット)させることができる。オフセットするファイルの前に指定し、コーデックコピーの時には効果がない。詳しくは後述。秒指定と、hh:mm:ss[.xxx] 形式が使える。 - -t duration (input/output)
出力時間を指定する。入力ファイルの前に指定すると出力時間を制限する。入力ファイルの後ろに指定すると指定時間になったら出力を止める。入力オプションと出力オプションをどのように使い分けるかというと、1入力だけならどちらでもよいが、2入力以上のときに -ss, -t を入力毎に使い分ける場合は -ss, -t 両方とも入力オプションで指定する。コーデックコピーするときに開始時間が1キーフレーム分ずれるがそれは出力時間に影響を与えない。-ss を入出力のオプションで併用した場合はその合計時間を起点とする。秒指定と、hh:mm:ss[.xxx] 形式が使える。 - -to position (input/output)
出力時間を指定する。入力ファイルの後ろに指定すると、コーデックコピーするときに開始時間が1キーフレーム分ずれるがそれは出力時間に影響を与えない。-ss を入出力のオプションで併用した場合は入力オプションの時間を起点とする。詳しくは後述。-t と -to を併用したら -t が優先される。入力ファイルの前に指定すると出力時間の引き算をせずにそのときの再生時間で出力時間を決める。秒指定と、hh:mm:ss[.xxx] 形式が使える。 - -frames (output,per-stream)
指定したフレーム数で出力する。vframes の使用推奨 - -fs limit_size (output)
指定したファイルサイズで出力を止める。指定したファイルサイズを目標にビットレートを調整するものではない。
参考記事
Seeking – FFmpegFFmpeg documentation : : Main optionsffmpeg で先頭と後ろを一度にカットするtrim
フィルタの trim について。入力した映像を秒指定とフレーム指定でカットする。出力されたデータは無圧縮データになる。詳しい解説は
trim フィルタの使い方 を参照。
- start, start_pts
開始秒の指定。規定値 - end, end_pts
終了秒の指定。規定値 - duration
最大の出力秒の指定 - start_frame
開始フレームの指定 - end_frame
終了フレームの指定
開始秒か開始フレームを 0 以外に指定した場合は PTS を 0 にリセットしないと指定したところから出力されないことに注意。
使い方例 3秒から 5秒まで映像を trim するコマンド
ffmpeg -i infile -an -filter_complex trim=3:5,setpts=PTS-STARTPTS outfile
参考記事
FFmpeg documentation : : trimatrim
フィルタの atrim について。入力した音声を秒指定とサンプル数指定でカットする。出力されたデータは無圧縮データになる。
- start, start_pts
開始秒の指定。規定値 - end, end_pts
終了秒の指定。規定値 - duration
最大の出力秒の指定 - start_sample
開始サンプル数の指定 - end_sample
終了サンプル数の指定
開始秒か開始サンプル数を 0 以外に指定した場合は PTS を 0 にリセットしないと指定したところから出力されないことに注意。サンプル数指定でのカットは音声のサンプリング周波数が1秒毎なので、48kHz の音声の場合 48000 サンプルが1秒になる。
使い方例 3秒から 5秒まで音声を atrim するコマンド
ffmpeg -i infile -vn -filter_complex atrim=3:5,asetpts=PTS-STARTPTS outfile
映像と音声を同時に trim するコマンド 「;」は別のソースにフィルタを掛けている
ffmpeg -i infile -filter_complex trim=3:5,setpts=PTS-STARTPTS;atrim=3:5,asetpts=PTS-STARTPTS outfile
参考記事
FFmpeg documentation : : atrimmovie, amovie
lavfilter を使ってフィルタ内でファイルを入力してフィルタを当てる方法。あまり使わないので詳しくない。出力されるデータの映像は rawvideo、音声は pcm_f32le になる。
- filename
入力ファイル名、ローカルファイルだけではなく特定のプロトコルも入力できる - format_name, f
指定したフォーマットで読み込む。無指定だと入力ファイルから特定する - seek_point, sp
指定した秒から入力する。規定値は 0 - streams, s
入力したストリームを特定する。dv が映像、da が音声。それぞれ入力する場合は + でつなげる
ffmpeg -f lavfi -i movie=infile:sp=3:s=dv+da[v][a];[v]trim=duration=2[out0];[a]atrim=duration=2[out1] outfile
参考記事
FFmpeg documentation : : movie各種カットの方法とベンチマークのまとめ
ベンチマークに用いた動画:【初音ミク4K-MV】0→∞への跳動:
Visual Works - PolyphonicSkies.net試す方法は開始20秒の時点から20秒間カットした動画を無圧縮の null 出力して3回のベンチマークの平均。30fpsなので20秒だと600フレームになる。
結果をまとめると、入力時点の指定を最初にするかしないかで読み込み時の CPU 負荷に大きな違いが出る。-f lavfi 入力はあまり使い道がわからなかった。
ffmpeg -ss 20 -i eien_4K_H264.mp4 -t 20 -an -benchmark -f null -
bench: utime=28.12s
bench: maxrss=213,910.67kB
ffmpeg -ss 20 -i eien_4K_H264.mp4 -to 20 -an -benchmark -f null -
bench: utime=28.21s
bench: maxrss=213,989.33kB
ffmpeg -ss 20 -i eien_4K_H264.mp4 -frames 600 -an -benchmark -f null -
bench: utime=28.39s
bench: maxrss=214,161.33kB
ffmpeg -i eien_4K_H264.mp4 -ss 20 -t 20 -an -benchmark -f null -
bench: utime=53.28s
bench: maxrss=214,353.33kB
この設定方法は15秒から読み込みを開始して、そこから5秒を正確に測る
ffmpeg -ss 15 -i eien_4K_H264.mp4 -ss 5 -t 20 -an -benchmark -f null -
bench: utime=34.02s
bench: maxrss=213,869.33kB
この設定方法は19秒から読み込みを開始して、そこから1秒を正確に測る
ffmpeg -ss 19 -i eien_4K_H264.mp4 -ss 1 -t 20 -an -benchmark -f null -
bench: utime=28.18s
bench: maxrss=214,550.67kB
ffmpeg -f lavfi -i movie=eien_4K_H264.mp4:sp=20:s=dv+da[v][a];[v]trim=duration=20[out0];[a]atrim=duration=20[out1] -an -benchmark -f null -
bench: utime=28.38s
bench: maxrss=477,461.33kB
ffmpeg -i eien_4K_H264.mp4 -filter_complex trim=20:40,setpts=PTS-STARTPTS -an -benchmark -f null -
bench: utime=53.02s
bench: maxrss=213,665.33kB
ffmpeg -i eien_4K_H264.mp4 -filter_complex trim=start_frame=600:end_frame=1200,setpts=PTS-STARTPTS -
bench: utime=53.23s
bench: maxrss=213,802.67kB
-ss では開始フレームを指定できないが、-ss と trim を併用することで開始フレームを正確に指定できる
ffmpeg -ss 19 -i eien_4K_H264.mp4 -filter_complex trim=start_frame=30:end_frame=630,setpts=PTS-STARTPTS -an -benchmark -f null -
bench: utime=28.39s
bench: maxrss=214,752.00kB
カットするフレーム数が分かっている場合はこちらでも良い
ffmpeg -ss 19 -i eien_4K_H264.mp4 -filter_complex trim=start_frame=30,setpts=PTS-STARTPTS -frames 600 -an -benchmark -f null -
bench: utime=28.299s
bench: maxrss=214,800.00kB
映像と音声を合わせてカットする方法
音声の trim コマンドである atrim では動画と同じようにフレーム数単位ではカットできないので秒単位かサンプル数単位でカットする。サンプル数は音声のサンプリング周波数を1秒とする。音声の開始時点を早める場合は読み込み開始時点を動画より早めるとその分だけズレる。
参考記事:
WAVとは(1) ~ 「WAVファイル」について、音のデジタル化やファイル形式をやさしく解説 | 豆知識元の素材の音声で初めから遅延が生じている場合は Mediainfo や tsMuxeR、BonTsDemux などで遅延を調べることができ、この遅延を参考に音声のカット位置をずらすことで動画と音声を正しい位置でカットできる。また音声のチャンネル数が変わるときに上のツールで調べた遅延以上の遅延が生じることもあるのでうまくカットするのは難しい。
秒単位で映像と音声をカットする方法(開始20秒から20秒間)
ffmpeg -i infile -filter_complex trim=20:40,setpts=PTS-STARTPTS;atrim=20:40,asetpts=PTS-STARTPTS outfile
秒単位で映像と音声をカットする方法(開始20秒から20秒間)
ffmpeg -ss 20 -i infile -filter_complex trim=duration=20,setpts=PTS-STARTPTS;atrim=duration=20,asetpts=PTS-STARTPTS outfile
フレーム数単位でカットする場合(音声48kHz:開始20秒から20秒間)
ffmpeg -i infile -filter_complex trim=start_frame=600:end_frame=1200,setpts=PTS-STARTPTS;atrim=start_sample=960000:end_sample=1920000,asetpts=PTS-STARTPTS outfile
この方法で音声をカットすると必ず再エンコードされるが FAW を使えば無劣化で編集できるので、-map を指定し atrim でカットして分離する。しかし FAW の場合は最初から分離してあり、AAC に戻す必要があるので動画と音声を一度のコマンドで出力する必要は特にない。
ffmpeg -i infile -i faw.wav -filter_complex [0:0]trim=start_frame=600:end_frame=1200,setpts=PTS-STARTPT[v];[1:0]atrim=start_sample=960000:end_sample=1920000,asetpts=PTS-STARTPTS[a] -map [v] video -map [a] audio.wav
参考記事
【ffmpeg】 マルチトラックの動画の作り方FAW な WAV を ffmpeg で編集する途中をカットして連結する場合
方法は2つあって、-f lavfi でシークポイントを指定して連結する方法と、1ファイルごとにカットしてパイプ連結していく方法がある。結果は後者の方法のほうが圧倒的に低負荷だった。また colormatrix の設定は最後の出力の時だけ正しく指定するだけで良く、途中に指定する必要はない。
-f lavfi はメモリ消費量が多いので、-ss -t とフレーム単位で指定する trim を併用するほうが実用的である。
一度の出力で音声を含めて出力することも可能だが、設定を間違えると全てやり直しになるので設定が確立出来ない間は分割出力のほうが無難。
3つのファイルを一度に取り込む場合 その1
ffmpeg -f lavfi -i movie="eien_4K_H264.mp4":sp=10:s=dv[v];[v]trim=duration=10[out0] -f lavfi -i movie="eien_4K_H264.mp4":sp=10:s=dv[v1];[v1]trim=duration=5[out0] -f lavfi -i movie="eien_4K_H264.mp4":sp=40:s=dv[v2];[v2]trim=duration=20[out0] -an -filter_complex "concat=n=3:v=1:a=0" -f null - -benchmark
bench: utime=64.101s
bench: maxrss=1,293,156kB
3つのファイルを一度に取り込む場合 その2
ffmpeg -i "eien_4K_H264.mp4" -filter_complex split=3[v1][v2][v3];[v1]trim=10:20,setpts=PTS-STARTPTS[v10];[v2]trim=10:15,setpts=PTS-STARTPTS[v20];[v3]trim=40:60,setpts=PTS-STARTPTS[v30];[v10][v20][v30]concat=n=3:v=1:a=0 -an -f null - -benchmark
bench: utime=80.387s
bench: maxrss=2,106,904kB
1つずつ読み込む場合 その1
ffmpeg -f lavfi -i movie="eien_4K_H264.mp4":sp=10:s=dv[v];[v]trim=duration=10[out0] -an -vcodec rawvideo -f avi pipe: | ffmpeg -i - -f lavfi -i movie="eien_4K_H264.mp4":sp=10:s=dv[v1];[v1]trim=duration=5[out0] -filter_complex "concat=n=2:v=1:a=0" -an -f avi pipe: | ffmpeg -i - -f lavfi -i movie="eien_4K_H264.mp4":sp=10:s=dv[v1];[v1]trim=duration=5[out0] -filter_complex "concat=n=2:v=1:a=0" -an -f null - -benchmark
bench: utime=8.689s
bench: maxrss=449,036kB
1つずつ読み込む場合 その2
ffmpeg -ss 10 -i "eien_4K_H264.mp4" -t 10 -an -vcodec rawvideo -f avi pipe: | ffmpeg -i - -ss 10 -i "eien_4K_H264.mp4" -t 15 -filter_complex "concat=n=2:v=1:a=0" -an -vcodec rawvideo -f avi pipe: | ffmpeg -i - -ss 40 -i "eien_4K_H264.mp4" -t 20 -filter_complex "concat=n=2:v=1:a=0" -an -f null - -benchmark
bench: utime=6.256s
bench: maxrss=201,620kB
オフセットが指定できるのは再エンコードされる映像の方で音声はコピーストリームにする。結果オフセットされた動画は時間が長くなったり短くなったりして音声と同期をとることができる。
追記 2013/08/26
ただし、入力ファイル前の -ss との併用はできないが、入力ファイル後の -ss は併用できる。
映像と音声の開始時点が一致しないが、映像と音声の両方が読み込める場合は -vsync -1 を使って映像をエンコードし、片方しか読み込めない場合は映像と音声を分離して処理する。
音声はそのままに映像の開始フレームを1秒挿入して動画時間が1秒長くなる
ffmpeg -itsoffset 1 -i infile -acodec copy outfile
音声はそのままに映像の開始1秒をカットする
ffmpeg -itsoffset -1 -i infile -acodec copy outfile
-ss の効果無し
ffmpeg -ss 1 -itsoffset -1 -i infile -acodec copy outfile
-ss の効果あり
ffmpeg -itsoffset -1 -i infile -ss 1 -acodec copy outfile
Seeking – FFmpeg より
1行目は 00:01:00 から 00:03:00 までをカットする
2行目は 00:01:00 から 00:02:00 までをカットするが遅い
3行目は 00:01:00 から 00:02:00 までをカットするが PTS 開始が 00:01:00 になる
4行目は 3行目の PTS 開始を 00:00:00 に変更する
5行目は 00:01:00 から 00:02:00 までをカットする
ffmpeg -ss 00:01:00 -i video.mp4 -to 00:02:00 -c copy cut.mp4
ffmpeg -i video.mp4 -ss 00:01:00 -to 00:02:00 -c copy cut.mp4
ffmpeg -ss 00:01:00 -i video.mp4 -to 00:02:00 -c copy -copyts cut.mp4
ffmpeg -ss 00:01:00 -i video.mp4 -to 00:02:00 -c copy -copyts -f nut - | ffmpeg -i - -c copy cut.mp4
ffmpeg -ss 00:01:00 -to 00:02:00
-i video.mp4
-c copy cut.mp4
- 関連記事
-
コメント
-
2017/04/14 URL 編集