web-dev-qa-db-ja.com

ffmpegで時間精度のビデオセグメントを抽出する方法は?

これはこの辺りで特に新しい質問領域ではありませんが、私はそこに提案されていることをあまり幸運なしに試しました。だから、私の話:

私は特定のチャンクを抽出したい、camera.movのstraight-from-the-cam.movビデオの15秒の塊を持っています。このビデオから、開始時間と終了時間で秒単位で識別できます。私は「コピー抽出」と呼ばれることをしようとすることから始めました:秒9から12を得るために

ffmpeg -i test.mov -vcodec copy -acodec copy -ss 9 -to 12 test-copy.mov

これは悪くないスタートでしたが、クリップの最初と最後にいくつかの黒いフレームがありますが、それは私にはできません。オリジナルからのきれいな編集でなければなりません。そこで、オリジナルを新しいトリミングされたクリップに再コーディングしてみました。

ffmpeg -i test.mov -ss 00:00:09 -t 00:00:03 test-out.mov

これは優れていますが、完全ではありません。クリップの先頭に黒いフレームはなくなりましたが、最後にはまだ残っています。

さらに閲覧して読んだ後、問題は、元のビデオにキーフレームがないためにffmpegが適切なポイントを見つけるのに苦労していることだと考えました。そこで、いくつかの異なる方法で、元のビデオを(おそらく)キーフレームを追加するように再コーディングしました。 1秒の境界(「9秒から12秒」)でビデオを選択できるようにしたいので、ウェブ上のさまざまな提案をコピーして、

ffmpeg -i test.mov -force_key_frames "expr:gte(t, n_forced)" test-forced.mp4

そして

ffmpeg -i test.mov -g 1 test-g-inserted.mp4

(キーフレーム検索をサポートするために必要なmp4コンテナに関するいくつかのコメントに基づいてこれらをmp4として作成しましたが、正直ここでハッキングしているだけです)その後、以前のように抽出を試みましたが、これらの新しいビデオではおそらくキーフレームがありますそれらに。運はありません-どちらもほぼ同じようです。最初は問題ありませんが、最後にはまだ黒いフレームがあります。 (FWIW、test-forced.mp4とtest-g-inserted.mp4の両方にも末尾の黒いフレームがあります。)

だから:私はまだ立ち往生している、とはしたくない。私が間違っていることについての洞察はありますか?私は近くにいるように感じますが、それらの黒いフレームを取り除く必要があります。

31
Jim Miller

まず最初に、開始時間と停止時間を知っていると仮定します。その期間にキーフレームを追加します。

ffmpeg -i a.mp4 -force_key_frames 00:00:09,00:00:12 out.mp4

ほとんどの場合、完全にビデオを直接カットできますが、場合によっては役に立ちません。そのため、上記のコマンドで処理しました。ここでは、 Ffmpeg Docs に従ってエンコードするときに問題になる可能性があるため、多くのキーフレームを追加しないように注意してください。

これで、特定の時間からビデオをカットすることができます。

ffmpeg -ss 00:00:09 -i out.mp4 -t 00:00:03 -vcodec copy -acodec copy -y final.mp4

これにより、カットの開始点と終了点にキーフレームを手動で追加したため、問題が解決します。それは私のために働いた。

乾杯。:)

33
BlueSword

質問やその他の回答が抱えている問題は、入力ファイルではなく出力ファイルのオプションとして-ssを使用していることだと思います。ほとんどのffmpegオプションはグローバルではありませんが、代わりにそれらが先行するファイルにのみ適用されます。オプションがどこに行く必要があるかはしばしば明らかではないので、時には試行錯誤が必要です。

-ss-tは、入力ファイルが適用される前に正しく使用されていたので、うまくいきました。出力にオーディオを含める場合、出力ファイルのオプションとして-shortestを使用する必要がありました。または、2秒間のビデオで2分間のオーディオを取得しました。

ffmpegバージョンN-67413-g2a88c74(基本的に2014年12月14日のgitソース)

以下は、最近クリップを作成するために使用したコマンドラインです。 (実際には、より良い例になるように微調整しました。私はこのために音声を残し、スローモーションはしませんでした。)

ffmpeg -ss 120.2 -t 0.75 -i ../mcdeint.60p.lossless264.slow.mkv -c:a libopus -shortest -aspect 16:9 -preset veryslow -x264-params nr=250:ref=6 -crf 22 -movflags +faststart clip2.mkv

-c:a copy(ソースにはAC3オーディオがある)を使用すると、mplayerで再生が不安定になります。おそらく、開始を含むオーディオフレームの先頭からオーディオを取得し、コンテナでa/vオフセットを使用する必要があります。起動時に、そのオフセット分だけオーディオがビデオよりも先に進むのに数秒かかり、それまでビデオは非常に低いFPSで再生されます。そのため、オーディオをxcodeしました。 opusもpcm_s16leもmp4に入れることができないため、この例ではmkvコンテナーを使用しました。

