首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过AVAssetReader读取音频样本

通过AVAssetReader读取音频样本
EN

Stack Overflow用户
提问于 2011-02-12 02:29:39
回答 3查看 19.5K关注 0票数 17

如何通过AVAssetReader读取音频样本?我发现了使用AVAssetReader进行复制或混合的示例,但这些循环总是由AVAssetWriter循环控制。是否可以创建一个AVAssetReader并读取它,获取每个样本并将每个音频样本的int32放入一个数组中?

谢谢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-02-18 00:40:54

要扩展@amrox的答案,您可以从CMBlockBufferRef获取一个AudioBufferList,例如

代码语言:javascript
复制
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); 
票数 27
EN

Stack Overflow用户

发布于 2011-02-15 04:51:42

代码语言:javascript
复制
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);
}
票数 18
EN

Stack Overflow用户

发布于 2015-03-28 06:23:52

这里的答案不是通用的。当AudioBufferList需要不同的大小时,对CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer的调用可能会失败。当以非交错样本为例时。

正确的方法是调用CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer两次。第一个调用查询AudioBufferList所需的大小,第二个调用实际填充AudioBufferList

代码语言:javascript
复制
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);

在一个真实的例子中,你必须执行错误处理,而且你也不应该对每一帧都进行恶意锁定,而是缓存AudioBufferList

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4972677

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档