You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:14:48