iOS swift convert mp3 to aac

前端 未结 2 1329
北海茫月
北海茫月 2021-01-05 13:21

I\'m converting an mp3 to m4a in Swift with code based on this.

It works when I generate a PCM file. When I change the export forma

相关标签:
2条回答
  • 2021-01-05 14:06

    update

    You're creating a caf file instead of an m4a.

    Replace AVFileTypeCoreAudioFormat with AVFileTypeAppleM4A in

    AVAssetWriter(URL: self.outputURL, fileType: AVFileTypeCoreAudioFormat)
    

    Call self.assetWriter.finishWritingWithCompletionHandler() when you've finished.

    0 讨论(0)
  • 2021-01-05 14:09

    Updated the source code in the question to Swift 4 and wrapped it in a class. Credit goes to Castles and Rythmic Fistman for original source code and answer. Left author's comments, added a few assertion's and print statements for debugging. Tested on iOS.

    The bit rate for the output file is hardcoded at 96kb/s, you can easily override this value. Most of the audio files I'm converting are 320kb/s, so I'm using this class to compress the files for offline storage. Compression results at the bottom of this answer.

    Usage:

    let inputFilePath = URL(fileURLWithPath: "/path/to/file.mp3")
    let outputFileURL = URL(fileURLWithPath: "/path/to/output/compressed.mp4")
    
    if let audioConverter = AVAudioFileConverter(inputFileURL: inputFilePath, outputFileURL: outputFileURL) {
        audioConverter.convert()
    }
    

    Class

    import AVFoundation
    
    final class AVAudioFileConverter {
    
      var rwAudioSerializationQueue: DispatchQueue!
      var asset:AVAsset!
      var assetReader:AVAssetReader!
      var assetReaderAudioOutput:AVAssetReaderTrackOutput!
      var assetWriter:AVAssetWriter!
      var assetWriterAudioInput:AVAssetWriterInput!
      var outputURL:URL
      var inputURL:URL
    
      init?(inputFileURL: URL, outputFileURL: URL) {
        inputURL = inputFileURL
        outputURL = outputFileURL
    
        if (FileManager.default.fileExists(atPath: inputURL.absoluteString)) {
          print("Input file does not exist at file path \(inputURL.absoluteString)")
          return nil
        }
      }
    
      func convert() {
        let rwAudioSerializationQueueDescription = " rw audio serialization queue"
        // Create the serialization queue to use for reading and writing the audio data.
        rwAudioSerializationQueue = DispatchQueue(label: rwAudioSerializationQueueDescription)
        assert(rwAudioSerializationQueue != nil, "Failed to initialize Dispatch Queue")
    
        asset = AVAsset(url: inputURL)
        assert(asset != nil, "Error creating AVAsset from input URL")
        print("Output file path -> ", outputURL.absoluteString)
    
        asset.loadValuesAsynchronously(forKeys: ["tracks"], completionHandler: {
          var success = true
          var localError:NSError?
          success = (self.asset.statusOfValue(forKey: "tracks", error: &localError) == AVKeyValueStatus.loaded)
          // Check for success of loading the assets tracks.
          if (success) {
            // If the tracks loaded successfully, make sure that no file exists at the output path for the asset writer.
            let fm = FileManager.default
            let localOutputPath = self.outputURL.path
            if (fm.fileExists(atPath: localOutputPath)) {
              do {
                try fm.removeItem(atPath: localOutputPath)
                success = true
              } catch {
                print("Error trying to remove output file at path -> \(localOutputPath)")
              }
            }
          }
    
          if (success) {
            success = self.setupAssetReaderAndAssetWriter()
          } else {
            print("Failed setting up Asset Reader and Writer")
          }
          if (success) {
            success = self.startAssetReaderAndWriter()
            return
          } else {
            print("Failed to start Asset Reader and Writer")
          }
    
        })
      }
    
      func setupAssetReaderAndAssetWriter() -> Bool {
        do {
          assetReader = try AVAssetReader(asset: asset)
        } catch {
          print("Error Creating AVAssetReader")
        }
    
        do {
          assetWriter = try AVAssetWriter(outputURL: outputURL, fileType: AVFileType.m4a)
        } catch {
          print("Error Creating AVAssetWriter")
        }
    
        var assetAudioTrack:AVAssetTrack? = nil
        let audioTracks = asset.tracks(withMediaType: AVMediaType.audio)
    
        if (audioTracks.count > 0) {
          assetAudioTrack = audioTracks[0]
        }
    
        if (assetAudioTrack != nil) {
    
          let decompressionAudioSettings:[String : Any] = [
            AVFormatIDKey:Int(kAudioFormatLinearPCM)
          ]
    
          assetReaderAudioOutput = AVAssetReaderTrackOutput(track: assetAudioTrack!, outputSettings: decompressionAudioSettings)
          assert(assetReaderAudioOutput != nil, "Failed to initialize AVAssetReaderTrackOutout")
          assetReader.add(assetReaderAudioOutput)
    
          var channelLayout = AudioChannelLayout()
          memset(&channelLayout, 0, MemoryLayout<AudioChannelLayout>.size);
          channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
    
          let outputSettings:[String : Any] = [
            AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
            AVSampleRateKey: 44100,
            AVEncoderBitRateKey: 96000,
            AVNumberOfChannelsKey: 2,
            AVChannelLayoutKey: NSData(bytes:&channelLayout, length:MemoryLayout<AudioChannelLayout>.size)]
    
          assetWriterAudioInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: outputSettings)
          assert(rwAudioSerializationQueue != nil, "Failed to initialize AVAssetWriterInput")
          assetWriter.add(assetWriterAudioInput)
    
        }
        print("Finsihed Setup of AVAssetReader and AVAssetWriter")
        return true
      }
    
      func startAssetReaderAndWriter() -> Bool {
        print("STARTING ASSET WRITER")
        assetWriter.startWriting()
        assetReader.startReading()
        assetWriter.startSession(atSourceTime: kCMTimeZero)
    
        assetWriterAudioInput.requestMediaDataWhenReady(on: rwAudioSerializationQueue, using: {
    
          while(self.assetWriterAudioInput.isReadyForMoreMediaData ) {
            var sampleBuffer = self.assetReaderAudioOutput.copyNextSampleBuffer()
            if(sampleBuffer != nil) {
              self.assetWriterAudioInput.append(sampleBuffer!)
              sampleBuffer = nil
            } else {
              self.assetWriterAudioInput.markAsFinished()
              self.assetReader.cancelReading()
              self.assetWriter.finishWriting {
                print("Asset Writer Finished Writing")
              }
              break
            }
          }
        })
        return true
      }
    }
    

    Input File: 17.3 MB

    // generated with afinfo on mac
    File:           D290A73C37B777F1.mp3
    File type ID:   MPG3
    Num Tracks:     1
    ----
    Data format:     2 ch,  44100 Hz, '.mp3' (0x00000000) 0 bits/channel, 0 bytes/packet, 1152 frames/packet, 0 bytes/frame
                    no channel layout.
    estimated duration: 424.542025 sec
    audio bytes: 16981681
    audio packets: 16252
    bit rate: 320000 bits per second
    packet size upper bound: 1052
    maximum packet size: 1045
    audio data file offset: 322431
    optimized
    audio 18720450 valid frames + 576 priming + 1278 remainder = 18722304
    ----
    

    Output File: 5.1 MB

    // generated with afinfo on Mac
    File:           compressed.m4a
    File type ID:   m4af
    Num Tracks:     1
    ----
    Data format:     2 ch,  44100 Hz, 'aac ' (0x00000000) 0 bits/channel, 0 bytes/packet, 1024 frames/packet, 0 bytes/frame
    Channel layout: Stereo (L R)
    estimated duration: 424.542041 sec
    audio bytes: 5019294
    audio packets: 18286
    bit rate: 94569 bits per second
    packet size upper bound: 763
    maximum packet size: 763
    audio data file offset: 44
    not optimized
    audio 18722304 valid frames + 2112 priming + 448 remainder = 18724864
    format list:
    [ 0] format:    2 ch,  44100 Hz, 'aac ' (0x00000000) 0 bits/channel, 0 bytes/packet, 1024 frames/packet, 0 bytes/frame
    Channel layout: Stereo (L R)
    ----
    
    0 讨论(0)
提交回复
热议问题