2015-07-10 122 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函數什麼價值? –