我正在尝试在 iOS 中将已拍摄的视频裁剪成一个圆圈。我该怎么做呢?我知道如何使用 AVCaptureSession 来做到这一点,但我不知道将已拍摄的视频作为 AVCaptureDevice 传递?有没有办法将视频裁剪成圆形。我想将其叠加在另一个视频之上,因此它也必须具有透明背景。谢谢。
我猜你想制作这样的东西:
您不需要
AVCaptureSession
,因为您没有捕捉视频。你想要一个AVMutableComposition
。您需要阅读AV Foundation 编程指南的“编辑”部分。以下是您需要执行的操作的摘要:
为您的视频创建
AVAsset
对象并等待它们加载轨道。创建一个
AVMutableComposition
。为每个输入视频的合成添加单独的
AVMutableCompositionTrack
。确保为每个轨道分配明确的、不同的轨道 ID。如果您让系统选择,它将为每个轨道使用 ID 1,并且您稍后将无法在合成器中访问这两个轨道。创建一个
AVMutableVideoComposition
。创建一个
AVMutableVideoCompositionInstruction
。对于每个输入视频,创建一个
AVMutableVideoCompositionLayerInstruction
并显式分配您在步骤 3 中使用的轨道 ID。将
AVMutableVideoCompositionInstruction
的 layerInstructions
设置为您在步骤 6 中创建的两层指令。将
AVMutableVideoComposition
的 instructions
设置为您在步骤 5 中创建的指令。创建一个实现
AVVideoCompositing
协议的类。将视频合成(在步骤 4 中创建)的 customVideoCompositorClass
设置为此自定义类(例如 videoComposition.customVideoCompositorClass = [CustomVideoCompositor class];
)。在您的自定义合成器中,从
AVAsynchronousVideoCompositionRequest
获取输入像素缓冲区,并使用它们来绘制复合帧(包含由前景视频帧的圆形块覆盖的背景视频帧)。您可以随心所欲地执行此操作。我使用 Core Graphics 完成此操作,因为这很简单,但您可能希望使用 OpenGL(或 Metal)来提高生产应用程序的效率。如果您使用 OpenGL,请务必指定 kCVPixelBufferOpenGLESCompatibilityKey
。使用步骤 1 中的构图创建
AVAssetExportSession
。设置会话的输出 URL 和文件类型。
将会话的
videoComposition
设置为步骤 4 中的视频合成。告诉会议
exportAsynchronouslyWithCompletionHandler:
。可能会很慢!您可以在这个 github 存储库中找到我的测试项目。
快速视频叠加
您有以下选择:向视频添加角点:
func applyCornersAsOverlayToComposition(
composition: AVMutableVideoComposition,
coverViewFrameSize: CGSize
) {
//set up the parent layer
let parentLayer = CALayer()
//apply corners
parentLayer.masksToBounds = true
parentLayer.cornerRadius = CollagePresenter.containerViewCornerRadius
let videoLayer = CALayer()
parentLayer.frame = CGRectMake(0, 0, coverViewFrameSize.width, coverViewFrameSize.height)
videoLayer.frame = CGRectMake(0, 0, coverViewFrameSize.width, coverViewFrameSize.height)
//priority is important to make an overlay
parentLayer.addSublayer(videoLayer)
let animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentLayer)
composition.animationTool = animationTool
}
AVMutableVideoComposition.instructions
和 AVMutableVideoCompositionLayerInstruction
重叠多个视频。它允许您转换视频(旋转、平移、缩放...)并组合多个视频
private func foo(
videoAsset1: AVURLAsset,
videoAsset2: AVURLAsset
) {
let composition = AVMutableComposition()
let trackVideo1 = videoAsset1.tracks(withMediaType: .video)[0]
let trackVideo2 = videoAsset2.tracks(withMediaType: .video)[0]
let videoTrack1 = composition.addMutableTrack(
withMediaType: .video,
preferredTrackID: kCMPersistentTrackID_Invalid
)!
let videoTrack2 = composition.addMutableTrack(
withMediaType: .video,
preferredTrackID: kCMPersistentTrackID_Invalid
)!
try! videoTrack1.insertTimeRange(
CMTimeRangeMake(start: CMTime.zero, duration: videoAsset1.duration),
of: trackVideo1,
at: CMTime.zero
)
try! videoTrack2.insertTimeRange(
CMTimeRangeMake(start: CMTime.zero, duration: videoAsset2.duration),
of: trackVideo1,
at: CMTime.zero
)
let transform1 = CGAffineTransform(scaleX: 0.1, y: 0.1)
.concatenating(CGAffineTransform(rotationAngle: 0))
.concatenating(
CGAffineTransformMakeTranslation(
0,
0
)
)
let transform2 = CGAffineTransform(scaleX: 0.2, y: 0.2)
.concatenating(CGAffineTransform(rotationAngle: 0))
.concatenating(
CGAffineTransformMakeTranslation(
2,
2
)
)
let layerInstruction1 = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack1)
layerInstruction1.setTransform(
transform1, at: CMTime.zero
)
let layerInstruction2 = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack2)
layerInstruction2.setTransform(
transform2, at: CMTime.zero
)
let mainInstruction = AVMutableVideoCompositionInstruction()
mainInstruction.backgroundColor = UIColor.yellow.cgColor
//Max duration
mainInstruction.timeRange = CMTimeRangeMake(
start: CMTime.zero,
duration: max(videoAsset1.duration, videoAsset2.duration)
)
mainInstruction.layerInstructions = [layerInstruction1, layerInstruction2]
let videoComposition = AVMutableVideoComposition()
videoComposition.renderSize = CGSize(width: 1920, height: 1080)
videoComposition.frameDuration = CMTimeMake(value: 1, timescale: 30)
videoComposition.instructions = [mainInstruction]
}
let videoComposition = AVMutableVideoComposition()
videoComposition.renderSize = CGSize(width: 1920, height: 1080)
videoComposition.frameDuration = CMTimeMake(value: 1, timescale: 30)
//every frame processing
videoComposition.customVideoCompositorClass = CustomCompositor.self
let customOverlayInstruction = CustomOverlayInstruction(
timeRange: CMTimeRangeMake(
start: CMTime.zero,
duration: videoAsset.duration
),
videoEntries: videoEntries
)
videoComposition.instructions = [customOverlayInstruction]