如何导出带有 UIViews 的视频?

rgo*_*alv 5 iphone calayer uiview ios swift

我问了这个问题:拍摄 UIView 的快照,除了一些按钮,以了解如何导出带有 UIViews 的图片。

现在,我想知道如何导出带有 UIView 的视频。这是我正在使用的代码:

  func createFinalVideo(){

    let composition = AVMutableComposition()
    let vidAsset = AVURLAsset(URL: myURL, options: nil)

    // get video track
    let vtrack =  vidAsset.tracksWithMediaType(AVMediaTypeVideo)
    let videoTrack:AVAssetTrack = vtrack[0]
    let vid_timerange = CMTimeRangeMake(kCMTimeZero, vidAsset.duration)

    let audioTrack = vidAsset.tracksWithMediaType(AVMediaTypeAudio)[0]

    let compositionVideoTrack:AVMutableCompositionTrack = composition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID())
    let compositionAudioTrack = composition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid))
    do {
        try compositionVideoTrack.insertTimeRange(vid_timerange, ofTrack: videoTrack, atTime: kCMTimeZero)
        try compositionAudioTrack.insertTimeRange(vid_timerange, ofTrack: audioTrack, atTime: kCMTimeZero)
    }
    catch let error as NSError{
        print("THERE SHOULD BE ERROR DIFFERENT THAN NIL")
        print(error)
        return;
    }

    compositionVideoTrack.preferredTransform = videoTrack.preferredTransform

    // Watermark Effect

    let contentLayer = CALayer()
    contentLayer.addSublayer(self.myTextView.layer)
    contentLayer.frame = CGRectMake(0, 0, self.view.bounds.width, self.view.bounds.height)

    let titleLayer = CATextLayer()
    titleLayer.string = "DO YOU HEAR THE PEOPLE SING?"
    titleLayer.fontSize = 18
    titleLayer.foregroundColor = UIColor.redColor().CGColor
    titleLayer.alignmentMode = kCAAlignmentCenter
    titleLayer.frame = CGRectMake(20, 10, self.view.bounds.width - 40, 20);
    titleLayer.displayIfNeeded()

    let parentlayer = CALayer()
    parentlayer.frame = CGRectMake(0, 0, self.view.bounds.width, self.view.bounds.height)
    parentlayer.addSublayer(self.playerLayer)
    parentlayer.addSublayer(titleLayer)
    self.view.layer.addSublayer(parentlayer)

    let layercomposition = AVMutableVideoComposition()
    layercomposition.frameDuration = CMTimeMake(1, 30)
    layercomposition.renderSize = CGSize(width: self.view.bounds.width, height: self.view.bounds.height)
    layercomposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: playerLayer, inLayer: parentlayer)

    // instruction for watermark
    let instruction = AVMutableVideoCompositionInstruction()
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, composition.duration)
    let videotrack = composition.tracksWithMediaType(AVMediaTypeVideo)[0] as AVAssetTrack
    let layerinstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videotrack)
    instruction.layerInstructions = NSArray(object: layerinstruction) as! [AVVideoCompositionLayerInstruction]
    layercomposition.instructions = NSArray(object: instruction) as! [AVVideoCompositionInstructionProtocol]
    //  create new file to receive data
    let dirPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
    let docsDir: AnyObject = dirPaths[0]
    let movieFilePath = docsDir.stringByAppendingPathComponent("completeFinalMovie.mov")
    let movieDestinationUrl = NSURL(fileURLWithPath: movieFilePath)

    do{
      try  NSFileManager.defaultManager().removeItemAtPath(movieFilePath)
    }
    catch let error as NSError{
        print(error)
        return;
    }

    // use AVAssetExportSession to export video
    let assetExport = AVAssetExportSession(asset: composition, presetName:AVAssetExportPresetHighestQuality)!
    assetExport.outputFileType = AVFileTypeQuickTimeMovie
    assetExport.outputURL = movieDestinationUrl
    assetExport.exportAsynchronouslyWithCompletionHandler({
        switch assetExport.status{
        case AVAssetExportSessionStatus.Failed:
            print("failed \(assetExport.error)")
        case AVAssetExportSessionStatus.Cancelled:
            print("cancelled \(assetExport.error)")
        default:
            print("Movie complete")

            // play video
            NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
              // self.playVideo(movieDestinationUrl!)
                UISaveVideoAtPathToSavedPhotosAlbum(movieFilePath, self,#selector(self.handleCompletionOfVideoToGallery), nil)
            })
        }
    })
}
Run Code Online (Sandbox Code Playgroud)

所以,在关于 firstResponder 的最后我遇到了崩溃,但这不是重要的事情,因为我创建的这个 titleLayer 只是为了测试。

我的主要问题是 UIViews 和 CALayer 如何解决我的问题。据我所知,我必须有一个 parentLayer,videoLayer(在这种情况下是我的 playerLayer,一个当前正在播放视频的 AVPlayerLayer)和一个 contentLayer,它是应该包含当前位于顶部的 UIViews 的层视频(如 Snapchat 的表情符号和录制视频顶部的文字)。如果我只是这样做,contentLayer.addSubLayer(self.emoji.layer) or contentLayer.addSubLayer(self.myTextView.layer)我会将录制的视频保存在我的画廊中,但上面没有任何内容(就像您录制 Snapchat 视频并放置表情符号、文本和其他任何内容一样,但是在尝试将视频保存到您设备的画廊时,最终保存的视频与录制的视频相同,上面没有任何表情符号和文字)。所以,有什么想法吗?

我知道 Swift 和 Objective-C,所以可以随意发布它们中的任何一个代码。