2012-05-30 26 views
7

我在寫一個通過網絡傳輸視頻和音頻的iOS應用程序。我可以使用AVCaptureSession將AAC流編碼到內存嗎?

我使用AVCaptureSession使用AVCaptureVideoDataOutput搶原始視頻幀和軟件using x264進行編碼。這很好。

我想爲音頻做同樣的事情,只是我不需要太多的音頻控制,所以我想用內置的硬件編碼器來產生AAC流。這意味着從音頻工具箱層使用Audio Converter。爲了做到這一點,我把一個處理程序AVCaptudeAudioDataOutput的音頻幀:

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
     fromConnection:(AVCaptureConnection *)connection 
{ 
    // get the audio samples into a common buffer _pcmBuffer 
    CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer); 
    CMBlockBufferGetDataPointer(blockBuffer, 0, NULL, &_pcmBufferSize, &_pcmBuffer); 

    // use AudioConverter to 
    UInt32 ouputPacketsCount = 1; 
    AudioBufferList bufferList; 
    bufferList.mNumberBuffers = 1; 
    bufferList.mBuffers[0].mNumberChannels = 1; 
    bufferList.mBuffers[0].mDataByteSize = sizeof(_aacBuffer); 
    bufferList.mBuffers[0].mData = _aacBuffer; 
    OSStatus st = AudioConverterFillComplexBuffer(_converter, converter_callback, (__bridge void *) self, &ouputPacketsCount, &bufferList, NULL); 
    if (0 == st) { 
     // ... send bufferList.mBuffers[0].mDataByteSize bytes from _aacBuffer... 
    } 
} 

在這種情況下的音頻轉換器的回調函數是非常簡單的(假設數據包大小和計數是正確安裝):

- (void) putPcmSamplesInBufferList:(AudioBufferList *)bufferList withCount:(UInt32 *)count 
{ 
    bufferList->mBuffers[0].mData = _pcmBuffer;   
    bufferList->mBuffers[0].mDataByteSize = _pcmBufferSize; 
} 

而設置的音頻轉換器看起來是這樣的:

{ 
    // ... 
    AudioStreamBasicDescription pcmASBD = {0}; 
    pcmASBD.mSampleRate = ((AVAudioSession *) [AVAudioSession sharedInstance]).currentHardwareSampleRate; 
    pcmASBD.mFormatID = kAudioFormatLinearPCM; 
    pcmASBD.mFormatFlags = kAudioFormatFlagsCanonical; 
    pcmASBD.mChannelsPerFrame = 1; 
    pcmASBD.mBytesPerFrame = sizeof(AudioSampleType); 
    pcmASBD.mFramesPerPacket = 1; 
    pcmASBD.mBytesPerPacket = pcmASBD.mBytesPerFrame * pcmASBD.mFramesPerPacket; 
    pcmASBD.mBitsPerChannel = 8 * pcmASBD.mBytesPerFrame; 

    AudioStreamBasicDescription aacASBD = {0}; 
    aacASBD.mFormatID = kAudioFormatMPEG4AAC; 
    aacASBD.mSampleRate = pcmASBD.mSampleRate; 
    aacASBD.mChannelsPerFrame = pcmASBD.mChannelsPerFrame; 
    size = sizeof(aacASBD); 
    AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &size, &aacASBD); 

    AudioConverterNew(&pcmASBD, &aacASBD, &_converter); 
    // ... 
} 

這似乎很直接只轉發它不起作用。一旦AVCaptureSession運行,音頻轉換器(特別是AudioConverterFillComplexBuffer)返回'hwiu'(硬件使用中)錯誤。轉換工作正常,如果會話被停止,但然後我不能捕獲任何東西...

我想知道是否有一種方法獲得AAC流出AVCaptureSession。我正在考慮的選項包括:

  1. 不知怎的,使用AVAssetWriterInput編碼音頻樣本插入到AAC,然後(不通過AVAssetWriter,這將只寫入一個文件)以某種方式獲取編碼的數據包。

  2. 重組我的應用程序,使其僅在視頻端使用AVCaptureSession並在音頻端使用Audio Queues。這會使流量控制(開始和停止錄製,響應中斷)更加複雜,我擔心它可能會導致音頻和視頻之間的同步問題。此外,它似乎不是一個好的設計。

有誰知道是否可以從AVCaptureSession中獲取AAC?我必須在這裏使用音頻隊列嗎?這可以讓我進入同步或控制問題嗎?

+0

你確定你的AudioConverter可以工作嗎?你有沒有試過關閉捕獲和編碼一些零,說? –

+0

是的,我做過了(我想我在問題中也提到了這個)。如果AVCaptureSession不處於「運行」狀態,編碼器將正常工作。 – Avner

+0

哎呀,對不起。看起來像你在一個綁定。將音頻輸入添加到捕獲會話似乎會佔用AAC編碼器。 –

回答

5

我最終向Apple尋求建議(事實證明,如果您有付費開發者帳戶,您可以這樣做)。

看來,AVCaptureSession抓住了AAC硬件編碼器,但只允許您使用它來直接寫入文件。

您可以使用該軟件編碼器,但你要問它具體而不是使用AudioConverterNew:

AudioClassDescription *description = [self 
     getAudioClassDescriptionWithType:kAudioFormatMPEG4AAC 
         fromManufacturer:kAppleSoftwareAudioCodecManufacturer]; 
if (!description) { 
    return false; 
} 
// see the question as for setting up pcmASBD and arc ASBD 
OSStatus st = AudioConverterNewSpecific(&pcmASBD, &aacASBD, 1, description, &_converter); 
if (st) { 
    NSLog(@"error creating audio converter: %s", OSSTATUS(st)); 
    return false; 
} 

- (AudioClassDescription *)getAudioClassDescriptionWithType:(UInt32)type 
              fromManufacturer:(UInt32)manufacturer 
{ 
    static AudioClassDescription desc; 

    UInt32 encoderSpecifier = type; 
    OSStatus st; 

    UInt32 size; 
    st = AudioFormatGetPropertyInfo(kAudioFormatProperty_Encoders, 
            sizeof(encoderSpecifier), 
            &encoderSpecifier, 
            &size); 
    if (st) { 
     NSLog(@"error getting audio format propery info: %s", OSSTATUS(st)); 
     return nil; 
    } 

    unsigned int count = size/sizeof(AudioClassDescription); 
    AudioClassDescription descriptions[count]; 
    st = AudioFormatGetProperty(kAudioFormatProperty_Encoders, 
           sizeof(encoderSpecifier), 
           &encoderSpecifier, 
           &size, 
           descriptions); 
    if (st) { 
     NSLog(@"error getting audio format propery: %s", OSSTATUS(st)); 
     return nil; 
    } 

    for (unsigned int i = 0; i < count; i++) { 
     if ((type == descriptions[i].mSubType) && 
      (manufacturer == descriptions[i].mManufacturer)) { 
      memcpy(&desc, &(descriptions[i]), sizeof(desc)); 
      return &desc; 
     } 
    } 

    return nil; 
} 

軟件編碼器會佔用CPU資源,當然,但會完成工作。

+0

你介意發佈轉換的隨附代碼嗎?主要是回調函數實現和_aacBuffer和_pcmBuffer定義。非常感謝。 –

+0

我正在尋找相同的Mac等價物,但未找到mac的製造商。有任何想法嗎 ? – Dinesh

+0

AudioConverterFillComplexBuffer中只有在iphones中發生錯誤。不在iPad中 –

相關問題