如何从iPhone/iPod的音乐库中拷贝音乐到自己的App里
程序员文章站
2022-05-28 10:29:56
...
最近做的app需要从iOS系统的音乐库里面拷贝选中的歌曲到APP的Documents目录下,在网上找了好久之后,终于找到两种方法,分别是可以导出成指定的格式和导出成Core Audio支持的caf格式,代码分别记录在下面
1,导出成caf格式,这种导出方式,文件名必须以.caf作为后缀,使用其他后缀会导出失败
上面的代码来自 http://www.subfurther.com/blog/2010/12/13/from-ipod-library-to-pcm-samples-in-far-fewer-steps-than-were-previously-necessary/ ,删减了一些更新界面的代码。
2,导出成mp3或者其他格式
以上的代码参考了 http://*.com/questions/4746349/copy-ipod-music-library-audio-file-to-iphone-app-folder 这个帖子, 他原帖中创建AVAssetExportSession时用的是这样的创建方式
但是这样的代码在我的APP上不能工作,所以把最后一个参数改成了AVAssetExportPresetAppleM4A,可以通过 [AVAssetExportSession exportPresetsCompatibleWithAsset:song]来获取歌曲支持哪些preset。
1,导出成caf格式,这种导出方式,文件名必须以.caf作为后缀,使用其他后缀会导出失败
- (void) convertToCAF:(NSString *)filename (MPMediaItem *)song { NSURL *assetURL = [song valueForProperty:MPMediaItemPropertyAssetURL]; AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil]; NSError *assetError = nil; AVAssetReader *assetReader = [[AVAssetReader assetReaderWithAsset:songAsset error:&assetError] retain]; if (assetError) { NSLog (@"error: %@", assetError); return; } AVAssetReaderOutput *assetReaderOutput = [[AVAssetReaderAudioMixOutput assetReaderAudioMixOutputWithAudioTracks:songAsset.tracks audioSettings: nil] retain]; if (! [assetReader canAddOutput: assetReaderOutput]) { NSLog (@"can't add reader output... die!"); return; } [assetReader addOutput: assetReaderOutput]; NSArray *dirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectoryPath = [dirs objectAtIndex:0]; NSString *exportPath = [[documentsDirectoryPath stringByAppendingPathComponent:filename] retain]; if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) { [[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil]; } NSURL *exportURL = [NSURL fileURLWithPath:exportPath]; AVAssetWriter *assetWriter = [[AVAssetWriter assetWriterWithURL:exportURL fileType:AVFileTypeCoreAudioFormat error:&assetError] retain]; if (assetError) { NSLog (@"error: %@", assetError); return; } AudioChannelLayout channelLayout; memset(&channelLayout, 0, sizeof(AudioChannelLayout)); channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo; NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey, [NSNumber numberWithFloat:44100.0], AVSampleRateKey, [NSNumber numberWithInt:2], AVNumberOfChannelsKey, [NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey, [NSNumber numberWithInt:16], AVLinearPCMBitDepthKey, [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved, [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey, [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey, nil]; AVAssetWriterInput *assetWriterInput = [[AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:outputSettings] retain]; if ([assetWriter canAddInput:assetWriterInput]) { [assetWriter addInput:assetWriterInput]; } else { NSLog (@"can't add asset writer input... die!"); return; } assetWriterInput.expectsMediaDataInRealTime = NO; [assetWriter startWriting]; [assetReader startReading]; AVAssetTrack *soundTrack = [songAsset.tracks objectAtIndex:0]; CMTime startTime = CMTimeMake (0, soundTrack.naturalTimeScale); [assetWriter startSessionAtSourceTime: startTime]; __block UInt64 convertedByteCount = 0; dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL); [assetWriterInput requestMediaDataWhenReadyOnQueue:mediaInputQueue usingBlock: ^ { // NSLog (@"top of block"); while (assetWriterInput.readyForMoreMediaData) { CMSampleBufferRef nextBuffer = [assetReaderOutput copyNextSampleBuffer]; if (nextBuffer) { // append buffer [assetWriterInput appendSampleBuffer: nextBuffer]; // NSLog (@"appended a buffer (%d bytes)", // CMSampleBufferGetTotalSampleSize (nextBuffer)); convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer); } else { // done! [assetWriterInput markAsFinished]; [assetWriter finishWriting]; [assetReader cancelReading]; NSDictionary *outputFileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:exportPath error:nil]; NSLog (@"done. file size is %lld", [outputFileAttributes fileSize]); // release a lot of stuff [assetReader release]; [assetReaderOutput release]; [assetWriter release]; [assetWriterInput release]; [exportPath release]; break; } } }]; }
上面的代码来自 http://www.subfurther.com/blog/2010/12/13/from-ipod-library-to-pcm-samples-in-far-fewer-steps-than-were-previously-necessary/ ,删减了一些更新界面的代码。
2,导出成mp3或者其他格式
- (void) convertToMp3: (MPMediaItem *)song { NSURL *url = [song valueForProperty:MPMediaItemPropertyAssetURL]; AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:url options:nil]; NSFileManager *fileManager = [NSFileManager defaultManager]; NSArray *dirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectoryPath = [dirs objectAtIndex:0]; NSLog (@"compatible presets for songAsset: %@",[AVAssetExportSession exportPresetsCompatibleWithAsset:songAsset]); NSArray *ar = [AVAssetExportSession exportPresetsCompatibleWithAsset: songAsset]; NSLog(@"%@", ar); AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset: songAsset presetName: AVAssetExportPresetAppleM4A]; NSLog (@"created exporter. supportedFileTypes: %@", exporter.supportedFileTypes); exporter.outputFileType = @"com.apple.m4a-audio"; NSString *exportFile = [documentsDirectoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.m4a",[song valueForProperty:MPMediaItemPropertyTitle]]]; NSError *error1; if([fileManager fileExistsAtPath:exportFile]) { [fileManager removeItemAtPath:exportFile error:&error1]; } NSURL* exportURL = [[NSURL fileURLWithPath:exportFile] retain]; exporter.outputURL = exportURL; // do the export [exporter exportAsynchronouslyWithCompletionHandler:^ { NSData *data1 = [NSData dataWithContentsOfFile:exportFile]; //NSLog(@"==================data1:%@",data1); int exportStatus = exporter.status; switch (exportStatus) { case AVAssetExportSessionStatusFailed: { // log error to text view NSError *exportError = exporter.error; NSLog (@"AVAssetExportSessionStatusFailed: %@", exportError); break; } case AVAssetExportSessionStatusCompleted: { NSLog (@"AVAssetExportSessionStatusCompleted"); break; } case AVAssetExportSessionStatusUnknown: { NSLog (@"AVAssetExportSessionStatusUnknown"); break; } case AVAssetExportSessionStatusExporting: { NSLog (@"AVAssetExportSessionStatusExporting"); break; } case AVAssetExportSessionStatusCancelled: { NSLog (@"AVAssetExportSessionStatusCancelled"); break; } case AVAssetExportSessionStatusWaiting: { NSLog (@"AVAssetExportSessionStatusWaiting"); break; } default: { NSLog (@"didn't get export status"); break; } } }]; }
以上的代码参考了 http://*.com/questions/4746349/copy-ipod-music-library-audio-file-to-iphone-app-folder 这个帖子, 他原帖中创建AVAssetExportSession时用的是这样的创建方式
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset: songAsset presetName: AVAssetExportPresetPassthrough];
但是这样的代码在我的APP上不能工作,所以把最后一个参数改成了AVAssetExportPresetAppleM4A,可以通过 [AVAssetExportSession exportPresetsCompatibleWithAsset:song]来获取歌曲支持哪些preset。