采样率 sample_rate 一般是44100
样本格式 sample_size(数据存储格式)
AV_SAMPLE_FMT_S16 16位二字节 内存格式为c1,c2,c1,c2.......
AV_SAMPLE_FMT_FLTP 浮点数四字节32位 内存格式为c1,c1........c2,c2
c1:左声道,c2:右声道
- Packed: L R L R L R L R
- Planar: L L L L R R R R ffmpeg内部存储模式,我们实际使用的音频文件都是Packed模式的。
播放pcm数据 (7条消息) PCM数据格式介绍_SuperDali的博客-CSDN博客_pcm数据格式
ffplay -ar 44100 channels 2 -f s16le -i 视频地址
AAC数据(8条消息) AAC文件格式详解_wd_cloud的博客-CSDN博客_aac格式
头文件
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libswresample/swresample.h>
}
编码器配置
AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);//创建AAC音频编码器
AVCodecContext *ac = avcodec_alloc_context3(codec);//配置编码器的上下文
ac->sample_rate=44100;
ac->channels=2;
ac->channel_layout=AV_CH_LAYOUT_STEREO;//双声道立体声
ac->sample_fmt=AV_SAMPLE_FMT_FLTP;//32位空间
ac->bit_rate=64000;
ac->flags=AV_CODEC_FLAG_GLOBAL_GEADER;//头部
打开编码器,创建输出上下文,索引,头部,编码后数据都写入输出上下文
int ret;
ret=avcodec_open2(ac,codec,NULL);//打开音频编码器,成功返回0
AVFormatContext*oc=NULL;//创建输出上下文
avformat_alloc_output_context2(&oc,NULL,NULL,输出文件名)
AVStream*st=avformat_new_stream(oc,NULL);//音频流
st->codecpar->codec_tag=0;//音频文件设置为0,视频为1
avcodec_parameters_from_context(st->codecpar,ac);//将已初始化的编码器的格式拷贝至音频流
//打印配置好的信息,第二个数据音频为0,视频为1,第四个数据1打印,0不打印
av_dump_format(oc,0,输出文件名,1);
打开输出文件流
ret=avio_open(&oc->pb,outputflie,AVIO_FLAG_WRITE);//pb是io流
//写入头部信息
avformat_write_header(oc,NULL);
创建重采样上下文
SwrContext*ctx=NULL;//重采样上下文
//ctx参数配置
swr_alloc_set_opts(ctx,ac->channel_layouy,ac->sample_fmt,ac->sample_rate,//输出音频参数
AV_CH_LAYOUT_STEREO,AV_SAMPLE_FMT_S16,44100,//输入音频参数
0,0
);
//ctx初始化
int ret=swr_init(ctx);
预备重采样
//将PCM数据一帧一帧存放到frame,每一帧1024个样本
AVFrame*frame=av_frame_alloc();
frame->format=AV_SAMPLE_FMT_FLTP;//样本格式
frame->channels=2;
frame->channel_layout=AV_CH_LAYOUT_STEREO;
frame->nb_samples=1024;//一帧音频样本数量
av_frame_get_buffer(frame,0);//frame缓存空间
//采样率*位深度*声道数*时间
int readSize=frame->nb_samples*2*2;//一帧大小 1024*16*2*1/8
char*pcms=new char[readSize];
打开输入文件,并读取,重采样
FILE*fp=fopen(inputfile,"rb"//二进制);//打开输入文件
for(;;)
{
int len=fread(pcms,1,readSize,fp);
if(len<0)
{
break;
}
//重采样之前的数据
const uint8_t*data[1];
data[0]=(uint8_t*)pcms;//强转换
//开始重采样
len=swr_convert(ctx,frame->data,frame->nb_samples,//重采样之后的数据
data,frame->nb_samples//重采样之前的数据
);
if(len<0)
{
break;
}
//重采样之后进行编码并写入acc文件
//frame 放原数据,packet放编码后数据
AVPacket pkt;
av_init_packet(&pkt);
//将重采样数据发送到编码线程
ret=avcodec_send_frame(ac,frame);
if(ret<0)
{
continue;
}
ret=avcodec_recevice_packet(ac,&pkt);
if(ret!=0)
{
continue
}
pkt.stream_index=0;//0:音频流
pkt.dts=0;
pkt.pts=0; //解码时间,显示时间初始化为0
av_interleaved_write_frame(oc,&pkt);
}
视频索引与结尾工作
delete pcms;
pcms=NULL;
//视频索引
av_write_trailer(oc);
avio_close(oc->pb);//关闭文件io流
avcodec_close(ac);//关闭编码器
avcodec_free_context(&ac)//清理编码器缓存
avformat_free_context(oc)//清理上下文
,释放空间