Skip to content

Commit e8cd598

Browse files
YLouWashUmeta-codesync[bot]
authored andcommitted
{CUDA Decoding} Restore SW decoder fallback in xprsDecoderMaker
Summary: A wheel built with `ENABLE_NVCODEC=ON` segfaults on any machine without an NVIDIA driver. The GitHub CI "Test wheel" job crashes with exit 139 after: Cannot load libcuda.so.1 [XPRS][WARNING]: Loading CUDA functions failed [DecoderFactory][WARNING]: Could not create a decoder for 'H.265'! With no driver, `getNvCodecContext()` throws while probing the HW entries and `enumDecoders()` catches it, returning a non-OK result. The SW `hevc`/`h264` decoders were already collected before the throw (they precede the HW entries in `kPreferredDecoderImplementations`), so the list is usable. `xprsDecoderMaker` bailed on the non-OK result and discarded that list, so no decoder was created and the null decoder was dereferenced downstream. Note the HW decoders never enter the list at all: the throw happens before `codecs.push_back`. Three changes: - Ignore the `enumDecoders()` result and fail only when the decoder list is genuinely empty. This is what fixes the crash. - On decoder `init()` failure, continue to the next candidate instead of returning, so the HW->SW fallback actually runs. This matters on a machine that does have a GPU, where enumeration succeeds but `init()` fails (NVDEC session limit, VRAM pressure). - Return `nullptr` rather than `decoder` when the loop is exhausted. Raised by DevMate: with the `continue` above, a candidate that initialized but failed `decode()` could otherwise be returned by a later iteration's fall-through. A non-null return is also load-bearing in `DecoderFactory::makeDecoder`, which stops at the first maker that returns anything, so handing back a known-bad decoder would prevent other registered makers from being tried. This also removes a pre-existing path to the same stale return. The GPU path is unchanged. Reviewed By: kongchen1992 Differential Revision: D114806413 fbshipit-source-id: e0886dcd9523d3b4cb20dd6efcd96f76c0f1b6fa
1 parent 2f4fc9e commit e8cd598

1 file changed

Lines changed: 10 additions & 3 deletions

File tree

vrs/utils/xprs/XprsDecoder.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,11 @@ unique_ptr<utils::DecoderI> xprsDecoderMaker(
373373
const string& codecFormatName = outputImageSpec.getCodecName();
374374
unique_ptr<VXDecoder> decoder;
375375
xprs::CodecList decoders;
376-
if (xprs::enumDecoders(decoders) != XprsResult::OK) {
376+
// enumDecoders can report a failure while still having collected usable SW
377+
// decoders, e.g. when CUDA init throws on a machine with no NVIDIA driver.
378+
(void)xprs::enumDecoders(decoders);
379+
if (decoders.empty()) {
380+
XR_LOGE("xprs::enumDecoders returned no decoders");
377381
return nullptr;
378382
}
379383
xprs::VideoCodecFormat codecFormat{};
@@ -399,7 +403,7 @@ unique_ptr<utils::DecoderI> xprsDecoderMaker(
399403
dec.implementationName,
400404
codecFormatName,
401405
xprs::getErrorMessage(res));
402-
return nullptr;
406+
continue;
403407
}
404408
decoder = make_unique<VXDecoder>(std::move(xprsDecoder));
405409
if (decoder->decode(encodedFrame, outDecodedFrame, outputImageSpec) == 0) {
@@ -424,8 +428,11 @@ unique_ptr<utils::DecoderI> xprsDecoderMaker(
424428
}
425429
}
426430
}
431+
// Reaching here means no candidate both initialized and decoded, so never
432+
// hand back the last instance: it may have failed decode, and a non-null
433+
// return stops DecoderFactory from trying any other registered maker.
427434
TelemetryLogger::error(context, "No decoder found for " + codecFormatName);
428-
return decoder;
435+
return nullptr;
429436
}
430437

431438
} // namespace vrs::vxprs

0 commit comments

Comments
 (0)