ffmpeg主要數據結構和函數

FFMpeg 中比較重要的函數以及數據結構如下:

1. 數據結構:

(1) AVFormatContext

(2) AVOutputFormat

(3) AVInputFormat

(4) AVCodecContext

(5) AVCodec

(6) AVFrame

(7) AVPacket

(8) AVPicture

(9) AVStream

2. 初始化函數:

(1)av_register_all()

(2) avcodec_open()

(3) avcodec_close()

(4)av_open_input_file()

(5)av_find_input_format()

(6)av_find_stream_info()

(7)av_close_input_file()

3. 音視頻編解碼函數:

(1)avcodec_find_decoder()

(2)avcodec_alloc_frame()

(3)avpicture_get_size()

(4)avpicture_fill()

(5) img_convert()

(6) avcodec_alloc_context()

(7)avcodec_decode_video()

(8)av_free_packet()

(9) av_free()

4. 文件操作:

(1) avnew_steam()

(2) av_read_frame()

(3)av_write_frame()

(4) dump_format()

5. 其他函數:

(1)avpicture_deinterlace()

(2)ImgReSampleContext()

(3)sws_setColorspaceDetails()

以下就根據,以上數據結構及函數在ffmpeg測試代碼output_example.c中出現的前後順進行分析。

交待完畢進入正題。

一.FFMpeg 中的數據結構:  

I. AVFormatContext

一般在使用ffmpeg sdk的代碼中AVFormatContext是一個貫穿始終的數據結構,很多函數都要用到它作爲參數。FFmpeg代碼中對這個數據結構的註釋是:format I/O context 此結構包含了一個視頻流的格式內容。其中存有了AVInputFormator AVOutputFormat同一時間AVFormatContext內只能存在其中一個),和AVStreamAVPacket這幾個重要的數據結構以及一些其他的相關信息,比如title,author,copyright等。還有一些可能在編解碼中會用到的信息,諸如:duration, file_size, bit_rate等。參考avformat.h頭文件。

Useage:

聲明:

AVFormatContext*oc; (1)

初始化:由於AVFormatConext結構包含許多信息因此初始化過程是分步完成,而且有些變量如果沒有值可用,也可不初始化。但是由於一般聲明都是用指針因此一個分配內存過程不可少:

oc =av_alloc_format_context(); (2)

結構中的AVInputFormat*(或AVOutputFormat*)是一定要初始化的,基本上這是編譯碼要使用什麼codec的依據所在:

oc->oformat =fmt; or oc->iformat = fmt; (3)

