FFmpeg开发条记(十八)FFmpeg兼容各种音频格式的播放

打印 上一主题 下一主题

主题 910|帖子 910|积分 2730

​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等),修改后的赋值代码如下所示:
  1. int out_nb_samples = audio_decode_ctx->frame_size; // 输出的采样数量
  2. if (out_nb_samples <= 0) {
  3.     out_nb_samples = 512;
  4. }
复制代码
3、SDL的音频回调函数当中,注意每次要凑足len个字节。鉴于重采样后的音频数据大概较大(主要是amr格式有这种情况),因此要按照len指定的长度切割数据,确保每次回调函数都刚好把长度为len的音频数据送往扬声器。修改后的回调代码如下所示:
  1. // 重采样。也就是把输入的音频数据根据指定的采样规格转换为新的音频数据输出
  2. int swr_size = swr_convert(swr_ctx, // 音频采样器的实例
  3.     &out_buff, MAX_AUDIO_FRAME_SIZE, // 输出的数据内容和数据大小
  4.     (const uint8_t **) frame->data, frame->nb_samples); // 输入的数据内容和数据大小
  5. audio_pos = (unsigned char *) out_buff; // 把音频数据同步到缓冲区位置
  6. // 这里要计算实际的采样位数
  7. audio_len = swr_size * out_channels * av_get_bytes_per_sample(out_sample_fmt);
复制代码
上述修改后的代码已经附在了《FFmpeg开发实战:从零基础到短视频上线》一书第10章的源码chapter10/playaudio2.c,这个c代码是playaudio.c的改进版,除了支持原来mp3和aac格式的音频播放,还支持ogg、amr、wma等格式的音频播放,以及asf、webm等视频文件的音频播放。
接着实行下面的编译命令。
  1. // 回调函数,在获取音频数据后调用
  2. void fill_audio(void *para, uint8_t *stream, int len) {
  3.     SDL_memset(stream, 0, len); // 将缓冲区清零
  4.     if (audio_len == 0) {
  5.         return;
  6.     }
  7.     while (len > 0) { // 每次都要凑足len个字节才能退出循环
  8.         int fill_len = (len > audio_len ? audio_len : len);
  9.         // 将音频数据混合到缓冲区
  10.         SDL_MixAudio(stream, audio_pos, fill_len, SDL_MIX_MAXVOLUME);
  11.         audio_pos += fill_len;
  12.         audio_len -= fill_len;
  13.         len -= fill_len;
  14.         stream += fill_len;
  15.         if (audio_len == 0) { // 这里要延迟一会儿,避免一直占据IO资源
  16.             SDL_Delay(1);
  17.         }
  18.     }
  19. }
复制代码
编译完成后实行以下命令启动测试程序,期望播放音频文件ring.ogg。
  1. 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
复制代码
程序运行完毕,发现控制台输出以下的日志信息。
  1. ./playaudio2 ../ring.ogg
复制代码
同时电脑扬声器传来了两个“叮咚”的铃声,体现上述代码正确实现了播放ogg音频的功能。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

商道如狼道

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表