Skip to content

Add support for full-range VP9 video decoding#6367

Open
JanuszL wants to merge 2 commits into
NVIDIA:mainfrom
JanuszL:support-vp9-full-range-video
Open

Add support for full-range VP9 video decoding#6367
JanuszL wants to merge 2 commits into
NVIDIA:mainfrom
JanuszL:support-vp9-full-range-video

Conversation

@JanuszL
Copy link
Copy Markdown
Contributor

@JanuszL JanuszL commented May 25, 2026

Category:

Bug fix (non-breaking change which fixes an issue)

Description:

This PR fixes full-range video handling for VP9 video decoding.

The GPU video decoders used NVDEC's video_full_range_flag to choose the
YUV-to-RGB conversion range. NVDEC does not always report this flag for VP9,
even when FFmpeg stream metadata marks the video as full range. The GPU and
legacy GPU paths now fall back to FFmpeg color_range metadata when NVDEC
does not report full range.

The CPU decoder also now propagates full-range source information to
libswscale so VP9 CPU decoding uses the expected conversion range.

Additional information:

Affected modules and functionalities:

  • fn.readers.video GPU NVDEC conversion range selection
  • fn.experimental.readers.video GPU decoder range selection
  • fn.experimental.readers.video CPU decoder libswscale conversion setup
  • Full dynamic range video tests

Key points relevant for the review:

  • The GPU change keeps NVDEC's range flag as the primary source and only
    falls back to FFmpeg color_range == AVCOL_RANGE_JPEG.
  • The CPU path sets libswscale source range from decoded frame metadata,
    falling back to stream metadata when the frame leaves it unspecified.
  • Test coverage uses the existing H.264 full-range asset and the new VP9
    full-range asset from DALI_extra.

Tests:

  • Existing tests apply
  • New tests added
    • Python tests
    • GTests
    • Benchmark
    • Other
  • N/A

Checklist

Documentation

  • Existing documentation applies
  • Documentation updated
    • Docstring
    • Doxygen
    • RST
    • Jupyter
    • Other
  • N/A

DALI team only

Requirements

  • Implements new requirements
  • Affects existing requirements
  • N/A

REQ IDs: N/A

JIRA TASK: N/A

@JanuszL JanuszL mentioned this pull request May 25, 2026
18 tasks
- Use FFmpeg color-range metadata as a fallback when NVDEC does not
  report full-range video. Pass full-range source details to libswscale
  in the CPU decoder and extend full dynamic range video coverage
  to the VP9 sample.

Signed-off-by: Janusz Lisiecki <jlisiecki@nvidia.com>
@JanuszL JanuszL force-pushed the support-vp9-full-range-video branch from 65316c0 to 539de9e Compare May 26, 2026 06:59
@JanuszL
Copy link
Copy Markdown
Contributor Author

JanuszL commented May 26, 2026

!build

@dali-automaton
Copy link
Copy Markdown
Collaborator

CI MESSAGE: [52611502]: BUILD STARTED

@dali-automaton
Copy link
Copy Markdown
Collaborator

CI MESSAGE: [52611502]: BUILD PASSED

@JanuszL JanuszL marked this pull request as ready for review May 26, 2026 20:18
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 26, 2026

Greptile Summary

This PR fixes full-range color handling for VP9 video decoding across all three decode paths in DALI: the legacy NVDEC path (NvDecoder), the newer GPU path (FramesDecoderGpu), and the CPU path (FramesDecoderCpu). The root cause is that NVDEC does not reliably set video_full_range_flag for VP9, so the GPU paths now OR that flag with codec_params_->color_range == AVCOL_RANGE_JPEG from FFmpeg; the CPU path feeds the frame-level (and stream-level fallback) color range into libswscale via sws_setColorspaceDetails.

  • GPU paths (frames_decoder_gpu.cc, nvdecoder.cc): fallback to FFmpeg color_range metadata when NVDEC's video_full_range_flag is zero, using a simple OR to keep NVDEC as the primary source.
  • CPU path (frames_decoder_cpu.cc): propagates per-frame color_range (falling back to stream-level codec_params_->color_range when the frame leaves it unspecified) into sws_setColorspaceDetails; a cached sws_src_full_range_ flag prevents the colorspace-detail update call from running on every frame.
  • Tests (test_video.py): existing full-range test functions are refactored into parameterized forms covering both H.264 and the new VP9 asset; the CPU reader is added as a new test variant.

