用简单工厂模式封装SDL
1、隐藏SDL的实现
2、渲染方式可替代
3、线程安全
xvideo_view.h
#pragma once
#include <mutex>
/// <summary>
/// 视频渲染接口
/// 1、隐藏SDL实现
/// 2、渲染方式可替代
/// 3、线程安全
/// </summary>
class XVideoView {
public:
enum Format {
RGBA = 0,
ARGB,
YUV420P
};
// 产品类型
enum RenderType {
SDL = 0
};
// 工厂类
static XVideoView* Creat(RenderType type = SDL);
// 抽象产品类
virtual bool Init(int w, int h, Format fmt = RGBA, void* win_id = nullptr) = 0;
virtual bool Draw(const unsigned char* data, int linesize = 0) = 0;
//void Scale(int w, int h)
//{
// scale_w_ = w;
// scale_h_ = h;
//}
protected:
int width_ = 0;
int height_ = 0;
Format fmt_ = RGBA;
std::mutex mtx_; //确保线程安全(不在头文件中引入命名空间)
int scale_w_ = 0; //显示大小
int scale_h_ = 0;
};
xvideo_view.cpp
#include "xsdl.h"
XVideoView* XVideoView::Creat(RenderType type)
{
switch (type) {
case XVideoView::SDL:
return new XSDL();
break;
default:
break;
}
return nullptr;
}
xsdl.h
#pragma once
#include "xvideo_view.h"
struct SDL_Window;
struct SDL_Renderer;
struct SDL_Texture;
// 具体产品类
class XSDL :public XVideoView {
public:
/// 初始化渲染窗口 线程安全
/// @para w 窗口宽度
/// @para h 窗口高度
/// @para fmt 绘制的像素格式
/// @para win_id 窗口句柄,如果为空,创建新窗口
/// @return 是否创建成功
bool Init(int w, int h, Format fmt = RGBA, void* win_id = nullptr) override;
//
/// 渲染图像 线程安全
///@para data 渲染的二进制数据
///@para linesize 一行数据的字节数,对于YUV420P就是Y一行字节数
/// linesize<=0 就根据宽度和像素格式自动算出大小
/// @return 渲染是否成功
bool Draw(const unsigned char* data, int linesize = 0) override;
private:
SDL_Window* win_ = nullptr;
SDL_Renderer* render_ = nullptr;
SDL_Texture* texture_ = nullptr;
};
xsdl.cpp
#include "xsdl.h"
#include <sdl/SDL.h>
#include <iostream>
using namespace std;
#pragma comment(lib,"SDL2.lib")
static bool InitVideo(string& strError)
{
static bool bOK = false;
static mutex mux;
unique_lock<mutex> sdl_lock(mux);
if (!bOK) {
if (SDL_Init(SDL_INIT_VIDEO)) {
strError = SDL_GetError();
return false;
}
}
// 设定缩放算法(线性插值)
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
bOK = true;
return true;
}
bool XSDL::Init(int w, int h, Format fmt, void* win_id)
{
string strError = "";
// 1、初始化视频库
if (!InitVideo(strError)) {
return false;
}
//确保线程安全
unique_lock<mutex> sdl_lock(mtx_);
width_ = w;
height_ = h;
fmt_ = fmt;
// 2、创建窗口
if (!win_) {
if (win_id) {
win_ = SDL_CreateWindowFrom(win_id);
if (!win_) {
cout << SDL_GetError() << endl;
return false;
}
}
else {
win_ = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
w, h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (!win_) {
cout << SDL_GetError() << endl;
return false;
}
}
}
// 3、创建渲染器
render_ = SDL_CreateRenderer(win_, -1, SDL_RENDERER_ACCELERATED);
if (!render_) {
cout << SDL_GetError() << endl;
return false;
}
// 4、创建材质
unsigned int sdl_fmt = SDL_PIXELFORMAT_RGBA8888;
switch (fmt)
{
case XVideoView::RGBA:
break;
case XVideoView::ARGB:
sdl_fmt = SDL_PIXELFORMAT_ARGB32;
break;
case XVideoView::YUV420P:
sdl_fmt = SDL_PIXELFORMAT_IYUV;
break;
default:
break;
}
texture_ = SDL_CreateTexture(render_, sdl_fmt, SDL_TEXTUREACCESS_STREAMING, w, h);
if (!texture_) {
cout << SDL_GetError() << endl;
return false;
}
return true;
}
bool XSDL::Draw(const unsigned char* data, int linesize)
{
if (!data) {
cout << "Data Is Empty!" << endl;
return false;
}
unique_lock<mutex> sdl_lock(mtx_);
if (!win_ || !render_ || !texture_ || width_ <= 0 || height_ <= 0) {
cout << "Init Is Fail!" << endl;
return false;
}
if (linesize <= 0) {
switch (fmt_)
{
case XVideoView::RGBA:
case XVideoView::ARGB:
linesize = width_ * 4;
break;
case XVideoView::YUV420P:
linesize = width_ * 1;
break;
default:
break;
}
}
// 5、渲染
//auto aa = SDL_UpdateTexture(texture_, NULL, data, linesize);
if (SDL_UpdateTexture(texture_, NULL, data, linesize)) { // 复制到显存
cout << SDL_GetError() << endl;
return false;
}
SDL_RenderClear(render_);
//材质复制到渲染器
//if (scale_w_ <= 0)scale_w_ = width_;
//if (scale_h_ <= 0)scale_h_ = height_;
SDL_Rect sdl_rect; // 目标尺寸
sdl_rect.x = 0;
sdl_rect.y = 0;
sdl_rect.w = width_;
sdl_rect.h = height_;
if (SDL_RenderCopy(render_, texture_, NULL, &sdl_rect)) {
cout << SDL_GetError() << endl;
return false;
}
SDL_RenderPresent(render_); // 渲染
return true;
}