※この記事の内容は、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というわけにはいかないようです。
あと、何かが取得できなかった時とかのエラー処理とかはいっさいやってませんのであしからずご了承ください。