web-dev-qa-db-ja.com

FFmpegとの間でデータをロスレスでパイプするにはどうすればよいですか?

FFmpegのあるインスタンスから別のインスタンスにストリームをパイプしましたが、中間ストリームで圧縮が使用されていたため、最終結果は醜いものでした。これを防ぐにはロスレスパイプが必要で、オーディオとビデオの両方を含める必要があります。

この問題には複数の答えがあると思います。ボーナスポイントは、ソリューション(パイプ可能な互換性のあるコンテナーとコーデック)の完全なリストを提供するすべてのユーザーに当てはまります。ボーナスポイントは、字幕など、他のデータを説明する人にも適用されます。

編集:私は適切なコーデック/コンテナの組み合わせを探しています。私はすでにパイプを使用していて、今はそれをロスレスにする必要があると言ったので、人々がなぜそれを理解するのに苦労していたのか分かりません。

私はこれを説明せずに説明する方法がわかりませんが、これはFAQサイトです。非常に具体的な回答が必要な質問をしても、このサイトにアクセスして何百万ものユーザーが自分の問題を検索エンジンに組み込みます。私の質問は、FFmpegインスタンス間でデータを無損失でパイプ処理する必要がある他の人が、私がやっていたこと、なぜうまくいかなかったのか、なぜこれが理由なのかを説明するナラティブとコードの壁に気を取られずに役立つように設計されています唯一のオプション。

7
Wutaz

(以前の回答の一部から)これを行う方法を学習した方法は、ビデオのrawvideoコーデック、pcm_s16leオーディオコーデック、およびFFmpegのnutラッパーを使用して、ストリーム。 nutはFFmpeg以外の主要なプログラムではサポートされていませんが、プロセス間でデータを効率的にパイプするために必要な非圧縮形式をサポートできる唯一のコンテナーです。

このエンコーディングの引数は次のようになります。

... -c:v rawvideo -c:a pcm_16le -f nut - ...

一部のオーディオは24ビット以上のサンプルで保存されます。これらのサンプルでは、​​代わりにpcm_24leまたは別の形式を使用する必要があります。 ffmpeg -codecsを実行すると、非圧縮オーディオ形式の完全なリストが表示されます(リストを検索する必要があります)。オーディオのサンプルサイズがわからない場合は、pcm_16leを使用しても目立った品質の低下はありません。

パイプの受信側で、入力を標準入力に設定すると、ffmpegが形式を検出してストリームをデコードします。

... ffmpeg -i - ...

この回答の省略記号(...)はコードの一部ではありません。これらはあなたのコードが行くところです。単一のハイフン(-)は、FFmpegに、それらが現れる場所に応じて、標準入力または標準出力のいずれかを使用するように指示します。

更新:

私はこれを改善するために簡単な実験を試みました、そして他のプログラムがそれを理解するので(少なくともVLCは)AVIより良いコンテナのようです。

... -c:v rawvideo -c:a pcm_16le -f avi - ...

これは、互換性のボーナスが追加された、旧バージョンとまったく同じように機能します。

後々、多くの状況で役に立たない質問を投稿したことを後悔しましたが、質問は誰にとっても役立つはずだと私の主張はしました。これにより、答えがより便利になります。

7
Wutaz

ビデオとオーディオをffmpegからffmpegにロスレスパイプする方法

質問者による要件:

  • ffmpegのあるインスタンスから別のインスタンスに無損失でパイプする
  • /dev/nullを行き来するかどうかは関係ありません

例:

ffmpeg -s 1280x720 -f rawvideo -i /dev/zero -ar 48000 -ac 2 -f s16le -i \
/dev/zero -c copy -f nut pipe:1 | ffmpeg -y -i pipe:0 -c copy -f nut /dev/null

誰かがこれを行う理由はわかりません。また、ffmpegからffmpegにパイプする理由はほとんどありませんが、ffmpegを1つだけ使用することができます。あなたがやりたいことをするプロセス。

オプションの機能:

  • -s 1280x720 -f rawvideo/dev/zero は一般的な入力形式ではないため、入力を説明するオプションがあるため、これらの追加オプションが必要です。

  • -i /dev/zero –ビデオ入力。この例では、「何もない」からビデオストリームを生成するために使用されています。これは、質問の質問者が使用されている入力に関する情報を提供することを拒否したため、この例で使用されました。

  • -ar 48000 -ac 2 -f s16le/dev/zero は一般的なオーディオ形式ではないため、入力を説明するオプション。

  • -i /dev/zero –オーディオ入力。この例では、「何もない」からオーディオストリームを生成するために使用されています。

  • -c copyストリームコピー 、または出力への入力を再多重化します。再エンコードは実行されていないため、プロセスはロスレスです。ストリームのコピーが質問者に受け入れられるかどうかは不明です。代わりに再エンコードが必要なのでしょうか?

  • -f nut –パイプに使用する形式をffmpegに通知する必要があります。ナットはコンテナ形式です。完全なリストについては、ffmpeg -formatsをご覧ください。もう1つの柔軟な形式は-f matroskaですが、質問者からの詳細情報がないと、使用する適切なまたは特定の出力コンテナー形式を提案することはできません。

  • pipe:1pipe protocol を使用してstdoutに出力します。または、番号を省略でき(pipe:のみ)、デフォルトでは書き込みにはstdoutファイル記述子が使用され、読み取りにはstdinが使用されます。

11
llogan

他の答えの1つの問題は、s16leではなくpcm_s16leであることです。また、冗長なパラメータが多数含まれています。

パイプの処理にはflacの代わりにpcmを使用します。処理にかかる時間がはるかに短いためです(PCMは生のオーディオであり、FLACはエンコードに長い時間がかかります)。

とにかく、ここに私がそれをする方法があります。

ffmpeg -i <input video file/stream> -vcodec rawvideo -acodec pcm_s16le pipe:1 | ffmpeg -f rawvideo -i - -vcodec <video output codec> -acodec <audio output codec> -vb <video bitrate if applicable> -ab <audio bitrate if applicable> <final-output-filename>

これは最後に試したときはうまくいきましたが、私の目標はffmpegをffplayにパイプすることでしたが、これは少し異なるプロセスです。

例:

これは、ビデオをffmpegから別のインスタンスに生のビデオ出力と16ビットリトルエンディアンPCMとしてパイプします(24ビットPCMを使用している場合を除き、どちらもロスレス、次にpcm_s24leに置き換えます)。次に、2番目にh.264に変換しますインスタンス、Androidプロジェクトのfraunhoefer AACライブラリを使用します(libfaacはより一般的にffmpegビルドに含まれています。代わりにこれに置き換えることができます。)

ffmpeg -i montypythonsflyingcircus-s1e1.avi -vcodec rawvideo -acodec pcm_s16le pipe:1 | ffmpeg -i - -vcodec libx264 -acodec libfdk_aac -vb 1200k -ab 96k mpfc-s1e01-output.mkv

これが字幕をパイプしない場合、いつでもそれらをSRTにリッピングし、後でそれらを多重化するか、簡単に上記のパイプに追加することができます。

0
Wyatt8740