Format related:

There are four supported output formats:

[“wav”, “aif”, “caf”, “m4a”]

Caf, which is core Audio Format, supports uncompressed formats, and compressed formats AAC

Wav, uncompressed format

M4a, compressed format, where the general data format is AAC compressed format

Does not support mp3 transfer out,

Audio to MP3, usually using lame library

Supported input formats:

[“wav”, “aif”, “caf”, “m4a”

“mp3”, “snd”, “au”, “sd2”,

“aif”, “aiff”, “aifc”, “aac”,

“mp4”, “m4v”, “mov” ]

And there’s no ending

Audio format conversion generally falls into four categories:

  • Conversion between uncompressed audio
  • Compressed audio between the conversion

Mp3 transfer is not supported

  • Uncompressed audio, go to compressed audio

Mp3 transfer is not supported

  • Compressed audio, uncompressed audio

In Audio Kit, combine (compressed Audio -> uncompressed Audio) and (uncompressed Audio (format A) -> uncompressed Audio (format B)) into one method

func convertToPCM

In Audio Kit, there are 3 methods for converting Audio formats:

  • Compressed audio between the conversion

func convertCompressed

  • Uncompressed audio, go to compressed audio

func convertAsset

  • Audio (including two kinds), to uncompressed audio

func convertToPCM

Determine whether to compress the audio

To determine whether the audio is compressed, look at the end of the file

    internal func isCompressed(url: URL) -> Bool {
      
        let ext = url.pathExtension.lowercased()
        return (ext == "m4a" || ext == "mp3" || ext == "mp4" || ext == "m4v" || ext == "mpg")
    }
Copy the code

implementation

Audio (including two kinds), to uncompressed audio

The ExtAudioFile Service is used

  • Configure format first
/ / to create a blank format template ASBD / / input ASBD var srcFormat = AudioStreamBasicDescription ASBD var dstFormat = () / / output AudioStreamBasicDescription() // ... // Get the ASBD from the source file SrcFormat error = ExtAudioFileGetProperty(inputFile, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &srcFormat) // ... / / configuration, Output of ASBD dstFormat. MSampleRate = outputSampleRate dstFormat. MFormatID = formatKey dstFormat. MChannelsPerFrame = outputChannels dstFormat.mBitsPerChannel = outputBitRate dstFormat.mBytesPerPacket = outputBytesPerPacket dstFormat.mBytesPerFrame = outputBytesPerFrame dstFormat.mFramesPerPacket = 1 dstFormat.mFormatFlags = KLinearPCMFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger / / visible, AIFF is compressed audio formats, PCM big end up if the format = = kAudioFileAIFFType {dstFormat. MFormatFlags = dstFormat. MFormatFlags | kLinearPCMFormatFlagIsBigEndian }Copy the code
  • Reconversion data

A while loop that reads to the end, numFrames 0

Use ExtAudioFileRead to read data,

Write data using ExtAudioFileWrite

