SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。SDL通过OpenGL和2D视频帧缓冲,提供了数种控制音频、视频、键盘、鼠标、控制杆及3D硬件的访问接口,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。目前SDL多用于开发游戏、模拟器、媒体播放器等多媒体应用领域。
1、下载SDL源码库,SDL2-2.0.10.tar.gz(下载网址:https://www.libsdl.org/download-2.0.php)
2、解压,然后执行以下命令
$ ./configure
$ make
$ sudo make install
3、如果出现Could not initialize SDL - No available video device(Did you set the DISPLAY variable?)错误,说明系统没有安装x11的库文件,因此编译出来的SDL库实际上不能用。安装x11库文件:
$ sudo apt-get install libx11-dev
$ sudo apt-get install xorg-dev
1、函数功能说明
1)初始化函数
SDL_Init():初始化SDL系统
SDL_CreateWindow():创建窗口SDL_Window
SDL_CreateRenderer():创建渲染器SDL_Renderer
SDL_CreateTexture():创建纹理SDL_Texture
2)循环渲染函数
SDL_UpdateTexture():设置纹理的数据
SDL_RenderCopy():将纹理的数据拷贝给渲染器
SDL_RenderPresent():显示
3)事件函数
SDL_WaitEvent():等待一个事件
SDL_PushEvent():发送一个事件
SDL_PumpEvents():将硬件设备产生的事件放入事件队列,用于读取事件,在调用该函数之前,必须调用SDL_PumpEvents搜集键盘等事件
SDL_PeepEvents():从事件队列提取一个事件
4)线程函数
SDL_CreateThread():SDL线程创建
SDL_WaitThead():SDL线程等待
SDL_CreateMutex/SDL_DestroyMutex():SDL互斥锁
SDL_LockMutex/SDL_UnlockMutex():SDL锁定互斥
SDL_CreateCond/SDL_DestoryCond():SDL条件变量(信号量)
SDL_CondWait/SDL_CondSingal():SDL条件变量(信号量)等待/通知
5)其他函数
SDL_Delay():工具函数,用于延时
SDL_Quit():退出SDL系统
2、数据结构说明
1)SDL_Window
SDL_Window代表一个“窗口”。
SDL_Window结构体定义了一个SDL2中的窗口。
有关它的定义在接口头文件中只有一行代码,但是这一行定义前面的注释非常之多,如下所示:
/**
* \brief The type used to identify a window
*
* \sa SDL_CreateWindow()
* \sa SDL_CreateWindowFrom()
* \sa SDL_DestroyWindow()
* \sa SDL_GetWindowData()
* \sa SDL_GetWindowFlags()
* \sa SDL_GetWindowGrab()
* \sa SDL_GetWindowPosition()
* \sa SDL_GetWindowSize()
* \sa SDL_GetWindowTitle()
* \sa SDL_HideWindow()
* \sa SDL_MaximizeWindow()
* \sa SDL_MinimizeWindow()
* \sa SDL_RaiseWindow()
* \sa SDL_RestoreWindow()
* \sa SDL_SetWindowData()
* \sa SDL_SetWindowFullscreen()
* \sa SDL_SetWindowGrab()
* \sa SDL_SetWindowIcon()
* \sa SDL_SetWindowPosition()
* \sa SDL_SetWindowSize()
* \sa SDL_SetWindowBordered()
* \sa SDL_SetWindowResizable()
* \sa SDL_SetWindowTitle()
* \sa SDL_ShowWindow()
*/
typedef struct SDL_Window SDL_Window;
2)SDL_Renderer
SDL_Renderer代表一个“渲染器”。
SDL_Renderer结构体定义了一个SDL2中的渲染器。
有关它的定义在接口头文件中只有一行代码,如下所示:
/**
* \brief A structure representing rendering state
*/
struct SDL_Renderer;
typedef struct SDL_Renderer SDL_Renderer;
3)SDL_Texture
SDL_Texture代表一个“纹理”。
SDL_Texture结构定义了一个SDL2中的纹理。
有关它的定义在接口头文件中只有一行代码,如下所示:
/**
* \brief An efficient driver-specific representation of pixel data
*/
struct SDL_Texture;
typedef struct SDL_Texture SDL_Texture;
4)SDL_Rect
SDL_Rect代表一个简单的矩形结构。
2、函数说明
1)打开音频设备
函数原型:int SDLCALL SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained);
参数说明:
desired:期望参数;
obtained:实际音频设备参数,一般情况设置为NULL即可。
SDL_AudioSpec 结构体:
typedef struct SDL_AudioSpec {
int freq; // 音频采样率
SDL_AudioFormat format; // 音频数据格式
Uint8 channels; // 声道数: 1 单声道, 2 立体声
Uint8 silence; // 设置静音的值, 因为声音采样是有符号的, 所以0当然就是这个值
Uint16 samples; // 音频缓冲区中的采样个数,要求必须是2的n次
Uint16 padding; // 考虑到兼容性的一个参数
Uint32 size; // 音频缓冲区的大小,以字节为单位
SDL_AudioCallback callback; // 填充音频缓冲区的回调函数
void *userdata; // 用户自定义的数据
} SDL_AudioSpec;
2)回调函数
函数原型:void (SDLCALL * SDL_AudioCallback) (void *userdata, Uint8 *stream, int len);
参数说明:
userdata: SDL_AudioSpec结构中的用户自定义数据,一般情况下可以不用;
stream:该指针指向需要填充的音频缓冲区;
len:音频缓冲区的大小(以字节为单位) 102422。
3)播放音频数据函数
函数原型:void SDLCALL SDL_PauseAudio(int pause_on)
参数说明:
pause_on:0开始播放音频数据。1播放静音的值。
3、实例源码
/**
* SDL2播放PCM
*/
#include
#include
#define PCM_BUFFER_SIZE (1024*2*2*2)
static Uint8 *s_audio_buf = NULL;
static Uint8 *s_audio_pos = NULL;
static Uint8 *s_audio_end = NULL;
//音频设备回调函数
void fill_audio_pcm(void *udata, Uint8 *stream, int len)
{
SDL_memset(stream, 0, len);
if(s_audio_pos >= s_audio_end) // 数据读取完毕
{
return;
}
int remain_buffer_len = s_audio_end - s_audio_pos;
len = (len < remain_buffer_len) ? len : remain_buffer_len;
// 拷贝数据到stream并调整音量
SDL_MixAudio(stream, s_audio_pos, len, SDL_MIX_MAXVOLUME/8);
printf("len = %d\n", len);
s_audio_pos += len; // 移动缓存指针
}
int main(int argc, char *argv[])
{
int ret = -1;
FILE *audio_fd = NULL;
SDL_AudioSpec spec;
const char *path = "test.pcm";
size_t read_buffer_len = 0;
//SDL 初始化
if(SDL_Init(SDL_INIT_AUDIO)) // 支持AUDIO
{
return ret;
}
//打开PCM文件
audio_fd = fopen(path, "rb");
if(!audio_fd)
{
goto _FAIL;
}
s_audio_buf = (uint8_t *)malloc(PCM_BUFFER_SIZE);
// 音频参数设置SDL_AudioSpec
spec.freq = 44100; // 采样频率
spec.format = AUDIO_S16SYS; // 采样点格式
spec.channels = 2; // 2通道
spec.silence = 0;
spec.samples = 1024; // 23.2ms -> 46.4ms 每次读取的采样数量,多久产生一次回调和 samples
spec.callback = fill_audio_pcm; // 回调函数
spec.userdata = NULL;
//打开音频设备
if(SDL_OpenAudio(&spec, NULL))
{
goto _FAIL;
}
//播放音频
SDL_PauseAudio(0);
int data_count = 0;
while(1)
{
// 从文件读取PCM数据
read_buffer_len = fread(s_audio_buf, 1, PCM_BUFFER_SIZE, audio_fd);
if(read_buffer_len == 0)
{
break;
}
data_count += read_buffer_len; // 统计读取的数据总字节数
printf("now playing %10d bytes data.\n",data_count);
s_audio_end = s_audio_buf + read_buffer_len; // 更新buffer的结束位置
s_audio_pos = s_audio_buf; // 更新buffer的起始位置
//the main thread wait for a moment
while(s_audio_pos < s_audio_end)
{
SDL_Delay(10); // 等待PCM数据消耗
}
}
printf("play finish\n");
// 关闭音频设备
SDL_CloseAudio();
_FAIL:
if(s_audio_buf)
free(s_audio_buf);
if(audio_fd)
fclose(audio_fd);
//退出SDL
SDL_Quit();
return 0;
}