首页 > 代码库 > 使用ffmpeg转码pcm至aac格式

使用ffmpeg转码pcm至aac格式

准备工作

去官网下载源码自己编译所需要的库,或者直接从官网下载已经编写好的库,由于本例是Window平台下的开发,而官网已经有了编译好的库,所以直接下载编译所需要的库文件即可。下载地址:需要下载两个压缩包,Dev版本和Shared版本,其中Dev版本是头文件和lib库文件,Shared是包含运行所需要的dll文件。

下载完成后,需要把这些头文件、静态库、动态链接库引入到我们的工程里面,不过在Windows下面,头文件除了要用到FFMPEG提供的,还要使用另外三个文件:inttypes.h,stdint.h,_mingw.h,这三个文件放到FFMPEG头文件的根目录下即可。


项目工程

代码示例

// C++代码需要加这个!!否则找不到函数的
extern "C"
{
#include "libavcodec\avcodec.h"
#include "libavformat\avformat.h"
#include "libswscale\swscale.h"

// 链接的ffmpeg库,我把所有可能需要用到的都写这里了
#pragma comment (lib, "Ws2_32.lib")  
#pragma comment (lib, "avcodec.lib")
#pragma comment (lib, "avdevice.lib")
#pragma comment (lib, "avfilter.lib")
#pragma comment (lib, "avformat.lib")
#pragma comment (lib, "avutil.lib")
#pragma comment (lib, "swresample.lib")
#pragma comment (lib, "swscale.lib")
};

int main(int argc, char* argv[])
{
	AVFormatContext* pFormatCtx;
	AVOutputFormat* fmt;
	AVStream* audio_st;
	AVCodecContext* pCodecCtx;
	AVCodec* pCodec;

	uint8_t* frame_buf;
	AVFrame* frame;
	int size;

	FILE *fileIn = fopen("Beyond.pcm", "rb");
	char* fileOut = "Beyond.aac";		

	// 初始化注册FFMPEG以供使用
	av_register_all();

	// 解码文件格式
	avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, fileOut);
	fmt = pFormatCtx->oformat;

	//注意输出路径
	if (avio_open(&pFormatCtx->pb, fileOut, AVIO_FLAG_READ_WRITE) < 0)  
	{
		printf("输出文件打开失败!\n");
		return -1;
	}

	audio_st = avformat_new_stream(pFormatCtx, 0);
	if (audio_st == NULL)
	{
		printf("新建流失败!!!\n");
		return -1;
	}

	// 设定转码信息
	pCodecCtx = audio_st->codec;
	pCodecCtx->codec_id = fmt->audio_codec;
	pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
	pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
	pCodecCtx->sample_rate= 44100;				// 音频的采样率
	pCodecCtx->channel_layout=AV_CH_LAYOUT_STEREO;
	pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout);
	pCodecCtx->bit_rate = 64000;				// 音频的比特率

	//调试输出格式信息
	av_dump_format(pFormatCtx, 0, fileOut, 1);

	pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
	if (!pCodec)
	{
		printf("找不到输入文件所需的编码器!\n");
		return -1;
	}
	if (avcodec_open2(pCodecCtx, pCodec,NULL) < 0)
	{
		printf("打开编码器失败!\n");
		return -1;
	}

	frame = avcodec_alloc_frame();
	frame->nb_samples= pCodecCtx->frame_size;
	frame->format= pCodecCtx->sample_fmt;
	
	size = av_samples_get_buffer_size(NULL, pCodecCtx->channels,pCodecCtx->frame_size,pCodecCtx->sample_fmt, 1);
	frame_buf = (uint8_t *)av_malloc(size);
	avcodec_fill_audio_frame(frame, pCodecCtx->channels, pCodecCtx->sample_fmt,(const uint8_t*)frame_buf, size, 1);
	
	// 填充输出的头文件信息
	avformat_write_header(pFormatCtx,NULL);

	AVPacket pkt;
	av_new_packet(&pkt,size);

	for (int i=0; ; i++)
	{
		//读入PCM
		if (fread(frame_buf, 1, size, fileIn) < 0)
		{
			printf("文件读取错误!\n");
			return -1;
		}
		else if(feof(fileIn))
		{
			break;
		}
		frame->data[0] = frame_buf;  //采样信号

		frame->pts=i*100;
		int got_frame=0;
		//编码
		int ret = avcodec_encode_audio2(pCodecCtx, &pkt,frame, &got_frame);
		if(ret < 0)
		{
			printf("编码错误!\n");
			return -1;
		}
		if (got_frame==1)
		{
			pkt.stream_index = audio_st->index;
			ret = av_write_frame(pFormatCtx, &pkt);
			av_free_packet(&pkt);
		}
	}
	
	//写文件尾
	av_write_trailer(pFormatCtx);

	//清理
	if (audio_st)
	{
		avcodec_close(audio_st->codec);
		av_free(frame);
		av_free(frame_buf);
	}
	avio_close(pFormatCtx->pb);
	avformat_free_context(pFormatCtx);
	fclose(fileIn);

	printf("转码完毕!!!\n");
	return 0;
}

由于FFMPEG会没事就修改接口,所以不同版本的FFMPEG可能会编译不过,反正2015年1月23日17:29:31是可以编译通过的。

参考

最简单的基于FFMPEG的音频编码器(PCM编码为AAC)

使用ffmpeg转码pcm至aac格式