(長(zhǎng)江大學(xué) 湖北 荊州 434023)
Ffmpeg是一套可以用來(lái)記錄、轉(zhuǎn)換數(shù)字音頻、視頻,并能將其轉(zhuǎn)化為流的開(kāi)源計(jì)算機(jī)程序。它提供了一套完整的音視頻解決方案,可以實(shí)現(xiàn)音視頻的轉(zhuǎn)碼、裁剪、拼接、縮放、旋轉(zhuǎn)、圖層的疊加等功能,唯一的缺點(diǎn)是其libavcodec編解碼庫(kù)在移植到Android平臺(tái)后,只支持軟編碼,兼容性很好,但不支持Android的MediaCodec硬編碼,所以編碼效率比較低。
交叉編譯是在一個(gè)平臺(tái)(windows)生成另一個(gè)平臺(tái)(Android)的可執(zhí)行代碼。由于ffmpeg是用c語(yǔ)言開(kāi)發(fā)的,不能直接運(yùn)行在Android系統(tǒng)中,所以需要編譯成Android可以執(zhí)行的代碼庫(kù)。通常是在windows下安裝Linux虛擬機(jī),編寫(xiě)shell腳本,修改ffmpeg配置文件,最后編譯生成so庫(kù)。編譯成功后會(huì)生成幾個(gè)so文件。libavcodec.so提供了一系列編碼器的實(shí)現(xiàn)。
libavformat.so實(shí)現(xiàn)了流協(xié)議,容器格式及其IO訪問(wèn)。
libavutil.so包含了各種工具函數(shù),命令入口也從這里開(kāi)始。
libavfilter.so提供了各種音視頻過(guò)濾器。
libavdevice.so提供了訪問(wèn)捕獲設(shè)備和回放設(shè)備的接口。
libswresample.so實(shí)現(xiàn)了混音和重采樣。
libswscale.so實(shí)現(xiàn)了色彩轉(zhuǎn)換和縮放功能。
OpenGL ES(OpenGL for Embedded Systems)是OpenGL(Open Graphics Library)三維圖形API的一個(gè)子集。OpenGL ES是為移動(dòng)設(shè)備而設(shè)計(jì)出來(lái)的,通過(guò)它可以直接調(diào)用GPU來(lái)進(jìn)行繪圖,效率很高性能很好。并且Android系統(tǒng)中是自帶OpenGL的,不需要像ffmpeg那樣必須要通過(guò)交叉編譯引入進(jìn)來(lái),我們可以直接通過(guò)Android提供的api來(lái)調(diào)用OpenGL。
MediaCodec是Android自帶一個(gè)庫(kù),可用于對(duì)視頻進(jìn)行編解碼。MediaCodec可以通過(guò)createInputSurface創(chuàng)建一個(gè)Surface,然后OpenGL將數(shù)據(jù)渲染到這個(gè)Surface上,這樣MediaCodec就可以對(duì)得到的視頻數(shù)據(jù)進(jìn)行編碼了,編碼后在通過(guò)MediaMuxer對(duì)其封裝成Mp4。在Android音視頻開(kāi)發(fā)中,通常使用OpenGL ES來(lái)繪制視頻,然后配合MediaCodec來(lái)對(duì)OpenGL進(jìn)行硬編碼生成視頻。
何為Canny邊緣檢測(cè)?
Canny邊緣檢測(cè)算法是一個(gè)多級(jí)邊緣檢測(cè)算法。Canny算法經(jīng)過(guò)多年的發(fā)展,已經(jīng)成為邊緣檢測(cè)的一種標(biāo)準(zhǔn)算法,性能和效果都比較優(yōu)化,在實(shí)際中被廣泛應(yīng)用。
Canny邊緣檢測(cè)主要的思想如下:1.應(yīng)用高斯濾波來(lái)平滑圖像,目的是去除噪聲;2.找尋圖像的強(qiáng)度梯度(intensity gradients);3.利于非最大抑制技術(shù)來(lái)消除邊緣誤檢;4.通過(guò)兩個(gè)閾值low和high來(lái)確定出邊緣;5.利用滯后技術(shù)來(lái)跟蹤邊界。
FFmpeg中已經(jīng)封裝好了Canny邊緣檢測(cè)算法,所以通過(guò)ffmpeg來(lái)調(diào)用邊緣檢測(cè)就方便很多了。
例如:ffmpeg-i input.png-vf edgedetect=low=0.1:high=0.4:mode=wires-frames:v 1-y edge.png

