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

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Mr__Hu/article/details/91795842


我的大部分学习都来自雷神,没有基础去雷神博客转转,每次都有很多收获。
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);
}
展开阅读全文

ffmpeg音频重采样、编码

01-21

我看网上的例子都是这样的(如下)。我有个问题:如果输入的nb_samples = 1151,输出的codec_ctx->frame_size = 2048;这样的话fifo需要写入两次后才能读出一次。如果输入的格式是平面格式,那么fifo中的数据格式就是(假设声道1的数据是1,声道2的数据是2):11111...(1151个1)22222...(1151个2)1111...(1151个1)2222...(1151个2);然后读出的数据格式就应该是,声道1:111111...2222..(1151个1,897个2);声道2:222...1111..22.(254个2,1151个1,x个2)。rn这样的话读出的数据肯定是不对的啊!! 那应该怎么处理呢?rn[code=c]rn//Resamping of the audiornrn m_pReSmpCtx = av_audio_resample_init(m_pAudioSt->codec->channels,m_audioFmt.in_channels,\rn m_pAudioSt->codec->sample_rate,m_audioFmt.in_sample_rate,\rn SAMPLE_FMT_S16,SAMPLE_FMT_S16,16,10,0,1.0);rnrn int32_t samples = delen / ((m_pAudioSt->codec->channels) * 2);rn int32_t resamplenum = 0;rn int32_t resamplesize = 0;rn int16_t *resamplebuff = new int16_t[MAX_AUDIO_FRAME_SIZE];rn resamplenum = audio_resample(m_pReSmpCtx,resamplebuff,(int16_t*)debuff,samples);rn resamplesize = resamplenum * 2 * (m_pAudioSt->codec->channels);rnrn if(CODEC_TYPE_IPMR == pkt.codecType)rn delete []debuff;rn rnrn av_fifo_realloc2(m_pFifo,av_fifo_size(m_pFifo)+resamplesize);rn av_fifo_generic_write(m_pFifo,resamplebuff,resamplesize,NULL);rn// av_fifo_write(m_pFifo,(uint8_t*)resamplebuff,resamplesize);rnrn delete []resamplebuff;rnrnrn while(av_fifo_size(m_pFifo) >= m_audioSmpSize)rn uint8_t *readbuff = new uint8_t[m_audioSmpSize];rn uint8_t *enbuff = new uint8_t[MAX_AUDIO_FRAME_SIZE];rn int32_t ensize = MAX_AUDIO_FRAME_SIZE;rn av_fifo_generic_read(m_pFifo,readbuff,m_audioSmpSize,NULL);rn AVPacket packet;rn av_init_packet(&packet);rn packet.size = avcodec_encode_audio(m_pAudioSt->codec,enbuff,ensize,(short *)readbuff);rn packet.flags |= AV_PKT_FLAG_KEY;rn packet.data = enbuff;rn packet.stream_index = m_pAudioSt->index;rn if (packet.size > 0 )rn if (av_write_frame(m_pFmtCtx,&packet) != 0)rn ret = RECORD_AUDIO_PLUGIN | WRITE_FRAME_ERR;rn delete []readbuff;rn delete []enbuff;rn return ret;rn rn rn delete []readbuff;rn delete []enbuff;rn av_free_packet(&packet);rnrn rn[/code] 论坛

没有更多推荐了,返回首页