从帧缓冲区处理 YUV I420?
Posted
技术标签:
【中文标题】从帧缓冲区处理 YUV I420?【英文标题】:Processing YUV I420 from framebuffer? 【发布时间】:2021-11-29 18:11:32 【问题描述】:我有一个名为 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
中的字节组合以生成可以在视频播放器中原始播放的字节流?
示例:
https://transfer.sh/E8LNy5/69518644-example-01.yuv
【问题讨论】:
您可以发布/上传一些示例数据(完整框架)吗?平面偏移看起来不对。 U和V之间只有192,这是不对的。步幅略大于宽度对我来说意味着有填充。 @ChristophRackwitz 当然,我已经添加了一个完整框架的链接。我必须承认在十六进制编辑器中查看它看起来很奇怪,但这是我从帧缓冲区中得到的? imgur.com/a/x4Ik5Gq 这是被解释为一个灰度流的 yuv 文件,384 宽。 352 像素宽的可用数据。数据看起来很奇怪。我还不能推测。 U 和 V 行 似乎也是交错的。如果是 U 然后是 V,我们会看到堆叠的两张平面图片,而不是并排的图片。如果它们是按样本交错的,我们会看到一张带有一些纹理的图片。一种奇怪的格式。数据从何而来? this 建议这种格式可以称为M420
。无论如何,奇怪,但可解码。
imgur.com/a/x4Ik5Gq 上的第二张图片看起来是否合理,颜色是否正确?可用数据确实是 320x180
【参考方案1】:
数据的布局看起来很奇怪,但使用给定的偏移量和步幅,这可以解码为 YUV。
首先有 384 * 180 字节的亮度。
以下是色度线,每条线长 192 字节...但 U 和 V 线轮流使用!这是由奇怪的偏移量造成的。 U 偏移量正好指向亮度后。 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()
【讨论】:
以上是关于从帧缓冲区处理 YUV I420?的主要内容,如果未能解决你的问题,请参考以下文章
WebGL - 当我从帧缓冲区读取像素数据时,图标失去透明度
尝试从帧缓冲区传递纹理会导致 L_INVALID_OPERATION:glDrawArrays:绘制的源纹理和目标纹理相同