MacOS编译ffmpeg并引入android

ffmpeg编译

编译环境:

  • 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
        # 新增命令行参数
        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

内容如下 具体内容需要根据自己电脑上面ndk环境进行修改

#!/bin/bash
set -x
# 目标Android版本
API=19
CPU=armv7-a
#so库输出目录
OUTPUT=/Users/tanyuanchao/Desktop/ffmpeg/ffmpeg-4.2.3/android/$CPU
# NDK的路径,根据自己的NDK位置进行设置
NDK=/Users/tanyuanchao/Library/Android/sdk/ndk/21.2.6472646
# 编译工具链路径
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
  # 这里是定义用几个CPU编译
  make -j12
  make install
}

build
  • 这里我android目标版本选择19
  • cpu架构选择armv7-a
  • 输出路径,ndk路径自己配置。

4.修改文件为可执行文件

chmod +x build_android_clang.sh

5.执行开始编译

./build_android_clang.sh

6.编译完成后得到的目录

image.png
  • include文件夹下为头文件
  • lib文件夹下为动态链接库.so文件

android中引入编译后的库

新建项目或者已有项目中进行以下操作

1.修改app的build.gradle新增如下内容

android {
    defaultConfig {
        // 新增1
        externalNativeBuild {
            cmake {
                cppFlags ""
                // 配置cmake编译的cpu架构,否则会还回去找其他架构,由于我们只编译的armeabi-v7a,所以找不到其他会报错
                abiFilters  'armeabi-v7a'
            }
        }
    }
        // 新增2
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }


}

2.创建jniLibs文件夹来放动态库!!!!这里有坑

  • 在下面新建armeabi-v7a文件夹然后将之前编译后的so文件拷贝进来
image.png

3.创建cpp文件夹

  • 在src/main/目录下新建cpp文件夹

  • cpp文件夹新建ffmpeg目录,然后将编译后的include文件夹全部拷贝过来

  • cpp文件夹新建native-lib.cpp,内容可以先不管,主要是返回ffmpeg的一些信息,用来后面测试是否成功

    #include 
    #include 
    #include 
    
    extern "C"{
    #include 
    #include 
    #include 
    #include 
    
    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库和头文件所在目录,方面后面使用
    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相关的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( 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 )
    
    
    # 查找代码中使用到的系统库
    find_library(
            log-lib
    
    
            log )
    
    # 配置目标so库编译信息
    add_library(
            native-lib
    
    
            SHARED
    
    
            native-lib.cpp
            )
    
    # 指定编译目标库时,cmake要链接的库
    target_link_libraries(
    
            # 指定目标库,native-lib 是在上面 add_library 中配置的目标库
            native-lib
    
            # 4. 连接 FFmpeg 相关的库
            avutil
            swresample
            avcodec
            avfilter
            swscale
            avformat
            avdevice
    
            # Links the target library to the log library
            # included in the NDK.
            ${log-lib} )
    
    
    

    第1步:设置动态库文件夹和头文件夹在你当前项目的目录位置

    第3步:依次将so库添加进来

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中初始化方法进行加载native-lib.cpp文件
  • 将textview内容设置为调用库文件返回的方法

5.进行运行

出现的问题

  • 如果运行到模拟器,且架构为x86会出现以下问题
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"

因为我们提供的so文件值提供了armeabi-v7a架构支持的,所以会出现这个问题,解决方案,换cpu架构的模拟器,或者直接运行到手机

  • 直接运行到手机,或者进行打包,出现的问题

    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
    

    还记得之前说的有坑的地方吧,创建的目录为jniLibs,找的很多方案,也不知道具体的原因,AS版本为4.0,然后尝试将jniLibs这个文件夹的名字修改,我将s去掉,然后修改CMakeLists.txt文件中的第一步

    # 1. 定义so库和头文件所在目录,方面后面使用
    set(ffmpeg_lib_dir ${CMAKE_SOURCE_DIR}/../jniLib/${ANDROID_ABI})
    

就可以打包成功了

运行效果

image.png

以上内容根据:开发的猫 的文章进行操作,记录实现过程中出现的问题

你可能感兴趣的:(MacOS编译ffmpeg并引入android)