將ffmpeg引入到Android工程中

思想覺悟發表於2020-02-17

準備工具

  • Android開發工具AS(需要下載NDK)
  • ffmpeg交叉編譯後的動態庫或靜態庫以及標頭檔案
    如果你不知道如何編譯ffmpeg請看這篇文章
    NDKr20使用clang編譯ffmpeg4.2.2

接入步驟

新建Native C++工程並引入標頭檔案和動態庫:

專案程式碼目錄

編寫CMakeLists.txt檔案:


cmake_minimum_required(VERSION 3.4.1)

# 引入FFmpeg的標頭檔案
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include)

# 方式一
# 引入FFmpeg的庫檔案,設定內部的方式引入,指定庫的目錄是 -L  指定具體的庫-l
# 這種方式方便快捷
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI}")

# 方式二
#設定ffmpeg庫所在路徑的變數
#set(FF ${CMAKE_SOURCE_DIR}/${CMAKE_ANDROID_ARCH_ABI})
#add_library(avcodec SHARED IMPORTED)
#set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${FF}/libavcodec.so)
#
#add_library(avformat SHARED IMPORTED)
#set_target_properties(avformat PROPERTIES IMPORTED_LOCATION ${FF}/libavformat.so)
#
#add_library(avutil SHARED IMPORTED)
#set_target_properties(avutil PROPERTIES IMPORTED_LOCATION ${FF}/libavutil.so)
#
#add_library(swscale SHARED IMPORTED)
#set_target_properties(swscale PROPERTIES IMPORTED_LOCATION ${FF}/libswscale.so)
#
#add_library(swresample SHARED IMPORTED)
#set_target_properties(swresample PROPERTIES IMPORTED_LOCATION ${FF}/libswresample.so)
#
#add_library(avfilter SHARED IMPORTED)
#set_target_properties(avfilter PROPERTIES IMPORTED_LOCATION ${FF}/libavfilter.so)

#找到包含所有的cpp檔案
file(GLOB allCpp src/main/cpp/*.*)

add_library(
             # 生成的庫的名字
             flyffmpeg-lib

             # 動態庫
             SHARED

             # 原始檔
             ${allCpp} )


target_link_libraries( #目標庫
                       flyffmpeg-lib

                       # 把ffmpeg的動態庫以來進來
                       avformat
                       avcodec
                       avutil
                       avfilter
                       swscale
                       swresample

                       # NDK中的log庫
                       log )
複製程式碼

相關注釋都已經寫的很清楚了,這裡就不再多解析了。ffmpeg就引入進去後,下面我編寫一個簡答的程式碼呼叫一下ffmpeg的相關api測試下是否能正常呼叫。

新建一個native方法獲取ffmpeg的版本號:

 public native static String getFFmpegVersion();
複製程式碼

jni相關程式碼:

#include <jni.h>
#include <string>

// 因為ffmpeg是純C程式碼,要在cpp中使用則需要使用 extern "C"
extern "C" {
#include "libavutil/avutil.h"
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_flyer_ffmpeg_FFmpegUtils_getFFmpegVersion(JNIEnv *env, jclass clazz) {
    //通過av_version_info()獲取版本號
    return env -> NewStringUTF(av_version_info());
}
複製程式碼

通過TextView顯示一下獲取到的版本號:

成功獲取到ffmpeg版本號

遇到的問題

  1. 報錯ffmpeg的相關庫沒有找到
    解決方法:檢查你專案的CMakeLists.txt中的ffmpeg相關庫有沒有正確連結;
    檢查build.gradle中有沒有配置好將相關so打包進去apk的配置:
sourceSets {
        main {
           //將依賴庫打進apk,否則可能出現找不到庫
          jniLibs.srcDirs = ['libs']
              }
          }
複製程式碼
  1. 報自定義封裝的so庫找不到 解決方法: 檢查build.gradle中是否設定了abiFilters
    筆者的環境實驗發現在cmake中設定abiFilters無效,依然會報so無法找到的錯誤,但是在ndk中設定則正常;
externalNativeBuild(){
            cmake{
                // 為什麼在這裡指定編譯架構會報so庫找不到的錯誤,而在ndk中指定則不會???
               // abiFilters "armeabi-v7a" //指定編譯為 armeabi-v7a
            }

            ndk {
                abiFilters "armeabi-v7a"
            }
        }
複製程式碼

最後如果你對音視訊開發感興趣可掃碼關注,後續我們共同探討,共同進步。

將ffmpeg引入到Android工程中

相關文章