开课吧-AI算法落地与工程部署实战-归鞍白云外,缭绕出前山

#1

download:开课吧-AI算法落地与工程部署实战

优化视频编辑工具的完整指南。
一.背景介绍
随着4G网络的推广和网络带宽的提高,视频已经成为互联网用户的主要消费载体,用户通过短视频分享和浏览信息。因此,视频的编辑功能变得越来越重要和普及。视频编辑应用如雨后春笋般涌现。
更好地推动吴德App的社区业务发展,吴德也开发了自己的符合吴德需求的视频剪辑工具。我们致力于创造一个“更快更强”的视频编辑工具。
二。视频编辑工具介绍
为了让大家更好的了解Get Things App的视频编辑工具,我们先简单介绍一下视频编辑工具的主要功能。
此内容暂时无法在舒菲文档之外显示。
以下是Get Things App的视频编辑工具的主要功能:

视频编辑工具关注以下内容:

视频编辑工具要操作的资源:

词:包括普通词、特殊艺术词、花语词等。
图片:包括静态图片,如JPEG/PNG等。,以及HEIC/GIF等动态图片。
视频:包括各类视频(各种编码和封装格式),主流格式一般有MP4封装格式、H264视频编码格式、AAC音频编码格式等等。
音频:包括各种音频(各种编码和打包格式),当然视频也包括音轨。

视频编辑工具的主要操作模式:

操作图片,视频帧:我们知道视频是由一帧一帧的图片组成的,所以操作视频帧和操作图片是一样的。我们在图片和视频帧上添加一些特效,达到一些有趣的效果来吸引用户。
音频操作:主流音频操作方式,如倍速、音量调节、变调等。,是现在短视频的主要播放方式。

编辑工具最后生成一个新的视频,将一些特效应用到特定的资源上,生成一个新的视频。
下面的流程图可以轻松让你了解视频编辑的工作流程。为了方便,我们输入一个视频,加上一些特效,生成一个新的视频。
此内容暂时无法在舒菲文档之外显示。
从上述过程可以看出,原始视频A.mp4被解包并分离成音频轨道和视频轨道。在对它们进行解码之后,音频特效被应用于音频数据,视频特效被应用于视频帧数据,然后被编码和封装以形成新的视频。当然解码和编码都是由一个队列控制的,流程图上有标注,但没有深入展开,大家可以理解。
经过上面的介绍,我们对视频编辑工具有了大致的了解。其实衡量一个视频编辑工具做得好不好,主要从以下几个方面入手:

内存占用

视频导出速度有多快?

导出的视频有多清晰?

从以下三个方面来阐述优化吴德App视频剪辑工具的心理过程。
第三,内存优化
性能是所有程序的首要指标。即使一个工具很强大,它也会在某一点崩溃,或者使用的内存激增,应用程序卡住。这个应用估计不能称之为优秀的应用。下面详细说说视频编辑工具的优化检测方案。
优化内存从良好的编码习惯开始,尤其是对于需要大量内存的音频和视频应用。比如一个1080 * 1920的视频,解码后的原始数据有1080 * 1920的帧图像大小,占用的内存是1080 * 1920 * (8 * 3)/8 = 5.93 MB,那么一个视频帧占用这么多,一般每秒有30帧,占用177.9MB,如果不控制的话,占用多少都没关系。希望下面的内存检测和优化方案能给你一些帮助。
3.1合理设计队列
在上面介绍视频编辑过程的视频中,我们谈到了解码队列和编码队列的概念。事实上,队列的概念在音视频中被频繁使用,也正是因为内存的限制,才引入了队列控制的方法。你可能还有点困惑,但看完下面的流程图,相信你会豁然开朗。
我们只选择解码部分来分析队列的重要应用。
此内容暂时无法在舒菲文档之外显示。
视频编辑工具中有几个重要的队列:

解码期间:

视频包队列:视频解码前存储包的队列。通常,推荐的队列大小是100
音频包队列:音频解码前存储包的队列,一般推荐的队列大小为150。
视频帧队列:视频解码后存储在帧中的队列。通常,推荐的队列大小是3
音频帧队列:音频解码后存储在帧中的队列,一般推荐的队列大小为8。

在编码过程中:

编码视频包队列:视频编码后存储包的队列,一般推荐大小为100。
编码音频包队列:存储音频编码后的包的队列,一般推荐大小为150。

通过上述方式设计队列的大小,可以在保证功能正常的同时,最大程度地减少内存占用,提高用户体验。
3.2排除内存泄漏故障
Android上有很多方法可以解决内存泄漏问题。这里有两个:

Asan检测

轮廓检测

Asan全称AddressSanitizer,是一个基于编译器的工具,用于快速检测本机代码中的内存错误。Asan可以解决以下四个核心问题:

以及堆缓冲区溢出和下溢。

