Skip to content

Commit 8f75c54

Browse files
authored
BETA CUDA interface: clarify 10->8 bit conversions (#934)
1 parent b60d50f commit 8f75c54

File tree

2 files changed

+28
-12
lines changed

2 files changed

+28
-12
lines changed

src/torchcodec/_core/BetaCudaDeviceInterface.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,30 @@ static UniqueCUvideodecoder createDecoder(CUVIDEOFORMAT* videoFormat) {
108108
" vs supported:",
109109
caps.nMaxMBCount);
110110

111+
// Below we'll set the decoderParams.OutputFormat to NV12, so we need to make
112+
// sure it's actually supported.
113+
TORCH_CHECK(
114+
(caps.nOutputFormatMask >> cudaVideoSurfaceFormat_NV12) & 1,
115+
"NV12 output format is not supported for this configuration. ",
116+
"Codec: ",
117+
static_cast<int>(videoFormat->codec),
118+
", chroma format: ",
119+
static_cast<int>(videoFormat->chroma_format),
120+
", bit depth: ",
121+
videoFormat->bit_depth_luma_minus8 + 8);
122+
111123
// Decoder creation parameters, most are taken from DALI
112124
CUVIDDECODECREATEINFO decoderParams = {};
113125
decoderParams.bitDepthMinus8 = videoFormat->bit_depth_luma_minus8;
114126
decoderParams.ChromaFormat = videoFormat->chroma_format;
127+
// We explicitly request NV12 format, which means 10bit videos will be
128+
// automatically converted to 8bits by NVDEC itself. That is, the raw frames
129+
// we get back from cuvidMapVideoFrame will already be in 8bit format. We
130+
// won't need to do the conversion ourselves, so that's a lot easier.
131+
// In the default interface, we have to do the 10 -> 8bits conversion
132+
// ourselves later in convertAVFrameToFrameOutput(), because FFmpeg explicitly
133+
// requests 10 or 16bits output formats for >8-bit videos!
134+
// https://github.com/FFmpeg/FFmpeg/blob/e05f8acabff468c1382277c1f31fa8e9d90c3202/libavcodec/nvdec.c#L376-L403
115135
decoderParams.OutputFormat = cudaVideoSurfaceFormat_NV12;
116136
decoderParams.ulCreationFlags = cudaVideoCreate_Default;
117137
decoderParams.CodecType = videoFormat->codec;

test/test_decoders.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,18 +1288,15 @@ def test_10bit_videos(self, device, asset):
12881288
# This just validates that we can decode 10-bit videos.
12891289
# TODO validate against the ref that the decoded frames are correct
12901290

1291-
if device == "cuda:0:beta":
1292-
# This fails on our BETA interface on asset 0 (only!) with:
1291+
if device == "cuda:0:beta" and asset is H264_10BITS:
1292+
# This fails on the BETA interface with:
12931293
#
12941294
# RuntimeError: Codec configuration not supported on this GPU.
12951295
# Codec: 4, chroma format: 1, bit depth: 10
12961296
#
1297-
# I don't remember but I suspect asset 0 is actually the one that
1298-
# fallsback to the CPU path on the default CUDA interface (that
1299-
# would make sense)
1300-
# We should investigate if and how we could make that fallback
1301-
# happen for the BETA interface.
1302-
pytest.skip("TODONVDEC P2 - investigate and unskip")
1297+
# It works on the default interface because FFmpeg fallsback to the
1298+
# CPU, while the BETA interface doesn't.
1299+
pytest.skip("Asset not supported by NVDEC")
13031300

13041301
decoder = VideoDecoder(asset.path, device=device)
13051302
decoder.get_frame_at(10)
@@ -1674,12 +1671,11 @@ def test_beta_cuda_interface_backwards(self, asset, seek_mode):
16741671

16751672
@needs_cuda
16761673
def test_beta_cuda_interface_small_h265(self):
1677-
# TODONVDEC P2 investigate why/how the default interface can decode this
1678-
# video.
1674+
# Test to illustrate current difference in behavior between the BETA and
1675+
# the default interface: this video isn't supported by NVDEC, but in the
1676+
# default interface, FFMPEG fallsback to the CPU while we don't.
16791677

1680-
# This is fine on the default interface - why?
16811678
VideoDecoder(H265_VIDEO.path, device="cuda").get_frame_at(0)
1682-
# But it fails on the beta interface due to input validation checks, which we took from DALI!
16831679
with pytest.raises(
16841680
RuntimeError,
16851681
match="Video is too small in at least one dimension. Provided: 128x128 vs supported:144x144",

0 commit comments

Comments
 (0)