8

我正在开展一个需要对大量短(1-5 秒)AVAssets 进行排序的项目(问题在 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来支持它的预览播放​​器。我将不胜感激任何帮助。

4

1 回答 1

0

@Jeff,我不知道您是否检查过 Apple 文档,但他们提到如果在此过程中未删除无声样本,则可能恰好出现 2112 个样本的延迟,因此建议在播放时手动删除系统在两个地方: - 当播放第一次开始时。- 当播放位置移动到另一个位置时 - 例如,用户向前或向后跳到媒体的另一部分并从该新位置开始播放

https://developer.apple.com/library/archive/technotes/tn2258/_index.html

如果它没有帮助,请给我更多关于您使用的技术,实现类型的详细信息,以便我可以帮助您。

于 2020-05-21T01:26:04.307 回答