美文网首页
MacOS编译ffmpeg并引入android

MacOS编译ffmpeg并引入android

作者: eliteTyc | 来源:发表于2020-06-17 12:55 被阅读0次

    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 <jni.h>
      #include <string>
      #include <unistd.h>
      
      extern "C"{
      #include <libavcodec/avcodec.h>
      #include <libavformat/avformat.h>
      #include <libavfilter/avfilter.h>
      #include <libavcodec/jni.h>
      
      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

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