精简但精确的PCM编码为AAC解析

来源:互联网 发布:顶尖恢复软件注册码 编辑:程序博客网 时间:2024/05/22 08:27

核心知识:

一、输出媒体文件所需的结构体:AVOutputFormat,AVFormatContext,AVStream,AVCodec,AVCodecContext,AVFrame,AVPacket(按出现先后顺序)。

二、AVOutputFormat是输出容器(container)句柄,直接关联文件,但只有句柄远远不够,我们需要设置相关参数AVFormatContext就是容器上下文(用avformat_alloc_context初始化),我们于其设置目标容器文件名,目标容器句柄,I/O上下文(this->pb);

三、只有上面两个,我们还是不能对相应文件进行写入操作,需要对其进行流化操作,我们用avformat_new_stream(aacFormatCtx, NULL);初始化一个空流,但这时这个Stream还是不能用!因为这是一个真正的空流!里面的数据指针和流头都还未被初始化,我们需要avformat_write_header(aacFormatCtx, NULL);这次才是真正的生成了可以用的流。

四、AVCodec这个结构体包含了一个解码器的必要参数,好在ffmpeg为我们提供了简单的接口avcodec_find_encoder,这样就可以很容易的获取一个编码器(只是相关参数!)。

五、仅仅有AvCOdec是远远不够的,如果我们想要得到一个真正的编码器,还需要在AVCodecContext设置采样率、比特率等控制音频必要的参数。至此,我们有了编码所需的一切准备,不过别急,我们还需要打开它,恰好avcodec_open2就提供了这个功能!

六、我们这时可以初始化我们的编码帧AVFrame了,编码格式和帧大小是我们要特别注意的,也是我们必须要设置的,因为这是我们确定一个桢大小的必要条件。当然我们还需要填充它,为了我们更好的控制,ffmpeg把缓冲区的控制留给了我们,但是这也正是我们应该要特别小心的地方,不要忘记在不用这个Frame的时候释放它!别相信Av_malloc,它只是malloc的一个wrapper:)

七、我们的Rtp传输需要用包,所以这时就需要把frame写为AVPacket,但是我们要先给AVPacket设置内存空间av_new_packet(&pkt, aacBufferSize);后面一个是PayLoad,不知道PayLoad是什么的回家去读幼儿园:)

八、看起来这时我们可以把包写进文件了av_write_frame(aacFormatCtx, &pkt);(有坑:)相对于av_interleaved_writ e_frame()),但是我们最重要的流序号和时间戳可不要忘了先设置好:),而且发送一个包后不要忘了清空这个包,(用的流媒体模型:))。

九、尽情地写入或发送把!

十、最后结束时可不要忘了清理战场!

av_frame_free用来释放AvFrame,我看到过好多例子,在这个之后还要av_free(Avframe->data[0]),其实完全没有必要!这个函数可以清空Avframe里面所有的动态内存!然后我们关闭aacFormatCtx的I/O口;av_write_trailer(aacFormatCtx);只是用来清空流的,一点都没有碰aacFormatCtx!所以我们需要手动释放aacFormatCtx!最后我们关闭编码器:)

至此,Good Job and enjoy it by yourself!

// EncodeToAAC.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"extern "C"{#include"libavcodec/avcodec.h"#include"libavformat/avformat.h"#include"libavdevice/avdevice.h"#include<stdlib.h>}int _tmain(int argc, _TCHAR* argv[]){av_register_all();/*pcmfile:要打开的pcm波形文件* aacStream:将要编码的流* aacFormatCtx:目标句柄上下文* aacCodecCtx:要创建的aac编码器上下文* aacCodec:aac编码器*/FILE *pcmfile = NULL;fopen_s(&pcmfile,"audio.pcm", "rb");if (!pcmfile){printf("Find PCMfile error!\n");return -1;}int aacBufferSize = 0;uint8_t *aacBuffer = NULL;AVFrame *aacFrame = NULL;AVStream *aacStream = NULL;AVOutputFormat *aacOutFmt = NULL;AVFormatContext *aacFormatCtx = NULL;AVCodecContext *aacCodecCtx = NULL;AVCodec *aacCodec = NULL;//容器流的准备aacFormatCtx = avformat_alloc_context();aacOutFmt = av_guess_format(NULL, "audio.aac", NULL);aacFormatCtx->oformat = aacOutFmt;sprintf_s(aacFormatCtx->filename, "%s", "audio.aac");if (avio_open(&aacFormatCtx->pb, "audio.aac", AVIO_FLAG_READ_WRITE)<0){printf("open file failed(get handle failed!)");return -1;}aacStream = avformat_new_stream(aacFormatCtx, NULL);avformat_write_header(aacFormatCtx, NULL);//解码器相关准备aacCodec = avcodec_find_encoder(AV_CODEC_ID_AAC);aacCodecCtx = avcodec_alloc_context3(aacCodec);aacCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;aacCodecCtx->codec = aacCodec;aacCodecCtx->time_base.den = 1;aacCodecCtx->time_base.num = 3600;aacCodecCtx->channels = 2;aacCodecCtx->channel_layout = AV_CH_LAYOUT_STEREO;aacCodecCtx->bit_rate = 192000;aacCodecCtx->sample_rate = 44100;aacCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;if (avcodec_open2(aacCodecCtx, aacCodec, NULL)<0){printf("creat this encoder erro !");return -2;}//编码帧的准备aacFrame = av_frame_alloc();aacFrame->nb_samples = aacCodecCtx->frame_size;aacFrame->format = aacCodecCtx->sample_fmt;aacBufferSize = av_samples_get_buffer_size(NULL, aacCodecCtx->channels, aacCodecCtx->frame_size, aacCodecCtx->sample_fmt, NULL);aacBuffer = (uint8_t *)av_malloc(aacBufferSize);avcodec_fill_audio_frame(aacFrame, aacCodecCtx->channels, aacCodecCtx->sample_fmt, aacBuffer, aacBufferSize, NULL);//发送包:)AVPacket pkt;av_new_packet(&pkt, aacBufferSize);for (int i = 1;; i++){fread(aacBuffer, sizeof(uint8_t), aacBufferSize, pcmfile);if (feof(pcmfile)){printf("srcfile meet end! exiting....\n");break;}aacFrame->data[0] = aacBuffer;int gotFrame;if (avcodec_encode_audio2(aacCodecCtx, &pkt, aacFrame, &gotFrame)<0){printf("encode error!!\n");break;}if (gotFrame){printf("encode success %d frame(s)\n", i);pkt.stream_index = aacStream->index;if (pkt.pts == AV_NOPTS_VALUE){pkt.pts = i * 3600;printf("encoded pkt pts: %d\n", pkt.pts);}av_write_frame(aacFormatCtx, &pkt);av_free_packet(&pkt);}}av_free_packet(&pkt);av_frame_free(&aacFrame);printf("encode all file success!\n");av_write_trailer(aacFormatCtx);avio_close(aacFormatCtx->pb);avformat_free_context(aacFormatCtx);avcodec_close(aacCodecCtx);fclose(pcmfile);return 0;}


0 0