本文正在参与「金石计划 . 分割6万现金大奖」

一、布景介绍

随着4G网络的推行和网络带宽的提高,视频成为互联网用户首要的消费载体,用户经过短视频来共享和浏览信息。由此视频的修改功用越来越重要、越来越普遍。视频修改的App也如漫山遍野般呈现。
为更好地推动得物App社区事务的开展,得物也自研符合得物需求的视频修改东西。咱们致力于打造一个“更快、更强”的视频修改东西。

二、视频修改东西介绍

为了让咱们更好地了解得物App的视频修改东西,咱们先简单介绍一下视频修改东西的首要功用。

得物视频编辑工具优化全指南

下面是得物App视频修改东西的首要功用:

得物视频编辑工具优化全指南

视频修改东西的重点如下:

  • 视频修改东西需求操作的资源:

    • 文字:包括普通的文字、特殊的艺术字、花字等等;
    • 图片:包括静态图,如JPEG/PNG等等,也包括HEIC/GIF等动态图;
    • 视频:包括各式各样的视频(各种编码和封装格局),干流的格局一般是MP4的封装格局、H264视频编码格局、AAC音频编码格局等等;
    • 音频:包括各式各样的音频(各种编码和封装格局),当然视频当然也是包括音频轨迹的。
  • 视频修改东西首要的操作方法:

    • 操作图片、视频帧:咱们知道视频是一帧一帧的图片组成的,所以操作视频帧和操作图片是一样的道理,咱们经过增加一些特效在图片和视频帧上面,完结一些风趣的作用来吸引用户。
    • 操作音频:干流的操作音频方法如倍速、调整音量、变调等等,都是现今短视频的首要玩法。
  • 视频修改东西终究生成的是一个新的视频,这个视频将特定的资源运用一些特效生成一个新的视频。

下面的流程图能够很便利地让咱们了解视频修改的作业流程。为了便利,咱们输入一个视频,加上一些特效,生成一个新的视频。

得物视频编辑工具优化全指南

从上面的流程能够看出来,原始视频A.mp4经过解封装分离出音频轨迹和视频轨迹,对它们解码之后,对音频数据运用音频特效、对视频帧数据运用视频特效,然后编码封装组成一个新的视频。当然解码和编码都是有一个行列操控的,流程图上标示了,没有深入打开,咱们了解即可。

经过上面的介绍,咱们对视频修改东西有了大概得了解,其实衡量一个视频修改东西做得好不好,首要从下面这几个方面着手:

  • 内存占用情况

  • 导出视频的速度怎么

  • 导出视频的明晰度怎么

下面从这三方面详细打开给咱们阐述得物App的视频修改东西优化的心路历程。

三、内存优化

性能是一切程序好不好的首要目标,一个东西即使功用再强大,可是一点就崩溃,或许用着用着内存暴涨、运用卡死,估量这个运用不能称为一个优异的运用,下面咱们详细谈一谈视频修改东西的优化检测计划。

优化内存从杰出的编码习惯开端,特别对音视频这种对内存需求十分高的运用而言。例如一个1080 * 1920的视频,解码出来原始数据一帧图片巨细也是1080 * 1920,占用内存是1080 * 1920 * (8 * 3 ) / 8 = 5.93 MB,一个视频帧就占用这么大,1秒一般有30帧,那得占用177.9MB,假如不加操控,那不管多高性能的手机也经不住这样的折腾。期望下面的内存检测和优化计划能够给你带来一些协助。

3.1 合理规划行列

上面咱们在介绍视频修改流程的视频谈到了解码行列和编码行列的概念。其实行列这个概念在音视频中运用十分频频,正是因为内存的限制,所以才引进行列这个操控方法。咱们或许还有点懵,可是看完下面的流程图,我相信你一定会豁然开朗。
咱们仅选取解码的部分来剖析一下行列的重要运用。

得物视频编辑工具优化全指南

在视频修改东西中有几个重要的行列:

  • 解码进程中:

    • Video Packet Queue:视频解码之前Packet寄存的行列,一般主张的行列巨细是100
    • Audio Packet Queue:音频解码之前Packet寄存的行列,一般主张的行列巨细是150
    • Video Frame Queue:视频解码之后Frame寄存的行列,一般主张的行列巨细是3
    • Audio Frame Queue:音频解码之后Frame寄存的行列,一般主张的行列巨细是8
  • 编码进程中:

    • Encode Video Packet Queue:视频编码之后Packet寄存的行列,一般主张的巨细是100

    • Encode Audio Packet Queue:音频编码之后的Packet寄存的行列,一般主张的巨细是150

