基于FFmpeg的短视频编辑工具Cut

前言

最近在学习FFmpeg和音视频的相关知识,为了加强对FFmpeg的认识和了解,于是撸了一个短视频编辑软件Cut。

效果图先行:

技术点

启动页优化

但启动app的时候会有一个短暂的黑屏或者白屏。为什么呢? 是因为在App启动时,系统会执行3个Task:

1、 加载并启动app
2、在app启动后,立即展示空白的window
3、创建app进程

一旦app进程完成了第一次绘制,系统进程就会用main activity替换已经展示的background window。之后用户才可以使用app。

这个空白的window就是导致白屏或者黑屏的罪魁祸首。怎么解决呢? 1.定义透明的主题,parent中的AppTheme为APP的主题
 

<style name="Theme.AppStartLoadTranslucent" parent="AppTheme">  <item name="android:windowIsTranslucent">true</item>  <item name="android:windowNoTitle">true</item>  </style>  

<!-- 启动界面 -->  <activity  android:name=".ui.LaunchActivity"  android:launchMode="singleTask"  android:theme="@style/Theme.AppStartLoadTranslucent">  <intent-filter>  <action android:name="android.intent.action.MAIN" />  <category android:name="android.intent.category.LAUNCHER" />  </intent-filter>  </activity> 

启动页优化原理

增量更新和全量更新

在App用了增量更新。

增量更新:增量更新是指在进行更新操作时,只更新需要改变的地方,不需要更新或者已经更新过的地方则不会重复更新,增量更新与全量更新相对。

