ffmpeg源码编译详细过程与使用(含demo)

1,369 阅读5分钟

前言

关于ffmpeg so库的编译,网上存在各种教程。有些基于windows,有些基于linux~而基于linux的:一般会选择安装虚拟机,在其上跑ubuntu系统。其实各种方式都是可以的,只要最后可以编译出我们需要的so库,就是正道。

win10开始自带了linux的子系统,我们可以直接使用该子系统进行编译工作,而无需安装虚拟机等繁琐流程。本章将详细罗列完整流程,大致流程会跟网上类似,但也有更新:

  • 编译新版的ffmpeg
  • demo中会使用ffmpeg新版的api(注:网上好多教程的demo部分其实无法正常使用,部分api在新版已经废弃)

开启linux子系统

启用子系统服务

打开【启用或关闭 Windows 功能】,勾选【适用于Linux的Windows子系统】或【Windows Subsystem For Linux】

linux子系统.png

安装完成后,重启电脑

安装linux

打开Microsoft store,搜索linux

ubuntu installer.png

这里选择安装Ubuntu 18.04 LTS(当然,版本可以自己选择适用的)

启动ubuntu

安装完成后,即可在开始菜单启动该ubuntu子系统。该子系统纯命令模式,大伙可以在编译过程中顺便熟悉下linux的命令,哈哈~

ubuntu.png

编译准备

先安装和下载需要的文件,并配置好环境

创建ffmpeg文件夹(非必须)

只是为了将所有资源整合到一起,统一管理,可以忽略该流程

下载ffmpeg

下载ndk

安装jdk并解压ndk

为什么需要这么繁琐,还要安装jdk呢?本来打算安装unzip用于解压ndk的,但是由于文件过大,unzip解压会失败,最后选择使用jar进行解压

  • sudo apt-get install default-jdk
  • jar xvf android.zip

安装vim

主要用于编辑编译脚本,当然也可以使用其他的文本编辑器进行

  • sudo apt-get install vim

编译

调整configure文件,修改生成生成以lib为前缀,.so为后缀的so库

这里可以使用vim进行修改。vim的查找快捷键为:先按ESC键,然后再 / , 输入需要搜索的关键字

修改前:
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)'

编写编译脚本:android_build.sh

#!/bin/bash
NDK_DIR=/home/king/ffmpeg/android-ndk-r16b
SYSROOT=${NDK_DIR}/platforms/android-19/arch-arm/
TOOLCHAIN=${NDK_DIR}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
function android_build
{
./configure \
--prefix=$PREFIX \
--disable-doc \
--enable-shared \
--disable-static \
--disable-symver \
--enable-gpl \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-doc \
--disable-symver
--cross-prefix=${TOOLCHAIN}/bin/arm-linux-androideabi- \
--target-os=android \
--arch=arm \
--enable-cross-compile \
--sysroot=${SYSROOT} \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
}

CPU=armv7-a
PREFIX=./android/$CPU
ADDI_CFLAGS="-marm"
android_build

给编译脚本增加权限

  • sudo chmod -R 777 android_build.sh

开始编译

  • ./android_build.sh

完成

编译完成后,会在当前目录/android/armv7-a/目录下看到生成的so库

so库的使用

使用新版的android studio可以很方便的给现有项目增加c++,直接在对应的module右键,选择Add C++ to Module,即可生成需要的文件。这里不使用这种便捷方式,而是使用最原始的流程,一步一步的构建整个流程。

创建FFmpegUtil类并声明本地方法

public class FFmpegUtil {

    static {
        System.loadLibrary("ffmpegdemo");
    }
    //JNI
    public native String avformatinfo();
    public native String avcodecinfo();
    public native String protocols();
    public native String bsf();
}

使用javac编译源文件FFmpegUtil.java,生成FFmpegUtil.class

执行javac FFmpegUtil.java即可(该步骤在所在源文件目录执行)

使用javah -jni生成C头文件

javah用法: 
  javah [options] <classes>
其中, [options] 包括:
  -o <file>                输出文件 (只能使用 -d 或 -o 之一)
  -d <dir>                 输出目录
  -v  -verbose             启用详细输出
  -h  --help  -?           输出此消息
  -version                 输出版本信息
  -jni                     生成 JNI 样式的标头文件 (默认值)
  -force                   始终写入输出文件
  -classpath <path>        从中加载类的路径
  -cp <path>               从中加载类的路径
  -bootclasspath <path>    从中加载引导类的路径
<classes> 是使用其全限定名称指定的
(例如, java.lang.Object)。

根据说明,执行的命令应该为:
javah -jni com.example.ffmpegdemo.FFmpegUtil

这里有一点需要注意的是,执行目录不是在FFmpegUtil.class所在的路径,而应该是在app\src\main\java\路径下

执行成功后,可以在该目录下看到生成了com_example_ffmpegdemo_FFmpegUtil.h文件

用C代码或CPP代码写函数原型的实现

  1. 在app\src\main\下增加cpp文件夹
  2. 创建可以在该目录下看到生成了com_example_ffmpegdemo_FFmpegUtil.cpp文件,实现具体的函数

添加ffmpeg so库的引用

  1. 在app\路径下添加libs文件夹
  2. 将几个平台的so库添加到libs目录下
  3. 将相应的头文件添加到libs目录下,统一放在include下
  4. 在module的build.gradle配置相关信息
android {
    
    defaultConfig {
        ...
        externalNativeBuild {
            cmake {
                cppFlags "-std=c++11"
                abiFilters "armeabi-v7a"
            }
        }
        ndk {
            //我们只有armeabi-v7a就只配置这个就行了
            abiFilters  'armeabi-v7a'
        }
    }
}

编写CMakeLists.txt文件

CMake文件的编写,官方有详细的教程:配置CMake。主要工作就是配置引用的so库和相应的头文件等消息,具体内容可看demo。

在module的build.gradle配置CMakeLists.txt

android {
    ...
    externalNativeBuild {
        cmake {
            // 要注意相对路径,我这里直接放在app\路径下
            path file('CMakeLists.txt')
        }
    }
}

使用

基本配置完成,可以正常的在module中使用FFmpegUtil提供的native方法啦~上图两张:

微信图片_20211125143418.jpg

微信图片_20211125143422.jpg

总结

总的流程下来,主要包含两方面:

  1. 如何不安装虚拟机编译新版ffmpeg的so库
  2. 如何使用编译出来的so库,即一般ndk的开发流程 当然,就像上边提及的,android studio对于ndk开发支持越来越好,也越来越简便。那为什么上边没有使用简便的方法呢?有时候你需要自己一步一步进行开发才能理解ADT在背后为我们做了哪些事情,假如脱离ADT我们可以怎么去完成相应的事情。

最后附上demo地址:gitee-demo