AVEExportSession |在视频上添加带有 GIF 和绘图的 UIView

问题描述

Objective : 我有一个视频,上面有一个 UIView,其中包含动画 GIF(不是本地存储,而是使用 giphy api)、文本或手绘。我想将其与单个视频中的图像一起导出。

What I did : 我创建了一个动画所在的 UIView。然后将其转换为 CALayer 并使用 AVMutableVideoCompotion 添加到视频中。

Problem : 带有动画的 UIView 被转换为图像而不是视频。我该如何解决这个问题。 以下是我的导出会话的程序。任何指针都会非常有帮助。

func convertVideoAndSavetophotoLibrary(videoURL: URL) {

    let file = FileManager.shared.getDocumentDirectory(path: currentFilename)
    FileManager.shared.clearPrevIoUsFiles(withPath: file.path)

    // File to composit
    let asset = AVURLAsset(url: videoURL as URL)
    let composition = AVMutableComposition.init()
    composition.addMutableTrack(withMediaType: AVMediaType.video,preferredTrackID: kCMPersistentTrackID_Invalid)
    let clipVideoTrack = asset.tracks(withMediaType: AVMediaType.video)[0]

    // Rotate to potrait
    let transformer = AVMutableVideoCompositionLayerInstruction(assetTrack: clipVideoTrack)
    let videoTransform:CGAffineTransform = clipVideoTrack.preferredTransform

    //fix orientation
    var videoAssetorientation_  = UIImage.Orientation.up

    var isVideoAssetPortrait_  = false

    if videoTransform.a == 0 && videoTransform.b == 1.0 && videoTransform.c == -1.0 && videoTransform.d == 0 {
        videoAssetorientation_ = UIImage.Orientation.right
        isVideoAssetPortrait_ = true
    }
    if videoTransform.a == 0 && videoTransform.b == -1.0 && videoTransform.c == 1.0 && videoTransform.d == 0 {
        videoAssetorientation_ =  UIImage.Orientation.left
        isVideoAssetPortrait_ = true
    }
    if videoTransform.a == 1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == 1.0 {
        videoAssetorientation_ =  UIImage.Orientation.up
    }
    if videoTransform.a == -1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == -1.0 {
        videoAssetorientation_ = UIImage.Orientation.down;
    }


    transformer.setTransform(clipVideoTrack.preferredTransform,at: CMTime.zero)
    transformer.setopacity(0.0,at: asset.duration)

    //adjust the render size if neccessary
    var naturalSize: CGSize
    if(isVideoAssetPortrait_){
        naturalSize = CGSize(width: clipVideoTrack.naturalSize.height,height: clipVideoTrack.naturalSize.width)
    } else {
        naturalSize = clipVideoTrack.naturalSize;
    }

    var renderWidth: CGFloat!
    var renderHeight: CGFloat!

    renderWidth = naturalSize.width
    renderHeight = naturalSize.height

    let parentlayer = CALayer()
    let videoLayer = CALayer()
    let watermarkLayer = CALayer()


    let videoComposition = AVMutableVideoComposition()
    videoComposition.renderSize = CGSize(width: renderWidth,height: renderHeight)
    videoComposition.frameDuration = CMTimeMake(value: 1,timescale: 30)
    videoComposition.renderScale = 1.0
    
    //---------------------->>>>>> converting uiview to uiimage
    watermarkLayer.contents = canvasView.asImage().cgImage

    parentlayer.frame = CGRect(origin: CGPoint(x: 0,y: 0),size: naturalSize)
    videoLayer.frame = CGRect(origin: CGPoint(x: 0,size: naturalSize)
    watermarkLayer.frame = CGRect(origin: CGPoint(x: 0,size: naturalSize)

    parentlayer.addSublayer(videoLayer)
    parentlayer.addSublayer(watermarkLayer)

    //---------------------->>>>>> Add view to video
    videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayers: [videoLayer],in: parentlayer)

    let instruction = AVMutableVideoCompositionInstruction()
    instruction.timeRange = CMTimeRangeMake(start: CMTime.zero,duration: CMTimeMakeWithSeconds(60,preferredTimescale: 30))

    instruction.layerInstructions = [transformer]
    videoComposition.instructions = [instruction]

    let exporter = AVAssetExportSession.init(asset: asset,presetName: AVAssetExportPresetHighestQuality)
    exporter?.outputFileType = AVFileType.mp4
    exporter?.outputURL = file
    exporter?.videoComposition = videoComposition
    exporter?.shouldOptimizeforNetworkUse = true
    
    exporter!.exportAsynchronously(completionHandler: {() -> Void in
        if exporter?.status == .completed {
            let outputURL: URL? = exporter?.outputURL
            self.savetoPhotoLibrary(url: outputURL!)
        }
    })
}

将 UIView 转换为 UIImage

extension UIView {
func asImage() -> UIImage {
    let renderer = UIGraphicsImageRenderer(bounds: bounds)
    return renderer.image { rendererContext in
        layer.render(in: rendererContext.cgContext)
    }
}

}

Code for Adding the GIF(我在这里使用的是 Giphy API),所以 gif 被下载然后添加

func didSelectMedia(giphyViewController: GiphyViewController,media: GPHMedia) {
    addMedia(media: media)
    giphyViewController.dismiss(animated: true) { [weak self] in
        self?.giphy = nil
    }
}

// GPHMediaView is a subclass of UIImageView
func addMedia(media: GPHMedia) {
    let mediaView = GPHMediaView()
    mediaView.media = media
    mediaView.contentMode = .scaleAspectFill
    mediaView.frame.size = CGSize(width: 150,height: 150)
    mediaView.center = canvasView.center
    canvasView.addSubview(mediaView)
    print(mediaView.frame)
    self.addGesturesTo(mediaView)
}

我得到的是:视频中的猫是一个 gif。但遗憾的是,我得到的只是一帧。现在我知道这是因为我正在将视图转换为图像。但这就是我需要知道的解决方案。如何将 gif 合并到视频中。

enter image description here

解决方法

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

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

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