2012-05-30 4 views
7

내가 네트워크를 통해 비디오와 오디오를 스트리밍 아이폰 OS 응용 프로그램을 쓰고 있어요.AVCaptureSession을 사용하여 AAC 스트림을 메모리로 인코딩 할 수 있습니까?

나는 AVCaptureVideoDataOutput를 사용하여 원시 비디오 프레임을 잡아 소프트웨어 using x264에서 그들을 인코딩하는 AVCaptureSession을 사용하고 있습니다. 이것은 잘 작동합니다.

가 나는 오디오 측면에서 많은 제어 그래서 내가 AAC 스트림을 생성하는 하드웨어 인코더 내장 사용하고 싶다고 필요가없는 것만 오디오, 같은 일을하고 싶었다. 즉, Audio Toolbox 레이어의 Audio Converter을 사용했습니다. 오디오 컨버터 콜백 함수는 아주 간단합니다이 경우

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

(패킷 크기를 가정하고 계산이 제대로 설치됩니다) :이를 위해 나는 AVCaptudeAudioDataOutput의 오디오 프레임에 대한 처리기에 넣어 :

- (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'(하드웨어 사용) 오류를 반환합니다. 세션이 정지하지만 내가 AVCaptureSession를 벗어난 AAC 스트림을 얻을 수있는 방법이 있다면 궁금 해서요

... 아무것도 캡처 할 수 없습니다 경우 변환 잘 작동합니다. 내가 고려하고있는 옵션은 다음과 같습니다

  1. 은 어떻게 든 AAC로 오디오 샘플을 인코딩하고 (뿐만 아니라 파일에 쓸 것이다, AVAssetWriter을 통해) 어떻게 든 인코딩 된 패킷을 얻을 수 AVAssetWriterInput를 사용하여.

  2. 비디오 측면에서만 AVCaptureSession을 사용하고 오디오 측면에서는 Audio Queues을 사용하도록 내 응용 프로그램을 재구성하십시오. 이렇게하면 흐름 제어 (녹음 시작 및 중단, 중단에 응답)가 더 복잡해지며 오디오 및 비디오간에 동기화 문제가 발생할 수 있습니다. 또한, 그것은 단지 좋은 디자인처럼 보이지 않습니다.

AVCaptureSession에서 AAC를 가져 오는 것이 가능하면 누구에게 알 수 있습니까? 여기에서 오디오 대기열을 사용해야합니까? 이게 나를 동기화 또는 제어 문제로 만들 수 있습니까?

+0

AudioConverter는 전혀 작동합니까? 캡처를 끄고 일부 0 인코딩을 시도 했습니까? –

+0

네, 제가 한 것입니다 (나는이 문제에 대해서도 언급했다). AVCaptureSession이 '실행 중'상태가 아니면 인코더가 정상적으로 작동합니다. – Avner

+0

죄송합니다. 당신이 묶인 것처럼 보입니다. 캡처 세션에 오디오 입력을 추가하면 AAC 인코더를 묶는 것처럼 보입니다. –

답변

5

내가 조언을 애플을 묻는 종료 (당신이 할 수있는 밝혀 당신은 유료 개발자 계정이있는 경우).

이 AVCaptureSession은 AAC 하드웨어 인코더의 보류를 잡고 것으로 보인다하지만 당신이 파일을 직접 작성하는 데 사용할 수 있습니다.

당신은 소프트웨어 인코더를 사용할 수 있지만 당신이 그것을 구체적으로 대신 사용하는 AudioConverterNew 물어 봐야 : 물론, CPU 자원을 차지합니다

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

소프트웨어 인코더

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

, 그러나 일을 끝낼 것이다.

+0

변환을 위해 동봉 된 코드를 게시 하시겠습니까? 주로 콜백 함수 구현과 _aacBuffer 및 _pcmBuffer 정의. 고마워. –

+0

동일한 Mac의 동일한 기능을 찾고 있지만 mManufacturer는 Mac에서 찾을 수 없습니다. 어떤 아이디어? – Dinesh

+0

아이폰에서만 AudioConverterFillComplexBuffer에 오류가 발생했습니다. 아이 패드에는 없다. –