Чтение аудиосэмплов через AVAssetReader - PullRequest
16 голосов
/ 11 февраля 2011

Как вы читаете аудио образцы через AVAssetReader? Я нашел примеры дублирования или микширования с использованием AVAssetReader, но эти циклы всегда контролируются циклом AVAssetWriter. Можно ли просто создать AVAssetReader и прочитать его, получая каждый семпл и выбрасывая int32 каждого аудиосэмпла в массив?

Спасибо.

Ответы [ 3 ]

26 голосов
/ 17 февраля 2011

Чтобы расширить ответ @ amrox, вы можете получить AudioBufferList из CMBlockBufferRef, например,

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); 
18 голосов
/ 14 февраля 2011
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);
}
6 голосов
/ 28 марта 2015

Ответы здесь не являются общими.Вызов CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer может произойти сбой, когда AudioBufferList должен иметь другой размер.Если в качестве примера используются сэмплы без перемежения.

Правильный способ - вызвать 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);

В реальном примере вы должны выполнить обработку ошибок, а также вы не должны неправильно распределять каждый кадрвместо этого кешируйте AudioBufferList.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...