Skip to content

cp: Port FFmpeg video codec support updates to main (2217) into r1.3.0#2222

Merged
thomasdhc merged 1 commit into
r1.3.0from
cherry-pick-2217-r1.3.0
Jul 17, 2026
Merged

cp: Port FFmpeg video codec support updates to main (2217) into r1.3.0#2222
thomasdhc merged 1 commit into
r1.3.0from
cherry-pick-2217-r1.3.0

Conversation

@svcnvidia-nemo-ci

Copy link
Copy Markdown
Contributor

beep boop [🤖]: Hi @suiyoubi 👋,

we've cherry picked #2217 into  for you! 🚀

Please review and approve this cherry pick by your convenience!

* Remove libopenh&libx264 and Add vp9 (#1930)

* fix: remove libopenh264 and replace with libx264

Signed-off-by: Dong Hyuk Chang <9426164+thomasdhc@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: install libx264

Signed-off-by: Dong Hyuk Chang <9426164+thomasdhc@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: drop libx264 support

Signed-off-by: Dong Hyuk Chang <9426164+thomasdhc@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Enhance video transcoding support by adding `libvpx-vp9` as a CPU fallback encoder alongside `h264_nvenc`. Update installation instructions and verification steps to reflect the new encoder options. Modify `ClipTranscodingStage` to validate encoder selection and handle encoding options for both encoders. Update relevant documentation and examples to guide users on using the new encoder.

Signed-off-by: Ao Tang <aot@nvidia.com>

* Minor update

Signed-off-by: Ao Tang <aot@nvidia.com>

* refine docs

Signed-off-by: Ao Tang <aot@nvidia.com>

* refine docs

Signed-off-by: Ao Tang <aot@nvidia.com>

* add back openlibh264 and inform user to install themself if needed

Signed-off-by: Ao Tang <aot@nvidia.com>

* docs format

Signed-off-by: Ao Tang <aot@nvidia.com>

---------

Signed-off-by: Dong Hyuk Chang <9426164+thomasdhc@users.noreply.github.com>
Signed-off-by: Ao Tang <aot@nvidia.com>
Co-authored-by: Dong Hyuk Chang <9426164+thomasdhc@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
(cherry picked from commit 79cacb4)

* Update FFmpeg codec support without PyAV source-build path (#1959)

Port the non-PyAV parts of #1959 onto latest main:

- Keep the strict FFmpeg allowlist installer and update its default tag to n8.1.2.
- Add the opt-in h264/hevc/av1 software decoder and libopenh264 installer.
- Improve video metadata error handling when ffprobe cannot open NVDEC-only codecs in CPU-only stages.
- Update video docs, tutorial preflight checks, and decoder tests for the optional software codec path.
- Make video benchmark entries install the opt-in h264 support at runtime and use libopenh264 explicitly.

The Docker image still follows latest main's #2203 behavior: it does not bake in system FFmpeg, does not force a PyAV source build, and leaves Dockerfile, pyproject.toml, and uv.lock unchanged.

(cherry picked from commit 8055f35)

* fix(video): avoid PyAV motion decode log callback deadlock

* comments addressed

Signed-off-by: Ao Tang <aot@nvidia.com>

* install video codecs for benchmark image build

Signed-off-by: Ao Tang <aot@nvidia.com>

---------

Signed-off-by: Dong Hyuk Chang <9426164+thomasdhc@users.noreply.github.com>
Signed-off-by: Ao Tang <aot@nvidia.com>
Co-authored-by: Dong Hyuk Chang <9426164+thomasdhc@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: NeMo Bot <nemo-bot@nvidia.com>
@svcnvidia-nemo-ci

Copy link
Copy Markdown
Contributor Author

/ok to test ef14b2f

@copy-pr-bot

copy-pr-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@greptile-apps

greptile-apps Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR ports FFmpeg video codec support updates (#2217) to the r1.3.0 release branch. The core change replaces Curator's FFmpeg build strategy with a strict --disable-everything allowlist that routes H.264/HEVC/AV1 decode through NVDEC only, and adds a new opt-in install_h264_support.sh script for containers that need software codecs. On the Python side, libx264 is removed from the supported encoder list and replaced with libvpx-vp9 as the recommended CPU fallback, the default encoder changes to h264_nvenc, and SoftwareCodecMissingError is introduced to give actionable diagnostics when a CPU-only Ray actor can't decode H.264 without a software codec.

  • New install_h264_support.sh: opt-in script that rebuilds FFmpeg from the same upstream tarball with software H.264/HEVC/AV1 decoders added, plus optional libopenh264 encoder via --with-libopenh264.
  • ClipTranscodingStage encoder changes: libvpx-vp9 replaces libx264 as the CPU fallback (with CRF-mode and VBR-mode options), libopenh264 availability is now probed at setup() time and raises a clear RuntimeError with a docs link if absent.
  • SoftwareCodecMissingError: new exception class raised by extract_video_metadata when ffprobe fails with a CUDA/NVDEC signal, catching the case where a CPU-only stage tries to probe an H.264 file without a software decoder; VideoReaderStage now handles this specifically at error level.

Confidence Score: 3/5

Safe to merge with a targeted fix to install_h264_support.sh before release; all Python-side logic is sound but the shell script bug causes misleading license messaging for default users.

The Python changes are well-structured and thoroughly tested. The one issue worth fixing before shipping is in install_h264_support.sh: the NOTE block about license obligations prints on every invocation regardless of whether --with-libopenh264 was passed, because the echo statements landed outside the if guard. Users running the default (LGPL-only) path receive an alarming license warning that does not apply to them. The av.logging.restore_default_callback() change correctly addresses a Ray/GIL deadlock but permanently alters process-wide PyAV logging, which is worth documenting.

docker/common/install_h264_support.sh (echo indentation places the license NOTE outside its if block)

Important Files Changed

Filename Overview
docker/common/install_ffmpeg.sh Rebuilt from scratch with --disable-everything strict allowlist; removes libaom, libass, libdav1d, libvorbis, libwebp, vaapi, and software h264/hevc/av1 decoders in favour of NVDEC-only h264_cuvid/hevc_cuvid/av1_cuvid plus libvpx-vp9. Config structure is clean and coherent.
docker/common/install_h264_support.sh New opt-in script to add software h264/hevc/av1 decoders (and optionally libopenh264 encoder). Contains a bash indentation bug where the NOTE/license-obligation echo block falls outside the if guard and prints unconditionally.
nemo_curator/utils/decoder_utils.py Adds SoftwareCodecMissingError, MP4 FOURCC header sniffing, and CUDA/NVDEC failure signal detection; wraps the existing CalledProcessError path to surface an actionable message. Logic is correct and well-tested.
nemo_curator/stages/video/clipping/clip_extraction_stages.py Removes libx264, adds libvpx-vp9 with CRF-mode and VBR-mode support, changes default encoder to h264_nvenc, adds libopenh264 probe at setup time, and cleans up _add_hwaccel_options. All edge cases are validated at setup() time.
nemo_curator/stages/video/filtering/motion_vector_backend.py Adds av.logging.restore_default_callback() before av.open() to prevent a Ray/GIL deadlock. Fix is correct but the call permanently alters process-wide PyAV logging state.
nemo_curator/stages/video/io/video_reader.py Adds a specific except SoftwareCodecMissingError handler that logs at ERROR level and skips the video, distinct from the generic Exception warning path. Correct layering of exception handling.
tutorials/video/getting-started/video_split_clip_example.py Adds _preflight_check_h264_decoder that probes ffmpeg -decoders at startup and calls sys.exit(2) with a clear message if the chosen encoder produces h264 but no software h264 decoder is available. Also updates default encoder and argparse choices.
benchmarking/tools/ci_benchmark_launcher.sh Switches the video-entry codec install from install_ffmpeg.sh to install_h264_support.sh --with-libopenh264. Since the Dockerfile also pre-installs this, the launcher re-runs the FFmpeg build on every CI run even when the image already has it — redundant but harmless.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Video Input] --> B[VideoReaderStage\npopulate_metadata via ffprobe]
    B -->|success| C[ClipTranscodingStage\nsetup]
    B -->|SoftwareCodecMissingError\nNVDEC-only ffprobe + no GPU| D[log error\nskip video]
    B -->|other error| E[log warning\nskip video]

    C -->|encoder=h264_nvenc| F{use_hwaccel?}
    C -->|encoder=libvpx-vp9\nCPU fallback| G[emit perf warning\n_add_libvpx_vp9_options\nCRF or VBR mode]
    C -->|encoder=libopenh264| H[_verify_libopenh264_available\nffmpeg -encoders probe]
    H -->|libopenh264 found| I[encode with libopenh264]
    H -->|not found| J[RuntimeError\npoint to install_h264_support.sh]

    F -->|yes| K[-hwaccel cuda\n-hwaccel_output_format cuda]
    F -->|no| L[encode with h264_nvenc\nno hwaccel flags]
    K --> M[_add_nvenc_options\nVBR+CQ mode]
    L --> M
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[Video Input] --> B[VideoReaderStage\npopulate_metadata via ffprobe]
    B -->|success| C[ClipTranscodingStage\nsetup]
    B -->|SoftwareCodecMissingError\nNVDEC-only ffprobe + no GPU| D[log error\nskip video]
    B -->|other error| E[log warning\nskip video]

    C -->|encoder=h264_nvenc| F{use_hwaccel?}
    C -->|encoder=libvpx-vp9\nCPU fallback| G[emit perf warning\n_add_libvpx_vp9_options\nCRF or VBR mode]
    C -->|encoder=libopenh264| H[_verify_libopenh264_available\nffmpeg -encoders probe]
    H -->|libopenh264 found| I[encode with libopenh264]
    H -->|not found| J[RuntimeError\npoint to install_h264_support.sh]

    F -->|yes| K[-hwaccel cuda\n-hwaccel_output_format cuda]
    F -->|no| L[encode with h264_nvenc\nno hwaccel flags]
    K --> M[_add_nvenc_options\nVBR+CQ mode]
    L --> M
Loading

Reviews (1): Last reviewed commit: "Port FFmpeg video codec support updates ..." | Re-trigger Greptile

Comment on lines +90 to +96
if [ "$WITH_LIBOPENH264" -eq 1 ]; then
echo " Encoder added: libopenh264 (Cisco OpenH264 binary)"
fi
echo " NOTE: This expands the container's codec footprint beyond Curator's"
echo " default strict FFmpeg allowlist. License obligations of the resulting binaries"
echo " are the user's responsibility."
echo

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 NOTE message always prints regardless of --with-libopenh264

The three echo lines for the NOTE (lines 93–95) are outside the if [ "$WITH_LIBOPENH264" -eq 1 ] block — the fi closes it on line 91. The indentation is misleading: the message about "License obligations of the resulting binaries are the user's responsibility" fires unconditionally, even when running without --with-libopenh264. This directly contradicts usage(), which clearly states the default (LGPL-only decoders) path has no special license obligations beyond LGPL itself. Users who run the script in its default mode will receive an alarming license warning that doesn't apply to them.

Comment on lines +184 to +185
# PyAV's Python log callback can deadlock in Ray workers when FFmpeg decoder
# threads log during codec-context teardown.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 restore_default_callback() is a process-wide global state change

av.logging.restore_default_callback() replaces PyAV's Python-level logging hook with FFmpeg's native C-level handler for the entire process, not just for this av.open() call. If any other code in the same Ray worker later relies on PyAV's Python log callback (e.g. for structured logging or log redirection), those messages will be silently dropped after the first call to decode_for_motion. The fix for the Ray/GIL deadlock is correct in motivation, but consider calling it once at worker startup (e.g. in a @ray.remote initializer) rather than on every decode_for_motion invocation, or document the side effect explicitly so future callers are not surprised.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@thomasdhc
thomasdhc merged commit 614c93b into r1.3.0 Jul 17, 2026
65 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants