Skip to content

Commit 82db435

Browse files
committed
WIP
1 parent 234e1d9 commit 82db435

File tree

2 files changed

+43
-33
lines changed

2 files changed

+43
-33
lines changed

src/torchcodec/_core/BetaCudaDeviceInterface.cpp

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ static UniqueCUvideodecoder createDecoder(CUVIDEOFORMAT* videoFormat) {
9898

9999
std::optional<cudaVideoChromaFormat> mapChromaFormat(
100100
const AVPixFmtDescriptor* desc) {
101+
// Return the corresponding cudaVideoChromaFormat if supported, std::nullopt
102+
// otherwise.
101103
TORCH_CHECK(desc != nullptr, "desc can't be null");
102104

103105
if (desc->nb_components == 1) {
@@ -117,6 +119,10 @@ std::optional<cudaVideoChromaFormat> mapChromaFormat(
117119
}
118120

119121
std::optional<cudaVideoCodec> validateCodecSupport(AVCodecID codecId) {
122+
// Return the corresponding cudaVideoCodec if supported, std::nullopt
123+
// otherwise
124+
// Note that we currently return nullopt (and thus fallback to CPU) for some
125+
// codecs that are technically supported by NVDEC, see comment below.
120126
switch (codecId) {
121127
case AV_CODEC_ID_H264:
122128
return cudaVideoCodec_H264;
@@ -148,6 +154,8 @@ std::optional<cudaVideoCodec> validateCodecSupport(AVCodecID codecId) {
148154
}
149155

150156
bool nativeNVDECSupport(const SharedAVCodecContext& codecContext) {
157+
// Return true iff the input video stream is supported by our NVDEC
158+
// implementation.
151159
auto codecType = validateCodecSupport(codecContext->codec_id);
152160
if (!codecType.has_value()) {
153161
return false;
@@ -177,28 +185,25 @@ bool nativeNVDECSupport(const SharedAVCodecContext& codecContext) {
177185
return false;
178186
}
179187

180-
if (!(static_cast<unsigned int>(codecContext->coded_width) >=
181-
caps.nMinWidth &&
182-
static_cast<unsigned int>(codecContext->coded_height) >=
183-
caps.nMinHeight &&
184-
static_cast<unsigned int>(codecContext->coded_width) <=
185-
caps.nMaxWidth &&
186-
static_cast<unsigned int>(codecContext->coded_height) <=
187-
caps.nMaxHeight)) {
188+
auto coded_width = static_cast<unsigned int>(codecContext->coded_width);
189+
auto coded_height = static_cast<unsigned int>(codecContext->coded_height);
190+
if (!(coded_width >= static_cast<unsigned int>(caps.nMinWidth) &&
191+
coded_height >= static_cast<unsigned int>(caps.nMinHeight) &&
192+
coded_width <= caps.nMaxWidth && coded_height <= caps.nMaxHeight)) {
188193
return false;
189194
}
190195

191196
// See nMaxMBCount in cuviddec.h
192197
constexpr unsigned int macroblockConstant = 256;
193-
if (!(static_cast<unsigned int>(
194-
codecContext->coded_width * codecContext->coded_height) /
195-
macroblockConstant <=
196-
caps.nMaxMBCount)) {
198+
if (!(coded_width * coded_height / macroblockConstant <= caps.nMaxMBCount)) {
197199
return false;
198200
}
199201

200-
// We explicitly request NV12 output format in createDecoder(), so we need to
201-
// make sure it's supported.
202+
// We'll set the decoderParams.OutputFormat to NV12, so we need to make
203+
// sure it's actually supported.
204+
// TODO: If this fail, we could consider decoding to something else than NV12
205+
// (like cudaVideoSurfaceFormat_P016) instead of falling back to CPU. This is
206+
// what FFmpeg does.
202207
if (!((caps.nOutputFormatMask >> cudaVideoSurfaceFormat_NV12) & 1)) {
203208
return false;
204209
}

test/test_decoders.py

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,19 +1701,19 @@ def test_beta_cuda_interface_backwards(self, asset, seek_mode):
17011701
assert beta_frame.duration_seconds == ref_frame.duration_seconds
17021702

17031703
@needs_cuda
1704-
def test_beta_cuda_interface_small_h265(self):
1705-
# Test to illustrate current difference in behavior between the BETA and
1706-
# the ffmpeg interface: this video isn't supported by NVDEC, but in the
1707-
# ffmpeg interface, FFMPEG fallsback to the CPU while we don't.
1708-
1709-
print()
1710-
a = VideoDecoder(H265_VIDEO.path, device="cuda").get_frame_at(0)
1711-
# with pytest.raises(
1712-
# RuntimeError,
1713-
# match="Video is too small in at least one dimension. Provided: 128x128 vs supported:144x144",
1714-
# ):
1715-
b = VideoDecoder(H265_VIDEO.path, device="cuda:0:beta").get_frame_at(0)
1716-
torch.testing.assert_close(a.data, b.data, rtol=0, atol=0)
1704+
def test_beta_cuda_interface_cpu_fallback(self):
1705+
# Non-regression test for the CPU fallback behavior of the BETA CUDA
1706+
# interface.
1707+
# We know that the H265_VIDEO asset isn't supported by NVDEC, its
1708+
# dimensions are too small. We also know that the FFmpeg CUDA interface
1709+
# fallbacks to the CPU path in such cases. We assert that we fall back
1710+
# to the CPU path, too.
1711+
1712+
ffmpeg = VideoDecoder(H265_VIDEO.path, device="cuda").get_frame_at(0)
1713+
with set_cuda_backend("beta"):
1714+
beta = VideoDecoder(H265_VIDEO.path, device="cuda").get_frame_at(0)
1715+
1716+
torch.testing.assert_close(ffmpeg.data, beta.data, rtol=0, atol=0)
17171717

17181718
@needs_cuda
17191719
def test_beta_cuda_interface_error(self):
@@ -1739,20 +1739,25 @@ def test_set_cuda_backend(self):
17391739
assert _get_cuda_backend() == "beta"
17401740

17411741
def assert_decoder_uses(decoder, *, expected_backend):
1742+
# TODO: This doesn't work anymore after
1743+
# https://github.com/meta-pytorch/torchcodec/pull/977
1744+
# We need to define a better way to assert which backend a decoder
1745+
# is using.
1746+
return
17421747
# Assert that a decoder instance is using a given backend.
17431748
#
17441749
# We know H265_VIDEO fails on the BETA backend while it works on the
17451750
# ffmpeg one.
1746-
if expected_backend == "ffmpeg":
1747-
decoder.get_frame_at(0) # this would fail if this was BETA
1748-
else:
1749-
with pytest.raises(RuntimeError, match="Video is too small"):
1750-
decoder.get_frame_at(0)
1751+
# if expected_backend == "ffmpeg":
1752+
# decoder.get_frame_at(0) # this would fail if this was BETA
1753+
# else:
1754+
# with pytest.raises(RuntimeError, match="Video is too small"):
1755+
# decoder.get_frame_at(0)
17511756

17521757
# Check that the default is the ffmpeg backend
17531758
assert _get_cuda_backend() == "ffmpeg"
17541759
dec = VideoDecoder(H265_VIDEO.path, device="cuda")
1755-
assert_decoder_uses(dec, expected_backend="ffmpeg")
1760+
# assert_decoder_uses(dec, expected_backend="ffmpeg")
17561761

17571762
# Check the setting "beta" effectively uses the BETA backend.
17581763
# We also show that the affects decoder creation only. When the decoder

0 commit comments

Comments
 (0)