android - MediaCodec KEY_FRAME_RATE 似乎被忽略了

标签 android android-ndk android-source android-mediacodec

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

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

结果总是一样的(非常高的帧率)

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

最佳答案

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 帧之间的呈现时间差异约为 17 毫秒,则对第 N-1 帧进行编码或丢弃。

棘手的部分是 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() 的调用,后者将缓冲区提交给视频编码器。

关于android - MediaCodec KEY_FRAME_RATE 似乎被忽略了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22336604/

相关文章:

Android - 动态添加 fragment

java - 如何仅在按住按钮时播放音频?

java - Android Studio 在新项目上从 C++ 支持开始会出现多个错误?

android - 包括另一个 NDK lib 项目中预构建的静态/共享 NDK lib

android - 使用 Android.bp 而不是 Android.mk 将应用程序构建到 Android 系统中

android - 什么是android中的boot.img文件?

android - 提交第一个apk到android平台时

android - 将文件保存在移动用户无法访问的android位置

android - 在 Android NDK 项目中使用 webrtc-58 - 使用 QT 构建时为 "Undefined reference to CopyOnWriteBuffer"

android - 将 git 与使用 repo 检索的 android 源存储库一起使用