第三章 使用ffmpeg把wav转aac

本文章介绍ffmpeg基本使用

1. 打开音频编码器

AVCodec *avcodec_find_encoder(enum AVCodecID id);
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);
avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, 
                        AVDictionary **options);

详见第二章

//muxer,demuters
av_register_all();
avcodec_register_all();

//1 打开音频编码器
AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if (!codec)
{
	cout << "avcodec_find_encoder error" << endl;
	getchar();
	return -1;
}
//创建编码上下文
AVCodecContext *c = avcodec_alloc_context3(codec);
if (!c)
{
	cout << "avcodec_alloc_context3 error" << endl;
	getchar();
	return -1;
}
c->bit_rate = 64000;					//压缩比特率
c->sample_rate = 44100;					//采样率
c->sample_fmt = AV_SAMPLE_FMT_FLTP;		//
c->channel_layout = AV_CH_LAYOUT_STEREO;//通道类型 立体声
c->channels = 2;						//通道数量 双通道
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;//全局的编码信息

//打开编码器
int ret = avcodec_open2(c, codec, NULL);
if (ret < 0)
{
	cout << "avcodec_open2 error" << endl;
	getchar();
	return -1;
}
cout << "avcodec_open2 success!" << endl;

 2. 打开输出封装的上下文

AVFormatContext *oc = NULL;
//创建输出的上下文
avformat_alloc_output_context2(&oc, NULL,NULL,outfile);
if (!oc)
{
	cout << "avformat_alloc_output_context2 error" << endl;
	return -1;
}

//创建音频流
AVStream *st = avformat_new_stream(oc, NULL);
st->codecpar->codec_tag = 0;
//根据提供的编解码器中的值填充参数结构
avcodec_parameters_from_context(st->codecpar, c);
//打印封装格式
av_dump_format(oc, 0, outfile, 1);

3. 打开io 写入头部

//打开文件
ret = avio_open(&oc->pb, outfile, AVIO_FLAG_WRITE);
if (ret < 0)
{
	cout << "avio_open error" << endl;
	getchar();
	return -1;
}
//写入头部
ret = avformat_write_header(oc, NULL);

4. 创建音频重采样上下文

//44100 16 2
//4 创建音频重采样上下文
SwrContext *actx = NULL;		//音频重采样上下文
actx = swr_alloc_set_opts(actx,
	c->channel_layout, c->sample_fmt, c->sample_rate,	//输出格式
	AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16,44100,		//输入格式
	0, 0);
if (!actx)
{
	cout << "swr_alloc_set_opts error" << endl;
	return -1;
}
ret = swr_init(actx);		//设置用户参数后初始化上下文
if (ret < 0)
{
	cout << "swr_init error" << endl;
	return -1;
}

5. 打开输入音频文件,进行重采样

6. 音频编码 音频封装如aac文件

//5 打开输入音频文件,进行重采样
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;//一帧音频存放的样本数量
ret = av_frame_get_buffer(frame, 0);	//创建空间
if (ret < 0)
{
	cout << "av_frame_get_buffer error" << endl;
	getchar();
	return -1;
}

int readSize = frame->nb_samples * 2 * 2;	//一次读取的大小 2个通道

char *pcm = new char[readSize];

FILE *fp = fopen(infile, "rb");

for (;;)
{
	int len = fread(pcm, 1, readSize, fp);
	if (len <= 0)break;
	const uint8_t *data[1];
	data[0] = (uint8_t*)pcm;

	//重采样 进行格式转换
	len = swr_convert(actx, frame->data, frame->nb_samples,
		data, frame->nb_samples
		);
	if (len <= 0)
		break;
	

	AVPacket pkt;
	av_init_packet(&pkt);

	//6 音频编码
	
	/*	向编码器提供原始视频或音频帧。使用avcodec_receive_packet()
		以检索缓冲的输出分组。
		参数:上下文 已经重采样的一帧数据
	*/
	ret = avcodec_send_frame(c, frame);
	if (ret != 0) continue;
	ret = avcodec_receive_packet(c, &pkt);//从编码器读取编码数据
	if (ret != 0) continue;


	//7 音频封装如aac文件
	pkt.stream_index = 0;	//索引 如果有视频可能从1开始
	pkt.pts = 0;
	pkt.dts = 0;
	ret = av_interleaved_write_frame(oc, &pkt);//写入一帧数据


	cout << "[" << len << "]";

}

//资源释放
delete pcm;
pcm = NULL;

//写入视频索引
av_write_trailer(oc);

//关闭视频输出io
avio_close(oc->pb);

//清理封装输出上下文
avformat_free_context(oc);

//关闭编码器
avcodec_close(c);

//清理编码器上下文
avcodec_free_context(&c);

你可能感兴趣的:(ffmpeg,ffmpeg,aac,音视频)