From 3622b88bd1fd5ca95412f5ee71edd6d11d5e7e4b Mon Sep 17 00:00:00 2001 From: pinjie Date: Fri, 7 Aug 2026 13:39:24 +0000 Subject: [PATCH] support yuv444 Signed-off-by: pinjie --- .../pix_fmt_variants/hevc_hvc1_yuv444p.mp4 | Bin 0 -> 44606 bytes .../src/PyNvBatchAsyncGopDecoder.cpp | 6 +-- .../src/PyNvGopDecoder_common.cpp | 12 +++-- .../src/PyNvVideoReader.cpp | 18 +++++-- .../tests/common/cases.py | 9 ++++ .../tests/test_pix_fmt_detection.py | 49 ++++++++++++++---- 6 files changed, 72 insertions(+), 22 deletions(-) create mode 100644 packages/on_demand_video_decoder/data/pix_fmt_variants/hevc_hvc1_yuv444p.mp4 diff --git a/packages/on_demand_video_decoder/data/pix_fmt_variants/hevc_hvc1_yuv444p.mp4 b/packages/on_demand_video_decoder/data/pix_fmt_variants/hevc_hvc1_yuv444p.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..3fb06c1c4f5f33b27bac4582676034634eb1be3c GIT binary patch literal 44606 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�# z`asved2SH^$qIl_fiAe9H7WqDt*)Y}qOPWfAmBZMG_;B-3Fftk?**vjzYWsV!5P0X!3zz6Zt&5_0??iPAiRkZ&t)Mk2ZOUO*}_>twqjiK$^|1FwZfJk8XXG%L^S`l zg+xWjd-&rC7=*f>o&o}i&{WYTbh|6bipFk&YafX zhw#AD&LDKbT}fSyan}HMFxpB5a8$K2cQiwwNf;~|kjzNrU<%#~M?+|+scRy^O&1}L zRzTSJ6KHreiGmG8QLxI0Lqw=Ejz%NvtExhBsgNjMfI=eE@FXHtAAu(O<1t3+;8N4n zLwHh9zE~s;N5P^nRHJ=}Kr$IYBq7PZVAf4wv!W6y5K5)ueGvqb7m|Ptz!Hqqpao#C zWE##$7l9{|{b@)vm29Mm@FY`>G}Tnqw}=!h)ks52I|vj&pk zf+b^7G$alz2TP$MP(&g&$b&J$9|Ki53I<5vNkZUIR2<+4NHnZ3nM46{5KzI;7!nyv zM0%0P2oM)YA8arX7_0^H4+Pqf1QN*y1V9_+FM)`tup@NXKtwv1^1OOQ}L2epSeTx8? z{zV|*eepCf1d<;^^84HPm|!AUA{t2nT2KK&3&{l>1mFlN-iwF>i3Xz4s6Ke$Rg_Ip zA^8~~FfC&UupkvI0Z+tYHhUldN+Nn~B1kI8_cR=y=*5uR7fbQN8fk$10Eq-v4g3t6 zV-ttGmWuGj0-vG!dw^O4AQTi44AIg-{B3C803Z%&)9;WNe+Gi{#UcW+P<%1aO>on5 zh$upE2o^~Nwj+Zd0zqJ~9t0BF$4E^d7z;&WEE`2)c;i+RP!pJ%iX{N8;{(7@6bZx@ zm=cSk5Q32meNY&8PZY2)!-P;XLsLkI24TQ}1QL}>z*4CY>hVuM$oe!2W{VL9I4p`l z3kK>WQ-dLEXh7E3gh_sX+Xf5(3IlqExc$u;?cqlzc>+CZBhZw;K?>RkP4NU2Pa_Ro z6*Yt(n&e9coU{Q*rqZxvupTN6MWZ4EDR>$b%bOUKM*xB+Q&1q^7^$o51A=(`g@78BOa$c+QUHi;Gzw~k9*87H(x4e>AvWCu%uXVZ zC}axW7l;Pjkx2Cf4yv(9_C*01f*=e>A^DZstsJDHrnQ+^psY{DkqC_F zWkeCg7kC{8OQ4~^bkM{MdqIy52*F_}>I|DO0B8b;3icv^{1=ADP@rrB=^J=D77ubT zh#xAR3aI{6?BB`bZ!#4HBIJK*Bal##)BbxLFd_j9VgyYiK?!8jqk+PJ&He*rq?fH$ z-vHnNTQJCwNMJfJ8d?k@J)l^IS|Lkp(Mf>}O=3Xu+#3G3*tB3W@${)(Pe~Aa&nxUY-^5oyqM+FuKtANx4sTCW528xD2Y5+r}o_H+SN&tg1o+nT! z5s{mY%7~P|EsBC3`oK~~YX5o;Zh0gUifSy4ieT&-fT$iM8ja)&0I;C|AxL5PA_z@r z8DMG|5ZPnkY4|#ZwQ5OhJMAsp#aUGFlZ1R2Kfo7;Vhsn zWUCFT0G;bFa5yv2W)4aPDAzy%A5q`76V$_?Kx5ZHSqGn7*Z}x#P{82>&JT(tpap_D z78G!-0H1(@!NmYg1JsS690KJDC}+SAT*z$FVB?_X2K@TK+vFMm41JZr6cp&NlK{p- zKfMMu2?w04@Q=5)?O3qCvlJpsoT12?{GH$HCEp8R!L) z1JrO6FjkOCLqjjLJCWCeVb1CCDkB!o0 aG!n#641;0}hM2;@(aIAXt-wDuwf_UFJFwya literal 0 HcmV?d00001 diff --git a/packages/on_demand_video_decoder/ext_impl/src/PyNvOnDemandDecoder/src/PyNvBatchAsyncGopDecoder.cpp b/packages/on_demand_video_decoder/ext_impl/src/PyNvOnDemandDecoder/src/PyNvBatchAsyncGopDecoder.cpp index a5a80a36..35ff6e73 100644 --- a/packages/on_demand_video_decoder/ext_impl/src/PyNvOnDemandDecoder/src/PyNvBatchAsyncGopDecoder.cpp +++ b/packages/on_demand_video_decoder/ext_impl/src/PyNvOnDemandDecoder/src/PyNvBatchAsyncGopDecoder.cpp @@ -280,11 +280,11 @@ void PyNvBatchAsyncGopDecoder::build_yuv_frame(Pixel_Format fmt, size_t H, size_ break; // TODO(YUV444_16Bit): same as P016 — LoadDLPack rejects "|u2". case Pixel_Format_YUV444_16Bit: - out.views.push_back(CAIMemoryView{{H, W, 1}, {W, 1, 1}, "|u2", stream_id, dst_ptr, false}); + out.views.push_back(CAIMemoryView{{H, W, 1}, {W * 2, 2, 2}, "|u2", stream_id, dst_ptr, false}); out.views.push_back( - CAIMemoryView{{H, W, 1}, {W, 1, 1}, "|u2", stream_id, dst_ptr + 2 * H * W, false}); + CAIMemoryView{{H, W, 1}, {W * 2, 2, 2}, "|u2", stream_id, dst_ptr + 2 * H * W, false}); out.views.push_back( - CAIMemoryView{{H, W, 1}, {W, 1, 1}, "|u2", stream_id, dst_ptr + 4 * H * W, false}); + CAIMemoryView{{H, W, 1}, {W * 2, 2, 2}, "|u2", stream_id, dst_ptr + 4 * H * W, false}); break; default: // Only NV12 is currently supported. Returning a DecodedFrameExt with an empty extBuf diff --git a/packages/on_demand_video_decoder/ext_impl/src/PyNvOnDemandDecoder/src/PyNvGopDecoder_common.cpp b/packages/on_demand_video_decoder/ext_impl/src/PyNvOnDemandDecoder/src/PyNvGopDecoder_common.cpp index f14e4444..109bc037 100644 --- a/packages/on_demand_video_decoder/ext_impl/src/PyNvOnDemandDecoder/src/PyNvGopDecoder_common.cpp +++ b/packages/on_demand_video_decoder/ext_impl/src/PyNvOnDemandDecoder/src/PyNvGopDecoder_common.cpp @@ -170,17 +170,23 @@ int PyNvGopDecoder::GetYUVFromFrame(NvDecoder* decoder, const uint8_t* pFrame, u (CUdeviceptr)(pFrame_buffer + width * height), false}); // todo: data+width*height assumes both planes are // contiguous. Actual NVENC allocation can have padding? + decoded_frame.views.push_back(CAIMemoryView{{height, width, 1}, + {width, 1, 1}, + "|u1", + reinterpret_cast(decoder->GetStream()), + (CUdeviceptr)(pFrame_buffer + 2 * width * height), + false}); } break; case Pixel_Format_YUV444_16Bit: { decoded_frame.views.push_back(CAIMemoryView{{height, width, 1}, - {width, 1, 1}, + {width * 2, 2, 2}, "|u2", reinterpret_cast(decoder->GetStream()), (CUdeviceptr)(pFrame_buffer), false}); decoded_frame.views.push_back( CAIMemoryView{{height, width, 1}, - {width, 1, 1}, + {width * 2, 2, 2}, "|u2", reinterpret_cast(decoder->GetStream()), (CUdeviceptr)(pFrame_buffer + 2 * (width * height)), @@ -188,7 +194,7 @@ int PyNvGopDecoder::GetYUVFromFrame(NvDecoder* decoder, const uint8_t* pFrame, u // contiguous. Actual NVENC allocation can have padding? decoded_frame.views.push_back( CAIMemoryView{{height, width, 1}, - {width, 1, 1}, + {width * 2, 2, 2}, "|u2", reinterpret_cast(decoder->GetStream()), (CUdeviceptr)(pFrame_buffer + 4 * (width * height)), diff --git a/packages/on_demand_video_decoder/ext_impl/src/PyNvOnDemandDecoder/src/PyNvVideoReader.cpp b/packages/on_demand_video_decoder/ext_impl/src/PyNvOnDemandDecoder/src/PyNvVideoReader.cpp index 9961e651..f216e9fc 100644 --- a/packages/on_demand_video_decoder/ext_impl/src/PyNvOnDemandDecoder/src/PyNvVideoReader.cpp +++ b/packages/on_demand_video_decoder/ext_impl/src/PyNvOnDemandDecoder/src/PyNvVideoReader.cpp @@ -748,29 +748,37 @@ DecodedFrameExt PyNvVideoReader::returnYUVFrame(void* pFrame_buffer, void* pFram (CUdeviceptr)(pFrame_buffer + width * height), false}); // todo: data+width*height assumes both planes are // contiguous. Actual NVENC allocation can have padding? - } - case Pixel_Format_YUV444_16Bit: { frame.views.push_back(CAIMemoryView{{height, width, 1}, {width, 1, 1}, + "|u1", + reinterpret_cast(this->decoder->GetStream()), + (CUdeviceptr)(pFrame_buffer + 2 * width * height), + false}); + } break; + case Pixel_Format_YUV444_16Bit: { + frame.views.push_back(CAIMemoryView{{height, width, 1}, + {width * 2, 2, 2}, "|u2", reinterpret_cast(this->decoder->GetStream()), (CUdeviceptr)(pFrame_buffer), false}); frame.views.push_back(CAIMemoryView{{height, width, 1}, - {width, 1, 1}, + {width * 2, 2, 2}, "|u2", reinterpret_cast(this->decoder->GetStream()), (CUdeviceptr)(pFrame_buffer + 2 * (width * height)), false}); // todo: data+width*height assumes both planes are // contiguous. Actual NVENC allocation can have padding? frame.views.push_back(CAIMemoryView{{height, width, 1}, - {width, 1, 1}, + {width * 2, 2, 2}, "|u2", reinterpret_cast(this->decoder->GetStream()), (CUdeviceptr)(pFrame_buffer + 4 * (width * height)), false}); // todo: data+width*height assumes both planes are // contiguous. Actual NVENC allocation can have padding? - } + } break; + default: + throw std::runtime_error("[ERROR] Unsupported pixel format for YUV output"); } CUDA_DRVAPI_CALL(cuStreamSynchronize(this->decoder->GetStream())); return frame; diff --git a/packages/on_demand_video_decoder/tests/common/cases.py b/packages/on_demand_video_decoder/tests/common/cases.py index 20f6bdcc..ce052312 100644 --- a/packages/on_demand_video_decoder/tests/common/cases.py +++ b/packages/on_demand_video_decoder/tests/common/cases.py @@ -86,6 +86,15 @@ def resource_cases() -> Tuple[ResourceDecodeCase, ...]: torch.uint16, ((256, 256), (128, 128, 2)), ), + ResourceDecodeCase( + "hevc_hvc1_yuv444", + str(PIX_FMT_VARIANTS_DIR / "hevc_hvc1_yuv444p.mp4"), + 33, + "yuv", + "YUV444", + torch.uint8, + ((256, 256), (256, 256), (256, 256)), + ), ResourceDecodeCase( "vfr_h264", str(TEMPORAL_VARIANTS_DIR / "vfr_h264_yuv420p.mp4"), diff --git a/packages/on_demand_video_decoder/tests/test_pix_fmt_detection.py b/packages/on_demand_video_decoder/tests/test_pix_fmt_detection.py index 2c44a63e..0cdf073b 100644 --- a/packages/on_demand_video_decoder/tests/test_pix_fmt_detection.py +++ b/packages/on_demand_video_decoder/tests/test_pix_fmt_detection.py @@ -37,6 +37,11 @@ VARIANTS_DIR = os.path.join(utils.get_data_dir(), "pix_fmt_variants") +PIXEL_FORMAT_NV12 = 3 +PIXEL_FORMAT_YUV444 = 4 +PIXEL_FORMAT_P016 = 5 +PIXEL_FORMAT_YUV444_16BIT = 6 + # Each variant lists the filename, the codec_tag carried by the container, the # bit-depth the stream actually encodes, and the dtype that should appear on the @@ -48,6 +53,7 @@ ("hevc_hev1_yuv420p10le.mp4", "hev1", 10, 5, "|u2", ((256, 256, 1), (128, 128, 2))), ("hevc_hvc1_yuv420p.mp4", "hvc1", 8, 3, "|u1", ((256, 256, 1), (128, 128, 2))), ("hevc_hvc1_yuv420p10le.mp4", "hvc1", 10, 5, "|u2", ((256, 256, 1), (128, 128, 2))), + ("hevc_hvc1_yuv444p.mp4", "hvc1", 8, 4, "|u1", ((256, 256, 1),) * 3), ("h264_avc1_yuv420p.mp4", "avc1", 8, 3, "|u1", ((256, 256, 1), (128, 128, 2))), ] @@ -59,6 +65,34 @@ def _video_path(name): return path +def _expected_plane_strides(pixel_format, luma_width, bytes_per_sample): + if pixel_format in (PIXEL_FORMAT_NV12, PIXEL_FORMAT_P016): + # Semi-planar 4:2:0: one Y plane followed by one interleaved UV plane. + return ( + ( + luma_width * bytes_per_sample, + bytes_per_sample, + bytes_per_sample, + ), + ( + luma_width * bytes_per_sample, + 2 * bytes_per_sample, + bytes_per_sample, + ), + ) + + if pixel_format in (PIXEL_FORMAT_YUV444, PIXEL_FORMAT_YUV444_16BIT): + # Planar 4:4:4: Y, U, and V are three full-resolution planes. + plane_strides = ( + luma_width * bytes_per_sample, + bytes_per_sample, + bytes_per_sample, + ) + return (plane_strides,) * 3 + + raise ValueError(f"unsupported pixel format in stride check: {pixel_format}") + + @pytest.mark.parametrize( "filename, codec_tag, bit_depth, expected_format, expected_dtype, expected_shapes", VARIANTS, @@ -97,17 +131,10 @@ def test_decode_from_gop_round_trip( expected_bytes_per_sample = 2 if bit_depth >= 10 else 1 luma_width = expected_shapes[0][1] - expected_strides = ( - ( - luma_width * expected_bytes_per_sample, - expected_bytes_per_sample, - expected_bytes_per_sample, - ), - ( - luma_width * expected_bytes_per_sample, - 2 * expected_bytes_per_sample, - expected_bytes_per_sample, - ), + expected_strides = _expected_plane_strides( + expected_format, + luma_width, + expected_bytes_per_sample, ) actual_strides = tuple(tuple(plane.__cuda_array_interface__["strides"]) for plane in planes) assert (