视频解码期间的采样时间/呈现时间不一致

时间:2014-03-13 03:42:52

标签: android decode encode mediacodec mediaextractor

我正在编写一个可以通过摄像头输入编码视频并通过解码编辑编码步骤处理视频的APP。对于相机,我使用Camera类而不是Intent来配置相机的细节设置。然后我将摄像机帧提供给编码器(API 16中的MediaCodec)和复用器(我使用ffmpeg muxer,因为我想使用4.1设备)。

我按照系统纳米时间测量相机帧的时间码,并选择帧的子集以适合所需的FPS(当前为15)。时间值中有一些小的“噪音”,例如(以毫秒为单位):0,60718,135246,201049,...而不是0,66000,133000,200000,.......

在尝试正确配置多路复用器(As this question)后,我可以制作一个视频(带有AVC编解码器),可以由设备上的视频播放器播放。播放速度是正确的,所以我认为视频应该有正确的帧时间信息。

但是,当我尝试解码视频以执行视频编辑过程时,我遇到了问题。我将标准视频提取/解码步骤用作these samples,如下所示:

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);
        extractor.advance();
    }
}
else
{
    Log.v(TAG, "Decoder dequeueInputBuffer timed out! Try again later");
}

来自getSampleTime()的采样时间在我对视频进行编码时具有正确的值。 (例如,他们正好是0,60718,135246,201049,......在我们身上)。它也是decoder.queueInputBuffer()输入中的显示时间。当解码器继续解码该帧时,我得到帧时间:

int decode_output_index = decoder.dequeueOutputBuffer(decode_buffer_info, TIMEOUT_USEC);
switch (decode_output_index)
{
    ....
    (some negative-value flags in MediaCodec)
    ....
    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);

        ....
    }
}

我希望设置与解码器输入中的时间序列相同的时间序列,但是我从解码器输出的BufferInfo中获得了很多0。解码的帧内容似乎是正确的,但大多数呈现时间值都是0.只有最后几帧具有正确的呈现时间。

我在使用Android 4.3的设备上测试整个相同的过程(即使使用相同的ffmpeg muxer而不是API 18中的MediaMuxer),一切看起来都很好。在4.1 / 4.2设备上,如果我通过设备上的内置摄像头APP捕获视频然后解码视频,那么演示时间也是正确的,尽管时间值也会因摄像头延迟而产生噪音。

视频或解码过程出现什么问题,视频可以正常播放和解码,但采样时间和演示时间不正确?我可能不得不使用一种解决方法来通过采样时间来衡量演示时间(通过使用队列很容易),但我想弄清楚我的工作中是否有任何遗漏部分。

1 个答案:

答案 0 :(得分:4)

无法保证MediaCodec在Android 4.3之前正确处理演示时间戳。这是因为在此之前没有添加确认PTS行为的CTS测试。

我确实记得某些供应商的AVC编解码器中的时间戳处理存在问题。我不记得有关细节,但是如果你在各种4.1 / 4.2设备上运行EncodeDecodeTest的缓冲区到缓冲区和缓冲区到表面的测试,你会发现一些故障。 (当然,你需要去除表面到表面的测试。)

您的时间戳处理代码看起来很好。时间戳不是H.264流的一部分,因此它实际上只是作为元数据通过编解码器转发,而您似乎正在拾取它并在所有正确的位置转发它。最重要的是,如果您正在传递有效的PTS值并获得良好的视频但是垃圾PTS值,则编解码器中的某些内容会错误处理它们。

您需要通过单独传递值来解决它,或者 - 如果输入帧速率始终是常规的 -​​ 通过计算它。从理论上讲,编码器可以对帧进行重新排序,因此将时间戳传递到编码器的顺序可能与它们出现的顺序不同......但是因为你知道制作电影时时间戳是升序的,所以你应该如果在实践中这是一个问题,我们可以对它们进行排序。

另一方面,系统延迟会导致&#34;摆动&#34;如果您在应用框架到达时抓取System.nanoTime(),则会在时间戳值中看到。你可以在Android 4.3中使用Surface输入做得更好,因为SurfaceTexture保存的时间戳设置得更接近捕获帧时的时间戳。 (我知道这对你目前的努力没有用,但是想给未来带来一些希望。)