美文网首页
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