MacOS編譯ffmpeg并引入android

ffmpeg編譯

編譯環(huán)境:

  • ndk-21.2.6472646
  • ffmpeg-4.2.3
  • AndroidStudio 4.0

1.下載源碼

下載地址

解壓得到目錄

image.png

2.修改configure腳本

  • 搜索 CMDLINE_SET,添加一行 cross_prefix_clang

    CMDLINE_SET="
        $PATHS_LIST
        ar
        arch
        as
        assert_level
        build_suffix
        cc
        objcc
        cpu
        cross_prefix
        # 新增命令行參數(shù)
        cross_prefix_clang
        custom_allocator
        cxx
        dep_cc
        # 省略其他.....
    "
    
  • 搜索 ar_default="${cross_prefix}${ar_default}" 修改其中兩行

    # 初始為
    ar_default="${cross_prefix}${ar_default}"
    cc_default="${cross_prefix}${cc_default}"
    cxx_default="${cross_prefix}${cxx_default}"
    nm_default="${cross_prefix}${nm_default}"
    pkg_config_default="${cross_prefix}${pkg_config_default}"
    
    #修改為
    ar_default="${cross_prefix}${ar_default}"
    #------------------------------------------------這兩行需要修改
    cc_default="${cross_prefix_clang}${cc_default}"
    cxx_default="${cross_prefix_clang}${cxx_default}"
    #------------------------------------------------
    nm_default="${cross_prefix}${nm_default}"
    pkg_config_default="${cross_prefix}${pkg_config_default}"
    
    
    

3.新建編譯腳本build_android_clang.sh

image.png

內(nèi)容如下 具體內(nèi)容需要根據(jù)自己電腦上面ndk環(huán)境進(jìn)行修改

#!/bin/bash
set -x
# 目標(biāo)Android版本
API=19
CPU=armv7-a
#so庫(kù)輸出目錄
OUTPUT=/Users/tanyuanchao/Desktop/ffmpeg/ffmpeg-4.2.3/android/$CPU
# NDK的路徑,根據(jù)自己的NDK位置進(jìn)行設(shè)置
NDK=/Users/tanyuanchao/Library/Android/sdk/ndk/21.2.6472646
# 編譯工具鏈路徑
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
# 編譯環(huán)境
SYSROOT=$TOOLCHAIN/sysroot

function build
{
  ./configure \
  --prefix=$OUTPUT \
  --target-os=android \
  --arch=arm \
  --cpu=armv7-a \
  --enable-asm \
  --enable-neon \
  --enable-cross-compile \
  --enable-shared \
  --disable-static \
  --disable-doc \
  --disable-ffplay \
  --disable-ffprobe \
  --disable-symver \
  --disable-ffmpeg \
  --sysroot=$SYSROOT \
  --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
  --cross-prefix-clang=$TOOLCHAIN/bin/armv7a-linux-androideabi$API- \
  --extra-cflags="-fPIC"

  make clean all
  # 這里是定義用幾個(gè)CPU編譯
  make -j12
  make install
}

build
  • 這里我android目標(biāo)版本選擇19
  • cpu架構(gòu)選擇armv7-a
  • 輸出路徑,ndk路徑自己配置。

4.修改文件為可執(zhí)行文件

chmod +x build_android_clang.sh

5.執(zhí)行開(kāi)始編譯

./build_android_clang.sh

6.編譯完成后得到的目錄

image.png
  • include文件夾下為頭文件
  • lib文件夾下為動(dòng)態(tài)鏈接庫(kù).so文件

android中引入編譯后的庫(kù)

新建項(xiàng)目或者已有項(xiàng)目中進(jìn)行以下操作

1.修改app的build.gradle新增如下內(nèi)容

android {
    defaultConfig {
        // 新增1
        externalNativeBuild {
            cmake {
                cppFlags ""
                // 配置cmake編譯的cpu架構(gòu),否則會(huì)還回去找其他架構(gòu),由于我們只編譯的armeabi-v7a,所以找不到其他會(huì)報(bào)錯(cuò)
                abiFilters  'armeabi-v7a'
            }
        }
    }
        // 新增2
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }


}

2.創(chuàng)建jniLibs文件夾來(lái)放動(dòng)態(tài)庫(kù)!?。?!這里有坑

  • 在下面新建armeabi-v7a文件夾然后將之前編譯后的so文件拷貝進(jìn)來(lái)
image.png

