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
相关新闻>>
- 发表评论
-
- 最新评论 更多>>