2011-02-11 7 views
15

AVAssetReader를 통해 오디오 샘플을 어떻게 읽으십니까? AVAssetReader를 사용하여 복제 또는 믹싱 예제를 찾았지만 이러한 루프는 항상 AVAssetWriter 루프에 의해 제어됩니다. AVAssetReader를 만들고이를 통해 읽을 수 있으며 각 샘플을 가져 와서 각 오디오 샘플의 int32를 배열에 던져 넣을 수 있습니까?AVAssetReader를 통해 오디오 샘플 읽기

감사합니다.

답변

25

@ 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); 
+0

정말 고마워요! 그게 내가 놓친 부분 이었어. –

+0

이 방법을 사용할 때 사운드가 고르지 않게됩니다. char *를 사용하는 @ amrox의 방법을 사용할 때'samples [i] * = 0.5; '와 같은 것을 수행하여 볼륨을 변경할 때 모든 것이 잘 작동합니다. – Dex

+0

샘플을 가져 와서 다른 오디오 파일에 쓸 수 있습니까? 오디오 파일을 뒤집어 쓰려고합니다. 제발 [제 질문] (http://stackoverflow.com/questions/41310944/reverse-an-audio-file-swift-objective-c)을보십시오. 어떤 도움을 주시면 감사하겠습니다. –

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

감사합니다. @amrox. 이것은 약간을 돕는다. 그러나 출력을 추가하고 독서를 시작하는 것이 빠진 것 같습니다. 그냥 다음과 같이 추가 할 수 있습니다 : \t [reader addOutput : readerOutput]; \t [독자 시작 읽기]; readerOutput을 만든 후에는 맞습니까? 일단 추가하면 전체 오디오 파일을 읽지 않고 한두 번만 읽을 수 있습니다. 그게 어떻게 작동해야합니까? 그렇다면이 방법으로 개별 샘플에 어떤 영향을 미치는지 이해할 수 없습니다. 오디오 파일의 각 샘플은 비트 깊이와 샘플 속도로 정의 된 양과 범위와 함께 int입니다. 그 int들에 어떻게 접근 할 수 있습니까? 다시 한 번 감사드립니다. –

+0

그들은 char * 데이터에 있습니다. 더 많은 제어가 필요하면 설정 사전에 더 많은 키를 설정하십시오 : AVNumberOfChannelsKey, AVLinearPCMBitDepthKey. 그리고 amrox에 현상금을 수여하는 것을 잊지 마십시오. –

5

여기에 나온 대답은 일반적인 것이 아닙니다. AudioBufferList 크기를 다르게 조정해야하는 경우 CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer에 대한 호출이 실패 할 수 있습니다. 비 intererleaved 샘플을 예로 들면.

올바른 방법은 CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer을 두 번 호출하는 것입니다. 첫 번째 호출은 AudioBufferList에 필요한 크기를 쿼리하고 두 번째 호출은 실제로 AudioBufferList을 채 웁니다. 당신은 오류 처리를 수행해야하고 또한 모든 프레임을 malloc을해서는 안 실제 예에서

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을 캐시합니다.

관련 문제