其中AVOutputFormat* fmtAVInputFormat* fmt。(AVInputFormat and AVOutputFormat的初始化在後面介紹。隨後在參考代碼output_example.c中有一行:

snprintf(oc-filename,sizeof(oc->filename), “%s”, filename); (4)

還不是十分清楚有什麼作用,估計是先要在輸出文件中寫一些頭信息。 

 

在完成以上步驟後,(初始化完畢AVInputFormat*(或AVOutputFormat*)以及AVFormatContext)接下來就是要利用oc初始化本節開始講到的AVFormatContext中的第二個重要結構。AVStream(假設已經有了聲明AVStream *video_st。參考代碼用了一個函數來完成初始化,當然也可以在主函數中做,傳遞進函數的參數是ocfmt->video_codec(這個在下一節介紹(29)):

vdeo_st =add_video_stream(oc, fmt->video_codec); (5)

此函數會在後面講到AVStream結構時分析。

AVFormatContext最後的一個設置工作是:

if(av_set_paramters(oc,NULL) < 0){ (6)

//handle error;

}

dump_format(oc, 0,filename, 1); (7)

作用就是看看先前的初始化過程中設置的參數是否符合規範,否則將報錯。

上面講的都是初始化的過程,包括AVFormatContext本身的和利用AVFormatContext初始化其他數據結構的。接下來要講講整個的編解碼過程。我想先將ouput_example.cmain函數內的編解碼函數框架描述一下。這樣比較清晰,而且編碼者爲了結構清晰,在寫ouput_example.c的過程中也基本上在main函數中只保持AVFormatContextAVStream兩個數據結構

 

AVOutputFormat其實也在但是包含在AVFormatContext中了)。

// open video codecand allocate the necessary encode buffers

if(video_st)

open_video(oc,video_st); (8)

// write the streamheader, if any

av_write_header(oc);(9)

// encode anddecode process

for(; ;){

write_video_frame(oc,video_st); (10)

// breakcondition…here

}

//close codec

if(video_st)

close_video(oc,video_st); (11)

//write the trailer, if any

av_write_trailer(oc);(12)

// free the streams

for(i=0;i<oc->b_streams; i++){

av_freep(&oc->streams[i]->codec);(13)

av_freep(&oc->streams[i]);(14)

}

//close the ouputfile

if(!(fmt->flags& AVFMT_NOFILE)){

url_fclose(&oc->pb);(15)

}

av_free(oc); (16)

通過以上的一串代碼,就可以清晰地看出AVFormatContex* ocAVStream* video_st是在使用ffmpeg SDK開發時貫穿始終的兩個數據結構。以下,簡要介紹一下三個標爲紅色的函數,他們是參考代碼output_example.c開發者自行定義的函數。這樣可以使整個代碼結構清晰,當然你在使用ffmpeg SDK時也可以在主函數中完成對應的功能。在後面我們會專門針對這三個函 

數做分析。

1. open_video(oc,video_st);

此函數主要是對視頻編碼器(或解碼器)的初始化過程。初始化的數據結構爲AVCodec* codecAVCodecContext* c包括用到了的SDK函數有:

c = st->codec; 

codec =avcodec_find_encoder(c->codec_id); //編碼時,找編碼器 (17)

codec =avcodec_find_decoder(c->codec_id); //解碼時,找解碼器 (18)

 

AVCodecContex是結構AVStream中的一個數據結構,因此在AVStream初始化後(5)直接復值給c

// internal openvideo codec

avcodec_open(c,codec);(19)

// allocate videostream buffer

// AVFrame *picture

// uint8_t*video_outbuf

video_outbuf_size=200000;

video_outbuf =av_maloc(video_outbuf_size); (20)

// allocate videoframe buffer

picture =alloc_picture(c->pix_fmt, c->width, c->height); (21)

上述三步比較容易理解,打開視頻編解碼codec、分配輸出流緩存大小、分配每一幀圖像緩存大小。其中AVFrame也是ffmpeg中主要數據結構之一。這一步(8)是對編解碼器的初始化過程。

2.write_video_frame(AVFormatContext *oc, AVStream *st)

這個函數中做了真正的編解碼工作,其中的函數比較複雜先列出來慢慢分析。

用到的數據結構有AVCodecContext *c, SwsContext*img_convert_ctx。其中SwsContext是用來變換圖像格式的。比如yuv422變到yuv420等,當然也用到函數,見下面列表。

fill_yuv_image(tmp_picture,frame_count, c->width, c->height); (22)

sws_scale(img_convert_ctx,tmp_picture->, tmp_picture->linesize,

0, c->height,picture->data, picture->linesize); (23)

img_convert_ctx =sws_getContxt(c->width, c->height, PIX_FMT_YUV420P, (24)

c->width,c->heigth, c->pix_fmt, sws_flags, NULL, NULL, NULL);

 

由於參考代碼中做的是一個編碼。因此,它總是要求編碼器輸入的是yuv文件,而且是yuv420格式的。就會有了以上一些處理過程。接下來調用編碼器編碼,數據規則化(打包)用到AVPacket,這也是ffmpeg中一個比較不好理解的地方。

out_size =avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture); (25)

AVPacket pkt;

av_init_packet(&pkt);(26)

//……handle pktprocess, we will analyze later

ret =av_write_frame(oc, &pkt); (27)

