将 AudioBufferList 转换为 CMSampleBuffer 会产生意想不到的结果

Jim*_*ong 5 audio core-audio ios

我正在尝试AudioBufferList将从音频单元获得的一个转换为一个CMSampleBuffer我可以传递给一个AVAssetWriter以保存来自麦克风的音频。这种转换有效,因为我为执行转换而进行的调用不会失败,但记录最终确实会失败,而且我在日志中看到一些似乎引起关注的输出。

我正在使用的代码如下所示:

- (void)handleAudioSamples:(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 = 48000;
    monoStreamFormat.mFormatID = kAudioFormatLinearPCM;
    monoStreamFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved;
    monoStreamFormat.mBytesPerPacket = 2;
    monoStreamFormat.mFramesPerPacket = 1;
    monoStreamFormat.mBytesPerFrame = 2;
    monoStreamFormat.mChannelsPerFrame = 1;
    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;
    }

    CMSampleTimingInfo timing = { CMTimeMake(1, 48000), 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
        PTKLogError(@"Failed to create sample buffer");
        CFRelease(format);
      return;
    }

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

    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));
Run Code Online (Sandbox Code Playgroud)

正如我所提到的,代码本身似乎没有失败,但AVAssetWriter不喜欢它,并且CMSampleBuffer我正在创建的代码的大小似乎为 0,基于正在记录以下日志条目的事实:

2015-07-09 19:34:00.710 xxxx[1481:271334] Original sample buf size: 0 for 1024 samples from 1 buffers, first buffer has size 2048
2015-07-09 19:34:00.710 xxxx[1481:271334] Original sample buf has 1024 samples
Run Code Online (Sandbox Code Playgroud)

奇怪的是,样本缓冲区报告它有 1024 个样本,但大小为 0。原始 AudioBufferList 有 2048 个字节的数据,这是我对 1024 个 2 字节样本的期望。

我在初始化和填充CMSampleBuffer.

Jim*_*ong 1

事实证明,样本量返回为 0 的事实是一个转移注意力的事实。一旦我清理了一些东西——值得注意的是,我正确设置了时间戳,如下所示:

uint64_t timeNS = (uint64_t)(hostTime * _hostTimeToNSFactor);
CMTime presentationTime = CMTimeMake(timeNS, 1000000000);
CMSampleTimingInfo timing = { CMTimeMake(1, 48000), presentationTime, kCMTimeInvalid };
Run Code Online (Sandbox Code Playgroud)

录音开始工作。

因此,如果其他人因报告的 0 样本缓冲区大小而感到困惑,请注意这是可以的,至少在您将数据输入到AVAssetWriter.