我正在尝试修改android 4.4中的screenrecord源代码,并降低捕获的帧速率,但不管我输入了什么值:
format->setFloat("frame-rate", 5);
结果总是一样的(非常高的帧速率)
编码器是否忽略此属性?
如何控制帧速率?
最佳答案
frame-rate
值不会被忽略,但它不会做您想要的事情。frame-rate
和i-frame-interval
的组合确定i帧(也称为“同步帧”)在编码输出中出现的频率。在某些设备上,帧速率值也可能在满足bitrate
目标方面发挥作用,但我对此不确定(请参见this post)。
编码器不丢弃帧。如果要降低帧速率,必须通过向其发送较少的帧来实现。MediaCodec
命令不会以固定帧速率“采样”屏幕。相反,它从曲面合成器(surfaceflinger)接收到的每一帧都被发送到编码器,并带有适当的时间戳。如果ScreenRecord每秒接收60帧,则输出每秒60帧。如果它连续快速地接收10帧,然后5秒钟内不接收任何内容,然后再接收几帧,那么您将在输出文件中得到确切的结果。
您可以修改screenrecord
以删除帧,但必须小心一点。如果尝试通过每隔一帧删除一次将最大帧速率从60fps降低到30fps,则可能会在“frame0-frame1-long_pause-frame2”序列中删除frame1,而视频将保留frame0,从而显示不完全的动画。所以你需要缓冲一个帧,然后编码或删除帧n-1,如果它和帧n之间的呈现时间差是~17ms。
棘手的是,在默认的操作模式下,screenrecord
将帧定向到编码器而不接触它们,所以您所看到的只是编码输出。您不能随意丢弃编码数据的各个帧,因此您确实希望防止编码器首先看到它们。如果使用screenrecord v1.1源,您可以进入用于screenrecord
的“覆盖”模式,使帧在到达编码器的路上通过--bugreport
。
在某些方面,编写降低帧速率的后处理器可能更简单。我不知道解码和重新编码视频会损失多少质量。
更新:对于如何粗略地执行此操作的示例,请将其添加到screenrecord
:
int64_t droppedFrames = 0;
+ {
+ static int flipflop = 0;
+ flipflop = 1 - flipflop;
+ if (flipflop) {
+ printf("dropping frame %lld\n", frameNumber);
+ return;
+ }
+ }
if (mLastFrameNumber > 0) {
注意,这是在获取下一个缓冲区的
processFrame_l()
之后发生的,并跳过对updateTexImage()
的调用,后者将缓冲区提交给视频编码器。