ffmpeg学习十:将pcm格式的音频编码为aac格式
2016-12-23 15:35
549 查看
上一节,我们使用alsa库编写了音频的采集和播放的程序。这一节,我们将在采集到的pcm格式的音频数据的基础上,进一步将其编码为aac格式。
aac既是一种文件的封装格式,又是音频的编码格式。一aac为封装格式的文件,以.aac为后缀。aac封装格式一般内部的音频数据编码格式也为aac。
音频编码和视频编码的流程基本一致,而视频编码我们在前面已经做过了。因此,关于程序的流程就没有太多需要废话的了。下面介绍几个音频相关的参数,这几个参数是编码器进行编码所必需的。
我们总共需要设置四个参数即可:
1.sample_rate
codecContext->sample_rate = frame->sample_rate;
sample_rate指的是采样率。也就是我们一秒钟采集多少次声音样本。
2.frame->channels
codecContext->channels = frame->channels;
frame->channels之的是通道的数目。音频一般有双通道或者单通道之分,一般都是双通道吧,我们的程序里面也是设置为双通道的。也就是frame->channels=2.
3.frame->format
codecContext->sample_fmt = frame->format;
frame->format指的是样本的格式。一个音频的样本一般用两个字节来描述,分为大小端。我们的程序中使用的是16bit的小端格式。
4.channel_layout
codecContext->channel_layout = AV_CH_LAYOUT_STEREO;
channel_layout 用来设置输出通道布局。这个参数不太理解!!!
![](http://img.blog.csdn.net/20161223154709536?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTkxMzYxMg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
libfdk_aac:
官网关于使能aac的介绍
-enable-nonfree –enable-libfdk-aac
同时我们需要安装libfdk-aac库:
sudo apt-get install libfdk-aac-dev
然后我们需要重新配置和便宜ffmpeg工程:
1.执行
2.make
3.make install
./out.bin recorder.pcm recorder.aac
使用ffplay recorder.aac即可听到声音。
init.sh
看过前面文章的reader就应该知道,init.sh就是到处共享库的位置,让我们的可执行程序知道动态链接库的位置。
音频编码概述
pcm是最原始的音频编码格式,这种编码是无损的。同时意味着存储这种数据的文件将会很庞大,因此必须进行压缩。pcm是音频的编码格式,它不是文件的封装格式,上一节我们录制的声音存储在一个.pcm为后缀的文件中,这只是我们愿意这么做而已,你完全可以不这么做,这没有关系。aac既是一种文件的封装格式,又是音频的编码格式。一aac为封装格式的文件,以.aac为后缀。aac封装格式一般内部的音频数据编码格式也为aac。
音频编码和视频编码的流程基本一致,而视频编码我们在前面已经做过了。因此,关于程序的流程就没有太多需要废话的了。下面介绍几个音频相关的参数,这几个参数是编码器进行编码所必需的。
我们总共需要设置四个参数即可:
1.sample_rate
codecContext->sample_rate = frame->sample_rate;
sample_rate指的是采样率。也就是我们一秒钟采集多少次声音样本。
2.frame->channels
codecContext->channels = frame->channels;
frame->channels之的是通道的数目。音频一般有双通道或者单通道之分,一般都是双通道吧,我们的程序里面也是设置为双通道的。也就是frame->channels=2.
3.frame->format
codecContext->sample_fmt = frame->format;
frame->format指的是样本的格式。一个音频的样本一般用两个字节来描述,分为大小端。我们的程序中使用的是16bit的小端格式。
4.channel_layout
codecContext->channel_layout = AV_CH_LAYOUT_STEREO;
channel_layout 用来设置输出通道布局。这个参数不太理解!!!
程序概述
程序流程图如下:程序
下面结合程序流程图和程序中的注释,来看程序://created by Jinwei Liu #include <math.h> #include <stdlib.h> #include <libavutil/opt.h> #include <libavcodec/avcodec.h> #include <libavutil/channel_layout.h> #include <libavutil/common.h> #include <libavutil/imgutils.h> #include <libavutil/mathematics.h> #include <libavutil/samplefmt.h> #include <libavutil/frame.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> int main(int argc, char **argv){ AVFrame *frame; AVCodec *codec = NULL; AVPacket packet; AVCodecContext *codecContext; int readSize=0; int ret=0,getPacket; FILE * fileIn,*fileOut; int frameCount=0; /* register all the codecs */ av_register_all(); if(argc!=3){ fprintf(stdout,"usage:./a.out xxx.pcm xxx.aac\n"); return -1; } //1.我们需要读一帧一帧的数据,所以需要AVFrame结构 //读出的一帧数据保存在AVFrame中。 frame = av_frame_alloc(); frame->format = AV_SAMPLE_FMT_S16; frame->nb_samples = 1024; frame->sample_rate = 11025; frame->channels = 2; fileIn =fopen(argv[1],"r+"); frame->data[0] = av_malloc(1024*4); //2.读出来的数据保存在AVPacket中,因此,我们还需要AVPacket结构体 //初始化packet memset(&packet, 0, sizeof(AVPacket)); av_init_packet(&packet); //3.读出来的数据,我们需要编码,因此需要编码器 //下面的函数找到h.264类型的编码器 /* find the mpeg1 video encoder */ codec = avcodec_find_encoder(AV_CODEC_ID_AAC); if (!codec){ fprintf(stderr, "Codec not found\n"); exit(1); } //有了编码器,我们还需要编码器的上下文环境,用来控制编码的过程 codecContext = avcodec_alloc_context3(codec);//分配AVCodecContext实例 if (!codecContext){ fprintf(stderr, "Could not allocate video codec context\n"); return -1; } /* put sample parameters */ codecContext->sample_rate = frame->sample_rate; codecContext->channels = frame->channels; codecContext->sample_fmt = frame->format; /* select other audio parameters supported by the encoder */ codecContext->channel_layout = AV_CH_LAYOUT_STEREO; //准备好了编码器和编码器上下文环境,现在可以打开编码器了 //根据编码器上下文打开编码器 if (avcodec_open2(codecContext, codec, NULL) < 0){ fprintf(stderr, "Could not open codec\n"); return -1; } //4.准备输出文件 fileOut= fopen(argv[2],"w+"); //下面开始编码 while(1){ //读一帧数据出来 readSize = fread(frame->data[0],1,1024*4,fileIn); if(readSize == 0){ fprintf(stdout,"end of file\n"); frameCount++; break; } //初始化packet av_init_packet(&packet); /* encode the image */ frame->pts = frameCount; ret = avcodec_encode_audio2(codecContext, &packet, frame, &getPacket); //将AVFrame中的像素信息编码为AVPacket中的码流 if (ret < 0) { fprintf(stderr, "Error encoding frame\n"); goto out; } if (getPacket) { frameCount++; //获得一个完整的编码帧 printf("Write frame %3d (size=%5d)\n", frameCount, packet.size); fwrite(packet.data, 1,packet.size, fileOut); av_packet_unref(&packet); } } /* flush buffer */ for ( getPacket= 1; getPacket; frameCount++){ frame->pts = frameCount; ret = avcodec_encode_audio2(codecContext, &packet, NULL, &getPacket); //输出编码器中剩余的码流 if (ret < 0){ fprintf(stderr, "Error encoding frame\n"); goto out; } if (getPacket){ printf("flush buffer Write frame %3d (size=%5d)\n", frameCount, packet.size); fwrite(packet.data, 1, packet.size, fileOut); av_packet_unref(&packet); } } //for (got_output = 1; got_output; frameIdx++) out: fclose(fileIn); fclose(fileOut); av_frame_free(&frame); avcodec_close(codecContext); av_free(codecContext); return 0; }
实验
使能aac编码器
现在,我们还不能运行这个程序,因为我们在便宜ffmpeg工程的时候没有使能aac编码器,所以我们需要重新编译ffmpeg,是的aac编码器可用。libfdk_aac:
官网关于使能aac的介绍
-enable-nonfree –enable-libfdk-aac
同时我们需要安装libfdk-aac库:
sudo apt-get install libfdk-aac-dev
然后我们需要重新配置和便宜ffmpeg工程:
1.执行
./configure --enable-libx264 --enable-gpl --enable-decoder=h264 --enable-encoder=libx264 --enable-shared --enable-static --disable-yasm --enable-nonfree --enable-libfdk-aac --enable-shared --prefix=tmp
2.make
3.make install
运行程序
有了aac编码器以后,再次运行这个程序,就可以将pcm格式的音频数据编码为aac格式了,例如,执行如下命令:./out.bin recorder.pcm recorder.aac
使用ffplay recorder.aac即可听到声音。
附注
MakefileVAR_INCLUDE := -I /home/mlinux/work/ffmpeg-2.7/ffmpeg-2.7.6/tmp/include VAR_SHARED_LIB_DIR = -L /home/mlinux/work/ffmpeg-2.7/ffmpeg-2.7.6/tmp/lib VAR_SHARED_LIBS = -l avcodec -l avformat -l avdevice -l avutil -l swresample -l avfilter -l swscale out.bin:pcm_2_aac.o gcc -o $@ $^ $(VAR_INCLUDE) $(VAR_SHARED_LIB_DIR) $(VAR_SHARED_LIBS) %.o:%.c gcc -c $< $(VAR_INCLUDE) $(VAR_SHARED_LIB_DIR) $(VAR_SHARED_LIBS) clean: rm -rf *.o *.bin
init.sh
export LD_LIBRARY_PATH=/home/mlinux/work/ffmpeg-2.7/ffmpeg-2.7.6/tmp/lib
看过前面文章的reader就应该知道,init.sh就是到处共享库的位置,让我们的可执行程序知道动态链接库的位置。
相关文章推荐
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- Managed Media Aggregation using Rtsp and Rtp
- [总结]FFMPEG视音频编解码零基础学习方法
- ASP编码必备的8条原则
- XML指南——XML编码
- C#中字符串编码处理
- ExtJS中文乱码之GBK格式编码解决方案及代码
- 程序员趣味读物 谈谈Unicode编码
- 文本文件编码方式区别
- C语言安全编码之数值中的sizeof操作符
- C#实现获取文本文件的编码的一个类(区分GB2312和UTF8)
- VC中BASE64编码和解码使用详解
- 计算机中的字符串编码、乱码、BOM等问题详解
- C#如何自动识别文件的编码
- Base64编码解码原理及C#编程实例
- 利用Ffmpeg获得flv视频缩略图和视频时间的代码
- C#编码好习惯小结
- javascript编码的几个方法详细介绍
- UTF8编码开发中页面空白问题的解决方法
- php生成固定长度纯数字编码的方法