Search code examples
iosswiftavfoundationavassetwriteravassetexportsession

AVAssetWriterInput with more than 2 channels


Does someone know how to use the AVAssetWriterInput init with more than 2 channels?

I'm trying to init an audioInput, to add it after on AVAssetWriter this way:

let audioInput = AVAssetWriterInput(mediaType: AVMediaTypeAudio, outputSettings: audioOutputSettings)

assetWriter.add(audioInput)

assetWriter.startWriting()

But it crashes when I init the audioInput with the audioOutputSettings dictionary containing the number of channels key greater than 2. The error is:

Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ’*** -[AVAssetWriterInput initWithMediaType:outputSettings:sourceFormatHint:] 6 is not a valid channel count for Format ID ‘aac ’. Use kAudioFormatProperty_AvailableEncodeNumberChannels (<AudioToolbox/AudioFormat.h>) to enumerate available channel counts for a given format.


Solution

  • As you found in the AVAssetWriterInput comment:

    If AVNumberOfChannelsKey specifies a channel count greater than 2, the dictionary must also specify a value for AVChannelLayoutKey.

    What it fails to mention is that the channel count depends on your format ID, so passing a AudioChannelLayout won't make AAC support anything other than 1 or 2 channels.

    Formats that do support 6 channels include LPCM kAudioFormatLinearPCM and, probably more interestingly, High Efficiency AAC (kAudioFormatMPEG4AAC_HE) which supports 2, 4, 6 and 8 channel audio.

    The following code creates an AVAssetWriterInput that is ready for 6 channel AAC HE sample buffers:

    var channelLayout = AudioChannelLayout()
    channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_5_1_D
    
    let audioOutputSettings: [String : Any] = [
        AVNumberOfChannelsKey: 6,
    
        AVFormatIDKey: kAudioFormatMPEG4AAC_HE,
        AVSampleRateKey: 44100,
        AVChannelLayoutKey: NSData(bytes: &channelLayout, length: MemoryLayout.size(ofValue: channelLayout)),
    ]
    let audioInput = AVAssetWriterInput(mediaType: .audio, outputSettings: audioOutputSettings)