栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

使用工厂模式封装SDL接口

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用工厂模式封装SDL接口

代码 

XVideoView.h

#ifndef XVIDEOVIEW_H
#define XVIDEOVIEW_H

#include 


class XVideoView
{
public:
	enum PixelFormat
	{
		RGBA = 0,
		ARGB,
		YUV420P
	};

	enum ViewType
	{
		VIEW_SDL = 0
	};

	XVideoView();
	static XVideoView* create(ViewType type = VIEW_SDL);

	
	virtual bool init(int w, int h, PixelFormat fmt = RGBA, void* winId = nullptr) = 0;

	// 清理所有清理的资源,包括关闭窗口
	virtual void close() = 0;

	// 处理窗口退出事件
	virtual bool isExit() = 0;

	
	virtual bool draw(const unsigned char* data, int lineSize = 0) = 0;
	void scale(int w, int h);

protected:
	int m_width;				// 材质宽高
	int m_height;
	int m_scaleWid;				// 显示大小
	int m_scaleHgh;
	PixelFormat m_fmt;
	std::mutex m_mtx;			// 保证线程安全
};

#endif

XVideoView.cpp

#include "XVideoView.h"
#include "XSDL.h"

XVideoView::XVideoView()
{
	m_width = 0;
	m_height = 0;
	m_fmt = ARGB;
	m_scaleWid = 0;
	m_scaleHgh = 0;
}

XVideoView* XVideoView::create(ViewType type)
{
	XVideoView* ret = nullptr;

	switch (type)
	{
		case VIEW_SDL:
			ret = new XSDL();  // 使用 SDL 方式进行渲染
			break;
		default:
			break;
	}

	return ret;
}

void XVideoView::scale(int w, int h)
{
	m_scaleWid = w;
	m_scaleHgh = h;
}

XSDL.h

#ifndef XSDL_H
#define XSDL_H

#include "XVideoView.h"

class SDL_Window;
class SDL_Renderer;
class SDL_Texture;

class XSDL : public XVideoView
{
public:
	XSDL();

	
	bool init(int w, int h, PixelFormat fmt = RGBA, void* winId = nullptr) override;

	// 清理所有清理的资源,包括关闭窗口
	void close() override;

	// 处理窗口退出事件
	bool isExit() override;

	
	bool draw(const unsigned char* data, int lineSize = 0) override;

private:
	bool initVideo();

	SDL_Window* m_win;
	SDL_Renderer* m_render;
	SDL_Texture* m_texture;
};

#endif

XSDL.cpp

#include 
#include "XSDL.h"
#include "sdl/SDL.h"

#pragma comment(lib, "SDL2.lib")

using namespace std;

XSDL::XSDL()
{
	m_win = nullptr;
	m_render = nullptr;
	m_texture = nullptr;
}

bool XSDL::initVideo()
{
	static bool first_init = false;
	static mutex mtx;

	unique_lock sdl_lock(mtx);  // sdl_lock 在创建时自动加锁,生命周期结束时自动解锁,为了解决锁还没释放函数就返回可能导致的死锁问题

	if (!first_init)
	{
		first_init = (SDL_Init(SDL_INIT_VIDEO) == 0);

		if (first_init)
		{
			//设定缩放算法,解决锯齿问题,线性插值算法
			SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
		}
		else
		{
			cerr << SDL_GetError() << endl;
		}
	}

	return first_init;
}

bool XSDL::init(int w, int h, PixelFormat fmt, void* winId)
{
	bool ret = ((w > 0) && (h > 0) && initVideo());

	if (ret)
	{
		close();  // 可能已经初始化,先进行清理操作

		// 确保线程安全
		unique_lock sdl_lock(m_mtx);  

		m_width = w;
		m_height = h;
		m_fmt = fmt;

		
		if (winId)
		{
			// 渲染到控件窗口
			m_win = SDL_CreateWindowFrom(winId);  
		}
		else
		{
			// 新建窗口
			m_win = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
		}

		if (!m_win)
		{
			cerr << SDL_GetError() << endl;
			ret = false;
		}

		
		if (ret)
		{
			m_render = SDL_CreateRenderer(m_win, -1, SDL_RENDERER_ACCELERATED);

			if (!m_render)
			{
				cerr << SDL_GetError() << endl;
				ret = false;
			}
		}

		
		if (ret)
		{
			unsigned int pixFmt = SDL_PIXELFORMAT_ARGB8888;

			switch (fmt)
			{
				case XVideoView::ARGB:
					break;
				case XVideoView::RGBA:
					pixFmt = SDL_PIXELFORMAT_RGBA8888;
					break;
				case XVideoView::YUV420P:
					pixFmt = SDL_PIXELFORMAT_IYUV;
					break;
			}

			m_texture = SDL_CreateTexture(m_render, pixFmt, SDL_TEXTUREACCESS_STREAMING, w, h);  // 这里的 w, h 为分辨率

			if (!m_texture)
			{
				cerr << SDL_GetError() << endl;
				ret = false;
			}
		}	
	}

	return ret;
}