encode就一定會有decode。而且ffmpeg專爲解碼而生,但是爲什麼在參考代碼中只用了encoder呢?個人猜想是因爲encode只是用yuv420來編碼,這樣的yuv420生成比較容易,要是用到解碼的化,還要在代碼中附帶一個其他格式的音視頻文件。在源代碼libavcodec文件夾中有一個apiexample.c的參考代碼,其中就做了編解碼。有空的化我會分析一下。

3.close_video(AVFormatContext *oc, AVStream *st)

avcodec_close(st->codec);

av_free(picture->data[0]);

av_free(picture);

av_free(video_outbuf);

 

比較容易理解,不多說了。

以上一大段雖然名爲介紹AVFormatContext。但基本上把ouput_example.c的視頻編碼部分的框架走了一遍,其一是想說明結構AVFormatContext的重要性,另一方面也是希望對使用FFMpeg SDK開發者有一個大致的框架。

其實,真正的一些編碼函數,內存分配函數在SDK中都已經封裝好了,只要搞清楚結構就能用了。而開發者要做的就是一些初始化的過程,基本上就是針對數據結構1的初始化。 

 

II. AVOutputFormat

雖然簡單(初始化)但是十分重要,他是編解碼器將要使用哪個codec指示。在其成員數據中最重要的就是關於視頻

 

codec的了:enum CodecID video_codec;

AVOutputFormat*fmt;

fmt =guess_format(NULL, filename, NULL); (28)

根據filename來判斷文件格式,同時也初始化了用什麼編碼器。當然,如果是用AVInputFormat *fmt的化,就是fix用什麼解碼器。(指定輸出序列->fix編碼器,指定輸入序列->fix解碼器?)

III. AVStream

AVStream作爲繼AVFormatContext後第二個貫穿始終的結構是有其理由的。他的成員數據中有AVCodecContext這基本的上是對所使用的Video Codec的參數進行設定的(包括bit rate、分辨率等重要信息)。同時作爲“Stream”,它包含了

 

這個概念中的一些數據,比如:幀率(r_frame_rate)、基本時間計量單位(time_base)、(需要編解碼的)首幀位置(start_time)、持續時間(duration)、幀數(nb_frames)以及一些ip信息。當然後面的這些信息中有些不是必須要初

 

始化的,但是AVCodecContex是一定要初始化的,而且就是作爲初始化AVStream最重要的一個部分。我們在前面就談到了AVStream的初始化函數(5),現在來看看他是怎麼做的:

// declaration

AVStream *video_st;

video_st =add_video_stream(oc, fmt->video_codec);

static AVStream*add_video_stream(AVFormatContex *oc, int codec_id){ (29)

AVCodecContext *c;// member of AVStream, which will be initialized here

AVStream *st; //temporary data, will be returned

st = av_new_stream(oc,0); (30)

c = st->codec;

// 以下基本是針對c的初始化過程。包括比特率、分辨率、GOP大小等。

……

// 以下的兩行需要注意一下,特別是使用MP4

if(!strcmp(oc->oformat->name,“mp4”) || !strcmp(oc->oformat->name, “mov”) ||!strcmp(oc->oformat->name, “3gp”))

c->flags |=CODEC_FLAG_GLOBAL_HEADER;

// st傳給video_st;

return st;

}

以上代碼中,有幾點需要注意的。一個是(30)c = st->codec是一定要做的,當然這是編程中最基本的問題,(30)是將st這個AVSteam綁定到AVFormatContext* oc上。後面的c = st->codec是將c綁定到stAVCodecContext上。其二是對c的初始化過程中,ouput_example.c裏做的是一些基本的配置,當然作爲使用者的你還希望對codec加入其他的一些編解碼的條件。

 可以參考avcodec.h裏關於AVCodecContext結構的介紹,註釋比較詳細的。關於AVStream的使用在前面介紹AVFormatContext時已有所涉及,在主函數中三個編解碼函數中(8)(10)(11)中。觀察相關的代碼,可以發現主要還是將AVStream中的AVCodecContext提取出來,再從中提取出AVCodec結構如在(8)中:

// open_video(oc,video_st);

// AVFormatContext*oc, AVStream *st

AVCodec *codec;

AVCodecContext *c;

