媒体创作和编辑基本是AVFoundation的高级接口,较少涉及底层接口。整个过程总的来说就是构建AVAsset的过程,而在视频编辑中,构建的是AVMutableComposition的过程。
整体关系
Composition :作为内容主体,一个抽象的可编辑的AVAsset子类,提供面向对象的多轨操作。
CompositionTrack ×N:管理时间,总的音视频轨信息。
AssetTrack片段 ×N
轨道的偏好信息:naturalTimeScale
、preferredTransform
、preferredVolume
AudioMix :附加信息,对音量的描述
inputParameters
:AudioMixInputParameters ×N:描述音量(+时间=渐变)、变速时的音调策略
AudioMixInputParameters的audioTapProcessor
可以使用AudioUnit给音频增加效果,但似乎查不到具体的额API文档,可参考:MTAudioProcessingTap with kMTAudio… | Apple Developer Forums 、gchilds/MTAudioProcessingTap-in-Swift: Example of creating an MTAudioProcessingTap in Swift4.2 。
VideoComposition :附加信息,对画面的描述
视频属性控制:
frameDuration
renderSize
colorParimaties
colorTransferFunction
colorYCbCrMatrix
视频操作,通过以下三种方式:
instructions
:AVVideoCompositionInstructionProtocol ×N
animationTool
:提供与Core Animation的几种交互方式,不能实时预览的,即设置到playerItem看不到效果。
新增一个用CALayer表示的视频轨:init(additionalLayer: CALayer, asTrackID: CMPersistentTrackID)
用CALayer层级关系管理视频轨:init(postProcessingAsVideoLayer: CALayer, in: CALayer)
、init(postProcessingAsVideoLayers: [CALayer], in: CALayer)
customVideoCompositorClass
:自己实现一个VideoComposition,可通过GL、Metal实现自定义的转场
以上API的Mutable版本的类才是可编辑的。
以上的Composition,可用于创建PlayerItem、AssetExportSession。AudioMix、VideoComposition作为属性设置到AssetExportSession、AssetReaderAudioMixOutput、playerItem。
具体API
AVMutableComposition
AVAsset的子类,因此这是最后预览、导出操作的数据对象。
整体操作
对整个composition对象进行整体操作,当然这会涉及多个轨道,除了对整体进行时间伸缩,否则较少使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 /// 插入空占位 func insertEmptyTimeRange(_ timeRange: CMTimeRange) /// 插入asset func insertTimeRange(_ timeRange: CMTimeRange, of asset: AVAsset, at startTime: CMTime) throws /// 移除时间段的内容,注意这里不会移除既有的轨道。 func removeTimeRange(_ timeRange: CMTimeRange) /// 伸缩时间,即改变时间区间内所有轨道的时长 func scaleTimeRange(_ timeRange: CMTimeRange, toDuration duration: CMTime) /// 配置视频画幅尺寸 var naturalSize: CGSize { get set }
轨道操作
大多数操作都是基于轨道。
1 2 3 4 5 /// 添加、移除轨道 func addMutableTrack(withMediaType mediaType: AVMediaType, preferredTrackID: CMPersistentTrackID) -> AVMutableCompositionTrack? func removeTrack(_ track: AVCompositionTrack) // 其他API只是获取轨道等非常用操作
AVMutableCompositionTrack
一个可修改的轨道。
常用配置属性
1 2 3 4 5 6 7 8 9 10 /// 视频翻转矩阵 var preferredTransform: CGAffineTransform { get set } /// 音频轨道音量 var preferredVolume: Float { get set } /// 其他不太常用的属性 var languageCode: String? { get set } var extendedLanguageTag: String? { get set } var naturalTimeScale: CMTimeScale { get set }
增删改查
1 2 3 4 5 6 func insertEmptyTimeRange(_ timeRange: CMTimeRange) func insertTimeRange(_ timeRange: CMTimeRange, of track: AVAssetTrack, at startTime: CMTime) throws func insertTimeRanges(_ timeRanges: [NSValue], of tracks: [AVAssetTrack], at startTime: CMTime) throws // 似乎不常用 func removeTimeRange(_ timeRange: CMTimeRange) func scaleTimeRange(_ timeRange: CMTimeRange, toDuration duration: CMTime) var segments: [AVCompositionTrackSegment]! { get set }
AVMutableAudioMix
包含混音(目前的混音只有音量调节)参数,所以其对象只有一个属性:
1 var inputParameters: [AVAudioMixInputParameters] { get set }
音频混音参数。
1 2 3 4 5 6 7 8 9 10 11 /// 创建 convenience init(track: AVAssetTrack?) /// 创建后也可以修改trackId更变应用的轨道 var trackID: CMPersistentTrackID { get set } /// 设置音量 func setVolume(_ volume: Float, at time: CMTime) func setVolumeRamp(fromStartVolume startVolume: Float, toEndVolume endVolume: Float, timeRange: CMTimeRange) /// 设置音调算法 var audioTimePitchAlgorithm: AVAudioTimePitchAlgorithm? { get set }
AVMutableVideoComposition
控制视频轨道组合行为。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /// 创建 init(propertiesOf asset: AVAsset) /// 配置视频相关属性 var frameDuration: CMTime { get set } var renderSize: CGSize { get set } var renderScale: Float { get set } // 不常用 var colorPrimaries: String? { get set } var colorTransferFunction: String? { get set } var colorYCbCrMatrix: String? { get set } /// 配置视频操作 var instructions: [AVVideoCompositionInstructionProtocol] { get set } var animationTool: AVVideoCompositionCoreAnimationTool? { get set } var customVideoCompositorClass: AVVideoCompositing.Type? { get set }
AVMutableVideoCompositionInstruction
提供一个时间范围内的视频组织信息。由一组AVMutableVideoCompositionLayerInstruction对象格式定义的指令组成的。
1 2 3 4 5 /// 自顶而下排列的layerInstructions var layerInstructions: [AVVideoCompositionLayerInstruction] { get set } var timeRange: CMTimeRange { get set } var enablePostProcessing: Bool { get set } var backgroundColor: CGColor? { get set }
AVMutableVideoCompositionLayerInstruction
给视频特效,用于定义给定视频轨道应用的基于时间的模糊、变形、和裁剪效果。从其构建方式可见,其更类似于AVMutableAudioMixInputParameters。
1 2 3 4 5 6 7 8 9 10 11 /// 构建 convenience init(assetTrack track: AVAssetTrack) var trackID: CMPersistentTrackID { get set } /// 支持的操作 func setOpacity(_ opacity: Float, at time: CMTime) func setOpacityRamp(fromStartOpacity startOpacity: Float, toEndOpacity endOpacity: Float, timeRange: CMTimeRange) func setTransform(_ transform: CGAffineTransform, at time: CMTime) func setTransformRamp(fromStart startTransform: CGAffineTransform, toEnd endTransform: CGAffineTransform, timeRange: CMTimeRange) func setCropRectangle(_ cropRectangle: CGRect, at time: CMTime) func setCropRectangleRamp(fromStartCropRectangle startCropRectangle: CGRect, toEndCropRectangle endCropRectangle: CGRect, timeRange: CMTimeRange)
LayerInstruction是应用于一个轨道的,意味着要想在应用特效的时候能看到底下的视频,则需要多个视频轨道。
VideoComposition+CoreAnimation
视频编辑中除了可以叠加轨道,还可以叠加CALayer。这通过VideoComposition的animationTool实现。其类是AVVideoCompositionCoreAnimationTool:
1 2 3 4 5 6 7 8 /// 添加额外的图层 convenience init(additionalLayer layer: CALayer, asTrackID trackID: CMPersistentTrackID) /// 自定义组织视频层与根图层。这里animationLayer是根图层,videoLayer视频层是其子图层,除此以外还可以在animationLayer添加更多子图层。 convenience init(postProcessingAsVideoLayer videoLayer: CALayer, in animationLayer: CALayer) /// 拷贝视频帧到多个视频层 convenience init(postProcessingAsVideoLayers videoLayers: [CALayer], in animationLayer: CALayer)
在视频中使用CoreAnimation,常需要设置geometryFlipped属性,让其坐标翻转一遍。
通过AVVideoCompositionCoreAnimationTool使用Core Animation时需要注意:
用AVCoreAnimationBeginTimeAtZero
表示0时间点;
isRemovedOnCompletion
设为false;
避免使用与UIView关联的CALayer。
AVAssetExportSession
高级导出类,是个高级API,要想更细化地配置,还是需要AVAssetReader+AVAssetWriter。
构建
1 init?(asset: AVAsset, presetName: String)
当然可以直接构建后就开始导出。其音视频的转码配置都囊括在presetName中,即既有的方案中去直接套用。
配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 /// 输出文件路径 var outputURL: URL? { get set } /// 文件类型,准确地来说是容器类型 var outputFileType: AVFileType? { get set } /// 文件长度限制 var fileLengthLimit: Int64 { get set } /// 导出时间区间 var timeRange: CMTimeRange { get set } /// 附带的元数据 var metadata: [AVMetadataItem]? { get set } /// 混音 var audioMix: AVAudioMix? { get set } /// 音调算法(在伸缩时长时) var audioTimePitchAlgorithm: AVAudioTimePitchAlgorithm { get set } /// 是否为网络播放优化 var shouldOptimizeForNetworkUse: Bool { get set } /// video composition var videoComposition: AVVideoComposition? { get set } /// custom video compositor var customVideoCompositor: AVVideoCompositing? { get }