1.工厂模式的封装
2.封装完窗口渲染器和材质的初始化+渲染画面随窗口大小缩放并解决锯齿问题
1.工厂模式封装 类图
1.1图像窗口初始化Init()可能只一次,而渲染Draw()很多次,所以封装不同线程。
都用的锁。
1.2锁的使用如下图所示:
static bool InitVideo()
{
static bool is_first = true;
static mutex mux; //1.定义锁的变量
unique_lock<mutex> sdl_lock(mux); //2.调用函数
if (!is_first)return true;
is_first = false;
if (SDL_Init(SDL_INIT_VIDEO))
{
cout << SDL_GetError() << endl;
return false;
}
return true;
}
2.封装完窗口渲染器和材质的初始化+渲染画面随窗口大小缩放并解决锯齿问题
其实就是用C++代码实现上面的类图
xvideo_view.h
xvideo_view.cpp
xsdl.h
xsdl.cpp
#ifndef XVIDEO_VIEW_H
#define XVIDEO_VIEW_H
#include <mutex>
class XVideoView
{
public:
enum Format
{
RGBA = 0,
ARGB,
YUV420P
};
enum RenderType
{
SDL = 0
};
static XVideoView* Create(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;
};
#endif
xvideo_view.cpp
#include "xsdl.h"
XVideoView* XVideoView::Create(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:
bool Init(int w, int h,Format fmt = RGBA,void* win_id = nullptr) override;
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;
static bool InitVideo()
{
static bool is_first = true;
static mutex mux;
unique_lock<mutex> sdl_lock(mux);
if (!is_first)return true;
is_first = false;
if (SDL_Init(SDL_INIT_VIDEO))
{
cout << SDL_GetError() << endl;
return false;
}
//设定缩放算法,解决锯齿问题,线性插值算法
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
return true;
}
bool XSDL::Init(int w, int h,Format fmt,void* win_id)
{
if (w <= 0 || h <= 0)return false;
//1.初始化SDL 视频库
InitVideo();
//确保线程安全
unique_lock<mutex> sdl_lock(mtx_);
width_ = w;
height_ = h;
fmt_ = fmt;
///2.创建窗口 渲染器 材质
win_ = SDL_CreateWindow("",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
w, h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
);
render_ = SDL_CreateRenderer(win_, -1, SDL_RENDERER_ACCELERATED);
//创建材质 (显存)
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 ((!win_)||(!render_)||(!texture_))
{
cerr << SDL_GetError() << endl;
return false;
}
render_ = SDL_CreateRenderer(win_, -1, SDL_RENDERER_ACCELERATED);
if (!render_)
{
cerr << SDL_GetError() << endl;
return false;
}
return true;
}
bool XSDL::Draw(const unsigned char* data,int linesize)
{
if (!data)return false;
unique_lock<mutex> sdl_lock(mtx_);//只要是线程调用就创建线程变量。
if (!texture_ || !render_ || !win_ || width_ <= 0 || height_ <= 0)
return false;
if (linesize <= 0)
{
switch (fmt_)
{
case XVideoView::RGBA:
case XVideoView::ARGB:
linesize = width_ * 4;
break;
case XVideoView::YUV420P:
linesize = width_;
break;
default:
break;
}
}
if (linesize <= 0)
return false;
//1.渲染器清空,复制内存到显存,材质复制到渲染器,显示
SDL_RenderClear(render_);
auto re = SDL_UpdateTexture(texture_, NULL, data, linesize);
if (re != 0)
{
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 rect;
rect.x = 0; rect.y = 0;
rect.w = scale_w_;//渲染的宽高,可缩放
rect.h = scale_h_;
re = SDL_RenderCopy(render_, texture_, NULL, &rect);
if (re != 0)
{
cout << SDL_GetError() << endl;
return false;
}
SDL_RenderPresent(render_);
return true;
}
调用的时候:
view = XVideoView::Create();
view->Init(sdl_width, sdl_height,
XVideoView::YUV420P,(void*)ui.label->winId());
view->Draw(yuv);