通过 CALayer 在从图库中挑选的风景视频上添加贴纸图像

问题描述

我正在添加 CALayer 以在视频上添加贴纸图像。哪个工作得很好。我正在以纵向模式拍摄图像或录制视频,例如 snapchat 和 TikTok。

问题是当我从图库中选择视频并在附加的黄色区域添加贴纸时。合并视频顶部的图像。压缩失败。

我想在任何我想要的视频顶部添加图像。当我在合并后播放时,图像应该在所需位置可见。对于图像,我只是捕获拖动视图的屏幕截图并将其作为图像传递给我的方法。这适用于从应用捕获的图像或录制视频,但不适用于图库媒体。

I followed the Ray tutorial

Video is in the middle,I played it via AVPlayer. Drageable view is on entire screen.Yellow is a sticker image. Which is draggable.

let asset = AVURLAsset(url: inputURL)
        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.")
            handler(nil)
            return
        }
        
        do {
            // 1
            let timeRange = CMTimeRange(start: .zero,duration: asset.duration)
            // 2
            try compositionTrack.insertTimeRange(timeRange,of: assetTrack,at: .zero)
            
            // 3
            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 {
            // 4
            print(error)
            handler(nil)
            return
        }
        
        compositionTrack.preferredTransform = assetTrack.preferredTransform
        let videoInfo = orientation(from: assetTrack.preferredTransform)
        
        var videoSize: CGSize
        if videoInfo.isPortrait {
            videoSize = CGSize(
                width: assetTrack.naturalSize.height,height: assetTrack.naturalSize.width)
        } else {
            videoSize = assetTrack.naturalSize
        }
        
        let videoLayer = CALayer()
        videoLayer.frame = CGRect(origin: .zero,size: videoSize)
        let overlayLayer = CALayer()
        overlayLayer.frame = CGRect(origin: .zero,size: videoSize)

        guard let image = capturedimage else {
            return
        }
        let imageLayer = CALayer()
        imageLayer.frame = overlayLayer.frame
        imageLayer.contents = image.cgImage
        overlayLayer.addSublayer(imageLayer)
        
        
        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]
        
        let filename = NSUUID().uuidString + ".mp4"
        _ = Utility.delete(fileName: filename)
        let compressedURL = NSURL.fileURL(withPath: NstemporaryDirectory() + filename)
        let urlAsset = AVURLAsset(url: inputURL,options: nil)
        
        guard let exportSession = AVAssetExportSession(asset: urlAsset,presetName: AVAssetExportPreset640x480) else {
            handler(nil)
            
            return
        }
        exportSession.outputURL = compressedURL
        exportSession.outputFileType = .mp4
        exportSession.shouldOptimizeforNetworkUse = true
        exportSession.videoComposition = videoComposition
        exportSession.exportAsynchronously { () -> Void in
            switch exportSession.status {
            case .unkNown:
                print("unkNown")
                handler(nil)
                break
            case .waiting:
                print("waiting")
                handler(nil)
                break
            case .exporting:
                print("exporting")
                handler(nil)
                break
            case .completed:
                print("File size before compression: \(inputURL.fileSizeString)")
                print("File size after compression: \(compressedURL.fileSizeString)")
                handler(compressedURL)
            case .Failed:
                print("Failed")
                handler(nil)
                break
            case .cancelled:
                print("cancelled")
                handler(nil)
                break
            @unkNown default:
                print("none")
                handler(nil)
            }
        }

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)