我正在Android中进行视频转码,并使用标准方法these samples来提取/解码视频。我在使用不同视频设备的不同设备上测试相同的过程,我发现解码器输入/输出的帧数有问题。
对于this question中的某些时间码问题,我使用队列记录提取的视频样本,并在获得解码器帧输出时检查队列,如下面的代码: (我省略了与编码相关的代码以使其更清晰)
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);
}
}
}
在某些情况下,队列可以“纠正”#34;如果解码器给出错误值(例如,很多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编解码器的一些打击垫上,事情变得更加混乱。一些视频具有来自解码器的良好PTS并且输入/输出帧计数是正确的(即,在完成解码时队列是空的)。有些视频具有一致的输入/输出帧数和解码器输出中的坏PTS(我仍然可以通过队列纠正它们)。对于某些视频,在解码过程中会丢失大量帧。例如,提取器在7秒视频中获得210帧,但解码器仅输出最后180帧。使用相同的解决方法无法恢复PTS。
有没有办法期望MediaCodec解码器的输入/输出帧数?或者更确切地说,知道解码器丢弃了哪些帧,而提取器为其提供了正确采样时间的视频样本?
答案 0 :(得分:1)
与the other question相同的基本故事。在4.3之前,没有测试确认馈送到编码器或解码器的每个帧都出现在另一侧。我记得有些设备会在某些测试中可靠地丢弃最后一帧,直到编解码器在4.3中被修复。
我当时没有搜索变通方法,所以我不知道是否存在变通方法。在发送EOS之前延迟可能会有所帮助,如果它导致某些事情提前关闭。
我不相信我曾经看过一个设备掉落了大量的帧。这似乎是一个不寻常的案例,因为即使没有经过仔细的测试,任何以类似方式行使MediaCodec
的应用程序都会引人注意。