基于 FFmpeg 的跨平台视频播放器简明教程(十):在 Android 运行 FFmpeg
系列文章目录
- 基于 FFmpeg 的跨平台视频播放器简明教程(一):FFMPEG + Conan 环境集成
- 基于 FFmpeg 的跨平台视频播放器简明教程(二):基础知识和解封装(demux)
- 基于 FFmpeg 的跨平台视频播放器简明教程(三):视频解码
- 基于 FFmpeg 的跨平台视频播放器简明教程(四):像素格式与格式转换
- 基于 FFmpeg 的跨平台视频播放器简明教程(五):使用 SDL 播放视频
- 基于 FFmpeg 的跨平台视频播放器简明教程(六):使用 SDL 播放音频和视频
- 基于 FFmpeg 的跨平台视频播放器简明教程(七):使用多线程解码视频和音频
- 基于 FFmpeg 的跨平台视频播放器简明教程(八):音画同步
- 基于 FFmpeg 的跨平台视频播放器简明教程(九):Seek 策略
前言
在前九章的学习中,我们已经成功地实现了一个基础的播放器,它拥有视频播放、音画同步、快进/快退等基本功能。当然,这个简易的示例还有许多可以优化的地方,比如添加更美观的用户界面,或者增加字幕功能等。然而,这并不是本教程的主要关注点。本系列文章更关注于跨平台播放器框架的构建,特别是在移动端。因此,从本章开始,我们将把重点转向 Android 端播放器的开发。
前置知识包括一些 Android 的基本开发,以及 JNI 开发等。这些前置知识默认你有所了解,本文不会涉及。关于 JNI 可以参考笔者之前写的 JNI 简明教程之手把手教你入门
本文代码在 android/tutorial01。
FFmpeg Android 编译
FFmpeg 的跨端编译也是老生常谈的话题了,本文不去讨论那些细节问题,只想提供一种最便捷的编译方法。在 CompilationGuide/Android 中给出了一些指导意见,例如直接使用已经编译好的 so,或者使用别人写好的脚本。对比了这几个方法,ffmpeg-android-maker 比较合适,优势包括:
- 网上那些已经编译好的 ffmpeg so,ffmepg 版本可能太老了。ffmpeg-android-maker 则是从源码直接编译
- ffmpeg-android-maker 能够自动拉取 ffmpeg 源码,只需要设置少量的变量就能开始编译
- ffmpeg-android-maker 功能、文档写的比较清楚,用起来没有卡点。
那么基于 ffmpeg-android-maker 要如何编译 android ffmpeg 呢?非常简单,步骤如下。
- 下载 ffmpeg-android-marker 仓库
git clone git@github.com:Javernaut/ffmpeg-android-maker.git
cd ffmpeg-android-maker
- 设置环境变量
export ANDROID_SDK_HOME=/Users/user/Library/Android/sdk
export ANDROID_NDK_HOME=/Users/user/Library/Android/sdk/ndk/25.2.9519653
- 运行脚本
./ffmpeg-android-maker.sh
编译成功后,你可以在当前文件夹的 build
目录下找到各个架构的 ffmpeg 库:
build
└── ffmpeg├── arm64-v8a│ ├── bin│ ├── include│ ├── lib│ └── share├── armeabi-v7a│ ├── bin│ ├── include│ ├── lib│ └── share├── x86│ ├── bin│ ├── include│ ├── lib│ └── share└── x86_64├── bin├── include├── lib└── share
其中 include 和 lib 是我们需要的。
FFmpeg so 导入 Android 项目
将 so 文件放置在正确的位置
第一步当然是将编译好的 ffmpeg so 文件和头文件拷贝到我们的项目中。在编译产物中,我们只需要 include 和 lib 文件夹即可,将它们拷贝至 3rdparty/ffmpeg/android 目录下。当然你也可以选择其他地方,这只是我个人的选择。
android
├── arm64-v8a
│ ├── include
│ └── lib
├── armeabi-v7a
│ ├── include
│ └── lib
├── x86
│ ├── include
│ └── lib
└── x86_64├── include└── lib
写 CMake 将 FFmpeg so 引入项目
ffmpeg 有多个 so 文件,在编译项目的过程中,如果一个一个地去写 link 命令有点麻烦。通常的做法是,创建一个新的 library,例如叫 ffmpeg_libs
,让 ffmpeg_libs
去 link 这些 so 文件,然后其他模块 link ffmpeg_libs
就能够链式地将所有依赖都带上了。
这部分属于 CMake 的知识范畴,不细说了,可以参考笔者之前写的 现代 CMake 简明教程(一)- CMake 基础。具体 CMake 源码在 CMakeLists.txt 大家自己看。
写 Kotlin 和 JNI 调用 FFmpeg API
Android app 想要调用 C/C++ 的接口就必须通过 JNI 接口来实现。首先,在应用层定义一个 native method 叫 stringFromFFMPEG
external fun stringFromFFMPEG(): String
接着定义 JNI 层接口,新建 src/cpp/native-lib.cpp
文件,并完成 JNI 层代码:
#include <jni.h>
#include <string>
extern "C"
{
#include <libavutil/avutil.h>
}extern "C" JNIEXPORT jstring JNICALL
Java_com_test_tutorial01_MainActivity_stringFromFFMPEG(JNIEnv* env,jobject /* this */) {std::string hello = "Hello from ffmpeg: " + std::string(av_version_info());return env->NewStringUTF(hello.c_str());
}
最后,我们将 UI 上的 TextView 中的字符串内容修改为这个函数的返回值即可:
binding.sampleText.text = stringFromFFMPEG()
最终呈现的效果如下图:
总结
本文介绍了一种非常便捷的编译 android ffmpeg 的方法:ffmpeg-android-maker。说明如何将 ffmpeg so 库导入至 android 项目中,并提供了实例代码(代码地址:这里)
参考
- JNI 简明教程之手把手教你入门
- CompilationGuide/Android
- 现代 CMake 简明教程(一)- CMake 基础
相关文章:

