美文网首页
windows编译FFmpeg for Android 和And

windows编译FFmpeg for Android 和And

作者: DD_Dog | 来源:发表于2019-11-19 20:58 被阅读0次

FFmpeg的编译是一个大坑,尤其是编译安卓平台的动态库和静态库,应用于APP中。在Linux平台编译是相对简单的,但是我经过尝试在Linux编译静态库没有成功,所以又在windows平台尝试编译了ffempg的动态库,应用成功了,这里分享一下。

一、搭建编译环境

  1. NDK 版本r14
  2. MinGW,minGW可以提供gcc编译环境,所以我们才能在windows进行编译
  3. FFMPEG源码 版本3.3.9

注意一定要注意NDK和FFmpeg的版本,如果你按照我的文章来的那就一定要下载NDK版本R14和FFmpeg版本3.3.9,并不一定要新版本,因为不同的FFmpeg需要不同版本的NDK支持,本文中的是验证过的。minGW的版本不用关心。

1.1 NDK配置

我使用的AndroidStudio,刚开始用自带的ndk-buidle进行编译,是通不过的,后来换到r14版本才能编译通过。
解压下载好的文件android-ndk-r14b-windows-x86_64.zip到固定目录,尽量不要有中文,我的路径:D:\Android\android-ndk-r14b。接下来配置到环境变量:
进入计算机->属性->高级系统设置->环境变量,在系统环境中新建NDK_PATH,目录为刚才解压的NDK14的目录,如下:

image.png

再打开PATH,添加刚才新建的NDK_PATH:

image.png
然后一路确定后,测试是否配置成功。
打开cmd命令行,输入ndk-build,如果成功有类似如下显示:
image.png

1.2 minGW安装配置

打开.exe文件,选择安装位置,我的安装目录是D:\programs\minGW
点击需要安装的组件,我选择全部勾选:

image.png
安装完成后,需要把两个路径添加到环境变量:D:\programs\minGWD:\programs\minGW\msys\1.0\bin
image.png

测试一下minGW是否配置成功:


image.png

如果就是配置成功了。

1.3 下载FFmpeg源码

切记一定下载3.3.9版本的,我试过编译4.0的是编译不过的。


image.png

下载后解压即可。

二、FFmpeg源码编译

那么问题来了,怎么执行编译命令呢?
这时候minGW上场了,还记得D:\programs\minGW\mysys\1.0\吗,它下面有一个msys.bat文件,双击打开就是类似于shell的环境。

2.1 修改生成的lib库文件名

编译之前首先要做件事情,就是修改源码目录下的configure文件,因为我要的是Android平台的so库,所以要在配置文件中修改生成的库名称。使用记事本打开就行,修改方案如下:

# 原来的配置内容:
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)'

什么?你问我直接编译完了修改文件行不行,我认为是不行的,当然我也测试过。反正按照我说的做,保证行。

2.2开始编译

编译都是分三个步骤:

  1. configure
  2. make
  3. make install
    因为ffmpeg编译时configure的参数很多,直接写在命令行会很麻烦,我们把这些写在脚本里面就很方便了:

#!/bin/bash
#NDK路径根据你自己设置的决定,注意不要直接拷贝window路径,因为linux不识别`\`,要使用`/`
NDK=D:/Android/android-ndk-r14b
SYSROOT=$NDK/platforms/android-18/arch-arm
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64
 
function build_one
{
./configure \
    --prefix=$PREFIX \
    --enable-shared \
    --disable-static \
    --disable-doc \
    --enable-cross-compile \
    --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
    --target-os=linux \
    --arch=armv7-a \  //注意平台
    --sysroot=$SYSROOT \
    --extra-cflags="-Os -fpic $ADDI_CFLAGS" \
    --extra-ldflags="$ADDI_LDFLAGS" \
    $ADDITIONAL_CONFIGURE_FLAG
}
CPU=armv7-a
PREFIX=$(pwd)/android/$CPU
ADDI_CFLAGS="-marm"
build_one
 
read -p "Press any key to continue."

保存为build_android.sh,其它名字也行。
注意里面的参数arch=armv7-a,新版的AndroidStudio已经不支持armeabi了,在使用so库的时候要与arch参数对应,后面会讲到。

打开mysys.bat,进入FFmpeg的源码目录:


image.png

添加可执行权限:

chmod 777 build_android.sh
image.png
可以看到,使用ls -l是看不到有可执行权限的,不过没关系。

步骤一、执行configure

./build_android.sh  //这里要等待较长的时间,我等了七八分钟的样子才有反应

如果没有报错的话就会打印:

Press any key to continue.  //按任意键退出脚本

步骤二、执行make

make //这一步会编译所有的.c文件,生成很多的.o文件,时间较长

步骤三、执行make install

make install   //这一步会生成头文件和lib库到步骤一中configure指定的路径android/armv7-a目录

执行这几步过程中可能会出错,如果出错,请严格对比版本号和环境变量是否正确。
生成文件目录如下:


image.png
image.png

接下来就是在AndroidStudio中使用了。

什么?为什么有带数字的,有不带数字的,该用哪个呢?用带数字的,至于为什么我也不知道,反正我试过只能用带数字的。

三、在AndroidStudio中使用编译好的FFmpeg库

我使用的较新的AndroidStudio版本,为什么要说这个呢?因为新版的AndroidStudio支持使用cmake,而不需要自己写Android.mk和Application.mk这些文件了。所以需要一定的cmake语法知识,大家可以自行搜索,需要几个简单的就行,我也会给出注释。


