MediaCodec
37c3317fd058; modified for Encode Wiki · CC BY-SA 4.0MediaCodec is Android’s framework for the codec components that ship with a device, which on a phone are mostly hardware blocks in the SoC. FFmpeg wraps its encoders as h264_mediacodec, hevc_mediacodec, vp8_mediacodec, vp9_mediacodec, mpeg4_mediacodec and av1_mediacodec, so you need an FFmpeg build for Android configured with MediaCodec support. The H.264 and HEVC encoders arrived in FFmpeg 6.0, the others in 6.1. It is the Android counterpart of VideoToolbox.
Which codecs you get depends on the phone. H.264 and HEVC encoders are nearly universal, VP9 and AV1 encoders are rarer, and quality, rate-control accuracy and bugs vary between vendors much more than with desktop GPUs.
Hardware or software encoder?
Section titled “Hardware or software encoder?”Hardware encoders in phones are designed for camera recording and video calls: real time, low power, forgiving of bitrate. They lose to x264, x265 and SVT-AV1 at slow presets in quality per bit, and many components accept only bitrate modes. Use MediaCodec for quick on-device transcodes. For anything you keep, encode on a computer. More in NVENC: hardware or software.
Find the encoders on your device
Section titled “Find the encoders on your device”Apps such as Codec Info list every encoder component with its supported codecs, bitrate modes and quality range. Names are vendor-specific, for example c2.exynos.h264.encoder or c2.google.av1.encoder, and you pass the exact name to FFmpeg with -codec_name when a device has several encoders for a codec. Without -codec_name Android picks one for you.
Example commands
Section titled “Example commands”Bitrate modes work on virtually every encoder:
ffmpeg -i input.mkv -c:v hevc_mediacodec -bitrate_mode vbr -b:v 4M -g 60 output.mp4ffmpeg -i input.mkv -c:v av1_mediacodec -codec_name c2.google.av1.encoder -bitrate_mode vbr -b:v 4M -g 60 output.mkvConstant quality only works if the encoder reports BITRATE_MODE_CQ and a quality range:
ffmpeg -i input.mkv -c:v hevc_mediacodec -bitrate_mode cq -global_quality 70 output.mp4FFmpeg passes -global_quality straight to Android’s quality key, so the value must be inside the range the device reports. It has no relation to CRF.
Options that matter
Section titled “Options that matter”| Option | What it does |
|---|---|
-bitrate_mode | cq, vbr, cbr or cbr_fd (CBR that may drop frames). Unset leaves it to the component. Check what the device supports first. |
-b:v | Target bitrate. Required for every mode but cq. |
-g | Keyframe interval. Android takes whole seconds, so FFmpeg divides -g by the integer frame rate and drops the remainder: -g 60 at 30 fps is a 2-second interval, -g 89 is still 2 seconds. Anything under one second, including FFmpeg’s default of 12 frames, becomes one second. |
-codec_name | Pick a specific encoder component. |
-operating_rate | Hint for how fast the encoder will be fed; not a frame-rate conversion. |
-level | AV1 level. FFmpeg’s values are Android bit flags, so use the named values (4.1), never numbers copied from NVENC or Vulkan. |
-qp_i_min … -qp_b_max | Quantizer bounds per frame type, when the component honours them. |
Pitfalls
Section titled “Pitfalls”- Input must be 8-bit
yuv420pornv12; the wrapper does not take 10-bit pixel formats. - Frame-dropping CBR (
cbr_fd) changes frame cadence and is wrong for anything that must stay frame-exact. - An encoder that opens is not necessarily good. Check the output for distortion, missing headers (AV1 and VP9 in particular) and correct timestamps before trusting a device.
Full option reference
Section titled “Full option reference”Every private option of av1_mediacodec in FFmpeg 9.0.2; the H.264, HEVC, VP8, VP9 and MPEG-4 MediaCodec encoders share all of them except -level, which each defines with its own codec’s levels. FFmpeg passes these to the Android component, which may ignore a key it does not support. INT_MAX is 2147483647. -profile:v also accepts main, high and professional for AV1.
| Parameter | Initial default | Accepted values / meaning |
|---|---|---|
-ndk_codec | -1 (auto) | Use the NDK MediaCodec API (1) or the Java one (0); auto uses NDK when no Java VM is available |
-ndk_async | 0 | Use the NDK API in asynchronous mode |
-codec_name | unset | Pick a specific component, e.g. c2.google.av1.encoder; unset uses the default for the MIME type |
-bitrate_mode | -1 (component default) | cq=0, vbr=1, cbr=2, cbr_fd=3 (CBR with frame dropping). cq takes its quality from -global_quality |
-pts_as_dts | -1 (auto) | Copy PTS to DTS; auto enables it when -bf is 0 or unset |
-operating_rate | 0 (unspecified) | Frames per second the component should be able to process, a speed hint; it does not change the output frame rate |
-qp_i_min | -1 (unset) | Lowest QP for I-frames |
-qp_p_min | -1 (unset) | Lowest QP for P-frames |
-qp_b_min | -1 (unset) | Lowest QP for B-frames |
-qp_i_max | -1 (unset) | Highest QP for I-frames |
-qp_p_max | -1 (unset) | Highest QP for P-frames |
-qp_b_max | -1 (unset) | Highest QP for B-frames |
-level | 0 (unspecified) | AV1 level, e.g. 5.1; named 2, 2.1, 2.2, 2.3, 3, 3.1, 3.2, 3.3, 4, 4.1, 4.2, 4.3, 5, 5.1, 5.2, 5.3, 6, 6.1, 6.2, 6.3, 7, 7.1, 7.2, 7.3 map to Android’s AV1Level* bit constants |