Android mac 交叉编译与ffmpeg编译踩坑记 (v7a 与 v8a and 动态库与静态库)

news2024/10/5 15:25:15

Android mac 交叉编译与ffmpeg编译踩坑记

环境:

system: mac

NDK: android-ndk-r17c

Fffmpeg: ffmpeg-4.0.2

Cmake: 3.10.2

Gradle: 4.1.3

tips: 本文记录踩坑过程,具体细节如果感兴趣可以在评论区留言交流讨论!

mac 编译 (动态库(so))

首先来回顾一下,mac原始库是如何编译的

先来创建一个最简单的so文件:

image-20230711093344318

只需要输入:

gcc -fPIC -shared main.c -o libmain.so

image-20230711093507390

这样就可以将c代码编译成so库

mac 编译 (静态库(a))

静态库稍微麻烦一点,需要先生成 .o文件 [ gcc -fPIC -c main.c -o main.o ]

然后通过 .o文件生成 .a文件 [ar -r libmain.a main.o]

image-20230711094503924

这样一来,就很轻易的编译成了静态库

android 交叉编译(动态库 arm-v7a)

这里就有疑问了, 为什么需要交叉编译 ?

因为刚才我们的代码是在mac上编译的 ,android并不认识, 要想android认识,就引出了交叉编译

就好像越南人来china买东西,必须吧越南盾换成人民币一样,必须要认识,才能够使用

在mac上,编译的方式是采用gcc

那么NDK也为我们提供了GCC

image-20230711095455235

那么只能这样:

image-20230711100232342

此时就会出现第一个坑:

找不到头文件

他的头文件都在这里, 只需要再次配置一下就OK

image-20230711101202396

配置完成头文件后,就会有第二个坑:

找不到 asm/types.h

image-20230711101338201

asm/types.h 在这里:

image-20230711101835708

那么这个也需要配置一下:

image-20230711102217655

最终编译, 还是不成功! .

最后还需要告诉gcc,当前编译的是什么android架构,当前编译的是v7a,那么只需要告诉gcc即可

image-20230711102511048

最终编译:

image-20230711102731233

完整命令:

/Users/ndk/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-gcc --sysroot=$NDK/platforms/android-21/arch-arm -isystem $NDK/sysroot/usr/include -isystem $NDK/sysroot/usr/include/arm-linux-androideabi -fPIC -shared main.c -o libmain-ndk-32.so

这样一来, 打包成的so库就可以在android v7a的手机上运行了!

但是问题就来了,我不可能每次打包都这么麻烦,输这么长的指令,实在是太丑了, 所以说我将它配置成了全局变量,并写成了shell

配置全局变量:

# .bash_profile

# NDK路径
export NDK="/Users/ndk/android-ndk-r17c"

# NDK的命令操作 配置到 Linux环境变量里面去
export PATH=$NDK:$PATH


# 下面是交叉编译相关
# ================= GCC ==================================
export NDK_GCC_x86="$NDK/toolchains/x86-4.9/prebuilt/darwin-x86_64/bin/i686-linux-android-gcc"

export NDK_GCC_x64="$NDK/toolchains/x86_64-4.9/prebuilt/darwin-x86_64/bin/x86_64-linux-android-gcc"

export NDK_GCC_arm="$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-gcc"

export NDK_GCC_arm_64="$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-gcc"


# ================================== config 配置架构 ==================================
export NDK_CFIG_x86="--sysroot=$NDK/platforms/android-21/arch-x86 -isystem $NDK/sysroot/usr/include -isystem $NDK/sysroot/usr/include/i686-linux-android"

export NDK_CFIG_x64="--sysroot=$NDK/platforms/android-21/arch-x86_64 -isystem $NDK/sysroot/usr/include -isystem $NDK/sysroot/usr/include/x86_64-linux-android"

export NDK_CFIG_arm="--sysroot=$NDK/platforms/android-21/arch-arm -isystem $NDK/sysroot/usr/include -isystem $NDK/sysroot/usr/include/arm-linux-androideabi"

export NDK_CFIG_arm_64="--sysroot=$NDK/platforms/android-21/arch-arm64 -isystem $NDK/sysroot/usr/include -isystem $NDK/sysroot/usr/include/aarch64-linux-android"

记得保存:

source ~/.bash_profile

Shell 命令

image-20230711103651463

重新编译v7a 动态库(so):

image-20230711103822045

android 交叉编译(动态库 arm-v8a)

v8a 的方式也是一样的,只是选择架构的时候选择v8a即可

image-20230711103915648

为了在android端演示, 写一个util方法,里面有加减乘除函数, 通过JNI调用试试

image-20230711112017150

可以直接采用sh命令来直接生成交叉编译后的so,

然后可以通过 file. XXX.so 来查看编译结果!

在android中测试打包后的so库:

创建一个C++工程, 配置CMake

image-20230711112611458

记得在gradle中设置NDK架构:

image-20230711112702104

最后直接来调用即可:

image-20230711112850894

android 交叉编译 (静态库 arm-v7a)

静态库与动态库类似,只需要将linux的编译方式换成NDK的编译方式即可

Linux编译方式:
1. 生成.o文件
gcc -fPIC -c main.c -o main.o 

2. 通过.o文件来构建 静态库
ar -r libmain.a main.o

先来找到NDK对应v7a架构的ar, 因为这里是通过ar来生成.a 文件的

image-20230711130713079

同样为了方便使用,我把它配置成了全局变量,并且写成了shell命令

# .bash_profile

# 下面是交叉编译相关
# ================= GCC ==================================
export NDK_GCC_x86="$NDK/toolchains/x86-4.9/prebuilt/darwin-x86_64/bin/i686-linux-android-gcc"

export NDK_GCC_x64="$NDK/toolchains/x86_64-4.9/prebuilt/darwin-x86_64/bin/x86_64-linux-android-gcc"

export NDK_GCC_arm="$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-gcc"

export NDK_GCC_arm_64="$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-gcc"


# ================================== config 配置架构 ==================================
export NDK_CFIG_x86="--sysroot=$NDK/platforms/android-21/arch-x86 -isystem $NDK/sysroot/usr/include -isystem $NDK/sysroot/usr/include/i686-linux-android"

export NDK_CFIG_x64="--sysroot=$NDK/platforms/android-21/arch-x86_64 -isystem $NDK/sysroot/usr/include -isystem $NDK/sysroot/usr/include/x86_64-linux-android"

export NDK_CFIG_arm="--sysroot=$NDK/platforms/android-21/arch-arm -isystem $NDK/sysroot/usr/include -isystem $NDK/sysroot/usr/include/arm-linux-androideabi"

export NDK_CFIG_arm_64="--sysroot=$NDK/platforms/android-21/arch-arm64 -isystem $NDK/sysroot/usr/include -isystem $NDK/sysroot/usr/include/aarch64-linux-android"


# ================================== ar配置 用来生成静态库 ==================================
export NDK_AR_x86="$NDK/toolchains/x86-4.9/prebuilt/darwin-x86_64/bin/i686-linux-android-ar"

export NDK_AR_x64="$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-ar"

export NDK_AR_arm="$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ar"

export NDK_AR_arm_64="$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-ar"

同样记得保存:

source ~/.bash_profile	

shell命令:

#!bin/bash

if [  $1 != 'v7a' ] && [ $1 != 'v8a' ]; then
	echo "请选择平台 正确指令: sh $0 v7a或v8a(生成架构) xxx"
	exit 0
fi

echo 您选择编译的平台是: $1

if [ -e $NDK ]; then

	 if [ "v7a" = $1 ]; then
	
		# 交叉编译生成.o文件
		$NDK_GCC_arm $NDK_CFIG_arm -fPIC -c $2.c -o $2.o
		
		echo "生成$2.o中..."
		sleep 1
		
		$NDK_AR_arm rcs -o lib-$2.a $2.o
	 else 
		$NDK_GCC_arm_64 $NDK_CFIG_arm_64 -fPIC -c $2.c -o $2.o

    echo "生成$2.o中..."
    sleep 1

    $NDK_AR_arm_64 rcs -o lib-$2.a $2.o
	 fi
	echo "执行成功"

else
	echo "执行失败"
fi

使用:

只需要简单的:

sh static_build.sh v7a util 即可

image-20230711132834051

android 交叉编译 (静态库 arm-v8a)

Arm-v8a编译静态库与动态库编译方式是一样的; 使用同一个shell命令

image-20230711132718889

在android中使用:

image-20230711133200529

使用效果和动态库类似,只是配置的方式不同

动态库与静态库的区别

  1. 静态库不会显示在apk中,在编译过程中,静态库的太吗都会copy到主库中

image-20230711133500901

相反动态库则全会打包到apk中

image-20230711133745838

ffmpeg编译(armv7a)

ffmpeg如何下载我就不说了, 写了一个脚本,我测试了很多次,只要NDK地址给对 80%都是可以编译成功的. 坑我全踩了 花了2天时间

build32.sh

#!/bin/bash

# NDK_PATH
NDK_ROOT=/Users/ndk/android-ndk-r17c

# NDK中gcc地址 arm-v7a地址
TOOLCHAIN=$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64

FLAGS="-isystem $NDK_ROOT/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -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"

# 1.定义编译后,所存放的目录
PREFIX=./android/arm32

# 2.--enable-small 优化大小 非常重要,必须优化才行的哦
# 3.--disable-programs 不编译ffmpeg程序(命令行工具),我们是需要获取静态、动态库
# 4.--disable-avdevice 关闭avdevice模块,此模块在android中无用
# 5.--disable-encoders 关闭所有编码器(播放不需要编码)
# 6.--disable-muxers 关闭所有复用器(封装器),不需要生成mp4这样的文件,所有关闭
# 7.--disable-filters 关闭所有滤镜
# 8.--enable-cross-compile 开启交叉编译(ffmpeg是跨平台的,注意:并不是所有库都有这么happy的选项)
# 9.--cross-prefix 看右边的值就知道是干嘛的,gcc的前缀..
# 10.disable-shared / enable-static 这个不写也可以,默认就是这样的,(代表关闭动态库,开启静态库)
# 11.--sysroot
# 12.--extra-cflags 会传给gcc的参数
# 13.--arch  --target-os 编译版本 v7a=arm; v8a=arm64;

./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=android

make clean

make install

如果你想编译v7a的,直接在这里创建build32.sh 吧NDK路径换成你自己的

image-20230711134705544

最好是手动创建好编译后存放的目录 [android/arm32]

编译大约3-5分钟就OK了

sh build32.sh

切记,编译时候切换到root环境编译

ffmpeg编译(armv8a)

还是同样的套路,写一个shell脚本:

build64.sh

#!/bin/bash

# NDK位置
NDK_ROOT=/Users/ndk/android-ndk-r17c

# GCC
TOOLCHAIN=$NDK_ROOT/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64

FLAGS="-isystem $NDK_ROOT/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv8-a -mcpu=generic -Wa,--noexecstack -Wformat -Werror=format-security  -O0 -fPIC"
INCLUDES=" -isystem $NDK_ROOT/sources/android/support/include"

# 1.定义编译后,所存放的目录
PREFIX=./android/arm64

# 2.--enable-small 优化大小 非常重要,必须优化才行的哦
# 3.--disable-programs 不编译ffmpeg程序(命令行工具),我们是需要获取静态、动态库
# 4.--disable-avdevice 关闭avdevice模块,此模块在android中无用
# 5.--disable-encoders 关闭所有编码器(播放不需要编码)
# 6.--disable-muxers 关闭所有复用器(封装器),不需要生成mp4这样的文件,所有关闭
# 7.--disable-filters 关闭所有滤镜
# 8.--enable-cross-compile 开启交叉编译(ffmpeg是跨平台的,注意:并不是所有库都有这么happy的选项)
# 9.--cross-prefix 看右边的值就知道是干嘛的,gcc的前缀..
# 10.disable-shared / enable-static 这个不写也可以,默认就是这样的,(代表关闭动态库,开启静态库)
# 11.--sysroot
# 12.--extra-cflags 会传给gcc的参数
# 13.--arch  --target-os 

