iPhone: проблемы кодирования 32 кГц PCM в 96 кбит AAC с использованием AudioConverterFillComplexBuffer - PullRequest
4 голосов
/ 22 июля 2011

Кто-нибудь имел успех преобразовать 32 кГц PCM в 96 Кбит AAC на iPhone / iOS?

Я не могу заставить это работать правильно на любом аппаратном устройстве. Код, который я написал, корректно работает только в симуляторе. При запуске на iPad / iPod / iPhone текущего поколения мой код пропускает большие фрагменты аудио.

Результирующий кодированный поток содержит повторяющуюся последовательность ~ 640 мсек «хорошего» звука, а затем ~ 640 мс «плохого» звука.

Кодирование как 16-битного линейного, так и 8,24 PCM с фиксированной точкой дало одинаковые результаты.

Вот код для настройки Audio Converter для кодирования MPEG4-AAC 96 кбит при 32 кГц:

AudioStreamBasicDescription descPCMFormat;
descPCMFormat.mSampleRate       = 32000;
descPCMFormat.mChannelsPerFrame = 1;
descPCMFormat.mBitsPerChannel   = sizeof(AudioUnitSampleType) * 8;
descPCMFormat.mBytesPerPacket   = sizeof(AudioUnitSampleType);
descPCMFormat.mFramesPerPacket  = 1;
descPCMFormat.mBytesPerFrame    = sizeof(AudioUnitSampleType);
descPCMFormat.mFormatID         = kAudioFormatLinearPCM;
descPCMFormat.mFormatFlags      = kAudioFormatFlagsAudioUnitCanonical;

AudioStreamBasicDescription descAACFormat;
descAACFormat.mSampleRate       = 32000;
descAACFormat.mChannelsPerFrame = 1;
descAACFormat.mBitsPerChannel   = 0;
descAACFormat.mBytesPerPacket   = 0;
descAACFormat.mFramesPerPacket  = 1024;
descAACFormat.mBytesPerFrame    = 0;
descAACFormat.mFormatID         = kAudioFormatMPEG4AAC;
descAACFormat.mFormatFlags      = 0;

AudioConverterNew(& descPCMFormat, & descAACFormat, &m_hCodec);

UInt32 ulBitRate = 96000;
UInt32 ulSize = sizeof(ulBitRate);
AudioConverterSetProperty(m_hCodec, kAudioConverterEncodeBitRate, ulSize, & ulBitRate);

Простая процедура преобразования. Эта процедура вызывается каждые 32 мсек с блоком из 1024 отсчетов PCM и ожидает 384 байта кодированного AAC:

OSStatus CMyObj::Convert(
    const AudioUnitSampleType * pSrc,
    const size_t        ulSrc,
    uint8_t           * pDst,
    size_t            & ulDst)
{
    // error and sanity checking removed.. 
    // assume caller is converting 1024 samples to at most 384 bytes

    OSStatus osStatus;

    m_pSrcPtr  = (uint8_t*)pSrc;
    m_ulSrcLen = ulSrc;    // verified to be 1024*sizeof(AudioUnitSampleType);    

    AudioBufferList destBuffers;
    destBuffers.mNumberBuffers              = 1;
    destBuffers.mBuffers[0].mNumberChannels = 1;
    destBuffers.mBuffers[0].mDataByteSize   = 384;
    destBuffers.mBuffers[0].mData           = pDst;

    AudioStreamPacketDescription destDescription;
    destDescription.mStartOffset            = 0;
    destDescription.mVariableFramesInPacket = 0;
    destDescription.mDataByteSize           = 384;

    UInt32 ulDstPackets                     = 1;

    osStatus = AudioConverterFillComplexBuffer(
                   m_hCodec,
                   InputDataProc, 
                   this, 
                   & ulDstPackets,
                   & destBuffers,
                   & destDescription);

    ulDst = destBuffers.mBuffers[0].mDataByteSize;

    return osStatus;
}

Процедура ввода данных просто предоставляет кодировщику 1024 выборки:

static OSStatus CMyObj::InputDataProc(
    AudioConverterRef               hCodec, 
    UInt32                         *pulSrcPackets, 
    AudioBufferList                *pSrcBuffers, 
    AudioStreamPacketDescription  **ppPacketDescription,
    void                           *pUserData)
{
    // error and sanity checking removed
    CMyObj *pThis = (CMyObj*)pUserData;

    const UInt32 ulMaxSrcPackets = pThis->m_ulSrcLen / sizeof(AudioUnitSampleType);

    const UInt32 ulRetSrcPackets = min(ulMaxSrcPackets, *pulSrcPackets);
    if( ulRetSrcPackets )
    {
        UInt32 ulRetSrcBytes = ulRetSrcPackets * sizeof(AudioUnitSampleType);

        *pulSrcPackets = ulRetSrcPackets;

        pSrcBuffers->mBuffers[0].mData           = pThis->m_pSrcPtr;
        pSrcBuffers->mBuffers[0].mDataByteSize   = ulRetSrcBytes;
        pSrcBuffers->mBuffers[0].mNumberChannels = 1;

        pThis->m_pSrcPtr   += ulRetSrcBytes;
        pThis-> m_ulSrcLen -= ulRetSrcBytes;

        return noErr;
    }

    *pulSrcPackets = 0;

    pSrcBuffers->mBuffers[0].mData           = NULL;
    pSrcBuffers->mBuffers[0].mDataByteSize   = 0;
    pSrcBuffers->mBuffers[0].mNumberChannels = 1;
    return 500; // local error code to signal end-of-packet
}

Все отлично работает при запуске на симуляторе.

Однако при запуске на устройстве InputDataProc не вызывается последовательно. До 20 раз подряд вызовы AudioConverterFillComplexBuffer провоцируют вызовы InputDataProc, и все выглядит хорошо. Затем для следующих ~ 21 вызовов AudioConverterFillComplexBuffer не будет вызываться InputDataProc. Этот шаблон повторяется навсегда:

-> Convert 
  -> AudioConverterFillComplexBuffer
     -> InputDataProc
       -> results in 384 bytes of 'good' AAC
-> Convert 
  -> AudioConverterFillComplexBuffer
     -> InputDataProc
       -> results in 384 bytes of 'good' AAC
.. repeats up to 18 more times

-> Convert 
  -> AudioConverterFillComplexBuffer
    -> results in 384 bytes of 'bad' AAC
-> Convert 
  -> AudioConverterFillComplexBuffer
    -> results in 384 bytes of 'bad' AAC
.. repeats up to 18 more times

Где преобразователь получает входные данные для создания «плохого» AAC, поскольку он не вызывает InputDataProc?

Кто-нибудь видит что-то явно не так с этим подходом?

Существуют ли какие-либо специальные настройки, которые необходимо выполнить для аппаратного кодека (MagicCookies или?)?

Поддерживает ли кодек HW AAC частоту дискретизации 32000?

1 Ответ

0 голосов
/ 22 августа 2016

Я считаю, что: значение outputBitRate по умолчанию для 32-кГц-входной PCM составляет 48000 бит, значение outputBitRate по умолчанию для 44,1 кГц-входной-PCM составляет 64000 бит.При использовании значения по умолчанию outputBitRate, входной сигнал 32 кГц создает огромный шум.Даже используйте , эти коды из образца Apple * , 44,1 кГц имеют небольшой шум1006 *

...