ソースは、非常に遅いyadif = 3:1、mcdeint = 3:1:10の出力からのロスレスx264エンコード(-qp 0)です(NTSC DVDからの一部のBFFインターレースビデオ) 、おそらくDVカメラから)。すべてのIフレームではなく、通常のキーフレーム間隔のPフレームです。

-ssを0.2秒調整することで、期待どおりに動作したため、ffmpegは必要なポイントまでデコードを処理する必要があります。私が望んでいたIフレームの単なる偶然ではありませんでした。たぶん-accurate_seekがデフォルトですか?また、ffvhuffロスレスソースを入力として使用した場合と同じ結果(バイト単位の同一gif出力)を取得します。 (ただし、要求されたポイントまでデコードする必要がないため、高速に実行されます。)

関連する可能性のある別のオプションは-seek2anyですが、「デマルチプレクサーレベルで非キーフレームをシーク」と表示されます。 (つまり、現在のフレームに必要な参照を実際に生成せずにデコードを開始します、すべてグレーを使用しますか?)

-c:v copyを使用しようとしませんでした。ループするために非常に短いクリップを切り取っているため、必要な場所にIフレームがないことを知っています。

これは私が実際に使用したコマンドラインで、音のない短いスローモーションクリップを作成します。

ffmpeg -ss 120.2 -t 0.75 -i ../vid.yadif3.1,mcdeint3.1.10.ffvhuff.mkv -an -shortest -aspect 16:9 -c:v libx264 -preset veryslow -x264-params nr=250:ref=6 -crf 22 -filter:v "setpts=3.0*PTS" -movflags +faststart -r 20 clip.mp4

-r 20は重要でした。mkvとは異なり、ffmpegのMP4出力は定数フレームレートのみであることに注意してください(編集:-vsync vfrはmp4マルチプレクサではデフォルトではないため)。区別することなく、出力FPS =入力FPSを設定し、それを実現するために必要なときにフレームを複製します。 x264とアニメーションGIF(透明度付き)はどちらも複製フレームを非常に効率的にエンコードできますが、それでも愚かなことです。

これを一例として作り上げる前に、mkvに出力し、次にffmpeg -i clip.mkv -c:v copy -movflags +faststart -r 20 clip.mp4をremuxに出力する2つのステップでそれを行いました。ちなみに、リコーディング時にビデオのfpsを変更することは、xcodingなしで、ffmpegではなく可能です。 https://superuser.com/questions/740196/reducing-video-size-with-avconv-why-does-the-size-increase 。しかし、とにかく、ffmpegはmkvを作成するときにlibx264に45フレームしか送信しませんでしたが、60fpsで2.2秒のビデオを作成すると考えていました。可変FPSを扱うためにmp4でffmpegを使用しないでください。

編集:mkv出力ではffmpegのデフォルトは-vsync vfrになりますが、mp4では出力されません。 -vsync vfrを使用すると、ffmpegはVFRをmp4出力に正常に書き込むことができます。

再びgif出力については、HTML5ビデオ(<video controls autoplay loop> <source src="clip.mp4" type="video/mp4"> </video>)で我慢しないことにした場合に備えて

ffmpeg -ss 120.2 -t 0.75 -i ../vid.yadif3.1,mcdeint3.1.10.ffvhuff.mkv -an -shortest -aspect 16:9 -filter:v "setpts=3.0*PTS,scale=854x480" -r 20 clip.gif

Gifコンテナにはアスペクト比が格納されないため、scale=を使用する必要がありました。そのため、再生時に自動スケーリングされません。 (私の720x480ピクセルの16:9ビデオは再生時に854x480にスケーリングされます。実際には853.333になりますが、丸められ、ffmpegは853x480をmkvコンテナーに格納するため、常に-aspect 16:9を使用します。 [SAR 32:27 DAR 16:9]ではなく、適切なアスペクト比[SAR 186:157 DAR 279:157]を保存する

10
Peter Cordes

キーフレームを追加する必要はありません。ピーターが言うように、それは単に正しい順序でオプションを取得することの問題です。ただし、正しい方法の決定的な公式ガイドについては、 https://trac.ffmpeg.org/wiki/Seeking を参照してください。

6
Adam Spiers

森の中で眠っているクマを突く???? ‍♂️。このスレッドで-toフラグについて言及されていませんでしたが、-tフラグよりも有用であることがわかりました。私にとってうまく機能するコマンドの例、

ffmpeg -y -i [INPUT.file] -ss 00:42:42 -to 00:84:84 -codec copy [OUTPUT.file]
2
ipatch

私も知りたいです。これまで、動画をロスレスに変換し、編集後にセグメントを抽出して再エンコードしました。

ffmpeg -i input -ss 9.48 -t 3.52 -c:v libx264 -crf 0 -g 1 -c:a copy TempIframe.mp4

しかし、これは時間がかかり、損失の多いプロセスです...

私は次のことを試しました成功なし:

ffmpeg -i source.mp4 -ss 1 -c:v copy -seek2any 1 -avoid_negative_ts 1 -safe 1 -c:a copy segment.mp4
0
AJ29