Skip to content

Commit bca1f10

Browse files
tsnlWyattBlue
authored andcommitted
Add yuv420p10le pix_fmt
1 parent 086dda0 commit bca1f10

2 files changed

Lines changed: 43 additions & 2 deletions

File tree

av/video/frame.pyx

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ supported_np_pix_fmts = {
2121
"gbrp14be", "gbrp14le", "gbrp16be", "gbrp16le", "gbrpf32be", "gbrpf32le", "gray",
2222
"gray16be", "gray16le", "gray8", "grayf32be", "grayf32le", "nv12", "pal8", "rgb24",
2323
"rgb48be", "rgb48le", "rgb8", "rgba", "rgba64be", "rgba64le", "yuv420p",
24-
"yuv422p10le", "yuv444p", "yuv444p16be", "yuv444p16le", "yuva444p16be",
24+
"yuv420p10le", "yuv422p10le", "yuv444p", "yuv444p16be", "yuv444p16le", "yuva444p16be",
2525
"yuva444p16le", "yuvj420p", "yuvj444p", "yuyv422",
2626
}
2727

@@ -321,7 +321,7 @@ cdef class VideoFrame(Frame):
321321
import numpy as np
322322

323323
# check size
324-
if frame.format.name in {"yuv420p", "yuvj420p", "yuyv422", "yuv422p10le"}:
324+
if frame.format.name in {"yuv420p", "yuvj420p", "yuyv422", "yuv420p10le", "yuv422p10le"}:
325325
assert frame.width % 2 == 0, "the width has to be even for this pixel format"
326326
assert frame.height % 2 == 0, "the height has to be even for this pixel format"
327327

@@ -407,6 +407,16 @@ cdef class VideoFrame(Frame):
407407
useful_array(frame.planes[1]),
408408
useful_array(frame.planes[2]),
409409
]).reshape(-1, frame.width)
410+
if frame.format.name == "yuv420p10le":
411+
# Read planes as uint16:
412+
y = useful_array(frame.planes[0], 2, "uint16").reshape(frame.height, frame.width)
413+
u = useful_array(frame.planes[1], 2, "uint16").reshape(frame.height // 2, frame.width // 2)
414+
v = useful_array(frame.planes[2], 2, "uint16").reshape(frame.height // 2, frame.width // 2)
415+
u_full = np.repeat(np.repeat(u, 2, axis=1), 2, axis=0)
416+
v_full = np.repeat(np.repeat(u, 2, axis=1), 2, axis=0)
417+
if channel_last:
418+
return np.stack([y, u_full, v_full], axis=2)
419+
return np.stack([y, u_full, v_full], axis=0)
410420
if frame.format.name == "yuv422p10le":
411421
# Read planes as uint16 at their original width
412422
y = useful_array(frame.planes[0], 2, "uint16").reshape(frame.height, frame.width)
@@ -652,6 +662,28 @@ cdef class VideoFrame(Frame):
652662
copy_array_to_plane(flat[u_start:v_start], frame.planes[1], 1)
653663
copy_array_to_plane(flat[v_start:], frame.planes[2], 1)
654664
return frame
665+
elif format == "yuv420p10le":
666+
if not isinstance(array, np.ndarray) or array.dtype != np.uint16:
667+
raise ValueError("Array must be uint16 type")
668+
669+
# Convert to channel-first if needed:
670+
if channel_last and array.shape[2] == 3:
671+
array = np.moveaxis(array, 2, 0)
672+
elif not (array.shape[0] == 3):
673+
raise ValueError("Array must have shape (3, height, width) or (height, width, 3)")
674+
675+
height, width = array.shape[1:]
676+
if width % 2 != 0 or height % 2 != 0:
677+
raise ValueError("Width and height must be even")
678+
679+
frame = VideoFrame(width, height, format)
680+
copy_array_to_plane(array[0], frame.planes[0], 2)
681+
# Subsample U and V by taking every other row and column:
682+
u = array[1, ::2, ::2].copy() # Need copy to ensure C-contiguous
683+
v = array[2, ::2, ::2].copy() # Need copy to ensure C-contiguous
684+
copy_array_to_plane(u, frame.planes[1], 2)
685+
copy_array_to_plane(v, frame.planes[2], 2)
686+
return frame
655687
elif format == "yuv422p10le":
656688
if not isinstance(array, np.ndarray) or array.dtype != np.uint16:
657689
raise ValueError("Array must be uint16 type")

tests/test_videoframe.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,15 @@ def test_ndarray_yuv444p16() -> None:
485485
assertNdarraysEqual(frame.to_ndarray(), array)
486486

487487

488+
def test_ndarray_yuv420p10le() -> None:
489+
array = numpy.random.randint(0, 65536, size=(3, 480, 640), dtype=numpy.uint16)
490+
for format in ("yuv420p10le",):
491+
frame = VideoFrame.from_ndarray(array, format=format)
492+
assert frame.width == 640 and frame.height == 480
493+
assert frame.format.name == format
494+
assert format in av.video.frame.supported_np_pix_fmts
495+
496+
488497
def test_ndarray_yuv422p10le() -> None:
489498
array = numpy.random.randint(0, 65536, size=(3, 480, 640), dtype=numpy.uint16)
490499
for format in ("yuv422p10le",):

0 commit comments

Comments
 (0)