iPhone:使用AudioConverterFillComplexBuffer将32KHz PCM编码为96Kbit AAC存在问题

4

有没有人在iPhone/iOS上成功将32KHz的PCM转换为96Kbit的AAC?

我无法让这项工作在任何硬件设备上正确运行。我编写的代码只能在模拟器中正常工作。当在当前一代iPad/iPod/iPhone上运行时,我的代码会“跳过”大量音频。

生成的编码流包含一个重复的模式,即约640毫秒的“好”音频后跟约640毫秒的“坏”音频。

对16位线性和8.24固定点PCM进行编码产生了相同的结果。

以下是设置音频转换器以将MPEG4-AAC 96 kbits @ 32KHz编码的代码:

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或其他)吗?

硬件AAC编解码器是否支持32000采样率?


1
我可以通过使用AudioConverterNewSpecific并指定mManufacturer kAppleSoftwareAudioCodecManufacturer来强制使用软件编解码器,从而使硬件的行为与模拟器相同。不过,找出如何使用硬件编解码器仍然是很好的。 - welch1820
1个回答

0
我发现:32KHz输入PCM的默认输出比特率为48000位,44.1KHz输入PCM的默认输出比特率为64000位。 当使用默认输出比特率时,32KHz输入会产生巨大的噪音。 即使使用苹果示例中的这些代码,44.1KHz输入也会有一点噪音。
然后我将输出比特率修正为64kbs,32KHz和44.1KHz都能正常工作。
UInt32 outputBitRate = 64000; // 64kbs
UInt32 propSize = sizeof(outputBitRate);
if (AudioConverterSetProperty(m_converter, kAudioConverterEncodeBitRate, propSize, &outputBitRate) != noErr) {
} else {
    NSLog(@"upyun.com uplivesdk  UPAACEncoder error 102");
}

rotoava,你能否请评论一下我的问题。我看到你在这方面有经验。 http://stackoverflow.com/questions/41638475/how-to-set-bitrate-correctly-for-aac-encoding-osx - mbaros

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接