./configure \
--prefix=$PREFIX \
--enable-small \
--disable-programs \
--disable-avdevice \
--disable-encoders \
--disable-muxers \
--disable-filters \
--enable-cross-compile \
--cross-prefix=$TOOLCHAIN/bin/aarch64-linux-android- \
--disable-shared \
--enable-static \
--sysroot=$NDK_ROOT/platforms/android-21/arch-arm64 \
--extra-cflags="$FLAGS $INCLUDES" \
--extra-cflags="-isysroot $NDK_ROOT/sysroot/" \
--arch=arm64 \
--target-os=android

make clean

make install

只需要吧NDK地址换成自己的即可:

image-20230711134959290

sh build64.sh

最终编译后,这就是编译结果:

image-20230711135314188

导入到android中使用:

image-20230711135700846

调用看看结果:

image-20230711135810027

我将本篇用到的所有命令已经全局配置放到项目中了,有需要的亲下载源码自取!

image-20230711140131262

完整代码

原创不易,您的点赞就是对我最大的支持!

往期文章:

  • android kotlin 协程(六) 源码浅析

  • android kotlin 协程(五) suspend与continuation

  • android kotlin 协程(四) 协程间的通信

  • android 自定义View:仿QQ拖拽效果

  • android MD 进阶[五] CoordinatorLayout 从源码到实战…

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

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

相关文章

Redis常见命令和使用示例

目录 1.使用官方文档学习redis 2.核心命令 SET GET 3.全局/通用命令 KEYS EXISTS DEL EXPIRE TTL TYPE 1.使用官方文档学习redis redis官网 点击搜索,输入,比如输入ping,会显示Commands,是一个命令,点击ping&#xff…

新版2021等启动unity包管理器本地服务器进程失败解决

1、问题 2、解决办法 最后我发现每个unity版本都有一个包管理器,也就是图中的路径,而且都是相同的路径,只是因为版本不同或多或少存在一些小差异,其他版本可以正常启动,就2021不行会不会是2021的包管理器这个文件夹出…

YOLOv5 实现 10 种热力图可视化方式教程

效果展示 GradCAMEigenCAMEigenGradCAMGradCAMElementWiseGradCAMPlusPlusHiResCAMLayerCAM

前端下载PDF内容空白且大小偏大问题解决

前端使用React框架axios请求后端接口下载文件,请求返回正常但文件大小和内容异常。经排查,其原因是使用了mockjs用作数据模拟,导致了请求异常,将其注释掉后,文件大小与内容恢复正常。 目录 1.文件异常 2.定位问题 3…

【C语言进阶技巧】指针解密:炼金术士的秘密面试题揭秘

【C语言进阶技巧】指针解密:炼金术士的秘密面试题揭秘 1. 主要涉及sizeof与strlen函数的使用的笔试题1.1 笔试题一(一维整形数组)1.2 笔试题二(不带\0的字符数组)1.3 笔试题三(带\0的字符数组)1.4 笔试题四 &#xff0…

【C#】默认打开图片、文件下载

系列文章 【C#】编号生成器(定义单号规则、固定字符、流水号、业务单号) 本文链接:https://blog.csdn.net/youcheng_ge/article/details/129129787 【C#】日期范围生成器(开始日期、结束日期) 本文链接:h…

Linux(centos7)系统关闭 virbr0

背景: 在使用 VMware 虚拟机安装 centos7 操作系统中,经常出现将 IP 地址分配到虚拟网桥接口virbr0 上,引起虚拟机不能正常访问网络的问题。 我是在学习 docker 网络分析这块遇到的问题,教程上在虚拟机上输入 ip addr 并没有出现 …

linux开发工具:repo

1:repo简单介绍 repo是Google开发的用于管理Android版本库的一个工具,它是由一系列的Python脚本组成,封装了一系列的Git命令,用来统一管理多个Git仓库。repo不是用于取代git,而是简化了对多个Git版本库的管理。 repo…

6 种方式读取 Springboot 的配置(原理+实战)

从配置文件中获取属性应该是SpringBoot开发中最为常用的功能之一,但就是这么常用的功能,仍然有很多开发者在这个方面踩坑。 我整理了几种获取配置属性的方式,目的不仅是要让大家学会如何使用,更重要的是弄清配置加载、读取的底层…

搭建Promethues + grafana +alertManager+blakbox 监控springboot 健康和接口情况