其中有幾個(gè)參數(shù)”-i input.png”代表輸入文件,”-vf edgedetect=low=0.1:high=0.4:mode=wires”代表使用邊緣檢測(cè)濾鏡,”-frames:v 1”代表從視頻中提取一幀,可以適用于一些動(dòng)態(tài)圖的情況,”-y edge.png代表”生成文件并強(qiáng)制覆蓋。其中關(guān)于edgedetect的參數(shù)有3個(gè)分別是low、high、mode。其中l(wèi)ow和high代表設(shè)置Canny閾值算法中的低閾值和高閾值。必須在[0,1]范圍內(nèi)選擇低閾值和高閾值,低閾值應(yīng)小于或等于高閾值。高閾值代表強(qiáng)邊緣像素,低閾值代表弱邊緣像素,然后通過(guò)八連通性將這些點(diǎn)相連。四連通區(qū)域是11011其中0代表中心點(diǎn),4個(gè)1代表上下左右四個(gè)方向。八連通區(qū)域是111101111也就是除了上下左右四個(gè)方向外,還有左上、右上、左下、右下。關(guān)于mode繪圖模式,例如wires代表生成黑白圖,colormix代表生成油畫(huà)卡通效果圖。
關(guān)于深度優(yōu)先遍歷算法的思想如下:
1.訪問(wèn)頂點(diǎn)v;
2.依次從v的未被訪問(wèn)的鄰接點(diǎn)出發(fā),對(duì)圖進(jìn)行深度優(yōu)先遍歷;直至圖中和v有路徑相通的頂點(diǎn)都被訪問(wèn);
3.若此時(shí)圖中尚有頂點(diǎn)未被訪問(wèn),則從一個(gè)未被訪問(wèn)的頂點(diǎn)出發(fā),重新進(jìn)行深度優(yōu)先遍歷,直到圖中所有頂點(diǎn)均被訪問(wèn)過(guò)為止。
通過(guò)Canny邊緣檢測(cè)可以得到一個(gè)二值化的圖像,背景是黑色,輪廓是白色的圖片。這時(shí)需要使用深度優(yōu)先遍歷得到這個(gè)圖片上所有白色的點(diǎn)。
定義圖片的左上角為(1,1)右下角為(width,height)。首先對(duì)這個(gè)圖片進(jìn)行從左到右,從上到下遍歷,直到找到一個(gè)白色點(diǎn),然后從這個(gè)白色的點(diǎn)開(kāi)始,采用八連通規(guī)則依次判斷周?chē)狞c(diǎn),同一個(gè)點(diǎn)只需要添加一次即可。最終得到深度優(yōu)先遍歷的點(diǎn)陣序列。
在Android中棧的最大內(nèi)存大小為1024KB,這里需要存儲(chǔ)大量的點(diǎn)陣數(shù)據(jù),如果棧空間不足會(huì)報(bào)錯(cuò)StackOverflowError,所以這里存儲(chǔ)坐標(biāo)的點(diǎn)陣時(shí)使用short類(lèi)型即可。另外還需要控制點(diǎn)陣存儲(chǔ)的最大數(shù)量限制以防止棧溢出。
方案一:使用FFmpeg軟編碼,速度慢但是兼容性好。實(shí)現(xiàn)思路是,在得到點(diǎn)陣序列后,依次將每一幀的序列生成Bitmap并保存成實(shí)際圖片在磁盤(pán)上。接下來(lái)調(diào)用FFmpeg命令對(duì)這每一幀圖片進(jìn)行處理生成視頻。例如:ffmpeg-framerate 30-i image-%03d.png-c:v libx264-y out.mp4 即可將一個(gè)圖片序列生成視頻。其中,-framerate 30控制輸入幀率為每秒30幀,-i image-%03d.png輸入一個(gè)圖片序列可以匹配image-001到image-999之間的所有圖片,-c:v libx264指定使用libx264庫(kù)進(jìn)行編碼。
方案二:直接將幀序列繪制到OpenGL的GlSurfaceView上,同時(shí)使用MediaCodec對(duì)GlSurfaceView進(jìn)行錄制,這種方案既滿足的實(shí)時(shí)預(yù)覽的需要,又可以快速的合成視頻。