4

iPhone/iOS で 32KHz PCM を 96Kbit AAC に変換できた人はいますか?

これをどのハードウェア デバイスでも正しく動作させることはできません。私が書いたコードは、シミュレーターでのみ正しく動作します。現在の世代の iPad/iPod/iPhone で実行すると、私のコードはオーディオの大部分を「スキップ」します。

結果のエンコードされたストリームには、約 640 ミリ秒の「良好な」オーディオとそれに続く約 640 ミリ秒の「不良」オーディオの繰り返しパターンが含まれます。

16 ビット リニア PCM と 8.24 固定小数点 PCM の両方をエンコードしても、同じ結果が得られました。

MPEG4-AAC 96kbits @ 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);

シンプルな変換ルーチン。このルーチンは、1024 個の PCM サンプルのブロックで 32 ミリ秒ごとに呼び出され、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 の呼び出しを引き起こし、すべて問題ないように見えます。その後、AudioConverterFillComplexBuffer への次の ~ 21 回の呼び出しでは、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

InputDataProc を呼び出していないため、コンバーターはどこで入力データを取得して「悪い」AAC を作成していますか?

このアプローチで明らかに間違っていることを誰かが見ていますか?

ハードウェア コーデック (MagicCookies または ?) で行う必要がある特別な設定はありますか?

HW AAC コーデックは 32000 サンプル レートをサポートしていますか?

4

1 に答える 1

0

I find that: the default outputBitRate for 32KHz-input-PCM is 48000 bit, the default outputBitRate for 44.1KHz-input-PCM is 64000 bit. When use the the default outputBitRate, 32KHz input makes huge noise. Even use these codes from apple`s sample , 44.1KHz input have a little noise.

Then i fix the outputBitRate to 64kbs, 32KHz & 44.1KHz both works well。</p>

UInt32 outputBitRate = 64000; // 64kbs
UInt32 propSize = sizeof(outputBitRate);
if (AudioConverterSetProperty(m_converter, kAudioConverterEncodeBitRate, propSize, &outputBitRate) != noErr) {
} else {
    NSLog(@"upyun.com uplivesdk  UPAACEncoder error 102");
}
于 2016-08-22T10:14:43.053 に答える