iphone開發:讀取音頻iPhone軟體開發教學課程

此處來源於網絡,沒有測試:

已經解決,有兩種方法,第一種是把文件轉存到程序的目錄下,轉存的格式為.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

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *