本系列的之前文章介绍了视频的编解码相关,接下来介绍音频的编解码,本文将mp3音频文件解码为pcm。

使用的mp3音频文件为从网易云音乐上下载的排骨教主的牵丝戏,文件大小为9.6MB。

先看一下文件信息:

$ffprobe test.mp3
Input #0, mp3, from 'test.mp3':Metadata:encoder         : Lavf57.25.100album           : 排骨翻唱合集artist          : 排骨教主title           : 牵丝戏comment         : 163 key(Don't modify):L64FU3W4YxX3ZFTmbZ+8/VtyyFZpYaEZwBWeBYUoIhTD9n+9XApvnDI33SQMX5/hovsUgti9hVA1nVRCnV2p/JFk/KogWWpzJQE7UDv7jwhDvQEpzKhh5cV1ribc34A73au+8wyCBqJDRJP2g7PSBHwGuxUsoS2O64gLvAdVfhfjd9p5aDHjskwNs6ZjhoQ45q6BlPJRf+bTmH0STg/SHgWMyYdN6EeHUVkFQTY06track           : 12Duration: 00:03:59.44, start: 0.025056, bitrate: 321 kb/sStream #0:0: Audio: mp3, 44100 Hz, stereo, fltp, 320 kb/sMetadata:encoder         : Lavc57.24Stream #0:1: Video: mjpeg (Baseline), yuvj420p(pc, bt470bg/unknown/unknown), 640x640 [SAR 256:256 DAR 1:1], 90k tbr, 90k tbn, 90k tbc (attached pic)Metadata:comment         : Cover (front)

注意音频流Stream #0:0这行信息,格式为mp3,采样率为44.1kHz,stereo立体声(即双声道),fltp表示数据格式为浮点型(float)。

解码流程图为:

可以看到和FFmpeg5入门教程05:解码视频流过程的基本流程是一样的。

解码代码为:

