2017-10-24 24 views
10

Próbuję utworzyć kopię CMSampleBuffer jako zwróconą przez captureOutput w AVCaptureAudioDataOutputSampleBufferDelegate.Głęboka kopia audio CMSampleBuffer

Problem polega na tym, że moje klatki pochodzące z metody delegowania captureOutput:didOutputSampleBuffer:fromConnection: są usuwane po tym, jak długo je przechowuję w CFArray.

Oczywiście, potrzebuję utworzyć głębokie kopie buforów przychodzących do dalszego przetwarzania. Wiem też, że CMSampleBufferCreateCopy tworzy tylko płytkie kopie.

Istnieje kilka Podobne pytania zadano na SO:

Ale żaden z nich nie pozwala mi używać prawidłowo CMSampleBufferCreate funkcji z 12 parametrów:

CMSampleBufferRef copyBuffer; 

    CMBlockBufferRef data = CMSampleBufferGetDataBuffer(sampleBuffer); 
    CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer); 
    CMItemCount itemCount = CMSampleBufferGetNumSamples(sampleBuffer); 

    CMTime duration = CMSampleBufferGetDuration(sampleBuffer); 
    CMTime presentationStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer); 
    CMSampleTimingInfo timingInfo; 
    timingInfo.duration = duration; 
    timingInfo.presentationTimeStamp = presentationStamp; 
    timingInfo.decodeTimeStamp = CMSampleBufferGetDecodeTimeStamp(sampleBuffer); 


    size_t sampleSize = CMBlockBufferGetDataLength(data); 
    CMBlockBufferRef sampleData; 

    if (CMBlockBufferCopyDataBytes(data, 0, sampleSize, &sampleData) != kCMBlockBufferNoErr) { 
    VLog(@"error during copying sample buffer"); 
    } 

    // Here I tried data and sampleData CMBlockBuffer instance, but no success 
    OSStatus status = CMSampleBufferCreate(kCFAllocatorDefault, data, isDataReady, nil, nil, formatDescription, itemCount, 1, &timingInfo, 1, &sampleSize, &copyBuffer); 

    if (!self.sampleBufferArray) { 
    self.sampleBufferArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 
    //EXC_BAD_ACCESS crash when trying to add sampleBuffer to the array 
    CFArrayAppendValue(self.sampleBufferArray, copyBuffer); 
    } else { 
    CFArrayAppendValue(self.sampleBufferArray, copyBuffer); 
    } 

W jaki sposób kopiować audio Audio CMS? Zachęcamy do używania dowolnego języka (szybkiego/obiektywnego-c) w swoich odpowiedziach.

+0

Czy to oczywiste, że potrzebujesz głębokiej kopii? Co się dzieje, gdy używasz 'CMSampleBufferCreateCopy'? Czy "CMSampleBufferCopySampleBufferForRange" dałoby głęboką kopię? Czy naprawdę potrzebujesz "CMSampleBuffer" do dalszego przetwarzania? Jeśli robisz własne przetwarzanie, długość + wskaźnik może być wygodniejsza. –

+0