c = st->codec;

codec =avcodec_find_encoder(c->codec_id); (31)

// open the codec

avcodec_open(c,codec); (32) 

 

同樣,我們可以看到在(10)(write_video_frame())AVFrame也是做爲傳遞AVCodecContext結構的載體而存在。(11

 

(close_video())比較簡單,不熬述。

IV. AVCodecContext

此結構在Ffmpeg SDK中的註釋是:main external apistructure其重要性可見一斑。而且在avcodec它的定義處,對其每個成員變量,都給出了十分詳細的介紹。應該說AVCodecContext的初始化是Codec使用中最重要的一環。雖然在前面的AVStream中已經有所提及,但是這裏還是要在說一遍。AVCodecContext作爲Avstream的一個成員結構,必須要在Avstream初始化後(30)再對其初始化(AVStream的初始化用到AVFormatContex)。雖然成員變量比較多,但是這裏只說一下在output_example.c中用到了,其他的請查閱avcodec.h文件中介紹。

// static AVStream*add_video_stream(AVFormatContext *oc, int codec_id)

AVCodecContext *c;

st =av_new_stream(oc, 0);

c = st->codec;

c->codec_id =codec_id;

c->codec_type =CODEC_TYPE_VIDEO;

c->bit_rate =400000; // 400 kbits/s

c->width = 352;

c->height = 288;// CIF

// 幀率做分母,秒做分子,那麼time_base也就是一幀所用時間。(時間基!)

c->time_base.den= STREAM_FRAME_RATE;

c->time_base.num= 1;

c->gop_size =12;

// here define:

// #defineSTREAM_PIX_FMT PIX_FMT_YUV420P

// pixel format,see PIX_FMT_xxx

// -encoding: setby user.

// -decoding: setby lavc.

c->pix_fmt =STREAM_PIX_FMT;

除了以上列出了的。還有諸如指定運動估計算法的: me_method。量化參數、最大b幀數:max_b_frames。碼率控制的參數、差錯掩蓋error_concealment、模式判斷模式:mb_decision (這個參數蠻有意思的,可以看看avcodec.h 1566)Lagrange multipler參數:lmin & lmax 宏塊級Lagrange multipler參數:mb_lmin & mb_lmaxconstant quantization parameterrate control method: cqp等。值得一提的是在AVCodecContext中有兩個成員數據結構:AVCodecAVFrameAVCodec記錄了所要使用的Codec信息並且含有

5個函數:initencoderclosedecodeflush來完成編解碼工作(參見avcode.h 2072行)。AVFrame中主要是包含了編碼後的幀信息,包括本幀是否是key frame*data[4]定義的YCbCr信息等,隨後詳細介紹。

初始化後,可以說AVCodecContext(8)&(10)中大顯身手。先在(8)open_video()中初始化AVCodec *codec以及AVFrame*

picture

// AVCodecContext*c;

codec =avcodec_find_encoder(c->codec_id);

……

picture =alloc_picture(PIX_FMT_YUV420P, c->width, c->height);

後在writer_video_frame(AVFormatContext*oc, AVStream *st)中作爲一個編解碼器的主要參數被利用:

AVCodecContext *c;

c = st->codec;

……

out_size =avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture);

VAVCodec

結構AVCodec中成員變量和成員函數比較少,但是很重要。他包含了CodecID,也就是用哪個Codec  像素格式信息。還有前面提到過的5個函數(initencodeclosedecoderflush)。順便提一下,雖然在參考代碼output_example.c中的編碼函數用的是avcodec_encode_video(),我懷疑在其中就是調用了AVCodecencode函數,他們傳遞的參數和返回值都是一致的,當然還沒有得到確認,有興趣可以看看ffmpeg源代碼。在參考代碼中,AVCodec的初始化後的使用都是依附於AVCodecContex,前者是後者的成員。在AVCodecContext初始化後(add_video_stream()),AVCodec也就能很好的初始化了:

//初始化

codec =avcodec_find_encoder(c->codec_id); (33)

//打開Codec

avcodec_openc, codec (34)

