通过AVAssetReader读取audio样本
如何通过AVAssetReader读取audio样本? 我find了使用AVAssetReader进行复制或混合的例子,但这些循环总是由AVAssetWriter循环控制。 是否有可能只是创build一个AVAssetReader并通读它,获取每个示例,并将每个audio样本的int32投入数组?
谢谢。
要扩展@ amrox的答案,你可以从CMBlockBufferRef获得一个AudioBufferList,例如
CMItemCount numSamplesInBuffer = CMSampleBufferGetNumSamples(buffer); AudioBufferList audioBufferList; CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer( buffer, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, &buffer ); for (int bufferCount=0; bufferCount < audioBufferList.mNumberBuffers; bufferCount++) { SInt16* samples = (SInt16 *)audioBufferList.mBuffers[bufferCount].mData; for (int i=0; i < numSamplesInBuffer; i++) { // amplitude for the sample is samples[i], assuming you have linear pcm to start with } } //Release the buffer when done with the samples //(retained by CMSampleBufferGetAudioBufferListWithRetainedblockBuffer) CFRelease(buffer);
AVAssetReader *reader = [[AVAssetReader alloc] initWithAsset:asset error:&error]; AVAssetTrack *track = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]; NSDictionary *settings = @{ AVFormatIDKey : [NSNumber numberWithInt:kAudioFormatLinearPCM] }; AVAssetReaderTrackOutput *readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:track outputSettings:settings]; [reader addOutput:readerOutput]; [reader startReading]; CMSampleBufferRef sample = [readerOutput copyNextSampleBuffer]; while ( sample ) { sample = [readerOutput copyNextSampleBuffer]; if ( ! sample ) { continue; } CMBlockBufferRef buffer = CMSampleBufferGetDataBuffer(sample); size_t lengthAtOffset; size_t totalLength; char *data; if ( CMBlockBufferGetDataPointer( buffer, 0, &lengthAtOffset, &totalLength, &data ) != noErr ) { NSLog(@"error!"); break; } // do something with data... CFRelease(sample); }
这里的答案不是通用的。 当AudioBufferList
需要不同的大小时,调用CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer
可能会失败。 举例来说,当非Intererleaved样本。
正确的方法是调用CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer
两次。 第一个调用查询AudioBufferList
所需的大小,第二个调用实际填充AudioBufferList
。
size_t bufferSize = 0; CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer( sampleBuffer, &bufferSize, NULL, 0, NULL, NULL, 0, NULL ); AudioBufferList *bufferList = malloc(bufferSize); CMBlockBufferRef blockBuffer = NULL; CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer( sampleBuffer, NULL, bufferList, bufferSize, NULL, NULL, kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, &blockBuffer ); // handle audio here free(bufferList); CFRelease(blockBuffer);
在现实世界的例子中,你必须执行error handling,也不应该malloc每一帧,而是cachingAudioBufferList
。