C/C++ FFmpeg トランスコーダーに奇妙な問題があります。これは、入力 MP4 (さまざまな入力コーデック) を受け取り、MP4 (x264、ベースライン & AAC LC @44100 サンプル レート、libfdk_aac) を生成して出力します。
結果として得られる mp4 ビデオには、きれいな画像 (x264) があり、オーディオ (AAC LC) も正常に機能しますが、ビデオのちょうど半分までしか再生されません。
オーディオの速度が遅くなったり、引き伸ばされたり、途切れたりすることはありません。動画の途中で止まるだけです。
1 つのヒントは、入力ファイルのサンプル レートが 22050 で、22050/44100 が 0.5 であることかもしれませんが、なぜこれが半分の時間でサウンドを停止させるのか、私にはよくわかりません。このようなエラーが原因で、音が間違った速度になることが予想されます。44100 を強制しようとせず、代わりに受信する sample_rate を使用するだけで、すべてがうまく機能します。
もう 1 つの推測は、pts の計算が機能しないことです。しかし、オーディオは(停止するまで)問題なく聞こえます。ビデオ部分についてもまったく同じことを行い、問題なく動作します。「まさに」、同じコードのようですが、「オーディオ」変数が「ビデオ」変数に置き換えられています。
FFmpeg は、プロセス全体でエラーを報告しません。また、入力からのすべてのパッケージの読み取りが完了した後、decoders/encoders/interleaved_writing をフラッシュします。ビデオではうまく機能するので、私の一般的なアプローチに大きな誤りがあるとは思えません。
これが私のコードの機能です(エラー処理と他のクラスのものを取り除きました):
AudioCodecContext のセットアップ
outContext->_audioCodec = avcodec_find_encoder(outContext->_audioTargetCodecID);
outContext->_audioStream =
avformat_new_stream(outContext->_formatContext, outContext->_audioCodec);
outContext->_audioCodecContext = outContext->_audioStream->codec;
outContext->_audioCodecContext->channels = 2;
outContext->_audioCodecContext->channel_layout = av_get_default_channel_layout(2);
outContext->_audioCodecContext->sample_rate = 44100;
outContext->_audioCodecContext->sample_fmt = outContext->_audioCodec->sample_fmts[0];
outContext->_audioCodecContext->bit_rate = 128000;
outContext->_audioCodecContext->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
outContext->_audioCodecContext->time_base =
(AVRational){1, outContext->_audioCodecContext->sample_rate};
outContext->_audioStream->time_base = (AVRational){1, outContext->_audioCodecContext->sample_rate};
int retVal = avcodec_open2(outContext->_audioCodecContext, outContext->_audioCodec, NULL);
リサンプラのセットアップ
outContext->_audioResamplerContext =
swr_alloc_set_opts( NULL, outContext->_audioCodecContext->channel_layout,
outContext->_audioCodecContext->sample_fmt,
outContext->_audioCodecContext->sample_rate,
_inputContext._audioCodecContext->channel_layout,
_inputContext._audioCodecContext->sample_fmt,
_inputContext._audioCodecContext->sample_rate,
0, NULL);
int retVal = swr_init(outContext->_audioResamplerContext);
デコード
decodedBytes = avcodec_decode_audio4( _inputContext._audioCodecContext,
_inputContext._audioTempFrame,
&p_gotAudioFrame, &_inputContext._currentPacket);
変換中 (もちろん、デコードによってフレームが生成された場合のみ)
int retVal = swr_convert( outContext->_audioResamplerContext,
outContext->_audioConvertedFrame->data,
outContext->_audioConvertedFrame->nb_samples,
(const uint8_t**)_inputContext._audioTempFrame->data,
_inputContext._audioTempFrame->nb_samples);
エンコーディング(もちろん、デコーディングによってフレームが生成された場合のみ)
outContext->_audioConvertedFrame->pts =
av_frame_get_best_effort_timestamp(_inputContext._audioTempFrame);
// Init the new packet
av_init_packet(&outContext->_audioPacket);
outContext->_audioPacket.data = NULL;
outContext->_audioPacket.size = 0;
// Encode
int retVal = avcodec_encode_audio2( outContext->_audioCodecContext,
&outContext->_audioPacket,
outContext->_audioConvertedFrame,
&p_gotPacket);
// Set pts/dts time stamps for writing interleaved
av_packet_rescale_ts( &outContext->_audioPacket,
outContext->_audioCodecContext->time_base,
outContext->_audioStream->time_base);
outContext->_audioPacket.stream_index = outContext->_audioStream->index;
書き込み(もちろん、エンコードによってパケットが生成された場合のみ)
int retVal = av_interleaved_write_frame(outContext->_formatContext, &outContext->_audioPacket);
何がそのような行動を引き起こすのかについて、私はまったく考えていません。