We may use PyAV library.
PyAV is a Pythonic binding for the FFmpeg libraries.
FFmpeg supports YUV422 Planar picture format, and PyAV also supports it.
Unlike other FFmpeg bindings, PyAV is relatively low-level - instead of using FFmpeg CLI, it allows more low level functionalities that supported by the C interface of FFmpeg.
libswscale is "sub module" of FFmpeg that supports multiple color formats conversions.
PyAV exposes some of the capabilities of libswscale.
Start by creating raw input file in yuv422p pixel format, using FFmpeg CLI.
Execute the following shell command for building sample input (used for testing):
ffmpeg -y -f lavfi -i testsrc=192x108:rate=1:duration=10 -vf "scale=out_color_matrix=bt709:out_range=tv" -pix_fmt yuv422p -f rawvideo input.yuv422p
The next example, uses PyAV for converting from raw yuv422p to BGR pixel format:
Create a VideoFrame
object:
frame = VideoFrame(cols, rows, 'yuv422p')
Assume y
, u
and v
are 3 color planes (y
is full resolution, and u
and v
are half resolution in the horizontal axis).
The planes may be stored in NumPy arrays or bytes arrays (multiple buffer formats are supported).
Update the 3 planes of frame
:
frame.planes[0].update(y)
frame.planes[1].update(u)
frame.planes[2].update(v)
Convert the frame to BGR format using reformat method, and convert to NumPy array:
bgr_frame = frame.reformat(cols, rows, 'bgr24', src_colorspace='ITU709', dst_colorspace='DEFAULT', interpolation='BILINEAR')
bgr = bgr_frame.to_ndarray()
The following code sample reads yuv422p
raw data from file, converts to BRG using PyAV (and shows the output using OpenCV):
import cv2
from av.video.frame import VideoFrame
# Build raw input file using shell command:
# ffmpeg -y -f lavfi -i testsrc=192x108:rate=1:duration=10 -vf "scale=out_color_matrix=bt709:out_range=tv" -pix_fmt yuv422p -f rawvideo input.yuv422p
cols, rows, n_frames = 192, 108, 10
frame = VideoFrame(cols, rows, 'yuv422p')
with open('input.yuv422p', 'rb') as f:
for n in range(n_frames):
y = f.read(cols*rows) # y = np.frombuffer(f.read(cols*rows), np.uint8).reshape(rows, cols)
u = f.read(cols*rows//2) # u = np.frombuffer(f.read(cols*rows//2), np.uint8).reshape(rows, cols//2)
v = f.read(cols*rows//2) # v = np.frombuffer(f.read(cols*rows//2), np.uint8).reshape(rows, cols//2)
frame.planes[0].update(y)
frame.planes[1].update(u)
frame.planes[2].update(v)
bgr_frame = frame.reformat(cols, rows, 'bgr24', src_colorspace='ITU709', dst_colorspace='DEFAULT', interpolation='BILINEAR')
bgr = bgr_frame.to_ndarray()
cv2.imshow('bgr', bgr)
cv2.waitKey(1000)
cv2.destroyAllWindows()
Notes:
Installing PyAV may be problematic (at least when using Windows).
Instead of using pip install
, I downloaded a whl
file from here (and used pip install
for installing the wheel).
I assumed that the YUV applies BT.709 standard (and applies "TV range" - Y
range is [16, 235] not [0, 255]).
For correct conversion, you have to know the exacts standard of your raw data.