Configure FFmpeg MediaCodec Encoding on Android

This article provides a practical guide on how to configure and enable hardware-accelerated video encoding in FFmpeg on Android using the MediaCodec API. By leveraging the device’s system-on-chip (SoC) hardware encoder, you can drastically reduce CPU usage, lower battery consumption, and increase video processing speeds in your Android applications.

1. Build FFmpeg with MediaCodec and JNI Support

To use MediaCodec hardware acceleration, you must compile FFmpeg with JNI (Java Native Interface) and MediaCodec modules enabled. During the configuration step of your FFmpeg build script, ensure the following flags are included:

./configure \
  --enable-jni \
  --enable-mediacodec \
  --enable-decoder=h264_mediacodec \
  --enable-encoder=h264_mediacodec \
  --enable-hwaccel=h264_mediacodec \
  --enable-parser=h264

Note: You can swap or add hevc_mediacodec (H.265) or vp9_mediacodec depending on your target format and device support.

2. Initialize the JVM in Your Native Code

Because MediaCodec is a Java-based API on Android, native C/C++ FFmpeg code must access the Java Virtual Machine (JVM). You must register the JVM pointer when your native library loads.

In your JNI initialization code (typically JNI_OnLoad), call av_jni_set_java_vm:

#include <libavcodec/jni.h>

jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    av_jni_set_java_vm(vm, NULL);
    return JNI_VERSION_1_6;
}

Without this initialization step, FFmpeg will fail to instantiate the MediaCodec instance and will fallback to software encoding.

3. Configure the Encoder in Your Application

When setting up your FFmpeg encoding pipeline in C/C++, you must explicitly request the MediaCodec encoder by name.

Locating the Encoder

Instead of using avcodec_find_encoder(AV_CODEC_ID_H264), lookup the encoder by name:

const AVCodec *codec = avcodec_find_encoder_by_name("h264_mediacodec");
if (!codec) {
    // Fallback or handle error (hardware encoding not supported)
}

Setting Codec Context Parameters

MediaCodec requires specific pixel formats and parameters. Standard Android devices typically expect NV12 or YUV420P color formats.

AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
codec_ctx->width = 1920;
codec_ctx->height = 1080;
codec_ctx->time_base = (AVRational){1, 30};
codec_ctx->framerate = (AVRational){30, 1};
codec_ctx->pix_fmt = AV_PIX_FMT_NV12; // Standard for MediaCodec
codec_ctx->bit_rate = 4000000;         // 4 Mbps

// Open the encoder
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
    // Handle initialization failure
}

4. Run via Command Line (FFmpeg CLI)

If you are executing FFmpeg command-line arguments using a mobile wrapper (such as FFmpeg-Kit), specify the codec using the -c:v flag:

ffmpeg -i input.yuv -pix_fmt nv12 -s 1920x1080 -c:v h264_mediacodec output.mp4

To verify that the hardware encoder is being utilized, check the console output log. You should see references to h264_mediacodec and system logcat messages from OMX or Codec2 initiating the hardware codec.