首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AVMutableComposition -How将多个音频记录与1个视频记录合并

AVMutableComposition -How将多个音频记录与1个视频记录合并
EN

Stack Overflow用户
提问于 2022-03-19 17:03:25
回答 1查看 231关注 0票数 0

我有几个音频剪辑,我用AVAudioRecorder录制了一段视频。使用AVMutableComposition,我希望在录制音频时将音频资产与视频合并。例如,视频是1分钟长,我录制了3个音频剪辑在5-10秒,20-25秒,和30-35秒。音频剪辑应该在这些特定的时间框架内与视频合并。当最后的视频播放时,音频将在这些时间帧上播放。

模型:

代码语言:javascript
复制
class AudioModel {

    var audioUrl: URL?
    var startTime: Double?
    var endTime: Double?
}

混合:

代码语言:javascript
复制
let mixComposition = AVMutableComposition()

guard let videoCompositionTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) else { return }
guard let audioFromVideoCompositionTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) else { return }
guard let audioModelCompositionTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) else { return }

let videoAsset = AVURLAsset(url: videoURL)
guard let videoTrack = videoAsset.tracks(withMediaType: .video).first else { return }

for audioModel in audioModels {

    let audioAsset = AVURLAsset(url: audioModel.url!)
    let startTime = CMTime(seconds: audioModel.startTime!, preferredTimescale: 1000)

    do {

        try videoCompositionTrack.insertTimeRange(CMTimeRangeMake(start: .zero, duration: videoAsset.duration), of: videoTrack, at: .zero)
            
        if let audioTrackFromAudioModel = audioAsset.tracks(withMediaType: .audio).first {
                
            try audioModelCompositionTrack.insertTimeRange(CMTimeRangeMake(start: startTime, duration: audioAsset.duration),
                                                               of: audioTrackFromAudioModel, at: .zero)
        }
            
        if let audioFromVideoTrack = videoAsset.tracks(withMediaType: .audio).first {
            try audioFromVideoCompositionTrack.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: videoAsset.duration),
                                                                   of: audioFromVideoTrack, at: .zero)
        }

    } catch {
    }
}

let exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)
// ... I know what to do from here
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-20 12:42:46

您的方法是正确的,但是您混淆了用于insertTimeRange的两个参数,并且多次从视频轨道中添加视频和音频。

insertTimeRange中的第一个参数是指原始音频资产中的timeRange,而不是组合;因此,假设对于要添加整个剪辑的每个音频剪辑,时间范围应该总是从.zero开始,而不是在startTime。at:参数不应该是.zero,而应该是"startTime“--在要添加音频的组合中的时间。

关于您的视频轨道和audioFromVideoTrack,我不会将它们作为循环的一部分添加,而是在循环之前添加它们。否则,您将多次添加它们(每个音频项一次),而不仅仅是一次,这可能导致不必要的行为或导出会话完全失败。

我编辑了您的代码,但没有进行实际测试,所以请稍加考虑。

代码语言:javascript
复制
guard let videoCompositionTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) else { return }
guard let audioFromVideoCompositionTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) else { return }
guard let audioModelCompositionTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) else { return }

let videoAsset = AVURLAsset(url: videoURL)
guard let videoTrack = videoAsset.tracks(withMediaType: .video).first else { return }

do {
    try videoCompositionTrack.insertTimeRange(CMTimeRangeMake(start: .zero, duration: videoAsset.duration), of: videoTrack, at: .zero)
    if let audioFromVideoTrack = videoAsset.tracks(withMediaType: .audio).first {
        try audioFromVideoCompositionTrack.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: videoAsset.duration), of: audioFromVideoTrack, at: .zero)
    }
} catch {
}

for audioModel in audioModels {
    let audioAsset = AVURLAsset(url: audioModel.url!)
    let startTime = CMTime(seconds: audioModel.startTime!, preferredTimescale: 1000)
    do {
        if let audioTrackFromAudioModel = audioAsset.tracks(withMediaType: .audio).first {
            try audioModelCompositionTrack.insertTimeRange(CMTimeRangeMake(start: .zero, duration: audioAsset.duration), of: audioTrackFromAudioModel, at: startTime)
        }
    } catch {
    }
}

let exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)
// ... I know what to do from here
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71540228

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档