var srcBuffer = [UInt8](repeating: 0, count: Int(bufferByteSize)) var sourceFrameOffset: UInt32 = 0 srcBuffer.withUnsafeMutableBytes { ptr in while true { let mBuffer = AudioBuffer(mNumberChannels: srcFormat.mChannelsPerFrame, mDataByteSize: bufferByteSize, mData: ptr.baseAddress) var fillBufList = AudioBufferList(mNumberBuffers: 1, mBuffers: mBuffer) var numFrames: UInt32 = 0 if dSTformat. mBytesPerFrame > 0 {numFrames = bufferByteSize/dstFormat.mBytesPerFrame} // Read data error = ExtAudioFileRead(inputFile, &numFrames, &fillBufList) if error ! = noErr { completionHandler? (createError(message: "Unable to read input file.")) return} // Unable to read input file. If numFrames == 0 {error = noErr break} sourceFrameOffset += numFrames ExtAudioFileWrite(outputFile, numFrames, &fillBufList) if error ! = noErr { completionHandler? (createError(message: "Unable to write output file.")) return } } }Copy the code

The remaining two conversion methods can, of course, be usedExtAudioFile Service

Audio Kit does not use ExtAudioFile Service in the other two conversion methods

The code that Audio Kit uses is much simpler

Compressed audio format between the conversion, the code is very simple

Use the AVAssetExportSession

let asset = AVURLAsset(url: inputURL) guard let session = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else { return } session.outputURL = outputURL session.outputFileType = .m4a session.exportAsynchronously { completionHandler? (nil) }Copy the code

One more. Uncompressed audio. Go to compressed audio

  • Get avasse Reader and Avasse Riter ready
let outputFormat = options? .format ?? outputURL.pathExtension.lowercased() let asset = AVAsset(url: inputURL) do { self.reader = try AVAssetReader(asset: asset) } catch let err as NSError { return } switch outputFormat { case "m4a", "mp4": format = .m4a formatKey = kAudioFormatMPEG4AAC case "aif": format = .aiff formatKey = kAudioFormatLinearPCM case "caf": format = .caf formatKey = kAudioFormatLinearPCM case "wav": format = .wav formatKey = kAudioFormatLinearPCM default: print("Unsupported output format: \(outputFormat)") return } do { self.writer = try AVAssetWriter(outputURL: outputURL, fileType: format) } catch let err as NSError { return }Copy the code
  • useAVAssetReaderTrackOutputComplete the transformation
Let writerInput = AVAssetWriterInput(mediaType:. Audio, outputSettings: outputSettings) writer.add(writerInput) guard let track = asset.tracks(withMediaType: .audio). First else {return} let readerOutput = AVAssetReaderTrackOutput(track: track, outputSettings: nil) guard reader.canAdd(readerOutput) else { return } reader.add(readerOutput) if ! writer.startWriting() { return } writer.startSession(atSourceTime: CMTime.zero) if ! reader.startReading() { return } let queue = DispatchQueue(label: "Com. Audiodesigndesk. FormatConverter. ConvertAsset") / / thread, perform the audio format conversion writerInput. RequestMediaDataWhenReady (on: queue, using: { var processing = true while writerInput.isReadyForMoreMediaData, processing { if reader.status == .reading, let buffer = readerOutput.copyNextSampleBuffer() { writerInput.append(buffer) } else { writerInput.markAsFinished() switch reader.status { case .failed: print("Conversion failed with error", reader.error ?? "") writer.cancelWriting() case .cancelled: print("Conversion cancelled") case .completed: // writer.endSession(atSourceTime: asset.duration) writer.finishWriting { } default: break } processing = false } } })Copy the code

The effect

Compressed audio, uncompressed audio, MP 3 to WAV

Original file MP3, 7.6m, bit rate 320 KB /s

ffprobe -hide_banner -print_format json 1_Le\ Papillon.mp3 { Input #0, mp3, from '1_Le Papillon.mp3': Metadata: Encoder: Lavf57.83.100 Duration: 00:03:08.73, start: 0.025057, bitrate: 320 KB /s Stream #0:0: Audio: Stereo, 44100 Hz, FLTP, 320 KB /s Metadata: encoder: Lavc57.10}Copy the code

The converted WAV, 66.6m, bit rate 2822 KB /s

Ffprobe-hide_banner -print_format json one.wav {Input #0, wav, from 'one.wav': Duration: 00:03:08.71, bitrate: 2822 kb/s Stream #0:0: Audio: pcm_s32le ([1][0][0][0] / 0x0001), 44100 Hz, 2 channels, s32, 2822 kb/s }Copy the code
Uncompressed audio, go to compressed audio, WAV to M4a

The input is the output of the previous one.

The output is 3.1m, bit rate 129 KB /s

ffprobe -hide_banner -print_format json one.m4a { Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'one.m4a': Metadata: major_brand : M4A minor_version : 0 compatible_brands: M4A isommp42 creation_time : The 2020-12-14 T08:05:13. 000000 z iTunSMPB: 00000000 00000840 0000004C 00000000007EFB74 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 Duration: 00:03:08.71, start: 0.047891, bitrate: 129 KB /s Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 127 kb/s (default) Metadata: creation_time : 2020-12-14T08:05:13.000000z Handler_name: Core Media Audio}Copy the code
Compressed audio format conversion between MP3 to M4A

The input is the raw MP3, the input for the first step

The output is 6.1m and the bit rate is 256 KB /s

ffprobe -hide_banner -print_format json two.m4a { Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'two.m4a': Metadata: major_brand : M4A minor_version : 0 compatible_brands: M4A isommp42 creation_time : The 2020-12-14 T08: outrebounded SAN Antonio 44-36. 000000 z iTunSMPB: 00000000 00000840 0000004C 00000000007EFB74 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 Duration: 00:03:08.71, start: 0.047891, bitrate: 256 KB /s Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 254 kb/s (default) Metadata: creation_time : 2020-12-14T08:44:36.000000z Handler_name: Core Media Audio}Copy the code

github repo