首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >最简单的基于FFMPEG的音频编码器(PCM编码为AAC)

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

作者头像
全栈程序员站长
发布2022-07-08 18:07:55
发布2022-07-08 18:07:55
1.8K0
举报

大家好,又见面了,我是全栈君。

本文介绍一个最简单的基于FFMPEG的音频编码器。该编码器实现了PCM音频採样数据编码为AAC的压缩编码数据。编码器代码十分简单,可是每一行代码都非常重要。通过看本编码器的源码。能够了解FFMPEG音频编码的流程。

本程序使用最新版的类库(编译时间为2014.5.6)。开发平台为VC2010。全部的配置都已经做好,仅仅须要执行就能够了。

流程(2014.9.29更新)

以下附一张使用FFmpeg编码音频的流程图。

使用该流程。不仅能够编码AAC的音频,并且能够编码MP3,MP2等等各种FFmpeg支持的音频。图中蓝色背景的函数是实际输出数据的函数。

浅绿色的函数是音频编码的函数。

简介一下流程中各个函数的意义:

av_register_all():注冊FFmpeg全部编解码器。 avformat_alloc_output_context2():初始化输出码流的AVFormatContext。 avio_open():打开输出文件。 av_new_stream():创建输出码流的AVStream。 avcodec_find_encoder():查找编码器。 avcodec_open2():打开编码器。 avformat_write_header():写文件头(对于某些没有文件头的封装格式,不须要此函数。比方说MPEG2TS)。 avcodec_encode_audio2():编码音频。即将AVFrame(存储PCM採样数据)编码为AVPacket(存储AAC,MP3等格式的码流数据)。 av_write_frame():将编码后的视频码流写入文件。 av_write_trailer():写文件尾(对于某些没有文件头的封装格式。不须要此函数。比方说MPEG2TS)。

代码

代码语言:javascript
复制
/**
 *最简单的基于FFmpeg的音频编码器
 *Simplest FFmpeg Audio Encoder
 *
 *雷霄骅 Lei Xiaohua
 *leixiaohua1020@126.com
 *中国传媒大学/数字电视技术
 *Communication University of China / Digital TV Technology
 *http://blog.csdn.net/leixiaohua1020
 *
 *本程序实现了音频PCM採样数据编码为压缩码流(MP3。WMA,AAC等)。 *是最简单的FFmpeg音频编码方面的教程。 *通过学习本样例能够了解FFmpeg的编码流程。 *This software encode PCM data to AAC bitstream. *It's the simplest audio encoding software based on FFmpeg.  *Suitable for beginner of FFmpeg  */#include <stdio.h>#define __STDC_CONSTANT_MACROS#ifdef _WIN32//Windowsextern "C"{#include "libavcodec/avcodec.h"#include "libavformat/avformat.h"};#else//Linux...#ifdef __cplusplusextern "C"{#endif#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>#ifdef __cplusplus};#endif#endifint flush_encoder(AVFormatContext *fmt_ctx,unsigned int stream_index){	int ret;	int got_frame;	AVPacket enc_pkt;	if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities &		CODEC_CAP_DELAY))		return 0;	while (1) {		enc_pkt.data = NULL;		enc_pkt.size = 0;		av_init_packet(&enc_pkt);		ret = avcodec_encode_audio2 (fmt_ctx->streams[stream_index]->codec, &enc_pkt,			NULL, &got_frame);		av_frame_free(NULL);		if (ret < 0)			break;		if (!got_frame){			ret=0;			break;		}		printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n",enc_pkt.size);		/* mux encoded frame */		ret = av_write_frame(fmt_ctx, &enc_pkt);		if (ret < 0)			break;	}	return ret;}int main(int argc, char* argv[]){	AVFormatContext* pFormatCtx;	AVOutputFormat* fmt;	AVStream* audio_st;	AVCodecContext* pCodecCtx;	AVCodec* pCodec;	uint8_t* frame_buf;	AVFrame* pFrame;	AVPacket pkt;	int got_frame=0;	int ret=0;	int size=0;	FILE *in_file=NULL;	                        //Raw PCM data	int framenum=1000;                          //Audio frame number	const char* out_file = "tdjm.aac";          //Output URL	int i;	in_file= fopen("tdjm.pcm", "rb");	av_register_all();	//Method 1.	pFormatCtx = avformat_alloc_context();	fmt = av_guess_format(NULL, out_file, NULL);	pFormatCtx->oformat = fmt;	//Method 2.	//avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, out_file);	//fmt = pFormatCtx->oformat;	//Open output URL	if (avio_open(&pFormatCtx->pb,out_file, AVIO_FLAG_READ_WRITE) < 0){		printf("Failed to open output file!\n");		return -1;	}	audio_st = avformat_new_stream(pFormatCtx, 0);	if (audio_st==NULL){		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;  	//Show some information	av_dump_format(pFormatCtx, 0, out_file, 1);	pCodec = avcodec_find_encoder(pCodecCtx->codec_id);	if (!pCodec){		printf("Can not find encoder!\n");		return -1;	}	if (avcodec_open2(pCodecCtx, pCodec,NULL) < 0){		printf("Failed to open encoder!\n");		return -1;	}	pFrame = av_frame_alloc();	pFrame->nb_samples= pCodecCtx->frame_size;	pFrame->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(pFrame, pCodecCtx->channels, pCodecCtx->sample_fmt,(const uint8_t*)frame_buf, size, 1);		//Write Header	avformat_write_header(pFormatCtx,NULL);	av_new_packet(&pkt,size);	for (i=0; i<framenum; i++){		//Read PCM		if (fread(frame_buf, 1, size, in_file) <= 0){			printf("Failed to read raw data! \n");			return -1;		}else if(feof(in_file)){			break;		}		pFrame->data[0] = frame_buf;  //PCM Data		pFrame->pts=i*100;		got_frame=0;		//Encode		ret = avcodec_encode_audio2(pCodecCtx, &pkt,pFrame, &got_frame);		if(ret < 0){			printf("Failed to encode!\n");			return -1;		}		if (got_frame==1){			printf("Succeed to encode 1 frame! \tsize:%5d\n",pkt.size);			pkt.stream_index = audio_st->index;			ret = av_write_frame(pFormatCtx, &pkt);			av_free_packet(&pkt);		}	}		//Flush Encoder	ret = flush_encoder(pFormatCtx,0);	if (ret < 0) {		printf("Flushing encoder failed\n");		return -1;	}	//Write Trailer	av_write_trailer(pFormatCtx);	//Clean	if (audio_st){		avcodec_close(audio_st->codec);		av_free(pFrame);		av_free(frame_buf);	}	avio_close(pFormatCtx->pb);	avformat_free_context(pFormatCtx);	fclose(in_file);	return 0;}