依照上面的方法规划行列的巨细,能够在确保功用正常的情况下最大程度的下降内存占用,提高用户体验。

3.2 排查内存走漏

Android上排查内存走漏的方法有很多,这儿介绍两种:

  • Asan检测

  • Profile检测

Asan全称是AddressSanitizer是一种基于编译器的快速检测的东西,用于检测原生代码中的内存过错问题,Asan能够处理如下四种核心问题:

  • 仓库和堆缓冲区上溢、下溢

  • 开释之后堆从头运用问题

  • 超过范围的仓库运用情况

  • 重复开释、过错开释问题

Asan的运用方法主张参考google官方文档,这儿就不多作介绍了: github.com/google/sani…

关于Profile的运用,假如需求检测Native内存运用情况,需求满意API>=29,咱们在运用的时分需求十分注意。

得物视频编辑工具优化全指南

下面是咱们在demo中运用Asan抓取的仓库:

20042-20042/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
20042-20042/? A/DEBUG: Build fingerprint: 'samsung/t2qzcx/t2q:11/RP1A.200720.012/G9960ZCU2AUGE:user/release-keys'
20042-20042/? A/DEBUG: Revision: '13'
20042-20042/? A/DEBUG: ABI: 'arm64'
20042-20042/? A/DEBUG: Timestamp: 2021-09-17 00:32:31+0800
20042-20042/? A/DEBUG: pid: 19946, tid: 20011, name: AudioTrack  >>> com.jeffmony.audioplayer <<<
20042-20042/? A/DEBUG: uid: 10350
20042-20042/? A/DEBUG: signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
2021-09-17 00:32:31.157 20042-20042/? A/DEBUG: Abort message: '=================================================================
    ==19946==ERROR: AddressSanitizer: heap-use-after-free on address 0x004ac1e41080 at pc 0x007157f69580 bp 0x00705c0bb350 sp 0x00705c0bab08
    READ of size 1792 at 0x004ac1e41080 thread T32 (AudioTrack)
        #0 0x7157f6957c  (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libclang_rt.asan-aarch64-android.so+0x9f57c)
        #1 0x706549c228  (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x14228)
        #2 0x706549bcd4  (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x13cd4)
        #3 0x70654994f0  (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x114f0)
        #4 0x70654a9cbc  (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x21cbc)
        #5 0x70654a91d4  (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x211d4)
        #6 0x715af9d188  (/system/lib64/libwilhelm.so+0x1c188)
        #7 0x71570ea290  (/system/lib64/libaudioclient.so+0x8b290)
        #8 0x71570e9480  (/system/lib64/libaudioclient.so+0x8a480)
        #9 0x7156b664d4  (/system/lib64/libutils.so+0x154d4)
        #10 0x71593e9974  (/system/lib64/libandroid_runtime.so+0xa5974)
        #11 0x7156b65db0  (/system/lib64/libutils.so+0x14db0)
        #12 0x7156ace234  (/apex/com.android.runtime/lib64/bionic/libc.so+0xb6234)
        #13 0x7156a68e64  (/apex/com.android.runtime/lib64/bionic/libc.so+0x50e64)
         0x004ac1e41080 is located 0 bytes inside of 1792-byte region [0x004ac1e41080,0x004ac1e41780)    freed by thread T32 (AudioTrack) here:        #0 0x7157f74c64  (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libclang_rt.asan-aarch64-android.so+0xaac64)        #1 0x70654a6d2c  (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x1ed2c)        #2 0x70654a6af0  (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x1eaf0)        #3 0x706549bf4c  (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x13f4c)        #4 0x706549bcd4  (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x13cd4)        #5 0x70654994f0  (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x114f0)        #6 0x70654a9cbc  (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x21cbc)        #7 0x70654a91d4  (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x211d4)        #8 0x715af9d188  (/system/lib64/libwilhelm.so+0x1c188)        #9 0x71570ea290  (/system/lib64/libaudioclient.so+0x8b290)

显示message是:heap-use-after-free on address 0x004ac1e41080 说明是运用了已经开释掉的内存了,再继续看,这个内存详细在什么地方被开释的?0x004ac1e41080 is located 0 bytes inside of 1792-byte region [0x004ac1e41080,0x004ac1e41780) Asan一个很大的优势便是能够追踪内存开释的途径,防止呈现内存走漏和野指针问题,特别是野指针,一旦呈现特别难排查,简直是C++开发的噩梦,期望咱们用好东西,一起培养杰出的C++编码习惯。

3.3 优化线程

