2011-07-22 4 views
4

У кого-нибудь был успех в преобразовании 32KHz PCM в 96Kbit AAC на iPhone/iOS?iPhone: проблемы с кодировкой 32KHz PCM до 96 Кбит AAC с использованием AudioConverterFillComplexBuffer

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

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

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

Вот код для настройки аудио конвертера для кодирования MPEG4-AAC 96kbits @ 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 выборок ИКХ, и ожидает 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; 
} 

proceedure входных данных просто обеспечивает 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 или?)?

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

+1

я мог получить оборудование вести себя так же, как на тренажере, заставляя SOFTWARE с использованием кодека AudioConverterNewSpecific и указав mManufacturer kAppleSoftwareAudioCodecManufacturer. Было бы здорово узнать, как использовать аппаратный кодек! – welch1820

ответ

0

Я нахожу, что: outputBitRate по умолчанию для 32KHz-input-PCM составляет 48000 бит, по умолчанию outputBitRate для 44.1KHz-input-PCM составляет 64000 бит. При использовании выходного сигнала OutputBitRate по умолчанию вход 32 КГц создает огромный шум. Даже используйте these codes from apple`s sample, 44.1KHz вход немного шума.

Тогда я исправить outputBitRate к 64kbs, 32 кГц & 44.1 КГц и работает хорошо.

UInt32 outputBitRate = 64000; // 64kbs 
UInt32 propSize = sizeof(outputBitRate); 
if (AudioConverterSetProperty(m_converter, kAudioConverterEncodeBitRate, propSize, &outputBitRate) != noErr) { 
} else { 
    NSLog(@"upyun.com uplivesdk UPAACEncoder error 102"); 
} 
+0

rotoava, не могли бы вы прокомментировать мой вопрос. Я вижу, у вас есть опыт в этом. http://stackoverflow.com/questions/41638475/how-to-set-bitrate-correctly-for-aac-encoding-osx – mbaros