结果

程序执行完毕后。会将一个PCM採样数据文件(*.pcm)编码为AAC码流文件(*.aac)。

下载

simplest ffmpeg audio encoder

项目主页

SourceForge:https://sourceforge.net/projects/simplestffmpegaudioencoder/

Github:https://github.com/leixiaohua1020/simplest_ffmpeg_audio_encoder

开源中国:http://git.oschina.net/leixiaohua1020/simplest_ffmpeg_audio_encoder

CSDNproject下载地址:

http://download.csdn.net/detail/leixiaohua1020/7324091

PUDNproject下载地址:

http://www.pudn.com/downloads644/sourcecode/multimedia/detail2605236.html

更新-1.1 (2015.2.13)=========================================

这次考虑到了跨平台的要求,调整了源码。经过这次调整之后,源码能够在以下平台编译通过:

VC++:打开sln文件就可以编译,无需配置。

cl.exe:打开compile_cl.bat就可以命令行下使用cl.exe进行编译,注意可能须要依照VC的安装路径调整脚本里面的參数。编译命令例如以下。

代码语言:javascript
复制
::VS2010 Environment
call "D:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"
::include
@set INCLUDE=include;%INCLUDE%
::lib
@set LIB=lib;%LIB%
::compile and link
cl simplest_ffmpeg_audio_encoder.cpp /link avcodec.lib avformat.lib avutil.lib ^
avdevice.lib avfilter.lib postproc.lib swresample.lib swscale.lib /OPT:NOREF

MinGW:MinGW命令行下执行compile_mingw.sh就可以使用MinGW的g++进行编译。 编译命令例如以下。

代码语言:javascript
复制
g++ simplest_ffmpeg_audio_encoder.cpp -g -o simplest_ffmpeg_audio_encoder.exe \
-I /usr/local/include -L /usr/local/lib -lavformat -lavcodec -lavutil

GCC:Linux或者MacOS命令行下执行compile_gcc.sh就可以使用GCC进行编译。编译命令例如以下。

代码语言:javascript
复制
gcc simplest_ffmpeg_audio_encoder.cpp -g -o simplest_ffmpeg_audio_encoder.out \
-I /usr/local/include -L /usr/local/lib -lavformat -lavcodec -lavutil

PS:相关的编译命令已经保存到了project目录中

CSDN下载地址:http://download.csdn.net/detail/leixiaohua1020/8445209

SourceForge上已经更新。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/116024.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年1月2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 流程(2014.9.29更新)
  • 代码
  • 结果
  • 下载
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档