【问题标题】:How to drop frames while recording with MediaCodec and InputSurface?使用 MediaCodec 和 InputSurface 录制时如何丢帧?
【发布时间】:2015-09-07 10:33:41
【问题描述】:

在我的 Android 应用中,我想用延时拍摄录制视频。我有一个 InputSurface -> MediaCodec (encoder) -> MediaMuxer.

但如果我想加快视频速度(例如:x3),我会得到具有非常高帧率的结果视频。例如:以正常速度,我得到 30fps 的视频。如果我加速 (x3),我可以得到 90fps 的视频。

由于视频帧率高,我手机的视频播放器无法正常播放视频(电脑的视频播放器播放视频没有问题)。所以我认为我必须丢掉一些帧以保持帧率低于 60fps。

但我不知道如何丢帧。因为在 AVC 流中,我们有 I、B、P 帧,它们可能依赖于其他帧,所以我们不能随意丢弃它们。有人可以帮帮我吗?

【问题讨论】:

    标签: android frame android-mediacodec mediamuxer timelapse


    【解决方案1】:

    您必须对流进行解码和重新编码,同时丢帧。只需将 60fps 视频中的时间戳减半即可获得 120fps 视频。

    请注意,原始 H.264 视频流中没有嵌入任何时间戳。由 MediaExtractor 解析并由 MediaMuxer 添加的 .mp4 包装器保存了计时​​信息。 MediaCodec 接口似乎接受并产生表示时间戳,但它主要只是传递它以帮助您保持与正确帧相关联的时间戳——帧可以由编码器重新排序。 (一些编码器确实会查看时间戳以尝试满足比特率目标,因此您不能传递虚假值。)

    您可以执行DecodeEditEncode example 之类的操作。当解码器调用releaseOutputBuffer() 时,您只需为每隔一帧的渲染参数传递“false”即可。

    如果您要接受来自其他来源的视频帧,例如用于屏幕录制的虚拟显示器,则不能将编码器的 Surface 直接交给显示器。您必须从中创建一个 SurfaceTexture create a Surface,然后在帧到达时对其进行处理。 DecodeEditEncode 示例正是这样做的,它使用 GLES 着色器修改每一帧。

    不过,屏幕录制确实存在额外的困难。来自虚拟显示器的帧在生成时到达,而不是以固定的帧速率,产生可变帧速率的视频。例如,您可能有这样的帧序列:

    [1] [2] <10 seconds pass> [3] [4] [5] ...
    

    虽然大多数帧的到达时间间隔为 16.7 毫秒 (60fps),但在显示未更新时会出现间隙。如果您的录制每隔一帧抓取一次,您将获得:

    [1] <10+ seconds pass> [3] [5] ...
    

    您最终会在错误的帧上暂停 10 秒,如果 12 之间有大量移动,这可能会很明显。使这项工作正常工作需要一些智能丢帧,例如根据需要重复上一帧以生成恒定帧率 30fps 视频。

    【讨论】:

    • 感谢您的回答。我从虚拟显示器接收视频帧。我有两个问题。首先:我在 DecodeEditEncode 示例中看不到 SurfaceTexture 类。在那里,作者使用了一个自定义类(InputSurface),其中包含一个 Surface。第二个问题:你说我必须创建一个SurfaceTexture,然后从它创建一个Surface。但是如何将创建的 Surface 传递给 Encoder?我的意思是 Surface1 = new Surface(mSurfaceTexture) 和 Surface2 = Encoder.createInputSurface()。所以我们有 2 个 Surface 对象。我该怎么办?
    • 要查看帮助类,请备份到目录:android.googlesource.com/platform/cts/+/jb-mr2-release/tests/…。 SurfaceTexture 是 OutputSurface.java 的一部分,它是发送解码视频的地方。编码器使用的Surface只能来自getInputSurface(); this 被传递给 InputSurface 构造函数。解码器 -> 输出表面 -> GLES -> 输入表面 -> 编码器。因此,您可以将 Surface 从 OutputSurface#getSurface() 传递到您的虚拟显示器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-12
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    • 2021-02-12
    • 1970-01-01
    • 2012-11-21
    相关资源
    最近更新 更多