在安卓中使用 FFmpegKit 剪切视频并添加文字水印

在安卓中用到的三方库:https://github.com/arthenica/ffmpeg-kit

这个库很强大,支持很多平台,每个平台都有各自的分支代码,用了一段时间,稳定性挺好的,

找到安卓下的分支:FFmpegKit for Android FFmpegKit Android 版

引入项目:

repositories {mavenCentral()
}dependencies {implementation 'com.arthenica:ffmpeg-kit-full:6.0-2'
}

每个平台下,又分为多个库,每个库包含不同的功能,因为功能越丰富,导入到项目中编译的包体积越大,尽量选择适合自己功能的库进行使用。


📦 FFmpeg 编译配置选项(库依赖分类)

配置项说明包含的库
min最小化构建-
min-gpl最小化构建并启用 GPL 库vid.stab, x264, x265, xvidcore
https启用 HTTPS 支持(使用非-GPL 依赖)gmp, gnutls
https-gpl启用 HTTPS 支持(使用 GPL 兼容依赖)gmp, gnutls, vid.stab, x264, x265, xvidcore
audio启用音频相关编码器/解码器lame, libilbc, libvorbis, opencore-amr, opus, shine, soxr, speex, twolame, vo-amrwbenc
video启用视频相关编码器/解码器dav1d, fontconfig, freetype, fribidi, kvazaar, libass, libiconv, libtheora, libvpx, libwebp, snappy, zimg
full启用所有非 GPL 第三方库dav1d, fontconfig, freetype, fribidi, gmp, gnutls, kvazaar, libass, libiconv, libilbc, libtheora, libvorbis, libvpx, libwebp, libxml2, opencore-amr, opus, shine, snappy, soxr, speex, twolame, vo-amrwbenc, zimg
full-gpl启用所有库(包括 GPL)dav1d, fontconfig, freetype, fribidi, gmp, gnutls, kvazaar, lame, libass, libiconv, libilbc, libtheora, libvorbis, libvpx, libwebp, libxml2, opencore-amr, opus, shine, snappy, soxr, speex, twolame, vid.stab, vo-amrwbenc, x264, x265, xvidcore, zimg

比如你如果只需要保存 rtsp 视频流 和 推流的话,只需要导入 min-gpl即可:

 implementation 'com.arthenica:ffmpeg-kit-min-gpl:6.0-2'

如果你想要更多,比如添加水印,就涉及到 FFmpeg 滤镜相关功能,就需要引入full-gpl

 implementation 'com.arthenica:ffmpeg-kit-full-gpl:6.0-2'

具体需要什么功能,可以进去看说明,说明没有涉及到的,并且你不想用全功能库,你也可以一个一个试试,也许就能满足你。

正文开始


由说明可知,使用方式为:

import com.arthenica.ffmpegkit.FFmpegKit;FFmpegSession session = FFmpegKit.execute("-i file1.mp4 -c:v mpeg4 file2.mp4");
if (ReturnCode.isSuccess(session.getReturnCode())) {// SUCCESS} else if (ReturnCode.isCancel(session.getReturnCode())) {// CANCEL} else {// FAILURELog.d(TAG, String.format("Command failed with state %s and rc %s.%s", session.getState(), session.getReturnCode(), session.getFailStackTrace()));}

或者异步调用:

FFmpegKit.executeAsync("-i file1.mp4 -c:v mpeg4 file2.mp4", new FFmpegSessionCompleteCallback() {@Overridepublic void apply(FFmpegSession session) {SessionState state = session.getState();ReturnCode returnCode = session.getReturnCode();// CALLED WHEN SESSION IS EXECUTEDLog.d(TAG, String.format("FFmpeg process exited with state %s and rc %s.%s", state, returnCode, session.getFailStackTrace()));}
}, new LogCallback() {@Overridepublic void apply(com.arthenica.ffmpegkit.Log log) {// CALLED WHEN SESSION PRINTS LOGS}
}, new StatisticsCallback() {@Overridepublic void apply(Statistics statistics) {// CALLED WHEN SESSION GENERATES STATISTICS}
});

与正常 ffmpeg 命令不同的是,在传入命令时,前面不需要加 “ffmpeg” 关键字,只需传入后面的具体命令即可,加上会报错哦!

关键代码:

搞了好久才凑齐的正确代码,这东西真不能听 AI 的一面之辞,不然就被 AI 一条路领到黑,

    private static String buildWatermarkCommand(VideoFile file, VideoTimeRange timeRange, String outputPath, String fontPath) {FFmpegKitConfig.setFontconfigConfigurationPath(fontPath);String drawtextFilter = String.format("drawtext=text='%s':fontfile=%s:fontcolor=white:fontsize=20:x=0:y=30",DEFAULT_WATERMARK, fontPath);List<String> commandList = new ArrayList<>();commandList.add("-ss");                              // 指定输入文件的开始时间,格式:HH:MM:SScommandList.add(timeRange.startTime);commandList.add("-i");                               // 输入文件路径commandList.add(file.filePath);commandList.add("-t");                               // 指定持续时间,格式:HH:MM:SScommandList.add(timeRange.durationStr);commandList.add("-vf");                              // 视频滤镜,用于添加水印文字commandList.add(drawtextFilter);commandList.add("-c:v");                             // 视频编码器设置commandList.add(VIDEO_CODEC);                        // 使用H.264软件编码器commandList.add("-preset");                          // 编码速度预设commandList.add(VIDEO_PRESET);                       // ultrafast:最快编码速度,文件稍大commandList.add("-crf");                             // 恒定质量因子(0-51,越小质量越好)commandList.add(String.valueOf(VIDEO_CRF));          // 23:平衡质量和文件大小的推荐值commandList.add("-c:a");                             // 音频编码器设置commandList.add("copy");                             // 直接复制音频流,不重新编码commandList.add("-r");commandList.add("20");                               // 每秒20帧commandList.add("-avoid_negative_ts");               // 避免负时间戳问题commandList.add("make_zero");                        // 将负时间戳调整为0commandList.add(outputPath);                         // 输出文件路径return String.join(" ", commandList);}

简单介绍下命令作用:对一段现有的视频文件进行剪辑,-ss指定开始时间,比如要剪切的原视频时长为两分钟,所以开始时间到结束时间就是:00:00:00 - 00:02:00 , 假设要剪辑中间一分钟的视频,那么 -ss指定的开始时间为:00:00:30 , -t持续时间就是:00:01:00 , 截取的时间段为:00:00:30 - 00:01:30 ,-c:v设置编码器,一般 H.264 就够了,如果设置其他的编码器,要看你的设备支持不支持了,-r设置帧率,如果你想要剪切的视频大小小一点,一方面就可以通过降低帧率,另一方面就可以降低码率来实现(上述命令码率未指定默认按原视频码率)。

如果你指定的时间范围,超过原视频时长会报错,这很正常,只是报错内容可能看不懂,这是一个问题点!

设置 FFmpegKitConfig.setFontconfigConfigurationPath的作用是 https://github.com/arthenica/ffmpeg-kit/wiki/Tips 参考第四条:ffmpeg 需要有效的 fontconfig 配置才能在使用 drawtext filter 时渲染文本。

这里指定一个存在的字体路径即可 比如:/system/fonts/NotoSansCJK-Regular.ttc

注意:有的字体不支持中文,写入中文水印的时候会乱码!


视频处理性能测试(A133,Android 10)

测试环境

  • 设备平台:A133
  • 操作系统:Android 10
  • 测试内容:视频加水印 vs 无水印处理
  • 加水印帧率:15fps
  • 视频格式:H.264 (宽高:720x576)(位率:512Kbps)

性能对比数据

视频时长处理方式耗时(ms)耗时(秒)输出文件大小
30s加水印52145.211.5M
30s加水印(15帧)38133.811.5M
30s不加水印1680.170.9M
60s加水印1201312.012.5M
60s加水印(15帧)73927.392.5M
60s不加水印2080.211.5M
120s加水印2200622.015.03M
120s加水印(15帧)1840418.405.03M
120s不加水印2770.282.8M
240s加水印5054750.5510.57M
240s加水印(15帧)3785737.8610.57M
240s不加水印4480.455.24M

在 A133 平台上,加水印操作是性能瓶颈,视频重编码操作对cpu要求比较高。


补充

在低端设备使用FFmpeg处理视频显然是不推荐的,更是不明智的,除非无可选择,可以选择的替代方式为在手机或者在服务器进行视频处理操作,这样速度和体验感更好。

在手机处理发现 不设置 FFmpegKitConfig.setFontconfigConfigurationPath也可以正常添加水印,这个操作应该是可有可无的!或者在特殊地方才会使用到它,有待发现。

开发中发现,只有full-gpl库,才能进行加水印重编码操作,其他库均不行,没办法,只有一个加水印操作也要引入全功能,apk包体积大概增加13M左右,而且这只是在应用只支持arm64-v8a的情况下,多一个就翻一倍!

而且full-gpl:6.0-2最低要求sdk 24,如果你的应用之前最小sdk 小于23,然后改为24时你会发现,包体积大小剧增,这是因为minSdkVersion >= 23 默认不压缩so 大小 ,导致apk体积会变大,大于23 就在清单文件的application标签下设置 android:extractNativeLibs="true" 压缩so ,就正常了。

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

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

相关文章

Flask + HTML 项目开发思路

Flask HTML 项目开发思路&#xff1a;以公共资源交易信息展示为例 一、开篇明义——为什么选 Flask 框架 在众多 Python Web 框架&#xff08;如 Django、Tornado 等&#xff09;里&#xff0c;本次项目坚定选择 Flask&#xff0c;背后有清晰的技术考量&#xff1a; 1. 轻量…

Vue中:deep()和 ::v-deep选择器的区别

在 Vue.js 中&#xff0c;:deep()和 ::v-deep都是用于穿透组件作用域的深度选择器&#xff0c;但它们在语法、适用场景和版本支持上存在区别。以下是两者的核心差异&#xff1a;一、​​语法与用法​ &#xff1a;Vue2中用 ::v-deep&#xff0c;Vue2中不支持:deep()&#xff0c…

Deep learning based descriptor

1、DH3D: Deep Hierarchical 3D Descriptors for Robust Large-Scale 6DoF Relocalization 论文链接 代码链接 这是一篇训练点云的文章&#xff0c;在训练出local descriptor之后&#xff0c;通过聚类的方法得出global descriptor&#xff0c;并且提出了hierarchical network&…

PandasAI连接LLM对MySQL数据库进行数据分析

1. 引言 在之前的文章《PandasAI连接LLM进行智能数据分析》中实现了使用PandasAI连接与DeepSeek模型通过自然语言进行数据分析。不过那个例子中使用的是PandasAI 2.X&#xff0c;并且使用的是本地.csv文件来作为数据。在实际应用的系统中&#xff0c;使用.csv作为库表的情况比…

FloodFill算法——DFS

FloodFill算法就是用来寻找性质相同的连通快的算法&#xff0c;这篇博客都是用dfs来实现FloodFill算法 1.图像渲染 题目链接&#xff1a;733. 图像渲染 - 力扣&#xff08;LeetCode&#xff09; 题目解析&#xff1a;将和&#xff08;sr,sc&#xff09;相连的所有像素相同的…

【BUUCTF系列】[极客大挑战 2019]LoveSQL 1

本文仅用于技术研究&#xff0c;禁止用于非法用途。 Author:枷锁 文章目录一、题目核心漏洞分析二、关键解题步骤与技术解析1. 确定列数&#xff08;ORDER BY&#xff09;2. 联合查询获取表名3. 爆破字段名4. 提取Flag三、漏洞根源与防御方案1. 漏洞成因2. 防御措施四、CTF技巧…

AI时代,童装销售的“指路明灯”

别看现在AI、大数据这些词眼花缭乱的&#xff0c;当年我刚入行那会儿&#xff0c;也跟你一样&#xff0c;对着一堆库存和销量数据发愁&#xff0c;不知道劲儿该往哪使。童装销售这行&#xff0c;看着简单&#xff0c;其实水挺深。不过呢&#xff0c;这二十多年摸爬滚打下来&…

Swin-Transformer从浅入深详解

第一部分&#xff1a;出现背景在 Swin Transformer 出现之前&#xff0c;计算机视觉&#xff08;Computer Vision, CV&#xff09;领域主要由 CNN (卷积神经网络) 主导。后来&#xff0c;NLP&#xff08;自然语言处理&#xff09;领域的 Transformer 模型被引入 CV&#xff0c;…

如何手动打包 Linux(麒麟系统)的 Qt 程序

gcc版本 gcc版本确保目标系统&#xff08;运行环境&#xff09;的 GCC 版本 高于或等于开发环境的版本&#xff0c;否则程序无法在目标平台运行。通过 gcc -v 可查看当前版本。cmake生成可执行文件 强烈建议在cmakelists添加设置运行时 rpath 为 $ORIGIN/…/lib&#xff08;相对…

解决 “crypto.hash is not a function”:Vite 从 6.x 升级至 7.x 后 `pnpm run dev` 报错问题

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template &#x1f33a; 仓库主页&#xff1a; GitCode︱ Gitee ︱ Github &#x1f496; 欢迎点赞 &#x1f44d; 收藏 ⭐评论 …

我的创作纪念日____在 CSDN一年来的成长历程和收获

365 天创作札记&#xff1a;在代码与文字的褶皱里&#xff0c;遇见 1300 束光一年来。点开csdn网站后台粉丝数的那一刻&#xff0c;1327 这个数字在屏幕上微微发烫。原来那些在深夜敲下的字符、调试到凌晨的代码示例、反复修改的技术拆解&#xff0c;真的在时光里悄悄织成了一张…

VirtualBox 的 HOST 键(主机键)是 右Ctrl 键(即键盘右侧的 Ctrl 键)笔记250802

VirtualBox 的 HOST 键&#xff08;主机键&#xff09;是 右Ctrl 键&#xff08;即键盘右侧的 Ctrl 键&#xff09;笔记250802 VirtualBox 的 HOST 键&#xff08;主机键&#xff09;是什么?HOST键 是 右Ctrl 键VirtualBox 的 主机键&#xff08;Host Key&#xff09; 是一个…

Zama的使命

全同态加密&#xff08;Fully Homomorphic Encryption&#xff0c;FHE&#xff09;实现互联网端到端加密的使命的重要里程碑。(FHE) 是一种无需解密即可处理数据的技术。它可用于在公共、无需许可的区块链上创建私人智能合约&#xff0c;只有特定用户才能看到交易数据和合约状态…

Go语言流式输出技术实现-服务器推送事件(Server-Sent Events, SSE)

目录引言背景与技术概述实现技术细节1. HTTP 头部配置2. 事件格式与发送3. 保持连接与刷新4. 处理连接关闭4.1 使用上下文管理连接生命周期4.2 使用通道管理客户端连接5. 客户端交互6.demo7.Go转发大模型流式输出demo引言 服务器推送事件&#xff08;Server-Sent Events, SSE&…

高端房产管理小程序

系统介绍1、用户端地图找房&#xff1a;对接地图API&#xff0c;地图形式显示周边房源,支持新盘和租房两种模式查询房价走势&#xff1a;城市房价走势&#xff0c;由后台每月录入房源搜索&#xff1a;搜索房源&#xff0c;支持多维度筛选房源类型&#xff1a;新盘销售、房屋租赁…

文本转语音(TTS)脚本

文本转语音(TTS)脚本 概述 generate_voice.py 是一个用于生成语音的Python脚本。该脚本提供了文本转语音(TTS)功能&#xff0c;可以将文本内容转换为语音文件。 功能特性 文本转语音: 将输入的文本转换为语音文件多种语音选项: 支持不同的语音类型和参数批量处理: 可以处理多个…

磁盘管理与分区

磁盘管理 一、磁盘类型 SATA,SCSI,SAS类型的磁盘&#xff0c;在Linux中用sd来表示。 其中第一块硬盘为sda&#xff0c;第二块二sdb&#xff0c;以此类推。 第一块硬盘的第一个分区为sda1。 nvme类型的磁盘&#xff0c;在Linux中使用nvmeXnYpZ进行表示。 X&#xff1a;数字&…

Linux 逻辑卷管理

练习创建物理卷(pv->vg->lv)物理卷&#xff08;PV&#xff09;就像把一块块独立的硬盘&#xff0c;标记成 "可用于搭建 LVM 的积木"&#xff0c;让系统知道这些硬盘可以被 LVM 管理。#把sdb这块硬盘标记为物理卷&#xff08;相当于给这块积木盖章&#xff0c;说…

向日葵参考基因组

向日葵参考基因组升级多个版本 向日葵基因组为油脂代谢、开花调控及菊类植物进化提供新见解-文献精读151-CSDN博客 官网 https://www.sunflowergenome.org/annotations-data/

什么是爬虫协议?

什么是爬虫协议&#xff1f; 爬虫协议&#xff08;Crawl Protocol&#xff09;是指为了有效地收集网页内容而建立的一些规定和标准&#xff0c;用以指导网络爬虫如何在互联网上抓取信息。 爬虫协议主要指的是Robots协议&#xff08;Robots Exclusion Protocol&#xff09;&am…