另一个影响内存的重要因素是线程,视频修改东西涉及到的线程十分多,线程的运用得遵循一些基本的准则:

  • 尽量少创建线程

  • 尽量少运用pthread_mutex_t

  • 本着功用隔绝准则运用线程

  • 能同步就别异步

以修改模块为例,这儿列一下咱们运用到的一切线程:

  • GL处理线程

  • 视频解封装线程

  • 视频中视频轨迹解码线程

  • 视频音频轨迹解码线程

  • 抽取缩略图线程

  • 音频编码线程

  • 视频编码线程

  • 视频封装线程

假如插入了独立的音频文件,还需求增加两个额定的线程:

  • 音乐文件播映线程

  • 音乐文件解码线程

上面列出的是一个视频修改东西能正常作业所必备的最少线程,假如你的视频修改东西中多了什么线程,咱们主张能够适当优化一下,究竟少一个线程,能够少一分开销,并且少一分线程同步的作业。

咱们在底层也依照Android的音讯机制重写了一套C++层的音讯分发SDK,这个咱们后续会别的共享文章阐释咱们定制的音讯分发SDK,这儿点到为止。

四、提高导出视频的速度

咱们运用视频修改东西,终究是期望导出一个视频,假如这个导出的进程很慢,那肯定是无法忍受的,从上面的介绍咱们已知视频的导出需求经过“解码——运用特效——编码”的进程,其间解码和编码这两个进程对速度的影响至关重要。因为解码和编码视频需求消耗很多的资源,现在首要有两种方法——“软解/编码”和“硬解/编码”。

假如你运用过FFmpeg或许其他运用CPU进行视频编解码的来处理视频的话,你或许已经遇到了处理速度慢的问题。这首要是因为软编码和软解码运用CPU进行运算,而CPU在处理视频上的速度远低于DSP芯片;简而言之“软解/编码”首要经过CPU来作业,经过CPU来主导很多的核算作业,是原始的处理方法,当然消耗的时刻也比较长;“硬解/编码”是经过GPU来处理,GPU是专用的图形处理芯片,对视频的解码和编码有专门的优化,所以编码和解码的速度十分快。

Android上运用MediaCodec来完结“硬解/编码”,iOS上运用VideoToolBox来完结“硬解/编码”,这儿着重介绍Android上编码解码的速度优化。

得物视频编辑工具优化全指南

从上面的流程咱们能够看出,编码在解码的后边,一个时长60s(30fps)的视频,需求解码1800帧,然后编码1800帧视频才干完好生成别的一个视频,这样串行的等待是耗时的首要原因。

这时分咱们参考多线程计划,将一个60s的视频均分为两段,然后这两段视频一起进行解码操作,生成导出了两个30s的暂时缓存视频文件,随后将这两个30s的视频合并为一个60s的B.mp4视频,最终删除暂时缓存文件,这样咱们只需求一起处理900帧的数据,理论上能够提高一倍的导出速度。

这便是并行导出,下面是得物App并行导出的基本流程。

得物视频编辑工具优化全指南

首要咱们要明确导出视频是需求消耗资源的,这个资源便是MediaCodec,终究是送入到GPU中处理,一个手机中的MediaCodec实例是有限的,正常情况下,一个手机能够提供的MediaCodec实例最多有16个,假如当时运用的MediaCodec实例超过16个,那么手机将无法正常作业。MediaCodec资源是手机中的一切App共同持有。所以并行分段的个数不是越多越好。

  • 只有一段,需求两个MediaCodec(一个用来解码视频,一个用来编码视频),注意:音频的解码和编码能够不要用MediaCodec,究竟音频的耗时少多了,不是瓶颈。

  • 分红两段需求四个MediaCodec,分红三段需求六个MediaCodec,分红四段需求八个MediaCodec,以此类推。

下面是并行导出的测试成果:
两段并行速度提高50% ~ 70%,内存增加20%, 三段并行速度提高60% ~ 90%,内存增加80%;并行超过三段的话就无法显着提高速度了。咱们比较主张并行两段,在一些性能很好的机型上并行三段。

假如有些同学对视频导出进程中文件操作还有疑问的,下面的示意图能够比较清楚地看出并行导出操作本地文件的进程:

  • 并行导出的进程中,生成了两个暂时文件

  • 并行导出完结后,这两个暂时文件合并为一个新的文件,两个暂时生成的文件被删除了(节约用户名贵的存储空间)

  • 原始文件jeffmony_out.mp4并没有被删除/修改

得物视频编辑工具优化全指南

Tips:现在咱们在处理进程中生成的暂时文件和终究的适配文件都会保存在/sdcard/Pictures/duapp/Compile/下,而在处理完结后的暂时文件清理进程会触发在某些机型上的保护机制,主张后续调整到App的私有目录下。

