1. 程式人生 > >ffmpeg編碼之PCM到AAC

ffmpeg編碼之PCM到AAC

編碼前檔案

編碼後文件

 編碼過程

實現方式

extern "C"
{
	#include <libavformat\avformat.h>
	#include <libswscale\swscale.h>
	#include <libswresample\swresample.h>
}

#include <iostream>
using namespace std;
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"swscale.lib")
#pragma comment(lib,"swresample.lib")

int main()
{
	char infile[] = "16.wav";
	char outfile[] = "out.aac";

	//register muxer,demuters 格式
	av_register_all();
	//register codec
	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;//位元率  :每秒傳輸的位元(bit)數,位元率越高,傳輸資料速度越快
	//取樣率:每秒採集的樣本數
	c->sample_rate = 44100;
	//樣本格式和儲存方式  float, planar
	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;
		getchar();
		return -1;
	}

	//第二個引數為空,就是根據檔案格式,自動選擇合適的編碼器
	AVStream *st = avformat_new_stream(oc,NULL);
	st->codecpar->codec_tag = 0;
	avcodec_parameters_from_context(st->codecpar,c);


	//3,open io,write head
	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 建立音訊重取樣上下文
	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;
		getchar();
		return -1;
	}
	ret = swr_init(actx);
	if (ret < 0)
	{
		cout << "swr_init error" << endl;
		getchar();
		return -1;
	}
	//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;
	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 音訊編碼
		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;
		pkt.pts = 0;
		pkt.dts = 0;
		ret = av_interleaved_write_frame(oc,&pkt);
		cout << "[" << len << "]";
	}

	delete pcm;
	pcm = NULL;

	//寫檔案尾
	av_write_trailer(oc);

	//關閉輸出流
	avio_close(oc->pb);
	//清理封裝輸出上下文
	avformat_free_context(oc);

	//關閉編碼器
	avcodec_close(c);
	//清理編碼器上下文
	avcodec_free_context(&c);

	cout << "======================end=========================" << endl;
	getchar();
	return 0;
}