From e78314e375b4513cac07d2a66855ef57f9e78c3b Mon Sep 17 00:00:00 2001 From: Dylan Pulver Date: Tue, 1 Sep 2026 22:27:10 +0300 Subject: [PATCH] Add yuv422p to supported_np_pix_fmts yuv422p has been handled by both to_ndarray() and from_ndarray() since #2054, but that PR did not add it to supported_np_pix_fmts, so the public set under-reports what the library converts. The existing checks are all of the form 'assert format in supported_np_pix_fmts', which cannot catch a missing entry, so the new test derives the answer from to_ndarray() over av.video.format.names instead. That needs 'names' in the format stub, which was missing. --- av/video/format.pyi | 2 ++ av/video/frame.py | 1 + tests/test_videoframe.py | 21 +++++++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/av/video/format.pyi b/av/video/format.pyi index 1ee0bc7a7..c63072115 100644 --- a/av/video/format.pyi +++ b/av/video/format.pyi @@ -28,3 +28,5 @@ class VideoFormatComponent: height: int def __init__(self, format: VideoFormat, index: int) -> None: ... + +names: set[str] diff --git a/av/video/frame.py b/av/video/frame.py index 699b1534f..839521cc3 100644 --- a/av/video/frame.py +++ b/av/video/frame.py @@ -344,6 +344,7 @@ def _numpy_avbuffer_free( "rgbf32le", "yuv420p", "yuv420p10le", + "yuv422p", "yuv422p10le", "yuv444p", "yuv444p16be", diff --git a/tests/test_videoframe.py b/tests/test_videoframe.py index a25873f7e..8971a75ef 100644 --- a/tests/test_videoframe.py +++ b/tests/test_videoframe.py @@ -755,11 +755,32 @@ def test_ndarray_yuv420p10le_zero_size() -> None: def test_ndarray_yuv422p() -> None: array = numpy.random.randint(0, 256, size=(960, 640), dtype=numpy.uint8) frame = VideoFrame.from_ndarray(array, format="yuv422p") + assert "yuv422p" in supported_np_pix_fmts assert frame.width == 640 and frame.height == 480 assert frame.format.name == "yuv422p" assertNdarraysEqual(frame.to_ndarray(), array) +def test_supported_np_pix_fmts_matches_to_ndarray() -> None: + # supported_np_pix_fmts is public API describing what to_ndarray() accepts, + # so it is checked against to_ndarray() itself rather than against a list + # that would have to be kept in step with it by hand. + converts = set() + for name in av.video.format.names: + try: + VideoFrame(32, 16, name).to_ndarray() + except Exception: + continue + converts.add(name) + + assert converts - supported_np_pix_fmts == set() + + # Names that av.video.format.names does not carry are aliases, so the + # advertised set is checked directly rather than through the sweep. + for name in supported_np_pix_fmts: + VideoFrame(32, 16, name).to_ndarray() + + def test_ndarray_yuv420p_align() -> None: array = numpy.random.randint(0, 256, size=(357, 318), dtype=numpy.uint8) frame = VideoFrame.from_ndarray(array, format="yuv420p")