在我的Android应用中,我想用Time-lapse录制视频。我有一个InputSurface - > MediaCodec(编码器) - > MediaMuxer。
但是如果我想加速视频(例如:x3),我会得到帧率很高的结果视频。例如:正常速度我得到视频30fps。如果我加速(x3),我得到视频90fps。
由于视频的帧率很高,我手机的视频播放器无法正常播放视频(电脑的视频播放器播放视频没有任何问题)。所以我认为我必须丢弃一些帧以保持帧速率低于60fps。
但我不知道如何丢帧。因为在AVC流中,我们有I,B,P帧,它们可能依赖于其他帧,所以我们不能随意丢弃它们。有人能帮助我吗?
答案 0 :(得分: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.7ms(60fps),但显示器未更新时仍有间隙。如果您的录音每隔一帧抓取一次,您将获得:
[1] <10+ seconds pass> [3] [5] ...
你最后在错误的帧上暂停了10秒钟,如果1和2之间有很多移动,这可能会很明显。正确地完成这项工作需要在帧丢失方面有一些智能,例如根据需要重复前一帧以产生恒定帧率30fps视频。