天天看點

ffmpeg之PCM轉AAC

AAC是一種常見的音頻格式,今天嘗試使用ffmpeg把pcm壓縮成AAC編碼。

第一步:初始化編碼相關變量

尋找AAC的編碼器

codec = avcodec_find_encoder(AV_CODEC_ID_AAC);           

 初始化編碼器上下文,主要通道數,采樣率,采樣格式

c = avcodec_alloc_context3(codec);
	if (!c) {
		fprintf(stderr, "Could not allocate audio codec context\n");
		return false;
	}
	c->channels = m_PcmChannel;
	c->channel_layout = av_get_default_channel_layout(m_PcmChannel);
	c->sample_rate = m_PcmSampleRate;
	c->sample_fmt = AV_SAMPLE_FMT_FLTP;//AV_SAMPLE_FMT_FLTP;
	c->bit_rate = 64000;
	/* Allow the use of the experimental AAC encoder. */
	c->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;           

 打開編碼器

if (avcodec_open2(c, codec, NULL) < 0) {
		fprintf(stderr, "Could not open codec\n");
		return false;
	}           

 設定格式轉換,主要是AAC需要的采樣格式位AV_SAMPLE_FMT_FLTP,而PCM格式位AV_SAMPLE_FMT_S16,是以需要進行格式的轉換。

resample_context = swr_alloc_set_opts(NULL, c->channel_layout, c->sample_fmt,
		c->sample_rate, c->channel_layout, m_PcmFormat, c->sample_rate, 0, NULL);
if (swr_init(resample_context) < 0)
	{
		fprintf(stderr, "Could not open resample context\n");
		return false;
	}           

第二步:初始化相關工作做完之後,可以進行轉碼工作,首先丢進。

對PCM進行重新采樣,轉換成AAC需要的PCM格式

if (swr_convert(resample_context, frame->extended_data, frame->nb_samples, (const uint8_t**)m_PcmPointer, 1024)<0)
	{
		fprintf(stderr, "Could not convert input samples (error )\n");
		if (NULL != frame)
		{
			av_frame_free(&frame);
		}
		return ;
	}           

 放進編碼器

ret = avcodec_send_frame(c, frame);           

第三步:從編碼器取出編碼完的資料

int  ret = avcodec_receive_packet(c, packet);           

第四步:由于編碼後的AAC檔案沒有頭,導緻寫成檔案無法識别,是以需要手動寫入AAC頭

// fill in ADTS data  
	m_pOutData[0] = 0xFF;
	m_pOutData[1] = 0xF1;
	m_pOutData[2] = ((profile) << 6) + (freqIdx << 2) + (chanCfg >> 2);
	m_pOutData[3] = (((chanCfg & 3) << 6) + (packetLen >> 11));
	m_pOutData[4] = ((packetLen & 0x7FF) >> 3);
	m_pOutData[5] = (((packetLen & 7) << 5) + 0x1F);
	m_pOutData[6] = 0xFC;           

至此,PCM轉成AAC的格式流程結束。

這裡對AVSampleFormat格式進行一下介紹,

如果是以下格式:

    AV_SAMPLE_FMT_U8,          ///< unsigned 8 bits

    AV_SAMPLE_FMT_S16,         ///< signed 16 bits

    AV_SAMPLE_FMT_S32,         ///< signed 32 bits

    AV_SAMPLE_FMT_FLT,         ///< float

    AV_SAMPLE_FMT_DBL,         ///< double

隻能儲存再AVFrame的uint8_t *data[0];

音頻保持格式如下:

LRLRLR。。。。

如果是以下格式

    AV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planar

    AV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planar

    AV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planar

    AV_SAMPLE_FMT_FLTP,        ///< float, planar

    AV_SAMPLE_FMT_DBLP,        ///< double, planar

plane 0: LLLLLLLLLLLLLLLLLLLLLLLLLL...

plane 1: RRRRRRRRRRRRRRRRRRRR....

plane 0對于uint8_t *data[0];