ffmpeg で時間単位やフレーム単位でカットする方法

ffmpeg では素材を時間単位、フレーム単位でカットする方法が幾つかあり、それらの使い方とベンチマークのまとめ。

等分割する場合には HLS や Segment のオプションを使う。
ffmpeg で Apple HTTP Live Streaming(HLS)を扱う
詳細な分割設定ができる Segment

関連記事
ffmpeg で指定秒ごとに分割する方法


修正(2016年7月14日)
Main options の内容を挙動に即した説明に直し曖昧な部分は削除した。

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キーフレーム分ずれるがそれは出力時間に影響を与えない。ss を入出力のオプションで併用した場合はその合計時間を起点とする。秒指定と、hh:mm:ss[.xxx] 形式が使える。
  • -to position (output)
    出力時間を指定する。入力ファイルの後ろに指定する。コーデックコピーするときに開始時間が1キーフレーム分ずれるがそれは出力時間に影響を与えない。ss を入出力のオプションで併用した場合は入力オプションの時間を起点とする。t と to を併用したら t が優先される。秒指定と、hh:mm:ss[.xxx] 形式が使える。
  • -frames (output,per-stream)
    指定したフレーム数で出力する。vframes の使用推奨
  • -fs limit_size (output)
    指定したファイルサイズで出力を止める。指定したファイルサイズを目標にビットレートを調整するものではない。

参考記事
Seeking – FFmpeg
FFmpeg documentation : : Main options

ffmpeg で先頭と後ろを一度にカットする

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 : : trim

atrim


フィルタの 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 : : atrim

movie, 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
関連記事

この記事へのコメント

-2017/04/14 (金) 05:57:14

動画の特定部分を切り出したい場合、「-copyts」を付けるやり方がベストですね。

管理人のみ通知 :

トラックバック


ニコニコチャンネル始めました
ニコラボチャンネル
スポンサード リンク
新着記事と追記・編集記事
スポンサード リンク
ブログ内検索
プロフィール

Author:ロベルト
お問い合わせはこちらまで
robelt2525[at]gmail.com

中の人 @nico_lab
ブログ更新用 @blo_nico_lab

詳しいプロフィールはこちら

カテゴリ
アクセスの多い記事
記事アーカイブ

2018
2016
2014
2013
12 11 10 09 08 07 06 05 04 03 02 01 

2012
2011
2010
2009

最新コメント
リンク
ニコニコ静画
アニメカテゴリ毎時ランキング
免責事項
当ブログはリンクフリーです。記事によりトラブルが生じた場合でも、当ブログ管理人は一切の責任を負いません。 当ブログに記載されている情報の正誤や利用は、ご自身の判断でお願いします。 紹介したアプリケーションに関する問い合わせは作者に問い合わせてください。ニコニコ動画に関する質問はまずは公式掲示板、2ch、各Q&Aサイトを参照ください。
ブログの読者になる(RSS)
アクセス数
FC2無料カウンターFC2無料カウンターFC2無料カウンターFC2無料カウンターFC2無料カウンターFC2無料カウンターFC2無料カウンターFC2無料カウンターFC2無料カウンター
FC2 Analyzer