Инструкции Swift AVFoundation не устанавливают непрозрачность

#swift #xcode #avfoundation #avkit #avmutablevideocomposition

Вопрос:

У меня есть функция, которая объединяет видео. Все видео правильно сливаются, и первые два видео будут воспроизводиться идеально, но затем воспроизводится только звук для третьего видео. Я предполагаю, что видео есть, но оно просто заблокировано вторым видео. Я в замешательстве, хотя, потому что я использую инструкции, чтобы установить непрозрачность каждого актива на 0, когда видео будет готово, но это не работает. Кроме того, даже если я не задам никаких инструкций, первое видео исчезнет, чтобы разрешить воспроизведение второго видео, но второе видео никогда не исчезает. Что происходит?!

     func mergeVideo(completion: @escaping (_ url: URL?, _ error: Error?) -> Void) {
        let mixComposition = AVMutableComposition()
        let videoComposition = AVMutableVideoComposition()

        guard let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
            completion(nil, nil)
            return
        }
        
        let outputURL = documentDirectory.appendingPathComponent("(id).mov")
        
        do {
            if FileManager.default.fileExists(atPath: outputURL.path) {
                try FileManager.default.removeItem(at: outputURL)
            }
        } catch {
            print(error.localizedDescription)
        }
        
        // If there is only one video, save export time.
        if let video = videos.first, videos.count == 1 {
            do {
                if let url = URL(string: video.videoURL) {
                    try FileManager().copyItem(at: url, to: outputURL)
                    completion(outputURL, nil)
                    mergedVideoURL = outputURL.lastPathComponent
                }
            } catch let error {
                completion(nil, error)
            }
            return
        }
        
        var currentTime = CMTime.zero
        let renderSize = CGSize(width: 1280.0, height: 720.0)
        let mainInstruction = AVMutableVideoCompositionInstruction()

        videos.enumerated().forEach { index, video in
            if let vidURL = URL(string: video.videoURL)?.lastPathComponent {
                let url = documentDirectory.appendingPathComponent(vidURL)
                let asset = AVAsset(url: url)

                guard let assetTrack = asset.tracks.first else { return }

                mainInstruction.timeRange = CMTimeRangeMake(start: .zero, duration: CMTimeAdd(mixComposition.duration, asset.duration))
                let instruction = AVMutableVideoCompositionLayerInstruction(assetTrack: assetTrack)
                instruction.setOpacity(0.0, at: asset.duration)
                mainInstruction.layerInstructions.append(instruction)
                          
                do {
                    let timeRange = CMTimeRangeMake(start: .zero, duration: asset.duration)
                    try mixComposition.insertTimeRange(timeRange, of: asset, at: currentTime)
                    currentTime = CMTimeAdd(currentTime, asset.duration)
                } catch let error {
                    completion(nil, error)
                }

            }
        }//forEach

        videoComposition.instructions = [mainInstruction]
        videoComposition.frameDuration = CMTimeMake(value: 1, timescale: 30)
        videoComposition.renderSize = renderSize
        
        guard let exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetPassthrough) else {
            completion(nil, nil)
            return
        }
        exporter.outputURL = outputURL
        exporter.outputFileType = .mov
        // Pass Video Composition to the Exporter.
        exporter.videoComposition = videoComposition
        
        exporter.exportAsynchronously {
            DispatchQueue.main.async {
                switch exporter.status {
                case .completed:
                    completion(exporter.outputURL, nil)
                case .failed:
                    completion(exporter.outputURL, exporter.error)
                case.cancelled:
                    completion(exporter.outputURL, exporter.error)
                case .unknown:
                    completion(exporter.outputURL, exporter.error)
                case .waiting:
                    print("waiting")
                case .exporting:
                    print("exporting")
                @unknown default:
                    completion(exporter.outputURL, exporter.error)
                }
            }
        }
    }