我正在尝试修改 android 4.4 中的 screenrecord 源并降低捕获的帧速率,但无论我输入什么值:
format->setFloat("frame-rate", 5);
结果总是一样的(非常高的帧率)
编码器是否忽略了这个属性? 如何控制帧速率?
最佳答案
frame-rate
值不会被忽略,但它不会执行您想要的操作。
frame-rate
和i-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/