使用的是bsdiff、 在bspatch中还会用到bzip2.
增量更新的流程:下载差分包,手机上的apk和差很包合并形成新的apk,然后再次安装。
 

  DownloadUtil.get().download(appPath, savePath, saveName,new DownloadUtil.OnDownloadListener() {@Overridepublic void onDownloadSuccess(File file) {if(file != null){mProgressDialog.dismiss();LogUtil.e("tag", "---path = " + file.getAbsolutePath());if(update_type == 1){//获取当前应用的apk文件/data/app/appString oldFile = Utils.getSourceApkPath(LaunchActivity.this, getPackageName());//2.合并得到最新版本的APK文件String newApkPath = MApplication.VIDEO_PATH+"meger.apk";//下载差分包的地址String patchFileAbsolutePath = file.getAbsolutePath();LogUtil.e(TAG, "oldfile:"+oldFile);LogUtil.e(TAG, "newfile:"+newApkPath);LogUtil.e(TAG, "patchfile:"+patchFileAbsolutePath);//jni调用baspatch old.APK 和 差分包 合成新的apkBspatchNDK.bspatch(oldFile, newApkPath, patchFileAbsolutePath);//再次安装Utils.installApk(LaunchActivity.this,newApkPath);}else if(update_type == 2){Utils.installApk(LaunchActivity.this,file);}}}@Overridepublic void onDownloading(int progress) {mProgressDialog.setProgress(progress);}@Overridepublic void onDownloadFailed() {mProgressDialog.dismiss();}});

这里会有一个问题?这个差分包,是什么版本和新版本的差分包?我这里是这样处理的:假如市场发布了1.0.01.0.11.0.2,最新版本为1.0.3.
差分包patch是:1.0.21.0.3生成的差分包。
因此:当且仅有版本为1.0.2(前一个版本),才能进行增量更新,1.0.2之前的(前一个版本之前的)都需要全量更新。所以在代码中有这样的一段判断:
 

if (MApplication.getUpgradeinfo().versionCode - Utils.getVerCode(this) == 1) {//前一个版本//增量更新//有新版本hasNewVersion = true;update_type = 1;apkUrl = MApplication.QINIU_ADDRESS + "diff-"+MApplication.getUpgradeinfo().versionCode+".patch";}else if(MApplication.getUpgradeinfo().versionCode - Utils.getVerCode(this) > 1){//全量更新hasNewVersion = true;apkUrl = MApplication.getUpgradeinfo().apkUrl;update_type = 2;} else {update_type = 0;hasNewVersion = false;toHome3Second();}

差分包怎么生成?下载了bsdiff,调用命令即可:(我这里是 Mac OS下执行的)

bsdiff old.apk new.apk diff.patch

然后然后就是差分包和旧的apk在Android如何合成的问题了。因为如何在Android使用bspacth,还得需要如何把bapacth引入Android Studio。 所以新开了一篇文章介绍,可以看这里。

ffmpeg命令行使用

FFmpeg的使用整个项目的重点,大部分的功能都需要它。而在之前的一篇文章中有介绍如何编译FFmpeg并且引入Android Studio 使用, 如何在Android 中使用FFmpeg命令。

ffmpeg命令

在项目中,使用的命令有:改变视频的速度,改变视频的分辨率,视频和视频的连接,视频和图片的合成,视频的剪辑。

【免费分享】音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击788280672加群免费领取~

改变视频的速度

点击分镜,会弹出一个popup可以选择分镜播放的速度

/*** 改变视频的速度的ffmpeg命令 atempo【0.5,2】*  ffmpeg -i input.mkv -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" output.mkv* @param videoPath 输入录像* @param outPath 输出路径* @param speed 速度* @return*/private String getSpeedCommandStr(String videoPath, float speed, String outPath) {if (TextUtils.isEmpty(videoPath) || TextUtils.isEmpty(outPath)) {return null;}String filter = String.format(Locale.getDefault(), "[0:v]setpts=%f*PTS[v];[0:a]atempo=%f[a]", 1/speed, speed);StringBuilder sb = new StringBuilder("ffmpeg");sb.append(" -i");sb.append(" "+videoPath);sb.append(" -filter_complex");sb.append(" "+filter);sb.append(" -map");sb.append(" [v]");sb.append(" -map");sb.append(" [a]");sb.append(" -b:v 3000k -g 25");sb.append(" -y");sb.append(" "+outPath);LogUtil.d(TAG,"------- cmd = " + sb.toString());return sb.toString();}

视频和视频的连接

在项目中共有3个分镜头,最后需要把这三个分镜合成一个完整的视频:

 /*** 合成视频命令* ffmpeg -f concat -i filelist.txt -c copy output.mkv* @param path* @return-vcodec libx264*/private String getComplexVideoCmd(String fileList,String path) {StringBuilder builder = new StringBuilder();builder.append("ffmpeg -f concat -safe 0 -i ");builder.append(fileList);
//        builder.append(" -b:v 4000K -b:a 96K ");
//        builder.append("-profile:v baseline -preset ultrafast ");
//        builder.append(" -b:v 1500K -b:a 48K -f mp4 ");builder.append(" ");builder.append(path);LogUtil.d(TAG,"----- 合成视频命令 = " + builder.toString());return builder.toString();}

在视频连接的时候会有一个坑,因为在fileList.txt里面写入的路径是绝对路径,在使用ffmpeg 命令连接视频的时候,会报 Operation not permitted的错误。加上-safe 0就可以解决了。

改变视频的分辨率

每一分镜的视频来源有可能是录制的,也可能是选择本地视频剪辑一部分的,因此分辨率和码率都会各部相同,就对每一分镜统一成相同分辨率和码率,如果不统一,不然会在视频连接的生成的视频会丢帧的厉害。

  /*** 改变视频分辨率的命令* @param videoPath* @return*/private String getChangeVideoSizeCmd(String videoPath,String outPath) {if (TextUtils.isEmpty(videoPath) || TextUtils.isEmpty(outPath)) {return null;}StringBuilder builder = new StringBuilder();builder.append("ffmpeg -y -i ");builder.append(videoPath);builder.append(" -vf scale=1080:1920 -r 25 ");builder.append(outPath);LogUtil.e(TAG, "----- 改变视频size 命令 = " + builder.toString());return builder.toString();}

视频的剪辑

对本地的视频剪辑出其中的一部分 ,现在固定3s。

 StringBuilder builder = new StringBuilder();builder.append("ffmpeg -ss ");builder.append(start);builder.append(" -t ");builder.append(duration);builder.append(" -i ");builder.append(inputFile);
//        builder.append(" -vcodec copy -acodec copy -b:v 4000K -b:a 96K -f mp4 ");builder.append(" -vcodec copy -acodec copy ");builder.append(MApplication.VIDEO_PATH);builder.append(outputName);LogUtil.e(TAG,"------------ 剪辑视频ffmpeg 命令 = " +builder.toString());final String[] command = builder.toString().split(" ");

视频和图片的合成

把三个分镜头合成一个视频后,可以对视频进行涂鸦,帖子,添加文本等操作。

   StringBuilder sb = new StringBuilder();sb.append("ffmpeg");sb.append(" -y -i");sb.append(" "+path);sb.append(" -i");sb.append(" "+imagePath);sb.append(" -filter_complex overlay ");sb.append(mergeVideo);String[] cmds = sb.toString().split(" ");LogUtil.d(TAG, "----- overlay 命令 " + sb.toString());

不足

在这个项目中,完成初期的预想,加深对FFmpeg认识和了解。但是1.0版本存在很多的不足,比如:

  1. 速度的变换范围少
  2. 合成视频画质差
  3. FFmpeg对一些功能,比如:在overlay做叠加,用scale缩放,改变速度功能较慢 。
  4. 不能添加滤镜

后记

这个项目将会一直会维护下去,完善所能知道的一些不足的地方,还请大家多多指导和多提意见,互相学习,感谢。

Thanks
FFmpeg
glide
butterknife
BaseRecyclerViewAdapterHelper
okhttp
bspatchlibrary
ffmpeglibrary
circular-progress-button
material-dialogs
Zhaoss
视频裁剪

作者:maimingliang
原文 基于FFmpeg的短视频编辑工具Cut - 掘金

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

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

相关文章

智能分析网关V4在工业园区周界防范场景中的应用

一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;对…

分布式系统——共识问题

1. 分布式系统 1.1 分布式系统的概念 分布式系统是由多台计算机组成的网络&#xff0c;这些计算机共同协作以实现一个共同的目标。在这种环境中&#xff0c;每台计算机作为一个独立的进程运行。但对最终用户来说&#xff0c;它们似乎是作为一个单一系统在操作。这个概念对于创…

大学生搜题软件,未来可期吗?

作为一家专注于软件开发的公司《智创有术》&#xff0c;我们致力于为客户提供创新、高效和可靠的解决方案。通过多年的经验和专业知识&#xff0c;我们已经在行业内建立了良好的声誉&#xff0c;并赢得了客户的信任和支持。 支持各种源码&#xff0c;网站搭建&#xff0c;APP&a…

数字孪生在增强现实(AR)中的应用

数字孪生在增强现实&#xff08;Augmented Reality&#xff0c;AR&#xff09;中的应用可以提供更丰富、交互性更强的现实世界增强体验。以下是数字孪生在AR中的一些应用&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff…

GBASE南大通用-Command 属性

GBASE南大通用CommandText 属性 获取或者设置要在数据源中执行的 SQL 语句&#xff0c;默认是空字符串。  语法 [Visual Basic] Public Overrides Property CommandText As String Get Set [C#] GBASE南大通用public override string CommandText { get; set; }  …

视频剪辑实战:如何批量嵌套合并视频,提高剪辑效率必备技巧

在视频剪辑工作中&#xff0c;经常要处理大量的视频片段。要提高工作效率&#xff0c;批量嵌套合并视频成为了一项必备技巧。现在一起看看云炫AI智剪如何使用一些实用的技巧&#xff0c;快速、准确地完成批量嵌套合并视频的任务。 合并后的视频截图&#xff0c;由两段不同片段组…

【STM32】STM32学习笔记-DMA直接存储器存储(23)

00. 目录 文章目录 00. 目录01. DMA简介02. DMA主要特性03. 存储器映像04. DMA框图05. DMA基本结构06. DMA请求07. 数据宽度与对齐08. 数据转运DMA09. ADC扫描模式DMA10. 附录 01. DMA简介 小容量产品是指闪存存储器容量在16K至32K字节之间的STM32F101xx、STM32F102xx和STM32F…

解决Gitlab Prometheus导致的磁盘空间不足问题

解决Gitlab Prometheus导致的磁盘空间不足问题 用docker搭建了一个gitlab服务&#xff0c;已经建立了多个项目上传&#xff0c;但是突然有一天就503了。 df -TH查看系统盘&#xff0c;发现已经Used 100%爆满了。。。 &#x1f4a1;Tips&#xff1a;/dev/vda1目录是系统盘目录。…

AntV L7 实现地图功能(高德)

一、 使用前的准备 首先&#xff0c;注册开发者账号&#xff0c;成为高德开放平台开发者 登陆之后&#xff0c;在进入「应用管理」 页面「创建新应用」 为应用添加 Key&#xff0c;「服务平台」一项请选择「 Web 端 ( JSAPI ) 」 二、安装依赖 // 安装L7 依赖 npm install…

【AI】WSL安装Anaconda

书接上篇&#xff0c;我们构建了wsl的CUDA环境&#xff0c;还有python环境没有搭建&#xff0c;这里我们就安装Anaconda来进行搭建python环境。 0.下载Anaconda安装包 这里有两个方式&#xff0c;一是直接在wsl中执行wget命令下载&#xff0c;这种方式没什么好说的&#xff0…

数据预处理 虚战1

import pandas as pd import numpy as npdf pd.read_csv(diabetes.csv)def preprocess(df):print(----------------------------------------------)print("Before preprocessing")print("Number of rows with 0 values for each variable")#遍历每一列fo…

2024年【危险化学品生产单位主要负责人】复审模拟考试及危险化学品生产单位主要负责人作业模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年危险化学品生产单位主要负责人复审模拟考试为正在备考危险化学品生产单位主要负责人操作证的学员准备的理论考试专题&#xff0c;每个月更新的危险化学品生产单位主要负责人作业模拟考试祝您顺利通过危险化学品…

深度学习 Day23——J3DenseNet算法实战与解析

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制&#x1f680; 文章来源&#xff1a;K同学的学习圈子 文章目录 前言1 我的环境2 pytorch实现DenseNet算法2.1 前期准备2.1.1 引入库2.1.2 设…

C++学习笔记(二十六):c++ 复制与拷贝构造函数

本节介绍拷贝构造函数。当我们复制数据或对象是一般情况下我们会有两个副本。但当我们仅需要读取数据或者修改一个已经存在的对象时&#xff0c;我们不想去复制一份副本&#xff0c;这样会造成性能的损耗。理解什么时候复制&#xff0c;什么时候不需要复制对提升程序的性能有较…

数据库服务器如何处理并发访问请求?

在当今的数字化时代&#xff0c;并发访问请求的处理已成为数据库服务器的重要挑战之一。随着应用程序和互联网的普及&#xff0c;数据库服务器需要处理来自大量用户和设备的并发访问请求&#xff0c;这对其性能和可扩展性提出了更高的要求。本文将探讨数据库服务器如何处理并发…

flutter 使用adb 同时连接 多个模拟器

MUMU模拟器 MuMu模拟器官网_安卓12模拟器_网易手游模拟器 传统只需要 连接一个 默认命令是 默认端口是7555 adb connect 127.0.0.1:7555 但是需要同时连接调试多个模拟器的时候 就需要连接多个 这里可以使用自带的多开 多开后 使用 1 是对应多开的序号 这样就可以查看对…

我是谁 whoami

文章目录 我是谁 whoami更多信息 我是谁 whoami 我知道你是谁&#xff0c;但我不知道我是谁&#xff0c;此时whoami可以帮助你&#xff0c;哈哈。 whoami将打印当前用户的名字。与id -un类似。 官方定义为&#xff1a; whoami - print effective userid 用法为&#xff1a; …

Redis基础学习一

1. Redis 入门 1.1. Redis 诞生历程 1.1.1.从一个故事开始 08 年的时候有一个意大利西西里岛的小伙子&#xff0c;笔名 antirez&#xff08;http://invece.org/&#xff09;&#xff0c;创建了一个访客信息网站 LLOOGG.COM。有的时候我们需要知道网站的访问情况&#xff0c;…

高级数据结构:并查集

文章目录 1.什么是并查集&#xff1a;2、并查集的基本结构3.现实问题和代码实现链接4.代码实现 1.什么是并查集&#xff1a; 对于一个集合S{a1,a2,……an-1,an}&#xff0c;这是可以对集合S进一步划分&#xff1a;S1&#xff0c;S2&#xff0c;……&#xff0c;Sm-1&#xff0…

阿里云迁移AWS视频点播技术攻坚

文章目录 &#x1f437; 背景&#x1f9a5; 简述&#x1f425; Aws服务&#x1f99c; AWS CloudFormation&#x1f41e; 问题&#x1f409; 落地方案&#x1f989; Aws vs Aliyun&#x1f344; 避坑指南 &#x1f437; 背景 由于AWS整体成本略低于阿里云&#xff0c;公司决定将…