美文网首页
Mac 下编译FFmpeg并在Android Studio集成.

Mac 下编译FFmpeg并在Android Studio集成.

作者: goodfree | 来源:发表于2020-11-11 09:37 被阅读0次

    环境

    • OS:macOS Catalina 10.15.7
    • IDE:Android Studio 4.1
    • FFmpeg Version:4.3

    下载

    git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg
    

    使用Homebrew下载

    Mac-Pro:~ andy$ brew search ffmpeg
    ==> Formulae
    ffmpeg ✔            ffmpeg2theora       ffmpeg@2.8          ffmpegthumbnailer
    

    查看版本

    Mac-Pro:~ andy$ ffmpeg -version
    ffmpeg version 4.3 Copyright (c) 2000-2020 the FFmpeg developers
    built with Apple clang version 12.0.0 (clang-1200.0.32.2)
    configuration: 
    libavutil      56. 51.100 / 56. 51.100
    libavcodec     58. 91.100 / 58. 91.100
    libavformat    58. 45.100 / 58. 45.100
    libavdevice    58. 10.100 / 58. 10.100
    libavfilter     7. 85.100 /  7. 85.100
    libswscale      5.  7.100 /  5.  7.100
    libswresample   3.  7.100 /  3.  7.100
    

    如果使用的是brew 下载的ffmpeg,它的目录在 /usr/local/Cellar/ffmpeg

    编写脚本

    单编

    在ffmpeg根目录创建build_android_clang.sh并添加以下代码

    touch build_android_clang.sh && vim build_android_clang.sh
    
    #!/bin/bash
    # 目标Android版本
    API=28
    # x86、x86_64、armeabi、armeabi-v7a、arm64-v8a
    CPU=$1
    # so库输出目录
    OUTPUT=/Users/andy/Development/workspace/StudioProjects/rep/ffmpeg-4.3/android/$CPU
    # NDK的路径,根据自己的NDK位置进行设置
    NDK=/Users/andy/Library/Android/sdk/ndk-bundle
    # 编译工具链路径
    TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
    # 编译环境
    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
      make -j12
      make install
    }
    build
    

    编译方式1(带参数):

    Mac-Pro:ffmpeg-4.3 andy$ . build_android_clang.sh "x86"
    

    编译方式2(不带参数):修改脚本把 CPU=$1替换成CPU=x86,然后直接执行

    Mac-Pro:ffmpeg-4.3 andy$ . build_android_clang.sh
    

    引用外文:如果编译出现失败,请尝试如下方案,修改configure,使用clang轻量编译器;

    1.CMDLINE_SET中添加cross_prefix_clang

    2.修改使用的默认交叉编译工具

    ## 替换前
    cc_default="${cross_prefix}${cc_default}"
    cxx_default="${cross_prefix}${cxx_default}"
    
    ##替换后
    cc_default="${cross_prefix_clang}${cc_default}"
    cxx_default="${cross_prefix_clang}${cxx_default}"
    

    https://www.jianshu.com/p/350f8e083e82

    其实查看configure配置,结合编译脚本配合的变量

    ${cross_prefix} = --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- 
    
    ${cross_prefix_clang} = --cross-prefix-clang=$TOOLCHAIN/bin/armv7a-linux-androideabi$API- 
    

    整编,一次性编译x86、x86_64、armeabi、armeabi-v7a、arm64-v8a,这里引用了外文脚本,并加以修改

    https://www.jianshu.com/p/0a7f3175c1b9

    但也可以修改单编译的脚本,其实就是增加fun 里面使用一个for或者while,修改一下脚本变量参数即可(要懂一些shell基本语法);附--arch=arm \ --cpu=armv7-a \

    for cpu in 'x86' 'x86_64' 'armeabi' 'armeabi-v7a' 'arm64-v8a'
    do
        echo "start build ${cpu}"
        build ${cpu}
    done
    

    整编

    脚本文件,build_ffmpeg.sh

    #!/bin/bash
    NDK_PATH=/Users/andy/Library/Android/sdk/ndk-bundle
    HOST_PLATFORM=darwin-x86_64
    API=29
    
    TOOLCHAINS="$NDK_PATH/toolchains/llvm/prebuilt/$HOST_PLATFORM"
    SYSROOT="$TOOLCHAINS/sysroot"
    CFLAG="-D__ANDROID_API__=$API -Os -fPIC -DANDROID "
    LDFLAG="-lc -lm -ldl -llog "
    
    PREFIX=android-build
    
    CONFIG_LOG_PATH=${PREFIX}/log
    COMMON_OPTIONS=
    CONFIGURATION=
    
    build() {
      APP_ABI=$1
      echo "======== > Start build $APP_ABI"
      case ${APP_ABI} in
      armeabi-v7a)
        ARCH="arm"
        CPU="armv7-a"
        MARCH="armv7-a"
        TARGET=armv7a-linux-androideabi
        CC="$TOOLCHAINS/bin/$TARGET$API-clang"
        CXX="$TOOLCHAINS/bin/$TARGET$API-clang++"
        LD="$TOOLCHAINS/bin/$TARGET$API-clang"
        CROSS_PREFIX="$TOOLCHAINS/bin/arm-linux-androideabi-"
        EXTRA_CFLAGS="$CFLAG -mfloat-abi=softfp -mfpu=vfp -marm -march=$MARCH "
        EXTRA_LDFLAGS="$LDFLAG"
        EXTRA_OPTIONS="--enable-neon --cpu=$CPU "
        ;;
      arm64-v8a)
        ARCH="aarch64"
        TARGET=$ARCH-linux-android
        CC="$TOOLCHAINS/bin/$TARGET$API-clang"
        CXX="$TOOLCHAINS/bin/$TARGET$API-clang++"
        LD="$TOOLCHAINS/bin/$TARGET$API-clang"
        CROSS_PREFIX="$TOOLCHAINS/bin/$TARGET-"
        EXTRA_CFLAGS="$CFLAG"
        EXTRA_LDFLAGS="$LDFLAG"
        EXTRA_OPTIONS=""
        ;;
      x86)
        ARCH="x86"
        CPU="i686"
        MARCH="i686"
        TARGET=i686-linux-android
        CC="$TOOLCHAINS/bin/$TARGET$API-clang"
        CXX="$TOOLCHAINS/bin/$TARGET$API-clang++"
        LD="$TOOLCHAINS/bin/$TARGET$API-clang"
        CROSS_PREFIX="$TOOLCHAINS/bin/$TARGET-"
        EXTRA_CFLAGS="$CFLAG -march=$MARCH -mtune=intel -mssse3 -mfpmath=sse -m32"
        EXTRA_LDFLAGS="$LDFLAG"
        EXTRA_OPTIONS="--cpu=$CPU "
        ;;
      x86_64)
        ARCH="x86_64"
        CPU="x86-64"
        MARCH="x86_64"
        TARGET=$ARCH-linux-android
        CC="$TOOLCHAINS/bin/$TARGET$API-clang"
        CXX="$TOOLCHAINS/bin/$TARGET$API-clang++"
        LD="$TOOLCHAINS/bin/$TARGET$API-clang"
        CROSS_PREFIX="$TOOLCHAINS/bin/$TARGET-"
        EXTRA_CFLAGS="$CFLAG -march=$CPU -mtune=intel -msse4.2 -mpopcnt -m64"
        EXTRA_LDFLAGS="$LDFLAG"
        EXTRA_OPTIONS="--cpu=$CPU "
        ;;
      esac
    
      echo "-------- > Start clean workspace"
      make clean
    
      echo "-------- > Start build configuration"
      CONFIGURATION="$COMMON_OPTIONS"
      CONFIGURATION="$CONFIGURATION --logfile=$CONFIG_LOG_PATH/config_$APP_ABI.log"
      CONFIGURATION="$CONFIGURATION --prefix=$PREFIX"
      CONFIGURATION="$CONFIGURATION --libdir=$PREFIX/libs/$APP_ABI"
      CONFIGURATION="$CONFIGURATION --incdir=$PREFIX/includes/$APP_ABI"
      CONFIGURATION="$CONFIGURATION --pkgconfigdir=$PREFIX/pkgconfig/$APP_ABI"
      CONFIGURATION="$CONFIGURATION --cross-prefix=$CROSS_PREFIX"
      CONFIGURATION="$CONFIGURATION --arch=$ARCH"
      CONFIGURATION="$CONFIGURATION --sysroot=$SYSROOT"
      CONFIGURATION="$CONFIGURATION --cc=$CC"
      CONFIGURATION="$CONFIGURATION --cxx=$CXX"
      CONFIGURATION="$CONFIGURATION --ld=$LD"
      CONFIGURATION="$CONFIGURATION $EXTRA_OPTIONS"
    
      echo "-------- > Start config makefile with $CONFIGURATION --extra-cflags=${EXTRA_CFLAGS} --extra-ldflags=${EXTRA_LDFLAGS}"
      ./configure ${CONFIGURATION} \
      --extra-cflags="$EXTRA_CFLAGS" \
      --extra-ldflags="$EXTRA_LDFLAGS"
    
      echo "-------- > Start make $APP_ABI with -j8"
      make -j10
    
      echo "-------- > Start install $APP_ABI"
      make install
      echo "++++++++ > make and install $APP_ABI complete."
    
    }
    
    build_all() {
    
      COMMON_OPTIONS="$COMMON_OPTIONS --target-os=android"
      COMMON_OPTIONS="$COMMON_OPTIONS --disable-static"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-shared"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-protocols"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-cross-compile"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-optimizations"
      COMMON_OPTIONS="$COMMON_OPTIONS --disable-debug"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-small"
      COMMON_OPTIONS="$COMMON_OPTIONS --disable-doc"
      COMMON_OPTIONS="$COMMON_OPTIONS --disable-programs"
      COMMON_OPTIONS="$COMMON_OPTIONS --disable-ffmpeg"
      COMMON_OPTIONS="$COMMON_OPTIONS --disable-ffplay"
      COMMON_OPTIONS="$COMMON_OPTIONS --disable-ffprobe"
      COMMON_OPTIONS="$COMMON_OPTIONS --disable-symver"
      COMMON_OPTIONS="$COMMON_OPTIONS --disable-network"
      COMMON_OPTIONS="$COMMON_OPTIONS --disable-x86asm"
      COMMON_OPTIONS="$COMMON_OPTIONS --disable-asm"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-pthreads"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-mediacodec"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-jni"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-zlib"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-pic"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-avresample"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=h264"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=mpeg4"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=mjpeg"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=png"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=vorbis"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=opus"
      COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=flac"
    
      echo "COMMON_OPTIONS=$COMMON_OPTIONS"
      echo "PREFIX=$PREFIX"
      echo "CONFIG_LOG_PATH=$CONFIG_LOG_PATH"
    
      mkdir -p ${CONFIG_LOG_PATH}
    
      build "armeabi-v7a"
      build "arm64-v8a"
      build "x86"
      build "x86_64"
    }
    
    echo "-------- Start --------"
    
    build_all
    
    echo "-------- End --------"
    

    其实以上代码略显复杂,同时也缺少了armeabi,等待编译完成后查看.so

    单编、整编so库目录

    Mac-Pro:x86 andy$ ls
    libavcodec.so         libavformat.so        libswscale.so
    libavdevice.so      libavutil.so         
    libavfilter.so      libswresample.so
    
    iShot2020-11-10 10.17.49.png iShot2020-11-10 10.18.23.png

    集成Android Studio

    新建Native C++项目,复制编译好的so和头文件到相应目录,截图如下


    iShot2020-11-10 14.09.47.png

    build.gradle

    defaultConfig{
    
        ...
        
        externalNativeBuild {
           cmake {
             cppFlags "-frtti -fexceptions"
          }
         }
       ndk {
          //默认生成平台架构armeabi、x86、x86_64、armeabi-v7a、arm64-v8a
          abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
       }
    }
    
    sourceSets {
            main {
                jniLibs.srcDirs = ['libs']
            }
     }
     
     
     externalNativeBuild {
            cmake {
               //makefile编译语言文件路径,默认新建的C++项目会放在cpp目录下,这里我移到src/main/根目下了
               path "src/main/CMakeLists.txt"
               version "3.10.2"
            }
        }
        
    

    CMakeLists.txt

    cmake_minimum_required(VERSION 3.10.2)
    
    project("myapplication")
    
    # 支持gnu++11 //默认创建C++时可选择C++11、C++14、C++17交叉工具链
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
    
    # 1. 定义so库和头文件所在目录
    set(ffmpeg_lib_dir ${CMAKE_SOURCE_DIR}/jniLibs/${ANDROID_ABI})
    set(ffmpeg_head_dir ${CMAKE_SOURCE_DIR}/cpp/ffmpeg)
    
    
    # 2. 添加头文件目录
    include_directories(${ffmpeg_head_dir}/includes)
    
    ## log在3.10.3不显示,需要降级3.6.0或者3.4.1
    message("cmake_source_dir = ${CMAKE_SOURCE_DIR}")
    message("ffmpeg_lib_dir = ${ffmpeg_lib_dir}")
    message("ffmpeg_head_dir = ${ffmpeg_head_dir}")
    
    # 3. 添加ffmpeg相关的so库
    
    ## 编解码器库
    add_library(
            avcodec
            SHARED
            IMPORTED)
    set_target_properties(
            avcodec
            PROPERTIES IMPORTED_LOCATION
            ${ffmpeg_lib_dir}/libavcodec.so)
    ## 设备库
    add_library(
            avdevice
            SHARED
            IMPORTED)
    set_target_properties(
            avdevice
            PROPERTIES IMPORTED_LOCATION
            ${ffmpeg_lib_dir}/libavdevice.so)
    ## 滤镜库
    add_library(
            avfilter
            SHARED
            IMPORTED)
    set_target_properties(
            avfilter
            PROPERTIES IMPORTED_LOCATION
            ${ffmpeg_lib_dir}/libavfilter.so)
    ## 格式库
    add_library(
            avformat
            SHARED
            IMPORTED)
    set_target_properties(
            avformat
            PROPERTIES IMPORTED_LOCATION
            ${ffmpeg_lib_dir}/libavformat.so)
    ## 资源重采集库
    add_library(
            avresample
            SHARED
            IMPORTED)
    set_target_properties(
            avresample
            PROPERTIES IMPORTED_LOCATION
            ${ffmpeg_lib_dir}/libavresample.so)
    ## 工具库
    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(
            swscale
            SHARED
            IMPORTED)
    set_target_properties(
            swscale
            PROPERTIES IMPORTED_LOCATION
            ${ffmpeg_lib_dir}/libswscale.so)
    
    add_library( # Sets the name of the library.
            native-lib
            SHARED
            cpp/native-lib.cpp)
    
    find_library( # Sets the name of the path variable.
            log-lib
            log)
    
    target_link_libraries( # Specifies the target library.
            native-lib
    
            # ffmpeg库关联
            avcodec
            avdevice
            avfilter
            avformat
            avresample
            avutil
            swresample
            swscale
    
            # Links the target library to the log library
            # included in the NDK.
            ${log-lib})
    

    native-lib.cpp

    extern "C" {
        #include <libavcodec/avcodec.h>
        #include <libavdevice/avdevice.h>
        #include <libavfilter/avfilter.h>
        #include <libavformat/avformat.h>
        #include <libavutil/avutil.h>
        #include <libswresample/swresample.h>
        #include <libswscale/swscale.h>
        JNIEXPORT jstring JNICALL
    
        Java_top_andy_myapplication_FFmpegActivity_ffmpegConfigInfo(JNIEnv *env, jobject thiz) {
            return env->NewStringUTF(avdevice_configuration());
        }
    
        //编解码器库
        JNIEXPORT jstring JNICALL
        Java_top_andy_myapplication_FFmpegActivity_avcodecInfo(JNIEnv *env, jobject thiz) {
        return env->NewStringUTF(avcodec_configuration());
        }
    
        //设备库
        JNIEXPORT jstring JNICALL
        Java_top_andy_myapplication_FFmpegActivity_avdeviceInfo(JNIEnv *env, jobject thiz) {
        return env->NewStringUTF(avdevice_configuration());
        }
    
        //滤镜库
        JNIEXPORT jstring JNICALL
        Java_top_andy_myapplication_FFmpegActivity_avfilterInfo(JNIEnv *env, jobject thiz) {
            return env->NewStringUTF(avfilter_configuration());
        }
    
        //格式库
        JNIEXPORT jstring JNICALL
        Java_top_andy_myapplication_FFmpegActivity_avformatInfo(JNIEnv *env, jobject thiz) {
            return env->NewStringUTF(avformat_configuration());
        }
    
        //工具库
        JNIEXPORT jstring JNICALL
        Java_top_andy_myapplication_FFmpegActivity_avutil(JNIEnv *env, jobject thiz) {
            return env->NewStringUTF(avutil_configuration());
        }
    
        //音频重采样库
        JNIEXPORT jstring JNICALL
        Java_top_andy_myapplication_FFmpegActivity_swresample(JNIEnv *env, jobject thiz) {
            return env->NewStringUTF(swresample_configuration());
        }
    
        //媒体缩放库(颜色转换和绽放)
        JNIEXPORT jstring JNICALL
        Java_top_andy_myapplication_FFmpegActivity_swscale(JNIEnv *env, jobject thiz) {
            return env->NewStringUTF(swscale_configuration());
        }
    }
    

    FFmpegActivity

    class FFmpegActivity : AppCompatActivity(){
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_ffmpeg_info)
    
    
            ffmpeg_info.text = ffmpegConfigInfo();
    
            avcodecInfo.setOnClickListener { ffmpeg_info.text = avcodecInfo() }
            avdeviceInfo.setOnClickListener { ffmpeg_info.text = avdeviceInfo() }
            avfilterInfo.setOnClickListener { ffmpeg_info.text = avfilterInfo() }
            avformatInfo.setOnClickListener { ffmpeg_info.text = avformatInfo() }
            avutil.setOnClickListener { ffmpeg_info.text = avutil() }
            swresample.setOnClickListener { ffmpeg_info.text = swresample() }
            swscale.setOnClickListener { ffmpeg_info.text = swscale() }
        }
    
    
    
        private external fun avcodecInfo():String //编解码器库
        private external fun avdeviceInfo():String //设备库
        private external fun avfilterInfo():String //滤镜库
        private external fun avformatInfo():String //格式库
        private external fun avutil():String //工具库
        private external fun swresample():String //音频重采样库
        private external fun swscale():String //媒体缩放库(颜色转换和绽放)
    
    
        private external fun ffmpegConfigInfo():String//FFmpeg配置信息
    
    
        companion object{
    
            init {
                System.loadLibrary("native-lib")
            }
        }
    

    Done

    相关文章

      网友评论

          本文标题:Mac 下编译FFmpeg并在Android Studio集成.

          本文链接:https://www.haomeiwen.com/subject/rbfebktx.html