FFmpeg APIの使い方(4): エンコード他

前回は、単にエンコードしただけですが、もう少しいじってみます。

固定フレームレート化

前回のコードだと、入力ファイルのフレームのptsをほぼそのまま使っていますが、フレームを増やしたり、減らしたり、順番を変えたりしたい場合、自分でptsを再定義する必要があります。フレームレートは固定にしてptsを再定義してみましょう。前回のコードから少し修正します。decode_allで入力ファイルを全てデコードした後、time_baseを設定したいフレームレートの逆数に設定します。

今回はフレームレートを30000/1001 (29.97fps) にしたいので、こうします。

次に、エンコードするフレームのptsを設定しているところ

これを以下のように変更します。

frame_countはwhileループの外で定義してください。

1フレームごとにframe_countは+1されます。

これで、ptsが再定義され固定フレームレート化します。

ファイル出力しないでプログラムで受け取る

今のプログラムでは、エンコードしたmp4データはファイル出力されますが、ファイル出力しないで、プログラムで受け取るようにしてみましょう。

format_context->pbにセットするAVIOContextを自分で作れば、プログラムで受け取れます。avio_openの代わりに以下のようにコールバック関数を渡してallocします。

bufsizeは適当な大きさにしてください。このio_contextを解放するときは、avio_closeの代わりに以下のようにbufferとio_contextをav_freeします。

 

再エンコードしないで映像と音声を再mux

これまでデコード、エンコードをやってきましたが、デコードもエンコードもしないで、コンテナだけ入れ替えてみましょう。movからmkvに入れ替えてみます。

デコード、エンコードはしないので、av_read_frameで受け取ったパケットをav_interleaved_write_frameで出力に渡せば良さそうです。ではそのコードを書いていきます。

まず、いつものように初期化

入力ファイルを開きます。

出力ファイルを開きます。

出力ファイルのAVFormatContextをallocして、io_contextをセットします。フォーマットはmkvにしたいので、”matroska”と指定します。

入力ファイルのストリーム情報を取得

ここまでは、これまでやってきたことと同じです。

次に、入力ファイルのストリームを列挙して、対応する出力ストリームを作っていきます。

各入力ストリームに対して、コーデックを探して、コーデックがあれば(ffmpegが対応していれば)出力ストリームを作ります。必要なパラメータを入力ストリームからコピーして、stream_mapに入力ストリームと出力ストリームの対応を記憶していきます。

これは、おまじないです。ないとフォーマットによってエラーになるので、書いてください。

出力フォーマットを設定できたので、ファイルを読み書きしていきます。

まず、avformat_write_headerを呼び出します。

で、読み書きしていきます。

先程作ったstream_mapで出力ストリームの番号を取得しています。出力にないストリームは-1にしたので、そのストリームのパケットは捨てます。stream_indexの設定と、タイムスタンプの変換を行って、output_contextに渡しています。

ファイルを全部処理したらav_write_trailerを呼び出して、

解放処理して終わりです。

説明したコード全文を貼っておきます。

y4mで外部エンコーダに渡す

FFmpegに組み込まれているエンコーダではなく、x264やx265などのエンコーダ単体のバイナリにフレームを渡してエンコードしたいときもあると思います。コマンドラインからは以下のようにしてffmpegからx264にフレームを渡すことができますが、これをFFmpeg APIを使ってやってみましょう。

基本的には前回書いたエンコードのコードとほぼ同じです。フォーマットやコーデック指定だけ修正して、x264をプログラムから起動して、データを渡してやればいいだけです。前回書いたエンコードのコードをベースに修正していきます。

まず、出力をファイルではなくプログラムで受け取りたいので、上で書いたようにavio_alloc_contextを使ってAVIOContextを作るように修正します。

write_packetのコールバック関数は、起動したx264の標準入力に書き込むようにします。

writeHandleを作るコードはffmpegとは特に関係ないので、説明はしませんが、CreatePipeで作ったパイプのハンドルです。相方の読み取りハンドルをSTARTUPINFOのhStdInputにセットして、x264のexe起動CreateProcessに渡して、x264の標準入力に書き込むことができるようにしたものです。

あとは、フォーマットを”yuv4mpegpipe”、コーデックを”wrapped_avframe”にすればOK

残りのコードは、io_contextの解放だけ修正が必要ですが、それ以外そのままです。

コードを貼っておきます。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です