最近開始在學習FFMPEG,準确點來講是FFMPEG for Android!也開始嘗試着寫部落格,主要是為了記錄自己的學習過程,和大家一起分享和探讨,共同進步。
在這裡,我會把自己遇到的一些坑提醒給大家,提高大家的學習效率。上文中我們已經在Linux環境下搭建好了FFMPEG開源庫的編譯環境,并且拿到了可以在Android上運作的動态庫,下面我們一起學習一個FFMPEG的簡單Demo,我把它叫做類'HelloWord'。程式猿癖好,喜歡把第一個程式叫做HelloWord!
建立一個Android工程
我覺得Android Studio運作起來比Eclipse慢,用起來也相對更熟悉,對于這種簡單的程式,還是喜歡用Eclipse+SDK環境編寫。如下圖,先建立了一個名為FFmpeg4Android的工程,這裡主要把它分為三塊,界面顯示及邏輯控制(MainActivity和activity_main.xml) 、 Native接口(FFmpegNative)和jni動态庫部分。工程目錄結構如下圖所示:
圖1-1 工程結構圖 代碼比較簡單,就不贅述了,相信有學習或開發過Android的都比較清楚,源碼後面也會給出,可以完整編譯運作。下面主要講下我們自己編寫的依賴FFMPEG開源庫的jni動态庫的編譯方法。
生成jni頭檔案
jni的函數聲明和定義是有一定規則的,函數名字都是以"JNIEXPORT 傳回類型 JNICALL Java_完整包名_類名_對應函數名"為規範的,不過Android Framework源碼裡面有另一套方法可以自定義函數名,有興趣的可以去看看,在開發應用的時候沒必要這麼去做,按照這種規則自動生成就好。 cmd進入到工程的bin/classes目錄下,執行javah -jni com.jacky.ffmpeg.jni.FFmpegNative就可以在目前目錄生成com_jacky_ffmpeg_jni_FFmpegNative.h頭檔案了,自動生成的頭檔案不需要做任何改動。
根據生成的jni頭檔案編寫.c或者.cpp檔案
可以先根據 .h檔案的結構快速的完成.c檔案結構的編寫,具體的實作代碼暫時忽略。簡單歸納了下: 建立與.h檔案字首同名的.c檔案; .c檔案include.h頭檔案; 複制.h檔案中的所有函數到.c檔案,并給函數參數加上變量名; 去掉函數後面分号,加花括号對,對于有傳回值得函數傳回預設值。 經過如上幾步,c檔案的結構就編寫完成了,然後可以逐漸完成各個接口函數的代碼編寫了。
編寫Android.mk檔案
編 譯獨立的jni庫相對要簡單些,下面幾行就可以了。
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg
LOCAL_SRC_FILES := com_jacky_ffmpeg_jni_FFmpegNative.c
include $(BUILD_SHARED_LIBRARY)
但是libffmpeg jni庫對FFMPEG的動态庫有依賴,這就要麻煩一些了,需要先PREBUILT所依賴的動态庫,如下
include $(CLEAR_VARS)
LOCAL_MODULE := avcodec
LOCAL_SRC_FILES := libavcodec-57.so
include $(PREBUILT_SHARED_LIBRARY)
然後在前面的基礎上加上LOCAL_SHARED_LIBRARIES,變成如下
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES := avcodec
LOCAL_MODULE := ffmpeg
LOCAL_SRC_FILES := com_jacky_ffmpeg_jni_FFmpegNative.c
include $(BUILD_SHARED_LIBRARY)
這裡簡單說明了有依賴第三方動态庫和無依賴的差別,以及mk檔案分别需要怎麼去編寫。完整代碼可以下載下傳,了解了這個應該就不會有什麼疑問了。
編寫Application.mk檔案(可選)
Application.mk中的APP_ABI設定了編譯後庫檔案支援的指令集,預設使用“armeabi”,APP_ABI取值為“all”則會編譯所有的,x86、arm的各種都會生成。也可以自行指定需要的某一種或者某幾種。
運作ndk-build編譯
注意兩點,一個是ndk-build以及jni的路徑,需要在jni目錄下執行ndk-build指令,要求已經配置好ndk-build系統環境或者使用完整路徑;另一個則是必須要有所依賴FFMPEG動态庫對應的頭檔案。我是在Linux環境下面先安裝了ffmpeg庫,是以local有了頭檔案可以直接編譯。你可以把用到的頭檔案拷貝到jni目錄能夠通路到地方,然後在mk檔案中用LOCAL_C_INCLUDES引用該頭檔案,或者像我一樣先安裝到系統環境裡。得讓編譯器能夠找的到頭檔案。 然後在jni的上一級目錄下,會生成libs和obj兩個目錄,直接libs裡面對應指令集的庫放到工程libs下面就可以編譯運作了,也可以全部指令集的都放過去,沒影響,隻是生成的安裝包會大一些。
源碼下載下傳位址 點選打開連結
在路上!