然后释放堆重用问题。

堆栈使用超出范围

重复发布,错误发布问题

0x004ac1e41080位于线程T32 (AudioTrack)释放的1792字节区域[0x004ac1e41080,0x004ac1e41780内的0个字节,此处:# 0 0x 7157 f 74 c 64(/data/app/~ ~ g 094 wkqj7 kzvdhvgydlda = =/com . jeffmony . audioplayer-kcu 1 nmgzpbiqdrjdxcjdoq = = =/lib/arm 64/lib clang _ rt
消息是:地址0x004ac1e41080上的heap-use-after-free,表示已经释放的内存已经被使用。继续读下去,这段记忆是从哪里释放出来的?0x004ac1e41080位于1792字节区域内0字节[0x004ac1e41080,0x 004 ac1e 41780]ASAN的一个很大的优点是可以跟踪内存释放的路径,防止内存泄漏和野指针问题,尤其是野指针问题。一旦特别难排查,简直就是C++开发的噩梦。希望你能善用工具。
3.3优化线程
影响内存的另一个重要因素是线程。视频编辑工具涉及到很多线程。线程的使用应遵循一些基本原则:

创建尽可能少的线程

尽量少用pthread_mutex_t。

使用基于功能隔离原则的线程。

能同步就不要异步。

以编辑模块为例。以下是我们使用的所有线程的列表:

总帐处理线程

视频解封装线程

视频轨道解码线程输入

音轨解码线程

缩略图提取线程

音频编码线程

视频编码线程

视频封装线程

如果插入单独的音频文件,则需要添加两个额外的线程:

音乐文件播放线程

音乐文件解码线程

上面列出的是视频编辑工具正常工作所需的最小线程数。如果你的视频编辑工具里有更多的线程,我们建议可以适当优化。毕竟少一个线程,可以减少开销,减少线程同步的工作。
在底层,我们根据Android的消息机制,重新编写了一套C++层的消息分发SDK。我们将在后面分享另一篇文章来解释我们定制的消息分发SDK,就这样。
第四,提高导出视频的速度。
当我们使用视频编辑工具时,我们最终想要导出一个视频。如果这个出口过程慢了,肯定是无法承受的。从上面的介绍我们知道,视频的导出需要经历“解码-应用特效-编码”的过程,其中解码和编码两个过程对速度至关重要。目前主要有两种方法——“软解码/编码”和“硬件解码/编码”,因为视频的解码和编码需要耗费大量的资源。
如果你使用过FFmpeg或者其他使用CPU的视频编解码器处理视频,你可能会遇到处理速度慢的问题。这主要是因为软编码和软解码使用CPU进行运算,CPU处理视频的速度远低于DSP芯片;简而言之,“软解/编码”主要通过CPU工作,这是原始的处理方式,耗时较长。“硬件解码/编码”由GPU处理,GPU是专用的图形处理芯片,对视频解码和编码有专门的优化,所以编解码速度很快。
Android上用MediaCodec实现“硬件解码/编码”,iOS上用VideoToolBox实现“硬件解码/编码”。这里着重介绍Android上编解码的速度优化。

从上面的过程我们可以看到,解码之后,一个时长为60s(30fps)的视频需要解码1800帧,然后1800帧的视频才能编码完成生成另一个视频,所以串行等待是耗时的主要原因。
此时我们参考多线程方案,将一个60s的视频分成两段,然后同时对两段进行解码,生成并导出两个30s的临时缓存视频文件,再将两个30s的视频合并成一个60s的B.mp4视频,最后删除临时缓存文件,这样我们只需要同时处理900帧数据,理论上可以使导出速度翻倍。
这就是平行导出,下面是采集App平行导出的基本流程。

首先我们要明确一点,导出视频是需要消耗资源的,就是MediaCodec,最后送到GPU处理。移动电话中只有有限数量的MediaCodec实例。正常情况下,一部手机最多可以提供16个MediaCodec实例。如果当前使用的MediaCodec实例超过16个,移动电话将无法正常工作。医疗资源是手机里所有app共享的。所以平行段的数量不是越多越好。

只有一个段落,需要两个媒体编解码器(一个用于解码视频,一个用于编码视频)。注意:MediaCodec可用于音频解码和编码。毕竟音频耗时少得多,也不是瓶颈。

需要四个媒体编解码器来分成两个段,六个媒体编解码器来分成三个段,八个媒体编解码器来分成四个段,等等。

以下是并行导出的测试结果:
两级并行速度提升50% ~ 70%,内存提升20%,三级并行速度提升60% ~ 90%,内存提升80%;如果并行跑三段以上,就不能明显提高速度。在一些性能较好的车型上,我们推荐两个平行段和三个平行段。
如果还有同学对视频导出过程中的文件操作有疑问,下图可以清晰的展示本地文件并行导出的过程:

在并行导出过程中,会生成两个临时文件。

并行导出完成后,两个临时文件合并成一个新文件,两个临时生成的文件被删除(为用户节省了宝贵的存储空间)。

原始文件jeffmony_out.mp4未被删除/修改。

温馨提示:目前处理过程中生成的临时文件和最终适配文件会保存在/SD card/pictures/du app/compile/中,处理后的临时文件的清理过程会触发部分机型上的保护机制。建议以后把它们调整到app的私有目录下。
下面是正常导出和并行导出的测试速度对比:可以清楚的看到,对于同一个视频(使用同一个滤镜),左边并行导出的速度几乎是右边正常导出的两倍。可以看出,并行导出可以明显提高视频导出的速度。
此内容暂时无法在舒菲文档之外显示。
当然,还有其他提高导出速度的建议。例如,在视频帧特效处理过程中,我们建议:

试着用FBO/EBO/阿波来处理纹理。

如果纹理太大,压缩它。

严格禁止使用GlFinish()。

这些做法是我们在视频剪辑开发过程中的实践经验,希望能给你带来一些帮助。
第五,提高导出视频的清晰度
一个视频编辑功能是否足够优秀,其中一个重要指标就是同等条件下导出的视频是否足够清晰。一般来说,衡量视频是否清晰有两种方式:

主观标准:找一些用户观看不同的视频,根据用户的观感输出视频清晰度的对比结果。用户一般根据颜色、画面亮度、柔和度等来评价清晰度。

客观标准:使用算法计算视频图像质量分数。目前,推荐使用网飞推出的开源库VMAF来计算视频帧质量分数。

其实主观标准更准确,但可操作性差,尤其是处理海量视频时,需要大量人力,无法有效进行。所以在日常工作中,海量计算推荐客观标准,重点判断使用主观标准。具体可以结合业务的重要性来开展。
以下是我们根据实际工作提出的提高视频清晰度的具体方法:

基本视频编码信息的优化

Profile的优化:Profile有三个级别,分别是Baseline、Main和High,其中Baseline Profile对应的定义最低,支持Android 3.0以后的所有版本。主配置文件的清晰度比基线配置文件要好,但只有Android 7.0以后才支持,高配置文件的清晰度最高,Android 7.0以后也支持。在我们设置编码器配置文件级别之前,我们需要判断它当前是否受支持。
比特率比特率设置:视频比特率是视频数据传输过程中单位时间内传输的数据比特数。它的单位是kbps,意思是文本。比特率越大,单位时间内填充的数据就越多,视频质量就越高。但是比特率并不是设置得越大越好,超过了必要的限度,视频质量的提升并不明显。建议通过使用适当的因子来调整比特率。比特率=宽度高度帧速率*因子,其中因子=0.15
码率模式:有三种通过的编码模式——VBR(可变比特率)、CBR(固定比特率)和ABR(平均比特率),其中ABR是最好的方式,可以兼顾质量和视频大小。
B帧设置:视频由I帧、P帧和B帧组成,其中I帧最大,P帧次之,B帧最小。我们在编码时设置尽可能多的B帧(在合理的范围内),不会降低清晰度,但可以大大降低视频大小,这样就可以相应提高码率,最终达到提高清晰度的目的。

HEVC编码优化:使用HEVC编码可以确保在不增加文件大小的情况下,视频的清晰度可以大大提高。在相同图像质量下,HEVC编码的视频比H.264编码的视频少40%左右

颜色调整

调整亮度、对比度、色温、饱和度、锐度等色彩参数,进而优化整体视频画面,让视频画面看起来“更清晰”。

子算法:利用机器学习的优势,使用ESRGAN算法对图像和视频进行去模糊、大小调整、降噪和锐化,从而重建图像,实现图像的超分辨率处理。

特征提取:计算噪声
非线性映射:放大和模糊噪声
图像重建:差分、过平滑、去噪

下面是超除法算法处理前后的对比图。可以清楚的看到,右图更清晰,噪点少了很多,更亮更平滑。

如果想了解视频清晰度优化的技术细节,可以参考微信官方账号发布的文章——视频清晰度优化指南。
六。摘要
本文首先介绍了Get Things App的主要功能,并提出了视频编辑工具优化的三个维度:

优化内存使用

加速视频导出。

提高导出视频的清晰度。

其中“提高视频导出速度”中强调了“并行导出”的技术方案。从最终的结果来看,视频导出的速度明显提高,也清楚的解释了为什么在“并行导出”的过程中会产生临时文件。为什么导出完成后需要删除临时文件?尽力给用户带来更好的体验。
最后,“提高导出视频的清晰度”中重点介绍的超分算法的应用效果明显提升。超分后的视频帧相比原帧更清晰,噪点更少,细节更真实。