※この記事の内容は、iOS4.2以降では正常に動作しない可能性があります。
iPodライブラリからの書き出し、第二回です。
前回、MP3からAACへの書き出しができないと書きましたが、おそらくAVAssetExportSessionがサポートしているファイルタイプにMP3がないからと思われます。supportedFileTypesメソッドで取得できるAVAssetExportSessionがサポートしているとおぼしきファイルタイプは以下のようなものです。
"com.apple.quicktime-movie", "com.apple.m4a-audio", "public.mpeg-4", "com.apple.m4v-video", "public.3gpp", "org.3gpp.adaptive-multi-rate-audio", "com.microsoft.waveform-audio", "public.aiff-audio", "public.aifc-audio"
オーディオで対応しているのは、「m4a」「3gpp」「wave」「aiff」「aifc」といったところのようです。
MP3の書き出しの他にも、WAVやAIFFの非圧縮ファイルをそのまま使いたい場合にも、ちょっとめんどくさい方法を使わないといけないようです。僕があれこれ試して成功した方法をとりあえず記録しておきます。もし他にスマートな方法がありましたらご指摘いただけるとうれしいです。
とりあえずコードです。前回のmediaPicker:didPickMediaItems:メソッドを以下のようにマルッと差し替えてください。あと、CoreMedia.Frameworkもインポートしてください。
- (void)mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection { MPMediaItem *item = [mediaItemCollection.items lastObject]; NSURL *url = [item valueForProperty:MPMediaItemPropertyAssetURL]; AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:url options:nil]; AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:urlAsset presetName:AVAssetExportPresetPassthrough]; NSArray *tracks = [urlAsset tracksWithMediaType:AVMediaTypeAudio]; AVAssetTrack *track = [tracks objectAtIndex:0]; id desc = [track.formatDescriptions objectAtIndex:0]; const AudioStreamBasicDescription *audioDesc = CMAudioFormatDescriptionGetStreamBasicDescription((CMAudioFormatDescriptionRef)desc); FourCharCode formatID = audioDesc->mFormatID; NSString *fileType = nil; NSString *ex = nil; switch (formatID) { case kAudioFormatLinearPCM: { UInt32 flags = audioDesc->mFormatFlags; if (flags & kAudioFormatFlagIsBigEndian) { fileType = @"public.aiff-audio"; ex = @"aif"; } else { fileType = @"com.microsoft.waveform-audio"; ex = @"wav"; } } break; case kAudioFormatMPEGLayer3: fileType = @"com.apple.quicktime-movie"; ex = @"mp3"; break; case kAudioFormatMPEG4AAC: fileType = @"com.apple.m4a-audio"; ex = @"m4a"; break; case kAudioFormatAppleLossless: fileType = @"com.apple.m4a-audio"; ex = @"m4a"; break; default: break; } exportSession.outputFileType = fileType; NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; NSString *filePath = [[docDir stringByAppendingPathComponent:[item valueForProperty:MPMediaItemPropertyTitle]] stringByAppendingPathExtension:ex]; exportSession.outputURL = [NSURL fileURLWithPath:filePath]; [exportSession exportAsynchronouslyWithCompletionHandler:^{ if (exportSession.status == AVAssetExportSessionStatusCompleted) { NSLog(@"export session completed"); } else { NSLog(@"export session error"); } [exportSession release]; }]; }
では、ちょっと解説していきます。
AVAssetExportSessionのpresetNameは前回のM4AではなくAVAssetExportPresetPassthroughにしています。これはiPodライブラリから変換をせずにコピーをするpresetのようです。ただし、この場合、outputFileTypeに指定すべきファイルタイプをM4Aの時のように絞ってくれませんので、自分で調べる必要があります。
まず、AVURLAssetが持っているオーディオのAVAssetTrackを取得。さらにAVAssetTrackがもっているformatDescriptionsを取得。formatDescriptionsはNSArrayなのですが、その中に入ってるのはObjective-Cのオブジェクトではなくて、CMAudioFormatDescriptionRefというCarbon?なオブジェクトが入っています。このCMAudioFormatDescriptionRefからCMAudioFormatDescriptionGetStreamBasicDescription()という関数を使って、みなさんおなじみのAudioStreamBasicDescriptionが取得できますので、これを見て判断しています。
wavやaiffのLinearPCMなファイルはどちらもFileIDがkAudioFormatLinearPCMですので、エンディアンで違いを判別しています。
MP3はあれこれ試した結果、FileTypeを@”com.apple.quicktime-movie”にして、ファイル名に拡張子「.mp3」をつけておくと、ExtAudioFileで開くことができました。この挙動は試してみたらできちゃった的な感じなので、なにか正当な方法があるといいなと思っているのですが…。ちなみに、もしかしたらMP3以外もQuickTimeで共通でいけるんじゃないかと思ったのですが、MP3以外でもデータはコピーされるものの、ExtAudioFileでそのままOpenというわけにはいかないようです。
あと、何かが取得できなかった時とかのエラー処理とかはいっさいやってませんのであしからずご了承ください。