FFMpeg SDK 開發手冊 1
FFMpeg SDK 開發手冊(1)[轉載] - [3DTV]
:轉載時請以超連結形式標明文章原始出處和作者資訊及本宣告
http://leezen.blogbus.com/logs/16084170.html
FFMpeg SDK 開發手冊
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()
以下就根據,以上資料結構及函式在ffmpeg測試程式碼output_example.c中出現的前後順進行分析。在此之前還是先談一下
ffmpeg的編譯問題。在linux下的編譯比較簡單,這裡不多說了。在windows下的編譯可以參考以下網頁:
%3D1
值得一提的是,在使用編譯後的sdk進行測試時(用到ffmpeg目錄下的output_example.c)編譯過程中可能會有以下兩個問
題:
1. Output_example.c用到了snprintf.h這個標頭檔案。然而這個標頭檔案在win下和linux下有所不同。具體在win下
可以用以下方法解決:
2. 如果使用vc6,或是vc6的命令列進行編譯,inline可能不認。錯誤會出現在common.h檔案中,可以在common.h中加入
#ifdef _MSC_VAR
#define inline __inline
#endif
交待完畢進入正題。
一.FFMpeg 中的資料結構:
I. AVFormatContext
一般在使用ffmpeg sdk的程式碼中AVFormatContext是一個貫穿始終的資料結構,很多函式都要用到它作為引數。FFmpeg程式碼
中對這個資料結構的註釋是:format I/O context
此結構包含了一個影片流的格式內容。其中存有了AVInputFormat(or AVOutputFormat同一時間AVFormatContext內只能存
在其中一個),和AVStream、AVPacket這幾個重要的資料結構以及一些其他的相關資訊,比如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* fmt或AVInputFormat* 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。參考程式碼中
用了一個函式來完成初始化,當然也可以在主函式中做,傳遞進函式的引數是oc 和fmt->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.c中main函式內的編解碼函式框架描述一下。這樣比較清晰,而且編碼者為了結
構清晰,在寫ouput_example.c的過程中也基本上在main函式中只保持AVFormatContext和AVStream兩個資料結構
(AVOutputFormat其實也在但是包含在AVFormatContext中了)。
// open video codec and allocate the necessary encode buffers
if(video_st)
open_video(oc, video_st); (8)
// write the stream header, if any
av_write_header(oc); (9)
// encode and decode process
for(; ;){
write_video_frame(oc, video_st); (10)
// break condition…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
av_freep(&oc->streams[i]->codec); (13)
av_freep(&oc->streams[i]); (14)
}
//close the ouput file
if(!(fmt->flags & AVFMT_NOFILE)){
url_fclose(&oc->pb); (15)
}
av_free(oc); (16)
透過以上的一串程式碼,就可以清晰地看出AVFormatContex* oc和AVStream* video_st是在使用ffmpeg SDK開發時貫穿始終的
兩個資料結構。以下,簡要介紹一下三個標為紅色的函式,他們是參考程式碼output_example.c開發者自行定義的函式。這樣
可以使整個程式碼結構清晰,當然你在使用ffmpeg SDK時也可以在主函式中完成對應的功能。在後面我們會專門針對這三個函
數做分析。
1. open_video(oc, video_st);
此函式主要是對影片編碼器(或解碼器)的初始化過程。初始化的資料結構為AVCodec* codec和AVCodecContext* 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 open video codec
avcodec_open(c,codec); (19)
// allocate video stream buffer
// AVFrame *picture
// uint8_t *video_outbuf
video_outbuf_size=200000;
video_outbuf = av_maloc(video_outbuf_size); (20)
// allocate video frame 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 pkt process, 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繫結到st的AVCodecContext上。其二是對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())比較簡單,不熬述。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24790158/viewspace-1040903/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MeterSphere開發者手冊
- [開發文件]bootstrap中文手冊boot
- Web 開發手冊——PHP 開發環境搭建WebPHP開發環境
- wxpython - 快速開發封裝手冊Python封裝
- 阿里Java開發手冊思考(三)阿里Java
- 阿里Java開發手冊思考(二)阿里Java
- 阿里Java開發手冊思考(一)阿里Java
- base業務框架開發手冊框架
- 阿里巴巴Java開發手冊阿里Java
- Web前端開發規範手冊Web前端
- TensorFlow開發者證書 中文手冊
- Java開發手冊精華總結Java
- MaxPHP(原Yao框架)完全開發手冊PHP框架
- 安卓開發開發規範手冊V1.0安卓
- 安卓開發開發規範手冊 V1.0安卓
- 阿里巴巴java開發手冊筆記阿里Java筆記
- Flutter開發者必備手冊 Flutter GoFlutterGo
- 阿里巴巴Java開發規範手冊阿里Java
- Qt 嵌入式圖形開發大全和QT開發手冊QT
- FFmpeg開發筆記(二十四)Linux環境給FFmpeg整合AV1的編解碼器筆記Linux
- 開發者手冊之如何成為 OceanBase Contributor
- javacv教程文件手冊開發指南匯總篇Java
- 純乾貨:微服務開發手冊之GRPC微服務RPC
- Web 安全開發規範手冊 V1.0Web
- Web安全開發規範手冊V1.0Web
- 《阿里巴巴 Java開發手冊》讀後感阿里Java
- 翻譯:man getopt(1)中文手冊
- 瑞芯微RK3288_Android9.0 SDK版本說明手冊Android
- 研發環境手冊
- 影片SDK開發,多平臺SDK快速接入
- 阿里巴巴Android開發手冊V1.0.0隨手筆記阿里Android筆記
- 君正x1000軟體開發指南手冊
- 唯品會Java開發手冊》1.0.2版閱讀Java
- F5 api介面開發實戰手冊(二)API
- 《碼出高效:Java開發手冊》背後的故事Java
- 阿里巴巴Java開發手冊閱讀筆記阿里Java筆記
- FFmpeg開發筆記(三十五)Windows環境給FFmpeg整合libsrt筆記Windows
- FFmpeg開發筆記(八)Linux交叉編譯Android的FFmpeg庫筆記Linux編譯Android
- Android 基於ffmpeg開發簡易播放器 - ffmpeg解封裝Android播放器封裝