Объединить два видео друг на друга - PullRequest
2 голосов
/ 30 апреля 2020

Я пытаюсь объединить два видео, чтобы второе видео было поверх другого видео. Мое второе видео имеет прозрачный фон, поэтому мой желаемый результат выглядит следующим образом:

enter image description here

Однако я не вижу второго видео в своем результате

Вот мой код:


func merge(video firstAsset: AVAsset, withSecondVideo secondAsset: AVAsset, completion: @escaping (_ mergedVideoURL: URL?, _ error: Error?) -> Void) {

        let mixComposition = AVMutableComposition()
        let firstTrack = mixComposition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid)
        let secondTrack = mixComposition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid)
        let audioTrack = mixComposition.addMutableTrack(withMediaType: AVMediaType.audio , preferredTrackID: kCMPersistentTrackID_Invalid)

        guard let firstMediaTrack = firstAsset.tracks(withMediaType: AVMediaType.video).first else { return }
        guard let secondMediaTrack = secondAsset.tracks(withMediaType: AVMediaType.video).first else { return }
        guard let audioAsset = secondAsset.tracks(withMediaType: AVMediaType.audio).first else { return }
        do {
            try firstTrack?.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: firstAsset.duration), of: firstMediaTrack, at: CMTime.zero)
            try secondTrack?.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: firstAsset.duration), of: secondMediaTrack, at: CMTime.zero)
            try audioTrack?.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: firstAsset.duration), of: audioAsset, at: CMTime.zero)
        } catch (let error) {
            print(error)
        }

        let width = max(firstMediaTrack.naturalSize.width, secondMediaTrack.naturalSize.width)
        let height = max(firstMediaTrack.naturalSize.height, secondMediaTrack.naturalSize.height)

        let videoComposition = AVMutableVideoComposition()
        videoComposition.renderSize = CGSize(width: width, height: height)
        videoComposition.frameDuration = firstMediaTrack.minFrameDuration

        let firstLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: firstMediaTrack)
        firstLayerInstruction.setTransform(firstMediaTrack.preferredTransform, at: CMTime.zero)

        let secondlayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: secondMediaTrack)
        secondlayerInstruction.setTransform(secondMediaTrack.preferredTransform, at: CMTime.zero)

        let instruction = AVMutableVideoCompositionInstruction()
        instruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: firstAsset.duration)
        instruction.layerInstructions = [firstLayerInstruction, secondlayerInstruction]

        videoComposition.instructions = [instruction]

        let outputUrl = URL(fileURLWithPath: ((FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last)?.path)!).appendingPathComponent("\(UUID().uuidString)-mergedVideo.mp4").path

        exportCompositedVideo(compiledVideo: mixComposition, toURL: URL(fileURLWithPath: outputUrl), withVideoComposition: videoComposition) { (output) in
            DispatchQueue.main.async(execute: {() -> Void in
                completion(output,nil)
            })
        }

    }

    func exportCompositedVideo(compiledVideo: AVMutableComposition, toURL outputUrl: URL, withVideoComposition videoComposition: AVMutableVideoComposition, completion: @escaping (_ mergedVideoURL: URL?) -> Void) {
        guard let exporter = AVAssetExportSession(asset: compiledVideo, presetName: AVAssetExportPresetHighestQuality) else { return }
        exporter.outputURL = outputUrl
        exporter.videoComposition = videoComposition
        exporter.outputFileType = AVFileType.mp4
        exporter.shouldOptimizeForNetworkUse = true
        exporter.exportAsynchronously(completionHandler: {
            switch exporter.status {
            case .completed:
                PHPhotoLibrary.shared().performChanges({PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: exporter.outputURL!)
                }) { saved, error in
                    if saved {
                        print("save of potentially looped video succesful")
                    }
                }
                completion(exporter.outputURL)
            case .exporting:
                let progress = exporter.progress
                print(" Progress "\(progress)")
            case .failed:
                print("Error: \(exporter.error)")
                print("Description: \(exporter.description)")
            default: break
            }
        })
    }

Я пробовал несколько решений, но результат всегда один и тот же

...