基于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() {
            @Override
            public void onDownloadSuccess(File file) {

                if(file != null){
                    mProgressDialog.dismiss();
                    LogUtil.e("tag", "---path = " + file.getAbsolutePath());

                    if(update_type == 1){
                        //获取当前应用的apk文件/data/app/app
                        String 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 和 差分包 合成新的apk
                        BspatchNDK.bspatch(oldFile, newApkPath, patchFileAbsolutePath);
                        
                        //再次安装
                        Utils.installApk(LaunchActivity.this,newApkPath);
                    }else if(update_type == 2){
                        Utils.installApk(LaunchActivity.this,file);
                    }


                 }

            }

            @Override
            public void onDownloading(int progress) {
                mProgressDialog.setProgress(progress);

            }

            @Override
            public 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.mfbz.cn/a/297057.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

腾讯云2核2G3M服务器够用吗?腾讯云2核2G3M云服务器性能评测

阿里云轻量应用服务器2核2G3M带宽优惠价格62元一年&#xff0c;100%CPU性能&#xff0c;3M带宽下载速度384KB/秒&#xff0c;40GB SSD系统盘&#xff0c;月流量200GB&#xff0c;折合每天6.6GB流量&#xff0c;超出月流量包的流量按照0.8元每GB的价格支付流量费&#xff0c;地域…

kubesphere和k8s的使用分享

文章目录 什么是kubernetesKubernetes的部分核心概念互式可视化管理平台与kubernetes的关系市面是常见的kubernetes管理平台 什么是kubesphereKubesphere默认安装的组件Kubesphere涉及的服务组件kubesphere的安装Kubesphere相关的内容 什么是kubernetes 就在这场因“容器”而起…

Vue CLI组件通信

目录 一、组件通信简介1.什么是组件通信&#xff1f;2.组件之间如何通信3.组件关系分类4.通信解决方案5.父子通信流程6.父向子通信代码示例7.子向父通信代码示例8.总结 二、props1.Props 定义2.Props 作用3.特点4.代码演示 三、props校验1.思考2.作用3.语法4.代码演示 四、prop…

科锐16位汇编学习笔记 03 汇编指令

指令种类 数据传送指令算数运算类指令位操作类指令串操作类指令控制转移类指令处理器控制类指令 数据传送类指令 传送类指令不影响标志位&#xff0c;**除了标志位传送指令外。** 传送指令MOV&#xff08;move&#xff09; 说明 ​ 把一个字节或字的操作数从源地址传送至…

swift ——多行文字前面内容省略

首先来说一说ios中的 lineBreakModelineBreakMode : 设置文字过长时的显示截断样式 可选值如下 byWordWrapping &#xff1a; 以单词为单位换行&#xff0c;以单词为单位截断。byCharWrapping &#xff1a;以字符为单位换行&#xff0c;以字符为单位截断。byClipping &#x…

Linux进程管理、ps命令、kill命令

每一个程序在运行的时候都会被操作系统注册为系统中的一个进程 补充一下操作系统的内容&#xff1a; 进程实体&#xff08;又称进程映像&#xff09;&#xff1a;程序段、相关数据段、PCB三部分构成 进程是进程实体的运行过程&#xff0c;是系统进行资源分配的一个独立单位 …

关于时间格式yyyy-M-d或yyyy-MM-d到yyyy-MM-dd的转换

工作时遇到前端传的时间格式是"2023-12-3 17:41:52"&#xff0c;和"2023-1-1 17:41:52"但是我想要的是"2023-12-03 17:41:52"和"2023-01-01 17:41:52"。下面给大家分享几个解决方法 方法一&#xff1a; 找前端&#xff01;让他改&…

关于《码农翻身》一书的读后感以及自己的一些拙见汇总

书籍名称 《码农翻身》 | 刘欣&#xff08;码农翻身&#xff09; 著 | 文章将以问答的形式进行叙述 1.是从什么渠道接触到《码农翻身》的 一个工作日的下午&#xff0c;手上的任务基本结束&#xff0c;翻了翻桌上的书和笔记之类的&#xff0c;同事见我在看书&#xff0c;于是向…

用opencv的DNN模块做Yolov5目标检测(纯干货,源码已上传Github)

最近在微信公众号里看到多篇讲解yolov5在openvino部署做目标检测文章&#xff0c;但是没看到过用opencv的dnn模块做yolov5目标检测的。于是&#xff0c;我就想着编写一套用opencv的dnn模块做yolov5目标检测的程序。在编写这套程序时&#xff0c;遇到的bug和解决办法&#xff0c…

Mac启动时候出现禁止符号

Mac启动时候出现禁止符号 启动时候出现禁止符号,意味着 选定的启动磁盘 包含 Mac 操作系统&#xff0c;但它不是 您的 Mac 可以使用的 macOS 。您应该在这个磁盘上 重新安装 macOS 。 可以尝试以下苹果提供的方法&#xff1a; Mac启动时候出现禁止符号 不要轻易抹除磁盘&am…

2023 最火的是什么? 超维计算 + 神经网络

从chatgpt开始&#xff0c;人工智能进步的步伐似乎势不可挡&#xff0c;但支撑这些程序的人工神经网络遇到了一些重大限制&#xff0c;其他的很难推理但是人类的大脑能够通过类比进行推理&#xff0c;当我们看到新事物时&#xff0c;我们不必生长新的神经元&#xff0c;我们可以…

【python】Python 3.11不支持Tix库

Tix库主要用于扩展Tkinter&#xff0c;但是Python 3.11 Tkinter已经不再支持Tix库。Tix模块提供了一些额外的部件和功能&#xff0c;但现在这些功能已经整合到了Tkinter库中。 一、如果在Python 3.11中想要使用Tix库&#xff0c;但发现它不再被内置支持&#xff0c;可以尝试以…

QCharView使用

QChart是 QGraphicsWidget的子类。 QCharView是QGraphicsView的子类 QCharView概念:title、系列、图标Chart、视图 说明: 需要添加Qt组件charts 在使用QChart或者QChartView之前需要添加宏定义QT_CHARTS_USE_NAMESPACE &#xff08;其实是使用了命名空间&#xff09;&#xff…

KVM虚拟化技术

在当今的云计算时代&#xff0c;虚拟化技术已经成为了企业和个人用户的首选。而在众多虚拟化技术中&#xff0c;KVM&#xff08;Kernel-based Virtual Machine&#xff09;虚拟化技术因其高性能、低成本和灵活性而备受青睐。本文将介绍KVM虚拟化技术的原理、特点以及应用场景。…

CDMP考试解析:从报名到成功不走弯路

❤️CDMP数据管理专业认证是由DAMA国际于2004推出&#xff0c;是一项涵盖学历教育、工作经验和专业知识考试在内的综合资格认证&#xff0c;也是目前全球wei一数据管理方面权威性认证。 &#x1f4b0;考试费用&#xff1a;CDMP的考试费用约为每科2500元。 其他可能的费用&#…

【web】Springboot3 集成 Swagger3

文章目录 Maven 依赖配置类&#xff08;可选&#xff09;访问示例 Maven 依赖 <!--swagger3--> <dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-ui</artifactId><version>2.0.2</v…

什么是谐波减速机?日本Harmonic哈默纳科谐波减速机有哪些优点?

一、什么是谐波减速机&#xff1f; 谐波减速装置最早期被叫做“strain wave gearing”&#xff0c;直译过来为“应变波齿轮”。其后被HarmonicDrive Systems 公司大规模商业实用化后&#xff0c;经过二次翻译后&#xff0c;中文名称才将其称为“谐波齿轮传动”。 谐波减速机是…

Ubuntu18 安装chatglm2-6b

记了下Ubuntu18 上安装chatglm2-6遇到的问题。 环境&#xff1a;Ubuntu18.04 V100(显卡) nvcc 11.6 显卡驱动cudacudnnaniconda chatglm6b 的安装 网上有很多&#xff0c; 不记录 了。 chatglm2-6b 我从别的地方拷贝的&#xff0c; 模型也包含了。 遇到的问题&#xf…

C++补充内容--语法篇

这里写目录标题 语法其他语法函数的存储类函数参数默认值格式默认参数位置重载函数的默认参数 指针名与正常指针的自增自减以及解引用与的优先级问题指针的赋值、加减数字、加减指针二维数组中的一些指针辨析输出调用字符指针时 会将该指针以及之后的元素全部输出二维数组未完全…

【Docker】配置阿里云镜像加速器

默认情况下&#xff0c;将来从docker hub &#xff08;https://hub.docker.com )上下载镜像太慢&#xff0c;所以一般配置镜像加速器。 没有账号的注册一个账号并登录 登录之后点击控制台 查看 cat /etc/docker/daemon.json
最新文章