我正在开展一个需要对大量短(1-5 秒)AVAsset
s 进行排序的项目(问题在 n = 30 或更少时可见)。我可以找到使用范围CMTimeRange(start: .zero, end: asset.duration)
插入合成轨道的所有参考材料和示例项目,因此:
let audioTrack: AVAssetTrack = ...
let videoTrack: AVAssetTrack = ...
var playhead = CMTime.zero
for asset in assets {
let assetRange = CMTimeRange(start: .zero, end: asset.duration)
let (sourceAudioTrack, sourceVideoTrack) = sourceTracks(from: asset)
try! audioTrack.insertTimeRange(assetRange, of: sourceAudioTrack, at: playhead)
try! videoTrack.insertTimeRange(assetRange, of: sourceVideoTrack, at: playhead)
playhead = playhead + assetRange.duration
}
问题是这会导致音频和视频不同步(视频似乎落后于音频。)一些观察结果:
- 当我使用较少的剪辑时,问题似乎消失或不那么严重
- 片段在单独播放时不会表现出这种行为
- 某些资产具有时间范围不同的视频和音频轨道。我认为这可能是因为这里讨论的启动框架问题
- 过滤掉轨道长度不同的资产并不能解决问题
- 时间范围均由系统以 44100 时间尺度给出,因此此处讨论的时间尺度不匹配/舍入似乎不适用
我已经测试了许多不同的计算时间范围的策略,但似乎都没有解决这个问题:
enum CompositionStrategy: Int, CaseIterable {
case each // Time range of source video track for video track, audio for audio
case videoTimeRange // Time range of source video track for both
case audioTimeRange // Time range of source audio track for both
case intersection // Intersection of source video and audio time ranges for both
case assetDuration // (start: .zero, end: asset.duration) for both
case trim // Apply audio trim from CoreMedia attachments: https://stackoverflow.com/a/33907747/266711
}
private static func calculateTimeRanges(strategy: CompositionStrategy, audioRange: CMTimeRange, videoRange: CMTimeRange, audioTrimFromStart: CMTime, audioTrimFromEnd: CMTime, assetDuration: CMTime) -> (video: CMTimeRange, audio: CMTimeRange) {
switch strategy {
case .each:
return (video: videoRange, audio: audioRange)
case .audioTimeRange:
return (video: audioRange, audio: audioRange)
case .videoTimeRange:
return (video: videoRange, audio: videoRange)
case .intersection:
let startTime = max(audioRange.start, videoRange.start)
let endTime = min(audioRange.end, videoRange.end)
let range = CMTimeRange(start: startTime, end: endTime)
return (video: range, audio: range)
case .assetDuration:
let range = CMTimeRange(start: .zero, duration: assetDuration)
return (video: range, audio: range)
case .trim:
let audioStart = audioRange.start + audioTrimFromStart
let audioEnd = audioRange.end - audioTrimFromEnd
let trimmedAudio = CMTimeRange(start: audioStart, end: audioEnd)
return (video: videoRange, audio: trimmedAudio)
}
}
(如果音频和视频时间范围不同,则前面片段中的播放头增量会增加为音频和视频时间范围计算的最大值)
这些策略都不能解决问题,我即将与 Apple 联系以获得代码级支持,但我希望我错过了一些简单的事情。我还在 Mac 上浏览了 iMovie,它能够完美地排列这些剪辑而没有同步问题,但它看起来不像是在使用它AVComposition
来支持它的预览播放器。我将不胜感激任何帮助。