基于 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是一个面向连接的协议,它意味着分别运行于两主…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...
