user1874818
user1874818

Reputation: 41

Android MediaCodec: how to request a key frame when encoding

In Android4.1, a key frame is often requested in a real-time encoding application. But how to do it using MediaCodec object? The current Android4.2 SDK seems not support it.

Upvotes: 4

Views: 6068

Answers (3)

landerlyoung
landerlyoung

Reputation: 1810

MediaCodec has a method called setParameters which comes to the rescue. In Kotlin you can do it like:

fun yieldKeyFrame(): Boolean {
    val param = Bundle()
    param.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0)
    try {
        videoEncoder.setParameters(param)
        return true
    } catch (e: IllegalStateException) {
        return false
    }
}

in above snippet, the videoEncoder is an instance of MediaCodec configured to encode.

Upvotes: 3

user2394982
user2394982

Reputation: 61

You can produce random keyframe by specifying MediaCodec.BUFFER_FLAG_SYNC_FRAME when queuing input buffers:

MediaCodec codec = MediaCodec.createDecoderByType(type);
codec.configure(format, ...);
codec.start();
ByteBuffer[] inputBuffers = codec.getInputBuffers();
for (;;) {
  int inputBufferIndex = codec.dequeueInputBuffer(timeoutUs);
  if (inputBufferIndex >= 0) {
    // fill inputBuffers[inputBufferIndex] with valid data
    ...
    codec.queueInputBuffer(inputBufferIndex, 0, inputBuffers[inputBufferIndex].limit(), presentationTime,
        isKeyFrame ? MediaCodec.BUFFER_FLAG_SYNC_FRAME : 0);
  }

}

Stumbled upon the need to insert random keyframe when encoding video on Galaxy Nexus. On it, MediaCodec didn't automatically produce keyframe at the start of the video.

Upvotes: 6

user2320957
user2320957

Reputation: 21

You can request a periodic key frame by setting the KEY_I_FRAME_INTERVAL key when configuring the encoder. In the example below I am requesting one every two seconds. I've omitted the other keys like frame rate or color format for the sake of clarity, but you will still want to include them.

    encoder = MediaCodec.createByCodecName(codecInfo.getName());
    MediaFormat inputFormat = MediaFormat.createVideoFormat(mimeType, width, height);

    /* ..... set various format options here ..... */
    inputFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2);

    encoder.configure(inputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
    encoder.start();

I suspect, however, that what you are really asking is how to request a random key frame while encoding, like at the start of a cut scene. Unfortunately I haven't seen an interface for that. It is possible that stopping and restarting the encoder would have the effect of creating a new key frame at the restart. When I have the opportunity to try that, I'll post the result here.

I hope this was helpful.

Thad Phetteplace - GLACI, Inc.

Upvotes: 2

Related Questions