2

マイクからオーディオをキャプチャし、AAC 形式でストリーミング サーバーにストリーミングする必要がある iPhone アプリを作成しています。そのため、最初にオーディオをキャプチャしてから、

AudioConverterFillComplexBuffer

オーディオを AAC に変換する方法。

以下はコードです

- (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{

   NSArray *audioChannels = connection.audioChannels;
   if (audioChannels == nil || [audioChannels count]==0) { 
        // NSLog(@"We have Video Frame");      
        [_encoder encodeFrame:sampleBuffer];
   }else{
        // NSLog(@"We have Audio Frame");
        if (hasAudio) {
            CMTime prestime =          CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
        double dPTS = (double)(prestime.value) / prestime.timescale;         

        [self getAudioBufferDataFromCMSampleBufferRef:sampleBuffer];      

        // describe output data buffers into which we can receive data.
        AudioBufferList outputBufferList;
        outputBufferList.mNumberBuffers = 1;
        outputBufferList.mBuffers[0].mNumberChannels = _aacASBD.mChannelsPerFrame;
        outputBufferList.mBuffers[0].mDataByteSize = _aacBufferSize;
        outputBufferList.mBuffers[0].mData = _aacBuffer;

        OSStatus st = AudioConverterFillComplexBuffer(_converter,   &putPcmSamplesInBufferList, (__bridge void *) self, &_numOutputPackets, &outputBufferList, NULL);

        if (0 == st) {             
            [_rtsp onAudioData:_aacBuffer :outputBufferList.mBuffers[0].mDataByteSize :dPTS];
        }else{
            NSLog(@"Error converting Buffer");
            NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:st userInfo:nil];
            NSLog([self OSStatusToStr :st] );
            char * str = new char[3];
            FormatError(str, st);

        } 

        if (_blockBuffer) // Double check that what you are releasing actually exists!
        {
            CFRelease(_blockBuffer);
        }          
  }


}

getAudioBufferDataFromCMSampleBufferRef のコードは次のとおりです。

- (AudioBuffer) getAudioBufferDataFromCMSampleBufferRef: (CMSampleBufferRef)audioSampleBuffer{

     AudioBufferList audioBufferList;  

     OSStatus err =      CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(audioSampleBuffer, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &_blockBuffer);
     AudioBuffer audioBuffer ;

     if (!err && _blockBuffer && audioBufferList.mBuffers[0].mData && (audioBufferList.mBuffers[0].mDataByteSize > 0))
     {
         for( int y=0; y<audioBufferList.mNumberBuffers; y++ )
         {
             audioBuffer = audioBufferList.mBuffers[y];           
             break;
         }
     }

    inputBuffer.mData=audioBuffer.mData;
    inputBuffer.mDataByteSize=audioBuffer.mDataByteSize;
    inputBuffer.mNumberChannels=1;

    return audioBuffer;
}

上記のバージョンのコードでは、BAD_ACCESS エラーが発生します。代わりに、blockBuffer を解放するコードを削除すると、メモリ リークが発生し、メモリ不足のためにアプリが最終的に終了します。

blockBuffer を保持せずに次のコードを記述した場合

 getAudioBufferDataFromCMSampleBufferRef

以下に示すように異なる

- (AudioBuffer) getAudioBufferDataFromCMSampleBufferRef: (CMSampleBufferRef)audioSampleBuffer
{
    _blockBuffer = CMSampleBufferGetDataBuffer(audioSampleBuffer);
    int audioBufferByteSize =    CMSampleBufferGetTotalSampleSize(audioSampleBuffer);                   

CMBlockBufferCopyDataBytes(_blockBuffer,0,audioBufferByteSize,inputBuffer.mData);
    inputBuffer.mDataByteSize=audioBuffer.mDataByteSize;
    inputBuffer.mNumberChannels=1;
}

このバージョンでは、ブロックバッファは保持されないため、解放する必要はありません。しかし、オーディオにひどいノイズが入ります。

この問題を解決する方法を知っている人はいますか?

ありがとう、オズグル

4

1 に答える 1

1

これが一般的に行われる 1 つの方法は、すべてのオーディオ サンプル データを保持されていないバッファーから独自の (事前に割り当てられ、保持され、ロックされていない) 循環 fifo バッファーにコピーすることです。次に、保持されていないバッファは無視します。これは、ある時点で解放されるためです。独自の循環バッファーでオーディオ データを使用します。

于 2015-07-16T03:17:22.217 に答える