Andriod studio3.5搭建ffmpeg helloworld(動態(tài)庫文件)

環(huán)境

win7、jdk8、Andriod studio3.5、 NDK21


寫在前

  1. 采用編譯好的ffmpeg動態(tài)庫文件(多個動態(tài)文件)
  2. Android studio3.5創(chuàng)建navtive c++工程已經(jīng)配置好jni demo,不用考慮gradle和cmake協(xié)調(diào)配置,非常方便
  3. 不同版本的Android studio創(chuàng)建的C+項目的CMakeLists.txt放置路徑不一樣,多用message命令確認內(nèi)置變量的值

簡單總結(jié)

一般NDK開發(fā)時會有三方面報錯

  1. 編輯C/C++代碼時,找不到頭文件。說明CMakeLists.txt配置有漏
  2. build構(gòu)建時,鏈接linked報錯。說明CMakeLists.txt配置有漏
  3. 運行時找不到so文件,閃退,這是外部so文件沒有打包如apk中。說明build.gradle配置有漏?;蛘邔⑼獠縮o文件放入main/jniLibs/{ABI版本}中
    具體的解決方案看本文最后

使用靜態(tài)文件 vs 使用動態(tài)文件

  1. 使用靜態(tài)文件在build構(gòu)建時會編入內(nèi)部so文件中;而使用動態(tài)文件,需要把外部so文件打包如spk中
  2. 靜態(tài)文件會缺少uncompress等函數(shù)定義,需要添加壓縮庫(Z);使用動態(tài)文件則不用

操作步驟-詳細:

  1. AS添加C++工程


    image.png
  2. 拷貝ffmpeg文件到AS工程,目錄結(jié)構(gòu)如下


    image.png
  3. 修改app的gradle.build

apply plugin: 'com.android.application'

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"
    defaultConfig {
        applicationId "com.example.mmffndk"
        minSdkVersion 21
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""
               abiFilters 'armeabi-v7a'    //ABIs [armeabi] are not supported for platform. Supported ABIs are [arm64-v8a, armeabi-v7a, x86, x86_64].
            
            }
        }

        ndk{                //修改點2
            abiFilters 'armeabi-v7a'
        }

        sourceSets {
            main {
                jniLibs.srcDirs = ['libs']  //jniLibs打包時會查找libs/${ANDROID_ARCH_ABI}/*.so
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}

  1. 修改CMakeLists.txt
  • 需要注意:
    1) 不同版本的android studio生成項目的CMakeLists.txt路徑不同,所以CMAKE_SOURCE_DIR的值不同
    2)使用ffmpeg動態(tài)庫,已經(jīng)包含壓縮等。所以target_link_libraries不需要添加 -lz
cmake_minimum_required(VERSION 3.4.1)

# 指定引入文件頭路徑 , include文件夾里放置了ffmpeg的.h頭文件
include_directories(${CMAKE_SOURCE_DIR}/ffmpeg/include)

# 指定 .so共享庫目錄 (相當(dāng)于添加 CXXFLAGS=-Lpath)
link_directories(${PROJECT_SOURCE_DIR}/../../../libs/${CMAKE_ANDROID_ARCH_ABI})

# 指定 c/c++ 源文件目錄
aux_source_directory(${CMAKE_SOURCE_DIR} cpp-list)
message(STATUS "cpp-list = ${cpp-list}")

add_library( # Sets the name of the library.
       native-lib11
       SHARED
       ${cpp-list})

find_library( # Sets the name of the path variable.
       log-lib
       log)

target_link_libraries( # Specifies the target library.
       native-lib11
       avcodec avdevice avfilter avformat avutil swresample swscale
       android
       ${log-lib})
  1. 點擊 build->rebuild project ,項目構(gòu)建完成后,打開 apk分析器(build ->apk analyze然后選擇apk)
    由于我們在app:build.gradle里配置 abiFilters=armeabi-v7a,而且配置了jniLibs.srcDirs = 'libs'。所以apk打包時會在lib下創(chuàng)建armeabi-v7a文件夾,并且把項目中l(wèi)ibs目錄下armeabi-v7a里所有so文件拷貝過來。 同樣的,如果配置 abiFilters='armeabi-v7a'和'arm64-v8a', 則會在apk的lib下創(chuàng)建armeabi-v7a和arm64-v8a兩個文件夾,并且把項目中的libs目錄下對應(yīng)的文件夾拷貝過來。如果項目中沒有l(wèi)ibs/arm64-v8a目錄,則build的時候會報錯
    image.png

常見錯誤

  1. 頭文件找不到
  • 現(xiàn)象:編輯c/cpp代碼時報錯 cannot find 'libavcodec'


    image.png
  • 原因:頭文件路徑錯誤
  • 解決方案:
    ①先在 CmakeLists.txt 里添加:include_directories(${CMAKE_SOURCE_DIR}/ffmpeg/include)
    ②點擊 build->refresh linked C++ projects
  1. 鏈接錯誤:linker command failed with exit code 1 (use -v to see invocation)
  • 現(xiàn)象:build構(gòu)建時報錯:undefined reference to 'avutil_configuration'
