2012-05-30 14 views
7

Ağ üzerinden video ve ses akışı yapan bir iOS uygulaması yazıyorum.Bir AAC akışını belleğe kodlamak için AVCaptureSession kullanabilir miyim?

Ben AVCaptureVideoDataOutput kullanarak ham video kareleri yakala ve yazılım using x264 onları kodlamak için AVCaptureSession kullanıyorum. Bu harika çalışıyor.

Ses için de aynısını yapmak istedim, yalnızca ses tarafında o kadar fazla kontrole ihtiyacım yok ki bu yüzden bir AAC akışı oluşturmak için yerleşik donanım kodlayıcısını kullanmak istedim. Bu, Ses Araç Kutusu katmanından Audio Converter kullanılması anlamına geliyordu. ses dönüştürücü geri arama işlevi oldukça basittir Bu durumda

- (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... 
    } 
} 

(paket boyutlarını varsayarak ve sayımlar düzgün kurulum vardır): Bunu yapmak için ben AVCaptudeAudioDataOutput 'ın ses çerçeveler için bir işleyici koymak:

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

Ve ses dönüştürücü kurulum

şuna benzer:

{ 
    // ... 
    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); 
    // ... 
} 

Bu oldukça düz görünüyor Sadece BT'yi İZİN VERMEZ. AVCaptureSession çalışırken, ses dönüştürücü (özellikle AudioConverterFillComplexBuffer) bir 'hwiu' (kullanımda donanım) hatası döndürür. Oturum durduğunda dönüşüm iyi çalışıyor, ancak daha sonra hiçbir şey yakalayamıyorum ...

AVCaptureSession'dan bir AAC akışı almanın bir yolu olup olmadığını merak ediyordum. Ben düşünüyorum seçenekleri şunlardır:

  1. nasılsa AAC halinde ses örnekleri kodlamak ve ardından (sadece bir dosyaya yazardı ki AVAssetWriter aracılığıyla) nasılsa kodlanmış paketleri almak için AVAssetWriterInput kullanarak.

  2. Uygulamamı yeniden düzenleme, böylece yalnızca video tarafında AVCaptureSession kullanıyor ve ses tarafında Audio Queues kullanıyor. Bu, akış kontrolünü (kaydı başlatmayı ve durdurmayı, kesintilere cevap vermeyi) daha karmaşık hale getirecek ve korkarım ki ses ve görüntü arasındaki eşzamanlama sorunlarına neden olabilir. Ayrıca, sadece iyi bir tasarım gibi görünmüyor.

AAC'yi AVCaptureSession'dan çıkarmak mümkün olup olmadığını bilen var mı? Ses Kuyruklarını burada kullanmak zorunda mıyım? Bu beni senkronize etme veya kontrol problemlerine sokabilir mi?

+0

AudioConverter cihazınızın hiç çalıştığından emin misiniz? Yakalama işlemini kapatıp bazı sıfırları kodlamayı denediniz mi? –

+0

Evet, yaptım (Sanırım bu konuda da bahsettim). AVCaptureSession 'çalışıyor' durumunda değilse kodlayıcı iyi çalışır. – Avner

+0

oops, üzgünüm. bir bağın varmış gibi görünüyor. yakalama oturumunuza bir ses girişi eklemek AAC kodlayıcısını bağlamış gibi görünüyor. –

cevap

5

Apple'dan tavsiye istemek zorunda kaldım (ücretli bir geliştirici hesabınız varsa bunu yapabilirsiniz).

AVCaptureSession, AAC donanım kodlayıcısını elinde tutuyor gibi görünüyor, ancak sadece dosyayı doğrudan yazmak için kullanmanıza izin veriyor.

Sen yazılım kodlayıcı kullanabilirsiniz ama bunun özellikle yerine kullanmak için AudioConverterNew sormak zorunda: tabii ki, CPU kaynaklarını alacak

- (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; 
} 

yazılım kodlayıcı ile

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; 
} 

, ama işi bitirecek.

+0

Dönüştürme için birlikte verilen kodu gönderebilir misiniz? Temelde geri arama işlevi uygulaması ve _aacBuffer ve _pcmBuffer tanımları. Çok teşekkürler. –

+0

Aynı için bir Mac eşdeğeri arıyorum ama mManufacturer, mac için bulunamadı. herhangi bir fikir ? – Dinesh

+0

AudioConverterFillComplexBuffer'da yalnızca iPhone'larda bir hata var. ipad değil –

İlgili konular