【问题标题】:Create CMSampleBufferRef from an AudioInputIOProc从 AudioInputIOProc 创建 CMSampleBufferRef
【发布时间】:2018-08-13 19:15:50
【问题描述】:

我有一个AudioInputIOProc,我从中得到一个AudioBufferList。我需要将此AudioBufferList 转换为CMSampleBufferRef

这是我目前编写的代码:

- (void)handleAudioSamples:(const AudioBufferList*)samples numSamples:(UInt32)numSamples hostTime:(UInt64)hostTime {
// Create a CMSampleBufferRef from the list of samples, which we'll own

  AudioStreamBasicDescription monoStreamFormat;
  memset(&monoStreamFormat, 0, sizeof(monoStreamFormat));
  monoStreamFormat.mSampleRate = 44100;
  monoStreamFormat.mFormatID = kAudioFormatMPEG4AAC;
  monoStreamFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved;
  monoStreamFormat.mBytesPerPacket = 4;
  monoStreamFormat.mFramesPerPacket = 1;
  monoStreamFormat.mBytesPerFrame = 4;
  monoStreamFormat.mChannelsPerFrame = 2;
  monoStreamFormat.mBitsPerChannel = 16;

  CMFormatDescriptionRef format = NULL;
  OSStatus status = CMAudioFormatDescriptionCreate(kCFAllocatorDefault, &monoStreamFormat, 0, NULL, 0, NULL, NULL, &format);
  if (status != noErr) {
    // really shouldn't happen
    return;
  }

  mach_timebase_info_data_t tinfo;
  mach_timebase_info(&tinfo);

  UInt64 _hostTimeToNSFactor = (double)tinfo.numer / tinfo.denom;

  uint64_t timeNS = (uint64_t)(hostTime * _hostTimeToNSFactor);
  CMTime presentationTime = CMTimeMake(timeNS, 1000000000);
  CMSampleTimingInfo timing = { CMTimeMake(1, 44100), kCMTimeZero, kCMTimeInvalid };

  CMSampleBufferRef sampleBuffer = NULL;
  status = CMSampleBufferCreate(kCFAllocatorDefault, NULL, false, NULL, NULL, format, numSamples, 1, &timing, 0, NULL, &sampleBuffer);
  if (status != noErr) {
    // couldn't create the sample buffer
    NSLog(@"Failed to create sample buffer");
    CFRelease(format);
    return;
  }

  // add the samples to the buffer
  status = CMSampleBufferSetDataBufferFromAudioBufferList(sampleBuffer,
                                                        kCFAllocatorDefault,
                                                        kCFAllocatorDefault,
                                                        0,
                                                        samples);
  if (status != noErr) {
    NSLog(@"Failed to add samples to sample buffer");
    CFRelease(sampleBuffer);
    CFRelease(format);
    NSLog(@"Error status code: %d", status);
    return;
  }

  [self addAudioFrame:sampleBuffer];

  NSLog(@"Original sample buf size: %ld for %d samples from %d buffers, first buffer has size %d", CMSampleBufferGetTotalSampleSize(sampleBuffer), numSamples, samples->mNumberBuffers, samples->mBuffers[0].mDataByteSize);
  NSLog(@"Original sample buf has %ld samples", CMSampleBufferGetNumSamples(sampleBuffer));
}

现在,给定 AudioInputIOProc 的这个函数定义,我不确定如何计算 numSamples:

OSStatus AudioTee::InputIOProc(AudioDeviceID inDevice, const AudioTimeStamp *inNow, const AudioBufferList *inInputData, const AudioTimeStamp *inInputTime, AudioBufferList *outOutputData, const AudioTimeStamp *inOutputTime, void *inClientData)

此定义存在于 WavTap 的 AudioTee.cpp 文件中。

当我尝试调用CMSampleBufferSetDataBufferFromAudioBufferList 时,我收到的错误是CMSampleBufferError_RequiredParameterMissing 错误代码-12731

更新:

为了澄清问题,以下是我从 AudioDeviceIOProc 获得的音频数据的格式:

Channels: 2, Sample Rate: 44100, Precision: 32-bit, Sample Encoding: 32-bit Signed Integer PCM, Endian Type: little, Reverse Nibbles: no, Reverse Bits: no

我得到了一个 AudioBufferList*,它包含我需要转换为 CMSampleBufferRef* 的所有音频数据(30 秒的视频)并将这些样本缓冲区添加到视频中(即 30 秒长)正在通过AVAssetWriterInput 写入磁盘。

【问题讨论】:

    标签: c++ objective-c macos audio core-audio


    【解决方案1】:

    三件事看起来不对:

    1. 您声明格式 ID 为 kAudioFormatMPEG4AAC,但将其配置为 LPCM。所以试试

      monoStreamFormat.mFormatID = kAudioFormatLinearPCM;

      当它被配置为立体声时,您也将格式称为“单声道”。

    2. 为什么要使用mach_timebase_info,它可能会在您的音频演示时间戳中留下空白?改为使用样本计数:

      CMTime presentationTime = CMTimeMake(numSamplesProcessed, 44100);

    3. 您的CMSampleTimingInfo 看起来不对,而且您没有使用presentationTime。当它可以是numSamples 并且它的呈现时间为零时,您将缓冲区的持续时间设置为 1 个样本长,这是不正确的。这样的事情会更有意义:

      CMSampleTimingInfo timing = { CMTimeMake(numSamples, 44100), presentationTime, kCMTimeInvalid };

    还有一些问题:

    您的AudioBufferList 是否有预期的 2 个AudioBuffers? 你有这个的可运行版本吗?

    附言我自己对此感到内疚,但在音频线程上分配内存是音频开发中的considered harmful

    【讨论】:

    • 对不起,我是新手。输入格式如下:`通道:2 采样率:44100 精度:32 位采样编码:32 位有符号整数 PCM 字节序类型:小反向半字节:无反向位:否` 我需要将此添加到 MP4视频。我有一个 AudioBufferList,其中包含我要添加到视频中的所有音频。感谢您的回复,我会尝试为此设置一个可运行的项目。
    • @AtharvaVaidya 你能把它添加到问题中并说出你传递给它的内容吗?
    • 那看起来像第四个问题:您的输入样本是 32 位,但您的样本缓冲区是 16 位。
    猜你喜欢
    • 1970-01-01
    • 2016-03-30
    • 1970-01-01
    • 2011-03-19
    • 1970-01-01
    • 2013-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多