Android JNI 篇 - 編譯 bilibili/ijkPlayer

weixin_33890499發表於2019-01-24

本篇文章已授權微信公眾號 guolin_blog(郭霖)獨家釋出

一、視訊庫播放庫哪家強

二、分析 ijkPlayer 構建流程

三、構建 ijkplayer

四、遷移 ijkplayer 到 android studio

一、視訊庫播放庫哪家強

視訊播放庫 bilibili/ijkplayer google/ExoPlayer VLC-Android
支援ffmpeg擴充 支援 不支援 嵌入ffmpeg 的 libavcodec庫
可擴充性 低,需要二次開發
體積大小 5M-45M 無體積 13M
播放的視訊格式 只要ffmpeg支援都支援 支援手機支援播放的 大多數易見視訊
start 2.1W 1.2W GitLab 296個
issue 2116 Open / 2318 Close 201 Open / 4389 Close Open 169/Closed 544
是否持續維護 維護中 維護中 維護中

二、分析 ijkPlayer 構建流程

1、 找到ijkplayergithub 主頁
2788235-4577d5d390186990.png
image

看了一下這目錄結構,en .... ,果然沒看懂,是不是越是龐大的專案,越是喜歡整這些讓人摸不著頭腦的目錄結構要存放程式碼檔案。(其實官方是為了模組化程式碼結構),那這個要從哪裡入手。

2、 先看簡介 readme.md ,整理出下面一個流程圖
2788235-b279a19730868a3d.png
image

三、構建 ijkplayer

按照 readme.md 的流程來

1、 搭建 linux 環境

傻瓜式安裝:

下載Ubuntu

下載VMWare

2、 搭建 JDK(linux) + Android SDK(linux + NDK(linux)
  • JDK :
sudo apt-get install openjdk-8-kdk
//配置環境變數:
sudo gedit  /etc/profile 
export  JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
  • Android SDK(linux):

1)手動下載 sdk-tools-linux-4333796.zip

2)進入目錄 /androidSDK/sdk-tools-linux/tools/bin
執行 ./sdkmanager --list 命令看下有哪些目錄可以下載:

2788235-289584a6c4ba06dc.png
image

接著拉必要的目錄,執行以下命令

./sdkmanager "add-ons;addon-google_apis-google-24" "add-ons;addon-google_apis-google-24"  "platform-tools" "platforms;android-28" "tools"

3)配置環境變數

sudo gedit  /etc/profile 
export ANDROID_SDK=/home/jiong/androidSDK/android-sdk-linux
export PATH=${PATH}:$ANDROID_SDK/tools:$ANDROID_SDK/platform-tools
sudo gedit  /etc/profile 
export ANDROID_NDK=/home/jiong/androidNDK/android-ndk-r14b
export PATH=$ANDROID_NDK:$PATH
3、手動下載 ijkpalyer ,並放到 ubuntu的任意一個目錄下。
4、拉取 ijkpalyer JNIffmpeg 程式碼
cd ijkplayer-android
./init-android.sh
5、拉取 openssl 程式碼
./init-android-openssl.sh
6、編譯openssl程式碼
cd android/contrib
./compile-openssl.sh clean
./compile-openssl.sh all
2788235-e7ab49a9143a5651.png
image
7、選擇配置ffmpeg資訊
cd ../../
cd config
rm module.sh
ln -s module-lite.sh module.sh
//如果需要支援更多的視訊格式用下面的配置
// ln -s module-default.sh module.sh 
8、編譯 ffmpeg 程式碼
cd ../
cd android/contrib
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh all
2788235-980ec80c4243ae91.png
FFmepg
9、編譯 ijkplayer jni 程式碼(依賴ffmpeg庫)
cd ..
./compile-ijk.sh all
2788235-44842bad31a8e699.png
image

四、遷移 ijkplayer 到 android studio

1、拷貝 編譯好的這個 /ijkplayer-android/android 目錄,用android studio 匯入這個工程(原始碼4.1G 有點大 )
2788235-3425753adc0c9d80.png
image

2788235-5f3d8a0add21e135.png
image
2、看下主要庫的大小-- 一共4.8M左右
2788235-44582c7d1a8f7ef8.png
image
3、跑起來:
2788235-00abc712af00c313.gif
image
4、但是結果發現 .avi .dv .asf的視訊都不支援
2788235-842e71c91e15e4c5.gif
image
5、修改 ffmpeg 的引數
//這裡的配置換成下面的配置引數,這裡是 linux 軟引用表示 module.sh 檔名,代表了module-default.sh 檔案
//ln -s module-lite.sh module.sh
ln -s module-default.sh module.sh 

