使用MediaExtractor和MediaCodec在视频播放中跳过帧

时间:2015-05-18 15:57:05

标签: java android video mediacodec mediaextractor

我正在使用MediaExtractor / MediaCodec解码视频并将其渲染为TextureView。作为模板,我使用了以下代码:https://github.com/vecio/MediaCodecDemo/blob/master/src/io/vec/demo/mediacodec/DecodeActivity.java

我希望能够以2倍的速度播放视频。幸运的是,媒体编码/解码速度足够快,因此我可以通过让MediaCodec每帧解码,然后只将每隔一帧渲染到屏幕来实现这一点。然而,这并不是一个很好的解决方案,特别是如果你想以任意值增加播放。例如,在10倍速度下,编解码器无法足够快地解码帧以每30帧以每秒10帧的速度播放。

因此,我希望通过多次调用MediaExtractor.advance()来控制播放,以跳过不需要解码的帧。例如:

        ...
        mDecoder.queueInputBuffer(inIndex, 0, sampleSize, mExtractor.getSampleTime(), 0);
        for (i = 0; i < playbackSpeedIncrease; i++) {
               mExtractor.advance();
        }
        ...

使用此代码,理论上提取器应仅提取每个 nth 帧,其中 n 由变量'playbackSpeedIncrease'定义。例如,如果 n = 5,则应该超过第1-4帧并仅提取第5帧。

但是,这在实践中不起作用。当我运行此代码时,渲染到屏幕的图像会失真:enter image description here

有谁知道这是为什么?有关更好的方式以任意速度播放视频的任何建议都会增加吗?

1 个答案:

答案 0 :(得分:6)

您通常无法使用AVC视频执行此操作。

编码视频具有保存完整图像的“关键”(或“同步”或“I”)帧,但关键帧之间的帧与前一帧保持“差异”。您可以在维基百科上找到一些关于视频编码方法的文章,例如: this one。你得到了令人讨厌的视频,因为你跳过一个关键帧,现在正在针对错误的图像计算差异。

如果您曾经看过视频快速顺畅但快速反向笨拙,例如在TiVo上,这就是为什么:视频解码器快速向前播放,但反过来它只播放I帧,将它们保持在屏幕上足够长的时间以获得所需的速率。在“更快”的前进/后退时,它变得均匀,因为该设备只是在播放I帧。您可以通过观察MediaExtractor所获得的帧上的SAMPLE_FLAG_SYNC标记来执行类似操作。

一般来说,您只能以设备可以解码的速度播放视频,或只播放关键帧。 (如果您对特定编码中特定视频的布局有足够的了解,您可以做得更好,例如播放I和P而不是B,但我不确定在AVC中是否可行。)

I帧的频率由视频编码器确定。它往往是每秒一或两个,但如果你从不同的来源获得视频,那么你可以期望GOP大小(图片组,即I帧之间有多少帧)变化。