索引地址:系列教程索引地址
上一篇:FFmpeg5开发入门教程14:Linux下摄像头捕获并编码为h264(无音频)
本系列的之前文章介绍了视频的编解码相关,接下来介绍音频的编解码,本文将mp3音频文件解码为pcm。
使用的mp3音频文件为从网易云音乐上下载的排骨教主的牵丝戏,文件大小为9.6MB。
先看一下文件信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| $ffprobe test.mp3 Input Metadata: encoder : Lavf57.25.100 album : 排骨翻唱合集 artist : 排骨教主 title : 牵丝戏 comment : 163 key(Don\'t modify):L64FU3W4YxX3ZFTmbZ+8/VtyyFZpYaEZwBWeBYUoIhTD9n+9XApvnDI33SQMX5/hovsUgti9hVA1nVRCnV2p/JFk/KogWWpzJQE7UDv7jwhDvQEpzKhh5cV1ribc34A73au+8wyCBqJDRJP2g7PSBHwGuxUsoS2O64gLvAdVfhfjd9p5aDHjskwNs6ZjhoQ45q6BlPJRf+bTmH0STg/SHgWMyYdN6EeHUVkFQTY06 track : 12 Duration: 00:03:59.44, start: 0.025056, bitrate: 321 kb/s Stream #0:0: Audio: mp3, 44100 Hz, stereo, fltp, 320 kb/s Metadata: encoder : Lavc57.24 Stream #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:解码视频流过程的基本流程是一样的。
解码代码为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
| #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){
if(av_sample_fmt_is_planar(codecCtx->sample_fmt)){ int numBytes =av_get_bytes_per_sample(codecCtx->sample_fmt); 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播放一下看看效果:
1
| ffplay -ar 44100 -ac 2 -f f32le -i test.pcm
|
ar为audio rate,ac为audio channel ,f32le为float 32位小端数据格式。
显示为:

没发现什么大问题。
完整代码在ffmpeg_beginner中的15.ffmpeg_audio_decode_mp32pcm
。
下一篇:FFmpeg5开发入门教程16:音频重采样解码为pcm