SDL配置与简单使用
windows安装:在VS2019中使用
1.官网下载:
解压
2:新建vs空项目
3:配置:
包含目录:include目录
库目录:lib/x64
添加依赖项:
窗口更改
4:将dll放在exe文件夹下(或者项目同级目录下)
5:测试
#include<SDL.h>
//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
int main(int argc, char* argv[]) {
//The window we'll be rendering to
SDL_Window* window = NULL;
//The surface contained by the window
SDL_Surface* screenSurface = NULL;
//Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
SDL_Log("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
}
else {
//Create window
window = SDL_CreateWindow("title", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (window == NULL) {
SDL_Log("Window could not be created! SDL_Error: %s\n", SDL_GetError());
}
else {
//Get window surface
screenSurface = SDL_GetWindowSurface(window);
//Fill the surface white
SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0xFF, 0xFF, 0xFF));
//Update the surface
SDL_UpdateWindowSurface(window);
//Hack to get window to stay up
SDL_Event e;
bool quit = false;
while (quit == false) {
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) quit = true;
}
}
}
//Destroy window
SDL_DestroyWindow(window);
//Quit SDL subsystems
SDL_Quit();
return 0;
}
}
结果:
SDL简单使用(播放yuv,与pcm数据)
1:窗口
SDL_Init(SDL_INIT_VIDEO);
window = SDL_CreateWindow("SDL2 Window", 200, 200, 640, 480, SDL_WINDOW_SHOWN );
render = SDL_CreateRenderer(window, -1, 0);
SDL_RenderClear(render);
SDL_RenderPresent(render);
2:事件检测
SDL_Event event;
SDL_WaitEvent(&event);
event.type==SDL_QUIT;
3:纹理渲染
3.1:纹理相关API
3.2:渲染相关API
4:播放视频(YUV)
下面说明一下使用SDL播放YUV视频的基本流程,主要分为两大部分:初始化SDL、循环显示画面。
4.1 初始化SDL
1). 初始化SDL (SDL_Init)
2). 创建窗口(SDL_CreateWindow)
3). 基于窗口创建渲染器(SDL_CreateRenderer)
4). 创建纹理(SDL_CreateTexture)
4.2 循环显示画面
1). 设置纹理的数据(SDL_UpdateTexture)
2). 纹理复制给渲染目标(SDL_RenderCopy)
3). 显示(SDL_RenderPresent)
4.3 代码实现:
/*
功能:使用SDL播放本地yuv视频
问题:宽高设置,缓冲区使用malloc分配堆区
播放一会就停止
原因:video_fd = fopen(path, "r");
要用rb模式,二进制方式读取
*/
#include <iostream>
extern "C" {
#include "SDL.h"
}
//Bit per Pixel
const int bpp = 12;
int screen_w = 960, screen_h = 640;
// 根据不同的YUV视频,来设置不同的 宽 * 高 数据
const int pixel_w = 854, pixel_h = 480;
unsigned char buffer[pixel_w * pixel_h * bpp / 8];
//Refresh Event
#define REFRESH_EVENT (SDL_USEREVENT + 1)
int thread_exit = 0;
int refresh_video(void* opaque) {
while (thread_exit == 0) {
SDL_Event event;
event.type = REFRESH_EVENT;
SDL_PushEvent(&event);
SDL_Delay(40);
}
return 0;
}
int main(int argc, char* argv[])
{
if (SDL_Init(SDL_INIT_VIDEO)) {
printf("Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}
SDL_Window* window;
// 创建SDL窗口
window = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_w, screen_h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
// 判断是否创建窗口成功
if (!window) {
printf("SDL: could not create window - exiting:%s\n", SDL_GetError());
return -1;
}
// 创建SDL渲染器
SDL_Renderer* sdlRenderer = SDL_CreateRenderer(window, -1, 0);
// 声明像素格式
Uint32 pixformat = 0;
// IYUV: Y + U + V (3 planes)
// YV12: Y + V + U (3 planes)
// I420也叫IYUV, 也叫YUV420
pixformat = SDL_PIXELFORMAT_IYUV;
// 按照YUV视频的宽高创建SDL纹理对象
SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h);
FILE* fp = NULL;
fp = fopen("F:/learn_ffmpeg/vs_works/test_FFmpeg/test_FFmpeg/test.yuv", "rb+");
if (fp == NULL) {
printf("cannot open this file\n");
return -1;
}
SDL_Rect sdlRect;
SDL_Thread* refresh_thread = SDL_CreateThread(refresh_video, NULL, NULL);
SDL_Event event;
while (1) {
//Wait
SDL_WaitEvent(&event);
if (event.type == REFRESH_EVENT) {
// 读取一帧数数据到缓冲区
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);
}
// 将数据更新到纹理
SDL_UpdateTexture(sdlTexture, NULL, buffer, pixel_w);
//FIX: If window is resize
sdlRect.x = 0;
sdlRect.y = 0;
sdlRect.w = screen_w;
sdlRect.h = screen_h;
SDL_RenderClear(sdlRenderer);
// 将更新后的纹理拷贝到渲染器
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);
// 渲染器显示画面
SDL_RenderPresent(sdlRenderer);
//Delay 40ms -- Dealy时常根据帧率进行调整
SDL_Delay(40);
}
else if (event.type == SDL_WINDOWEVENT) {
//If Resize
SDL_GetWindowSize(window, &screen_w, &screen_h);
}
else if (event.type == SDL_QUIT) {
break;
}
}
return 0;
}
5:播放音频(pcm)
5.1 函数调用步骤如下:
* 函数调用步骤如下:
*
* [初始化]
* SDL_Init(): 初始化SDL。
* SDL_OpenAudio(): 根据参数(存储于SDL_AudioSpec)打开音频设备。
* SDL_PauseAudio(): 播放音频数据。
*
* [循环播放数据]
* SDL_Delay(): 延时等待播放完成。
5.2 代码实现
/**
* 功能:最简单的SDL2播放音频的例子(SDL2播放PCM)
*
* SDL实际上是对底层绘图 API(Direct3D,OpenGL)的封装
*
* 函数调用步骤如下:
*
* [初始化]
* SDL_Init(): 初始化SDL。
* SDL_OpenAudio(): 根据参数(存储于SDL_AudioSpec)打开音频设备。
* SDL_PauseAudio(): 播放音频数据。
*
* [循环播放数据]
* SDL_Delay(): 延时等待播放完成。
*
*/
#include<SDL.h>
#include<stdio.h>
#define BLOCK_SIZE 4096000//太小的话会播放一半就结束了
static Uint8* audio_buf = NULL;
static size_t buffer_len = 0;
static Uint8 *audio_pos = NULL;
void read_audio_data(void* udata, Uint8* stream, int len) {
if (buffer_len == 0) {
return;
}
//SDL2中必须首先使用SDL_memset()将stream中的数据设置为0。
SDL_memset(stream, 0, len);//清空缓冲区
len = (len < buffer_len) ? len : buffer_len;
SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);
audio_pos += len;
buffer_len -= len;
}
int main(int argc, char* argv[]) {
int ret = -1;
char* path = "1.pcm";
FILE * audio_fd = NULL;
//SDL_Init该函数可以确定希望激活的子系统
if (SDL_Init(SDL_INIT_AUDIO)) {
SDL_Log("Failed to init!\n");
return ret;
}
audio_fd = fopen(path, "rb");//rb??
if (!audio_fd) {
SDL_Log("Failed to open pcm file!\n");
goto __FAIL;
}
audio_buf = (Uint8*)malloc(BLOCK_SIZE);
if (!audio_buf) {
SDL_Log("Failed to alloc memory!\n");
goto __FAIL;
}
SDL_AudioSpec spec;
spec.freq = 48000;
spec.channels = 5.1;
spec.format = AUDIO_S16LSB;
spec.callback = read_audio_data; //回调函数的作用是填充音频缓冲区,当音频设备需要更多的数据的时候会调用该回调函数
spec.userdata = NULL;
if (SDL_OpenAudio(&spec, NULL))
{
SDL_Log("Failed to open audio device!\n");
goto __FAIL;
}
//当pause_on设置为0的时候即可开始播放音频数据。设置为1的时候,将会播放静音的值。
SDL_PauseAudio(0);
do {
buffer_len = fread(audio_buf,1, BLOCK_SIZE, audio_fd);
audio_pos = audio_buf;
while (audio_buf < (audio_buf + buffer_len)) {
SDL_Delay(1);
}
} while (buffer_len != 0);
SDL_CloseAudio();
ret = 0;
__FAIL:
if (audio_fd) {
fclose(audio_fd);
}
if (audio_buf) {
free(audio_buf);
}
SDL_Quit();
return 0;
}
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果