2

私は 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 デコーダーの入出力フレーム数を期待する方法はありますか? または、より正確には、エクストラクタが正しいサンプル時間でビデオ サンプルを提供している間に、デコーダによってドロップされたフレームを知るには?

4

1 に答える 1

2

他の質問と同じ基本的な話です。4.3 より前のバージョンでは、エンコーダーまたはデコーダーに供給されたすべてのフレームが反対側に送信されることを確認するテストはありませんでした。コーデックが 4.3 で修正されるまで、一部のデバイスは特定のテストで最後のフレームを確実にドロップしたことを思い出します。

当時は回避策を探していなかったので、存在するかどうかはわかりません。何かが早期にシャットダウンする原因となっている場合は、EOS を送信する前に遅延すると役立つ場合があります。

デバイスが大量のフレームをドロップするのを見たことがないと思います。これは異常なケースのように思えMediaCodecます。慎重にテストしなくても、同様の方法で機能するすべてのアプリで顕著だったからです。

于 2014-03-17T05:58:57.843 に答える