#include <stdio.h> #include <SDL.h> // 每次读取2帧数据, 以1024个采样点一帧 2通道 16bit采样点为例 #define PCM_BUFFER_SIZE (1024*2*2*2) // 音频PCM数据缓存 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 ", len); s_audio_pos += len; // 移动缓存指针 } // 提取PCM文件 // ffmpeg -i input.mp4 -t 20 -codec:a pcm_s16le -ar 44100 -ac 2 -f s16le 44100_16bit_2ch.pcm // 测试PCM文件 // ffplay -ar 44100 -ac 2 -f s16le 44100_16bit_2ch.pcm #undef main int main(int argc, char* argv[]) { // 1.初始化SDL if (SDL_Init(SDL_INIT_AUDIO)) { fprintf(stderr, "SDL_Init error: %s ", SDL_GetError()); return -1; } // 2.打开PCM文件 FILE *audio_fd = fopen("44100_16bit_2ch.pcm", "rb"); if (audio_fd == NULL) { printf("fopen pcm file error. "); return -1; } // 3.打开音频设备 SDL_AudioSpec spec; spec.freq = 44100; // 采样频率 spec.format = AUDIO_S16SYS; // 采样格式 spec.channels = 2; // 通道 spec.silence = 0; // 静音值 spec.samples = 1024; // 采样个数 spec.callback = fill_audio_pcm; spec.userdata = NULL; if (SDL_OpenAudio(&spec, NULL)) { fprintf(stderr, "SDL_OpenAudio error: %s ", SDL_GetError()); fclose(audio_fd); SDL_Quit(); return -1; } // 5.播放音频 SDL_PauseAudio(0); int data_count = 0; s_audio_buf = (uint8_t *)malloc(PCM_BUFFER_SIZE); while(1) { // 读取pcm数据 size_t len = fread(s_audio_buf, 1, PCM_BUFFER_SIZE, audio_fd); if (len == 0) { break; } data_count += len; printf("now playing %10d bytes data. ",data_count); s_audio_end = s_audio_buf + len; s_audio_pos = s_audio_buf; while(s_audio_pos < s_audio_end) { SDL_Delay(10); // 等待PCM数据消耗 } } // 6.关闭音频设备 printf("play PCM finish "); SDL_CloseAudio(); // 7.退出 if (s_audio_buf) { free(s_audio_buf); } if (audio_fd) { fclose(audio_fd); } SDL_Quit(); return 0; }