核心知识:
一、输出媒体文件所需的结构 体: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设置采样率、 比特率等控制音频必要的参数。至此,我们有了编码所需的一切准备,不过别急,我们还需要打开它,恰好avco dec_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(a acFormatCtx);只是用来清空流的,一点都没有碰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;
}