SDL2文章列表

SDL2入门

SDL2事件处理

SDL2纹理渲染

本来计划写FFmpeg+SDL2视频播放,但是发现要说的内容有点多,所以还是先从简单的音频数据播放开始,一步一步来。

打开音频设备

1
2
3
4
int SDLCALL SDL_OpenAudio(SDL_AudioSpec * desired,
SDL_AudioSpec * obtained);
// desired:期望的参数。
// obtained:实际音频设备的参数,一般情况下设置为NULL即可。

SDL_AudioSpec

1
2
3
4
5
6
7
8
9
10
11
12
13
//在这个结构体中包含了音频的各种参数
typedef struct SDL_AudioSpec
{
int freq; /**< 音频采样率*/
SDL_AudioFormat format; /**< 音频数据格式 */
Uint8 channels; /**< 声道数: 1 单声道, 2 立体声 */
Uint8 silence; /**< 设置静音的值*/
Uint16 samples; /**< 音频缓冲区中的采样个数,要求必须是2的n次*/
Uint16 padding; /**< 考虑到兼容性的一个参数*/
Uint32 size; /**< 音频缓冲区的大小,以字节为单位*/
SDL_AudioCallback callback; /**< 填充音频缓冲区的回调函数 */
void *userdata; /**< 用户自定义的数据 */
} SDL_AudioSpec;

SDL_AudioCallback

当音频设备需要更多数据的时候会调用该回调函数。

1
2
3
4
5
6
// userdata:SDL_AudioSpec结构中的用户自定义数据,一般情况下可以不用。
// stream:该指针指向需要填充的音频缓冲区。
// len:音频缓冲区的大小(以字节为单位)。
void (SDLCALL * SDL_AudioCallback) (void *userdata,
Uint8 *stream,
int len);

播放音频数据

1
2
// 当pause_on设置为0的时候即可开始播放音频数据。设置为1的时候,将会播放静音的值。
void SDLCALL SDL_PauseAudio(int pause_on)

播放PCM音频Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <stdio.h>
#include <tchar.h>
#include <SDL_types.h>
#include "SDL.h"

static Uint8 *audio_chunk;
static Uint32 audio_len;
static Uint8 *audio_pos;
int pcm_buffer_size = 4096;

//回调函数,音频设备需要更多数据的时候会调用该回调函数
void read_audio_data(void *udata, Uint8 *stream, int len) {
SDL_memset(stream, 0, len);
if (audio_len == 0)
return;
len = (len > audio_len ? audio_len : len);

SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);
audio_pos += len;
audio_len -= len;
}

int WinMain(int argc, char *argv[]) {

if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
printf("Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}

SDL_AudioSpec spec;
spec.freq = 44100;//根据你录制的PCM采样率决定
spec.format = AUDIO_S16SYS;
spec.channels = 1; //单声道
spec.silence = 0;
spec.samples = 1024;
spec.callback = read_audio_data;
spec.userdata = NULL;

if (SDL_OpenAudio(&spec, NULL) < 0) {
printf("can't open audio.\n");
return -1;
}

FILE *fp = fopen("C:\\Users\\lenovo\\Desktop\\1111111.pcm", "rb+");
if (fp == NULL) {
printf("cannot open this file\n");
return -1;
}
char *pcm_buffer = (char *) malloc(pcm_buffer_size);

//播放
SDL_PauseAudio(0);

while (1) {
if (fread(pcm_buffer, 1, pcm_buffer_size, fp) != pcm_buffer_size) { //从文件中读取数据,剩下的就交给音频设备去完成了,它播放完一段数据后会执行回调函数,获取等多的数据
break;
}

audio_chunk = (Uint8 *) pcm_buffer;
audio_len = pcm_buffer_size; //长度为读出数据长度,在read_audio_data中做减法
audio_pos = audio_chunk;

while (audio_len > 0) //判断是否播放完毕
SDL_Delay(1);
}
free(pcm_buffer);
SDL_Quit();

return 0;
}

OK!第一步完成,能正常播放出声音了。

想要录制PCM自己试一下?可以试试用这个Android音视频(五) OpenSL ES录制、播放音频(带源码)录制一段。

源码 GitHub-SimplePlayer-pcm_player

====== 更新 完成了FFmpeg+SDL2播放音频流的开发,代码请看源码 GitHub-SimplePlayer-audio_player