基于 FFmpeg 的跨平台视频播放器简明教程(十):在 Android 运行 FFmpeg
系列文章目录 基于 FFmpeg 的跨平台视频播放器简明教程(一):FFMPEG Conan 环境集成基于 FFmpeg 的跨平台视频播放器简明教程(二):基础知识和解封装(demux)基于 FFmpeg 的跨平台视频…...

正点原子嵌入式linux驱动开发——Linux LCD驱动
LCD是很常用的一个外设,通过LCD可以显示绚丽的图片、界面等,提交人机交互的效率。STM32MP1提供了一个LTDC接口用于连接RGB接口的液晶屏。本章就来学校一下如何在Linux下驱动LCD屏。 LCD和LTDC简介 LCD简介 这里在当时学习stm32裸机开发的时候就学过了…...

2-Java进阶知识总结-6-多线程
文章目录 多线程--基本概念并发和并行进程和线程多线程 多线程--实现方式一,继承Thread类方法介绍实现步骤注意事项 方式二,实现Runnable接口Thread构造方法实现步骤 方式三,实现Callable接口方法介绍实现步骤 三种多线程实现方法对比 多线程…...

openwrt下游设备在校园网(DLUT-LingShui)中使用ipv6网络
背景:校园网最多支持6台设备的无感认证,需要使用路由器(本人使用openwrt系统)为更多的设备提供网络,但校园网分配的ipv6地址子网为/128,不能为路由器下的设备分配全球ipv6地址,因此需要使用nat6转发下游设备的局域网ip…...

10个基于.Net开发的Windows开源软件项目
1、基于.NET的强大软件开发工具 一个基于.Net Core构建的简单、跨平台快速开发框架。JNPF开发平台前后端封装了上千个常用类,方便扩展;集成了代码生成器,支持前后端业务代码生成,满足快速开发,提升工作效率;…...