Confidence Score: 5/5

Safe to merge. The fallback logic is additive (NVDEC flag is still the primary source), the sws_setColorspaceDetails call is correctly guarded against per-frame overhead, and the new VP9 test assets are present in DALI_extra.

All three decode paths apply the fix consistently and conservatively: NVDEC's own flag remains authoritative when set, and FFmpeg metadata is only used as a fallback. The CPU path's per-frame caching correctly amortizes the colorspace-detail update to once per range transition. Test coverage validates the full-range VP9 round-trip for every affected path, and the reference assets are confirmed present in DALI_extra.

No files require special attention.

Important Files Changed

Filename Overview
dali/operators/video/frames_decoder_cpu.cc Adds sws_setColorspaceDetails call after context creation to pass full-range metadata; guarded by sws_src_full_range_ so it only fires when the range changes.
dali/operators/video/frames_decoder_gpu.cc Extracts full-range detection into IsFullRange, OR-ing NVDEC's video_full_range_flag with codec_params_->color_range == AVCOL_RANGE_JPEG.
dali/operators/video/legacy/reader/nvdecoder/nvdecoder.cc Adds full_range_from_codecpar_ member initialized in constructor; OR-ed with video_full_range_flag in handle_sequence_ to provide FFmpeg fallback for VP9.
dali/test/python/decoder/test_video.py Parameterizes existing full-range tests over H.264 and VP9 assets; adds CPU+VP9 variant; DALI_extra assets confirmed present.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Video File / Stream] --> B{Decode Path}
    B -->|Legacy GPU| C[NvDecoder: full_range_from_codecpar_]
    C --> D[handle_sequence_]
    D --> E[full_range = video_full_range_flag OR full_range_from_codecpar_]
    E --> F[Convert YUV to RGB with correct range]
    B -->|New GPU| G[FramesDecoderGpu::IsFullRange]
    G --> H[video_full_range_flag OR codec_params color_range == JPEG]
    H --> I{Full range?}
    I -->|Yes| J[YUV_TO_RGB_FULL_RANGE]
    I -->|No| K[YUV_TO_RGB]
    B -->|CPU| L[FramesDecoderCpu::CopyToOutput]
    L --> M[src_full_range from frame or codecpar fallback]
    M --> N{Range changed vs cached?}
    N -->|Yes| O[sws_setColorspaceDetails + update cache]
    N -->|No| P[Skip]
    O --> Q[sws_scale to output]
    P --> Q
Loading

Reviews (3): Last reviewed commit: "Avoid redundant sws_setColorspaceDetails..." | Re-trigger Greptile

Comment thread dali/operators/video/frames_decoder_cpu.cc Outdated
Cache the last applied source full-range flag in FramesDecoderCpu and
only call sws_setColorspaceDetails when it changes. Previously the call
ran for every decoded frame even though sws_ctx_ is created once,
forcing libswscale to recompute coefficient tables unnecessarily.

Also bump copyright headers on the five video decoder files touched in
this PR to include 2026.

Signed-off-by: Janusz Lisiecki <jlisiecki@nvidia.com>
@JanuszL
Copy link
Copy Markdown
Contributor Author

JanuszL commented May 26, 2026

@greptile review

@JanuszL
Copy link
Copy Markdown
Contributor Author

JanuszL commented May 26, 2026

!build

@dali-automaton
Copy link
Copy Markdown
Collaborator

CI MESSAGE: [52699111]: BUILD STARTED

@dali-automaton
Copy link
Copy Markdown
Collaborator

CI MESSAGE: [52699111]: BUILD PASSED

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants