以编程方式在视频Swift上添加UIView层

以编程方式在视频Swift上添加UIView层,swift,avassetexportsession,avmutablecomposition,avurlasset,Swift,Avassetexportsession,Avmutablecomposition,Avurlasset,我试图在视频上添加UIView,我使用的代码来自我在互联网上找到的Tutiarial() 功能代码如下所示: func addViewToVideo(fromVideoAt videoURL: URL, withView: UIView, onComplete: @escaping (URL?) -> Void) { let asset = AVURLAsset(url: videoURL) let composition = AVMutableComposition()

我试图在视频上添加UIView,我使用的代码来自我在互联网上找到的Tutiarial() 功能代码如下所示:

func addViewToVideo(fromVideoAt videoURL: URL, withView: UIView, onComplete: @escaping (URL?) -> Void) {

    let asset = AVURLAsset(url: videoURL)
    let composition = AVMutableComposition()

    guard
        let compositionTrack = composition.addMutableTrack(
            withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid),
        let assetTrack = asset.tracks(withMediaType: .video).first
    else {
        print("Something is wrong with the asset.")
        onComplete(nil)
        return
    }

    do {
        let timeRange = CMTimeRange(start: .zero, duration: asset.duration)
        try compositionTrack.insertTimeRange(timeRange, of: assetTrack, at: .zero)

        if let audioAssetTrack = asset.tracks(withMediaType: .audio).first,
           let compositionAudioTrack = composition.addMutableTrack(
            withMediaType: .audio,
            preferredTrackID: kCMPersistentTrackID_Invalid) {
            try compositionAudioTrack.insertTimeRange(
                timeRange,
                of: audioAssetTrack,
                at: .zero)
        }
    } catch {
        print(error)
        onComplete(nil)
        return
    }

    compositionTrack.preferredTransform = assetTrack.preferredTransform

    let videoSize: CGSize = CGSize(width: assetTrack.naturalSize.height, height: assetTrack.naturalSize.width)

    let videoLayer = CALayer()
    videoLayer.frame = CGRect(origin: .zero, size: videoSize)
    let overlayLayer = CALayer()
    overlayLayer.frame = CGRect(origin: .zero, size: videoSize)

    addImage(imagePassed: self.upperView.asImage(), to: overlayLayer, videoSize: videoSize)


    let outputLayer = CALayer()
    outputLayer.frame = CGRect(origin: .zero, size: videoSize)

    outputLayer.addSublayer(videoLayer)
    outputLayer.addSublayer(overlayLayer)

    let videoComposition = AVMutableVideoComposition()
    videoComposition.renderSize = videoSize
    videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
    videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(
        postProcessingAsVideoLayer: videoLayer,
        in: outputLayer)

    let instruction = AVMutableVideoCompositionInstruction()
    instruction.timeRange = CMTimeRange(
        start: .zero,
        duration: composition.duration)
    videoComposition.instructions = [instruction]
    let layerInstruction = compositionLayerInstruction(
        for: compositionTrack,
        assetTrack: assetTrack)
    instruction.layerInstructions = [layerInstruction]

    guard let export = AVAssetExportSession(
            asset: composition,
            presetName: AVAssetExportPresetHighestQuality)
    else {
        print("Cannot create export session.")
        onComplete(nil)
        return
    }

    let videoName = UUID().uuidString
    let exportURL = URL(fileURLWithPath: NSTemporaryDirectory())
        .appendingPathComponent(videoName)
        .appendingPathExtension("mov")

    export.videoComposition = videoComposition
    export.outputFileType = .mov
    export.outputURL = exportURL

    export.exportAsynchronously {
        DispatchQueue.main.async {
            switch export.status {
            case .completed:
                onComplete(exportURL)
            default:
                print("Something went wrong during export.")
                print(export.error ?? "unknown error")
                onComplete(nil)
                break
            }
        }
    }
}

private func addImage(imagePassed: UIImage, to layer: CALayer, videoSize: CGSize) {
    let image = imagePassed
    let imageLayer = CALayer()

    let aspect: CGFloat = image.size.width / image.size.height
    let width = videoSize.width
    let height = width / aspect
    imageLayer.frame = CGRect(
        x: 0,
        y: -height * 0.15,
        width: width,
        height: height)

    imageLayer.contents = image.cgImage
    layer.addSublayer(imageLayer)
}

private func compositionLayerInstruction(for track: AVCompositionTrack, assetTrack: AVAssetTrack) -> AVMutableVideoCompositionLayerInstruction {
    let instruction = AVMutableVideoCompositionLayerInstruction(assetTrack: track)
    let transform = assetTrack.preferredTransform

    instruction.setTransform(transform, at: .zero)

    return instruction
}
它工作得很好,但我不知道是什么原因,当url来自前摄像头时,视频仅显示在视图的上部。
这就像一半是视频,一半是黑屏。

可能是转换的问题。可能会对你有所帮助谢谢,我实现了你链接的问题中的解决方案,但它并没有完全解决问题,我达到的最佳水平是在视频显示时倒置@aheze时对
cAffineTransform(a:0,b:-1,c:1,d:0,tx:0,ty:assetSize.width)