音视频技术(4)-SDL播放PCM
- 2020 年 3 月 27 日
- 笔记
SDL 是一套跨平台的音视频播放框架,对齐了底层硬件的差异,开发者可以专注于音视频的处理,本文记录在iOS上使用SDL播放pcm音频裸数据的实现过程。pcm是音频的裸数据。
- sdl编译:可以直接在sdl官网下载源码编译成iOS平台使用的.a静态库,编译方式有两种,1)xcode编译;2)shell脚本编译,详细可以参考源码里的readme文档 源码目录:

image.png
用sh脚本编译的.a文件,最后运行不过去,会报错,在sdl论坛里提问了,也没有人回答,建议用第一种方式编译,笔者在学习的过程中节省时间,直接扣了别人已经编译好的.a文件
- 集成:1)copy 头文件到工程目录下,2) 添加库引用,参考如下库引用,可能有用不到的

image.png
- 代码编写,代码不多,100行左右即可实现,核心代码实现如下
执行流程: 初始化SDL –> 打开pcm文件–>调用SDL播放–>SDL回调里取每一帧的播放数据–>当前线程等待pcm播放完,然后再去取下一个缓存的数据
#import "AudioPlayerSDL2.h" static Uint32 audio_len; static Uint8 *audio_pos; void fill_audio(void *udata, Uint8 *stream, int len){ SDL_memset(stream, 0, len); if(audio_len == 0){ return; } len = (len > audio_len? audio_len : len); printf("audio %d %d n", audio_len, len); SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME); audio_pos += len; audio_len -= len; } int cppTest(){ SDL_SetMainReady(); if(SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)){ printf("Could not initialize SDL -%sn", SDL_GetError()); return -1; } SDL_AudioSpec wanted_spec; wanted_spec.freq = 44100; wanted_spec.format = AUDIO_S16SYS; wanted_spec.channels = 2; wanted_spec.silence = 0; wanted_spec.samples = 1024; wanted_spec.callback = fill_audio; if (SDL_OpenAudio(&wanted_spec, NULL) < 0){ printf("can't open audio.n"); return -1; } NSString *pcmdir = [NSString stringWithFormat:@"resource.bundle/test1.pcm"]; NSString *ppth = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:pcmdir]; FILE *fp = fopen([ppth UTF8String], "r"); if(fp == NULL){ printf("cannot open this filen"); return -1; } else { printf("open file :%s", [pcmdir UTF8String]); } int pcm_buffer_size = 4096; char *pcm_buffer = (char *)malloc(pcm_buffer_size); int data_count = 0; SDL_PauseAudio(0); while (1) { if(fread(pcm_buffer, 1, pcm_buffer_size, fp) != pcm_buffer_size){ // fseek(fp, 0, SEEK_SET); // fread(pcm_buffer, 1, pcm_buffer_size, fp); // data_count = 0; break; } printf("Now Playing %10d Bytes data.n", data_count); data_count += pcm_buffer_size; audio_len = pcm_buffer_size; audio_pos = (Uint8 *) pcm_buffer; // SDL_PauseAudio(0); while (audio_len > 0) { SDL_Delay(1); } } if(pcm_buffer){ free(pcm_buffer); } fclose(fp); SDL_Quit(); return 0; }
使用ffmpeg从mp4中提取pcm文件 提取:ffmpeg -i 1.mp4 -vn -ar 44100 -ac 2 -f s16le out.pcm 播放:ffplay -ac 2 -ar 44100 -f s16le out.pcm