当然还有其他的提高导出速度的主张,例如在视频帧特效处理的进程中,咱们主张:

  • 尽量选用FBO/EBO/ABO方法处理texture

  • 纹路假如过大体进行压缩

  • 严禁选用glFinish()

这些做法都是咱们在视频修改开发进程中的实在经验,期望能给咱们带来一些协助。

五、提高导出视频的明晰度

一个视频修改功用是否满足优异,其间的一个重要目标便是平等条件下导出的视频是否满足清楚,通常而言,衡量视频是否明晰的有两种方法:

  • 片面规范:找一些用户观看不同的视频,根据用户的观感输出视频明晰度的对比成果,用户一般根据色彩、画面亮度、柔和度等来评估明晰度。

  • 客观规范:运用算法核算视频画面质量分,现在比较引荐Netflix推出的开源库VMAF来核算视频帧的质量分。

实践上片面规范是比较精确的,可是可操作性比较差,特别是处理海量视频的时分,需求很多的人力,无法有效开展,因而日常作业中还是引荐客观规范进行海量核算,片面规范进行重点判断。详细的能够结合事务的重要程度来开展。

下面结合咱们实践的作业给出详细提高视频明晰度的方法:

  • 视频根底编码信息优化

    • Profile优化:Profile有三种Level,分别是Baseline、Main、High,其间Baseline Profile对应明晰度最低,Android 3.0之后的版本都支撑的,Main Profile明晰度比Baseline Profile明晰度要好,可是从Android 7.0之后才支撑,High Profile明晰度最高,也是从Android 7.0之后才支撑。咱们在设置Encoder Profile Level之前,需求判断一下当时是否支撑。
    • Bitrate码率设置: 视频码率是视频数据传输时单位时刻内传送的数据位数。单位是kbps,望文生义,码率越大,单位时刻填充的数据就越多,视频质量就越高。但码率也不是设置的越大越好,超过必要极限,对视频画质的提高已不显着,主张选用适宜的factor来调整码率。Bitrate = width * height * frameRate * factor,其间factor=0.15。
    • Bitrate Mode: 有三种经过的编码模式——VBR(可变码率)、CBR(固定码率)、ABR(平均码率),其间ABR是最好的方法,能够统筹质量和视频巨细。
    • B帧设置: 视频有I帧、P帧、B帧构成,其间I帧最大,P帧次之,B帧最小,咱们在编码时尽量多设置B帧(在合理的范围内),并不会下降明晰度,可是能够大大下降视频的巨细,这样咱们就能够相应地调大码率,终究完结了提高明晰度的目标。
  • HEVC编码优化: 运用HEVC编码,能够确保在不增加文件巨细的情况下,大大提高视频的明晰度。在相同的图画质量下,HEVC编码的视频比H.264编码的视频约削减40%

  • 色彩调优

    • 综合调整亮度、对比度、色温、饱和度、锐度等色彩参数,从而优化整体的视频画面,让视频画面看上去“更明晰”。
  • 超分算法: 选用ESRGAN算法,运用机器学习的优势对图片和视频进行去模糊、Resize、降噪、锐化等处理,重建图片,完结对图片的超分辨率处理。

    • 特征提取:核算噪点
    • 非线性映射:扩大,模糊化噪点
    • 图画重建:差分,滑润过度,去噪
  • 下面是运用超分算法处理前后的对比图,能够很显着地看出右边的图愈加明晰,少了很多噪点、图片更亮、过度更滑润。

得物视频编辑工具优化全指南

假如咱们想了解视频明晰度优化的技能细节,能够参考文章–视频明晰度优化指南

六、总结

本文开篇从介绍得物App的首要功用打开,提出了视频修改东西优化的三个维度:

  • 优化内存占用

  • 提高视频导出速度

  • 提高导出视频的明晰度

其间在“提高视频导出速度”时重点谈到了“并行导出”的技能计划,从终究的成果来看,视频导出速度的提高十分显着,一起也十分清楚地解说了“并行导出”进程中为什么生成暂时文件?为什么有必要在导出完结之后删除暂时文件?尽力给用户带来较好的体验。

最终在“提高导出视频的明晰度”中重点提到的超分算法运用作用提高显着,超分之后的视频帧相比原帧图愈加明晰、噪点更少,并且细节部分愈加真实。

后续咱们还会结合AR特效输出更多有意义的技能共享,敬请期待。

* /JeffMony

关注得物技能,每周一三五晚18:30更新技能干货
要是觉得文章对你有协助的话,欢迎评论转发点赞~