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 ...
随机推荐
- AXI4的主从机的收发机制
AXI4的收发机制 1.AXI4的译码器 对于多个主机和从机的AXI4总线的互联架构,译码器都是重要的.主机的端口一般有三个译码器,分别是读地址通道.写地址通道和写数据通道的译码器.主要作用是将通道的 ...
- Linux电脑如何下载QGIS?
本文介绍在Linux操作系统Ubuntu版本中,通过命令行的方式,配置QGIS软件的方法. 在Ubuntu等Linux系统中,可以对空间信息加以可视化的遥感.GIS软件很少,比如ArcGIS下 ...
- .Net单元测试xUnit和集成测试指南(1)
引言 在现代化的软件开发中,单元测试和集成测试是确保代码质量和可靠性的关键部分.ASP.NET Core 社区内提供了强大的单元测试框架,xUnit 是其中之一,它提供了简单.清晰和强大的测试功能,编 ...
- requests进阶
requests进阶 三.requests模块处理cookie相关的请求 1 爬虫中使用cookie 为了能够通过爬虫获取到登录后的页面,或者是解决通过cookie的反扒,需要使用request来处理 ...
- #cdq分治,树状数组#洛谷 5459 [BJOI2016]回转寿司
题目 求 \[\sum_{i=1}^n\sum_{j=i}^{n}[L\leq \sum_{k=i}^j a_k\leq R] \] 分析(树状数组) 考虑前缀和,改为是否有两个数的差在\([L\si ...
- 2024最新AIGC系统ChatGPT网站源码,GPTs应用,Ai绘画网站源码
一.前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统,支持OpenAI-GPT全模型+国内AI全模型.本期针对源码系统整体测试下来非常完美,那么 ...
- C++ STL 容器和算法:详解和实例演示
C++ STL(标准模板库)提供了一组丰富的容器和算法,使得开发者能够更加高效地编写程序.本文将介绍STL中的一些常用容器和算法. 容器 vector vector是一个动态数组,可以在运行时调整大小 ...
- 一文了解网络编程之走进TCP三次握手和HTTP那些你不知道的事
受到很多引人入胜的标题党的影响,我终于决定,要起一个比他们还标题党的题目,打不过还不能加入吗,嘿嘿. 网络编程一直是我的弱项,其实归根结底还是我太懒了,一看到那个osi七层模型,TCP/IP模型还有那 ...
- std::thread 五:打包任务(packaged_task)
#include <iostream> #include <thread> #include <mutex> #include <list> #incl ...
- 如何通过 kubectl 进入 node shell
概述 假设这样一个场景: 生产环境中,Node 都需要通过堡垒机登录,但是 kubectl 是可以直接在个人电脑上登录的. 这种场景下,我想要通过 kubectl 登录到 K8S 集群里的 Node, ...