2015-07-10 123 views
4

我试图将我从音频单元获得的AudioBufferList转换为CMSampleBuffer,我可以将其传递到AVAssetWriter以保存来自麦克风的音频。这种转换很有效,因为我为执行转换所做的调用不会失败,但录制最终会失败,而且我在日志中看到一些似乎引起关注的输出。将AudioBufferList转换为CMSampleBuffer产生意外结果

的代码我使用看起来像这样:

- (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的情况下。

+0

什么是_hostTimeToNSFactor?谢谢 –

+0

@PabloMartinez我们通过调用'mach_timebase_info'和这个数学来计算它:'_hostTimeToNSFactor =(double)tinfo.numer/tinfo.denom'。 但是,可能有更好的方法:https://developer.apple.com/library/ios/qa/qa1643/_index.html –

+0

感谢吉姆,你传递给hostTime函数什么价值? –