播放一个yuv420p格式的文件
yuv的格式与rgb格式的存储方式不同
yuv数据是 yyyyyyyy uu vv 的存储
rgb是rgba rgba rgba 存储
同样一帧图像 yuv420会比rgb数据更小
读取时就要注意数据存储格式不同,数据大小也不同
直接上代码
sdl_qt_play_yuv.h
#include <QtWidgets/QWidget>
#include <SDL2/SDL.h>
#include <fstream>
#include "ui_sdl_qt_play_yuv.h"
class sdl_qt_play_yuv : public QWidget
{
Q_OBJECT
public:
sdl_qt_play_yuv(QWidget *parent = Q_NULLPTR);
void timerEvent(QTimerEvent* ev) override;
private:
Ui::sdl_qt_rgbClass ui;
SDL_Window* sdl_window;
SDL_Renderer* sdl_render;
SDL_Texture* sdl_texture;
unsigned char* yuv_data;
std::ifstream yuv_file;
};
sdl_qt_play_yuv.cpp
#include "sdl_qt_play_yuv.h"
#include <QMessageBox>
#include <QDebug>
#define PIX_SIZE 2
#pragma comment(lib, "SDL2.lib")
void sdl_qt_play_yuv::timerEvent(QTimerEvent* ev)
{
yuv_file.read((char*)yuv_data, ui.label->width() * ui.label->height()*1.5);//一帧图像的yuv420的数据量就是像素的1.5倍
//数据复制到材质 yuv平面存储 yyyyyyyy uu vv
SDL_UpdateTexture(sdl_texture, nullptr, yuv_data, ui.label->width());
SDL_RenderClear(sdl_render);
//材质写入渲染
SDL_Rect sdl_rect;
sdl_rect.x = 0;
sdl_rect.y = 0;
sdl_rect.w = ui.label->width();
sdl_rect.h = ui.label->height();
SDL_RenderCopy(sdl_render, sdl_texture,
nullptr,//原图位置和尺寸
&sdl_rect//目标位置和尺寸
);
//开始渲染
SDL_RenderPresent(sdl_render);
if (yuv_file.eof()) {
yuv_file.clear();
yuv_file.seekg(0);
}
}
sdl_qt_play_yuv::sdl_qt_play_yuv(QWidget *parent)
: QWidget(parent)
{
yuv_file.open("input.yuv", std::ios_base::binary);//打开一个400*300的yuv视频文件
if (!yuv_file) {
QMessageBox::information(this, "", "open yuv failed!");
return;
}
ui.setupUi(this);
ui.label->resize(400, 300);//yuv文件并没有视频的宽高数据, 这里手动指定
SDL_Init(SDL_INIT_VIDEO);
//创建窗口
sdl_window = SDL_CreateWindowFrom((void*)ui.label->winId());
if (!sdl_window) {
exit(-1);
}
//创建渲染器
sdl_render = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_ACCELERATED);
if (!sdl_render) {
exit(-2);
}
//创建材质 设置成支持yuv格式
sdl_texture = SDL_CreateTexture(sdl_render,
SDL_PIXELFORMAT_IYUV,
SDL_TEXTUREACCESS_STREAMING,
ui.label->width(),
ui.label->height());
if (!sdl_texture) {
exit(-3);
}
//清屏
SDL_RenderClear(sdl_render);
yuv_data = new unsigned char[ui.label->width() * ui.label->height() * PIX_SIZE];
startTimer(5);//利用定时器粗略控制帧率
}