音视频开发——(四)编码音频


我的大部分学习都来自雷神,没有基础去雷神博客转转,每次都有很多收获。
https://blog.csdn.net/leixiaohua1020/article/details/42658139

一、编码一般步骤

avformat_alloc_output_context2();                //初始化输出码流
avio_open();                                     //打开输出文件
av_new_stream();                                 //创建输出码流
avcodec_find_encoder();                          //寻找解码器
avcodec_alloc_context3();                        //打开解码器上下文
avcodec_open2();                                 //打开解码器
avformat_write_header();                         //写文件头
avcodec_send_frame();               
avcodec_receive_packet();                        //两步为编码
av_interleaved_write_frame();                   //将编码后压缩包写入文件
av_write_trailer();                             //写文件尾

主要流程图可以去雷神那看看,对于像我这样的初学者很有帮助。

二、编码

2.1 创建编码器(本文创建AAC)

AVCodec *avcodec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if (avcodec == NULL) 
{
	//创建失败
    return -1;
}
AVCodecContext *avcodec_context = avcodec_alloc_context3(avcodec);
avcodec_context->bit_rate = 64000;
avcodec_context->sample_rate = 44100;
avcodec_context->sample_fmt = AV_SAMPLE_FMT_FLTP;
avcodec_context->channel_layout = AV_CH_LAYOUT_STEREO;
avcodec_context->channels = 2;
avcodec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

//打开编码器
int ret = avcodec_open2(avcodec_context,avcodec,NULL);
if (ret < 0)
{
    //打开失败
    return -1;
}

2.2 核心编码

需要注意两点:

1.由于PCM格式为S16,AAC格式为FLTP,所以在编码前需要重采样音频,将其格式转换为所需格式。
2.PCM大小为1152,但是AAC的只有1024,所以也需要注意nb_samples的设置。

len = swr_convert(actx, frame->data, frame->nb_samples,
                      data, frame->nb_samples);
AVPacket pkt;
av_init_packet(&pkt);

// 音频编码
ret = avcodec_send_frame(avcodec_context,frame);
if (ret != 0) continue;
ret = avcodec_receive_packet(avcodec_context,&pkt);
if (ret != 0) continue;

// 音频封装成aac文件
pkt.stream_index = 0;
pkt.pts = 0;
pkt.dts = 0;
ret = av_interleaved_write_frame(oc,&pkt);
cout << "[" << len << "]";
av_packet_unref(&pkt);

三、源码

int main(int argc, char *argv[])
{
	char infile[] = "out.pcm";
	char outfile[] = "out.aac";
	
	av_register_all();
	avcodec_register_all();

	AVCodec *avcodec = avcodec_find_encoder(AV_CODEC_ID_AAC);
	if (!codec)
	{
    	cout << "avcodec_find_encoder error" << endl;
    	return -1;
	}
	
	AVCodecContext *avcodec_context = avcodec_alloc_context3(avcodec);
	if (!avcodec_context)
	{
    	cout << "avcodec_alloc_context3 error" << endl;
    	return -1;
	}
	avcodec_context->bit_rate = 64000;
	avcodec_context->sample_rate = 44100;
	avcodec_context->sample_fmt = AV_SAMPLE_FMT_FLTP;
	avcodec_context->channel_layout = AV_CH_LAYOUT_STEREO;
	avcodec_context->channels = 2;
	avcodec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

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

	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);

	ret = avio_open(&oc->pb,outfile,AVIO_FLAG_WRITE);
	if (ret < 0)
	{
    	cout << "avio_open error" << endl;
    	return -1;
	}
	
	ret = avformat_write_header(oc,NULL);

	SwrContext *actx = NULL;
	actx = swr_alloc_set_opts(actx, avcodec_context->channel_layout,
							avcodec_context->sample_fmt,avcodec_context->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;
	}
	
	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;
    	return -1;
	}

	int readSize = frame->nb_samples * 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);

    	//音频编码
    	ret = avcodec_send_frame(avcodec_context,frame);
    	if (ret != 0) continue;
    	ret = avcodec_receive_packet(avcodec_context,&pkt);
    	if (ret != 0) continue;

    	// 音频封装成aac文件
    	pkt.stream_index = 0;
    	pkt.pts = 0;
    	pkt.dts = 0;
    	ret = av_interleaved_write_frame(oc,&pkt);
    	cout << "[" << len << "]";
    	av_packet_unref(&pkt);
	}

	AVPacket pkt;
	av_init_packet(&pkt);

	ret = avcodec_send_frame(avcodec_context, NULL);
	cout << "ret1 = " << ret << endl;
	ret = avcodec_receive_packet(avcodec_context, &pkt);
	cout << "ret2 = " << ret << endl;

	pkt.stream_index = 0;
	pkt.pts = 0;
	pkt.dts = 0;
	ret = av_interleaved_write_frame(oc,&pkt);
	av_packet_unref(&pkt);

	delete pcm;
	pcm = NULL;
	av_write_trailer(oc);

	avio_close(oc->pb);
    avformat_free_context(oc);
	avcodec_close(c);
	avcodec_free_context(&c);
	fclose(fp);
}

猜你喜欢

转载自blog.csdn.net/Mr__Hu/article/details/91795842