一。概述 架构图: 拓扑图: prometheus 是一个开源系统,用于构建监控和报警的工具包。 Prometheus 收集其指标并将其存储为时间序列数据,即指标信息与记录它的时间戳一起存储,以及称为标签的可选键值对。 特点&#…

003.PADS VX2.4选项设置及显示颜色设置

文章目录 一、PADS颜色设置及选项设置二、选项设置1.全局2.设计3.栅格和捕获4.显示5.布线选项页6.覆铜平面选项页7.文本和线选项页8.文本和线选项页9.过孔样式选项页 一、PADS颜色设置及选项设置 一、颜色设置 1.点击设置—显示颜色)(快捷键…

Kkfileview | Docker | 文件预览kkfile配置

文章目录 简介DockerRedis部署 简介 kkFileView为文件文档在线预览解决方案,该项目使用流行的spring boot搭建,易上手和部署,基本支持主流办公文档的在线预览,如doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,rar,图片,视频,音频等等 …

SQLSERVER 临时表 和 表变量 有区别吗

一:背景 1. 讲故事 今天和大家聊一套面试中经常被问到的高频题,对,就是 临时表 和 表变量 这俩玩意,如果有朋友在面试中回答的不好,可以尝试看下这篇能不能帮你成功迈过。 二:到底有什么区别 1. 前置思…

十五、flex弹性元素的样式

目录&#xff1a; 1. 基本布局 2. 弹性元素的属性&#xff1a;flex-grow 3. 弹性元素的属性&#xff1a;flex-shrink 4. 弹性元素的属性&#xff1a;flex-basis 5. flex 统一设置这3个属性&#xff08;常用&#xff09; 6. order 一、基本布局 <style>*{margin: 0;paddin…

【Maven】类或者包提示找不到,报红

背景 使用IDEA&#xff0c;类或者包提示找不到&#xff0c;报红 解决方法 1. maven reload 2. 检查profiles是否对 3. 不要选中offline模式 4. 检查本地仓库位置 5. 清掉idea缓存 6. 到本地maven仓库删掉出错的包然后重新maven reload 7. update本地仓库 8. 排查是不是别人没…

智慧用电安全监控管理系统

智慧用电安全监控管理系统是一种基于物联网技术的用电安全管理系统&#xff0c;它通过远程通信技术和云计算平台&#xff0c;实现了对电气设备的实时监控、数据采集、费用计算、远程控制等功能。该系统不仅可以提高用电安全管理的效率&#xff0c;还可以为用户提供更加便捷、可…

Linux(centos 7)将 ens33 改为 eth0

背景&#xff1a; 先说明一下 eth0 与 ens33 的关系&#xff0c;目前的主流网卡为使用以太网络协定所开发出来的以太网卡&#xff08;Ethernet)&#xff0c;因此我们 Linux 就称呼这种网络接口为 ethN (N为数字)。 举个例子&#xff1a;就是说主机上面有一张以太网卡&#xff0…

C++线性表、单链表

概述 在先说链表前&#xff0c;我们先来理清几个概念。 什么是线性表、顺序表和链表&#xff1f;三者有什么关系&#xff1f; 线性表&#xff1a;元素线性排列&#xff0c;在逻辑上具有次序的存储结构。 顺序表&#xff1a;线性表的顺序存储称为线性表。它是用一组地址连续(逻…

抖音短视频seo源码开发部署-技术分享(四)

一、 抖音短视频seo源码开发流程 抖音短视频SEO源码开发流程如下&#xff1a; 1.分析需求&#xff1a;首先需要明确你的SEO目标。分析竞争对手&#xff0c;了解抖音短视频平台的规则&#xff0c;选定目标关键词和主题。 2.编写代码&#xff1a;根据需求编写代码&#xff0c;…

docker 安装向量数据库 Milvus

Miluvs 官网为 www.milvus.io/ Milvus 向量数据库能够帮助用户轻松应对海量非结构化数据&#xff08;图片 / 视频 / 语音 / 文本&#xff09;检索。单节点 Milvus 可以在秒内完成十亿级的向量搜索&#xff08;请参考&#xff1a;在线教程&#xff09;&#xff0c;分布式架构亦…