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

Android 视频解码期间采样时间/呈现时间不一致,android,decode,encode,android-mediacodec,mediaextractor,Android,Decode,Encode,Android Mediacodec,Mediaextractor,我正在编写一个应用程序,可以通过摄像机输入对视频进行编码,并通过解码编辑编码步骤对视频进行处理。对于相机,我使用camera类,而不是配置相机的细节设置。然后我将相机帧馈送到API 16中的编码器MediaCodec和muxer,因为我想在4.1设备上工作,所以我使用ffmpeg muxer 我通过system nano time测量相机帧的时间码,并选择帧子集以适合当前所需的FPS 15。时间值中存在一些小噪音,例如毫秒:0、60718、135246、201049、。。。而不是66000133

我正在编写一个应用程序,可以通过摄像机输入对视频进行编码,并通过解码编辑编码步骤对视频进行处理。对于相机,我使用camera类,而不是配置相机的细节设置。然后我将相机帧馈送到API 16中的编码器MediaCodec和muxer,因为我想在4.1设备上工作,所以我使用ffmpeg muxer

我通过system nano time测量相机帧的时间码,并选择帧子集以适合当前所需的FPS 15。时间值中存在一些小噪音,例如毫秒:0、60718、135246、201049、。。。而不是6600013300200000

在尝试将多路复用器正确配置为之后,我可以使用AVC编解码器生成视频,该视频可以由设备上的视频播放器播放。播放速度是正确的,所以我认为视频应该有正确的帧时间信息

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

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");
}
我希望设置与解码器输入中的时间序列相同的时间序列,但我从解码器输出的BufferInfo中获得了很多0。解码的帧内容似乎正确,但大多数显示时间值为0。只有最后几帧具有正确的显示时间

我在安卓4.3设备上测试了整个相同的过程,即使使用相同的ffmpeg muxer,而不是API 18中的MediaMuxer,一切看起来都很好。在4.1/4.2设备上,如果我通过设备上的内置摄像头应用程序捕获视频,然后解码视频,则显示时间也正确,尽管由于摄像头延迟,时间值也有噪音


当视频可以正常播放和解码,但采样时间正确且呈现时间不好时,视频或解码过程有什么问题?我可能需要使用一种变通方法,通过采样时间来测量演示时间。使用队列很容易,但我想知道我的工作中是否缺少任何部分。

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

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

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

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


另一方面,如果在帧到达应用程序时抓取system.nanoTime,系统中的延迟将导致时间戳值中出现的抖动。在Android 4.3中,使用Surface输入可以做得更好一些,因为SurfaceTexture保存的时间戳设置得更接近捕获帧的时间。我知道这对你目前的努力没有帮助,但我想给你的未来带来一些希望。

谢谢你的回复。在最后一部分中,系统时间可能不规则,但我无法通过摄像机调用的帧获得更精确的时间测量,因此我仍然使用系统时间,并设计了一个简单的算法,将任意时间序列过滤到15FPS左右。无法向ffmpeg发送重新排序的时间戳,如果中的下一个时间戳不大于上一个,则跳过该时间戳。你给ffmpeg发送了什么时间戳?我看到你说它们是正确的,只是为了再次检查?我记得它需要一些基于时基的pkt.pts计算。den你试过在这些设备上运行CTS测试吗?解码器的输出帧时间是否等于输入帧时间?CTS测试在本机摄像头应用程序编码的视频上正常工作。时间戳总是递增的,解码器的输入/输出是一致的。对于我自己制作的视频,提取的采样时间是正确的,并成为解码器输入,但输出不一致。@fadden,在CameraCaptureActivity中的Grafika中,当您录制视频时,即25秒 ds的视频,然后播放它,我们会发现时间戳问题。文件将是25秒的视频,但帧偏移到较早的时间。因此视频帧实际上在21秒后停止,最后一帧刚刚出现。你必须在real player上运行视频,而不是在应用程序内观看。知道如何解决此问题吗?开始录制前的UpdateMaximage可能会导致此偏移?谢谢:
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);

        ....
    }
}