使用AVMutableComposition合并两个视频遇到困难
解决AVMutableComposition合并视频仅显示第一个的问题
嘿,我之前也踩过这个坑!用AVMutableComposition合并视频却只出第一个,大概率是这几个环节没处理到位,咱们一步步排查:
确认第二个视频轨道是否正确插入到合成中
你只贴了第一个视频的初始化代码,得检查有没有把第二个视频(clip2)的轨道也添加进composition。核心是要计算好插入的时间点——必须接在第一个视频的时长之后,而不是覆盖或者漏加。示例代码参考:// 初始化第二个视频资源 let videoAsset2 = AVAsset(url: clip2) // 获取第二个视频的视频轨道 guard let videoTrack2 = videoAsset2.tracks(withMediaType: .video).first else { return } // 给合成创建可修改的视频轨道(如果还没创建) if composition.tracks(withMediaType: .video).isEmpty { _ = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid) } guard let compositionVideoTrack = composition.tracks(withMediaType: .video).first else { return } // 插入第二个视频:起始时间是合成当前的总时长,确保接在第一个视频后面 let insertTime = composition.duration try? compositionVideoTrack.insertTimeRange( CMTimeRange(start: .zero, duration: videoAsset2.duration), of: videoTrack2, at: insertTime )别漏了音频轨道的同步处理
很多人只处理视频轨道,忘了音频!如果第二个视频带音频,没同步添加的话可能导致导出异常,甚至视频不显示。同步处理音频轨道的逻辑和视频类似:if let audioTrack2 = videoAsset2.tracks(withMediaType: .audio).first { // 创建合成的音频轨道(如果不存在) if composition.tracks(withMediaType: .audio).isEmpty { _ = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) } guard let compositionAudioTrack = composition.tracks(withMediaType: .audio).first else { return } try? compositionAudioTrack.insertTimeRange( CMTimeRange(start: .zero, duration: videoAsset2.duration), of: audioTrack2, at: composition.duration ) }检查AVAssetExportSession的配置细节
导出环节也容易出问题:- 确保
outputURL是唯一的,避免覆盖旧文件导致异常; - 如果两个视频分辨率不同,要么提前统一尺寸,要么用
AVAssetExportPresetPassthrough(仅当分辨率一致时适用); - 一定要等待导出异步回调完成,不要提前终止操作。示例:
guard let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality) else { return } exportSession.outputURL = yourUniqueOutputURL exportSession.outputFileType = .mov exportSession.exportAsynchronously { DispatchQueue.main.async { switch exportSession.status { case .completed: // 导出成功后再保存到相机胶卷 PHPhotoLibrary.shared().performChanges({ PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: exportSession.outputURL!) }) { success, _ in if success { print("合并视频已保存") } } case .failed: print("导出失败:\(exportSession.error?.localizedDescription ?? "未知错误")") default: break } } }- 确保
验证第二个视频资源是否加载完成
AVAsset是异步加载的,如果直接操作未加载完成的资源,可能导致轨道获取失败。可以用loadValuesAsynchronously确保资源加载完成后再处理:videoAsset2.loadValuesAsynchronously(forKeys: ["tracks"]) { DispatchQueue.main.async { var error: NSError? let status = videoAsset2.statusOfValue(forKey: "tracks", error: &error) if status == .loaded { // 这里再执行添加轨道的逻辑 } else { print("第二个视频加载失败:\(error?.localizedDescription ?? "")") } } }
内容的提问来源于stack exchange,提问作者ZbadhabitZ
相关产品推荐
相关产品推荐

