Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A Swift adaptation of Chris Adamson's Objective-C code for exporting iPod Library audio tracks (obtained as AVAssets using an MPMediaPickerController) to LPCM. See http://www.subfurther.com/blog/2010/12/13/from-ipod-library-to-pcm-samples-in-far-fewer-steps-than-were-previously-necessary/ for Chris' original post.
import UIKit
import AVFoundation
protocol FileConverterDelegate {
func fileConversionCompleted()
}
class FileConverter : NSObject {
var delegate : FileConverterDelegate?
func convertIpodAudioWithAsset(asset: AVURLAsset, exportPath: String)
{
// MARK: Reader Setup
// create a reader
var assetError = NSErrorPointer()
let assetReader = AVAssetReader(asset: asset, error: assetError)
if (assetError != nil) {
println(assetError)
return
}
// create an asset for the reader
var assetReaderOutput : AVAssetReaderOutput = AVAssetReaderAudioMixOutput(audioTracks: asset.tracks, audioSettings: nil)
// confirm we can add an output to the reader...
if (assetReader.canAddOutput(assetReaderOutput) == false) {
println("can't add reader output... die!")
return // ...and bail if we can't
}
// but if we can, then add our output to the asset reader
assetReader.addOutput(assetReaderOutput)
// create an export url from our exportPath (AVAssetWriter requires an NSURL)
let exportURL = NSURL.fileURLWithPath(exportPath)
// MARK: Writer Setup
// create an asset writer with our new exportURL
let assetWriter = AVAssetWriter(URL: exportURL, fileType: AVFileTypeCoreAudioFormat, error: assetError)
// make sure we're good, bail if we're not
if (assetError != nil) {
println(assetError)
return
}
// set up the channel layout
var channelLayout = AudioChannelLayout()
memset(&channelLayout, 0, sizeof(AudioChannelLayout));
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
// set up a dictionary with our outputsettings
var outputSettings = [
AVFormatIDKey: kAudioFormatLinearPCM,
AVSampleRateKey: 44100,
AVNumberOfChannelsKey: 2,
AVChannelLayoutKey: NSData(bytes:&channelLayout, length:sizeof(AudioChannelLayout)),
AVLinearPCMBitDepthKey: 16,
AVLinearPCMIsNonInterleaved: false,
AVLinearPCMIsFloatKey: false,
AVLinearPCMIsBigEndianKey: false
]
// create an asset writer input
let assetWriterInput = AVAssetWriterInput(mediaType:AVMediaTypeAudio, outputSettings:outputSettings as NSDictionary as [NSObject : AnyObject])
if (assetWriter.canAddInput(assetWriterInput)) {
assetWriter.addInput(assetWriterInput)
} else {
println("can't add asset writer input... die!")
return
}
assetWriterInput.expectsMediaDataInRealTime = false
// MARK: File Conversion
assetWriter.startWriting()
assetReader.startReading()
let audioTrack = asset.tracks[0] as! AVAssetTrack
let startTime = CMTimeMake(0, audioTrack.naturalTimeScale)
assetWriter.startSessionAtSourceTime(startTime)
// we need to do this on another thread, so let's set up a dispatch group...
var convertedByteCount : Int = 0
let dispatchGroup = dispatch_group_create()
let mediaInputQueue = dispatch_queue_create("mediaInputQueue", nil)
// ... and go
dispatch_group_enter(dispatchGroup)
assetWriterInput.requestMediaDataWhenReadyOnQueue(mediaInputQueue) {
while assetWriterInput.readyForMoreMediaData {
var nextBuffer = assetReaderOutput.copyNextSampleBuffer()
if nextBuffer != nil {
// append buffer
assetWriterInput.appendSampleBuffer(nextBuffer)
convertedByteCount += CMSampleBufferGetTotalSampleSize(nextBuffer)
} else {
// done!
assetWriterInput.markAsFinished()
assetReader.cancelReading()
dispatch_group_leave(dispatchGroup)
// notify our delegate that we're done with the conversion
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), {
self.delegate?.fileConversionCompleted()
})
break
}
}
} // end assetWriterInput block
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.