VI. AVFrame

AVFrame是個很有意思的結構,它本身是這樣定義的:

typedef structAVFrame {

FF_COMMON_FRAME

}AVFrame;

其中,FF_COMMON_FRAME是以一個宏出現的。由於在編解碼過程中AVFrame中的數據是要經常存取的。爲了加速,要採取這樣的代碼手段。

AVFrame是作爲一個描述原始圖像(也就是YUV或是RGB…還有其他的嗎?)的結構,他的頭兩個成員數據,uint8_t

*data[4]int linesize[4],第一個存放的是YCbCryuv格式),linesize是啥?由這兩個數據還能提取處另外一個數據結構:

typedef struct AVPicture{

uint8_t *data[4];

int linesize[4]; //number of bytes per line

}AVPicture ;

此外,AVFrame還含有其他一些成員數據,比如。是否key_frame、已編碼圖像書coded_picture_number、是否作爲參考幀reference、宏塊類型 *mb_type等等(avcodec.h 446行)。

AVFrame的初始化並沒有他結構上看上去的那麼簡單。由於AVFrame還有一個承載圖像數據的任務(data[4])因此,對他分配內存應該要小心完成。output_example.c中提供了alloc_picute()來完成這項工作。參考代碼中定義了兩個全局變量:

AVFrame *picture*tmp_picture。(如果使用yuv420格式的那麼只用到前一個數據picture就行了,將圖像信息放入picture中。如果是其他格式,那麼先要將yuv420格式初始化後放到tmp_picture中在轉到需求格式放入picture中。)在open_video()打開編解碼器後初始化AVFrame

picture =alloc_picture(c->pix_fmt, c->width, c->height);

tmp_picture =alloc_picture(PIX_FMT_YUV420P, c->width, c->height);

static AVFrame*alloc_picture(int pix_fmt, int width, int height){

AVFrame *picture;

uint8_t*picture_buf; // think about why use uint8_t? a byte!

picture =avcodec_alloc_frame(); (35)

if(!picture)

return NULL;

size =avpicture_get_size(pix_fmt, width, height); (36)

picture_buf =av_malloc(size); (37)

if(!picture_buf){

av_free(picture);(38)

return NULL;

}

avpicture_fill ( (AVPicture*)picture, picture_buf, pix_fmt, width, height); (39)

return picture;

}

從以上代碼可以看出,完成對一個AVFrame的初始化(其實也就是內存分配),基本上是有這樣一個固定模式的。至於(35)(39)分別完成了那些工作,以及爲什麼有這樣兩步,還沒有搞清楚,需要看原代碼。我的猜測是(35)AVFrame做了基本的內存分配,保留了對可以提取出AVPicture的前兩個數據的內存分配到(39)來完成。說到這裏,我們觀察到在(39)中有一個(AVPicture *)pictureAVPicture這個結構也很有用。基本上他的大小也就是要在網絡上傳輸的包大小,我們在後面可以看到AVPacketAVPicture有密切的關係。 

 

VIIAVPicture

AVPicture在參考代碼中沒有自己本身的申明和初始化過程。出現了的兩次都是作爲強制類型轉換由AVFrame中提取出來的:

// open_video()

avpicture_fill((AVPicture*)picture, picture_buf, pix_fmt, width, height); (40)

//write_video_frame

// AVPacket pkt;

if(oc->oformat->flags& AVFMT_RAWPICTURE){

……

pkt.size =sizeof(AVPicture); (41)

}

(40)中,實際上是對AVFramedata[4]linesize[4]分配內存。由於這兩個數據大小如何分配確實需要有pix_fmtwidthheight來確定。如果輸出文件格式就是RAW圖片(如YUVRGB),AVPacket作爲將編碼後數據寫入文件的基本數據單元,他的單元大小、數據都是由AVPacket來的。總結起來就是,AVPicture的存在有以下原因,AVPicturePicture的概念從Frame中提取出來,就只由Picture(圖片)本身的信息,亮度、色度和行大小。而Frame還有如是否是key frame之類的信息。這樣的類似分級是整個概念更加清晰。

