NDK 编译(二)—— NDK 编译与集成 FFmpeg

NDK 编译系列文章共三篇,目录如下:

NDK 编译(一)—— Linux 知识汇总
NDK 编译(二)—— NDK 编译与集成 FFmpeg
NDK 编译(三)—— CMake 原生构建工具

在使用 NDK 进行音视频开发时,势必会用到 FFmpeg,因此我们要知道如何编译 FFmpeg 并将其集成到 Android 项目中。

1、准备工作

1.1 下载 FFmpeg

下载 Linux 版的 FFmpeg 4.0.6 版本并解压:

[root@frank AndroidNDK]# wget https://ffmpeg.org/releases/ffmpeg-4.0.6.tar.bz2
[root@frank AndroidNDK]# tar -xjf ffmpeg-4.0.6.tar.bz2

解压好了后将进入 FFmpeg 的目录,将用户手册导出到文件中方便查看:

[root@frank AndroidNDK]# cd ffmpeg-4.0.6/
[root@frank ffmpeg-4.3.6]# ./configure --help -> ffmpeg_help.txt

1.2 下载 NDK

下载 Linux 版本的 NDK r17c 版本并解压:

[root@frank AndroidNDK]# wget https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip?hl=zh_cn
[root@frank AndroidNDK]# unzip android-ndk-r17c-linux-x86_64.zip

2、编译 FFmpeg

实际上在 FFmpeg 根目录下有一个编译脚本 configure.sh,运行该脚本就可以编译出完整的 FFmpeg 的库文件和头文件,但是这样编译出的库在 Android 上用不了。所以我们才需要通过 NDK 做交叉编译,编译出 Android 可以使用的静态库或动态库。由于编译 FFmpeg 的参数众多,因此我们把编译指令写入一个脚本文件中:

#!/bin/bash
# NDK 根目录
NDK_ROOT=/root/AndroidNDK/android-ndk-r17c
# 定义 NDK 交叉编译时使用的编译器(所在的目录)
TOOLCHAIN=$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
# 编译参数的 FLAGS 可以从 AS 的 app\.cxx\...\x86_64\build.ninja(不同版本路径不同)
# 与 4.0.2 版本相比去掉了 -fstackprotector-strong 参数,因为 4.0.6 不识别
FLAGS="-isystem $NDK_ROOT/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fPIC"
# 编译时所需的系统的头文件
INCLUDES=" -isystem $NDK_ROOT/sources/android/support/include"# 执行 configure 脚本,用于生成 makefile,参数详解:
#--prefix: 安装目录
#--enable-small: 启用小型优化,以减小生成的库文件的大小
#--disable-programs:不编译 ffmpeg 自带的程序(命令行工具),我们是需要获得静态(动态)库
#--disable-avdevice:关闭 avdevice 模块(音视频设备支持),此模块在 android 中无用
#--disable-encoders:关闭所有编码器(播放不需要编码)
#--disable-muxers:关闭所有复用器(封装器),不需要生成 mp4 这样的文件,所以关闭
#--disable-filters:关闭视频滤镜
#--enable-cross-compile:开启交叉编译,用于在一个平台上为另一个平台生成可执行文件(ffmpeg 支持跨平台)
#--cross-prefix:指定交叉编译工具链的前缀,例如 gcc 的前缀 xxx/xxx/xxx-gcc 则给 xxx/xxx/xxx-
#--disable-shared 和 enable-static:禁用生成动态库和启用生成静态库。不写也可以,默认就是这样的
#--sysroot: 指定系统根目录,用于定位 Android 平台的头文件和库文件
#--extra-cflags: 会传给 gcc 的参数
#--arch:指定目标平台的体系结构,一般真机为 ARM,模拟器为 x86
#--target-os: 指定目标操作系统,这里为 AndroidPREFIX=./output/android
./configure \
--prefix=$PREFIX \
--enable-small \
--disable-programs \
--disable-avdevice \
--disable-encoders \
--disable-muxers \
--disable-filters \
--enable-cross-compile \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--disable-shared \
--enable-static \
--sysroot=$NDK_ROOT/platforms/android-21/arch-arm \
--extra-cflags="$FLAGS $INCLUDES" \
--extra-cflags="-isysroot $NDK_ROOT/sysroot/" \
--arch=arm \
--target-os=androidmake clean
make install

