FFmpeg5入门教程15:mp3音频解码为pcm
本系列的之前文章介绍了视频的编解码相关,接下来介绍音频的编解码,本文将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相关推荐
- 【FFmpeg杂记】音频解码输出PCM格式数据分析
FFmpeg音频解码后输出的为PCM数据,PCM中的声音数据没有被压缩. FFmpeg中音视频数据基本上都有Packed和Planar两种存储方式,对于双声道音频来说,Packed方式为两个声 ...
- 零基础HTML入门教程(12)——插入音频audio标签
本章目录 1.任务目标 2.audio标签 3.任务实操 4.小结 1.任务目标 我们前几个小结学习了,插入图片,或者插入超链接,那我们这一小结学习一下插入音频audio标签 2.audio标签 直到 ...
- mysql数据库入门教程(15):流程控制结构
一.流程控制结构介绍 #流程控制结构 /* 顺序.分支.循环 */ 1.分支结构 #1.if函数 /* 语法:if(条件,值1,值2) 功能:实现双分支 应用在begin end中或外面 如果条件成立 ...
- Python爬虫入门教程15:音乐网站数据的爬取
前言
- arduino步进电机程序库_Arduino入门教程15(步进电机驱动库的使用):Arduino Uno R3+ULN2003+步进电机 使用Stepper驱动库,控制步进电机转动角度...
本篇介绍步进电机驱动库的使用,通过读取电位器输入,控制步进电机转动相应角度. Stepper库是官方提供的驱动库,我们启动Arduino IDE,点击「文件」-「示例」就能找到Stepper库,官方提 ...
- Python爬取入门教程16:音频素材网站的爬取
前言
- Helm3入门教程全系列,26小时轻松掌握Helm
很多人都使用过Ubuntu下的ap-get或者CentOS下的yum, 这两者都是Linux系统下的包管理工具.采用apt-get/yum,应用开发者可以管理应用包之间的依赖关系,发布应用:用户则可以 ...
- Android NDK开发之旅31 FFmpeg音频解码
###前言 #####基于Android NDK开发之旅30--FFmpeg视频播放这篇文章,我们已经学会视频解码基本过程.这篇文章就对音频解码进行分析. #####音频解码和视频解码的套路基本是一样 ...
- C#,入门教程(16)——可变数据类型(var)的基础知识与使用禁忌
上一篇: C#,入门教程(15)--类(class)的基础知识https://blog.csdn.net/beijinghorn/article/details/124012719 一.权威说法 先看 ...
最新文章
- 激荡十年:美国正在衰落和正在兴起的25个行业
- 笔记本Wifi连接出现“设置与网络连接不匹配”的解决方法
- 构造函数和析构函数能否声明为虚函数?
- datasnap 2011连接池,数据集对象池
- js 嵌入php_PHP快速入门第一讲:什么是PHP
- vue + element-ui tab切换
- three.js几何体的旋转,缩放,平移
- 如何在Mac上使用终端阻止网站?
- 回溯法2——和尚挑水
- 软件测试 vb,使用VB6.0进行自动化测试
- 软考高级 真题 2016年上半年 信息系统项目管理师 综合知识
- Office Scan(OSCE)10.0客户端手动卸载
- 六万字 HTTP 必备知识学习,程序员不懂网络怎么行,一篇HTTP入门 不收藏都可惜
- 3D打印:我的打印机使用经验技巧记录
- 台式计算机开关电源原理图,开关电源电路原理(附原理图)
- ArcGIS Server 10.8.1安装
- php和phalcon,PHP_phalcon框架使用指南,初次认识phalcon是在刚学php的时
- 大数据文字游戏_什么是大数据?
- //菱形,内藏十字架
- ESP32学习(3):ESP32上运行ILI9341驱动LCD
热门文章
- 自动获取cookie,爬取新浪微博热门评论
- element-UI中el-select组件使用拼音进行模糊匹配可选择项
- 服务器信号满格但网速很慢,4G信号满格网速却很慢?一招搞定!
- 什么是粉丝福利购?淘宝优惠券的来由。
- 建筑结构抗震分析之施加地震波的方法与理论机理
- 计算机不能进入桌面,电脑开机后进不了桌面,详细教您电脑开机后无法进入桌面怎么办...
- 阿里云安装配置mysql(centos版)
- QNX与Linux两家未来有望独霸车载电子操作系统
- 注册淘宝安装工要求 淘宝安装工怎么接活
- 逐步实现一个简易的飞机大战(c++)