使用 MediaCodec,如何生成间隔小于 1 秒的关键 i 帧?
Using MediaCodec, how can I generate key i-frames with interval less than 1 second?
MediaFormat.KEY_I_FRAME_INTERVAL 只需要一个整数值,我想这就是控制编码器生成 I 帧的频率的原因吧?那么这是否意味着如果我使用 MediaCodec 我就不可能更频繁地生成 I 帧?
您或许可以通过缩放时间戳来解决这个问题。如果你例如在将它们输入编码器时将时间戳乘以 2,然后在从编码器输出缓冲区上获得的时间戳上除以 2,您应该能够获得半秒的 I 帧间隔。然后您还需要将比特率(和帧率)减半以使其匹配。这当然不理想,但应该能让您获得正确的效果。
我终于找到了这个问题的解决方法!
在需要关键帧之前插入以下代码,然后它将在下一个可用帧上生成关键帧。
Bundle b = new Bundle();
b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
encoder.setParameters(b);
文档说:
A zero value means a stream containing all key frames is requested.
所以你只需要:
MediaFormat format = MediaFormat.createVideoFormat(...);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 0);
它适用于某些设备,但对于某些设备(例如 Nexus 6p)它会产生异常:
E/ACodec: [OMX.qcom.video.encoder.avc] configureCodec returning error -1010
E/ACodec: signalError(omxError 0x80001001, internalError -1010)
E/MediaCodec: Codec reported err 0xfffffc0e, actionCode 0, while in state 3
E/MediaCodec: configure failed with err 0xfffffc0e, resetting...
KEY_I_FRAME_INTERVAL 也可以从 Android 7.1.
开始接收浮点数
因此现在可以做这样的事情了:
val mediaFormat: MediaFormat = MediaFormat.createVideoFormat(VIDEO_MIME_TYPE, 480, 640)
// 30 Frames per second
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30)
// 1 second between key frames!
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1)
// 0.3 seconds between key frame!
mediaFormat.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 0.3F)
MediaFormat.KEY_I_FRAME_INTERVAL 只需要一个整数值,我想这就是控制编码器生成 I 帧的频率的原因吧?那么这是否意味着如果我使用 MediaCodec 我就不可能更频繁地生成 I 帧?
您或许可以通过缩放时间戳来解决这个问题。如果你例如在将它们输入编码器时将时间戳乘以 2,然后在从编码器输出缓冲区上获得的时间戳上除以 2,您应该能够获得半秒的 I 帧间隔。然后您还需要将比特率(和帧率)减半以使其匹配。这当然不理想,但应该能让您获得正确的效果。
我终于找到了这个问题的解决方法!
在需要关键帧之前插入以下代码,然后它将在下一个可用帧上生成关键帧。
Bundle b = new Bundle();
b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
encoder.setParameters(b);
文档说:
A zero value means a stream containing all key frames is requested.
所以你只需要:
MediaFormat format = MediaFormat.createVideoFormat(...);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 0);
它适用于某些设备,但对于某些设备(例如 Nexus 6p)它会产生异常:
E/ACodec: [OMX.qcom.video.encoder.avc] configureCodec returning error -1010
E/ACodec: signalError(omxError 0x80001001, internalError -1010)
E/MediaCodec: Codec reported err 0xfffffc0e, actionCode 0, while in state 3
E/MediaCodec: configure failed with err 0xfffffc0e, resetting...
KEY_I_FRAME_INTERVAL 也可以从 Android 7.1.
开始接收浮点数因此现在可以做这样的事情了:
val mediaFormat: MediaFormat = MediaFormat.createVideoFormat(VIDEO_MIME_TYPE, 480, 640)
// 30 Frames per second
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30)
// 1 second between key frames!
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1)
// 0.3 seconds between key frame!
mediaFormat.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 0.3F)