2011-02-11 7 views
15

¿Cómo se leen las muestras de audio a través de AVAssetReader? He encontrado ejemplos de duplicación o mezcla utilizando AVAssetReader, pero esos bucles siempre están controlados por el bucle AVAssetWriter. ¿Es posible simplemente crear un AVAssetReader y leerlo, obteniendo cada muestra y lanzando el int32 de cada muestra de audio en una matriz?Lectura de muestras de audio a través de AVAssetReader

Gracias.

Respuesta

25

Para ampliar la respuesta de @ amrox, se puede obtener una AudioBufferList del CMBlockBufferRef, por ejemplo,

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

¡Muchas gracias! Esa era la parte que me faltaba. –

+0

Cuando uso este método, mi sonido se vuelve agitado, cuando uso el método de @ amrox, que usa un char *, todo funciona bien cuando se altera el volumen haciendo algo como 'samples [i] * = 0.5;' ¿Alguna razón para esto? – Dex

+0

¿Es posible obtener las muestras y luego escribirlas en otro archivo de audio? Intento revertir un archivo de audio. Por favor, eche un vistazo a [mi pregunta] (http://stackoverflow.com/questions/41310944/reverse-an-audio-file-swift-objective-c). Cualquier ayuda sería apreciada. –

16
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); 
} 
+2

Gracias @amrox. Esto ayuda a algunos. Pero creo que falta agregar la salida e iniciar la lectura. Eso solo se puede agregar con: \t [reader addOutput: readerOutput]; \t [reader startReading]; después de crear readerOutput, ¿verdad? Una vez que agregue eso, esto no lee todo un archivo de audio, sino solo una o dos veces. ¿Es así como se supone que debe funcionar? Si es así, no entiendo cómo esto me lleva a las muestras individuales. Cada muestra en un archivo de audio es un int, con la cantidad y el rango definidos por la profundidad de bits y la frecuencia de muestreo. ¿Cómo puedo llegar a esos momentos? Gracias de nuevo. –

+0

Están en esa char * datos. Configure más teclas en el diccionario de configuración si desea más control: AVNumberOfChannelsKey, AVLinearPCMBitDepthKey. Y no te olvides de otorgar la recompensa a amrox. –

5

Las respuestas aquí no son genéricas. La llamada a CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer puede fallar cuando el tamaño AudioBufferList necesita un tamaño diferente. Al tener muestras no intererleaved como ejemplo.

La forma correcta es llamar al CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer dos veces. La primera llamada consulta el tamaño necesario para el AudioBufferList y el segundo realmente llena el 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); 

En un ejemplo del mundo real debe realizar el control de errores y también que no debe malloc cada cuadro, en lugar caché el AudioBufferList.

Cuestiones relacionadas