核心知識:
一、輸出媒體文件所需的結構 體: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;
}