此處來源於網絡,沒有測試:
已經解決,有兩種方法,第一種是把文件轉存到程序的目錄下,轉存的格式為.caf文件,使用的接口為AVAssetReader,AVAssetWriter,AVAssetReaderAudioMixOutput,AVAssetWriterInput;代碼可以參考http://www.subfurther.com/blog/2010/12/13/from-ipod-library-to-pcm-samples-in-far-fewer-steps-than-were-previously-necessary/ 上面說的很清楚了,而且代碼也已經給出;
但這種方法缺點是速度慢,而且每讀一個音頻文件,都會在程序文件夾下生成一個.caf文件(.caf 文件大小約是.mp3的十倍)
第二種方法是直接把文件內容分塊讀入內存,主要用於音頻解析:
//傳入參數就是獲取到的MPMediaItem的AssetURL;
(void)loadToMemory:(NSURL*)asset_url
{
NSError *reader_error=nil;
AVURLAsset *item_choosed_asset=[AVURLAsset URLAssetWithURL:asset_url opti*****:nil];
AVAssetReader *item_reader=[AVAssetReader assetReaderWithAsset:item_choosed_asset error:&reader_error];
if (reader_error) {
NSLog(@"failed to creat asset reader,reason:%@",[reader_error description]);
return;
}
NSArray *asset_tracks=[item_choosed_asset tracks];
AVAssetReaderAudioMixOutput *item_reader_output=[AVAssetReaderAudioMixOutput assetReaderAudioMixOutputWithAudioTracks:asset_tracks audioSettings:nil];
if ([item_reader canAddOutput:item_reader_output]) {
[item_reader addOutput:item_reader_output];
}else {
NSLog(@"the reader can not add the output");
}
UInt64 total_converted_bytes;
UInt64 converted_count;
UInt64 converted_sample_num;
size_t sample_size;
short* data_buffer=nil;
CMBlockBufferRef next_buffer_data=nil;
[item_reader startReading];
while (item_reader.status==AVAssetReaderStatusReading) {
CMSampleBufferRef next_buffer=[item_reader_output copyNextSampleBuffer];
if (next_buffer) {
total_converted_bytes=CMSampleBufferGetTotalSampleSize(next_buffer);//next_buffer的總字節數;
sample_size=CMSampleBufferGetSampleSize(next_buffer, 0);//next_buffer中序號為0的sample的大小;
converted_sample_num=CMSampleBufferGetNumSamples(next_buffer);//next_buffer中所含sample的總個數;
NSLog(@"the number of samples is %f",(float)converted_sample_num);
NSLog(@"the size of the sample is %f",(float)sample_size);
NSLog(@"the size of the whole buffer is %f",(float)total_converted_bytes);
//copy the data to the data_buffer varible;
//這種方法中,我們每獲得一次nextSampleBuffer後就對其進行解析,而不是把文件全部載入內存後再進行解析;
//AVAssetReaderOutput 的copyNextSampleBuffer方法每次讀取8196個sample的數據(最後一次除外),這些數據是以short型存放在內存中(兩字節為一單元)
//每個sample的大小和音頻的聲道數相關,可以用CMSampleBufferGetSampleSize來獲得,所以每次調用copyNextSampleBuffer後所獲得的數據大小為8196*sample_size(byte);
//據此,我們申請data_buffer時每次需要的空間也是固定的,為(8196*sample_size)/2個short型內存(每個short占兩字節);
if (!data_buffer) {
data_buffer= new short[4096*sample_size];
}
next_buffer_data=CMSampleBufferGetDataBuffer(next_buffer);
OSStatus buffer_status=CMBlockBufferCopyDataBytes(next_buffer_data, 0, total_converted_bytes, data_buffer);
if (buffer_status!=kCMBlockBufferNoErr) {
NSLog(@"something wrong happened when copying data bytes");
}
/*
此時音頻的數據存儲在data_buffer中,這些數據是音頻原始數據(未經任何壓縮),可以對其進行解析或其它操作
*/
}else {
NSLog(@"total sameple size %d", converted_count);
size_t total_data_length=CMBlockBufferGetDataLength(item_buffer);
NSLog(@"item buffer length is %f",(float)total_data_length);
break;
}
//CFRelease(next_buffer);
}
if (item_reader.status==AVAssetReaderStatusCompleted) {
NSLog(@"read over......");
}else {
NSLog(@"read failed;");
}
}
第二種,個人應用測試,可以使用。
MPMediaPickerController *pickerController = [[MPMediaPickerController alloc]
initWithMediaTypes: MPMediaTypeMusic];
//pickerController.prompt = @"Choose song";
pickerController.allowsPickingMultipleItems = NO;
pickerController.delegate = self;
[self presentModalViewController:pickerController animated:YES];
[pickerController release];
//將讀取出來的數據寫入沙盒,然後再用路徑得到nsdata。
- (void)mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection
{
NSArray *media_array = [mediaItemCollection items];
MPMediaItem *song_item = [media_array objectAtIndex:0];
SongObject *song_object = [[SongObject alloc] init];
[song_object setSong_name:[song_item valueForProperty: MPMediaItemPropertyTitle]];
[song_object setSinger_name:[song_item valueForKey:MPMediaItemPropertyPodcastTitle]];
NSURL *url = [song_item valueForProperty:MPMediaItemPropertyAssetURL];
NSLog(@"url is %@",url);
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:url options:nil];
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset: songAsset presetName: AVAssetExportPresetAppleM4A];
exporter.outputFileType = @"com.apple.m4a-audio";
NSString *exportFile = [myDocumentsDirectory() stringByAppendingPathComponent: @"exported.m4a"];
if ([[NSFileManager defaultManager] fileExistsAtPath:exportFile])
{
NSError *deleteErr = nil;
[[NSFileManager defaultManager] removeItemAtPath:exportFile error:&deleteErr];
if (deleteErr)
{
NSLog (@"Can't delete %@: %@", exportFile, deleteErr);
}
}
//[songAsset loadValuesAsynchronouslyForKeys:<#(NSArray *)#> completionHandler:<#^(void)handler#>]
NSURL *path_url = [NSURL fileURLWithPath:exportFile];
exporter.outputURL = path_url;
[exporter exportAsynchronouslyWithCompletionHandler:^{
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");
// set up AVPlayer
NSData *data = [NSData dataWithContentsOfURL:path_url];
NSLog(@"data is %@",data);
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;
}
}
}];
[song_object release];
[mediaPicker dismissModalViewControllerAnimated:YES];
}
摘自 雲懷空-abel