Deep Copie de Audio CMSampleBuffer

J'essaye de créer une copy d'un CMSampleBuffer comme returnné par captureOutput dans un AVCaptureAudioDataOutputSampleBufferDelegate .

Le problème que je rencontre est que mes images proviennent de la méthode déléguée captureOutput:didOutputSampleBuffer:fromConnection: cours de captureOutput:didOutputSampleBuffer:fromConnection: après les avoir conservées dans CFArray pendant longtime.

De toute évidence, j'ai besoin de créer des copys profondes des tampons entrants pour un traitement ultérieur. Je sais également que CMSampleBufferCreateCopy crée uniquement des copys superficielles.

Il y a quelques questions connexes ont été posées sur SO:

  • Extraire des données d'un CMSampleBuffer pour créer une copy profonde
  • La création d'une copy de CMSampleBuffer dans Swift renvoie OSStatus -12743 (format de média non valide)
  • Copie profonde de CMImageBuffer ou CVImageBuffer

Mais aucun d'entre eux m'aide à utiliser correctement la fonction CMSampleBufferCreate avec 12 parameters:

  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 sortinged 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); } 

Comment copyz-vous profondément Audio CMSampleBuffer? N'hésitez pas à utiliser n'importe quelle langue (swift / objective-c) dans vos réponses.

Voici une solution de travail que j'ai finalement implémentée. J'ai envoyé cet extrait au support technique d'Apple Developer et leur ai demandé de vérifier s'il s'agissait d'un moyen correct de copyr le tampon d'échantillonnage entrant. L'idée de base est de copyr AudioBufferList , puis de créer un CMSampleBuffer et de définir AudioBufferList sur cet exemple.

  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; } 

Réponse au support au niveau du code:

Ce code semble correct (bien que vous vouliez append quelques vérifications d'erreurs supplémentaires). J'ai testé avec succès dans une application qui implémente le délégué captureOutput:didOutputSampleBuffer:fromConnection: méthode pour capturer et save de l'audio. L'audio capturé que j'obtiens en utilisant ce code de copy profonde semble être le même que ce que je reçois en utilisant directement le tampon d'échantillon fourni (sans la copy profonde).

Assistance technique Apple Developer