首页 > 其他分享 >【音视频连载-008】基础学习篇-SDL 播放 PCM 音频文件(下)

【音视频连载-008】基础学习篇-SDL 播放 PCM 音频文件(下)

时间:2022-10-13 16:35:44浏览次数:71  
标签:stream 音频 音视频 len 音频文件 PCM SDL audio


公众号回复:OpenGL,领取学习资源大礼包

音视频学习入门技术文章连载:

接上篇 SDL 播放 PCM 音频文件,已经实现了 ​​推​​​ 的模式去播放,接下来看看 ​​拉​​ 的模式如何实现。

PCM 文件素材准备

前面的文章中已经准备好了相关素材,这里就不重复了,还是用同样的 PCM 文件作为这次实验素材。

代码实践

首先还是要通过 ​​SDL_OpenAudioDevice​​ 方法打开一个音频设备。

    SDL_AudioSpec audioSpec;
audioSpec.freq = 44100;
audioSpec.format = AUDIO_S16SYS;
audioSpec.channels = 2;
audioSpec.silence = 0;
audioSpec.samples = 1024;
// 拉的模式,这里要传一个函数
audioSpec.callback = fill_audio;

SDL_AudioDeviceID deviceId;
if ((deviceId = SDL_OpenAudioDevice(nullptr, 0, &audioSpec, nullptr, SDL_AUDIO_ALLOW_ANY_CHANGE)) < 2) {
cout << "open audio device failed " << endl;
return -1;
}

不同的是,这里 ​​callback​​​ 参数不能是 nullptr 了,要传一个函数指针。这个函数在 ​​拉​​ 模式下会不断回调,从而将音频数据填充给设备缓冲区。

函数声明如下:

typedef void (SDLCALL * SDL_AudioCallback) (
// 传用户自定义的数据
void *userdata,
// 指向要填充给设备缓冲区的音频数据Buffer的指针
Uint8 * stream,
// 音频数据Buffer的长度
int len);

参数 ​​stream​​​ 是个指针类型,它指向要填充给设备缓冲区的音频数据 Buffer ,而 len 就是 Buffer 的长度。​​userdata​​ 是我们自定义的数据,需要的时候可以用到。

在这个函数中我们要做的就是将读取的 PCM 音频数据传给 ​​stream​​ 指向的 Buffer ,而且还不能超出 len 的长度,如果超出了截断一下,下次回调时传剩下的部分。

因此就有了如下的实现:

// 读取出 pcm 数据长度
static Uint32 audio_len;
// 读取出的音频数据 Buffer
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 = len > audio_len ? audio_len : len;

// 将 stream 和 audio_pos 进行混合播放
// SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);

// 单独播放 audio_pos,也就是解码出来的音频数据
memcpy(stream, audio_pos, len);

audio_pos += len;
audio_len -= len;

if (audio_len <= 0){
// 读取完了,通知继续读取数据
notifyGetAudioFrame();
}
}

首先将 ​​stream​​​ 数据清空。然后比较读出的 pcm 数据长度 ​​audio_len​​​ 和 ​​len​​​ 的大小,保证数据大小不超过 ​​len​​ 的要求。

在播放时,也就是给 ​​stream​​​ 写数据时有两种方式。一种是直接 ​​memcpy​​​ 将音频数据 ​​audio_pos​​​ 拷贝到 Buffer 上就好了。另一种是通过 ​​SDL_MixAudio​​ 方法。

​SDL_MixAudio​​​ 方法顾名思义就是混音了,将 ​​stream​​​ 和音频数据 ​​audio_pos​​​ 混合播放,由于一开始就将 ​​stream​​ 数据清空为 0 了,所以看似混音,实际上和直接播放音频数据效果一致的。

最后,如果读出的 pcm 数据长度大于 ​​len​​,那说明数据还没有全部填充完,下一次回调把剩下的填充到缓冲区,同时移动相应的指针位置。

如果小于,就得通知继续读取数据了,这里自定义了一个事件去通知应用读取音频数据。

// 自定义事件,通知读取音频数据
void notifyGetAudioFrame(){
SDL_Event sdlEvent;
sdlEvent.type = SDL_EVENT_BUFFER_END;
SDL_PushEvent(&sdlEvent);
}

