0

在我的 Android 应用程序中,我想用 Time-lapse 录制视频。我有一个 InputSurface -> MediaCodec(编码器)-> MediaMuxer。

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

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

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

4

1 回答 1

2

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

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

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

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

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

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

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

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

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

于 2015-06-22T16:00:43.507 回答