@RhythmicFistman tak, oczywiste jest, że potrzebuję głębokiej kopii, jeśli użyję 'CMSampleBufferCreateCopy', a następnie zatrzymam skopiowaną próbkę w' CFArray' więcej niż 1s, 'didOutputSampleBuffer' przestanie być wywoływane. Możesz go łatwo odtworzyć za pomocą tego [pytania] (https://stackoverflow.com/questions/30850676/avcaptureoutput-didoutputsamplebuffer-stops-getting-called). Sprawdzę zachowanie za pomocą 'CMSampleBufferCopySampleBufferForRange' i zaktualizuję. –

+0

Ach, ok, to, że buforowanie zatrzymujące blokuje połączenia od uczestników jest ważną informacją. Czy masz link do działającej wersji powyższego kodu? –

Odpowiedz

6

Oto działające rozwiązanie, które w końcu zaimplementowałem. Wysłałem ten fragment do działu wsparcia technicznego dla programistów Apple i poprosiłem ich o sprawdzenie, czy jest to właściwy sposób na skopiowanie przychodzącego bufora próbek. Podstawową ideą jest kopia AudioBufferList, a następnie utworzenie CMSampleBuffer i ustawienie AudioBufferList tej próbki.

 AudioBufferList audioBufferList; 
     CMBlockBufferRef blockBuffer; 
     //Create an AudioBufferList containing the data from the CMSampleBuffer, 
     //and a CMBlockBuffer which references the data in that AudioBufferList. 
     CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &blockBuffer); 
     NSUInteger size = sizeof(audioBufferList); 
     char buffer[size]; 

     memcpy(buffer, &audioBufferList, size); 
     //This is the Audio data. 
     NSData *bufferData = [NSData dataWithBytes:buffer length:size]; 

     const void *copyBufferData = [bufferData bytes]; 
     copyBufferData = (char *)copyBufferData; 

     CMSampleBufferRef copyBuffer = NULL; 
     OSStatus status = -1; 

     /* Format Description */ 

     AudioStreamBasicDescription audioFormat = *CMAudioFormatDescriptionGetStreamBasicDescription((CMAudioFormatDescriptionRef) CMSampleBufferGetFormatDescription(sampleBuffer)); 

     CMFormatDescriptionRef format = NULL; 
     status = CMAudioFormatDescriptionCreate(kCFAllocatorDefault, &audioFormat, 0, nil, 0, nil, nil, &format); 

     CMFormatDescriptionRef formatdes = NULL; 
     status = CMFormatDescriptionCreate(NULL, kCMMediaType_Audio, 'lpcm', NULL, &formatdes); 
     if (status != noErr) 
     { 
     NSLog(@"Error in CMAudioFormatDescriptionCreator"); 
     CFRelease(blockBuffer); 
     return; 
     } 

     /* Create sample Buffer */ 
     CMItemCount framesCount = CMSampleBufferGetNumSamples(sampleBuffer); 
     CMSampleTimingInfo timing = {.duration= CMTimeMake(1, 44100), .presentationTimeStamp= CMSampleBufferGetPresentationTimeStamp(sampleBuffer), .decodeTimeStamp= CMSampleBufferGetDecodeTimeStamp(sampleBuffer)}; 

     status = CMSampleBufferCreate(kCFAllocatorDefault, nil , NO,nil,nil,format, framesCount, 1, &timing, 0, nil, &copyBuffer); 

     if(status != noErr) { 
     NSLog(@"Error in CMSampleBufferCreate"); 
     CFRelease(blockBuffer); 
     return; 
     } 

     /* Copy BufferList to Sample Buffer */ 
     AudioBufferList receivedAudioBufferList; 
     memcpy(&receivedAudioBufferList, copyBufferData, sizeof(receivedAudioBufferList)); 

     //Creates a CMBlockBuffer containing a copy of the data from the 
     //AudioBufferList. 
     status = CMSampleBufferSetDataBufferFromAudioBufferList(copyBuffer, kCFAllocatorDefault , kCFAllocatorDefault, 0, &receivedAudioBufferList); 
     if (status != noErr) { 
     NSLog(@"Error in CMSampleBufferSetDataBufferFromAudioBufferList"); 
     CFRelease(blockBuffer); 
     return; 
     } 

Code-Level Pomoc odpowiedź:

Ten kod wygląda ok (chociaż będziemy chcieli dodać kilka dodatkowych sprawdzanie błędów). Udało mi się przetestować go w aplikacji, która implementuje metodę delegowania AVCaptureAudioDataOutput captureOutput:didOutputSampleBuffer:fromConnection: do przechwytywania i nagrywania dźwięku. Przechwycony dźwięk, który otrzymuję podczas korzystania z tego kodu głębokiego, wydaje się być taki sam jak uzyskany, gdy bezpośrednio wykorzystuję dostarczony bufor próbki (bez głębokiej kopii).

Pomoc techniczna dla programistów Apple

+0

To świetnie, ale napotykam podobny problem z próbkami wideo (muszę zachować bufory próbek). Czy masz jakieś wskazówki, jak to zaimplementować? –