SDL结合QWidget的简单使用说明
SDL(Simple DirectMeida Layer)是一个简单的封装媒体库,功能主要涉及了相关于OpenGL或者DirectX的显卡硬件功能和一些鼠标,键盘等外设访问。这里主要只说明一下它的渲染功能
因为Qt本身不支持YUV流媒体数据显示,且QWidget默认是栅格式渲染(qml是默认GPU),用的是CPU,这样如果渲染方面涉及了反走样,优化等数据计算,对CPU的消耗是比较高的,这里我们期望能用GPU来负责处理渲染
GPU的处理就必须使用能调用显卡的功能,通常来说在Win下是Opengl和D3D,但是要短时间熟悉使用还是比较麻烦的,这里就需要SDL了;SDL已经在下层封装好了这些显卡相关库的使用,我们只需要按照他定义的更简洁的一系列接口即可实现效果
这里以YV12为例,因为个人需求,我又加上了在渲染层上再渲染一张png图片和一段文字的效果
首先在官网下载源代码http://www.libsdl.org/download-2.0.php
目前最新的源码版本是2.0.8,且主页依然提供了1.0版本的下载。1.0的使用和接口跟2.0有很多不一样的地方,这里建议还是直接用最新版
下载解压后目录如图
可以看到SDL支持各大主流平台,这里因为是在Win上,直接进入VisualC目录
解决方案已经存在,直接打开编译即可。
成功后在输出目录找到
这就是我们需要的动态库(另外还有一个SDL2main的库,因为我们是通过Qt创建的窗口,所以这个不需要了,如果完全使用SDL来建立渲染窗口的话,一定要加上这个库)
下一步,先创建一个QWidget用来做渲染
#ifndef _SDL_RENDER_WND_H__
#define _SDL_RENDER_WND_H__
/********************************************************************
文件名 : SDLRenderWnd
作者 : @Kaiming
创建时间: 2018/3/26 11:27
版本 : 1.0
文件描述: SDL YUV420流输出窗口
*********************************************************************/ #include <QWidget>
struct SDL_Renderer;
struct SDL_Texture;
struct SDL_Window; class SDLRenderWnd : public QWidget
{
Q_OBJECT public:
SDLRenderWnd(QWidget *parent = );
~SDLRenderWnd(); void Clear(); protected:
virtual void resizeEvent(QResizeEvent *event); private:
static void SDL_Related_Init();
static void SDL_Related_Uninit(); public slots:
//根据传入数据流显示视频
void PresentFrame(const unsigned char* pBuffer, int nImageWidth, int nImageHeight);
private:
SDL_Renderer* m_pRender;
SDL_Texture* m_pTexture;
SDL_Window* m_pWindow; static int m_nRef; //引用计数来确定SDL全局资源的创建和回收
}; #endif // _SDL_RENDER_WND_H__
具体实现
#include "SDLRenderWnd.h"
extern "C" {
#include "sdl\SDL.h"
}
#pragma comment(lib, "SDL2.lib") int SDLRenderWnd::m_nRef = ;
SDLRenderWnd::SDLRenderWnd(QWidget *parent)
: QWidget(parent),
m_pTexture(nullptr),
m_bEmpty(true)
{
setUpdatesEnabled(false);
SDL_Related_Init();
m_pWindow = SDL_CreateWindowFrom((void*)winId());
m_pRender = SDL_CreateRenderer(m_pWindow, -, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
} SDLRenderWnd::~SDLRenderWnd()
{
if (m_pWindow)
SDL_DestroyWindow(m_pWindow);
if (m_pRender)
SDL_DestroyRenderer(m_pRender);
if (m_pTexture)
SDL_DestroyTexture(m_pTexture);
SDL_Related_Uninit();
} void SDLRenderWnd::PresentFrame(const unsigned char* pBuffer, int nImageWidth, int nImageHeight)
{
if (!m_pRender) {
printf("Render not Create\n");
}
else {
int nTextureWidth = , nTextureHeight = ;
//首先查询当前纹理对象的宽高,如果不符合,那么需要重建纹理对象
SDL_QueryTexture(m_pTexture, nullptr, nullptr, &nTextureWidth, &nTextureHeight);
if (nTextureWidth != nImageWidth || nTextureHeight != nImageHeight) {
if (m_pTexture)
SDL_DestroyTexture(m_pTexture);
//这里指定了渲染的数据格式,访问方式和宽高大小
m_pTexture = SDL_CreateTexture(m_pRender, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING,
nImageWidth, nImageHeight);
}
} if (!m_pTexture) {
printf("YUV Texture Create Failed\n");
}
else {
//用新数据刷新纹理
SDL_UpdateTexture(m_pTexture, nullptr, pBuffer, nImageWidth);
//清除当前渲染
SDL_RenderClear(m_pRender);
//拷贝纹理对象到渲染器中
SDL_RenderCopy(m_pRender, m_pTexture, nullptr, nullptr);
//最终渲染
SDL_RenderPresent(m_pRender);
}
} void SDLRenderWnd::Clear()
{
} void SDLRenderWnd::SDL_Related_Init()
{
if ( == m_nRef++)
{
SDL_Init(SDL_INIT_VIDEO);
}
} void SDLRenderWnd::SDL_Related_Uninit()
{
if ( == --m_nRef)
{
SDL_Quit();
}
}
因为SDL是纯C库,注意加上extern “C";通过SDL_CreateWindowFrom((void*)winId());建立QWidget的窗口句柄和SDL的联系,这之后,Widget本身就没什么操作的了,剩下的工程都交给SDL来负责;然后通过创建的SDL_Window建立SDL_Render渲染器
渲染过程具体看PresentFrame里面的注释,还有一点要特别注意的是一定要加上setUpdatesEnabled(false);这句是关闭QWidget自身的刷新动作,如果不设置,那么就会存在两个渲染互相刷新,如果窗口不动还好,一旦resize的时候就就会有明显的闪烁效果
还有一点就是,参看我头文件里是把PresentFrame写成了一个slot,所以刷新动作是放在主线程执行的,并不是说子线程执行不可以,但是从自己的测试来看,子线程执行渲染会出现很多不可预知的问题,比如窗口缩放后会导致渲染无效,崩溃等等。另外提一句老生常谈的话就是调用这个slot注意保护参数,数据流是指针形式,如果异步执行要小心指针无效的情况
下一篇谈在这个基础上给视频加图片,文字效果的方式
SDL结合QWidget的简单使用说明的更多相关文章
- SDL结合QWidget的简单使用说明(2)
上篇主要讲了针对yv12流数据的渲染,但有时候我们显示视频还要求加一些信息,比如头像,昵称等等.一般的想法是在渲染窗口之上做一个小控件来负责: 但是很遗憾,你会发现你的控件被SDL的渲染完全遮住了,渲 ...
- Oracle 中 union 和union all 的简单使用说明
1.刚刚工作不久,经常接触oracle,但是对oracle很多东西都不是很熟.今天我们来了解一下union和union all的简单使用说明.Union(union all): 指令的目的是将两个 S ...
- struts 标签<s:ierator>的简单使用说明
struts 标签<s:ierator>的简单使用说明,只显示<s:ierator> 的前6条数据 <s:iterator value="lstVisitor& ...
- Spring依赖注入 --- 简单使用说明
Spring依赖注入 --- 简单使用说明 本文将对spring依赖注入的使用做简单的说明,enjoy your time! 1.使用Spring提供的依赖注入 对spring依赖注入的实现方法感兴趣 ...
- Linux下源码安装ffmpeg及ffmpeg的简单使用说明
一.编译安装 ffmpeg在安装时依赖的包和版本都很让人头疼,不同编译环境也各不相同.公司之前封装了一个又各种出错. 其实办法很简单,就是到官网一步一步按着做就行了:http://trac.ffmpe ...
- Android自定义属性简单使用说明
原创文章,转载请注明出处:http://www.cnblogs.com/baipengzhan/p/Android_attrs.html 本文从实用角度说明Android自定义属性的基本使用流程,清晰 ...
- ViewPager的简单使用说明
前提:工程中使用ViewPager,需要导入google提供的jar包(android-support-v4.jar). 要学习ViewPager的使用,建议直接看官方文档 Creating Swip ...
- jmeter作接口测试入门的简单使用说明
一.添加接口信息 1.添加线程组 (1)路径如下图: (2)部分内容解释 a. Number of Threads(users):线程数 b. Ramp-Up Period(in seconds) ...
- GreenDao的简单使用说明(五)多表n:m
在设计一些比较复杂的数据库结构的时候,我们会遇到表之间是n:m的关系,就是常说的多对多的关系,最常用的情况,就是用户权限这块,日常最常见的就是学生与老师的关系了,哪么我们来看一下GreenDao中如何 ...
随机推荐
- samtools flags 的含义
对于双端比对的数据,生成的BAM文件中,R1端序列和R2端序列的标识符是一样的,之前一直不知道如何根据bam文件区分哪条序列是R1端,哪条序列是R2端,昨天仔细研究了一下,原来代表R1端和R2端的信息 ...
- 一些 Linux 常用命令说明
目前由于自己接触到的是 Windows 的操作系统,所以会经常使用 git bash 来提交代码到 github上. git bash 是 Windows 下模拟 Linux 的命令行工具. 在此总结 ...
- 结构型模式概述(Structural Pattern)
结构型模式可以描述两种不同的东西:类与类的实例.结构型模式可以分为类结构型模式和对象结构型模式. 类结构型模式关心类的组合,可以由多个类组合成一个更大的系统,在类结构型模式中只存在继承关系和实现关系: ...
- 甘特图生产排程(APS)定制开发
高速开发完毕APS的数据可视化.订单展示.资源调度.智能排程等差点儿所有功能模块. 自己主动智能排程功能 提供专业需求分析师及开发团队,按需开发"全自己主动智能排程"这一APS的主 ...
- Bitmap之安卓手机壁纸的设置
MainActivity: package com.hyzhou.imagedemo; import java.io.File; import android.os.Bundle; import an ...
- GIS-ArcGIS 数据库备份还原
Create directory sdebak as 'E:\10_DataFile'; alter system set deferred_segment_creation=false; ALTER ...
- ftp简单命令
1.连接ftp ftp 192.168.10.15 进去后输入用户名 ,然后再输入密码,就这样登陆成功了,你会看到 ftp> 2.进入ftp后,你对目录需要切换操作.和linux一样的命令.cd ...
- php学习十一:组合
我们在类当中我往往会用到一些对象,此时的继承就无法满足我们的需求,这个时候我们需要用到组合.继承如果是is..a的关系,那么组合就是has...a的关系,直接在本类里面声明即可,不过声明的是一个对象 ...
- linux mysql添加用户,删除用户,以及用户权限
一些主要的命令: 登录: mysql -u username -p 显示全部的数据库: show databases; 使用某一个数据库: use databasename; 显示一个数据库的全部表: ...
- java+socket 简易聊天工具
1.服务器端程序 package com.test3; import java.io.*; import java.net.*; import java.awt.*; import java.awt. ...