tree: a4bca4c6aaaf5d931fcac4c9d6b8d0ef8d6e0608
  1. 7.1.1.bcr.beta.1/
  2. 7.1.1.bcr.beta.10/
  3. 7.1.1.bcr.beta.2/
  4. 7.1.1.bcr.beta.3/
  5. 7.1.1.bcr.beta.4/
  6. 7.1.1.bcr.beta.5/
  7. 7.1.1.bcr.beta.6/
  8. 7.1.1.bcr.beta.7/
  9. 7.1.1.bcr.beta.8/
  10. 7.1.1.bcr.beta.9/
  11. 9.0.1.beta.bcr/
  12. 9.0.1.beta.bcr.1/
  13. 9.0.1.beta.bcr.2/
  14. _overlay_utils.py
  15. component_config_test.py
  16. generate_component_defs.py
  17. generate_component_defs_test.py
  18. generate_component_srcs.py
  19. generate_component_srcs_test.py
  20. generate_config_defs.py
  21. generate_resolved_profiles.py
  22. metadata.json
  23. README.md
modules/ffmpeg/README.md

ffmpeg

The ffmpeg module is a hand crafted port from the original configure build scripts.

Structure

Libraries

Each FFmpeg library is available as a cc_library target with two variants:

TargetDescription
@ffmpeg//:avutilCore utility library (pixel formats, math, logging, memory, etc.)
@ffmpeg//:avcodecCodec encoding/decoding library
@ffmpeg//:avformatContainer muxing/demuxing and I/O library
@ffmpeg//:avfilterAudio/video filter graph library
@ffmpeg//:avdeviceDevice capture/playback library
@ffmpeg//:swresampleAudio resampling and format conversion library
@ffmpeg//:swscaleVideo scaling and pixel format conversion library
@ffmpeg//:postprocVideo post-processing library (7.1.1 only; not present in 9.0.1)

Bare targets vs with_defaults/ targets

