Skip to content

Commit 195900f

Browse files
YLouWashUfacebook-github-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 and `enumDecoders()` catches it, returning a non-OK result -- but the SW `hevc`/`h264` decoders were already collected before the throw, 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. 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 decoder instead of returning, so HW->SW fallback works. - Skip HW decoders for monochrome streams, which NVDEC cannot decode. These changes were reviewed as part of D103253728 and D110227872 but never reached master: the landed commit for D103253728 (`a4556645655d`) contains only its four `arvr/projects/compression/xprs/` files, and D110227872 was never landed. This file was last modified on 2026-04-29, so ShipIt exported a copy that had never received them. The GPU path is unchanged. Reviewed By: kongchen1992 Differential Revision: D114806413
1 parent 2f4fc9e commit 195900f

1 file changed

Lines changed: 23 additions & 2 deletions

File tree

vrs/utils/xprs/XprsDecoder.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,18 @@ Ocean::Worker* getWorkers(uint32_t pixels) {
9393
return pixels >= 640 * 480 ? Ocean::WorkerPool::get().scopedWorker()() : nullptr;
9494
}
9595

96+
bool isMonochromePixelFormat(PixelFormat fmt) {
97+
switch (fmt) {
98+
case PixelFormat::GREY8:
99+
case PixelFormat::GREY10:
100+
case PixelFormat::GREY12:
101+
case PixelFormat::GREY16:
102+
return true;
103+
default:
104+
return false;
105+
}
106+
}
107+
96108
} // namespace
97109

98110
namespace vrs::vxprs {
@@ -373,7 +385,11 @@ unique_ptr<utils::DecoderI> xprsDecoderMaker(
373385
const string& codecFormatName = outputImageSpec.getCodecName();
374386
unique_ptr<VXDecoder> decoder;
375387
xprs::CodecList decoders;
376-
if (xprs::enumDecoders(decoders) != XprsResult::OK) {
388+
// enumDecoders can report a failure while still having collected usable SW
389+
// decoders, e.g. when CUDA init throws on a machine with no NVIDIA driver.
390+
(void)xprs::enumDecoders(decoders);
391+
if (decoders.empty()) {
392+
XR_LOGE("xprs::enumDecoders returned no decoders");
377393
return nullptr;
378394
}
379395
xprs::VideoCodecFormat codecFormat{};
@@ -388,6 +404,11 @@ unique_ptr<utils::DecoderI> xprsDecoderMaker(
388404
if (!options.useHwCodecs && dec.hwAccel) {
389405
continue;
390406
}
407+
// NVDEC cannot decode monochrome H.265, used by the grayscale SLAM and
408+
// eye-tracking cameras.
409+
if (dec.hwAccel && isMonochromePixelFormat(outputImageSpec.getPixelFormat())) {
410+
continue;
411+
}
391412
unique_ptr<xprs::IVideoDecoder> xprsDecoder{createDecoder(dec)};
392413
if (!xprsDecoder) {
393414
XR_LOGE("Creating xprs decoder '{}' for {} failed!", dec.implementationName, codecFormatName);
@@ -399,7 +420,7 @@ unique_ptr<utils::DecoderI> xprsDecoderMaker(
399420
dec.implementationName,
400421
codecFormatName,
401422
xprs::getErrorMessage(res));
402-
return nullptr;
423+
continue;
403424
}
404425
decoder = make_unique<VXDecoder>(std::move(xprsDecoder));
405426
if (decoder->decode(encodedFrame, outDecodedFrame, outputImageSpec) == 0) {

0 commit comments

Comments
 (0)