VideoLab 是开源的,高性能且灵活的 iOS 视频剪辑与特效框架,提供了更 AE(Adobe After Effect)化的使用方式。框架核心基于 AVFoundation 与 Metal。目前已有的特性:
以下是一些特性的 GIF 示例:
多图层
文字动画
关键帧动画
预合成
转场
仓库地址:https://github.com/ruanjx/VideoLab
本文将和大家分享 AVFoundation 视频剪辑流程,以及 VideoLab 框架的设计与实现。
在开始介绍之前,建议刚接触视频剪辑的同学可以先看下如下 WWDC 视频:
让我们来看下 AVFoundation 视频剪辑的整体工作流程:
我们来拆解下步骤:
AVAsset
。AVComposition
、AVVideoComposition
及 AVAudioMix
。其中 AVComposition
指定了音视频轨道的时间对齐,AVVideoComposition
指定了视频轨道在任何给定时间点的几何变换与混合,AVAudioMix
管理音频轨道的混合参数。AVPlayerItem
,并从中创建一个 AVPlayer
来播放编辑效果。AVAssetExportSession
,用来将编辑结果写入文件。让我们先来看下 AVComposition
,AVComposition
是一个或多个 AVCompositionTrack
音视频轨道的集合。其中 AVCompositionTrack
又可以包含来自多个 AVAsset
的 AVAssetTrack
。
下图的例子,将两个 AVAsset
中的音视频 AVAssetTrack
组合到 AVComposition
的音视频 AVCompositionTrack
中。
设想下图所示的场景, AVComposition
包含两个 AVCompositionTrack
。我们在 T1 时间点需要混合两个 AVCompositionTrack
的图像。为了达到这个目的,我们需要使用 AVVideoComposition
。
AVVideoComposition
可以用来指定渲染大小和渲染缩放,以及帧率。此外,还存储了实现 AVVideoCompositionInstructionProtocol
协议的 Instruction(指令)数组,这些 Instruction 存储了混合的参数。有了这些混合参数之后,AVVideoComposition
可以通过一个实现 AVVideoCompositing
协议的 Compositor(混合器) 来混合对应的图像帧。
整体工作流如下图所示:
让我们聚焦到 Compositor,我们有多个原始帧,需要处理并输出新的一帧。工作流程如下图所示:
流程可分解为:
AVAsynchronousVideoCompositionRequest
绑定了当前时间的一系列原始帧,以及当前时间所在的 Instruction。startVideoCompositionRequest:
回调,并接收到这个 Request。finishWithComposedVideoFrame:
交付渲染后的帧。使用 AVAudioMix
,你可以在 AVComposition
的音频轨道上处理音频。AVAudioMix
包含一组的 AVAudioMixInputParameters
,每个 AVAudioMixInputParameters
对应一个音频的 AVCompositionTrack
。如下图所示:
AVAudioMixInputParameters
包含一个 MTAudioProcessingTap
,你可以使用它来实时处理音频。当然,对于线性音量变化可以直接使用音量斜率接口 setVolumeRampFromStartVolume:toEndVolume:timeRange:
此外,AVAudioMixInputParameters
还包含一个 AVAudioTimePitchAlgorithm
,你可以使用它来设置音高。
前面我们介绍了 AVFoundation 视频剪辑流程,接下来我们介绍下 VideoLab 框架的设计。
先简要介绍下 AE(Adobe After Effect),AE 是特效设计师常用的动态图形和视觉效果软件(更多介绍参见[AE官网](https://www.adobe.com/cn/products/aftereffects.html))。AE 通过”层“控制视频、音频及静态图片的合成,每个媒体(视频、音频及静态图片)对象都有自己独立的轨道。
下图是在 AE 中合成两个视频的示例。
我们来分解下这张示例图:
基于对 AE 的分析,我们可以设计相似的描述方式:
RenderComposition
,对应 AE 中的合成(Composition)。包含一组 RenderLayer
(对应 AE 中的层)。此外,RenderComposition
还包含 BackgroundColor
、FrameDuration
、RenderSize
,分别对应背景色、帧率及渲染大小等剪辑相关参数。RenderLayer
,对应 AE 中的层(Layer)。包含了 Source
、TimeRange
、Transform
、AudioConfiguration
、Operations
,分别对应素材来源、在时间轴的时间区间、变换(位置、旋转、缩放)、音频配置及特效操作组。RenderLayerGroup
,对应 AE 的预合成。RenderLayerGroup
继承自 RenderLayer
,包含一组 RenderLayer
。KeyframeAnimation
,对应 AE 的关键帧动画。包含了 KeyPath
、Values
、KeyTimes
、TimingFunctions
,分别对应关键路径、数值数组、关键时间数组、缓动函数数组。以上介绍了 RenderComposition
、RenderLayer
、RenderLayerGroup
以及 KeyframeAnimation
。从前面的 AVFoundation 介绍可知,我们需要生成 AVPlayerItem
与 AVAssetExportSession
用于播放与导出。因此,我们需要有一个对象可以解析这几个描述对象,并用 AVFoundation 的方法生成 AVPlayerItem
与 AVAssetExportSession
。框架将这个对象命名为 VideoLab
,可以理解成这是一个实验室。
整体的工作流程如下:
我们来拆解下步骤:
RenderLayer
。RenderComposition
,设置其 BackgroundColor
、FrameDuration
、RenderSize
,以及 RenderLayer
数组。RenderComposition
创建 VideoLab
。VideoLab
生成 AVPlayerItem
或 AVAssetExportSession
。这个章节主要介绍了框架的设计思路。设计思路总的来说,希望框架是类 AE 化灵活的方式设计。
从前面的介绍,我们知道一个 RenderLayer
可能包含一个素材来源。素材来源可以是视频、音频及静态图片等。框架抽象了 Source
协议,以下是 Source
协议的核心代码:
public protocol Source {
var selectedTimeRange: CMTimeRange { get set }
func tracks(for type: AVMediaType) -> [AVAssetTrack]
func texture(at time: CMTime) -> Texture?
}
selectedTimeRange
是素材本身的选择时间区间,如一段长 2 分钟的视频,我们选择 60s-70s 的区间作为编辑素材,那么 selectedTimeRange
就是 [60s-70s)(实际代码使用 CMTime
)。tracks(for:)
方法,用于根据 AVMediaType
获取 AVAssetTrack
。texture(at:)
方法,用于根据时间获取 Texture
(纹理)。框架提供了 4 种内置的源,分别为:1. AVAssetSource
,AVAsset
;2. ImageSource
,静态图片;3. PHAssetVideoSource
,相册视频;4. PHAssetImageSource
,相册图片。我们也可以实现 Source
协议,提供自定义的素材来源。
到目前为止我们已经知道了 RenderComposition
、RenderLayer
、RenderLayerGroup
、KeyframeAnimation
、Source
,接下来将介绍 VideoLab
类如何利用这些对象创建 AVComposition
、AVVideoComposition
以及 AVAudioMix
。
让我们先来看下 AVComposition
,我们需要给 AVComposition
分别添加视频轨道与音频轨道。
让我们结合一个示例来说明这个过程,如下图所示,这个 RenderComposition
有 RenderLayer1(包含视频/音频)、RenderLayer2(仅视频)、RenderLayer3(图片)、RenderLayer4(仅特效操作组)以及一个 RenderLayerGroup
(包含 RenderLayer5、RenderLayer6,均包含视频/音频)。
让我们先聊下添加视频轨道,添加视频轨道包含以下步骤:
1. 将 RenderLayer 转换为 VideoRenderLayer
VideoRenderLayer
是框架内部对象,包含一个 RenderLayer
,主要负责将 RenderLayer
的视频轨道添加到 AVComposition
中。可转换为 VideoRenderLayer
的 RenderLayer
包含以下几类:1. Source
包含视频轨道;2. Source
为图片类型;3. 特效操作组不为空(Operations
)。
VideoRenderLayerGroup
是 RenderLayerGroup
对应视频的框架内部对象,包含一个 RenderLayerGroup
。可转换为 VideoRenderLayerGroup
的 RenderLayerGroup
只需满足一个条件:包含的 RenderLayer
组有一个可以转化为 VideoRenderLayer
。
转换 VideoRenderLayer
之后如下图所示:
2. 将 VideoRenderLayer 视频轨道添加到 AVComposition 中
对于 RenderLayer 的 Source 包含视频轨道的 VideoRenderLayer,从 Source 中获取视频 AVAssetTrack,添加到 AVComposition。
对于 RenderLayer 的 Source 为图片类型或仅有特效操作组类型(Source
为空)的 VideoRenderLayer,使用空视频添加一个新的视频轨道(这里的空视频是指视频轨道是黑帧且不包含音频轨道的视频)
添加完之后 AVComposition
的视频轨道如下图所示:
如图所示,VideoRenderLayer1 与 VideoRenderLayer5 共用了一个视频轨道。这是由于苹果对视频轨道数量有限制,我们需要尽量的重用视频轨道(每条视频轨道对应一个解码器,当解码器数量超出系统限制时,会出现无法解码的错误)。
框架视频轨道重用的原则是,如果要放入的 VideoRenderLayer 与之前视频轨道的 VideoRenderLayer 在时间上没有交集,则可以重用这个视频轨道,所有视频轨道都重用不了则新增一个视频轨道。
让我们接着聊下添加音频轨道,添加音频轨道包含以下步骤:
1. 将 RenderLayer 转换为 AudioRenderLayer
AudioRenderLayer
是框架内部对象,包含一个 RenderLayer
,主要负责将 RenderLayer
的音频轨道添加到 AVComposition
中。可转换为 AudioRenderLayer
的 RenderLayer
只需满足一个条件:Source
包含音频轨道。
AudioRenderLayerGroup
是 RenderLayerGroup
对应音频的框架内部对象,包含一个 RenderLayerGroup
。可转换为 AudioRenderLayerGroup
的 RenderLayerGroup
只需满足一个条件:包含的 RenderLayer
组有一个可以转化为 AudioRenderLayer
。
转换 AudioRenderLayer
之后如下图所示:
2. 将 AudioRenderLayer 音频轨道添加到 AVComposition 中
对于 RenderLayer 的 Source 包含音频轨道的 AudioRenderLayer,从 Source 中获取音频 AVAssetTrack,添加到 AVComposition。
添加完之后 AVComposition
的音频轨道如下图所示:
如图所示,不同于视频轨道的重用,音频的每个 AudioRenderLayer
都对应一个音频轨道。这是由于一个 AVAudioMixInputParameters
与一个音频的轨道一一对应,而其音高设置(audioTimePitchAlgorithm
)作用于整个音频轨道。如果重用的话,会存在一个音频轨道有多个 AudioRenderLayer
的情况,这样会导致所有的 AudioRenderLayer
都要配置同样的音高,这显然是不合理的。
从前面的 AVFoundation 介绍可知,AVVideoComposition
可以用来指定渲染大小和渲染缩放,以及帧率。此外,还有一组存储了混合参数的 Instruction(指令)。有了这些混合参数之后,AVVideoComposition
可以通过自定义 Compositor(混合器) 来混合对应的图像帧。
这个章节将主要介绍如何生成这组 Instruction(指令),以及创建 AVVideoComposition
。我们将使用上个章节生成的 VideoRenderLayer
,生成这组 Instruction(指令)。
让我们结合一个简单示例来说明这个过程,如下图所示,这个 AVComposition
有 VideoRenderLayer1、VideoRenderLayer2、VideoRenderLayer3 三个 VideoRenderLayer
。转换过程包含以下步骤:
VideoRenderLayer
的起始时间点与结束时间点(如下图 T1-T6)。VideoRenderLayer
,都作为 Instruction 的混合参数(如下图 Instruction1-Instruction5)。接着我们创建 AVVideoComposition
,并设置帧率、渲染大小、Instruction 组以及自定义的 Compositor。核心代码如下:
let videoComposition = AVMutableVideoComposition()
videoComposition.frameDuration = renderComposition.frameDuration
videoComposition.renderSize = renderComposition.renderSize
videoComposition.instructions = instructions
videoComposition.customVideoCompositorClass = VideoCompositor.self
到目前为止,我们已经有了渲染所需的 Instruction 组与混合参数,我们继续介绍如何利用它们在 Compositor 中绘制帧画面。我们对前面的 Compositor 工作流程做一个更新,将混合参数更新为与 Instruction 有交集的 VideoRenderLayer
组。
我们同样以一个示例来说明视频混合的规则,如下图所示,在 T1 时间点,我们想要混合这几个 VideoRenderLayer
的画面。
我们的渲染混合规则如下:
VideoRenderLayer
组,依据其所包含的 RenderLayer
的 layerLevel
。如上图所示在纵向从高到低的排序。VideoRenderLayer
组,对每个 VideoRenderLayer
分为以下三种混合方式:VideoRenderLayer
是 VideoRenderLayerGroup
,即为预合成方式。遍历处理完自己内部的 VideoRenderLayer
组,生成一张纹理,混合到前面的纹理。VideoRenderLayer
的 Source
包含视频轨道或 Source
为图片类型,拿到纹理处理自己的特效操作组(Operations),接着混合到前面的纹理。VideoRenderLayer
仅特效操作组,所有的操作作用于前面混合的纹理。渲染混合规则总结来说,按层级渲染,从下往上。如当前层级有纹理则先处理自己的纹理,再混合进前面的纹理。如当前层级没有纹理,则操作直接作用于前面的纹理。
让我们将规则用在上图的示例中,假设我们最后输出的纹理为 Output Texture:
从前面的 AVFoundation 介绍可知,AVAudioMix
用于处理音频。AVAudioMix
包含一组的 AVAudioMixInputParameters
,可以设置 MTAudioProcessingTap
实时处理音频,设置 AVAudioTimePitchAlgorithm
指定音高算法。
这个章节将主要介绍如何生成这组 AVAudioMixInputParameters
,以及创建 AVAudioMix
。我们将使用 AVComposition 章节生成的 AudioRenderLayer
,生成这组 AVAudioMixInputParameters
。
让我们结合一个简单示例来说明这个过程,如下图所示,这个 AVComposition
有 AudioRenderLayer1、AudioRenderLayer2、AudioRenderLayer3 三个 AudioRenderLayer
。转换过程包含以下步骤:
AudioRenderLayer
创建了一个 AVAudioMixInputParameters
AVAudioMixInputParameters
设置一个 MTAudioProcessingTap
。MTAudioProcessingTap
用于实时处理音频,从 RenderLayer
的 AudioConfiguration
获取音频配置,实时计算当前时间点的音量。AVAudioMixInputParameters
设置 AVAudioTimePitchAlgorithm
。AVAudioTimePitchAlgorithm
用于设置音高算法,从 RenderLayer
的 AudioConfiguration
获取音高算法配置。接着我们创建 AVAudioMix
,并设置 AVAudioMixInputParameters
组。代码如下:
let audioMix = AVMutableAudioMix()
audioMix.inputParameters = inputParameters
以上几个章节从大的维度介绍了框架的实现,对于 Metal 部分的介绍,后续会考虑再起一篇文章介绍。接下来的几个章节,介绍下框架的后续计划、开发框架过程逆向其他应用的一些分享以及推荐的学习资料。
笔者在开发框架过程中,逆向了国内外一众视频编辑器。在比较各自的方案之后,选用了 AVFoundation 加 Metal 的方案作为框架核心。这里简要分享下逆向 Videoleap 的一些亮点:
尽量少的 Draw Call,尽量将一个层的操作都放在一个 Shader 脚本中(如 Videoleap 中对一个视频片段的 YUV 转 RGB、滤镜、变换等都在一个 Shader 内)。
使用 IOSurface 生成纹理性能更优(需要系统大于等于 iOS 11)。
Metal 对应方法 makeTexture(descriptor:iosurface:plane:)
Open GL 对应方法 texImageIOSurface(_:target:internalFormat:width:height:format:type:plane:)
尽量多的使用 Framebuffer Fetch(如果 fragment 只是像素点本身的颜色变化可以使用,如果有参考临近像素点则无法使用)
[Metal 参考资料](https://stackoverflow.com/questions/40968576/read-framebuffer-in-metal-shader),框架中的 Metal 脚本对应的 [[color(0)]]
[Open GL 参考资料](https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/BestPracticesforShaders/BestPracticesforShaders.html),搜索 GL_EXT_shader_framebuffer_fetch
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/1ea0TG_Zq8F4qXD_v6KH9Q
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。