Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/195.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android MediaCodec解码器输入/输出帧计数_Android_Codec_Decoder_Android Mediacodec_Mediaextractor - Fatal编程技术网

Android MediaCodec解码器输入/输出帧计数

Android MediaCodec解码器输入/输出帧计数,android,codec,decoder,android-mediacodec,mediaextractor,Android,Codec,Decoder,Android Mediacodec,Mediaextractor,我正在Android中进行视频转码,并使用标准方法提取/解码视频。我用不同的视频设备在不同的设备上测试了相同的过程,发现解码器输入/输出的帧数有问题 对于中的一些时间码问题,我使用队列记录提取的视频样本,并在获得解码器帧输出时检查队列,如以下代码: (为了更清楚,我省略了编码相关代码) Queue sample\u time\u Queue=new LinkedList(); .... //在转码循环中 如果(是否解码输入完成==false) { int decode\u input\u ind

我正在Android中进行视频转码,并使用标准方法提取/解码视频。我用不同的视频设备在不同的设备上测试了相同的过程,发现解码器输入/输出的帧数有问题

对于中的一些时间码问题,我使用队列记录提取的视频样本,并在获得解码器帧输出时检查队列,如以下代码: (为了更清楚,我省略了编码相关代码)

Queue sample\u time\u Queue=new LinkedList();
....
//在转码循环中
如果(是否解码输入完成==false)
{
int decode\u input\u index=decoder.dequeueInputBuffer(超时\u USEC);
如果(解码输入索引>=0)
{
ByteBuffer解码器\输入\缓冲=解码\输入\缓冲[解码\输入\索引];
int sample\u size=extractor.readSampleData(解码器输入缓冲区,0);
如果(样本大小<0)
{
解码器.queueInputBuffer(解码\u流的输入\u索引、0、0、MediaCodec.BUFFER\u标志\u结束\u);
_解码_输入_完成=真;
}
其他的
{
长样本时间=提取器.getSampleTime();
queueInputBuffer(解码输入索引,0,样本大小,样本时间,0);
样本时间队列。报价(样本时间);
提取器;
}
}
其他的
{
DumpLog(标记“Decoder dequeueInputBuffer超时!请稍后重试”);
}
}
....
如果(是解码还是输出完成==false)
{
int decode\u output\u index=decoder.dequeueOutputBuffer(decode\u buffer\u info,TIMEOUT\u USEC);
开关(解码输出索引)
{
案例MediaCodec.INFO\u输出\u缓冲区\u已更改:
{
....
打破
}
案例MediaCodec.INFO\u输出\u格式\u已更改:
{
....
打破
}
case MediaCodec.INFO\u请稍后再试:
{
DumpLog(标记“Decoder dequeueOutputBuffer超时!请稍后重试”);
打破
}
违约:
{
ByteBuffer解码输出缓冲区=解码输出缓冲区[解码输出索引];
long ptime\u us=解码缓冲区\u info.presentationTimeUs;
布尔值是_decode_EOS=((解码_buffer_info.flags&MediaCodec.buffer_FLAG_END_流)!=0);
如果(是解码EOS)
{
//解码器给出EOS输出。
_解码_输出_完成=真;
....                                    
}
其他的
{
//某些视频的帧时间可能不一致。
//作为一种解决方法,我们使用帧时间队列来保护这一点。
long sample_time=sample_time_queue.poll();
如果(样本时间==ptime\U us)
{
//很好,解码器的输入/输出时间是一致的。
}
其他的
{
//如果解码器输入/输出帧计数一致,我们可以信任采样时间。
ptime\u us=采样时间;
}
//处理此框架
....
}
decoder.releaseOutputBuffer(解码输出索引,false);
}
}
}
在某些情况下,如果解码器给出错误值(例如大量0),队列可以“纠正”PTS。然而,关于解码器输入/输出的帧计数仍然存在一些问题

在HTC One 801e设备上,我使用编解码器OMX.qcom.video.decoder.avc对视频进行解码(使用MIME类型video/avc)。除最后一帧外,其余帧的采样时间和PTS匹配良好。 例如,如果提取器提供100帧,然后EOS到解码器,则前99个解码帧具有完全相同的时间值,但最后一帧丢失,我从解码器获得输出EOS。我测试了内置摄像头、ffmpeg muxer或Windows上的视频处理AP编码的不同视频。最后一帧都消失了

在一些带有OMX.MTK.VIDEO.DECODER.AVC编解码器的PAD上,事情变得更加混乱。一些视频具有来自解码器的良好PTS,且输入/输出帧计数正确(即解码完成时队列为空)。有些视频具有一致的输入/输出帧数,解码器输出中的PTS不好(我仍然可以通过队列更正它们)。对于某些视频,解码过程中会丢失很多帧。例如,提取器在7秒视频中获得210帧,但解码器仅输出最后180帧。使用相同的解决方法无法恢复临时技术秘书处

是否有任何方法可以预期MediaCodec解码器的输入/输出帧计数?或者更准确地说,当提取器以正确的采样时间为其提供视频样本时,要知道解码器丢弃了哪些帧?

与中相同的基本情况。在4.3之前,没有任何测试确认馈送到编码器或解码器的每一帧都来自另一侧。我记得在某些测试中,某些设备会可靠地丢弃最后一帧,直到4.3中修复了编解码器

我当时没有寻找解决办法,所以我不知道是否存在。如果在发送EOS之前延迟可能会导致某些东西提前关闭


我不相信我曾经看到过一个设备掉了大量的帧。这似乎是一个不寻常的情况,因为在任何以类似方式运行
MediaCodec
的应用程序中,即使没有仔细测试,也会注意到这一点。

你能确认每台设备上使用的安卓版本吗?同样,4.3之前的版本没有任何保证。在4.3的开发过程中,在某些测试中,qcom设备上出现了丢失最后一帧的问题,因此如果是4.1/4.2设备,也就不会有什么意外了。我无法访问带有MTK编解码器的设备,因此无法在那里发表评论。你能从PTS值判断它是否以规则的模式丢弃帧吗
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);
        }
    }
}