AVAssetWriter 仅在 iOS 中从特定视频写入音频时失败

AVAssetWriter fails only in iOS when writing audio from specific videos

我有一个用于调整视频大小的示例项目,适用于大多数视频。但是,AVAssetWriter 无法写入特定视频的音频,错误为:

Error Domain=AVFoundationErrorDomain 
Code=-11800 "The operation could not be completed" 
UserInfo={
  NSLocalizedFailureReason=An unknown error occurred (-12780), 
  NSLocalizedDescription=The operation could not be completed, 
  NSUnderlyingError=0x282e956e0 {
    Error Domain=NSOSStatusErrorDomain Code=-12780 "(null)"
  }
}

更有问题的是,如果我在 macOS 上 运行 相同的代码可以正常工作,但它在 iOS 中中断。我认为这不是硬件问题,因为它也会在 iOS 模拟器中损坏。

这些是我用于(解)压缩资产轨道的设置:

func audioDecompressionSettings() -> [String: Any] {
    return [
        AVFormatIDKey: kAudioFormatLinearPCM
    ]
}

func audioCompressionSettings() -> [String: Any] {
    var audioChannelLayout = AudioChannelLayout()
    memset(&audioChannelLayout, 0, MemoryLayout<AudioChannelLayout>.size)
    audioChannelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo
    
    return [
        AVFormatIDKey: kAudioFormatMPEG4AAC,
        AVSampleRateKey: 44100,
        AVEncoderBitRateKey: 128000,
        AVNumberOfChannelsKey: 2,
        AVChannelLayoutKey: NSData(bytes: &audioChannelLayout, length: MemoryLayout<AudioChannelLayout>.size)
    ]
}

func videoDecompressionSettings() -> [String: Any] {
    return [
        kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,
        kCVPixelBufferMetalCompatibilityKey as String: true
    ]
}

func videoCompressionSettings(size: CGSize) -> [String: Any] {
    return [
        AVVideoCodecKey: AVVideoCodecType.h264,
        AVVideoWidthKey: size.width,
        AVVideoHeightKey: size.height
    ]
}

可以找到完整的源代码here

在该项目中有两个目标,一个用于 Mac,另一个用于 iOS,它们都使用相同的代码来调整视频大小。我还包含了两个示例视频文件:fruit.mp4rain.mp4。第一个在两个目标中都运行良好,但第二个在 iOS.

中失效

我是不是遗漏了什么,或者这可能是 Apple 的 bug?

有问题的视频的音频设置是:

Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 5.1, fltp, 386 kb/s (default)

另一个是:

Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 137 kb/s (default)

两者之间的重要区别在于音频通道的数量:第一个为 5.1(5 个全带宽通道 + 一个 low-frequency 效果通道),第二个为立体声 (2)。

读取视频文件时,我们指定解压设置:

[AVFormatIDKey: kAudioFormatLinearPCM]

这意味着解压缩的音频将与源文件具有相同数量的声道。在我们的例子中,我们有一个 5.1(实际上是 6)通道资产,我们想将它写入一个 2 通道文件。似乎 AVAssetWriterInput 在 iOS 中没有正确处理这种情况,我们得到一个错误。

问题的解决方案是在从资产中解压缩音频时指定我们想要的音频通道数,如下所示:

[
    AVFormatIDKey: kAudioFormatLinearPCM
    AVNumberOfChannelsKey: 2
]