zoukankan      html  css  js  c++  java
  • FFmpeg: mac下手动编译android上使用的FFmpeg(支持x86、armeabi-v7a、arm64-v8a)

    之前一直在linux下编译FFmpeg,最近换电脑了,尝试了下在mac下编译ffmpeg,特记录之。

    一. 准备工作

    1. 下载FFmpeg。(http://ffmpeg.org/download.html#releases),看了下最新的是4.1.4,我用的是3.4.6。

    2. 下载mac上使用的NDK。(https://developer.android.google.cn/ndk/downloads/index.html), 我用的是android-ndk-r14b-darwin-x86_64.zip,不推荐使用ndk-bundle,有些头文件在ndk-bundle里没有,遇到过一次。

    3. 修改FFmpeg3.4.6目录下的configure文件。如果不修改的话之后编译生成的版本号会加在so的后面,会导致android不能识别,切记。

    修改的内容如下,将:

    SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
    LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
    SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
    SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR)$(SLIBNAME)'

    修改成:

    SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
    LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
    SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
    SLIB_INSTALL_LINKS='$(SLIBNAME)'

    4. 编写编译用的脚本文件。这个网上有很多,我找到了两个可以用的:

    用于编译 armeabi-v7a、arm64-v8a、x86_64版本的:

    #!/bin/bash
    
    echo "进入FFmpeg编译脚本"
    
    # NDK环境    
    export NDK=/Users/haiyuegao/Library/Android/android-ndk-r14b
    export SYSROOT=$NDK/platforms/android-21/arch-arm
    export TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
    PREFIX=android-build
    
    COMMON_OPTIONS="
        --prefix=android/ 
        --target-os=android 
        --enable-shared 
        --enable-runtime-cpudetect 
        --enable-small 
        --disable-static 
        --disable-debug 
        --disable-ffmpeg 
        --disable-ffplay 
        --disable-ffprobe 
        --disable-ffserver 
        --disable-doc 
        --disable-symver 
        --disable-asm 
        --disable-stripping 
        --disable-armv5te 
        "
    
    function build_android {
    
        echo "开始编译FFmpeg..."
    
        # armeabi
        echo "开始编译FFmpeg(armeabi)"
        ./configure 
        --libdir=${PREFIX}/libs/armeabi 
        --incdir=${PREFIX}/include/armeabi 
        --pkgconfigdir=${PREFIX}/pkgconfig/armeabi 
        --arch=arm 
        --cpu=armv6 
        --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- 
        --sysroot=$SYSROOT 
        --extra-ldexeflags=-pie 
        ${COMMON_OPTIONS}
        make clean
        make -j8 && make install
        echo "结束编译FFmpeg(armeabi)"
    
        # armeabi-v7a
        echo "开始编译FFmpeg(armeabi-v7a)"
        ./configure 
        --libdir=${PREFIX}/libs/armeabi-v7a 
        --incdir=${PREFIX}/include/armeabi-v7a 
        --pkgconfigdir=${PREFIX}/pkgconfig/armeabi-v7a 
        --arch=arm 
        --cpu=armv7-a 
        --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- 
        --sysroot=$SYSROOT 
        --extra-cflags="-march=armv7-a -mfloat-abi=softfp -mfpu=neon" 
        --extra-ldexeflags=-pie 
        ${COMMON_OPTIONS}
        make clean
        make -j8 && make install
        echo "结束编译FFmpeg(armeabi-v7a)"
    
        # arm64-v8a
        echo "开始编译FFmpeg(arm64-v8a)"
        ./configure 
        --libdir=${PREFIX}/libs/arm64-v8a 
        --incdir=${PREFIX}/include/arm64-v8a 
        --pkgconfigdir=${PREFIX}/pkgconfig/arm64-v8a 
        --arch=aarch64 
        --cpu=armv8-a 
        --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- 
        --sysroot=$SYSROOT 
        --extra-ldexeflags=-pie 
        ${COMMON_OPTIONS} 
        make clean
        make -j8 && make install
        echo "结束编译FFmpeg(arm64-v8a)"
    
        # x86_64
        echo "开始编译FFmpeg(x86_64)"
        ./configure 
        --libdir=${PREFIX}/libs/x86_64 
        --incdir=${PREFIX}/include/x86_64 
        --pkgconfigdir=${PREFIX}/pkgconfig/x86_64 
        --arch=x86_64 
        --cpu=x86_64 
        --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- 
        --sysroot=$SYSROOT 
        --extra-ldexeflags=-pie 
        ${COMMON_OPTIONS}
        make clean
        make -j8 && make install
        echo "结束编译FFmpeg(x86_64)"
    
        echo "编译结束"
    
    };
    build_android
    macos_build_android.sh

    用于编译x86版本的

    #!/bin/bash
    
    echo "进入FFmpeg编译脚本"
    
    # NDK环境    
    export NDK=/Users/haiyuegao/Library/Android/android-ndk-r14b
    export SYSROOT=$NDK/platforms/android-21/arch-x86
    export TOOLCHAIN=$NDK/toolchains/x86-4.9/prebuilt/darwin-x86_64
    PREFIX=android-build
    
    COMMON_OPTIONS="
        --prefix=android/ 
        --target-os=android 
        --enable-shared 
        --enable-runtime-cpudetect 
        --enable-small 
        --disable-static 
        --disable-debug 
        --disable-ffmpeg 
        --disable-ffplay 
        --disable-ffprobe 
        --disable-ffserver 
        --disable-doc 
        --disable-symver 
        --disable-asm 
        --disable-stripping 
        --disable-armv5te 
        "
    
    function build_android {
    
        echo "开始编译FFmpeg..."
    
        # x86
        echo "开始编译FFmpeg(x86)"
        ./configure 
        --libdir=${PREFIX}/libs/x86 
        --incdir=${PREFIX}/include/x86 
        --pkgconfigdir=${PREFIX}/pkgconfig/x86 
        --arch=x86 
        --cpu=i686 
        --cross-prefix=$TOOLCHAIN/bin/i686-linux-android- 
        --sysroot=$SYSROOT 
        --extra-cflags="-Os -fpic -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32" 
        --extra-ldexeflags=-pie 
        ${COMMON_OPTIONS} 
        make clean
        make -j8 && make install
        echo "结束编译FFmpeg(x86)"
    
    
        echo "编译结束"
    
    };
    build_android
    macos_build_android_x86.sh

    需要注意的是:要根据自己电脑的实际环境修改下上面的NDK目录地址,我的NDK地址是:

    5. 修改脚本的执行权限。将脚本放置到ffmpeg的根目录下,为其添加执行权限:

    然后打开终端,cd到ffmpeg那级目录,分别执行以下两条命令(如果要编译x86版本,就把shell脚本的名字换成x86版本的那个):

    chmod 777 macos_build_android.sh 
    ./macos_build_android.sh

    6. 开始编译。视电脑的配置不同编译的时间也不同,我电脑用了大约5分钟左右完成了编译。

    等待编译完成,稍后ffmpeg那级目录会出现一个android-build文件夹,里面包含了我们会用到的库文件和头文件。

    二. 集成FFmpeg到项目中

    1. 新建一个支持C++的Android Studio 项目。

    2. 拷贝ffmpeg库文件和头文件。将编译生成的libs文件夹和include文件夹分别拷贝到项目的app目录下:

    3. 更新配置文件。

    修改app目录下的build.gradle文件:

    添加下列代码到gradle文件:

        externalNativeBuild {
                cmake {
                    cppFlags "-std=c++11"
                }
                ndk {
                    abiFilters "armeabi-v7a","x86"
                }
            }
            sourceSets {
                main {
                    jniLibs.srcDirs=['libs']
                }
            }
    externalNativeBuild {
            cmake {
                path "CMakeLists.txt"
            }
        }

    最终文件如下:

    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 28
        defaultConfig {
            applicationId "com.yongdaimi.android.ffapitest"
            minSdkVersion 19
            targetSdkVersion 28
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
            externalNativeBuild {
                cmake {
                    cppFlags "-std=c++11"
                }
                ndk {
                    abiFilters "armeabi-v7a","x86"
                }
            }
            sourceSets {
                main {
                    jniLibs.srcDirs=['libs']
                }
            }
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
        externalNativeBuild {
            cmake {
                path "CMakeLists.txt"
            }
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'com.android.support:appcompat-v7:28.0.0'
        implementation 'com.android.support.constraint:constraint-layout:1.1.3'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    }
    build.gradle

    修改app目录下的CMakeLists.txt文件:

    # For more information about using CMake with Android Studio, read the
    # documentation: https://d.android.com/studio/projects/add-native-code.html
    
    # Sets the minimum version of CMake required to build the native library.
    
    cmake_minimum_required(VERSION 3.4.1)
    
    # Creates and names a library, sets it as either STATIC
    # or SHARED, and provides the relative paths to its source code.
    # You can define multiple libraries, and CMake builds them for you.
    # Gradle automatically packages shared libraries with your APK.
    
    
    # 添加头文件路径
    include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/${ANDROID_ABI})
    
    
    # 设置FFmpeg库所在路径
    set(FF ${CMAKE_CURRENT_SOURCE_DIR}/libs/${ANDROID_ABI})
    
    # 打印当前位置信息
    message("Current souce file positon: " ${CMAKE_CURRENT_SOURCE_DIR})
    
    
    # avcodec
    add_library(avcodec SHARED IMPORTED)
    set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${FF}/libavcodec.so)
    
    
    add_library( # Sets the name of the library.
            native-lib
    
            # Sets the library as a shared library.
            SHARED
    
            # Provides a relative path to your source file(s).
            src/main/cpp/native-lib.cpp)
    
    # Searches for a specified prebuilt library and stores the path as a
    # variable. Because CMake includes system libraries in the search path by
    # default, you only need to specify the name of the public NDK library
    # you want to add. CMake verifies that the library exists before
    # completing its build.
    
    find_library( # Sets the name of the path variable.
            log-lib
    
            # Specifies the name of the NDK library that
            # you want CMake to locate.
            log)
    
    # Specifies libraries CMake should link to your target library. You
    # can link multiple libraries, such as libraries you define in this
    # build script, prebuilt third-party libraries, or system libraries.
    
    target_link_libraries( # Specifies the target library.
            native-lib
            avcodec
    
            # Links the target library to the log library
            # included in the NDK.
            ${log-lib})
    CMakeLists.txt

    最终目录结构如下:

    这里一定要注意CMakeLists.txt这个文件的位置,我在Windows下创建AS项目时这个文件在app目录下,在Mac上创建AS项目时这个文件却在app/src/main/cpp目录下,个人为了保持习惯,便将这个文件仍然移动到了app目录下,若使用Mac上默认的位置,则上述CMakeLists.txt和build.gradle中声明文件的位置部分也需要修改,切记。

    4. 添加测试代码。打开native-lib.cpp,修改已有的JNI方法:

    #include <jni.h>
    #include <string>
    
    
    extern "C" {
    #include <libavcodec/avcodec.h>
    }
    
    extern "C" JNIEXPORT jstring JNICALL
    Java_com_yongdaimi_android_ffapitest_MainActivity_stringFromJNI(
            JNIEnv *env,
            jobject /* this */) {
        std::string hello = "Hello from C++";
    
        hello += avcodec_configuration();
    
    
        return env->NewStringUTF(hello.c_str());
    } 

    由于FFmpeg是使用纯C编写的,因此在导入其头文件的时候要注意使用extern "C" 大括号包裹。

    之后运行项目,如果能出现相关的配置信息就说明FFmpeg已经加载成功了。

    三. 常见错误说明

    1. Error computing CMake server result.

    若编译出现

    Error computing CMake server result.
    Check for working C compiler: D:/sdk/sdk/ndk-bundle/toolchains/llvm/prebuilt/windows-x86_64/bin/clang.exe
    Check for working C compiler: D:/sdk/sdk/ndk-bundle/toolchains/llvm/prebuilt/windows-x86_64/bin/clang.exe -- works
    Detecting C compiler ABI info
    Detecting C compiler ABI info - done
    Detecting C compile features
    Detecting C compile features - done
    Check for working CXX compiler: D:/sdk/sdk/ndk-bundle/toolchains/llvm/prebuilt/windows-x86_64/bin/clang++.exe
    Check for working CXX compiler: D:/sdk/sdk/ndk-bundle/toolchains/llvm/prebuilt/windows-x86_64/bin/clang++.exe -- works
    Detecting CXX compiler ABI info
    Detecting CXX compiler ABI info - done
    Detecting CXX compile features
    Detecting CXX compile features - done
    Boost version: 1.70.0
    Configuring for JNI
    Configuring done

    则打开Build的Toggle View按钮,根据Log分析出错的详细原因,看看是native-lib.cpp的文件找不到或者是其它问题。

    2. ninja error needed by missing and no known rule to make it

    Error:error: '../../../../src/main/jniLibs/x86/libstblur_preview_api.so', 
    needed by '../../../../build/intermediates/cmake/debug/obj/x86/libjnistblur_preview_api.so', missing and no known rule to make it

    这种错误一般是缺失了某个平台的库导致的,首先查看具体缺失的是哪个平台的so库,如果该平台的库不需要,可以在app下的build.gradle中声明不加载:

         ndk {
                // 声明只使用这两个版本的库,否则默认的可是4个平台
                abiFilters 'armeabi-v7a','arm64-v8a'
            }

    或者是检查下CMakeLists.txt中FFmpeg库的路径声明是否正确:

    比如我这里声明的库路径就是app/libs/具体的平台。

    参考链接:

    1.  FFmpeg编译For Android(Mac)

    2. 在Mac中编译Android平台的FFmpeg( arm和x86

  • 相关阅读:
    单例模式
    属性和方法的调用
    整型数从最小到最大取值,二进制变动机制
    java数据类型
    插入字符,数组顺序不变
    运算符“/”
    CentOS7 防火墙(firewall)的操作命令(转)
    面试题4(剑指)-螺旋打印矩阵
    面试题3(剑指)-重建二叉树
    面试题2——遍历二叉树
  • 原文地址:https://www.cnblogs.com/yongdaimi/p/11284118.html
Copyright © 2011-2022 走看看