编译 FFmpeg 过程:

  1. 定义两个变量,这两个变量在后续脚本中会被多次用到
    • NDK 的根目录:/root/AndroidNDK/android-ndk-r17c
    • 交叉编译的编译器所在的目录:TOOLCHAIN=$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
  2. 定义编译产物输出路径的变量:PREFIX=./output/android
  3. 定义 gcc 的编译参数,需要两个变量:
    • FLAGS:
      • -isystem <directory>:添加 directory 到编译器的系统包含路径中。我们要添加系统级别的头文件供编译器和系统使用,这里我们添加的路径是 $TOOLCHAIN/sysroot/usr/include/arm-linux-androideabi,它包含 iotcl.h 和 ioctls.h 等头文件
      • -D <macro>=<value>:-D 用来指定宏的值,这里我们指定 ANDROID_API__=33
      • -g:会生成源码级别的 debug 信息,
      • -DANDROID:-D 是一个预处理器定义的参数,用于定义预处理器宏。在编译过程中使用该参数会定义一个名为 ANDROID 的宏,并指定为 true,以便在代码中进行条件编译
      • -fdata-sections:GCC 的编译选项之一,用于将每个数据(变量)放置在独立的数据段(section)中
      • -ffunction-sections:GCC 编译选项之一,用于在生成目标文件时将每个函数放置在独立的代码段(section)中,作用是对生成的目标文件进行优化,以便在链接(linking)过程中更好地进行代码优化和减少最终可执行文件的大小
      • -funwind-tables:GCC 的编译选项之一,用于生成用于异常处理和堆栈展开(stack unwinding)的 unwind 表格(unwind tables)。该参数会为每个函数生成 unwind 表格,这些表格描述了函数中的异常处理逻辑和堆栈展开过程所需的信息
      • -fstack-protector-strong:GCC 的编译选项,用于启用堆栈保护机制,以防止栈溢出攻击
      • -no-canonical-prefixes:GCC 的编译选项之一,用于禁用规范化的前缀(canonical prefixes)
      • -D_FORTIFY_SOURCE=2:用于启用强化源代码(fortify source)的功能,以增强程序的安全性和防范某些类型的常见漏洞。具体而言,可以开启缓冲区溢出保护、安全字符串处理函数和编译时警告功能
      • -W:GCC 的编译选项之一,会启用指定的警告。-Wformat 就会启用格式字符串相关的警告,而 -Werror=format-security 会将格式字符串安全性警告视为错误
      • -fno-limit-debug-info:GCC 的编译选项之一,用于禁用调试信息的大小限制
      • -fPIC:是 GCC 的编译选项之一,用于生成位置无关代码(Position Independent Code,PIC)。位置无关代码是一种可执行代码或共享库的形式,其加载和执行的位置不依赖于内存的绝对地址。这种代码的特点是可以在内存中的任何位置加载并正确执行,因此适用于共享库的使用场景。使用位置无关代码可以使共享库在不同的进程地址空间中共享,并减少地址冲突的可能性。
    • INCLUDES:包含 gcc 编译时所需要的系统头文件
  4. 通过 ./configure 运行 FFmpeg 提供的编译脚本,其下面配置的参数主要分为两大类,一是对 FFmpeg 进行剪裁,因为 Android 开发用不到 FFmpeg 所有的功能,因此禁用掉不用的功能可以减小编译产物的大小;二是启用交叉编译,并配置编译相关的参数,具体详见脚本注释

编译完成之后会在我们指定的 /ffmpeg-4.0.6//output/android 目录下生成三个目录:include、lib、share:

2023-12-28.FFmpeg4.0.6编译产物

include 包含的是头文件,lib 是库文件,share 则是一些示例代码。

我们将它们打包准备从 Linux 服务器上下载到本地:

[root@frank output]# zip -r ffmpeg.zip ./*

3、为 AS 配置 FFmpeg

