1-4、封装SDL

用简单工厂模式封装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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值