# MediaCodec

Canonical URL: https://encode.wiki/tools/hardware-encoders/mediacodec/
Content version: ca42e61ede0a24f789d7287a0001244ad22f4abf
Status: current
License: CC BY-SA 4.0
Checksum (SHA-256): 7af906232650540eb5acdb1b512e0ac673eeb2fef858f3f12b4fd528a2817bdd

MediaCodec 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](/tools/hardware-encoders/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?

Hardware encoders in phones are designed for camera recording and video calls: real time, low power, forgiving of bitrate. They lose to [x264](/tools/software-encoders/x264/), [x265](/tools/software-encoders/x265/) and [SVT-AV1](/tools/software-encoders/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](/tools/hardware-encoders/nvenc/#hardware-or-software-encoder).

## Find the encoders on your device

Apps such as [Codec Info](https://play.google.com/store/apps/details?id=com.parseus.codecinfo) 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

Bitrate modes work on virtually every encoder:

```sh
ffmpeg -i input.mkv -c:v hevc_mediacodec -bitrate_mode vbr -b:v 4M -g 60 output.mp4
```

```sh
ffmpeg -i input.mkv -c:v av1_mediacodec -codec_name c2.google.av1.encoder -bitrate_mode vbr -b:v 4M -g 60 output.mkv
```

Constant quality only works if the encoder reports `BITRATE_MODE_CQ` and a quality range:

```sh
ffmpeg -i input.mkv -c:v hevc_mediacodec -bitrate_mode cq -global_quality 70 output.mp4
```

FFmpeg 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

| 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

- Input must be 8-bit `yuv420p` or `nv12`; 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

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 |
