HeyThere
HeyThere

Reputation: 583

Using MediaCodec, how can I generate key i-frames with interval less than 1 second?

MediaFormat.KEY_I_FRAME_INTERVAL only takes an integer value, and I assume this is what controls how frequent the encoder generates an I-frame right? So does that mean if I am using MediaCodec I cannot possibly generate I-frames more frequently?

Upvotes: 2

Views: 2922

Answers (4)

Valerio
Valerio

Reputation: 278

KEY_I_FRAME_INTERVAL can also receive float since Android 7.1.

Therefore is now possible to do something like this :

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) 

Upvotes: 0

Oleg Sokolov
Oleg Sokolov

Reputation: 1143

The documentation says that:

A zero value means a stream containing all key frames is requested.

So all what you need is:

MediaFormat format = MediaFormat.createVideoFormat(...);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 0);

It works for some devices, but for some devices (Nexus 6p for example) it produces exception:

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...

Upvotes: 0

HeyThere
HeyThere

Reputation: 583

I finally found a workaround for this issue!

Insert the following code before a key frame is needed, then it will generate a key frame on the next available frame.

        Bundle b = new Bundle();
        b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
        encoder.setParameters(b);

Upvotes: 2

mstorsjo
mstorsjo

Reputation: 13317

You can probably work around this by scaling your timestamps. If you e.g. multiply the timestamps by 2 when inputting them into the encoder, and then divide by 2 on the timestamps you get on the output buffers from the encoder, you should be able to get an I-frame interval of half a second. Then you also need to halve the bitrate (and frame rate) to make it match. This isn't ideal of course, but should allow you to get the right effect.

Upvotes: 1

Related Questions