1.渲染项目
SDL渲染RGB数据到Qt的控件,并能够通过定时器刷新
背景
简单的理解一下SDL和QT之间的功能:SDL是音视频播放和渲染的一个开源库,主要利用它进行视频渲染和音频播放。Qt主要用于写播放器简单UI,也就是最后的图像展示。
- SDL和QT之间的对比,参考:https://blog.csdn.net/u012939880/article/details/107149405
背景:使用SD渲染图像,并且能通过定时器不断刷新,最后的显示窗口通过QT界面显示。实现SDL和QT的联合渲染。
实现方法:把QT的窗口句柄的winld值,赋给SDL的环境变量。
- SDL初始化
- 创建窗口时用QT创建,其中lable对应的窗口句柄传给SDL
- 创建渲染器、材质,定时刷新函数
问题1:qt无法打开ui文件
解决办法:https://blog.csdn.net/cpp_learner/article/details/114703212
过程总结:
- 显示页面尺寸:QWidget——geometry 中的宽度和高度 目的是为了创建材质的大小
- 结果展示时:刷新的时候界面先刷新一下,是因为QT的界面刷新,然后才是定时器
- 在函数重载是,要在后面加上override 防止重载写错,一旦写错很难发现
具体操作细节,例如如何创建QT以及SDL配置参考:
1.SDL渲染流程:
2.创建QT:https://www.cnblogs.com/yongdaimi/p/15559261.html
代码展示:
头文件
#pragma once
#include <QtWidgets/QWidget>
#include "ui_sdlqtrgb.h"
class SDLQTRGB : public QWidget
{
Q_OBJECT
public:
SDLQTRGB(QWidget *parent = Q_NULLPTR);
void timerEvent(QTimerEvent* ev) override;//一般来说现在在重载函数后面加上override 防止重载写错
private:
Ui::SDLQTRGBClass ui;
};
cpp文件
#include "sdlqtrgb.h"
#include<SDL.h>
#include<iostream>
#pragma conmment(lib,"SDL2.lib")
using namespace std;
//全局静态变量的定义
static int sdl_width = 0;
static int sdl_height = 0;
static SDL_Window* sdl_window = NULL;// 窗口,静态全局变量只在本cpp文件内有效
static SDL_Renderer* sdl_render = NULL;//渲染器
static SDL_Texture* sdl_texture = NULL;//材质
static unsigned char* rgb = NULL;
static int pixel_size = 4;//这里面是看你的RGB像素格式的
SDLQTRGB::SDLQTRGB(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
//SDL_Init(SDL_INIT_VIDEO); //初始话语句
//1. 初始化判断是否创建成功 成功返回0 失败返回非0值
if (SDL_Init(SDL_INIT_VIDEO))
{
cout << SDL_GetError << endl;
}
//取得之前创建的lable的宽和高 guoqu
sdl_width = ui.label->width(); //这里面将sdl_width 做成全局静态变量
sdl_height = ui.label->height();
//2. 创建窗口,这里取得lable所对应的窗口句柄
sdl_window = SDL_CreateWindowFrom((void*)ui.label->winId());//获取控件,这里是指针类型的,转成void *
if (!sdl_window)
{
cout << SDL_GetError << endl;
}
//3.创建渲染器
sdl_render = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_ACCELERATED);
if (!sdl_render)
{
cout << SDL_GetError << endl;
return;
}
//4.创建材质
sdl_texture = SDL_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, sdl_width, sdl_height);//要修改的
if (!sdl_texture)
{
cout << SDL_GetError << endl;
return;
}
//申请一块内存空间用于存放RGB数据
rgb = new unsigned char[sdl_width * sdl_height * pixel_size];//注意new了之后,就要考虑什么时候释放内存
/*如果析构当中销毁:考虑一个问题,在这个窗口对象(因为写的对象就是窗口对象)被销毁的时候,也就是窗口被关闭的时候,考虑是否还会
*有其他元素访问到这个rgb,如果在另外一个线程访问时,会发生:窗口关闭了,但依然还被访问,那么程序就会宕掉,所以要考虑是都还有线程被读写
*(主程序关掉并不能保证子线程退出,所以一般在处理多线程析构的时候要去让子线程退出*/
//定时器刷新 10ms
startTimer(20);
}
//定时进入不能保证准确性,要自己确认
void SDLQTRGB::timerEvent(QTimerEvent* ev)
{
static unsigned char tmp = 255;
tmp--;
//动态的更新RGB图像
for (int j = 0;j < sdl_height;j++)
{
int begin = j * sdl_width * pixel_size;
for (int i = 0;i < sdl_width * pixel_size;i += 4)
{
rgb[begin + i] = 0; //B
rgb[begin + i + 1] = tmp;//G
rgb[begin + i + 2] = 0;//R
rgb[begin + i + 3] = tmp;//A
}
}
// 5. 动态更新材质信息
if (SDL_UpdateTexture(sdl_texture, NULL, rgb, sdl_width * pixel_size))
{
cout<<SDL_GetError<<endl;
return;
}
//6. 清理屏幕
if (SDL_RenderClear(sdl_render))
{
cout << SDL_GetError() << endl;
return;
}
//7.复制材质到渲染对象
SDL_Rect rect; //rect是目标位置 设定渲染的目标区域
rect.x = 0;
rect.y = 0;
rect.w = sdl_width;
rect.h = sdl_height;
if (SDL_RenderCopy(sdl_render, sdl_texture, NULL, &rect))
{
cout << SDL_GetError << endl;
return;
}
//8.执行渲染操作
SDL_RenderPresent(sdl_render);
}
内容后续继续完善……