音视频学习:使用NDK编译FFmpeg动态库

1. 环境

1.1 基础配置

  • NDK 22b (r22b)
  • FFmpeg 4.4
  • Ubuntu 22.04

1.2 下载ffmpeg

官网提供了 .tar.xz 包,可以直接下载解压:

wget https://ffmpeg.org/releases/ffmpeg-4.4.tar.xz
tar -xvf ffmpeg-4.4.tar.xz
cd ffmpeg-4.4

1.3 安装基础工具链

sudo apt-get update && sudo apt-get install \
build-essential autoconf automake libtool \
pkg-config cmake git wget unzip yasm

可能不包含全部,遇到报错缺少的工具链的,把报错抛给AI,按提示下载即可:)


2. 编译脚本配置

注意将脚本中的 export NDK 换成自己的路径

 #!/bin/bashecho ">>>>>>>>> 编译硬件解码版本 <<<<<<<<"#替换为你自己的NDK路径.export NDK=/home/xaye/Android/Sdk/ndk/android-ndk-r22TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64function build_android{echo "开始编译 $CPU"./configure \--prefix=$PREFIX \--enable-neon  \--enable-hwaccels  \--enable-gpl   \--enable-postproc \--enable-shared \--disable-debug \--enable-small \--enable-jni \--enable-mediacodec \--enable-decoder=h264_mediacodec \--disable-static \--disable-doc \--enable-ffmpeg \--disable-ffplay \--disable-ffprobe \--disable-avdevice \--disable-doc \--disable-symver \--cross-prefix=$CROSS_PREFIX \--target-os=android \--arch=$ARCH \--cpu=$CPU \--cc=$CC \--cxx=$CXX \--enable-cross-compile \--sysroot=$SYSROOT \--extra-cflags="-Os -fpic $OPTIMIZE_CFLAGS" \--extra-ldflags="$ADDI_LDFLAGS"make cleanmakemake installecho "编译成功 $CPU"}#armv8-aARCH=arm64CPU=armv8-aAPI=21CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clangCXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysrootCROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-PREFIX=$(pwd)/android/$CPUOPTIMIZE_CFLAGS="-march=$CPU"build_android#armv7-aARCH=armCPU=armv7-aAPI=16CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clangCXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysrootCROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-PREFIX=$(pwd)/android/$CPUOPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "build_android

3. 执行编译

# 赋予执行权限
chmod +x build_android.sh# 开始编译(约10-30分钟)
./build_android.sh

编译完成后,会生成 android/armv7-aandroid/armv8-a 目录,结构如下

