我正在尝试修改android 4.4中的screenrecord源并降低捕获的帧速率,但无论我放入什么值:
format->setFloat("frame-rate", 5);
结果始终相同(帧速率非常高)
编码器是否忽略此属性? 如何控制帧速率?
答案 0 :(得分:9)
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之间的呈现时间差异是~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()
,将缓冲区提交给视频编码器。