3.創(chuàng)建cpp文件夾

  • 在src/main/目錄下新建cpp文件夾

  • cpp文件夾新建ffmpeg目錄,然后將編譯后的include文件夾全部拷貝過(guò)來(lái)

  • cpp文件夾新建native-lib.cpp,內(nèi)容可以先不管,主要是返回ffmpeg的一些信息,用來(lái)后面測(cè)試是否成功

    #include <jni.h>
    #include <string>
    #include <unistd.h>
    
    extern "C"{
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libavfilter/avfilter.h>
    #include <libavcodec/jni.h>
    
    JNIEXPORT jstring JNICALL
        Java_com_elitetyc_elitevideo_MainActivity_ffmpegName(JNIEnv *env, jobject  /* this */) {
    
            char info[40000] = {0};
            AVCodec *c_temp = av_codec_next(NULL);
            while (c_temp != NULL) {
                if (c_temp->decode != NULL) {
                    sprintf(info, "%sdecode:", info);
                } else {
                    sprintf(info, "%sencode:", info);
                }
                switch (c_temp->type) {
                    case AVMEDIA_TYPE_VIDEO:
                        sprintf(info, "%s(video):", info);
                        break;
                    case AVMEDIA_TYPE_AUDIO:
                        sprintf(info, "%s(audio):", info);
                        break;
                    default:
                        sprintf(info, "%s(other):", info);
                        break;
                }
                sprintf(info, "%s[%s]\n", info, c_temp->name);
                c_temp = c_temp->next;
            }
    
            return env->NewStringUTF(info);
        }
    }
    
  • cpp文件夾新建CMakeLists.txt

    
    cmake_minimum_required(VERSION 3.4.1)
    
    # 支持gnu++11
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
    
    # 1. 定義so庫(kù)和頭文件所在目錄,方面后面使用
    set(ffmpeg_lib_dir ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
    set(ffmpeg_head_dir ${CMAKE_SOURCE_DIR}/ffmpeg)
    
    # 2. 添加頭文件目錄
    include_directories(${ffmpeg_head_dir}/include)
    
    # 3. 添加ffmpeg相關(guān)的so庫(kù)
    add_library( avutil
            SHARED
            IMPORTED )
    set_target_properties( avutil
            PROPERTIES IMPORTED_LOCATION
            ${ffmpeg_lib_dir}/libavutil.so )
    
    add_library( swresample
            SHARED
            IMPORTED )
    set_target_properties( swresample
            PROPERTIES IMPORTED_LOCATION
            ${ffmpeg_lib_dir}/libswresample.so )
    
    add_library( avcodec
            SHARED
            IMPORTED )
    set_target_properties( avcodec
            PROPERTIES IMPORTED_LOCATION
            ${ffmpeg_lib_dir}/libavcodec.so )
    
    add_library( avfilter
            SHARED
            IMPORTED)
    set_target_properties( avfilter
            PROPERTIES IMPORTED_LOCATION
            ${ffmpeg_lib_dir}/libavfilter.so )
    
    add_library( swscale
            SHARED
            IMPORTED)
    set_target_properties( swscale
            PROPERTIES IMPORTED_LOCATION
            ${ffmpeg_lib_dir}/libswscale.so )
    
    add_library( avformat
            SHARED
            IMPORTED)
    set_target_properties( avformat
            PROPERTIES IMPORTED_LOCATION
            ${ffmpeg_lib_dir}/libavformat.so )
    
    add_library( avdevice
            SHARED
            IMPORTED)
    set_target_properties( avdevice
            PROPERTIES IMPORTED_LOCATION
            ${ffmpeg_lib_dir}/libavdevice.so )
    
    
    # 查找代碼中使用到的系統(tǒng)庫(kù)
    find_library(
            log-lib
    
    
            log )
    
    # 配置目標(biāo)so庫(kù)編譯信息
    add_library(
            native-lib
    
    
            SHARED
    
    
            native-lib.cpp
            )
    
    # 指定編譯目標(biāo)庫(kù)時(shí),cmake要鏈接的庫(kù)
    target_link_libraries(
    
            # 指定目標(biāo)庫(kù),native-lib 是在上面 add_library 中配置的目標(biāo)庫(kù)
            native-lib
    
            # 4. 連接 FFmpeg 相關(guān)的庫(kù)
            avutil
            swresample
            avcodec
            avfilter
            swscale
            avformat
            avdevice
    
            # Links the target library to the log library
            # included in the NDK.
            ${log-lib} )
    
    
    

    第1步:設(shè)置動(dòng)態(tài)庫(kù)文件夾和頭文件夾在你當(dāng)前項(xiàng)目的目錄位置

    第3步:依次將so庫(kù)添加進(jìn)來(lái)

4.MainActivity修改

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        tvName.text = ffmpegName()

    }

    private  external  fun ffmpegName():String

    companion object{
        init {
            System.loadLibrary("native-lib")
        }
    }
}
  • companion object中初始化方法進(jìn)行加載native-lib.cpp文件
  • 將textview內(nèi)容設(shè)置為調(diào)用庫(kù)文件返回的方法

5.進(jìn)行運(yùn)行

出現(xiàn)的問(wèn)題,

  • 如果運(yùn)行到模擬器,且架構(gòu)為x86會(huì)出現(xiàn)以下問(wèn)題
java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.elitetyc.elitevideo-Ixc9OTEY7urV3gNO0Lazeg==/base.apk"],nativeLibraryDirectories=[/data/app/com.elitetyc.elitevideo-Ixc9OTEY7urV3gNO0Lazeg==/lib/x86, /system/lib, /system/product/lib]]] couldn't find "libnative-lib.so"

因?yàn)槲覀兲峁┑膕o文件值提供了armeabi-v7a架構(gòu)支持的,所以會(huì)出現(xiàn)這個(gè)問(wèn)題,解決方案,換cpu架構(gòu)的模擬器,或者直接運(yùn)行到手機(jī)

  • 直接運(yùn)行到手機(jī),或者進(jìn)行打包,出現(xiàn)的問(wèn)題

    More than one file was found with OS independent path 'lib/armeabi-v7a/libavutil.so'. If you are using jniLibs and CMake IMPORTED targets, see https://developer.android.com/studio/preview/features#automatic_packaging_of_prebuilt_dependencies_used_by_cmake
    

    還記得之前說(shuō)的有坑的地方吧,創(chuàng)建的目錄為jniLibs,找的很多方案,也不知道具體的原因,AS版本為4.0,然后嘗試將jniLibs這個(gè)文件夾的名字修改,我將s去掉,然后修改CMakeLists.txt文件中的第一步

    # 1. 定義so庫(kù)和頭文件所在目錄,方面后面使用
    set(ffmpeg_lib_dir ${CMAKE_SOURCE_DIR}/../jniLib/${ANDROID_ABI})
    

就可以打包成功了

運(yùn)行效果

image.png

以上內(nèi)容根據(jù):開(kāi)發(fā)的貓 的文章進(jìn)行操作,記錄實(shí)現(xiàn)過(guò)程中出現(xiàn)的問(wèn)題

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容