ffmpeg API 笔记:使用libavcodec/libavformat/libswscale ffmpeg例子
Update 2010.1.5: 其實研究ffmpeg不用找什么教程,第一步應該是下載ffmpeg的源碼包。下面提到的An FFmpeg and SDL Tutorial確實有講解,但是教程總是跟不上代碼的變化的,所以直接看可工作代碼最好;ffmpeg的結構很分明,后臺是幾個庫:libxxx,前臺是三個程序ffmpeg, ffplay, ffserver,那篇教程說的就是ffplay的實現。一個播放器,其實重點不是解碼,解碼的東西是lib去做的,主要是做聲音視頻的時鐘同步。ffplay的代碼可以說是一個可用播放器最簡單的實現了,源碼里面有個output_example.c,可以說是最基本的api示范吧。ffmpeg是轉換編碼解碼轉換程序,因為涉及重新采樣等等,所以代碼量也不少的。
這兩天"調研"了下ffmpeg的API,不得不承認被雷倒:ffmpeg又是一個很geek的項目,純社區開發,基于逆向,功能強大,但是文檔極度有限,想了解API?看源碼去…… 網上關于ffmpeg API的資料,無非是ffmpeg文檔里面的兩個鏈接,Using libavformat and libavcodec by
Martin B?hme(以及其Update,介紹了新引入的API)跟An FFmpeg and SDL Tutorial
by Stephen Dranger;兩個tutorial基于ffmpeg 0.4.8,現在ffmpeg發布的版本是0.5.0,好像數值相差不大,不過0.4.8是5年前的了(相比之下wine用了15年版本號才到達1.0,有過之余無不及),兩個教程里面的代碼在0.5.0下一編譯,哇,一堆錯誤,可不僅有些api函數變了,有些結構成員壓根就沒了,頭文件的位置更是不一樣(各個庫分家了)……所以我調試了好幾個小時,終于把例子的代碼弄好(其實Martin B?hme那篇有一段09年加入的更新說明,鏈接了有相關的解決辦法,我一開始沒注意,幾個小時自己解決,不過也有收獲)。
最后我調試好的代碼流程:打開一個視頻文件,抓取前5幀保存為文件;
【基于Stephen Dranger的Tutorial1】源碼在此:GoogleCode
用到的API就這么多,當然實際代碼稍復雜一點;ppm圖像是類似BMP的非壓縮格式,SaveFrame就是相當于把pFrameRGB的內存拷貝進文件,寫文件并不復雜;
調試過程的問題,首先是頭文件,ffmpeg 0.5.0的API已經拆分成好幾個獨立的庫,用pacman -Ql ffmpeg看了下文件分布,在include下好幾個目錄都是它的,看名字可以大概猜出他們的功能:
libavdevice:對輸出輸入設備的支持;
libavformat:對音頻視頻格式的解析
libavutil:集項工具;
libpostproc:后期效果處理;
libswscale:視頻場景比例縮放、色彩映射轉換;
?
修改好頭文件包含,終于少了些not declared錯誤;
Martin B?hme那篇教程的代碼是使用g++編譯的,雖然代碼是C風格;在我修改了頭文件以及一些錯誤之后,居然鏈接出錯,av_register_all什么的函數統統undefined reference,想到ffmpeg是純C實現,以及以前用g++編譯GTK出現回呼函數找不到的經歷,相信又是g++的function mangling搞的,Google了一下,解決方法是把幾個頭文件包含在exterc "C"里面。
代碼里面的錯誤還涉及一些結構成員的變化,比如
pFormatCtx->streams[i]->codec.codec_type==CODEC_TYPE_VIDEO就有個類型錯誤,因為0.5.0里面的codec已經是指針,而不是結構了,要把.換成->,而相應地獲得解碼器指針,不再需要&:
pCodecCtx=&pFormatCtx->streams[videoStream]->codec;原教程提到一個視頻碼率的rate的Hack:
// Hack to correct wrong frame rates that seem to be generated by some codecs<br /> if(pCodecCtx->frame_rate>1000 && pCodecCtx->frame_rate_base==1)<br /> pCodecCtx->frame_rate_base=1000;好吧現在frame_rate跟frame_rate_base壓根就沒了,去掉算了;
最麻煩的變化還是原代碼里面的img_convert,就是解碼出一個幀的數據后,需要轉換成RGB格式才能寫入文件,然而這個函數在0.5.0里面徹底沒了。嘗試把img_convert完全注釋掉,把原始幀img_convert寫入文件,還算可喜的是能夠看到圖形,只是被分成三個畫面的通道圖形罷了;
Google了一番,還是回到 Stephen Dranger的An FFmpeg and SDL Tutorial第八節,介紹了swscale的接口,雖然里面的例子是轉換成SDL所用的YUV,而不是RGB;注意到其使用的參數PIX_FMT_YUV420P,跟img_convert所用的PIX_FMT_RGB24有相同前序,就試試照樣花虎了;
給sws_getContext傳入源格式的H/W,格式,輸出格式的H/W,PIX_FMT_RGB24格式,其中有個參數flags的解釋是 specify which algorithm and options to use for rescaling,是選擇在縮放過程中是使用線性還是雙立方等算法(參數文檔沒說,要找看源碼去),這里照抄了例子里面的SWS_BICUBIC。獲得這個SwsContext,類似python的re.compile,再用這個轉換器去轉換每一個幀,所以后面每次解碼了幀后,調用sws_scale,跟原來的img_convert倒是挺像;
也就是說,以后如果需要對視頻進行4:3跟16:9的轉換,就是在sws_getContext的參數里面做設置了;
最后整個程序正常,會把視頻的前5幀抓成圖像了,只是會有個小警告:
?
估計是轉換成RGB,swscale里面沒有特別優化的算法?
目前發現程序運行的時候CPU占用很高,是因為程序還沒有控制幀速的時鐘,只會用盡CPU的性能不斷的讀取解碼;
PT修改過可編譯通過(ffmpeg 5.0/gcc 4.4.2/ubuntu 9.10)的前三個Tutorial代碼可在Google Code查看下載。(編譯方法請看各個文件頭部的注釋說明)
tags: ffmpeg, img_convert, libavcodec, libavformat, libswscale
posted in Programming by BOYPT
總結
以上是生活随笔為你收集整理的ffmpeg API 笔记:使用libavcodec/libavformat/libswscale ffmpeg例子的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: allegro16.3 中的orcad
- 下一篇: gdb中看内存(x命令)