{
  "schemaVersion": 1,
  "contentVersion": "ca42e61ede0a24f789d7287a0001244ad22f4abf",
  "id": "docs/tools/hardware-encoders/mediacodec",
  "collection": "docs",
  "title": "MediaCodec",
  "description": "MediaCodec is Android's interface to the hardware video encoders in a phone's SoC, used from FFmpeg as h264_mediacodec, hevc_mediacodec, vp9_mediacodec and av1_mediacodec.",
  "canonicalUrl": "https://encode.wiki/tools/hardware-encoders/mediacodec/",
  "apiUrl": "https://encode.wiki/api/v1/documents/docs/tools/hardware-encoders/mediacodec.json",
  "markdownUrl": "https://encode.wiki/api/v1/markdown/docs/tools/hardware-encoders/mediacodec.md",
  "status": "current",
  "tags": [
    "migrated"
  ],
  "license": "CC BY-SA 4.0",
  "dates": {
    "lastVerified": "2026-10-08T00:00:00.000Z"
  },
  "authors": [],
  "sources": [
    {
      "title": "FFmpeg 9.0.2 MediaCodec encoders",
      "url": "https://github.com/FFmpeg/FFmpeg/blob/n9.0.2/libavcodec/mediacodecenc.c",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "Android MediaCodecInfo.EncoderCapabilities",
      "url": "https://developer.android.com/reference/android/media/MediaCodecInfo.EncoderCapabilities",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "Android MediaCodecList",
      "url": "https://developer.android.com/reference/android/media/MediaCodecList",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "FFmpeg 9.0.2 codec registry (allcodecs.c)",
      "url": "https://github.com/FFmpeg/FFmpeg/blob/n9.0.2/libavcodec/allcodecs.c",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    }
  ],
  "provenance": {
    "originUrl": "https://github.com/av1-community-contributors/codec-wiki/blob/37c3317fd058b23c71a87679bed5619a98f77752/docs/encoders_hw/mediacodec.mdx",
    "originCommit": "37c3317fd058b23c71a87679bed5619a98f77752",
    "migratedAt": "2026-08-21T00:00:00.000Z",
    "modified": true,
    "originPath": "docs/encoders_hw/mediacodec.mdx"
  },
  "headings": [
    {
      "depth": 2,
      "text": "Hardware or software encoder?",
      "anchor": "hardware-or-software-encoder"
    },
    {
      "depth": 2,
      "text": "Find the encoders on your device",
      "anchor": "find-the-encoders-on-your-device"
    },
    {
      "depth": 2,
      "text": "Example commands",
      "anchor": "example-commands"
    },
    {
      "depth": 2,
      "text": "Options that matter",
      "anchor": "options-that-matter"
    },
    {
      "depth": 2,
      "text": "Pitfalls",
      "anchor": "pitfalls"
    },
    {
      "depth": 2,
      "text": "Full option reference",
      "anchor": "full-option-reference"
    }
  ],
  "sections": [
    {
      "id": "_preamble",
      "title": "Page introduction",
      "depth": 0,
      "canonicalUrl": "https://encode.wiki/tools/hardware-encoders/mediacodec/",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/hardware-encoders/mediacodec/_preamble.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/hardware-encoders/mediacodec/_preamble.md",
      "checksum": "ebcbe5158b10afd7cc25dd26c87a5654612dd984a2ce5042e94fce204a8717ea",
      "bytes": 740
    },
    {
      "id": "hardware-or-software-encoder",
      "title": "Hardware or software encoder?",
      "depth": 2,
      "anchor": "hardware-or-software-encoder",
      "canonicalUrl": "https://encode.wiki/tools/hardware-encoders/mediacodec/#hardware-or-software-encoder",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/hardware-encoders/mediacodec/hardware-or-software-encoder.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/hardware-encoders/mediacodec/hardware-or-software-encoder.md",
      "checksum": "824682e641aabc1b56c5f26c515064833cc6f3d3a66636b7436bb041c7ace3dd",
      "bytes": 574
    },
    {
      "id": "find-the-encoders-on-your-device",
      "title": "Find the encoders on your device",
      "depth": 2,
      "anchor": "find-the-encoders-on-your-device",
      "canonicalUrl": "https://encode.wiki/tools/hardware-encoders/mediacodec/#find-the-encoders-on-your-device",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/hardware-encoders/mediacodec/find-the-encoders-on-your-device.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/hardware-encoders/mediacodec/find-the-encoders-on-your-device.md",
      "checksum": "cf2e50d20882c13e4ee2793260708789432f937be6a9acfc971a19dac8cb42bc",
      "bytes": 467
    },
    {
      "id": "example-commands",
      "title": "Example commands",
      "depth": 2,
      "anchor": "example-commands",
      "canonicalUrl": "https://encode.wiki/tools/hardware-encoders/mediacodec/#example-commands",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/hardware-encoders/mediacodec/example-commands.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/hardware-encoders/mediacodec/example-commands.md",
      "checksum": "18049323ad7bee6b438bc283d364b518153c3d8753c23f6ccc906fb31b7c4175",
      "bytes": 636
    },
    {
      "id": "options-that-matter",
      "title": "Options that matter",
      "depth": 2,
      "anchor": "options-that-matter",
      "canonicalUrl": "https://encode.wiki/tools/hardware-encoders/mediacodec/#options-that-matter",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/hardware-encoders/mediacodec/options-that-matter.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/hardware-encoders/mediacodec/options-that-matter.md",
      "checksum": "dbf5b89bcd097e1dd8ae37ec0cc9eb86abf8e5a846f3ad88985c0109b87938a9",
      "bytes": 963
    },
    {
      "id": "pitfalls",
      "title": "Pitfalls",
      "depth": 2,
      "anchor": "pitfalls",
      "canonicalUrl": "https://encode.wiki/tools/hardware-encoders/mediacodec/#pitfalls",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/hardware-encoders/mediacodec/pitfalls.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/hardware-encoders/mediacodec/pitfalls.md",
      "checksum": "5cbfa10bc706255d1e9eebf9bec92b8c693fbbeafa8344c79cf975d713329636",
      "bytes": 387
    },
    {
      "id": "full-option-reference",
      "title": "Full option reference",
      "depth": 2,
      "anchor": "full-option-reference",
      "canonicalUrl": "https://encode.wiki/tools/hardware-encoders/mediacodec/#full-option-reference",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/hardware-encoders/mediacodec/full-option-reference.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/hardware-encoders/mediacodec/full-option-reference.md",
      "checksum": "b754f6212f2a74f6a961b18e56ee5a6a99b0c319af2e9572f757b7c10b71eac8",
      "bytes": 4274
    }
  ],
  "outboundReferences": [
    "/tools/hardware-encoders/nvenc/#hardware-or-software-encoder",
    "/tools/hardware-encoders/videotoolbox/",
    "/tools/software-encoders/svt-av1/",
    "/tools/software-encoders/x264/",
    "/tools/software-encoders/x265/",
    "https://play.google.com/store/apps/details?id=com.parseus.codecinfo"
  ],
  "checksum": "7af906232650540eb5acdb1b512e0ac673eeb2fef858f3f12b4fd528a2817bdd",
  "contentFormat": "markdown",
  "markdown": "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/).\n\nWhich 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.\n\n## Hardware or software encoder?\n\nHardware 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).\n\n## Find the encoders on your device\n\nApps 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.\n\n## Example commands\n\nBitrate modes work on virtually every encoder:\n\n```sh\nffmpeg -i input.mkv -c:v hevc_mediacodec -bitrate_mode vbr -b:v 4M -g 60 output.mp4\n```\n\n```sh\nffmpeg -i input.mkv -c:v av1_mediacodec -codec_name c2.google.av1.encoder -bitrate_mode vbr -b:v 4M -g 60 output.mkv\n```\n\nConstant quality only works if the encoder reports `BITRATE_MODE_CQ` and a quality range:\n\n```sh\nffmpeg -i input.mkv -c:v hevc_mediacodec -bitrate_mode cq -global_quality 70 output.mp4\n```\n\nFFmpeg 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.\n\n## Options that matter\n\n| Option | What it does |\n| --- | --- |\n| `-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. |\n| `-b:v` | Target bitrate. Required for every mode but `cq`. |\n| `-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. |\n| `-codec_name` | Pick a specific encoder component. |\n| `-operating_rate` | Hint for how fast the encoder will be fed; not a frame-rate conversion. |\n| `-level` | AV1 level. FFmpeg's values are Android bit flags, so use the named values (`4.1`), never numbers copied from NVENC or Vulkan. |\n| `-qp_i_min` … `-qp_b_max` | Quantizer bounds per frame type, when the component honours them. |\n\n## Pitfalls\n\n- Input must be 8-bit `yuv420p` or `nv12`; the wrapper does not take 10-bit pixel formats.\n- Frame-dropping CBR (`cbr_fd`) changes frame cadence and is wrong for anything that must stay frame-exact.\n- 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.\n\n## Full option reference\n\nEvery 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.\n\n| Parameter         | Initial default          | Accepted values / meaning                                                                                                                                                                                        |\n| ----------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `-ndk_codec`      | `-1` (auto)              | Use the NDK MediaCodec API (1) or the Java one (0); auto uses NDK when no Java VM is available                                                                                                                                                       |\n| `-ndk_async`      | `0`                      | Use the NDK API in asynchronous mode                                                                                                                                                                             |\n| `-codec_name`     | unset                    | Pick a specific component, e.g. `c2.google.av1.encoder`; unset uses the default for the MIME type                                                                                                                                                       |\n| `-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`                                                                                               |\n| `-pts_as_dts`     | `-1` (auto)              | Copy PTS to DTS; auto enables it when `-bf` is 0 or unset                                                                                                                                               |\n| `-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                                                                                                                                           |\n| `-qp_i_min`       | `-1` (unset)             | Lowest QP for I-frames                                                                                                                                                               |\n| `-qp_p_min`       | `-1` (unset)             | Lowest QP for P-frames                                                                                                                                                               |\n| `-qp_b_min`       | `-1` (unset)             | Lowest QP for B-frames                                                                                                                                                               |\n| `-qp_i_max`       | `-1` (unset)             | Highest QP for I-frames                                                                                                                                                               |\n| `-qp_p_max`       | `-1` (unset)             | Highest QP for P-frames                                                                                                                                                               |\n| `-qp_b_max`       | `-1` (unset)             | Highest QP for B-frames                                                                                                                                                               |\n| `-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 |\n"
}