[2/2] Linking CXX shared library G:\learn\androidlearn\workstation\Mmffndk\app\build\intermediates\cmake\debug\obj\armeabi-v7a\libnative-lib.so
  FAILED: G:/android/workstation/Mmffndk/app/build/intermediates/cmake/debug/obj/armeabi-v7a/libnative-lib.so 
  cmd.exe /C "cd . && G:\learn\androidlearn\studio\sdk\ndk\21.0.6113669\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=armv7-none-linux-androideabi21 --gcc-toolchain=G:/android/studio/sdk/ndk/21.0.6113669/toolchains/llvm/prebuilt/windows-x86_64 --sysroot=G:/android/studio/sdk/ndk/21.0.6113669/toolchains/llvm/prebuilt/windows-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -march=armv7-a -mthumb -Wformat -Werror=format-security   -O0 -fno-limit-debug-info  -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--fatal-warnings -Wl,--exclude-libs,libunwind.a -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libnative-lib.so -o G:\learn\androidlearn\workstation\Mmffndk\app\build\intermediates\cmake\debug\obj\armeabi-v7a\libnative-lib.so CMakeFiles/native-lib.dir/native-lib.cpp.o  -lavformat -lavcodec -lavfilter -lavutil -lswresample -lswscale -landroid -llog -latomic -lm && cd ."
  G:/android/studio/sdk/ndk/21.0.6113669/toolchains/llvm/prebuilt/windows-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin\ld: error: cannot find -lavformat
  G:/android/studio/sdk/ndk/21.0.6113669/toolchains/llvm/prebuilt/windows-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin\ld: error: cannot find -lavcodec
  G:/android/studio/sdk/ndk/21.0.6113669/toolchains/llvm/prebuilt/windows-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin\ld: error: cannot find -lavfilter
  G:/android/studio/sdk/ndk/21.0.6113669/toolchains/llvm/prebuilt/windows-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin\ld: error: cannot find -lavutil
  G:/android/studio/sdk/ndk/21.0.6113669/toolchains/llvm/prebuilt/windows-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin\ld: error: cannot find -lswresample
  G:/android/studio/sdk/ndk/21.0.6113669/toolchains/llvm/prebuilt/windows-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin\ld: error: cannot find -lswscale
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:27: error: undefined reference to 'avutil_configuration'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:40: error: undefined reference to 'av_register_all'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:42: error: undefined reference to 'avformat_alloc_context'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:52: error: undefined reference to 'av_dict_set'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:54: error: undefined reference to 'avformat_open_input'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:62: error: undefined reference to 'avformat_find_stream_info'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:87: error: undefined reference to 'avcodec_find_decoder'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:94: error: undefined reference to 'avcodec_open2'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:102: error: undefined reference to 'sws_getContext'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:108: error: undefined reference to 'av_malloc'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:110: error: undefined reference to 'av_init_packet'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:116: error: undefined reference to 'av_frame_alloc'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:119: error: undefined reference to 'av_frame_alloc'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:122: error: undefined reference to 'avpicture_get_size'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:121: error: undefined reference to 'av_malloc'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:125: error: undefined reference to 'avpicture_fill'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:136: error: undefined reference to 'av_read_frame'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:144: error: undefined reference to 'avcodec_decode_video2'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:155: error: undefined reference to 'sws_scale'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:179: error: undefined reference to 'av_free_packet'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:185: error: undefined reference to 'av_frame_free'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:186: error: undefined reference to 'av_frame_free'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:188: error: undefined reference to 'avcodec_close'
  G:/android/workstation/Mmffndk/app/src/main/cpp/native-lib.cpp:189: error: undefined reference to 'avformat_free_context'
  clang++: error: linker command failed with exit code 1 (use -v to see invocation)
  • 原因:so文件沒有引入
  • 解決方法:在 CMakeLists.txt添加
# 指定 .so共享庫目錄 (如果是 .a靜態(tài)文件,需要添加 CXXFLAGS)
link_directories(${PROJECT_SOURCE_DIR}/../../../libs/${CMAKE_ANDROID_ARCH_ABI})
  1. ffmpeg的so文件沒有打入apk包
    現(xiàn)象:打包沒報錯,運行時閃退,報錯如下
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.mmffndk, PID: 7253
    java.lang.UnsatisfiedLinkError: dlopen failed: library "libavformat.so" not found: needed by /data/app/~~VZddftg5_hnlp3FkuHdTxg==/com.example.mmffndk-NDSt_nrh6mmjLv39fko4gQ==/lib/arm/libnative-lib.so in namespace classloader-namespace
        at java.lang.Runtime.loadLibrary0(Runtime.java:1087)
        at java.lang.Runtime.loadLibrary0(Runtime.java:1008)
        at java.lang.System.loadLibrary(System.java:1664)
        at com.example.mmffndk.MainActivity.<clinit>(MainActivity.java:25)
        at java.lang.Class.newInstance(Native Method)
        at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:95)
        at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:43)
        at android.app.Instrumentation.newActivity(Instrumentation.java:1253)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3353)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
D/libEGL: loaded /vendor/lib/egl/libEGL_emulation.so

解決方案:
① 打開 apk analyze,確認ffmpeg相關(guān)的外部so文件沒有打入apk中


image.png

② 確認app:build.gradle有沒有報錯


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

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

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