大きなライブWMVビデオフィードをすべて同じサイズの小さなチャンクに分割する必要があります。ひとつだけを除いて、これをうまく動作させるスクリプトを作成しました:ビデオチャンクはキーフレームで始まらないため、ほとんどのビデオチャンクを再生するときに、元のビデオのキーフレームが最終的に表示されるまで画像を表示しません達した。
出力ビデオをキーフレームで開始するようにffmpegに指示する方法はありませんか?
コマンドラインの外観は次のとおりです。
ffmpeg.exe -i "C:\test.wmv" -ss 00:00:00 -t 00:00:05 -acodec copy -vcodec copy -async 1 -y "0000.wmv"
ffmpeg.exe -i "C:\test.wmv" -ss 00:00:05 -t 00:00:05 -acodec copy -vcodec copy -async 1 -y "0001.wmv"
等々...
FFMPEGの最新ビルドには、新しいオプション「セグメント」が含まれています。
ffmpeg -i INPUT.mp4 -acodec copy -f segment -vcodec copy -reset_timestamps 1 -map 0 OUTPUT%d.mp4
これにより、キーフレームに基づいてセグメントに分割される一連の番号付き出力ファイルが生成されます。私自身のテストでは、数分以上MP4形式のみで使用したことはありませんが、うまく機能しています。
公式の FFMPEG Docs で述べたように、-ss timestart
before-i input_file.ext
。これは、生成されたビデオの先頭を、指定されたタイムスタンプの前に見つかった最近接キーフレームに設定する(または理解している)ためです。
例を次のように変更します。
ffmpeg.exe -ss 00:00:00 -i "C:\test.wmv" -t 00:00:05 -acodec copy -vcodec copy -async 1 -y "0000.wmv"
.flv
および.mp4
ファイル。
ここに私が働くことができる解決策があります:
Av501とd33pikaで示唆されているように、キーフレームの場所を見つけるためにffprobeを使用しました。 ffprobeは非常に冗長で、すべてのキーフレームを出力するのに数秒から数分かかる場合があり、長いビデオから必要なフレーム範囲をスコープする方法がないため、5つのステップに進みます。
目的のチャンクサイズの約2倍で、元のファイルからビデオチャンクをエクスポートします。
ffmpeg -i source.wmv -ss 00:00:00 -t 00:00:06 -acodec copy -vcodec copy -async 1 -y 0001.wmv
Ffprobeを使用して、キーフレームの場所を見つけます。目的のチャンクサイズに最も近いキーフレームを選択します。
ffprobe -show_frames -select_streams v -print_format json=c=1 0001.wmv
Ffprobeの出力から、そのキーフレームの直前のフレームのpkt_dts_time
を取得します。
ステップ1のエクスポートされたチャンクのffmpeg。同じ入力ファイルと出力ファイルを指定し、-ss 00:00:00
および-t
[ステップ3で見つかった値]を指定します。
ffmpeg -i 0001.wmv -ss 00:00:00 -t 00:00:03.1350000 -acodec copy -vcodec copy -async 1 -y 0001.wmv
-ss
[繰り返しにわたってステップ3で見つかった値の累積合計]を使用して、ステップ1から再開します。
このように進めると、ビデオをキーフレームで分割するための効率的で堅牢な方法を得ることができました。
Ffmpegの新しいビルドを使用すると、ffprobeとffmpegセグメントマルチプレクサを使用してこれを実現できます。
1. ffprobeとawkを使用して、希望するチャンク長にできるだけ近いキーフレームを識別します。
ffprobe -show_frames -select_streams v:0 -print_format csv **[SOURCE_VIDEO]** 2>&1 | grep -n frame,video,1 | awk 'BEGIN { FS="," } { print $1 " " $5 }' | sed 's/:frame//g' | awk 'BEGIN { previous=0; frameIdx=0; size=0; } { split($2,time,"."); current=time[1]; if (current-previous >= **[DURATION_IN_SECONDS]**){ a[frameIdx]=$1; frameIdx++; size++; previous=current;} } END { str=a[0]; for(i=1;i<size;i++) { str = str "," a[i]; } print str;}'
どこで
出力は、キーフレームのカンマ区切り文字列です。
2. ffmpegへの入力として上記のキーフレーム出力を使用します。
ffmpeg -i [SOURCE_VIDEO] -codec copy -map 0 -f segment -segment_frames [OUTPUT_OF_STEP_1] [SEGMENT_PREFIX] _%03d .[SOURCE_VIDEO_EXTENSION] =
どこで
つかいます ffprobe -show_frames -pretty <stream>
キーフレームを識別します。
スクリプトを実行する意思があり、特定の間隔でフレームを作成する場合は、1つの方法があります
Ffprobeを実行し、出力からIフレームの位置を収集します
ffprobe -show_streams
同じスクリプトを使用して一連の-ss -tコマンドを実行し、必要なチャンクを取得します。
その後、スクリプトに最小フレーム数を決定させることができます(たとえば、10フレーム以内に2つのI画像がある場合、そこにチャンクすることは望ましくありません)。
もう1つの方法は、gstreamerのmultisfilesinkを使用して、モードをキーフレームに設定することです(ただし、すべてのキーフレームでチャンクされるため、理想的ではない場合があります)。