void XSDL::close()
{
	unique_lock sdl_lock(m_mtx);

	if (m_texture)
	{
		SDL_DestroyTexture(m_texture);
		m_texture = nullptr;
	}

	if (m_render)
	{
		SDL_DestroyRenderer(m_render);
		m_render = nullptr;
	}

	if (m_win)
	{
		SDL_DestroyWindow(m_win);
		m_win = nullptr;
	}
}

bool XSDL::isExit()
{
	bool ret = false;
	SDL_Event evt;
	SDL_WaitEventTimeout(&evt, 1);

	if (evt.type == SDL_QUIT)
	{
		ret = true;
	}

	return ret;
}

bool XSDL::draw(const unsigned char* data, int lineSize)
{
	unique_lock sdl_lock(m_mtx);
	bool ret = (data && (m_width > 0) && (m_height > 0) &&  m_win && m_render && m_texture);

	if (ret)
	{
		if (lineSize <= 0)
		{
			switch (m_fmt)
			{
				case XVideoView::RGBA:
				case XVideoView::ARGB:
					lineSize = m_width * 4;
					break;
				case XVideoView::YUV420P:
					lineSize = m_width;
					break;
				default:
					break;
			}

			if (lineSize <= 0)
			{
				cerr << "Param lineSize is invalid ...n" << endl;
				ret = false;
			}
		}

		if (ret)
		{
			// 复制内存到显存中
			ret = (SDL_UpdateTexture(m_texture, nullptr, data, lineSize) == 0);

			if (ret)
			{
				SDL_Rect rect;
				SDL_Rect* pr = nullptr;

				rect.x = 0;
				rect.y = 0;
				rect.w = m_scaleWid;  // rect.w, rect.h 为显示的尺寸大小
				rect.h = m_scaleHgh;

				
				if ((m_scaleWid > 0) && (m_scaleHgh > 0))
				{
					pr = ▭
				}

				// 清空屏幕
				SDL_RenderClear(m_render);

				// 将材质复制到渲染器
				ret = (SDL_RenderCopy(m_render, m_texture, nullptr, pr) == 0);

				if (ret)
				{
					SDL_RenderPresent(m_render);
				}
				else
				{
					cerr << SDL_GetError() << endl;
				}
			}
			else
			{
				cerr << SDL_GetError() << endl;
			}
		}
		
	}

	return ret;
}

测试代码

SdlQtRGB.h

#pragma once

#include 
#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;
    void resizeEvent(QResizeEvent* evt) override;
};

SdlQtRGB.cpp

#include "SdlQtRGB.h"
#include "XVideoView.h"
#include 
#include 
#include 

using namespace std;

static unsigned char* yuv = nullptr;
static int sdl_width = 0;
static int sdl_height = 0;
static int pixel_size = 2;
static ifstream yuv_file;
static XVideoView* view = nullptr;

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);

    view = XVideoView::create();

    if (view)
    {    
        view->init(sdl_width, sdl_height, XVideoView::YUV420P);
        view->init(sdl_width, sdl_height, XVideoView::YUV420P, (void*)ui.label->winId());
    }
    
    yuv = new unsigned char[sdl_width * sdl_height * pixel_size];

    startTimer(10);  // 每过10ms就会调用一次 timerEvent,1s大约有100帧的图像
}

void SdlQtRGB::timerEvent(QTimerEvent* evt)
{
    yuv_file.read((char*)yuv, sdl_width * sdl_height * 1.5);  // 读取一帧数据

    if (view)
    {
        view->draw(yuv);

        if (view->isExit())
        {
            view->close();
            delete view;

            exit(0);
        }
    }
}

void SdlQtRGB::resizeEvent(QResizeEvent* evt)
{
    ui.label->resize(size());
    ui.label->move(0, 0);
    // view->scale(width(), height());
}

SdlQtRGB::~SdlQtRGB()
{
    delete[] yuv;
}

测试结果

 可以成功的渲染。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/779737.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号