#include <stdio.h>#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavformat/avformat.h"
#include "libavutil/avutil.h"
#include "libavutil/ffversion.h"
#include "libswresample/swresample.h"
#include "libswscale/swscale.h"
#include "libpostproc/postprocess.h"int main()
{const char inFileName[] = "/home/jackey/Music/test.mp3";const char outFileName[] = "test.pcm";FILE *file=fopen(outFileName,"w+b");if(!file){printf("Cannot open output file.\n");return -1;}AVFormatContext *fmtCtx =avformat_alloc_context();AVCodecContext *codecCtx = NULL;AVPacket *pkt=av_packet_alloc();AVFrame *frame = av_frame_alloc();int aStreamIndex = -1;do{if(avformat_open_input(&fmtCtx,inFileName,NULL,NULL)<0){printf("Cannot open input file.\n");return -1;}if(avformat_find_stream_info(fmtCtx,NULL)<0){printf("Cannot find any stream in file.\n");return -1;}av_dump_format(fmtCtx,0,inFileName,0);for(size_t i=0;i<fmtCtx->nb_streams;i++){if(fmtCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_AUDIO){aStreamIndex=(int)i;break;}}if(aStreamIndex==-1){printf("Cannot find audio stream.\n");return -1;}AVCodecParameters *aCodecPara = fmtCtx->streams[aStreamIndex]->codecpar;AVCodec *codec = avcodec_find_decoder(aCodecPara->codec_id);if(!codec){printf("Cannot find any codec for audio.\n");return -1;}codecCtx = avcodec_alloc_context3(codec);if(avcodec_parameters_to_context(codecCtx,aCodecPara)<0){printf("Cannot alloc codec context.\n");return -1;}codecCtx->pkt_timebase = fmtCtx->streams[aStreamIndex]->time_base;if(avcodec_open2(codecCtx,codec,NULL)<0){printf("Cannot open audio codec.\n");return -1;}while(av_read_frame(fmtCtx,pkt)>=0){if(pkt->stream_index==aStreamIndex){if(avcodec_send_packet(codecCtx,pkt)>=0){while(avcodec_receive_frame(codecCtx,frame)>=0){/*Planar(平面),其数据格式排列方式为 (特别记住,该处是以点nb_samples采样点来交错,不是以字节交错):LLLLLLRRRRRRLLLLLLRRRRRRLLLLLLRRRRRRL...(每个LLLLLLRRRRRR为一个音频帧)而不带P的数据格式(即交错排列)排列方式为:LRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRL...(每个LR为一个音频样本)*/if(av_sample_fmt_is_planar(codecCtx->sample_fmt)){int numBytes =av_get_bytes_per_sample(codecCtx->sample_fmt);//pcm播放时是LRLRLR格式,所以要交错保存数据for(int i=0;i<frame->nb_samples;i++){for(int ch=0;ch<codecCtx->channels;ch++){fwrite((char*)frame->data[ch]+numBytes*i,1,numBytes,file);}}}}}}av_packet_unref(pkt);}}while(0);av_frame_free(&frame);av_packet_free(&pkt);avcodec_close(codecCtx);avcodec_free_context(&codecCtx);avformat_free_context(fmtCtx);fclose(file);return 0;
}

和解码视频的部分类似。解码结果为84.5MB。

我们使用ffplay播放一下看看效果:

ffplay -ar 44100 -ac 2 -f f32le -i test.pcm

ar为audio rate,ac为audio channel ,f32le为float 32位小端数据格式。

显示为:

没发现什么大问题。

完整代码在github中的15.ffmpeg_audio_decode_mp32pcm

FFmpeg5入门教程15:mp3音频解码为pcm相关推荐

  1. 【FFmpeg杂记】音频解码输出PCM格式数据分析

      FFmpeg音频解码后输出的为PCM数据,PCM中的声音数据没有被压缩.   FFmpeg中音视频数据基本上都有Packed和Planar两种存储方式,对于双声道音频来说,Packed方式为两个声 ...

  2. 零基础HTML入门教程(12)——插入音频audio标签

    本章目录 1.任务目标 2.audio标签 3.任务实操 4.小结 1.任务目标 我们前几个小结学习了,插入图片,或者插入超链接,那我们这一小结学习一下插入音频audio标签 2.audio标签 直到 ...

  3. mysql数据库入门教程(15):流程控制结构

    一.流程控制结构介绍 #流程控制结构 /* 顺序.分支.循环 */ 1.分支结构 #1.if函数 /* 语法:if(条件,值1,值2) 功能:实现双分支 应用在begin end中或外面 如果条件成立 ...

  4. Python爬虫入门教程15:音乐网站数据的爬取

    前言

  5. arduino步进电机程序库_Arduino入门教程15(步进电机驱动库的使用):Arduino Uno R3+ULN2003+步进电机 使用Stepper驱动库,控制步进电机转动角度...

    本篇介绍步进电机驱动库的使用,通过读取电位器输入,控制步进电机转动相应角度. Stepper库是官方提供的驱动库,我们启动Arduino IDE,点击「文件」-「示例」就能找到Stepper库,官方提 ...

  6. Python爬取入门教程16:音频素材网站的爬取

    前言

  7. Helm3入门教程全系列,26小时轻松掌握Helm

    很多人都使用过Ubuntu下的ap-get或者CentOS下的yum, 这两者都是Linux系统下的包管理工具.采用apt-get/yum,应用开发者可以管理应用包之间的依赖关系,发布应用:用户则可以 ...

  8. Android NDK开发之旅31 FFmpeg音频解码

    ###前言 #####基于Android NDK开发之旅30--FFmpeg视频播放这篇文章,我们已经学会视频解码基本过程.这篇文章就对音频解码进行分析. #####音频解码和视频解码的套路基本是一样 ...

  9. C#,入门教程(16)——可变数据类型(var)的基础知识与使用禁忌

    上一篇: C#,入门教程(15)--类(class)的基础知识https://blog.csdn.net/beijinghorn/article/details/124012719 一.权威说法 先看 ...

最新文章

  1. 激荡十年:美国正在衰落和正在兴起的25个行业
  2. 笔记本Wifi连接出现“设置与网络连接不匹配”的解决方法
  3. 构造函数和析构函数能否声明为虚函数?
  4. datasnap 2011连接池,数据集对象池
  5. js 嵌入php_PHP快速入门第一讲:什么是PHP
  6. vue + element-ui tab切换
  7. three.js几何体的旋转,缩放,平移
  8. 如何在Mac上使用终端阻止网站?
  9. 回溯法2——和尚挑水
  10. 软件测试 vb,使用VB6.0进行自动化测试
  11. 软考高级 真题 2016年上半年 信息系统项目管理师 综合知识
  12. Office Scan(OSCE)10.0客户端手动卸载
  13. 六万字 HTTP 必备知识学习,程序员不懂网络怎么行,一篇HTTP入门 不收藏都可惜
  14. 3D打印:我的打印机使用经验技巧记录
  15. 台式计算机开关电源原理图,开关电源电路原理(附原理图)
  16. ArcGIS Server 10.8.1安装
  17. php和phalcon,PHP_phalcon框架使用指南,初次认识phalcon是在刚学php的时
  18. 大数据文字游戏_什么是大数据?
  19. //菱形,内藏十字架
  20. ESP32学习(3):ESP32上运行ILI9341驱动LCD

热门文章

  1. 自动获取cookie,爬取新浪微博热门评论
  2. element-UI中el-select组件使用拼音进行模糊匹配可选择项
  3. 服务器信号满格但网速很慢,4G信号满格网速却很慢?一招搞定!
  4. 什么是粉丝福利购?淘宝优惠券的来由。
  5. 建筑结构抗震分析之施加地震波的方法与理论机理
  6. 计算机不能进入桌面,电脑开机后进不了桌面,详细教您电脑开机后无法进入桌面怎么办...
  7. 阿里云安装配置mysql(centos版)
  8. QNX与Linux两家未来有望独霸车载电子操作系统
  9. 注册淘宝安装工要求 淘宝安装工怎么接活
  10. 逐步实现一个简易的飞机大战(c++)