[Swift3] AVFoundationで動画の加工合成処理

動画の合成方法を調べていたらこちら（[AVFoundationで動画の加工合成処理](http://qiita.com/KUMAN/items/a2a1e903b26b062d2d79)）で紹介されている方法がわかりやすかったのでSwiftで書き直しました。

```swift
func capture(_ captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAt outputFileURL: URL!, fromConnections connections: [Any]!, error: Error!) {
        // 動画URLからアセットを生成
        let videoAsset: AVURLAsset = AVURLAsset(url: outputFileURL, options: nil)
        
        // ベースとなる動画のコンポジション作成
        let mixComposition : AVMutableComposition = AVMutableComposition()
        let compositionVideoTrack: AVMutableCompositionTrack = mixComposition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid)
        
        // アセットからトラックを取得
        let videoTrack: AVAssetTrack = videoAsset.tracks(withMediaType: AVMediaTypeVideo)[0]
        
        // コンポジションの設定
        try! compositionVideoTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAsset.duration), of: videoTrack, at: kCMTimeZero)
        compositionVideoTrack.preferredTransform = videoAsset.tracks(withMediaType: AVMediaTypeVideo)[0].preferredTransform
        
        // ロゴのCALayerの作成
        let logoImage: UIImage = UIImage(named: "logo.png")!
        let logoLayer: CALayer = CALayer()
        logoLayer.contents = logoImage.cgImage
        logoLayer.frame = CGRect(x: 5, y: 25, width: 57, height: 57)
        logoLayer.opacity = 0.9
        
        // 動画のサイズを取得
        let videoSize: CGSize = videoTrack.naturalSize
        
        // 親レイヤーを作成
        let parentLayer: CALayer = CALayer()
        let videoLayer: CALayer = CALayer()
        parentLayer.frame = CGRect(x: 0, y: 0, width: videoSize.width, height: videoSize.height)
        videoLayer.frame = CGRect(x: 0, y: 0, width: videoSize.width, height: videoSize.height)
        parentLayer.addSublayer(videoLayer)
        parentLayer.addSublayer(logoLayer)
        
        // 合成用コンポジション作成
        let videoComp: AVMutableVideoComposition = AVMutableVideoComposition()
        videoComp.renderSize = videoSize
        videoComp.frameDuration = CMTimeMake(1, 30)
        videoComp.animationTool = AVVideoCompositionCoreAnimationTool.init(postProcessingAsVideoLayer: videoLayer, in: parentLayer)
        
        // インストラクション作成
        let instruction: AVMutableVideoCompositionInstruction = AVMutableVideoCompositionInstruction()
        instruction.timeRange = CMTimeRangeMake(kCMTimeZero, mixComposition.duration)
        let layerInstruction: AVMutableVideoCompositionLayerInstruction = AVMutableVideoCompositionLayerInstruction.init(assetTrack: videoTrack)
        instruction.layerInstructions = [layerInstruction]
        
        // インストラクションを合成用コンポジションに設定
        videoComp.instructions = [instruction]
        
        // 動画のコンポジションをベースにAVAssetExportを生成
        let _assetExport = AVAssetExportSession.init(asset: mixComposition, presetName: AVAssetExportPresetMediumQuality)
        // 合成用コンポジションを設定
        _assetExport?.videoComposition = videoComp
        
        // エクスポートファイルの設定
        let videoName: String = "test.mov"
        let _exportPath: String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
        let exportPath: String = _exportPath + "/" + videoName
        let exportUrl: URL = URL(fileURLWithPath: exportPath)
        _assetExport?.outputFileType = AVFileTypeQuickTimeMovie
        _assetExport?.outputURL = exportUrl
        _assetExport?.shouldOptimizeForNetworkUse = true
        
        // ファイルが存在している場合は削除
        if FileManager.default.fileExists(atPath: exportPath) {
            try! FileManager.default.removeItem(atPath: exportPath)
        }
        
        // エクスポート実行
        _assetExport?.exportAsynchronously(completionHandler: {() -> Void in
            // 端末に保存
            let library: ALAssetLibrary = ALAssetsLibrary()
            if library.videoAtPathIs(compatibleWithSavedPhotosAlbum: exportUrl) {
                library.writeVideoAtPath(toSavedPhotosAlbum: self.delegate.exportUrl, completionBlock: nil)
            }
        })
    }
```