从帧缓冲区处理 YUV I420?
Processing YUV I420 from framebuffer?
我有一个名为 buf
的字节数组,其中包含从帧缓冲区获取的 YUV I420 格式的单个视频帧。对于每个视频帧,我还有以下信息:
Size (e.g. 320x180)
Stride Y (e.g. 384)
Stride U (e.g. 384)
Stride V (e.g. 384)
Plane offset Y (e.g. 0)
Plane offset U (e.g. 69120)
Plane offset V (e.g. 69312)
连接文件中的多个视频帧,并将其与大小信息一起传递给 VLC 或 FFmpeg 中的原始视频解码器只会产生乱码,所以我认为 buf
中的字节应该使用这些信息重新排序上面生成可播放的输出,但我对处理视频完全陌生,所以这可能是错误的。
我应该将大小、步幅和偏移信息与 buf
中的字节相结合,以生成可以在视频播放器中原始播放的字节流?
示例:
数据的布局看起来很奇怪,但使用给定的偏移量和步长,这可以解码为 YUV。
首先有384 * 180字节的亮度。
以下是色度线,每条线长 192 字节...但是 U 线和 V 线轮流出现!这是由奇怪的偏移量造成的。 U offset 正好指向 luma 之后。 V 偏移量进一步增加了 192 个字节...并且读取将跳过 384 个字节。
这是提取这些平面并将它们组装为 I420 的代码,用于使用 cvtColor
进行解码:
#!/usr/bin/env python3
import numpy as np
import cv2 as cv
def extract(data, offset, stride, width, height):
data = data[offset:] # skip to...
data = data[:height * stride] # get `height` lines
data.shape = (height, stride)
return data[:, :width] # drop overscan/padding
width, height = 320, 180
Yoffset = 0
Uoffset = 69120 # 384*180
Voffset = 69312 # 384*180 + 192
Ystride = 384
Ustride = 384
Vstride = 384
data = np.fromfile("69518644-example-01.yuv", dtype=np.uint8)
Y = extract(data, Yoffset, Ystride, width, height)
U = extract(data, Uoffset, Ustride, width // 2, height // 2)
V = extract(data, Voffset, Vstride, width // 2, height // 2)
# construct I420: Y,U,V planes in order
i420 = np.concatenate([Y.flat, U.flat, V.flat])
i420.shape = (height * 3 // 2, width)
result = cv.cvtColor(i420, cv.COLOR_YUV2BGR_I420)
cv.namedWindow("result", cv.WINDOW_NORMAL)
cv.resizeWindow("result", width * 4, height * 4)
cv.imshow("result", result)
cv.waitKey()
cv.destroyAllWindows()
我有一个名为 buf
的字节数组,其中包含从帧缓冲区获取的 YUV I420 格式的单个视频帧。对于每个视频帧,我还有以下信息:
Size (e.g. 320x180)
Stride Y (e.g. 384)
Stride U (e.g. 384)
Stride V (e.g. 384)
Plane offset Y (e.g. 0)
Plane offset U (e.g. 69120)
Plane offset V (e.g. 69312)
连接文件中的多个视频帧,并将其与大小信息一起传递给 VLC 或 FFmpeg 中的原始视频解码器只会产生乱码,所以我认为 buf
中的字节应该使用这些信息重新排序上面生成可播放的输出,但我对处理视频完全陌生,所以这可能是错误的。
我应该将大小、步幅和偏移信息与 buf
中的字节相结合,以生成可以在视频播放器中原始播放的字节流?
示例:
数据的布局看起来很奇怪,但使用给定的偏移量和步长,这可以解码为 YUV。
首先有384 * 180字节的亮度。
以下是色度线,每条线长 192 字节...但是 U 线和 V 线轮流出现!这是由奇怪的偏移量造成的。 U offset 正好指向 luma 之后。 V 偏移量进一步增加了 192 个字节...并且读取将跳过 384 个字节。
这是提取这些平面并将它们组装为 I420 的代码,用于使用 cvtColor
进行解码:
#!/usr/bin/env python3
import numpy as np
import cv2 as cv
def extract(data, offset, stride, width, height):
data = data[offset:] # skip to...
data = data[:height * stride] # get `height` lines
data.shape = (height, stride)
return data[:, :width] # drop overscan/padding
width, height = 320, 180
Yoffset = 0
Uoffset = 69120 # 384*180
Voffset = 69312 # 384*180 + 192
Ystride = 384
Ustride = 384
Vstride = 384
data = np.fromfile("69518644-example-01.yuv", dtype=np.uint8)
Y = extract(data, Yoffset, Ystride, width, height)
U = extract(data, Uoffset, Ustride, width // 2, height // 2)
V = extract(data, Voffset, Vstride, width // 2, height // 2)
# construct I420: Y,U,V planes in order
i420 = np.concatenate([Y.flat, U.flat, V.flat])
i420.shape = (height * 3 // 2, width)
result = cv.cvtColor(i420, cv.COLOR_YUV2BGR_I420)
cv.namedWindow("result", cv.WINDOW_NORMAL)
cv.resizeWindow("result", width * 4, height * 4)
cv.imshow("result", result)
cv.waitKey()
cv.destroyAllWindows()