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:
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, ©Buffer); 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, ©Buffer); 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