image.png

3.1 新建工程/Module

你需要新建支持c++的工程,再新建Module。如果你使用的工程不支持c++,新建Module时参考android studio: 为现有项目添加C++支持也可以。
我新建的支持C++的工程:

image.png
在默认Module里面会生成默认的两个文件:
image.png

build.gradle中也会生成JNI相关配置:

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        ...
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt" //cmake配置文件路径
            version "3.10.2"
        }
    }
}

3.2 本地方法并生成头文件

java代码如下:

 public class NativeAPI {

    public static native String stringFromJNI();

    public static native String urlprotocolinfo();

    public static native String avformatinfo();

    public static native String avcodecinfo();

    public static native String avfilterinfo();
}

生成头文件,如果不知道怎么快速生成,请参考AndroidStudio JNI 快速生成头文件

3.3 编写本地方法的实现

首先要引入FFmpeg库文件,拷贝so库到libs文件夹:


image.png

拷贝FFmpeg的头文件到指定目录,这个目录并不确定,只要在CMakeList.txt中引入即可:


image.png

修改build.gradle文件,在defaultconfig中添加指定平台,还记得编译FFmpeg时的arch=armv7-a参数吧,一定要对应,否则编译可以通过,但是运行时会报错。

//指定平台,与编译FFmpeg时的arch参数对应
ndk{
     abiFilters 'armeabi-v7a'
}

//指定SO库路径

3.4 CMakeList.txt

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

#lib库工程名,并非so生成的so库名称,可以不写
project(TestFFmpeg)

# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)

#包含指定目录的头文件
include_directories(include/)

#添加库文件 参数:生成的库名称  动态库(即so库) 源文件
add_library(native-lib SHARED native-lib.cpp)

#创建导入的库目标,FFmpeg7个SO库
add_library(avutil-55 SHARED IMPORTED)
add_library(swresample-2 SHARED IMPORTED)
add_library(avcodec-57 SHARED IMPORTED)
add_library(avfilter-6 SHARED IMPORTED)
add_library(swscale-4 SHARED IMPORTED)
add_library(avdevice-57 SHARED IMPORTED)
add_library(avformat-57 SHARED IMPORTED)

#设置变量,CMAKE_SOURCE_DIR是CMakeList.txt的路径
set(LIB_DIR ${CMAKE_SOURCE_DIR}/../../../libs/${ANDROID_ABI})

#message(SEND_ERROR  "jni libs dir=${LIB_DIR}")

#设置目标属性,例如avutil-55的IMPORTED_LOCATION属性值是${LIB_DIR}/libavutil-55.so
set_target_properties(avutil-55 PROPERTIES IMPORTED_LOCATION ${LIB_DIR}/libavutil-55.so)
set_target_properties(swresample-2 PROPERTIES IMPORTED_LOCATION ${LIB_DIR}/libswresample-2.so)
set_target_properties(avcodec-57 PROPERTIES IMPORTED_LOCATION ${LIB_DIR}/libavcodec-57.so)
set_target_properties(avfilter-6 PROPERTIES IMPORTED_LOCATION ${LIB_DIR}/libavfilter-6.so)
set_target_properties(swscale-4 PROPERTIES IMPORTED_LOCATION ${LIB_DIR}/libswscale-4.so)
set_target_properties(avdevice-57 PROPERTIES IMPORTED_LOCATION ${LIB_DIR}/libavdevice-57.so )
set_target_properties(avformat-57 PROPERTIES IMPORTED_LOCATION ${LIB_DIR}/libavformat-57.so)

#在指定目录下搜索一个库, 保存在变量中
find_library(
        # 变量名
        log-lib

        #搜索log库
        log)

#目标文件与库文件进行链接
target_link_libraries(
        # Specifies the target library.
        native-lib

        # Links the target library to the log library
        # included in the NDK.
        avutil-55
        swresample-2
        avcodec-57
        avfilter-6
        swscale-4
        avdevice-57
        avformat-57
        ${log-lib})

native-lib.cpp

没有写完整,最后有Demo地址

extern "C" {
//因为FFmpeg是C库,所以要在extern "C"里面
#include "include/com_flyscale_testforffmpeg_NativeAPI.h"
#include "include/libavformat/avformat.h"
#include "include/libavutil/avutil.h"
#include "include/libavfilter/avfilter.h"
#include "include/libavcodec/avcodec.h"


JNIEXPORT jstring JNICALL Java_com_flyscale_testforffmpeg_NativeAPI_urlprotocolinfo
        (JNIEnv *env, jclass clazz) {
    char info[40000] = {0};
    av_register_all();

    struct URLProtocol *pup = NULL;

    struct URLProtocol **p_temp = &pup;
    avio_enum_protocols((void **) p_temp, 0);

    while ((*p_temp) != NULL) {
        sprintf(info, "%sInput: %s\n", info, avio_enum_protocols((void **) p_temp, 0));
    }
    pup = NULL;
    avio_enum_protocols((void **) p_temp, 1);
    while ((*p_temp) != NULL) {
        sprintf(info, "%sInput: %s\n", info, avio_enum_protocols((void **) p_temp, 1));
    }
    return env->NewStringUTF(info);
}
...

运行即可。
Demo下载地址

参考:

android开发-Windows环境下编译FFMPEG源码
AndroidStudio中使用FFMPEG入门

Android Studio 中的 CMake message 输出位置在哪里

相关文章

网友评论

      本文标题:windows编译FFmpeg for Android 和And

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