将 AudioBufferList 转换为 CMSampleBuffer 会产生意外结果
Posted
技术标签:
【中文标题】将 AudioBufferList 转换为 CMSampleBuffer 会产生意外结果【英文标题】:Converting an AudioBufferList to a CMSampleBuffer Produces Unexpected Results 【发布时间】:2015-07-10 02:55:56 【问题描述】:我正在尝试将从音频单元获得的 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));
正如我所提到的,代码本身似乎并没有失败,但 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
奇怪的是,样本缓冲区报告它有 1024 个样本,但大小为 0。原始 AudioBufferList 有 2048 个字节的数据,这是我对 1024 个 2 字节样本的预期。
我在初始化和填充CMSampleBuffer
的方式上做错了吗?
【问题讨论】:
【参考方案1】:事实证明,样本量恢复为 0 的事实是一个红鲱鱼。一旦我清理了一些东西——值得注意的是,我正确设置了时间戳,如下所示:
uint64_t timeNS = (uint64_t)(hostTime * _hostTimeToNSFactor);
CMTime presentationTime = CMTimeMake(timeNS, 1000000000);
CMSampleTimingInfo timing = CMTimeMake(1, 48000), presentationTime, kCMTimeInvalid ;
录音开始工作了。
因此,如果有人被报告的 0 样本缓冲区大小吓跑了,请注意这是可以的,至少在您将数据输入到 AVAssetWriter
的情况下。
【讨论】:
@PabloMartinez 我们通过调用mach_timebase_info
和这个数学计算它:_hostTimeToNSFactor = (double)tinfo.numer / tinfo.denom
。但是,可能有更好的方法:developer.apple.com/library/ios/qa/qa1643/_index.html
谢谢 Jim,您在 hostTime 上传递给函数的值是什么?
你好 Jim 你能告诉我什么是 hostTime 吗?我不知道从哪里得到那个参数。我只有一个 AudioBufferList
Pablo,抱歉回复晚了:我以为我已经回答了你的问题,但显然我没有。在这段代码中,hostTime
是我们在音频单元回调中得到的时间戳:[sampleDelegate handleAudioSamples:&list numSamples:inNumberFrames hostTime:inTimeStamp->mHostTime];
嗨,你有完整的代码示例可以展示吗?我有同样的问题,但并不真正了解不同的部分是如何结合在一起的。 tnx以上是关于将 AudioBufferList 转换为 CMSampleBuffer 会产生意外结果的主要内容,如果未能解决你的问题,请参考以下文章
AudioBufferList to float ** 转换 EZAudio EZMicrophone for Visual Plotting
aurioTouch2 录音问题。我需要将数据从一个 AudioBufferList 添加到另一个
如何在渲染回调中交错非交错的 AudioBufferList?
MAGNOLIA CMS - 使用 cmsu:simpleSearch 和 cmsu:searchResultSnippet 链接无法正确显示并且无法将日期转换为可读格式