SDL播放YUV格式视频
代码
1 |
|
(一)
为什么要用binary打开文件?
以二进制模式打开文件是为了确保文件内容按原始字节读取或写入,而不经过任何修改或转换。
在文本模式下(即不使用 std::ios::binary
时),文件的读写操作可能会受到操作系统的影响,特别是在处理不同操作系统的换行符时
(二)
SDL_PIXELFORMAT_IYUV
格式?
SDL_PIXELFORMAT_IYUV
是 SDL 库中定义的一种像素格式,表示 YUV420P 格式的图像数据。它是一种压缩的 YUV 格式,通常用于视频和图像处理。下面是对 SDL_PIXELFORMAT_IYUV
的详细介绍:
- YUV 颜色空间:
- Y 表示亮度分量(Luminance),它决定了图像的亮度或灰度级别。
- U 和 V 表示色度分量(Chrominance),它们共同描述了图像的颜色信息。
- YUV 格式通过分离亮度和色度来减少数据量,这在视频压缩和传输中非常有效。
- YUV420P 格式:
- YUV420P 是一种常见的 YUV 格式,其中亮度(Y)分量的分辨率与原图一致,而色度(U 和 V)分量的分辨率是亮度的四分之一。
- IYUV 和 YV12 都是 YUV420P 的变种,它们的区别在于 U 和 V 分量的存储顺序。
- IYUV 格式的结构:
- 在
IYUV
格式中,图像数据按平面(Plane)排列:- Y 平面:首先存储所有像素的亮度信息,大小为
width * height
字节。 - U 平面:接下来存储所有 U 分量数据,大小为
width/2 * height/2
字节。 - V 平面:最后存储所有 V 分量数据,大小同样为
width/2 * height/2
字节。 - 存储:YYYYYYYY UUUU VVVV
- Y 平面:首先存储所有像素的亮度信息,大小为
- 这意味着对于一个
400x300
的图像,IYUV 格式的数据结构如下:- Y 分量:400x300 = 120,000 字节
- U 分量:200x150 = 30,000 字节
- V 分量:200x150 = 30,000 字节
- 总数据量:120,000 + 30,000 + 30,000 = 180,000 字节
- 与 YV12 的区别:
- IYUV:在内存中按 Y -> U -> V 的顺序存储。
- YV12:在内存中按 Y -> V -> U 的顺序存储。
- 在 SDL 中的使用:
SDL_PIXELFORMAT_IYUV
在 SDL 中用于处理、显示和转换视频帧。开发者可以使用 SDL 的渲染函数(如SDL_UpdateTexture
)来显示这种格式的图像。- 这种格式被广泛用于视频解码和播放,因为它比 RGB 更节省存储空间和带宽。
- 应用场景:
- 视频播放:IYUV 格式常用于视频解码器输出的数据格式,适合直接传递给视频渲染器。
- 视频传输和存储:由于其数据压缩特性,YUV420 格式在视频编码中很常见,例如在 MPEG、H.264 等视频编码标准中。
(三)
1 | yuv_file.read((char*)yuv, sdl_width * sdl_height * 1.5); |
这里$\times 1.5$为什么?
具体解释:
YUV 格式的图像数据通常分为三个平面:
- Y 分量(亮度信息,Luminance):每个像素都有一个 Y 分量,因此 Y 平面的大小是图像的宽度乘以高度(
sdl_width * sdl_height
)。 - U 分量(色度信息,Chrominance):U 分量平面通常是 Y 平面大小的四分之一(
sdl_width/2 * sdl_height/2
),因为 U 分量是 2x2 像素块共享的。 - V 分量(色度信息,Chrominance):V 分量平面的大小与 U 分量相同,也是 Y 平面的四分之一。
因此,对于一个 YUV420 格式的图像(比如 IYUV 或 YV12 格式):
- Y 平面:占用
sdl_width * sdl_height
字节。 - U 平面:占用
(sdl_width/2) * (sdl_height/2)
字节,即sdl_width * sdl_height / 4
字节。 - V 平面:占用的字节数与 U 平面相同,也是
sdl_width * sdl_height / 4
字节。
所以,YUV420 图像的总数据量为:
总数据量=Y平面+U平面+V平面
总数据量$=sdl_width \times sdl_height + \displaystyle\frac{sdl_width \times sdl_height}{4}+\displaystyle\frac{sdl_width \times sdl_height}{4}$
总数据量$=sdl_width \times sdl_height\times (1+\frac{1}{4}+\frac{1}{4})=sdl_width \times sdl_height\times1.5$
因此,乘以 1.5
是为了读取包含整个 YUV 图像帧的所有数据,包括 Y、U、V 三个分量。这确保了从文件中读取到的字节数足够填充一个完整的 YUV 图像帧。
1 | // 处理yuv数据 |
为什么第四个参数一个需要乘pix_size
?
在 SDL_UpdateTexture
函数中,第四个参数表示每一行数据的字节数(通常称为 “pitch” 或 “stride”)。对于不同的像素格式,这个参数的值会有所不同。
- YUV 数据:通常 YUV 数据的每个像素由多个平面(例如 Y、U、V 平面)表示,每个平面可能有不同的分辨率。第四个参数
sdl_width
直接表示一行像素的宽度,因为每个 Y 分量通常占用一个字节。 - RGB 数据:RGB 数据通常使用单个平面表示,每个像素由多个字节(例如 3 个字节的 RGB24 或 4 个字节的 RGBA32)表示。因此,第四个参数需要乘以
pix_size
,即每个像素的字节数,以表示一行数据的总字节数。