私は Android でのビデオ トランスコーディングに取り組んでおり、これらのサンプルとして標準的な方法を使用してビデオを抽出/デコードしています。さまざまなビデオ デバイスを搭載したさまざまなデバイスで同じプロセスをテストしたところ、デコーダの入出力のフレーム カウントに問題があることがわかりました。
この質問のようなタイムコードの問題については、次のコードのように、キューを使用して抽出されたビデオ サンプルを記録し、デコーダー フレーム出力を取得したときにキューを確認します。
Queue<Long> sample_time_queue = new LinkedList<Long>();
....
// in transcoding loop
if (is_decode_input_done == false)
{
int decode_input_index = decoder.dequeueInputBuffer(TIMEOUT_USEC);
if (decode_input_index >= 0)
{
ByteBuffer decoder_input_buffer = decode_input_buffers[decode_input_index];
int sample_size = extractor.readSampleData(decoder_input_buffer, 0);
if (sample_size < 0)
{
decoder.queueInputBuffer(decode_input_index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
is_decode_input_done = true;
}
else
{
long sample_time = extractor.getSampleTime();
decoder.queueInputBuffer(decode_input_index, 0, sample_size, sample_time, 0);
sample_time_queue.offer(sample_time);
extractor.advance();
}
}
else
{
DumpLog(TAG, "Decoder dequeueInputBuffer timed out! Try again later");
}
}
....
if (is_decode_output_done == false)
{
int decode_output_index = decoder.dequeueOutputBuffer(decode_buffer_info, TIMEOUT_USEC);
switch (decode_output_index)
{
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
{
....
break;
}
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
{
....
break;
}
case MediaCodec.INFO_TRY_AGAIN_LATER:
{
DumpLog(TAG, "Decoder dequeueOutputBuffer timed out! Try again later");
break;
}
default:
{
ByteBuffer decode_output_buffer = decode_output_buffers[decode_output_index];
long ptime_us = decode_buffer_info.presentationTimeUs;
boolean is_decode_EOS = ((decode_buffer_info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0);
if (is_decode_EOS)
{
// Decoder gives an EOS output.
is_decode_output_done = true;
....
}
else
{
// The frame time may not be consistent for some videos.
// As a workaround, we use a frame time queue to guard this.
long sample_time = sample_time_queue.poll();
if (sample_time == ptime_us)
{
// Very good, the decoder input/output time is consistent.
}
else
{
// If the decoder input/output frame count is consistent, we can trust the sample time.
ptime_us = sample_time;
}
// process this frame
....
}
decoder.releaseOutputBuffer(decode_output_index, false);
}
}
}
場合によっては、デコーダがエラー値 (たとえば、多数の 0) を与える場合、キューは PTS を「修正」できます。ただし、デコーダーの入出力のフレーム数に関しては、まだいくつかの問題があります。
HTC One 801e デバイスでは、コーデック OMX.qcom.video.decoder.avc を使用してビデオをデコードします (MIME タイプ video/avc を使用)。サンプル時間と PTS は、最後のフレームを除いて、フレームでよく一致しています。たとえば、エクストラクタが 100 フレームをフィードし、次に EOS をデコーダにフィードする場合、最初の 99 のデコードされたフレームはまったく同じ時間値を持ちますが、最後のフレームが失われ、デコーダから EOS が出力されます。内蔵カメラ、ffmpeg マルチプレクサー、または Windows 上のビデオ処理 AP によってエンコードされたさまざまなビデオをテストします。いずれも最後の1コマが消えています。
OMX.MTK.VIDEO.DECODER.AVC コーデックの一部のパッドでは、状況がさらに混乱します。一部のビデオは、デコーダからの良好な PTS を持ち、入力/出力フレーム カウントは正しいです (つまり、デコードが完了すると、キューは空になります)。一部のビデオでは、一貫した入力/出力フレーム カウントがあり、デコーダー出力の PTS が正しくありません (キューでそれらを修正することもできます)。一部のビデオでは、デコード中に多くのフレームが失われます。たとえば、エクストラクタは 7 秒のビデオで 210 フレームを取得しますが、デコーダは最後の 180 フレームのみを出力します。同じ回避策を使用して PTS を回復することはできません。
MediaCodec デコーダーの入出力フレーム数を期待する方法はありますか? または、より正確には、エクストラクタが正しいサンプル時間でビデオ サンプルを提供している間に、デコーダによってドロップされたフレームを知るには?