网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
显示基本流程其实就是 创建SDL 创建窗口 绑定窗口渲染器 创建纹理 设置纹理到渲染器进行显示
初始化SDL extern DECLSPEC int SDLCALL SDL_Init(Uint32 flags);
创建windows窗口 extern DECLSPEC SDL_Window * SDLCALL SDL_CreateWindow(const char *title,int x, int y, int w, int h, Uint32 flags);
创建对应窗口的渲染器 SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags);
创建纹理数据 SDL_CreateTextureFromSurface()或者 SDL_CreateTexture();
设置纹理到渲染器上 extern DECLSPEC int SDLCALL SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,const SDL_Rect * srcrect,const SDL_Rect * dstrect);
显示到窗口 extern DECLSPEC void SDLCALL SDL_RenderPresent(SDL_Renderer * renderer);
延迟 SDL_Delay(10000);
清理内存 SDL_DestroyTexture(tex);SDL_DestroyRenderer(ren);SDL_DestroyWindow(win);
退出SDL_Quit();
### 2.2、API介绍
SDL_Init 初始化
1、int SDL_Init(Uint32 flags)
flages:
SDL_INIT_TIMER 定时器子系统
SDL_INIT_AUDIO 音频子系统
SDL_INIT_VIDEO 视频子系统,同时会初始化事件子系统
SDL_INIT_EVENTS 事件子系统
SDL_INIT_EVERYTHING 初始化所有子系统
2、SDL_CreateWindow 创建窗口
SDL_Window* SDL_CreateWindow(const char *title,
int x, int y, int w,
int h, Uint32 flags);
title:窗口标题
x,y,w,h:窗口坐标 中间(SDL_WINDOWPOS_CENTERED)还是不指定(SDL_WINDOWPOS_UNDEFINED)
flags:
::SDL_WINDOW_FULLSCREEN,//全屏 ::SDL_WINDOW_OPENGL,//使用OpenGL上下文
::SDL_WINDOW_HIDDEN, //窗口不可见 ::SDL_WINDOW_BORDERLESS, //无边框
::SDL_WINDOW_RESIZABLE,//窗口大小可变 ::SDL_WINDOW_MAXIMIZED, //窗口最大化
::SDL_WINDOW_MINIMIZED,//窗口最小化 ::SDL_WINDOW_INPUT_GRABBED,//输入捕获
3、SDL_CreateRenderer 创建渲染器
SDL_Renderer* SDL_CreateRenderer(SDL_Window* window,
int index,
Uint32 flags)
window: 指明在哪个窗口里进行渲染
index: 指定渲染驱动的索引号。一般指定为 -1.
flags:
SDL_RENDERER_SOFTWARE //The renderer is a software fallback 软件备份
SDL_RENDERER_ACCELERATED //The renderer uses hardware acceleration 硬件加速
SDL_RENDERER_PRESENTVSYNC //Present is synchronized with the refresh rate 刷新率同步
SDL_RENDERER_TARGETTEXTURE //The renderer supports rendering to texture 支持渲染纹理
4、SDL_CreateTexture()基于渲染器创建一个纹理
SDL_Texture * SDLCALL SDL_CreateTexture(SDL_Renderer * renderer,
Uint32 format,
int access, int w,int h);
renderer:目标渲染器。
format :纹理的格式。后面会详述。
access :可以取以下值(定义位于SDL_TextureAccess中)
SDL_TEXTUREACCESS_STATIC :变化极少
SDL_TEXTUREACCESS_STREAMING :变化频繁
SDL_TEXTUREACCESS_TARGET :暂时没有理解
w :纹理的宽
h :纹理的高
创建成功则返回纹理的ID,失败返回0
但是其中有部分细节
### 2.3、加载图片的话利用Surface来加速一下
//加载图片 利用Surface 返回指定渲染器的图片纹理
SDL_Texture * LoadImage(string str_path)
{
SDL_Texture * tex = NULL;
SDL_Surface *bmp = NULL;
//加载图片到Surface 便于硬件加速
bmp = SDL\_LoadBMP(str_path.c\_str());
if (bmp == NULL)
{
cout << "SDL\_LoadBMP error" << endl;
return tex;
}
//在指定渲染器Renderer上创建纹理Texture
tex = SDL\_CreateTextureFromSurface(ren, bmp);
//释放Surface内存
SDL\_FreeSurface(bmp);
return tex;
}
### 2.4、需要指定纹理的位置大小 要利用SDL\_Rect数据结构
//绘制图像 指定位置
void ApplySurface(int x, int y, SDL_Texture *tex, SDL_Renderer *rend)
{
//为了指定纹理Texture的绘制位置 我们需要创建一个SDL_Rect表示一个矩形 有位置宽高参数
//矩形
SDL_Rect pos;
pos.x = x;//坐标
pos.y = y;
//通过纹理Texture查询纹理图片的宽高
SDL\_QueryTexture(tex, NULL, NULL, &pos.w, &pos.h);
//在渲染器ren的pos位置绘制纹理图像tex
SDL\_RenderCopy(ren, tex, NULL, &pos);
return;
}
### 2.5、SDL中的数据结构及SDL坐标
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210328100227914.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p3MTk5Ng==,size_16,color_FFFFFF,t_70#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210328103200676.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p3MTk5Ng==,size_16,color_FFFFFF,t_70#pic_center)
### 3、SDL显示图片
#include
#include
using namespace std;
#ifdef __cplusplus
extern “C”
{
#endif // !__cplusplus
#include “SDL.h”
//#include “SDL_main.h”
#ifdef __cplusplus
}
#endif // !__cplusplus
#pragma comment(lib,“SDL2.lib”)
#pragma comment(lib,“SDL2main.lib”)
#pragma comment(lib,“SDL2test.lib”)
#pragma comment(lib,“legacy_stdio_definitions.lib”)
extern “C” { FILE __iob_func[3] = { *stdin,*stdout,*stderr }; }
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
SDL_Window *win = NULL;
SDL_Renderer *ren = NULL;
//加载图片 返回指定渲染器的图片纹理
SDL_Texture * LoadImage(string str_path)
{
SDL_Texture * tex = NULL;
SDL_Surface *bmp = NULL;
//加载图片到Surface 便于硬件加速
bmp = SDL\_LoadBMP(str_path.c\_str());
if (bmp == NULL)
{
cout << "SDL\_LoadBMP error" << endl;
return tex;
}
//在指定渲染器Renderer上创建纹理Texture
tex = SDL\_CreateTextureFromSurface(ren, bmp);
//释放Surface内存
SDL\_FreeSurface(bmp);
return tex;
}
//绘制图像 指定位置
void ApplySurface(int x, int y, SDL_Texture *tex, SDL_Renderer *rend)
{
//为了指定纹理Texture的绘制位置 我们需要创建一个SDL_Rect表示一个矩形 有位置宽高参数
//矩形
SDL_Rect pos;
pos.x = x;//坐标
pos.y = y;
//通过纹理Texture查询纹理图片的宽高
SDL\_QueryTexture(tex, NULL, NULL, &pos.w, &pos.h);
/\*
extern DECLSPEC int SDLCALL SDL_RenderCopy(SDL_Renderer * renderer,
SDL_Texture * texture,
const SDL_Rect * srcrect,
const SDL_Rect * dstrect);
//两个NULL分别是第一个NULL是一个指向源矩形的指针,从图像上裁剪下的一块矩形;而另一个是指向目标矩形的指针。
我们将NULL传入这两个参数,
是告诉SDL绘制整个源图像(第一个NULL),并把它画在屏幕上(0,0 )的位置,
拉伸这个图像让它填满整个窗口(第二个NULL)
SDL_RenderCopy(ren, tex, NULL, NULL);
*/
//在渲染器ren的pos位置绘制纹理图像tex
SDL_RenderCopy(ren, tex, NULL, &pos);
return;
}
int main(int argc, char *argv[])
{
//SDL初始化
if (SDL_Init(SDL_INIT_VIDEO))
{
cout << “SDL_Init error” << endl;
}
else
{
cout << “SDL_Init success” << endl;
}
/*SDL创建windows窗口
extern DECLSPEC SDL_Window * SDLCALL SDL_CreateWindow(const char *title,
int x, int y, int w,
int h, Uint32 flags);
标题 坐标 宽高 属性
SDL_WINDOW_SHOWN 表示创建之后马上弹出显示
*/
//SDL_WINDOWPOS_CENTERED表示sdl把窗口设定到指定坐标轴的中央
win = SDL_CreateWindow(“Paint Picture!” ,SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (win == NULL)
{
cout << “SDL_CreateWindow error” << endl;
return -1;
}
/*
创建渲染器 需指定我们用来绘制的窗口win
extern DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window * window,
int index, Uint32 flags);
指定渲染器绑定的窗口 指定可选用的显卡驱动 -1表示sdl自动选择 选择额外属性
SDL_RENDERER_ACCELERATED 表示使用硬件加速 使用显卡
SDL_RENDERER_PRESENTVSYNC 表示使用显示器的刷新率来更新画面
*/
ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (ren == NULL)
{
cout << “SDL_CreateRenderer error” << endl;
return -1;
}
SDL_Texture \*background = NULL, \*image = NULL;
background = LoadImage("4.bmp");
image = LoadImage("5.bmp");
if (background == NULL || image == NULL)
{
cout << "LoadImage error" << endl;
return -1;
}
SDL\_RenderClear(ren);//先清除
int bw, bh;
SDL\_QueryTexture(background, NULL, NULL, &bw, &bh);
for (int i = 0; i < SCREEN_WIDTH; i+= bw)
{
for (int j = 0; j < SCREEN_HEIGHT; j += bh)
{
ApplySurface(i, j, background, ren);
}
}
SDL\_QueryTexture(image, NULL, NULL, &bw, &bh);
int x = SCREEN_WIDTH / 2 - bw / 2;
int y = SCREEN_HEIGHT / 2 - bh / 2;
ApplySurface(x, y, image, ren);
SDL\_RenderPresent(ren);//刷新
SDL\_Delay(10000);//延迟展示
//清除内存
SDL\_DestroyTexture(background);
SDL\_DestroyTexture(image);
SDL\_DestroyRenderer(ren);
SDL\_DestroyWindow(win);
SDL\_Quit();
return 0;
}
参考博客[SDL显示图片](https://bbs.csdn.net/topics/618668825)
### 4、SDL显示视频
#include
#include
using namespace std;
#ifdef __cplusplus
extern “C”
{
#endif // !__cplusplus
#include “SDL.h”
//#include “SDL_main.h”
#ifdef __cplusplus
}
#endif // !__cplusplus
#pragma comment(lib,“SDL2.lib”)
#pragma comment(lib,“SDL2main.lib”)
#pragma comment(lib,“SDL2test.lib”)
//解决VS2015库不对应问题
#pragma comment(lib,“legacy_stdio_definitions.lib”)
extern “C” { FILE __iob_func[3] = { *stdin,*stdout,*stderr }; }
//每个像素点占的位数 YUV420就是12个位 8+2+2
const int bpp = 12;
//窗口大小
const int screen_w = 640, screen_h = 360;
//视频大小
const int pixel_w = 640, pixel_h = 360;
//每帧图像的内存存放
unsigned char buffer[pixel_w*pixel_h*bpp / 8];
int main(int argc, char *argv[])
{
//SDL初始化
if (SDL_Init(SDL_INIT_VIDEO))
{
cout << “SDL_Init error” << endl;
return -1;
}
else
{
cout << “SDL_Init success” << endl;
}
//创建窗口
//SDL\_WINDOWPOS\_CENTERED 居中
//SDL\_WINDOW\_OPENGL 使用openGL SDL\_WINDOW\_RESIZABLE无边框
SDL_Window \*screen = NULL;
screen = SDL\_CreateWindow("SDL Play Vedio", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
screen_w, screen_h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (!screen)
{
cout << "SDL\_CreateWindow error" << endl;
return -1;
}
//创建窗口的渲染器 -1表示渲染驱动自动选择
SDL_Renderer\* sdlRenderer = SDL\_CreateRenderer(screen, -1, 0);
Uint32 pixformat = 0;
//IYUV: Y + U + V (3 planes)
//YV12: Y + V + U (3 planes)
pixformat = SDL_PIXELFORMAT_IYUV; //YUV422 则每个像素占12位
//创建纹理 之前也可以使用从suface中获取
/\*
extern DECLSPEC SDL_Texture * SDLCALL SDL_CreateTexture(SDL_Renderer * renderer,
Uint32 format, //纹理的格式
int access, //SDL_TEXTUREACCESS_STREAMING 表示变化频繁
int w, int h);//纹理数据的宽高
*/
SDL_Texture* sdlTexture = NULL;
sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h);
if (sdlTexture == NULL)
{
cout << “SDL_CreateWindow error” << endl;
return -1;
}
//打开视频文件
FILE \*fp = NULL;
fp = fopen("sintel\_640\_360.yuv", "rb+");
if (fp == NULL) {
printf("cannot open this file\n");
return -1;
}
//使用矩形来定位纹理显示在渲染器的坐标
SDL_Rect sdlRect;
while (1) {
//每次读取一个帧画面
if (fread(buffer, 1, pixel_w\*pixel_h\*bpp / 8, fp) != pixel_w\*pixel_h\*bpp / 8) {
// Loop
fseek(fp, 0, SEEK\_SET);
fread(buffer, 1, pixel_w\*pixel_h\*bpp / 8, fp);
}
//将数据填充到纹理中
/\*
extern DECLSPEC int SDLCALL SDL_UpdateTexture(SDL_Texture * texture,
const SDL_Rect * rect,
const void *pixels,//数据内存地址
int pitch);//像素数据行之间的字节数
//填充纹理还可以使用
extern DECLSPEC int SDLCALL SDL_UpdateYUVTexture(SDL_Texture * texture,
const SDL_Rect * rect,
const Uint8 *Yplane, int Ypitch,
const Uint8 *Uplane, int Upitch,
const Uint8 *Vplane, int Vpitch);
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
ect,
const Uint8 *Yplane, int Ypitch,
const Uint8 *Uplane, int Upitch,
const Uint8 *Vplane, int Vpitch);
[外链图片转存中…(img-7P4jmowf-1715745216821)]
[外链图片转存中…(img-2S2IXk0i-1715745216822)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!