VIIIAVPacket

AVPacket的存在是作爲寫入文件的基本單元而存在的。我們可能會認爲直接把編碼後的比特流寫入文件不就可以了,爲什麼還要麻煩設置一個AVPacket結構。在我看來這樣的編碼設置是十分有必要的,特別是在做視頻實時傳輸,同步、邊界問題可以通過AVPacket來解決。AVPacket的成員數據有兩個時間戳、數據data(通常是編碼後數據)、大小size等等(參見avformat.h 48行)。講AVPacket的用法就不得不提到編解碼函數,因爲AVPacket的好些信息只有在編解碼後才能的知。在參考代碼中(ouput_example.c362394行),做的一個判斷分支。如果輸出文件格式是RAW圖像(即YUVRGB)那麼就沒有編碼函數,直接寫入文件(因爲程序本身生成一個YUV文件),這裏的代碼雖然在此看來沒什麼價值,但是如果是解碼函數解出yuv文件(或rgb)那麼基本的寫文件操作就是這樣的:

if(oc->oformat->flags& AVFMT_RAWPICTURE) {

AVPacket pkt; // 這裏沒有用指針!

av_init_packet(&pkt);

pkt.flags |=PKT_FLAG_KEY // raw picture 中,每幀都是key frame?

pkt.stream_index =st->index;

pkt.data = (uint8_t*)picture;

pkt.size =sizeof(AVPicture);

ret =av_write_frame(oc, &pkt);

}

輸出非raw picture,編碼後:

else{

// video_outbuf& video_outbuf_sizeopen_video()中初始化

out_size =avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture); (42)

if(out_size >0){

AVPacket pkt;

av_init_packet(&pkt);(43)

pkt.pts=av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);(44)

if(c->coded_frame->key_frame)

pkt.flags |=PKT_FLAG_KEY;

pkt.stream_index=st->index;

pkt.data=video_outbuf;

pkt.size=out_size; 

 

/* write thecompressed frame in the media file */

ret =av_write_frame(oc, &pkt); (45)

} else {

ret = 0;

}

if (ret != 0) {

fprintf(stderr,"Error while writing video frame\n");

exit(1);

}

其中video_outbufvideo_outbuf_sizeopen_video()裏的初始化是這樣的:

video_outbuf =NULL;

// 輸出不是raw picture,而確實用到編碼codec

if(!(oc->oformat->flags & AVFMT_RAWPICTURE)){

video_outbuf_size =200000;

video_outbuf =av_malloc(video_outbuf_size);

}

(43)AVPacket結構的初始化函數。(44)比較難理解,而且爲什麼會有這樣的一些時間戳我也沒有搞明白。其他的AVPacket成員數據的賦值比較容易理解,要注意的是video_outbufvideo_outbuf_size的初始化問題,由於在參考代碼中初始化和使用不在同一函數中,所以比較容易忽視。(45)是寫文件函數,AVFormatContext* oc中含有文件名等信息,返回值ret因該是一共寫了多少數據信息,如果返回0則說明寫失敗。(42)(45)作爲比較重要的SDK函數,後面還會介紹的。.

IX. Conclusion

以上分析了FFMpeg中比較重要的數據結構。下面的這個生成關係理一下思路:(->表示派生出)

AVFormatContext->AVStream->AVCodecContext->AVCodec

|

AVOutputFormat orAVInputFormat

AVFrame->AVPicture….>AVPacket

二.FFMpeg 中的函數:

在前一部分的分析中我們已經看到FFMpeg SDK提供了許多初始化函數和編碼函數。我們要做的就是對主要數據結構正確的初始化,以及正確使用相應的編解碼函數以及讀寫(I/O)操作函數。作爲一個整體化的代碼SDKFFMpeg有一些他自己的標準化使用過程。比如函數av_register_all();就是一個最開始就該調用的註冊函數,他初始化了libavcodec註冊了所有的的codec和視頻文件格式(format)。下面,我沿着參考代碼(ouput_example.c)的脈絡,介紹一下相關函數。

 

