Reading audio samples via AVAssetReader

后端 未结 3 1280
陌清茗
陌清茗 2020-11-27 13:05

How do you read audio samples via AVAssetReader? I\'ve found examples of duplicating or mixing using AVAssetReader, but those loops are always controlled by the AVAssetWrite

相关标签:
3条回答
  • 2020-11-27 13:31
    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);
    }
    
    0 讨论(0)
  • 2020-11-27 13:37

    To expand on @amrox's answer, you can get an AudioBufferList from the CMBlockBufferRef, e.g.

    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); 
    
    0 讨论(0)
  • 2020-11-27 13:42

    The answers here are not generic. The call to CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer might fail when the AudioBufferList needs to be sized differently. When having non-intererleaved samples as example.

    The correct way is to call CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer twice. The first call queries the size needed for the AudioBufferList and second one actually fills the 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);
    

    In a real world example you must perform error handling and also you should not malloc every frame, instead cache the AudioBufferList.

    0 讨论(0)
提交回复
热议问题