本文是上面文章的摘要,只用于自己快速浏览.
目录
ffplay
可以使用ffplay播放《音频录制02_编程》中录制好的PCM文件,测试一下是否录制成功。
播放PCM需要指定相关参数:
ar:采样率
ac:声道数
f:采样格式
s16le:PCM signed 16-bit little-endian
更多PCM的采样格式可以使用命令查看
Windows:ffmpeg -formats | findstr PCM
Mac:ffmpeg -formats | grep PCM
SDL
一. 简介
ffplay是基于FFmpeg、SDL两个库实现的。通过编程的方式播放音视频,也是需要用到这2个库
SDL(Simple DirectMedia Layer),是一个跨平台的C语言多媒体开发库。
支持Windows、Mac OS X、Linux、iOS、Android
提供对音频、键盘、鼠标、游戏操纵杆、图形硬件的底层访问
SDL播放音频有2种模式:
Push(推):【程序】主动推送数据给【音频设备】
Pull(拉):【音频设备】主动向【程序】拉取数据
二. 下载
Windows平台下载
Mac平台下载
三.HelloWorld
- 环境配置
.pro文件中设置库的访问路径
在Windows环境中,还需要处理一下dll文件
- 打印版本
#include <SDL2/SDL.h>
SDL_version v;
SDL_VERSION(&v);
// 2 0 14
qDebug() << v.major << v.minor << v.patch;
播放PCM
一. 初始化系统
SDL分成好多个子系统(subsystem):
Video:显示和窗口管理
Audio:音频设备管理
Joystick:游戏摇杆控制
Timers:定时器
…
目前只用到了音频功能,所以只需要通过SDL_init函数初始化Audio子系统即可。
二. 打开音频设备
需要传递的参数:
采样率,采样格式(位深度,大小端,…),声道数,音频缓冲区的样本数量
读取文件的音频数据和长度,回调函数
三. 打开文件
打开需要播放的pcm文件
四. 开始播放
数据流向
读取的数据:通过循环不断从文件中读取数据,将数据放入一个bufferData,并记录读取的数据长度bufferLen
填充的数据:将读取的数据在回调函数内填充到stream,并移动bufferData的指针
播放数据:将stream内填充的数据进行播放.当播放完的时候再次调用回调函数进行填充.
如果bufferData还没有被消耗完(通过bufferLen是否大于0来判断),循环就空转(线程忙等),如果消耗完就从文件中读取数据到bufferData.如果再读取不到数据,就退出循环结束线程.
存在的问题
最后一次读取到bufferData的数据在被全部填充到stream后的那一刻,循环会立即退出,释放资源,线程销毁.这时stream内填充的数据还没有来的及播放,就被迫终止了.
从上边的分析可以看出导致问题出现是在bufferData变为0时的那次填充.
如何解决这个问题?
延时退出,记录变为0时那次填充到stream的数据大小,在根据每分钟播放的数据大小能计算出一个时间,让线程延时这个时间退出就能保证最后的数据播放完成.
五. 回调函数
// 等待音频设备回调(会回调多次)
void pull_audio_data(void *userdata,
// 需要往stream中填充PCM数据
Uint8 *stream,
// 希望填充的大小(samples * format * channels / 8)
int len
) {
//播放器没有数据播放时就会调用这个回调函数,来拉取数据
//数据被填充到stream
//需要填充的数据大小,比如len为4096 就是这次最多可以填充4096个字节的数据 len的大小是根据设置的音频缓冲区的样本数量(1024) 声道数(2) 采样格式(16bit) 共同决定的
//但bufferData内的数据可能大于4096 也可能小于 4096 ,所以要取bufferLen和 len中较小的那个值,来防止越界
}
六. 释放资源
关闭文件
关闭音频设备
清理子系统
行者常至,为者常成!