/******************************************************************

main()

******************************************************************/

1. av_register_all();

usage: initializeibavcoded, and register all codecs and formats

每個使用FFMpeg SDK的工程都必須調用的函數。進行codecformat的註冊,然後才能使用。聲明在allformats.c中,都是宏有興趣看看。

2. AVOutputFormatguess_format(const char *short_name, const char *filename, const char*mime_type)

usage: 通過文件後綴名,猜測文件格式,其實也就是要判斷使用什麼編碼器(or解碼器)。

AVOutputFormat *fmt

fmt =guess_format(NULL, filename, NULL);

3. AVFormatContext*av_alloc_format_context(void) 

 

usage: allocate theoutput media context.實際是初始化AVFormatContext的成員數據AVClass

AVFormatContext*ic;

ic->av_class =&av_format_context_class;

//where

// format_to_name,options are pointer to function

static const AVClassav_format_context_class = {“AVFormatContext”, format_to_name, options};

4. static AVStream*add_video_stream(AVFormatContext *ox, int codec_id);

AVStream *video_st;

video_st =add_video_stream(oc, fmt->video_codec);

5. intav_set_parameters(AVFormatContext *s, AVFormatParameters *ap)

usage: set theoutput parameters (must be done even if no parameters).

AVFormatContext*oc;

// if failed,return integer smaller than zero

av_set_parameters(oc,NULL);

6. voiddump_format(AVFormatContext *ic, int index, const char *url, int is_output);

usage: 這一步會用有效的信息把 AVFormatContext的流域(streams field)填滿。作爲一個可調試的診斷,我們會將這些信息全盤輸出到標準錯誤輸出中,不過你在一個應用程序的產品中並不用這麼做:

dump_format(oc, 0,filename, 1); // 也就是指明AVFormatContext中的事AVOutputFormat,還是 // AVInputFormat

7. static voidopen_video(AVFormatContext *oc, AVStream *st)

open_video(oc,video_st);

8. intav_write_header(AVFormatContext *s)

usage: allocate thestream private data and writer the stream header to an output media file. params media

file

handle, return 0 ifOK, AVERROR_xxx if error.

write the streamheader, if any

av_write_header(oc);

9. static voidwrite_video_frame(AVFormatContext *oc, AVStream *st)

write_video_frame(oc,video_st);

10. static voidclose_video(AVFormatContext *oc, AVStream *st)

// close each codec

close_video(oc,video_st);

11. intav_write_trailer(AVFormatContext *s)

usage: write thetrailer, if any. Write the stream trailer to an output media file and free thefile private

data.

av_write_trailer(oc);

12. voidav_freep(void *arg)

usage: free thestreams. Frees memory and sets the pointer to NULL. arg pointer to the pointerwhich should

be freed .

av_freep(&oc->streams[i]->codec);

av_freeep(&oc->streams[s]); 

 

13. inturl_fclose(ByteIOContext *s);

usage: close theoutput file

url_fclose(&oc->pb);

14. voidav_free(void *ptr)

usage: free thestream. Free memory which has been allocated with av_malloc(z)() orav_realloc().

av_free(oc);

/******************************************************************

******************************************************************

add_video_stream()

AVCodecContext *c

AVStream *st

******************************************************************/

******************************************************************

1.AVStream *av_new_stream(AVFormatContext*s, int id)

usage: add a newstream to a media file. s: media file handle, id: file format dependent streamid

st =av_new_stream(oc, 0);

/******************************************************************

******************************************************************

open_video()

AVCodecContext *c

AVCodec *codec

AVFrame *picture,*tmp_picture

uint8_t*video_output

int frame_count,video_outbuf_size;

******************************************************************

******************************************************************/

1 AVCodec*avcodec_find_encoder(enum CodecID id)

usage: find thecodec of encoder by CodecID. 在前面main中的guess_format()就已經開始爲此準備了。

codec =avcodec_find_encoder(c->codec_id);

2 int avcodec_open(AVCodecContext*avctx, AVCodec *codec);

