ffmpeg-5、SDL的vs环境部署及图片显示 、视频播放、音频播放_sdl播放图片

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事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);

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事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行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值