MediaCodec KEY_FRAME_RATE似乎被忽略了

时间:2014-03-11 21:04:27

标签: android android-ndk android-source mediacodec

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

format->setFloat("frame-rate", 5);

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

编码器是否忽略此属性? 如何控制帧速率?

1 个答案:

答案 0 :(得分:9)

frame-rate值不会被忽略,但它不能达到你想要的效果。

frame-ratei-frame-interval的组合决定了I帧(也称为“同步帧”)出现在编码输出中的频率。帧速率值也可能在某些设备上满足bitrate目标时起作用,但我不确定(请参阅例如this post)。

MediaCodec编码器不会丢帧。如果你想降低帧速率,你必须通过向它发送更少的帧来实现。

screenrecord命令不以固定的帧速率“采样”屏幕。相反,它从表面合成器(SurfaceFlinger)接收的每个帧都会以适当的时间戳发送到编码器。如果screenrecord每秒接收60帧,则输出为60fps。如果它连续快速接收10帧,接着是5秒后没有任何帧,接着是更多帧,你将在输出文件中得到它。

您可以修改screenrecord以删除帧,但您必须要小心。如果你试图通过丢弃每隔一帧来将最大帧速率从60fps降低到30fps,那么你冒的风险是在“frame0 - frame1 - long_pause - frame2”序列中你将丢弃frame1,并且视频将保留在frame0上相反,显示一个不完整的动画。所以你需要缓冲一个帧,然后编码或丢弃帧N-1,如果它与帧N之间的呈现时间差异是~17ms。

棘手的部分是screenrecord在其默认操作模式下,将帧指向编码器而不触及它们,所以你看到的只是编码输出。您不能随意丢弃编码数据的各个帧,因此您确实希望阻止编码器首先看到它们。如果您使用screenrecord v1.1来源,则可以使用“覆盖”模式(用于--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(),将缓冲区提交给视频编码器。