FFmpeg 把pcm音频转换为aac

//AAC在数据开始时候加了一些参数:采样率、声道、采样大小。 PCM文件不能直接播放,需要转为其他格式才//能播放。 AAC格式可以直接播放。 PCM是原始数据没有经过编码和压缩。这里会有一些杂音,是因为wav的前面是有一点协议帧头,按照音频去处理了

extern "C"
{
	#include 
	#include 
	#include 
}

#include 
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";
	//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;
		getchar();
		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  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);



	//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;
		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;//4个byte
	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;
		
/** 转换音频。
 *
 * 输入和in_count可以设置为 0 以在
 *结束。
 *
 * 如果提供的输入多于输出空间,则输入将被缓冲。
 * 您可以通过使用 swr_get_out_samples() 检索
 * 给定数量的输出样本数的上限
 * 输入样本。转换将直接运行,尽可能不复制。
 *
 * @param s 分配的 Swr 上下文,并设置参数
 *@param输出缓冲区,在打包音频的情况下只需要设置第一个
 * 每个通道的样本输出空间量@param out_count
 *@param输入缓冲区,在打包音频的情况下只需要设置第一个
 * 一个通道中可用的输入样本数量@param in_count
 *
 * @return每个通道输出的样本数,误差时为负值
 */

		

		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;//因为只有1路,所有只有索引为0
		pkt.pts = 0;//因为音频其实不存在P帧之类,所以不许要,只需要默认就可以了
		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);






















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

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