FFmpeg开发笔记(十八)FFmpeg兼容各种音频格式的播放
FFmpeg结合SDL可以播放音频文件,也能播放视频文件中的音频流,《FFmpeg开发实战:从零基础到短视频上线》一书第10章的示例程序playaudio.c支持播放mp3和aac两种格式的音频,却不支持播放其他格式的音频。
因为mp3和aac两个格式拥有标准的规范定义,比如mp3规定每帧音频固定包含1152个样本,而aac规定每帧音频固定包含1024个样本。在它们的解码器实例AVCodecContext中,即可从frame_size字段获取每帧音频的样本数量。
然而其他音频格式(如ogg、amr、wma等)的每帧样本数并不固定,从frame_size字段取到的样本数量为0,这不仅导致SDL初始化失败,还导致重采样过程异常。为了能够播放其他格式的音频,需要对playaudio.c做下列三处修改。
1、从解码器实例获取音频样本数时,如果发现frame_size为0,就要把样本数变量设为512(注意该数值必须为2的n次幂,如256、512、1024等),修改后的赋值代码如下所示:
int out_nb_samples = audio_decode_ctx->frame_size; // 输出的采样数量
if (out_nb_samples <= 0) {
out_nb_samples = 512;
}
2、在遍历音频帧的时候,要重新计算实际的采样位数,以便确定多少音频数据送给扬声器。具体的计算过程是这样的:先调用swr_convert函数对音频重采样,该函数的返回值为输出的数据大小;这个输入大小乘以声道数量乘以音频样本的位深(位深表示每个音频样本占据几个字节),最终的乘积便是要送给扬声器的音频数据大小。详细的计算代码如下所示:
// 重采样。也就是把输入的音频数据根据指定的采样规格转换为新的音频数据输出
int swr_size = swr_convert(swr_ctx, // 音频采样器的实例
&out_buff, MAX_AUDIO_FRAME_SIZE, // 输出的数据内容和数据大小
(const uint8_t **) frame->data, frame->nb_samples); // 输入的数据内容和数据大小
audio_pos = (unsigned char *) out_buff; // 把音频数据同步到缓冲区位置
// 这里要计算实际的采样位数
audio_len = swr_size * out_channels * av_get_bytes_per_sample(out_sample_fmt);
3、SDL的音频回调函数当中,注意每次要凑足len个字节。鉴于重采样后的音频数据可能较大(主要是amr格式有这种情况),因此要按照len指定的长度切割数据,确保每次回调函数都刚好把长度为len的音频数据送往扬声器。修改后的回调代码如下所示:
// 回调函数,在获取音频数据后调用
void fill_audio(void *para, uint8_t *stream, int len) {
SDL_memset(stream, 0, len); // 将缓冲区清零
if (audio_len == 0) {
return;
}
while (len > 0) { // 每次都要凑足len个字节才能退出循环
int fill_len = (len > audio_len ? audio_len : len);
// 将音频数据混合到缓冲区
SDL_MixAudio(stream, audio_pos, fill_len, SDL_MIX_MAXVOLUME);
audio_pos += fill_len;
audio_len -= fill_len;
len -= fill_len;
stream += fill_len;
if (audio_len == 0) { // 这里要延迟一会儿,避免一直占据IO资源
SDL_Delay(1);
}
}
}
上述修改后的代码已经附在了《FFmpeg开发实战:从零基础到短视频上线》一书第10章的源码chapter10/playaudio2.c,这个c代码是playaudio.c的改进版,除了支持原来mp3和aac格式的音频播放,还支持ogg、amr、wma等格式的音频播放,以及asf、webm等视频文件的音频播放。
接着执行下面的编译命令。
gcc playaudio2.c -o playaudio2 -I/usr/local/ffmpeg/include -L/usr/local/ffmpeg/lib -I/usr/local/sdl2/include -L/usr/local/sdl2/lib -lsdl2 -lavformat -lavdevice -lavfilter -lavcodec -lavutil -lswscale -lswresample -lpostproc -lm
编译完成后执行以下命令启动测试程序,期望播放音频文件ring.ogg。
./playaudio2 ../ring.ogg
程序运行完毕,发现控制台输出以下的日志信息。
Success open input_file ../ring.ogg.
out_sample_rate=11025, out_nb_samples=512
out_buffer_size=1024
256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256
Success play audio file.
Quit SDL.
同时电脑扬声器传来了两个“叮咚”的铃声,表示上述代码正确实现了播放ogg音频的功能。
FFmpeg开发笔记(十八)FFmpeg兼容各种音频格式的播放的更多相关文章
- FFmpeg开发笔记(五):ffmpeg解码的基本流程详解(ffmpeg3新解码api)
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- FFmpeg开发笔记(十):ffmpeg在ubuntu上的交叉编译移植到海思HI35xx平台
FFmpeg和SDL开发专栏(点击传送门) 上一篇:<FFmpeg开发笔记(九):ffmpeg解码rtsp流并使用SDL同步播放>下一篇:敬请期待 前言 将ffmpeg移植到海思H ...
- FFmpeg开发笔记(四):ffmpeg解码的基本流程详解
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- FFmpeg开发笔记(九):ffmpeg解码rtsp流并使用SDL同步播放
前言 ffmpeg播放rtsp网络流和摄像头流. Demo 使用ffmpeg播放局域网rtsp1080p海康摄像头:延迟0.2s,存在马赛克 使用ffmpeg播放网络rtsp文件流 ...
- FFmpeg开发笔记(三):ffmpeg介绍、windows编译以及开发环境搭建
前言 本篇章是对之前windows环境的补充,之前windows的是无需进行编译的,此篇使用源码进行编译,版本就使用3.4.8. FFmpeg简介 FFmpeg是领先的多媒体框架,能够解码 ...
- python3.4学习笔记(十八) pycharm 安装使用、注册码、显示行号和字体大小等常用设置
python3.4学习笔记(十八) pycharm 安装使用.注册码.显示行号和字体大小等常用设置Download JetBrains Python IDE :: PyCharmhttp://www. ...
- Django笔记十八之save函数的继承操作和指定字段更新等实例方法
本文首发于微信公众号:Hunter后端 原文链接:Django笔记十八之save函数的继承操作和指定字段更新等实例方法 这篇笔记主要介绍 Django 一些实例方法. 什么是 实例,我们知道通过fil ...
- FFmpeg开发笔记(一)搭建Linux系统的开发环境
对于初学者来说,如何搭建FFmpeg的开发环境是个不小的拦路虎,因为FFmpeg用到了许多第三方开发包,所以要先编译这些第三方源码,之后才能给FFmpeg集成编译好的第三方库.不过考虑到刚开始仅仅调用 ...
- FFmpeg开发笔记(二)搭建Windows系统的开发环境
由于Linux系统比较专业,个人电脑很少安装Linux,反而大都安装Windows系统,因此提高了FFmpeg的学习门槛,毕竟在Windows系统搭建FFmpeg的开发环境还是比较麻烦的.不过若有已经 ...
- Java开发笔记(八十九)缓存字节I/O流
文件输出流FileOutputStream跟FileWriter同样有个毛病,每次调用write方法都会直接写到磁盘,使得频繁的写操作性能极其低下.正如FileWriter搭上了缓存兄弟Buffere ...
随机推荐
- python打包Windows.exe程序(pyinstaller)
python打包Windows.exe程序(pyinstaller) 基础命令 pip install pyinstaller 使用pip命令来安装pyinstaller模块. -F: pyinsta ...
- 知名压缩软件 xz 被植入后门,黑客究竟是如何做到的?
昨天,Andres Freund 通过电子邮件告知 oss-security@ 社区,他在 xz/liblzma 中发现了一个隐藏得非常巧妙的后门,这个后门甚至影响到了 OpenSSH 服务器的安全. ...
- 13 JavaScript关于prototype(超重点)
13 JavaScript关于prototype(超重点) prototype是js里面给类增加功能扩展的一种模式. 写个面向对象来看看. function People(name, age){ th ...
- #矩阵乘法#洛谷 3702 [SDOI2017]序列计数
题目链接 分析 考虑容斥,用总方案减去全是合数的方案数, 可以发现 \(n\) 很大,\(p\) 很小,直接用矩阵乘法转移即可 代码 #include <cstdio> #include ...
- 编译opencv: Linux编译opencv
opencv官网:https://opencv.org/releases/ github下载地址:https://github.com/opencv/opencv/releases mkdir ...
- HarmonyOS应用侧与前端页面数据通道建立
一. 应用侧调用前端页面函数 应用侧可以通过runJavaScript()方法调用前端页面的JavaScript相关函数.在下面的示例中,点击应用侧的"runJavaScript" ...
- 抓包整理————wireshark 抓包[二]
前言 简单整理一些wireshark抓包. 正文 打开wireshark 的capture的option 选项: 然后可以看到可以捕获的选项: 可以看到这里有我的以太网和虚拟机网卡流量. 这个就是将l ...
- leetcode:94. 二叉树的中序遍历
94. 二叉树的中序遍历 给定一个二叉树,返回它的中序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,3,2] 进阶: 递归算法很简单,你可以通过迭代算法完成吗? ...
- WPF/C#:让绘制的图形可以被选中并将信息显示在ListBox中
实现的效果 如果你对此感兴趣,可以接着往下阅读. 实现过程 绘制矩形 比如说我想绘制一个3行4列的表格: private void Button_Click_DrawRect(object sende ...
- 科普达人丨一图看懂块存储&云盘
简介: 建议收藏 原文链接:https://click.aliyun.com/m/1000363155/ 本文为阿里云原创内容,未经允许不得转载.