web-dev-qa-db-ja.com

Webから直接ビデオ部分からベストパレットgifを効率的に作成する方法

私はしばらくの間、この2つのコマンドを使用して、ビデオセグメントをアニメーションGIFに変換し、ffmpegに最適なパレットを計算させてきました。

ffmpeg -ss $START -i $IN_FILE -t $LENGTH -vf "fps=$FPS,scale=$WIDTH:-1:flags=lanczos,palettegen" palette.png
ffmpeg -ss $START -i $IN_FILE -i palette.png -t $LENGTH -filter_complex "fps=$FPS,scale=$WIDTH:-1:flags=lanczos [x]; [x] [1:v] paletteuse" output.gif

これはローカルファイルでは非常にうまく機能しますが、$IN_FILEにリモートURLを使用し始めると、必要な部分を2回ダウンロードします。1回はパレット生成用、もう1回は実際の変換用です。

事前に完全なファイルをダウンロードすることは一般的に問題外です-長いビデオの途中で非常に小さなシーケンスに興味があることがよくあります。

-ss-tを使用してごく一部をダウンロードし、再エンコードせずに一時ファイルに保存しようとしました。

ffmpeg -ss $START -i $IN_URL -t $LENGTH -vc copy -ac none temp.mkv

この場合、帯域幅の浪費を回避します(ファイルの関連部分のみがダウンロードされ、1回だけ)が、シークは正確ではなくなります 入力の-ssの粒度はストリームコピーを行うときにシークするためのキーフレーム

理論的にはgifに変換する場合、これをさらに正確にシークして修正することは可能ですが、上記で生成された一時ファイルの開始の元のタイムスタンプを取得する方法がないようであるため、不可能です。 gifにトランスコードするときに-ssする必要がある場所を計算します。 -copy_tsで遊んでみましたが、何も得られませんでした。

簡単な解決策は、この最初のステップで再エンコードすることです(おそらく、プロセスでスケール/リサンプルを適用して、後で2回実行しないようにします)が、1つの余分な無駄なエンコードによるコスト/品質の低下を回避したいと思います。

だから:どうすれば、潜在的に大きなネットワークファイルの小さな部分のベストパレットビデオからgifへの変換を実行し、それを効率的にフェッチし(=一度ダウンロードし、関連する部分のみ)、正確なシークを使用し、余分な再エンコードを行わないでください。

1
Matteo Italia

この問題は、 複数のチェーンを持つフィルターグラフ を使用することで簡単に解決できます。これにより、シーク/ダウンロード/フィルターを1回だけ実行し、複数の方法で処理できます。シーク/フィルタリングされたストリームは、パレットジェネレーターの両方に送られ、パレットアプリケーションフィルターに送られます。パレットアプリケーションフィルターは、生成されたパレットと一緒にそれを使用します。グラフィカルに:

                                       .--> palettegen [pal]---.
 input                                /                        |
 [0:v] -> fps -> scale -> split=2 [a][b]                       V
 with                                 `-> [b] fifo [b] -> [b] [pal] paletteuse -> out.gif
precise
 seek

これは次のように解釈されます。

ffmpeg -ss $START -I $IN_URL -t $LENGTH -filter_complex "fps=$FPS,scale=$WIDTH:-1:flags=lanczos,split=2 [a][b]; [a] palettegen [pal]; [b] fifo [b]; [b] [pal] paletteuse" out.gif

2つの別々のパイプラインブランチの入力として同じストリームを使用するには、splitフィルターを使用する必要があることに注意してください。

編集fifo@のおかげで追加されましたギャンのコメント; palettegenはパレットを生成する前にストリームの最後まで待機する必要があり、paletteuseはパレットを取得する前に[b]の消費を開始できないため、必要です。したがって、ビデオが大きい場合[b]のデフォルトのバッファは十分ではなく、ffmpegはフレームのドロップを開始します。解決策は、中央にfifoを追加して、任意のサイズのバッファリングを処理することです(メモリ内のストリーム全体のバッファリングは、使用可能なRAMに負担をかける可能性があるため、ビデオの長さを超えないように注意する必要があります)。

(恥知らずなプラグ:これはコマンドです 私は今使用しています 私の tube2gif_bot テレグラムボット)


最も重要なことは、これは使用しているコマンドの理解についての話です。質問で引用された2番目のコマンドはすでに複雑なフィルターグラフを使用していましたが、Webから盲目的にコピーして貼り付けたため、不透明なフィルターグラフの構文を理解しようとはしなかったため、少し調整するだけでは発生しませんでした。最善の解決策だったでしょう。

1
Matteo Italia