Skip to content

Commit 84a94d5

Browse files
committed
Add yuv422p support for video frame to_ndarray and from_ndarray
1 parent 6a0cf68 commit 84a94d5

File tree

2 files changed

+35
-8
lines changed

2 files changed

+35
-8
lines changed

av/video/frame.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -449,13 +449,19 @@ def to_ndarray(self, channel_last=False, **kwargs):
449449
import numpy as np
450450

451451
# check size
452-
if frame.format.name in {"yuv420p", "yuvj420p", "yuyv422", "yuv422p10le"}:
453-
assert frame.width % 2 == 0, (
454-
"the width has to be even for this pixel format"
455-
)
456-
assert frame.height % 2 == 0, (
457-
"the height has to be even for this pixel format"
458-
)
452+
if frame.format.name in {
453+
"yuv420p",
454+
"yuvj420p",
455+
"yuyv422",
456+
"yuv422p10le",
457+
"yuv422p",
458+
}:
459+
assert (
460+
frame.width % 2 == 0
461+
), "the width has to be even for this pixel format"
462+
assert (
463+
frame.height % 2 == 0
464+
), "the height has to be even for this pixel format"
459465

460466
# cases planes are simply concatenated in shape (height, width, channels)
461467
itemsize, dtype = {
@@ -563,7 +569,7 @@ def to_ndarray(self, channel_last=False, **kwargs):
563569
return array
564570

565571
# special cases
566-
if frame.format.name in {"yuv420p", "yuvj420p"}:
572+
if frame.format.name in {"yuv420p", "yuvj420p", "yuv422p"}:
567573
return np.hstack(
568574
[
569575
useful_array(frame.planes[0]),
@@ -1022,6 +1028,19 @@ def from_ndarray(array, format="rgb24", channel_last=False):
10221028
copy_array_to_plane(flat[u_start:v_start], frame.planes[1], 1)
10231029
copy_array_to_plane(flat[v_start:], frame.planes[2], 1)
10241030
return frame
1031+
elif format == "yuv422p":
1032+
check_ndarray(array, "uint8", 2)
1033+
check_ndarray_shape(array, array.shape[0] % 4 == 0)
1034+
check_ndarray_shape(array, array.shape[1] % 2 == 0)
1035+
1036+
frame = VideoFrame(array.shape[1], array.shape[0] // 2, format)
1037+
u_start = frame.width * frame.height
1038+
v_start = u_start + u_start // 2
1039+
flat = array.reshape(-1)
1040+
copy_array_to_plane(flat[0:u_start], frame.planes[0], 1)
1041+
copy_array_to_plane(flat[u_start:v_start], frame.planes[1], 1)
1042+
copy_array_to_plane(flat[v_start:], frame.planes[2], 1)
1043+
return frame
10251044
elif format == "yuv422p10le":
10261045
if not isinstance(array, np.ndarray) or array.dtype != np.uint16:
10271046
raise ValueError("Array must be uint16 type")

tests/test_videoframe.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,14 @@ def test_ndarray_yuv420p() -> None:
648648
assertNdarraysEqual(frame.to_ndarray(), array)
649649

650650

651+
def test_ndarray_yuv422p() -> None:
652+
array = numpy.random.randint(0, 256, size=(960, 640), dtype=numpy.uint8)
653+
frame = VideoFrame.from_ndarray(array, format="yuv422p")
654+
assert frame.width == 640 and frame.height == 480
655+
assert frame.format.name == "yuv422p"
656+
assertNdarraysEqual(frame.to_ndarray(), array)
657+
658+
651659
def test_ndarray_yuv420p_align() -> None:
652660
array = numpy.random.randint(0, 256, size=(357, 318), dtype=numpy.uint8)
653661
frame = VideoFrame.from_ndarray(array, format="yuv420p")

0 commit comments

Comments
 (0)