Java多线程秘籍,掌握这5种方法,让你的代码优化升级
介绍5种多线程方法,助您提高编码效率! 如果您的应用程序与那些能够同时处理多个任务的应用程序相比表现不佳,很可能是因为它是单线程的。解决这个问题的方法之一是采用多线程技术。 以下是一些可以考虑的方法: 线程(…...
npm install报错 缺少python
报错信息: Building:E:tolsnvmnodesnodeexe : ode emos ant-desig-we-eos odemodules node-gypbintnode-gp.s rebld -verbose -Libsass_ext --Libsas_cflags- lags --libsass_librarygyp info it worked if it ends with ok gyp verb cli [ gyp verb cliE: toolsnv…...

达梦:开启sql日志记录
前言 开启sql日志记录,可协助排查定位数据库问题。生产开启会有一定的性能消耗,建议打开 SQL 日志异步刷盘功能 1.配置sqllog.ini文件 sqllog.ini 用于 SQL 日志的配置,当且仅当 INI 参数 SVR_LOG1 时使用。 运行中的数据库实例,可…...
C语言开发,指针进阶,字符串查找,包含,拼接
文章目录 C语言开发,指针进阶。1.字符串与指针的关系2.指针获取字符串具体内容3.字符串比较,查找,包含,拼接4.字符串大小写 C语言开发,指针进阶。 1.字符串与指针的关系 // // Created by MagicBook on 2023-10-22. …...

PyCharm中文使用详解
PyCharm是一个Python IDE,可以帮助程序员节省时间,提高生产力。那么具体怎么用呢?本文介绍了PyCharm的安装、插件、外部工具、专业功能等,希望对大家有所帮助。 之前没有系统介绍过PyCharm。如何配置环境,如何DeBug&a…...

一键同步,无处不在的书签体验:探索多电脑Chrome书签同步插件
说在前面 平时大家都是怎么管理自己的浏览器书签数据的呢?有没有过公司和家里的电脑浏览器书签不同步的情况?有没有过电脑突然坏了但书签数据没有导出,导致书签数据丢失了?解决这些问题的方法有很多,我选择自己写个chr…...

在Go项目中二次封装Kafka客户端功能
1.摘要 在上一章节中,我利用Docker快速搭建了一个Kafka服务,并测试成功Kafka生产者和消费者功能,本章内容尝试在Go项目中对Kafka服务进行封装调用, 实现从Kafka自动接收消息并消费。 在本文中使用了Kafka的一个高性能开源库Sarama, Sarama是一个遵循MIT许可协议的Apache Kafk…...

CVE-2021-44228 Apache log4j 远程命令执行漏洞
一、漏洞原理 log4j(log for java)是由Java编写的可靠、灵活的日志框架,是Apache旗下的一个开源项目,使用Log4j,我们更加方便的记录了日志信息,它不但能控制日志输出的目的地,也能控制日志输出的内容格式;…...

前端跨域相关
注:前端配置跨域后服务器端(Nginx)也需要配置,否则接口无法访问 vue跨域 配置文件 /vue.config.js devServer: { port: 7100, proxy: { /api: { target: http://域名, changeOrigin: true, logLevel: debug, pathRewrite: { ^/…...

HTML笔记-狂神
1. 初识HTML 什么是HTML? Hyper Text Markup Language : 超文本标记语言 超文本包括:文字、图片、音频、视频、动画等 目前使用的是HTML5,使用 W3C标准 W3C标准包括: 结构化标准语言(HTML、XML) 表现标…...
python自动化测试工具selenium
概述 selenium是网页应用中最流行的自动化测试工具,可以用来做自动化测试或者浏览器爬虫等。官网地址为:Selenium。相对于另外一款web自动化测试工具QTP来说有如下优点: 免费开源轻量级,不同语言只需要一个体积很小的依赖包支持…...

输入/输出应用程序接口和设备驱动程序接口
文章目录 1.输入/输出应用程序接口1.字符设备接口2.块设备接口3.网络设备接口1.网络设备套接字通信 4.阻塞/非阻塞I/O 2.设备驱动程序接口1.统一标准的设备驱动程序接口 1.输入/输出应用程序接口 1.字符设备接口 get/put系统调用:向字符设备读/写一个字符 2.块设备接口 read/wr…...
Python---Socket 网络通信
Socket :进程之间通信的工具,进程之间想要进行网络通信需要Socket,两个进程之间通过socket进行相互通讯,就必须有服务端和客服端。 Socket服务端编程 # 1.创建socket对象 import socketsocket_server socket.socket()# 2. 绑定socket_server到指定IP和…...

使用 jdbc 技术升级水果库存系统(优化版本)
抽取执行更新方法抽取查询方法 —— ResultSetMetaData ResultSetMetaData rsmd rs.getMetaData();//元数据,结果集的结构数据 抽取查询方法 —— 解析结果集封装成实体对象提取 获取连接 和 释放资源 的方法将数据库配置信息转移到配置文件 <dependencies><depend…...

网络协议--广播和多播
12.1 引言 在第1章中我们提到有三种IP地址:单播地址、广播地址和多播地址。本章将更详细地介绍广播和多播。 广播和多播仅应用于UDP,它们对需将报文同时传往多个接收者的应用来说十分重要。TCP是一个面向连接的协议,它意味着分别运行于两主…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...