近期由於工作任務,需要開發一個跨平台視頻聊天系統,其中就用到了ffmpeg進行采集與編碼,網上找了一大堆的資料,雖然都有一些有用的東西,但實在太碎片化了,這幾天一直在整理和實驗這些資料,邊整理,邊做一個總結,今天先總結一下采集的步驟,我是在linux平台下進行試驗的,操作系統是ubuntu13.04 64bit,ffmpeg的版本是2.0.1,采用C語言開發,我的目標是從攝像頭采集到1幀視頻,然后用容器輸出這幀的圖像並把圖像保存為bmp文件。整個采集的步驟是:連接視頻源->獲取視頻流->demux(解復用)視頻格式->匹配解碼器->解碼->轉換->輸出,這個是步驟的概述,下面針對ffmpeg的具體操作逐一進行一個講解:
連接視頻源
使用av_find_input_format函數連接v4l2(video4linux2)攝像頭設備,大部分的攝像頭設備在Linux下都是v4l2類型的,這個函數返回AVInputFromat*類型的數據。
我的代碼:AVInputFormat *inputFmt=av_find_input_format("video4linux2");
獲取視頻流
使用avformat_open_input函數打開上一步驟的攝像頭設備獲取視頻流.
我的代碼:avformat_open_input(&fmtCtx,"/dev/video0",inputFmt,NULL);
代碼備注:fmtCtx是一個AVFormatContext*對象,是一個視頻格式處理的上下文對象,很重要,里面有這個采集的視頻的元數據,"/dev/video0"是攝像頭的映射路徑,這部分是Linux基礎,不是本文的重點,inputFmt就是第一步得到的AVInputFormat*對象,inputFmt不是必須的參數,NULL也可以,如果是NULL,則會自動檢測。
demux(解復用)視頻格式
fmtCtx里面包含了采集到的視頻流的視頻格式,如果是攝像頭的話,應該是RAWVIDEO類型的數據,codec_id=14。
我的代碼:fmtCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO
代碼備注:fmtCtx->streams實際上是一個二維數組或數組指針,因為fmtCtx->streams數組內每一個元素都指向一個一維數組,每一個一維數組都有可能有數據,比如音頻、視頻、字幕等,因此這里的理想處理方式應該是用一個循環匹配每一個的fmtCtx->streams,因為我們這里只關心視頻,因此我們只需要匹配codec_type==AVMEDIA_TYPE_VIDEO的數據就可以了。
匹配解碼器
既然上一步已經經過解復用知道了視頻流的格式是RAWVIDEO類型了,接下來要做的就是找到對應的解碼器進行解碼了,這里用到了函數avcodec_find_decoder,返回AVCodec*類型數據,就是一個解碼器對象。
我的代碼:avcodec_find_decoder(fmtCtx->streams[i]->codec->codec_id)
以下部分開始暫時我自己代碼還沒完成,完成后會貼上來,所以我只是會說明以下采用哪些函數,至於函數怎么用我暫時不提供,大家可以等待我近期更新或自行去ffmpeg官網開api documentation
解碼
所謂解碼,就是用上一步得到的解碼器打開視頻流幀(幀是視頻的最小單位),這里用到函數是av_read_frame與avcodec_decode_video2,av_read_frame從視頻流中讀取一幀,但這個函數返回的不是幀對象AVFrame*,而是Packet對象AVPacket,要經過avcodec_decode_video2這個解碼函數才能得到AVFrame*對象,這里說明一下,AVPacket最多可能包含一個幀,而一個AVFrame可能會包含很多個AVPacket,二者的區別請讀者請自行Google,以后我也許會專門開篇說明。
我的代碼:有點復雜,稍后我整理好貼上來
轉換
經過解碼后得到的是YUYV422格式的視頻幀,這種格式如果要進行網絡傳輸比如視頻聊天,要進行H264編碼,而H264編碼目前輸入源必須是YUV420格式的,YUYV422與YUV420格式間的轉換我后面會補上,我自己的代碼也剛寫到這個位置,我稍后確認代碼沒問題后會貼上來,這里暫且不討論網絡傳輸和H264部分,這里就討論怎么把YUYV422輸出到容器或者保存成圖片文件呢,要進行一次YUV格式到RGB24格式的轉換,采用函數sws_scale進行轉換。
輸出
到這步前,實際上我們已經得到了RGB24格式的數據了,接下來輸出分2種情況,一種是采用容器的方式輸出,這種方式的話可以直接把RGB24格式的數據源作為容器的輸入源即可了,比如IOS下可以采用UIIMAGEVIEW作為容器,還有一種是保存成bmp圖,以圖片的形式輸出,如果保存成bmp圖片的話,在C語言下不用任何第三方庫的前提下,需要自己建立bmp數據結構來生成bmp文件。