#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)
}
}
}
}