音频CMSampleBuffer的深层复制 [英] Deep Copy of Audio CMSampleBuffer

查看:1087
本文介绍了音频CMSampleBuffer的深层复制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 AVCaptureAudioDataOutputSampleBufferDelegate 中创建captureOutput返回的CMSampleBuffer副本。

I am trying to create a copy of a CMSampleBuffer as returned by captureOutput in a AVCaptureAudioDataOutputSampleBufferDelegate.

我遇到的问题是我的框架来自委托方法 captureOutput:didOutputSampleBuffer:fromConnection:在我将它们保留在 CFArray 很长一段时间。

The problem I am having is that my frames coming from delegate method captureOutput:didOutputSampleBuffer:fromConnection: being dropped after I retain them in CFArray for long time.

显然,我需要创建传入缓冲区的深层副本以便进一步处理。我也知道 CMSampleBufferCreateCopy 只能创建浅拷贝。

Obviously, I need to create deep copies of incoming buffers for further processing. I also know that CMSampleBufferCreateCopy only creates shallow copies.

在SO上询问的相关问题很少:

There are few related questions were asked on SO:

  • Pulling data from a CMSampleBuffer in order to create a deep copy
  • Creating copy of CMSampleBuffer in Swift returns OSStatus -12743 (Invalid Media Format)
  • Deep Copy of CMImageBuffer or CVImageBuffer

但它们都没有帮助我正确使用 CMSampleBufferCre吃了12个参数的函数:

But none of them helps me to use correctly CMSampleBufferCreate function with 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 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);
  }

如何深度复制音频CMSampleBuffer?在你的答案中随意使用任何语言(swift / objective-c)。

How do you deep copy Audio CMSampleBuffer? Feel free to use any language (swift/objective-c) in your answers.

推荐答案

这是我最终实施的工作解决方案。我将此代码段发送给Apple Developer Technical support,并要求他们检查这是否是复制传入样本缓冲区的正确方法。基本思路是复制 AudioBufferList ,然后创建 CMSampleBuffer 并设置 AudioBufferList 到此示例。

Here is a working solution I finally implemented. I sent this snippet to Apple Developer Technical support and asked them to check if it is a correct way to copy incoming sample buffer. The basic idea is copy AudioBufferList and then create a CMSampleBuffer and set AudioBufferList to this sample.

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

代码级支持回答:


此代码看起来不错(尽管您需要添加一些额外的错误
检查)。我已经在一个实现
AVCaptureAudioDataOutput委托的应用程序中成功测试了它
captureOutput:didOutputSampleBuffer:fromConnection:方法到
捕获和记录音频。我在使用
时获得的音频这个深拷贝代码看起来与使用提供的样本缓冲区(没有深拷贝)直接
时得到的相同。

This code looks ok (though you’ll want to add some additional error checking). I've successfully tested it in an app that implements the AVCaptureAudioDataOutput delegate captureOutput:didOutputSampleBuffer:fromConnection: method to capture and record audio. The captured audio I'm getting when using this deep copy code appears to be the same as what I get when directly using the provided sample buffer (without the deep copy).

Apple开发者技术支持

Apple Developer Technical Support

这篇关于音频CMSampleBuffer的深层复制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