將 ffmpeg 編譯為 android JNI 庫 | 挨踢的甘蔗
dxjia
憋說話,好好乾,你想要的時間都會給你
Programmer
之前有開源了一個 ffmpeg shared library,其中是把 ffmpeg 2.6 源碼編譯為android 平台可用的共享庫,在其中只介紹了如何編譯,但對於如何將這些共享庫轉變為 JNI 使用卻沒有講太多。本文就著重介紹一下思路,方便後續升級 ffmpeg 版本。
編譯 ffmpeg 共享庫依據 使用 介紹下載 ffmpeg 源碼,配置編譯腳本進行編譯。build_android_arm.sh
和 build_android_x86.sh
兩個腳本分別是用來編譯用於 arm 平台的庫文件和 x86 平台的庫的,如果你只需要 arm 平台的,那 x86 的可以不用管了。注意:
每次運行完腳本編譯之後,會在 ffmpeg 源碼目錄下生成一個 config.h 文件,這個也是後續編譯 jni 必需的,需要在運行另一個編譯腳本之前進行保存, 我這裡採用的方式是將 config.h 重命名為不同的名字,在編譯 jni 時根據 target 不同引用不同的頭文件,即:運行完 build_android_arm.sh
之後,將 config.h 重命名為 arm_config.h
,運行完 build_android_x86.sh
之後,重命名為 x86_config.h
編譯 jni
新建一個android項目,並新建一個 library module,也可以直接在你的 app 項目里,看自己的需要了。
禁用 android studio JNI 自動編譯在 你的 build.gradle
中增加下面幾行代碼,來禁用 as 對 jni 的自動編譯,因為我們需要自己手動編譯 jni。參考 build.gradle。
1234 |
sourceSets.main { jni.srcDirs = [] //disable automatic ndk-build jniLibs.srcDirs = ["libs"]} |
在module下新建 jni 目錄,在該目錄下新建 Android.mk
文件,內容複製 這裡,當然後續對該文件根據需要還有少許調整,後面會提到。
頭文件
將從 ffmpeg 源碼編譯得到的 arm 和 x86 的 include 文件夾 整個複製到 jni 目錄下,注意 arm和x86相同的文件直接覆蓋或略過都可以的,主要是要讓它們互相補充。
後續實際編譯你會發現,這些頭文件並不夠,還會缺少很多.h文件,所以後續隨著編譯的過程,必須自己一點點從ffmpeg源碼目錄不斷補充頭文件。
在 jni 目錄下新建 prebuilt
目錄,然後在 prebuilt 目錄內,分別新建 armeabi
和 x86
目錄,然後將 ffmpeg 源碼編譯的出來的 arm 的幾個so庫文件複製到 armeabi 目錄下,同理,將 x86 的複製到 x86 目錄下。接下來,修改 Android.mk 文件中的對應的 so 名,都改成自己的對應文件名。如下:
1234 |
nclude $(CLEAR_VARS)LOCAL_MODULE:= avcodec-prebuilt-$(LIB_NAME_PLUS)LOCAL_SRC_FILES:= prebuilt/$(LIB_NAME_PLUS)/libavcodec-56.soinclude $(PREBUILT_SHARED_LIBRARY) |
不同的 ffmpeg 版本,這些so的版本是不同的,體現在so文件名都有個數字尾巴,這裡不要去掉這些尾巴,因為它們之間還有依賴。如果確實不想帶尾巴,那麼就需要去改ffmpeg源碼的makefile了
複製源文件
ffmpeg
可執行文件執行命令的入口是 ffmpeg.c 文件的 main 函數,所以我們的原理就是將個這個main函數修改為我們的jni函數,那麼java層調用這個jni介面就可以執行命令了。從ffmpeg 源碼目錄下的複製下面的文件到jni目錄下
123456789 |
ffmpeg.cffmpeg.harm_config.hx86_config.hcmdutils.ccmdutils.hcmdutils_common_opts.hffmpeg_filter.cffmpeg_opt.c |
調整 Android.mk
的 LOCAL_SRC_FILES
部分,將 jni 目錄下的 所有 .c 文件都加入其中,這樣才能參與編譯。
內容如下:
12345 |
#if USE_ARM_CONFIG#include "arm_config.h"#elif USE_X86_CONFIG#include "x86_config.h"#endif |
增加 jni 介面
如何增加jni這裡不多講了,網上資料很多,也可以參考 library.將 ffmpeg.c main函數修改為你的 jni介面,然後在 jni 目錄下執行 build.sh
(windows下執行 build.cmd) 進行手動編譯,一般這裡你就會發現少很多頭文件,可以一點點試,缺少哪個頭文件就從ffmpeg源碼目錄copy到include的對應目錄下,注意有些是需要保留目錄結構的,沒有就新建。
在java部分的jni文件中,使用static代碼塊載入lib庫,如下:
12345678910 |
static { System.loadLibrary("avutil-54"); System.loadLibrary("swresample-1"); System.loadLibrary("avcodec-56"); System.loadLibrary("avformat-56"); System.loadLibrary("swscale-3"); System.loadLibrary("avfilter-5"); System.loadLibrary("avdevice-56"); System.loadLibrary("ffmpegjni");} |
注意名字,修改為你實際使用的版本,並且名字上不帶lib
,參考 FFmpegNativeHelper.java,
至此,從 android studio里編譯就可以將所有lib和jni庫都編譯到你的工程里去了。
附:
實際移植 ffmpeg3.0 的時候遇到的其他問題:
- 在編譯ffmpeg源碼時,編譯完 arm 的版本,去編 x86 版本的時候,提示 strtop 錯誤,這是由 ffmpeg 的makefile bug造成的,再
run build_android_x86.sh
之前先手動刪除compat/strtop.o & compat/strtop.d
文件。
本文標題:將 ffmpeg 編譯為 android JNI 庫
文章作者:dxjia
發布時間:2016-07-27, 15:14:38
最後更新:2016-08-09, 12:53:43
原始鏈接:http://dxjia.cn/2016/07/27/how_to_compile_ffmpeg_for_android/
許可協議: "署名-非商用-相同方式共享 4.0" 轉載請保留原文鏈接及作者。
文章目錄
- 1. 編譯 ffmpeg 共享庫
- 2. 編譯 jni
- 2.1. 禁用 android studio JNI 自動編譯
- 2.2. 準備文件
- 2.2.1. Android.mk
- 2.2.2. 頭文件
- 2.2.3. prebuilt
- 2.2.4. 複製源文件
- 2.2.5. 新建 config.h 文件
- 2.2.6. 增加 jni 介面
- 2.2.7. java 部分
推薦閱讀:
※法意編譯 | 特朗普現象:民主過盛還是民主不足?
※梭羅和隱逸的《瓦爾登湖》(王淑霞 編譯)
※中央編譯局
※經略編譯 | 怒從何來?「劍橋分析」與我們的時代
※獨家編譯 | 五千年歷史耶路撒冷 到底是誰的「首都」?