編譯ffmpeg指令碼do-compile-ffmpeg.sh 檔案裡面有這麼一句程式碼:

export COMMON_FF_CFG_FLAGS=.$FF_BUILD_ROOT/../../config/module.sh
  • 我們來看一下兩者的指令碼有哪些不同:左邊指令碼支援的編碼全開(預設),右邊指令碼,全部先關閉,再開幾個支援的。
2788235-84092898c8f9012d.png
image
6、重新編譯出 ffmpeg
  • 使用全部開啟的編譯指令碼,編譯出 so 。46M ,果然夠大


    2788235-59a7a722ce6cd1c0.png
    image
7、重新跑一下, avi 、asf 、dv都能播放了。
2788235-c145a3938cd8de95.gif
image
8、如果每次都要在 linux 編譯出 so ,再移到 android studio 上跑非常麻煩,如何把ijkpalyerjni 原始碼放到 android studio一鍵編譯。看下面:
  • linux 下觀察 jni 資料夾有哪些檔案,其中有兩個是連結檔案(右下角有個箭頭),並且三個資料夾都是空檔案,沒有放置原始碼在裡面。
    2788235-86fb35aaf663d717.png
    image
  • android-ndk-prof 原始碼在以下資料夾(右鍵屬性,可以看到真實檔案的路徑)
/ijkplayer-android/android-ndk-profiler-dummy/jni
  • ffmpegso 庫檔案,以及include 資料夾在以下資料夾(看complie-ffmpeg.sh 的指令碼語言打包的輸出路徑)
/ijkplayer-android/android/contrib/build/ffmpeg-armv7a/output
  • ijkmedia原始碼在以下資料夾(右鍵屬性,可以看到真實檔案的路徑)
/ijkplayer-android/ijkmedia
  • 全部拷貝過去,ffmpeg 拷貝 so庫以及標頭檔案 過去即可,畢竟ffmpeg 一般不需要二次開發,有bug 等更新就可以,不然每次編譯 十幾分鍾,太長。android-ndk-profiler-dummyijkmedia模組就把原始碼拷貝過來。 結果位置見下圖:

    2788235-0ee19721a799140b.png
    image

  • 接下來需要修改 /jni/Android.mk,不然編譯不過去:
    舊程式碼

LOCAL_PATH := $(call my-dir)

MY_APP_JNI_ROOT := $(realpath $(LOCAL_PATH))
MY_APP_PRJ_ROOT := $(realpath $(MY_APP_JNI_ROOT)/..)
MY_APP_ANDROID_ROOT := $(realpath $(MY_APP_PRJ_ROOT)/../../../..)

ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-armv7a/output)
MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)
endif
ifeq ($(TARGET_ARCH_ABI),armeabi)
MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-armv5/output)
MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)
endif
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-arm64/output)
MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)
endif
ifeq ($(TARGET_ARCH_ABI),x86)
MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-x86/output)
MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)
endif
ifeq ($(TARGET_ARCH_ABI),x86_64)
MY_APP_FFMPEG_OUTPUT_PATH := $(realpath $(MY_APP_ANDROID_ROOT)/contrib/build/ffmpeg-x86_64/output)
MY_APP_FFMPEG_INCLUDE_PATH := $(realpath $(MY_APP_FFMPEG_OUTPUT_PATH)/include)
endif

include $(call all-subdir-makefiles)

由於 jni 需要使用相對路徑 ,去掉$(realpath),這裡只保留armeabi-v7a改成:

LOCAL_PATH := $(call my-dir)
MY_APP_ANDROID_ROOT := $(LOCAL_PATH)

MY_APP_FFMPEG_OUTPUT_PATH :=  $(MY_APP_ANDROID_ROOT)/ffmpeg/lib
MY_APP_FFMPEG_INCLUDE_PATH :=  $(MY_APP_ANDROID_ROOT)/ffmpeg/include


include $(call all-subdir-makefiles) //找到所有目錄下第一層子目錄的 android.mk 進行編譯
  • ijkmedia 模組下面的第一層資料夾 凡是有 Android.mk 的,並且裡面使用 $(realpath $(LOCAL_PATH)) 的,都要把 $(realpath)去掉。
  • 好了在 android studio 編譯起來:
    2788235-98b6bbccae29071d.gif
    image
  • 跑起來,大功告成:
2788235-1b94c59baaec1943.gif
image

相關文章