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")