usage: opens /inits the AVCodecContext. 打開失敗的話,返回值小於零。

avcodec_open(c,codec);

3 void*av_malloc(unsigned in size);

usage: you canredefine av_malloc and av_free in your project to use your memory allocator.You do not need

to suppress thisfile because the linker will do it automatically

Memory allocationof size byte with alignment suitable for all memory accesses (including vectorsif

available on theCPU). av_malloc(0) must return a non NULL pointer.

video_outbuf_size =200000;

video_outbuf =avmalloc(video_outbuf_size);

4 static AVFrame*alloc_picture(int pix_fmt, int width, int height)

picture =alloc_picture(c->pix_fmt, c->width, c->height); 

 

/******************************************************************

******************************************************************

******************************************************************

alloc_picture()

AVFrame *picture

uint8_t*picture_buf

int size

******************************************************************

******************************************************************/

******************************************************************

1.avcodec_alloc_frame()

 

usage: initializeAVFrame* picture

picture = avcodec_alloc_frame()

2. intavpicture_get_size(int pix_fmt, int width, int height)

 

usage: 根據像素格式和視頻分辨率獲得picture存儲大小。

size =avpicture_get_size(pix_fmt, width, height);

picture_buf =av_malloc(size)

3. intavpicture_fill(AVPicture *picture, uint8_t *ptr, int pix_fmt, int width, intheight)

 

usage: Picturefield are filled with ‘ptr’ addresses, also return size。用ptr中的內容根據文件格式(YUV…

和分辨率填充picture。這裏由於是在初始化階段,所以填充的可能全是零。

avpicture_fill((AVPicture*)picture,picture_buf, pix_fmt, width, height);

/******************************************************************

******************************************************************

write_video_frame()

int out_size, ret;

AVCodecContext *c;

static structSwsContext *img_convert_ctx

******************************************************************

******************************************************************/

1 struct SwsContext*sws_getContext(int srcW, ……)

usage: 轉變raw picture格式的獲取context函數,比如下面的代碼就是將其他格式的(如yuv422)轉爲yuv420,就要將

context 保存在img_convert_ctx中,然後再利用後面的介紹函數做轉化。

img_convert_ctx =sws_getContext(c->width, c->height,

PIX_FMT_YUV420P,

c->width,c->height,

c->pix_fmt,

sws_flags, NULL,NULL, NULL);

2 intsws_scale(struct SwsContext *ctx, uing8_t* src[], int srcStride[], intsrcSliceY, int srcSliceH,

uint8_t* dst[], intdstStride[]);

usage: 根據SwsContext保存的目標文件contextsrcsource)轉爲dst(destination)

sws_scale(img_convert_ctx,tmp_picture->data, tmp_picture->linesize, 0, c->height,picture->data, picture-

>linesize);

4. intavcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size, constAVFrame *pict);

 

usage: 根據AVCodecContextpict編碼到buf中,buf_sizebuf的大小。 

 

out_size =avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture);

5 static inlinevoid av_init_packet(AVPacket *pkt)

usage: initializeoptional fields of a packet.初始化AVPacket

AVPacket pkt;

av_init_packet(&pkt)

6 int64_tav_rescale_q(int64_t a, AVRational bq, AVRational cq)

 

usage: 校準時間基(maybe

pkt.pts =av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);

7 intav_write_frame(AVFormatContext *s, AVPacket *pkt)

 

usage: write apacket to an output media file . pkt: the packet, which contains thestream_index,

buf/buf_size,dts/pts, …if error return<0, if OK =0, if end of stream wanted =1

ret =av_write_frame(oc, &pke);

/******************************************************************

******************************************************************

static voidclose_video(AVFormatContext *oc, AVStream *st)

{

avcodec_close(st->codec);

av_free(picture->data[0]);

av_free(picture);

if (tmp_picture) {

av_free(tmp_picture->data[0]);

av_free(tmp_picture);

}

av_free(video_outbuf);

}

/******************************************************************

******************************************************************

講初始化過的,特別是分配過內存的,都要釋放。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章