android/├── armv7-a/│   ├── lib/*.so│   └── include/   <-- FFmpeg 头文件└── armv8-a/├── lib/*.so└── include/

这些 .so 文件,分别对应:

  • armv7-a/ → 用于 Android 项目的 armeabi-v7a
  • armv8-a/ → 用于 Android 项目的 arm64-v8a

4. Android 项目配置

修改 build.gradle,启用 NDK 支持

 android {defaultConfig {externalNativeBuild {cmake {cppFlags "-std=c++11"abiFilters 'armeabi-v7a', 'arm64-v8a'}}}externalNativeBuild {cmake {path "CMakeLists.txt"}}ndkVersion '22.0.7026061'}

放入头文件

将 FFmpeg 头文件复制到 app/src/main/cpp/ 下,就是把上面编译生成的整个 include 文件夹复制进去,不用在意v7a还是v8a,头文件接口都是一样的。

创建 CMakeLists.txt

app/ 目录下创建:

# 最低 CMake 版本要求
cmake_minimum_required(VERSION 3.4.1)# 项目设置
project("ffmpeg_jni")# 设置 C 标准(FFmpeg 需要 C11)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)# 打印当前 ABI 用于调试
message("Current ABI: ${ANDROID_ABI}")# 设置 FFmpeg 库路径(根据实际路径调整)
set(FFMPEG_LIBS_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})# 定义 FFmpeg 核心库(按依赖顺序)
set(FFMPEG_LIBSavutilswresampleavcodecavformatswscale# 可选添加其他库:postproc, avfilter 等
)# 导入预编译的 FFmpeg 共享库
foreach(LIB ${FFMPEG_LIBS})add_library(${LIB} SHARED IMPORTED)set_target_properties(${LIB} PROPERTIESIMPORTED_LOCATION "${FFMPEG_LIBS_DIR}/lib${LIB}.so"# 对于 Android 8.0+ 需要设置 SONAMEIMPORTED_SONAME "lib${LIB}.so")message("Imported lib: ${FFMPEG_LIBS_DIR}/lib${LIB}.so")
endforeach()# 添加 Android 日志库
find_library(log-lib log)# 设置 JNI 源文件
file(GLOB JNI_SOURCES src/main/cpp/*.cpp)# 创建 JNI 库
add_library(ffmpeg_jni SHARED ${JNI_SOURCES})# 头文件包含路径(根据 FFmpeg 头文件位置调整)
target_include_directories(ffmpeg_jni PRIVATE${CMAKE_SOURCE_DIR}/src/main/cpp/include  # 头文件放在这里${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/include  # 如果 FFmpeg 头文件随库提供
)# 链接库
target_link_libraries(ffmpeg_jniandroid${log-lib}${FFMPEG_LIBS}  # 按依赖顺序自动链接
)# 编译选项优化
target_compile_options(ffmpeg_jni PRIVATE-Wall-Werror-fno-exceptions-fno-rtti-fvisibility=hidden
)

5. JNI 代码实现

Java 层声明

创建 FFmpegHelper.java

public class FFmpegHelper {static {// 按依赖顺序加载FFmpeg库System.loadLibrary("avutil");System.loadLibrary("swresample");System.loadLibrary("avcodec");System.loadLibrary("avformat");System.loadLibrary("swscale");System.loadLibrary("ffmpeg_jni"); // 我们的JNI库}public static native String getFFmpegVersion();
}

Native 层实现

创建 ffmpeg_jni.cpp

#include <jni.h>
#include <android/log.h>
//#include <libavutil/avutil.h>
#include <stdio.h>extern "C" {
#include <libavutil/avutil.h>
}#define LOG_TAG "FFmpegJNI"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)extern "C" {
JNIEXPORT jstring JNICALL
Java_com_xaye_compiler_FFmpegHelper_getFFmpegVersion(JNIEnv *env, jclass clazz) {// 调用FFmpeg API获取版本信息const char* version = av_version_info();LOGD("Native FFmpeg version: %s", version);return env->NewStringUTF(version ? version : "Unknown");
}
}

注意:在#include ffmpeg 库的头文件时,要使用 extern "C" 包起来,不然会报错!


6. 验证

在主界面 打印版本号

  Log.i("MainActivity", " FFmpeg version : "+FFmpegHelper.getFFmpegVersion());

输出:

在这里插入图片描述


代码已上传 ffmpeg-compiler

参考:音视频学习 (六) 一键编译 32/64 位 FFmpeg 4.2.2

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

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

相关文章

前端开发避坑指南:React 代理配置常见问题与解决方案

前端开发避坑指南:React 代理配置常见问题与解决方案 一、为什么需要配置代理?二、使用 create-react-app 默认配置代理三、使用 http-proxy-middleware 配置复杂代理四、高级代理配置五、生产环境中的代理配置一、为什么需要配置代理? React 应用在开发过程中经常需要与后端…

用影刀RPA打通内容创作“最后一公里”:CSDN草稿一键同步多平台发布

文章目录 引言 一、需求场景&#xff1a;多平台分发的效率困境1. 痛点分析2. 影刀RPA的破局价值 二、影刀RPA是啥&#xff1f;打工人逆袭神器&#xff01;三、手把手教你造"搬运工"——技术宅的土味开发日记第一步&#xff1a;当个"偷窥狂"——观察手动操作…

进程与线程:09 进程同步与信号量

课程引入&#xff1a;进程同步与信号量 接下来这节课开始&#xff0c;我们再开始讲多进程图像。讲多进程图像的下一个点&#xff0c;前面我们讲清楚了多进程图像要想实现切换&#xff0c;调度是如何做的。同时&#xff0c;多个进程放在内存中&#xff0c;就会存在多进程合作的…

【愚公系列】《Manus极简入门》036-物联网系统架构师:“万物互联师”

&#x1f31f;【技术大咖愚公搬代码&#xff1a;全栈专家的成长之路&#xff0c;你关注的宝藏博主在这里&#xff01;】&#x1f31f; &#x1f4e3;开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主&#xff01; &#x1f…

MySQL 8.0 OCP 英文题库解析(四)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题26~30 试题26:…

什么是原码和补码

补码的本质确实是模运算&#xff08;Modular Arithmetic&#xff09;&#xff0c;这是理解补码为何能统一加减法的核心数学原理。下面用最通俗的语言和例子解释清楚&#xff1a; —### 1. 先理解什么是“模运算”- 模运算就是“周期性计数”&#xff0c;比如钟表&#xff1a; -…

笔记项目 day02

一、用户登录接口 请求参数&#xff1a; 用loginDTO来封装请求参数&#xff0c;要加上RequestBody注解 响应参数&#xff1a; 由于data里内容较多&#xff0c;考虑将其封装到一个LoginUser的实体中&#xff0c;用户登陆后&#xff0c;需要生成jwtToken并返回给前端。 登录功…

2025年土木建筑与水利工程国际会议(ICCHE 2025)

2025 International Conference on Civil and Hydraulic Engineering (ICCHE 2025) &#xff08;一&#xff09;会议信息 会议简称&#xff1a;ICCHE 2025 大会地点&#xff1a;中国银川 投稿邮箱&#xff1a;icchesub-paper.com 收录检索&#xff1a;提交Ei Compendex,CPCI,C…

运行Spark程序-在shell中运行1

&#xff08;一&#xff09;分布式计算要处理的问题 【老师提问&#xff1a;分布式计算要面临什么问题&#xff1f;】 【老师总结】 分布式计算需要做到&#xff1a; 1.分区控制。把大的数据拆成一小份一小份的&#xff08;分区&#xff0c;分片&#xff09;让多台设备同时计算…

一文理清人工智能,机器学习,深度学习的概念

目录 一、人工智能的起源与核心范畴&#xff08;1950-1980&#xff09; 1.1 智能机器的最初构想 1.2 核心范畴的初步分化 二、机器学习的兴起与技术分化&#xff08;1980-2010&#xff09; 2.1 统计学习的黄金时代 2.2 神经网络的复兴与子集定位 2.3 技术生态的形成与AI…

《Effective Python》第1章 Pythonic 思维总结——编写优雅、高效的 Python 代码

《Effective Python》第1章 Pythonic 思维总结——编写优雅、高效的 Python 代码 在编程的世界里&#xff0c;每个语言都有其独特的风格和最佳实践。对于 Python 而言&#xff0c;“Pythonic”已经成为描述遵循 Python 特定风格的代码的代名词。这种风格不仅让代码更易读、更简…

MySQL 事务(二)

文章目录 事务隔离性理论理解隔离性隔离级别 事务隔离级别的设置和查看事务隔离级别读未提交读提交&#xff08;不可重复读&#xff09; 事务隔离性理论 理解隔离性 MySQL服务可能会同时被多个客户端进程(线程)访问&#xff0c;访问的方式以事务方式进行一个事务可能由多条SQL…

代码仓提交分支规范

以下是我部门开发时用的分支规范&#xff0c;参考于Linux社区 Tips 分支命名通常遵循一些最佳实践和规则&#xff0c;以便使分支的用途和内容清晰易懂&#xff0c;就在写一个文档的主题一样。 功能分支 (Feature Branches) 用于开发新功能。 命名格式&#xff1a;feature/功能名…

Google Earth Engine(GEE) 代码详解:批量计算_年 NDVI 并导出(附 Landsat 8 数据处理全流程)

一、代码整体目标 基于 Landsat 8 卫星数据,批量计算 2013-2020 年研究区的 NDVI(归一化植被指数),实现去云处理、数据合成、可视化及批量导出为 GeoTIFF 格式,适用于植被动态监测、生态环境评估等场景。 二、代码分步解析(含核心原理与易错点) 1. 加载并显示研究区边…

Maven 处理依赖冲突

Maven处理依赖冲突 什么是依赖冲突&#xff1f;如何解决&#xff1f;Maven自动处理依赖冲突的规则路径优先原则第一声明优先原则注意 子模块覆盖父模块父模块声明dependency子模块覆盖dependency父模块声明dependencyManagement 子模块覆盖dependency父模块声明dependencyManag…

docker 安装 sqlserver2022 和注意点

一、前言 1、可以直接参考微软官方文档 快速入门&#xff1a;使用 Docker 运行 SQL Server Linux 容器映像&#xff0c;这里主要是说一些注意点和坑 二、安装 1、拉取镜像 docker pull mcr.microsoft.com/mssql/server:2022-latest2、创建挂载目录&#xff0c;这里只是比官方…

Dagster Pipes系列-1:调用外部Python脚本

本文是"Dagster Pipes教程"的第一部分&#xff0c;介绍如何通过Dagster资产调用外部Python脚本并集成到数据管道中。首先&#xff0c;创建Dagster资产subprocess_asset&#xff0c;利用PipesSubprocessClient资源执行外部脚本external_code.py&#xff0c;实现跨进程…

【SQL系列】多表关联更新

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

C++进阶学习:STL常用容器--map/multimap容器

1. map 容器基本概念 map 中所有元素都是 pair pair 中第一个元素为 key &#xff08;键值&#xff09; 起到索引运用 第二个元素为 value&#xff08;实值&#xff09; 所有元素都会根据元素的键值自动排序 本质&#xff1a; map/multimap 属于关联式容器 底层结构是用二…

let,const,var关键字的区别

let,const,var关键字 let&#xff0c;const&#xff0c;var都存在变量提升 它们都存在变量提升但是稍微有点不同 var变量声明会被提升到作用域的顶部&#xff0c;并且会被初始化为 undefinedlet 和 const&#xff1a;变量声明也会被提升到作用域的顶部&#xff0c;但不会被初…