Every library and binary target has two forms:

  • Bare target (e.g. @ffmpeg//:avcodec) — all component flags default to False. No codecs, muxers, demuxers, or filters are compiled in unless you explicitly enable them via --@ffmpeg//:enable_<component>=True.
  • with_defaults/ target (e.g. @ffmpeg//:with_defaults/avcodec) — a Bazel transition enables the precomputed component profile for the target platform (OS + CPU). Additional components can be enabled explicitly with the same component flags as bare targets.

Use with_defaults/ for most applications. Use bare targets when you need precise control over binary size by enabling only specific components.

Binaries

TargetDescription
@ffmpeg//:ffmpegMedia transcoding tool
@ffmpeg//:ffprobeMedia stream analysis tool

Both also have with_defaults/ variants (e.g. @ffmpeg//:with_defaults/ffmpeg).

Note that there is no ffplay binary as it requires SDL2 which is not in the bazel-central-registry. (bazelbuild/bazel-central-registry#7077)

Install tree

For consumers that need FFmpeg as files on disk instead of Bazel cc_library targets, the module exposes install-tree targets:

  • @ffmpeg//:gen_dir — the bare, fully user-controlled install tree
  • @ffmpeg//:with_defaults/gen_dir — the platform-default convenience install tree

Building either target materializes an install-style directory tree containing:

  • include/ with the headers exported through Bazel's C++ compilation context for the FFmpeg libraries
  • lib/ with the built FFmpeg libraries and native library dependencies
  • link-flags.txt with additional linker flags needed to consume the libraries

This is useful for packaging workflows, generated toolchains, or integrations that expect an include/ + lib/ layout.

gen_dir follows the bare target behavior: all component flags default to False, and codecs, muxers, demuxers, filters, and protocols are only compiled in when explicitly enabled with --@ffmpeg//:enable_<component>=True. Use with_defaults/gen_dir when you want FFmpeg's platform-appropriate default component set. Extra components can still be enabled with the same flags:

bazel build @ffmpeg//:gen_dir --@ffmpeg//:enable_http_protocol=True
bazel build @ffmpeg//:with_defaults/gen_dir
bazel build @ffmpeg//:with_defaults/gen_dir --@ffmpeg//:enable_http_protocol=True

Component flags

FFmpeg codecs, muxers, demuxers, parsers, bitstream filters, filters, and device I/O modules are individually gated by bool_flag settings. Each flag defaults to False and can be enabled on the command line or via .bazelrc:

bazel build @ffmpeg//:avcodec --@ffmpeg//:enable_h264_decoder=True --@ffmpeg//:enable_aac_decoder=True

The flag naming convention follows FFmpeg's configure script: enable_<component> where <component> is the lowercase name with type suffix. Examples:

FlagComponent type
enable_h264_decoderDecoder
enable_aac_encoderEncoder
enable_mp4_muxerMuxer
enable_mov_demuxerDemuxer
enable_h264_parserParser
enable_h264_mp4toannexb_bsfBitstream filter
enable_scale_filterFilter
enable_alsa_indevInput device
enable_alsa_outdevOutput device

Optional codec libraries in 9.0.1.beta.bcr

The following component flags enable the newly supported BCR libraries. All flags remain False by default, including on with_defaults/ targets. Enabling a flag selects the FFmpeg implementation, the required BCR dependency, and the corresponding CONFIG_LIB* definitions. Encoders and decoders can be selected independently.

BCR moduleFlags (after --@ffmpeg//:)
codec2@1.2.0enable_libcodec2_decoder, enable_libcodec2_encoder
dav1d@1.5.4enable_libdav1d_decoder
gsm@1.0.24enable_libgsm_decoder, enable_libgsm_encoder, enable_libgsm_ms_decoder, enable_libgsm_ms_encoder
lame@4.0enable_libmp3lame_encoder
libjxl@0.12.0.bcr.1enable_libjxl_decoder, enable_libjxl_encoder, enable_libjxl_anim_decoder, enable_libjxl_anim_encoder
openjpeg@2.5.4enable_libopenjpeg_encoder
rav1e@0.8.1enable_librav1e_encoder
shine@3.1.1enable_libshine_encoder
speex@1.2.1enable_libspeex_decoder, enable_libspeex_encoder
twolame@0.4.0enable_libtwolame_encoder
vorbis@1.3.7enable_libvorbis_decoder, enable_libvorbis_encoder
xvidcore@1.3.7enable_libxvid_encoder

For example, add LAME encoding and dav1d decoding to the platform defaults:

bazel build @ffmpeg//:with_defaults/ffmpeg \
    --@ffmpeg//:enable_libmp3lame_encoder=True \
    --@ffmpeg//:enable_libdav1d_decoder=True

JPEG XL requires a C++17 toolchain; with older compiler defaults, pass --cxxopt=-std=c++17 --host_cxxopt=-std=c++17. The animation flags do not require the still-image flags. FFmpeg 9.0.1 no longer has a libopenjpeg_decoder; its native jpeg2000_decoder remains available.

This module version requires Bazel 8.5.0 or later because rav1e@0.8.1 uses rules_rs. Bazel resolves this requirement even when rav1e encoding is off. The BCR version is 9.0.1.beta.bcr; ffmpeg, ffprobe, and av_version_info() continue to report the upstream release version 9.0.1.

Selecting Xvid, x264, or x265 makes the generated FFmpeg license report GPL version 3 or later, including for OpenSSL 3 configurations. This is the overlay‘s common license choice for these external GPL codecs. FFMPEG_LICENSE, CONFIG_GPLV3, and CONFIG_VERSION3 reflect that choice; CONFIG_GPL remains 0, so selecting an external codec does not also enable FFmpeg’s internal GPL implementations or change the default component profile.

Adding new versions

The Bazel overlay relies on several generated .bzl files that are produced by Python scripts and checked into the overlay. When adding a new FFmpeg version, these must be regenerated in order (later steps depend on earlier ones).

StepScriptInputOutputWhen to re-run
1generate_config_defs.pyFFmpeg configure scriptconfig.h.in, libavutil/avconfig.h.in, libavutil/ffversion.h.inNew FFmpeg version (changed ARCH_LIST, HAVE_LIST, CONFIG_LIST)
2generate_component_defs.pyFFmpeg configure and component declarationscomponent_defs.bzlNew FFmpeg version (changed components, deps, CONFIG_EXTRA)
3generate_component_srcs.pyFFmpeg Makefiles + component_defs.bzl + config.h.incomponent_srcs.bzlNew FFmpeg version or changed component/configuration definitions
4generate_resolved_profiles.pycomponent_defs.bzlcomponent_resolved.bzlChanged component_defs.bzl (new components, deps, profiles, available libs)

Why resolution is pre-computed

Unlike FFmpeg‘s configure script which probes the build host for available libraries and features, Bazel’s environment is fully static: library availability is determined by MODULE.bazel, and component selection is a build-time choice via bool_flag settings. There is no system to probe at build time for component selection purposes (system capability detection is handled separately by rules_cc_autoconf).

Because the dependency graph is static, generate_resolved_profiles.py pre-computes the full transitive closure of component dependencies for each (OS, CPU) combination and writes the results as flat dicts in component_resolved.bzl. The structure is:

  • Private _RESOLVED_{OS} dicts with the common resolved state per OS
  • Public RESOLVED_{OS}_{CPU} names (aliased to the OS base when identical, or full dicts when CPU-specific overrides exist)
  • A RESOLVED_COMPONENTS map keyed by "{os}-{cpu}" (e.g. "linux-x86_64") consumed by the transition
  • A RESOLVED_DEFAULT fallback for unknown platforms

The Bazel transition constructs the key from attr.os and attr.cpu, then does a single dict lookup -- no iterative resolution loops at build time.

Quick reference

All generator scripts accept --version <VERSION> to target a specific overlay directory (e.g. 7.1.1.bcr.beta.5). When omitted, the latest version from metadata.json is used automatically.

# Step 1: regenerate config header templates
python3 generate_config_defs.py /path/to/ffmpeg/source

# Step 2: regenerate component declarations and dependencies
python3 generate_component_defs.py /path/to/ffmpeg/source

# Step 3: regenerate per-component source lists
python3 generate_component_srcs.py /path/to/ffmpeg/source

# Step 4: regenerate resolved profiles
python3 generate_resolved_profiles.py

# Target a specific version:
python3 generate_component_srcs.py --version 7.1.1.bcr.beta.5 /path/to/ffmpeg/source

Adding a New FFmpeg Version to the BCR

When adding new versions, the following steps may be helpful.

1. Directory Setup

cp -r modules/ffmpeg/7.1.1 modules/ffmpeg/<NEW_VERSION>

Add "<NEW_VERSION>" to metadata.json "versions" array.

2. Files to Update

All paths below are relative to modules/ffmpeg/<NEW_VERSION>/.

Configuration headers

Regenerate config.h.in and the libavutil header templates with generate_config_defs.py. Preserve the autoconf substitutions in avconfig.h.in and the PACKAGE_VERSION substitution in ffversion.h.in.

component_defs.bzl

Run generate_component_defs.py against the new FFmpeg source tree to update:

VariableSource in configure
COMPONENT_TYPESDECODER_LIST, ENCODER_LIST, MUXER_LIST, DEMUXER_LIST, FILTER_LIST, BSF_LIST, PROTOCOL_LIST, INDEV_LIST, OUTDEV_LIST
PROFILE_EVERYTHINGFlat union of all the above lists
CONFIG_EXTRA_REGISTRYCONFIG_EXTRA block in configure
FILTER_SYMBOL_MAPFILTER_LIST entries mapped to their C symbol names (see libavfilter/allfilters.c)

The generator preserves the default component policy from 7.1.1.bcr.beta.7. Use --policy-version to choose another existing overlay when deliberately changing that policy. It also marks threads available, matching ffmpeg_config_checks.bzl, so the new tee_muxer dependency on fifo_muxer does not remove tee_muxer from the default profile. Optional TLS, external-library, and platform components can require explicit enable_<component> flags even when their dependencies are available.

ffmpeg_config_checks.bzl

Diff the new configure for added/removed/changed feature-detection checks and mirror them as checks.AC_TRY_COMPILE entries.

BUILD.bazel

Update unconditional source lists (_AVUTIL_SRCS, _AVCODEC_BASE_SRCS, etc.) by diffing the new Makefiles' unconditional OBJS = / OBJS += lines. Check for new/removed headers in glob patterns and any new library dependencies.

Test BUILD.bazel files

Add or remove test targets in libavcodec/tests/, libavfilter/tests/, libavutil/tests/, libswscale/tests/, and tests/ if test sources changed.

3. Regenerating component_srcs.bzl

generate_component_srcs.py (at modules/ffmpeg/generate_component_srcs.py) is reusable across versions. It reads PROFILE_EVERYTHING from component_defs.bzl in the target overlay directory, parses OBJS-$(CONFIG_*) lines from the FFmpeg Makefiles, and writes component_srcs.bzl directly to the overlay.

Steps:

  1. Update component_defs.bzl in the overlay first (the script depends on it).
  2. Run:
    python3 generate_component_srcs.py [--version <VERSION>] /path/to/ffmpeg/source
    
  3. New components are handled automatically as long as PROFILE_EVERYTHING is current.

Script tunables

The generator reads subsystem names from CONFIG_EXTRA_REGISTRY. If the new FFmpeg version introduces Makefile changes, these settings inside generate_component_srcs.py may need updating:

VariableWhen to update
OBJECT_PREFIXESA supported architecture adds another object-file group
MAKEFILE_FEATURESStatic Makefile conditions change; keep these consistent with config.h.in
EXTERNAL_FILES_TO_SKIPNew source files require external/platform headers unavailable in the Bazel build
LIBS[].sub_makefilesA library gains a new sub-directory with its own Makefile (e.g. libavcodec/vvc/)

Architecture Makefiles are discovered recursively, including nested HEVC and VVC directories. AArch64 source selections also include neon/Makefile. Sources selected by fixed CONFIG_* settings in config.h.in are emitted unconditionally and excluded from the conditional source groups. The generator includes both STLIBOBJS and SHLIBOBJS: Bazel produces static and shared libraries, and shared libraries need their own copies of FFmpeg's hidden helper definitions, as described in ffbuild/library.mak. Shared-group IDs and definition sections are preserved from the immutable 7.1.1.bcr.beta.7 overlay. Use --reference-version to choose another existing version as the reference; regeneration does not use the output file as input. FFmpeg 9.0.1 omits Makefile entries for its declared JPEG XL animation codecs. The generator supplies missing animation entries from the corresponding still-image entries, while preserving any explicit upstream animation entries.

4. Regenerating component_resolved.bzl

generate_resolved_profiles.py reads component_defs.bzl and pre-computes the resolved component state for each (OS, CPU) combination:

  • linux (aarch64, x86_64): CONFIGURE_DEFAULT_COMPONENTS + LINUX_COMPONENTS
  • macos (aarch64, x86_64): CONFIGURE_DEFAULT_COMPONENTS + MACOS_COMPONENTS
  • windows (aarch64, x86_64): CONFIGURE_DEFAULT_COMPONENTS + WINDOWS_COMPONENTS
  • default: CONFIGURE_DEFAULT_COMPONENTS

Currently the aarch64 and x86_64 profiles for each OS are identical (architecture-specific behavior is handled by select() on source files, not component flags). When CPU-specific component lists are added to component_defs.bzl, the generator will produce distinct dicts per (OS, CPU) pair automatically.

For each profile, the script:

  1. Enables all components in the profile
  2. Propagates select and suggest edges to a fixpoint
  3. Prunes components whose deps, deps_any, conflict, or select constraints are not satisfiable

Run after any change to component_defs.bzl:

python3 generate_resolved_profiles.py [--version <VERSION>]

The script prints a summary of pruned components (with reasons) to stderr, which is useful for verifying that the right components are being disabled.

5. x86 NASM Assembly

FFmpeg uses NASM-syntax .asm files for x86 SIMD optimizations (161 files in 7.1.1). These are compiled via rules_nasm and linked into each library through select() on @platforms//cpu:x86_64.

Key points for new versions:

  • Component .asm files follow the same component flags as their C initialization files.
  • config.asm is auto-generated from config.h by a genrule (converts #define to %define).
  • Template .asm files (e.g. *_template.asm) must be excluded from srcs and listed in hdrs.
  • Include-only files (x86inc.asm, x86util.asm) go in hdrs, not srcs.
  • All nasm_library targets are tagged manual to avoid building on non-x86 platforms.

When updating, check each library's x86/Makefile for new .asm files. The glob patterns in BUILD.bazel pick up additions automatically. If a new library gains x86 assembly, add a corresponding nasm_library target and wire it into the cc_variant_library srcs.

For FFmpeg 9.0.1, libavcodec uses separate NASM targets for x86, x86/hevc, x86/vvc, and x86/h26x: rules_nasm names object files by basename, and those directories contain different sources with the same basename. The experimental libswscale implementation (CONFIG_UNSTABLE) and SVE/SME assembly remain disabled. The ffmpeg graph HTML and CSS are embedded without compression using FFmpeg's ffbuild/bin2c.c.

The 9.0.1 swscale patch keeps ff_sws_chroma_pos available with CONFIG_UNSTABLE=0, because graph.c also calls it from the legacy scaler.

The 9.0.1 BoringSSL patch uses BIO_read for PEM serialization and BoringSSL's SSL_set_mtu and SSL_max_seal_overhead for DTLS, because the pinned BoringSSL does not provide BIO_read_ex, DTLS_set_link_mtu, or DTLS_get_data_mtu.

6. External Library Dependencies

Components that wrap external libraries (e.g. libx264_encoder, alsa_indev) need conditional select() entries in the library target's deps so the external library is linked only when the component is enabled. The pattern is:

deps = [...] + select({
    "//:enable_libx264_encoder_is_true": ["@x264"],
    "//conditions:default": [],
}),

When adding a new version, check COMPONENT_REGISTRY in component_defs.bzl for entries with "deps" fields. If the dep maps to a bazel_dep in MODULE.bazel, ensure a matching select() exists on the appropriate library target (avcodec, avformat, avfilter, or avdevice).

Dependencies listed as "suggest" (e.g. bzlib, lzma) are optional -- the source code guards their usage behind autoconf CONFIG_* flags and compiles without them.

Bug Report Guidance

FFmpeg is a colossal project with enormous configurability. The Bazel Central Registry CI does not have sufficient infrastructure to test all supported FFmpeg components and features.

Consumers are asked to open a pull-request, not just file an issue. The maintainers of this FFmpeg Bazel integration are not users of every component or feature, and cannot be expected to diagnose and fix bugs they cannot reproduce. Fixes depend on contributions from the consumers who encounter them.

When identifying and reporting issues, please take the following steps:

  1. Follow Bazel Central Registry guidance to create the issue.
  2. Open a pull-request with the fix by introducing a new .bcr.* variant for the affected version.
  3. Expand the presubmit pipelines where possible to add regression testing for the affected feature.