Можно ли использовать AVCaptureSession для кодирования потока AAC в память?

Я пишу приложение для iOS, которое транслирует видео и аудио по сети.

Я использую AVCaptureSessionдля захвата необработанных видеокадров с помощью AVCaptureVideoDataOutputи кодирую их в программном обеспечении с использованием x264. Это прекрасно работает.

Я хотел сделать то же самое для аудио, только мне не нужно было так много контроля над аудио, поэтому я хотел использовать встроенный аппаратный кодировщик для создания потока AAC. Это означало использование Audio Converterиз слоя Audio Toolbox. Для этого я добавил обработчик аудиокадров 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 только на стороне видео и использовало аудиоочередина стороне аудио. Это усложнит управление потоком (запуск и остановка записи, реагирование на прерывания) и, боюсь, может вызвать проблемы с синхронизацией аудио и видео. Кроме того, это просто не похоже на хороший дизайн.

Кто-нибудь знает, возможно ли получить AAC из AVCaptureSession? Должен ли я использовать здесь аудиоочереди? Может ли это привести к проблемам с синхронизацией или управлением?

7
задан Cœur 25 March 2019 в 18:22
поделиться