2

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?

HeyThere
  • 503
  • 1
  • 5
  • 19
  • Here's [a link](https://stackoverflow.com/a/58933377/10960892) to my answer to similar question: – puksec Nov 19 '19 at 11:51
  • Here's a link to my answer to the similar question: https://stackoverflow.com/a/58933377/10960892 – puksec Nov 19 '19 at 11:52

4 Answers4

2

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);
HeyThere
  • 503
  • 1
  • 5
  • 19
1

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.

mstorsjo
  • 12,983
  • 2
  • 39
  • 62
0

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...
Oleg Sokolov
  • 1,134
  • 1
  • 12
  • 19
0

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) 
Valerio
  • 278
  • 1
  • 6
  • 18