// 在程序事件循环中去响应事件,读取音频 Buffer
while (!bQuit) {
while (SDL_PollEvent(&windowEvent)) {
switch (windowEvent.type) {
case SDL_EVENT_BUFFER_END:
// 读取音频数据
if (fread(buffer, 1, bufferSize, pFile)) {
data_count += bufferSize;
audio_chunk = reinterpret_cast<Uint8 *>(buffer);
audio_len = bufferSize;
audio_pos = audio_chunk;
}
default:
break;
}
}
}

在事件的消息循环中进行响应,读取音频 Buffer 。如果读取的到的长度等于 0 了,也可以通过 ​​fseek​​ 方法将指针 seek 到 0,循环读取。

最后运行一下程序,就会播放出和原来 mp3 一样的音乐了。

总结

以上就是音视频基础学习连载的 ​​008​​ 篇。

通过两篇文章讲解了 SDL 播放音频的两种方式,后续会主要以 ​​拉​​ 的模式进行开发。

本文具体代码见仓库:

​https://github.com/glumes/av-beginner​

本篇文章对应的提交 ​​tag​​​ 为 ​​av-beginner-004​​,可切换至对应源码查看。

能力有限,文中有不对之处,

【音视频连载-008】基础学习篇-SDL 播放 PCM 音频文件(下)_数据


扫码关注公众号【音视频开发进阶】,一起学习多媒体音视频开发~~~

【音视频连载-008】基础学习篇-SDL 播放 PCM 音频文件(下)_数据_02


喜欢就点个吧 ▽

标签:stream,音频,音视频,len,音频文件,PCM,SDL,audio
From: https://blog.51cto.com/u_12127193/5753704

相关文章

  • 【音视频连载-004】基础学习篇-SDL 加载图片并显示
    公众号回复:OpenGL,领取学习资源大礼包音视频学习入门技术文章连载:​​技术开发故事会连载​​​​【音视频连载-001】基础学习篇-SDL介绍以及工程配置​​​​【音视频连载-......
  • 【音视频连载-009】第二季 FFmpeg 打造简易播放器
    公众号回复:OpenGL,领取学习资源大礼包音视频学习入门技术文章连载:​​技术开发故事会连载​​​​【音视频连载-001】基础学习篇-SDL介绍以及工程配置​​​​【音视频连载-......
  • 声网、新东方、伴鱼英语的音视频技术解读
    编辑:InfoQ薛梁互动直播、线上会议、在线医疗和在线教育是音视频技术应用的重要场景,而这些场景对高可用、高可靠、低延时有着苛刻的要求,很多团队在音视频产品开发过程中会遇......
  • 2K 12|20倍HDMI\SDi\ip\Usb3.0全接口音视频同步输出会议摄像机
    一款支持1920*1080P(2K)会议PTZ摄像机,广播级图像,12倍和20倍智能变焦镜头可选,支持全接口音视频同步输出:SDI\HDMI\IP\USB3.0,最高支持1920×1080P/60Fps,250个精准预设位。在取多......
  • 深入浅出,聊聊实时音视频中的回声消除与降噪
    在实时音频互动场景中,回声消除、降噪、自动增益(即3A算法)是直接影响音质和体验的重要环节之一。如何降低计算量,提升处理效率,如何兼容更多的设备、环境等,让3A算法可以适应......
  • 10_PCM转WAV
    播放器是无法直接播放PCM的,因为播放器并不知道PCM的采样率、声道数、位深度等参数。当PCM转成某种特定的音频文件格式后(比如转成WAV),就能够被播放器识别播放了。本文通过2......
  • 09_使用SDL播放PCM
    通过命令ffpay播放PCM可以使用ffplay播放《08_音频录制02_编程》中录制好的PCM文件,测试一下是否录制成功。播放PCM需要指定相关参数:ar:采样率ac:声道数f:采样格式,sam......
  • 音视频服务质量指标
    除了实时通信延迟指标外,音视频通信中还有业务服务质量指标,包括音频服务质量和视频服务质量。由于音频数据量比较小,受网络的影响不大,并且3A问题非常复杂,这里就不介绍了。接......
  • 音视频客户端需要解决的问题
    音视频不同步。音视频数据经网络传输后,由于网络抖动和延迟等问题,很可能造成音视频不同步。对此,可在音视频直播客户端增加音视频同步模块以保障音视频的同步。 回音。......
  • Python抖音视频去水印,并打包成exe可执行文件
    前言抖音里面的视频保存之后,会发现全都带有水印,所以如何解决视频去除水印就很有必要,所以教程来了,本次教程不仅会教大家如何去除视频里的水印,并且教大家将程序制作成exe可......