0%

AVFoundation影片编辑API

媒体创作和编辑基本是AVFoundation的高级接口,较少涉及底层接口。整个过程总的来说就是构建AVAsset的过程,而在视频编辑中,构建的是AVMutableComposition的过程。

整体关系

Composition:作为内容主体,一个抽象的可编辑的AVAsset子类,提供面向对象的多轨操作。

  • CompositionTrack ×N:管理时间,总的音视频轨信息。
    • AssetTrack片段 ×N
    • 轨道的偏好信息:naturalTimeScalepreferredTransformpreferredVolume

AudioMix:附加信息,对音量的描述

  • inputParameters:AudioMixInputParameters ×N:描述音量(+时间=渐变)、变速时的音调策略

AudioMixInputParameters的audioTapProcessor可以使用AudioUnit给音频增加效果,但似乎查不到具体的额API文档,可参考:MTAudioProcessingTap with kMTAudio… | Apple Developer Forumsgchilds/MTAudioProcessingTap-in-Swift: Example of creating an MTAudioProcessingTap in Swift4.2

VideoComposition:附加信息,对画面的描述

  • 视频属性控制:

    • frameDuration
    • renderSize
    • colorParimaties
    • colorTransferFunction
    • colorYCbCrMatrix
  • 视频操作,通过以下三种方式:

    • instructions:AVVideoCompositionInstructionProtocol ×N

      • VideoCompositionLayerInstruction:提供几种图像以时间点、时间区间/渐变操作

        • opacity

        • transform

        • cropRectangle

    • 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 }

AVMutableAudioMixInputParameters

音频混音参数。

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 }

欢迎关注我的其它发布渠道