YUV 格式分析
Y、U、V 各占一个字节
YUV444 : 每4个像素点为一组,这4个像素点包含4个Y、4个U、4个V,每个像素点占用3个字节。
YUV422 : 每4个像素点为一组,这4个像素点包含4个Y、2个U、2个V,每个像素点占用2个字节。
YUV420 : 每4个像素点为一组,这4个像素点包含4个Y、1个U、1个V,每个像素点占用1.5个字节。
H264 和 H265 中默认使用的像素点格式为 YUV420。
ffmpeg工具生成YUV格式的视频素材
SDL播放YUV文件直接渲染
代码
SdlQtRgb.h
#pragma once
#include <QtWidgets/QWidget>
#include "ui_SdlQtRGB.h"
class SdlQtRGB : public QWidget
{
Q_OBJECT
public:
SdlQtRGB(QWidget *parent = Q_NULLPTR);
~SdlQtRGB();
private:
Ui::SdlQtRGBClass ui;
void timerEvent(QTimerEvent* evt) override;
};
SdlQtRgb.cpp
#include "SdlQtRGB.h"
#include "sdl/SDL.h"
#include <iostream>
#include <fstream>
#include <QMessageBox>
#pragma comment(lib, "SDL2.lib")
using namespace std;
static SDL_Window* sdl_win = nullptr;
static SDL_Renderer* sdl_render = nullptr;
static SDL_Texture* sdl_texture = nullptr;
static unsigned char* yuv = nullptr;
static int sdl_width = 0;
static int sdl_height = 0;
static int pixel_size = 2;
static ifstream yuv_file;
void SdlQtRGB::timerEvent(QTimerEvent* evt)
{
SDL_Rect rect;
rect.x = 0;
rect.y = 0;
rect.w = sdl_width;
rect.h = sdl_height;
yuv_file.read((char*)yuv, sdl_width * sdl_height * 1.5); // 读取一帧数据
SDL_RenderClear(sdl_render);
// YUV 平面存储方式, RGB 交叉存储方式
// YYYYYYYY UU VV
SDL_UpdateTexture(sdl_texture, nullptr, yuv,
sdl_width // 一行 Y 的字节数
);
SDL_RenderCopy(sdl_render, sdl_texture, nullptr, &rect);
SDL_RenderPresent(sdl_render);
}
SdlQtRGB::SdlQtRGB(QWidget *parent)
: QWidget(parent)
{
yuv_file.open("400_300_25.yuv", ios::in | ios::binary);
if (!yuv_file)
{
QMessageBox::information(this, "information", "open 400_300_25.yuv failed!");
return;
}
ui.setupUi(this);
sdl_width = 400;
sdl_height = 300;
ui.label->resize(400, 300);
// 初始化 SDL
if (SDL_Init(SDL_INIT_VIDEO))
{
cout << SDL_GetError() << endl;
}
// 创建窗口
sdl_win = SDL_CreateWindowFrom((void*)ui.label->winId()); // 通过 Qt 控件中的句柄来创建窗口
if (!sdl_win)
{
cout << SDL_GetError() << endl;
}
// 创建渲染器
sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED);
if (!sdl_render)
{
cout << SDL_GetError() << endl;
}
// 创建材质
sdl_texture = SDL_CreateTexture(sdl_render, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, sdl_width, sdl_height);
if (!sdl_texture)
{
cout << SDL_GetError() << endl;
}
yuv = new unsigned char[sdl_width * sdl_height * pixel_size];
startTimer(10); // 每过10ms就会调用一次 timerEvent,1s大约有100帧的图像
}
SdlQtRGB::~SdlQtRGB()
{
delete[] yuv;
}
注意:YUV 和 RGB 的存储方式不同,YUV 为平面存储,RGB 为交叉存储。
显示效果如下:
以 YUV 的方式一帧一帧的方式显示了图片。