在本地解压上一步得到的 ffmpeg.zip,将 include 和 lib 文件夹内的文件拷贝到 Android Studio 的项目中,具体步骤如下:

  1. 将 include 文件夹拷贝到 /src/main/cpp 目录下

  2. 将 lib 文件夹内的 6 个静态库(.a 结尾)文件拷贝到 /src/main/cpp/armeabi-v7a 目录下(因为我们后续要在 CPU 架构为 armeabi-v7a 的真机上使用这些静态库)

  3. 配置 CMakeLists 文件:

    # 1、引入头文件
    include_directories(${CMAKE_SOURCE_DIR}/include)# 2、引入库文件
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/${CMAKE_ANDROID_ARCH_ABI}")find_library(log-liblog)# 3、链接 FFmpeg 的静态库到目标库,注意顺序,比如 avformat 要在
    # avcodec 的前面
    target_link_libraries(ffmpeg${log-lib}avformat avcodec avfilter avutil swresample swscale)
    

    配置 target_link_libraries 时要注意 6 个静态库的顺序,因为 avcodec 是依赖 avformat 的,被依赖的库要写在前面。如果想排除掉顺序影响,可以写成下面这样:

    target_link_libraries(ffmpeg${log-lib}-Wl,--start-groupavformat avcodec avfilter avutil swresample swscale-Wl,--end-group)
    
  4. 配置 build.gradle 添加 CPU 架构过滤:

    android {defaultConfig {externalNativeBuild {cmake {abiFilters 'armeabi-v7a'}}ndk {abiFilters 'armeabi-v7a'}}
    }
    
  5. 最后调用 avutil 库中的函数,输出 FFmpeg 的版本号,测试配置是否成功:

    // 因为 FFmpeg 是用纯 C 写的,所以要用 C 的方式编译
    extern "C" {
    #include <libavutil/avutil.h>
    }extern "C" JNIEXPORT jstring JNICALL
    Java_com_linux_ffmpeg_NativeLib_stringFromJNI(JNIEnv *env,jobject /* this */) {std::string hello = "FFmpeg 版本:";hello.append(av_version_info());return env->NewStringUTF(hello.c_str());
    }
    

    调用 JNI 函数,我写在了 Android 单元测试中:

    @RunWith(AndroidJUnit4::class)
    class ExampleInstrumentedTest {@Testfun test() {// Logcat 输出 test: FFmpeg 版本:4.0.6Log.d("Test", "test: ${NativeLib().stringFromJNI()}")}
    }
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/4636.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

icloud里面的通讯录怎么全部导出,通讯录格式如何转换,简单!

随着科技的发展&#xff0c;我们的日常生活越来越离不开手机和各种应用程序。通讯录作为手机中最重要的功能之一&#xff0c;记录着我们的亲朋好友、同事和业务伙伴的联系方式。因此&#xff0c;定期备份通讯录变得尤为重要。iCloud作为苹果公司提供的一项云服务&#xff0c;可…

【触摸案例-控件不能响应的情况 Objective-C语言】

一、接下来,我们来说这个“控件不能响应的情况”, 1.素材里边,有一个“不接受用户交互的情况”,这么一个代码,把它打开, 把这个项目啊,复制过来,改一个名字,叫做“04-控件不能响应的情况”, 打开之后,command + R,运行一下, 在storyboard上,你也可以看得出来,我…

java-stream流案例

需求 代码 Vote类 // 1. 定义一个投票类 public class Vote {private String name;private ArrayList<String> voteList;public Vote(String name, ArrayList<String> voteList) {this.name name;this.voteList voteList;}public String getName() {return nam…

16册 | 移动机器人(自动驾驶)系列

此文档整理推荐了16本移动机器人&#xff08;自动驾驶&#xff09;相关的书籍&#xff0c;内容包括&#xff1a;ROS、机器人基础开发、分布式机器人控制、集群机器人控制、嵌入式机器人、多传感器融合等等。 学习&#xff0c;切勿急于求成&#xff0c;读书自学&#xff0c;需多…

就业班 第三阶段(tomcat) 2401--4.28 day1 tomcat1安装配置及单机多实例

企业 Tomcat 运维 文章目录 企业 Tomcat 运维一、Tomcat 简介1、Tomcat好帮手---JDK2、安装Tomcat & JDK1、系统环境说明2 、安装JDK3、安装Tomcat 二、Tomcat目录介绍1、tomcat主目录介绍2、webapps目录介绍3、Tomcat配置介绍&#xff08;conf&#xff09;4、Tomcat的管理…

Qt窗口

QMainWindow Qt 窗⼝ 是通过 QMainWindow类 来实现的。 QMainWindow 是⼀个为⽤⼾提供主窗⼝程序的类&#xff0c;继承⾃ QWidget 类&#xff0c;并且提供了⼀个预定义的 布局。QMainWindow 包含 ⼀个菜单栏&#xff08;menu bar&#xff09;、多个⼯具栏(tool bars)、多个浮动…

JavaScript底层原理(栈、堆、主线程、任务队列、事件循环机制)

1. 栈(heap)和堆(stack) 栈是栈内存的简称&#xff0c;堆是堆内存的简称。顾名思义&#xff0c;内存是干啥的&#xff1f;内存就是用来存放数据的。 栈 栈只有一个入口&#xff0c;同时也是出口&#xff0c;数据遵循先进后出、后进先出的原则。 栈用于存放基本类型数据和引用…

安装库后JupyterLab一直报ModuleNotFoundError问题解决

背景&#xff1a; 先安装的Python3.10&#xff0c;安装在默认路径&#xff1a; C:\Users\#用户名省略#\AppData\Local\Programs\Python\Python310\ 后安装的Anaconda&#xff0c;更改过路径在D盘&#xff1a; D:\ProgramData\anaconda3 此时C盘Python安装路径下Scripts文件…

YAW-100B全自动压力试验机

一、简介 微机控制压力试验机测控系统采用高精度数字伺服阀&#xff0c;具有力闭环控制功能&#xff0c;能够实现等载荷速率加载或等应力速率加载&#xff0c;控制精度高&#xff0c;可靠性好&#xff0c;完全满足GB/T 17617《水泥胶沙强度检验方法&#xff08;ISO方法&#x…

matlab学习004-使用matlab绘制卷积波形图

目录 1&#xff0c;序列&#xff1a;x(n)u(n-2)-u(n-10)&#xff0c;h(n)((0.9)^n)*u(n) 1&#xff09;前期基础 ①conv函数 ②离散单位阶跃信号 2&#xff09;波形图 3&#xff09;代码 ①使用input方法 ②代码改进【推荐使用】 2&#xff0c;信号x(t)2[u(t1)-u(t…

红黑树笔记

2-3树 -> 左倾红黑树 红黑树实际上是2-3树的一种基于BST的实现。普通二叉搜索树&#xff08;BST&#xff09;中的每一个节点&#xff0c;只有一个键&#xff0c;两条链接&#xff08;两个子节点&#xff09;&#xff0c;这种节点被称为2节点。2-3树中&#xff0c;引入了一个…

【智能算法】土拨鼠优化算法(PDO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2022年&#xff0c;AE Ezugwu等人受到土拨鼠觅食行为与自然行为启发&#xff0c;提出了土拨鼠优化算法&#xff08;Prairie Dog Optimization algorithm, PDO&#xff09;。 2.算法原理 2.1算法思…

云服务器搭建XSS-platform、DVWA靶机和Permeate论坛

目录 前言准备环境安装步骤一、 部署MySQL二、 系统部署三、系统安装主页介绍 前言 我发现目前网上的xss-platform的搭建教程都是基于本地搭建的&#xff0c;这样搭建好的xss平台只能在本地使用&#xff0c;无法测试别的网站。而网络上的大部分xss平台又几乎都是收费的&#x…

vue3学习笔记-快速上手

创建第一个vue3的应用 之前看书学习vue,书籍对应的版本是vue2,今天群里看小伙伴聊天&#xff0c;觉得他们说得对 &#xff0c;反正是从零开始学&#xff0c;而且vue2都不维护了&#xff0c;那为什么不直接学习vue3呢&#xff0c;于是乎&#xff0c;又开启了从0学vue3之路。 参考…

2024Xtu程设第一次练习题解

程设练习题谢大会专门查重 1.1531奇怪的数字 题目让我们从小到大输出1e6以内所有的答案&#xff0c;其实也没什么好的思路 就是将一个数n的所有位都拆出来&#xff0c;遍历这些位&#xff08;每次取一个x&#xff09;&#xff0c;然后通过作除法&#xff08;y n / x&#xf…

java多态知识

目录 一、定义 二、注意事项 三、多态的好处 四、多态的弊端以及解决办法 一、定义 多态定义:多态是在继承/实现情况下的一种现象&#xff0c;表现为:对象多态、行为多态。 对象多态&#xff1a;都是同一对象&#xff0c;表现出不同角色&#xff0c;比如小明&#xff0c;…

java:SpringBoot入门

Spring 提供若干子项目,每个项目用于完成特定功能 Spring Boot 可以简化配置并且快速开发 SpringBootWeb快速入门 创建Springboot模块并使用Springweb依赖 在类上添加注解 RestController可以将字符串自动转成json返回数据给页面 再在方法上添加注解 RequestMapping(&…

python应用-socket网络编程(2)

socket 是 Python 标准库中的一个模块&#xff0c;它提供了低级别的网络通信接口。使用 socket 模块&#xff0c;你可以创建客户端和服务器应用程序&#xff0c;以便在网络上进行数据交换。 接着上文我们介绍下socket模块其他的一些函数。 目录 gettimeout() 和settimeout()…

0422empAJAX项目

数据库字段&#xff1a; 多条件查询&#xff1b; 分页查询&#xff1b; 添加图片&#xff1b; ajax离职操作&#xff1b; 删除选项&#xff0c;点击离职操作后仍然可实现删除选项

项目部署总结

1、安装jdk 第一步&#xff1a;上传jdk压缩安装包到服务器 第二步&#xff1a;将压缩安装包解压 tar -xvf jdk-8uXXX-linux-x64.tar.gz 第三步&#xff1a;配置环境变量 编辑/etc/profile文件&#xff0c;在文件末尾添加以下内容&#xff1a; export JAVA_HOME/path/to/j…