MediaCodec的KEY_FRAME_RATE似乎被忽略了。

10

我正在尝试修改Android 4.4中screenrecord的源代码,并降低捕获帧速率,但无论我输入什么值:


I am trying to modify the source for screenrecord in Android 4.4 and lower the captured frame rate, but no matter what value I put in:
format->setFloat("frame-rate", 5);

结果始终相同(非常高的帧速率)

编码器是否忽略了这个属性?我如何控制帧率?


2
看起来这个值只用于将一些头信息写入生成的mp4文件中,而不是用于控制捕获速率。要做到这一点,您需要修改编码器循环并相应地丢弃帧。 - marcone
1个回答

11
frame-rate值不会被忽略,但它并不能做到你想要的效果。 frame-ratei-frame-interval的组合决定了编码输出中I帧(也称为“同步帧”)出现的频率。帧速率值在某些设备上达到bitrate目标可能也会发挥作用,但我不确定(例如参见此帖)。 MediaCodec编码器不会丢帧。如果您想降低帧率,必须通过向其发送更少的帧来实现。 screenrecord命令不会以固定的帧速率对屏幕进行“采样”。相反,它从表面合成器(SurfaceFlinger)接收的每一帧都会发送到编码器,并有适当的时间戳。如果screenrecord接收到60帧/秒,则将输出60fps。如果它连续接收10帧,然后5秒钟没有任何内容,然后再来几个,那么输出文件中就会有这样的内容。
您可以修改screenrecord以删除帧,但必须小心。如果您尝试将最大帧速率从60fps降低到30fps,通过跳过每个其他帧来实现,那么在“frame0-frame1-long_pause-frame2”序列中,您会跳过frame1,视频将停留在frame0上,显示不完整的动画。因此,您需要缓冲一帧,如果frame N-1和frame N之间的呈现时间差大约为17ms,则编码或删除frame N-1。
棘手的部分是screenrecord在其默认操作模式下,直接将帧传输到编码器,所以你只能看到经过编码后的输出。你不能任意丢弃单个帧的编码数据,所以你真正想要的是让编码器在第一时间就不要看到它们。如果使用screenrecord v1.1源代码,可以利用“overlay”模式(用于--bugreport),让帧在传输到编码器之前通过screenrecord
在某些方面,编写一个后处理程序以降低帧率可能会更简单。我不知道通过解码和重新编码视频会失去多少质量。
更新:要进行粗略操作的示例,请将以下内容添加到processFrame_l():
     int64_t droppedFrames = 0;
+    {
+        static int flipflop = 0;
+        flipflop = 1 - flipflop;
+        if (flipflop) {
+            printf("dropping frame %lld\n", frameNumber);
+            return;
+        }
+    }

     if (mLastFrameNumber > 0) {

请注意,此操作发生在updateTexImage()之后,该操作获取下一个缓冲区,并跳过对swapBuffers()的调用,这将提交缓冲区给视频编码器。

Note this comes after updateTexImage(), which acquires the next buffer, and skips the call to swapBuffers(), which submits the buffer to the video encoder.

我正在尝试使用screenrecord v1.1来设置帧率,但是一直没有成功。如果我只是在threadLoop中跳过帧,它不起作用。我该如何成功地跳过帧? - jacob
你的补丁很好用,但是在最后一帧有问题。当没有帧到达时,最后一帧不会被捕获。如果没有帧到达,我能强制重复最后一帧吗? - jacob
1
swapBuffers()看作是“提交我刚刚绘制的内容到视频编码器”。如果你只调用swapBuffers()而没有绘制任何东西,你会感到不满意。updateTexImage()的意思是“获取从合成器中最新的内容,并将其放入GLES纹理中”。因此,如果你查看processFrame_l(),你可以看到它获取了新帧(或旧帧,如果没有新内容出现),渲染了一些文本,然后将其提交给视频编码器。 - fadden
像往常一样,您的建议非常有效。我添加了一个线程,根据所需的帧速率唤醒过度,这样我就不会丢失最后一帧。但是我认为编码器会在重复使用相同帧时(使用低比特率时)增强输出,但实际上并没有。有没有办法告诉它这样做? - jacob
这取决于H.264编码器。我不知道你可以依靠什么行为。 - fadden
显示剩余14条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接