簡體   English   中英

Android MediaCodec解碼器輸入/輸出幀數

[英]Android MediaCodec decoder input/output frame count

我正在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編碼的不同視頻。 他們所有的最后一幀都消失了。

在使用OMX.MTK.VIDEO.DECODER.AVC編解碼器的某些鍵盤上,情況變得更加混亂。 一些視頻具有來自解碼器的良好PTS,並且輸入/輸出幀計數正確(即,解碼完成后隊列為空)。 某些視頻的輸入/輸出幀數一致,而解碼器輸出中的PTS不好(我仍然可以通過隊列來糾正它們)。 對於某些視頻,解碼期間會丟失很多幀。 例如,提取器在7秒鍾的視頻中獲得210幀,但解碼器僅輸出最后180幀。 使用相同的解決方法無法恢復PTS。

有什么方法可以預期MediaCodec解碼器的輸入/輸出幀數嗎? 或更准確地說,是要知道解碼器丟棄了哪些幀,而提取器為它提供了具有正確采樣時間的視頻采樣?

其他問題相同的基本故事。 在4.3之前的版本中,沒有測試可以確認輸入到編碼器或解碼器的每個幀都來自另一側。 我記得某些設備在某些測試中會可靠地丟棄最后一幀,直到編解碼器在4.3中得到修復。

當時我沒有尋找解決方法,所以我不知道是否存在。 如果EOS導致某些東西提前關閉,則延遲發送EOS可能會有所幫助。

我不相信我曾經見過設備掉落大量幀。 這似乎是一種不尋常的情況,因為即使沒有經過仔細測試,在以類似方式行使MediaCodec任何應用程序中也會注意到這一點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM