/* ------------------------------------------------------------------
 * Copyright (C) 1998-2010 PacketVideo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 * -------------------------------------------------------------------
 */
// -*- c++ -*-
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

//                 A A C   F I L E   P A R S E R

// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

/**
 *  @file aacfileparser.cpp
 *  @brief This file contains the implementation of the raw AAC file parser.
 */

//----------------------------------------------------------------------------
// INCLUDES
//----------------------------------------------------------------------------
#include "aacfileparser.h"
#include "pv_audio_type_defs.h"
#include "getactualaacconfig.h"
#include "media_clock_converter.h"
#include "pvmp4audiodecoder_api.h"

// Use default DLL entry point for Symbian
#include "oscl_dll.h"
OSCL_DLL_ENTRY_POINT_DEFAULT()

//! specially used in ResetPlayback(), re-poition the file pointer
int32 AACBitstreamObject::reset(int32 filePos)
{
    PVMF_AACPARSER_LOGDEBUG((0, "RESET::IN iBytesRead [%d] iBytesProcessed [%d] iFilePtr [%d] iActualSize [%d] iPos[%d]", iBytesRead, iBytesProcessed, ipAACFile->Tell(), iActual_size, iPos));
    iBytesRead  = filePos; // set the initial value
    iBytesProcessed = filePos;
    if (ipAACFile)
    {
        AACUtils::SeektoOffset(ipAACFile, filePos, Oscl_File::SEEKSET);
    }
    iPos = AACBitstreamObject::MAIN_BUFF_SIZE;
    iActual_size = 0;
    PVMF_AACPARSER_LOGDEBUG((0, "RESET::OUT iBytesRead [%d] = iBytesProcessed [%d] iFilePtr [%d] iActualSize [%d] iPos[%d]", iBytesRead, iBytesProcessed, ipAACFile->Tell(), iActual_size, iPos));
    return refill();
}

//! read data from bitstream, this is the only function to read data from file
int32 AACBitstreamObject::refill()
{

    PVMF_AACPARSER_LOGDEBUG((0, "REFILL::IN iBytesRead [%d] iBytesProcessed [%d] iFilePtr [%d] iActualSize [%d] iPos[%d] iFileSize [%d]", iBytesRead, iBytesProcessed, ipAACFile->Tell(), iActual_size, iPos, iFileSize));

    if (iBytesRead > 0 && iFileSize > 0 && (uint32)iBytesRead >= iFileSize)
    {
        // if number of bytes read so far exceed the file size,
        // then first update the file size (PDL case).
        if (!UpdateFileSize()) return AACBitstreamObject::MISC_ERROR;
        PVMF_AACPARSER_LOGDEBUG((0, "REFILL::updated file size [%d]", iFileSize));

        //At this point we're near the end of data.
        //Quit reading data but don't return EOF until all data is processed.
        if (iBytesProcessed < iBytesRead)
        {
            return AACBitstreamObject::EVERYTHING_OK;
        }
        else
        {
            //there is no more data to read.
            if ((uint32)iBytesRead >= iFileSize || (uint32)iBytesProcessed >= iFileSize)
                return AACBitstreamObject::INSUFFICIENT_DATA;
        }
    }

    if (!ipAACFile)
    {
        PVMF_AACPARSER_LOGERROR((0, "AACBitstreamObject::refill- Misc Error"));
        return AACBitstreamObject::MISC_ERROR;
    }

    // Get file size at the very first time
    if (iFileSize == 0)
    {
        if (ipAACFile->Seek(0, Oscl_File::SEEKEND))
        {
            return AACBitstreamObject::MISC_ERROR;
        }

        iFileSize = (uint32)ipAACFile->Tell();

        if (!(iFileSize > 0))
        {
            return AACBitstreamObject::MISC_ERROR;
        }

        if (ipAACFile->Seek(0, Oscl_File::SEEKSET))
        {
            return AACBitstreamObject::MISC_ERROR;
        }

        // first-time read, set the initial value of iPos
        iPos = AACBitstreamObject::MAIN_BUFF_SIZE;
        iBytesProcessed = 0;
    }

    int32 remain_bytes = 0;
    //check whether there is any leftover data in the buffer.
    if (iPos >= iActual_size)
    {
        remain_bytes = 0;
    }
    else
    {
        remain_bytes = iActual_size - iPos;
    }
    if (remain_bytes > 0)
    {
        // move the remaining stuff to the beginning of iBuffer
        oscl_memcpy(&iBuffer[0], &iBuffer[iPos], remain_bytes);
    }

    // read data
    if ((iActual_size = ipAACFile->Read(&iBuffer[remain_bytes], 1, iMax_size - remain_bytes)) == 0)
    {
        return AACBitstreamObject::READ_ERROR;
    }

    iBytesRead += iActual_size;
    iActual_size += remain_bytes;
    iPos = 0;
    PVMF_AACPARSER_LOGDEBUG((0, "REFILL::OUT iBytesRead [%d] iBytesProcessed [%d] iFilePtr [%d] iActualSize [%d] iPos[%d] iFileSize [%d]", iBytesRead, iBytesProcessed, ipAACFile->Tell(), iActual_size, iPos, iFileSize));

    return AACBitstreamObject::EVERYTHING_OK;
}

//! get the updated file size
bool AACBitstreamObject::UpdateFileSize()
{
    if (ipAACFile != NULL)
    {
        uint32 aRemBytes = 0;
        TOsclFileOffset remainingBytes = 0;
        if (ipAACFile->GetRemainingBytes(remainingBytes))
        {
            aRemBytes = (uint32)remainingBytes;
            uint32 currPos = (uint32)(ipAACFile->Tell());
            iFileSize = currPos + aRemBytes;
            return true;
        }
    }
    return false;
}

//! get frame size and number of data blocks for the next frame, in preparation of getNextFrame()
int32 AACBitstreamObject::getNextFrameInfo(int32& frame_size, int32& numDateBlocks)
{
    PVMF_AACPARSER_LOGDEBUG((0, "AACBitstreamObject::getNextFrameInfo In"));

    int32 ret_value = AACBitstreamObject::EVERYTHING_OK;

    // Need to refill?
    if (iFileSize == 0 || iPos + 4 >= iActual_size)
    {
        ret_value = refill();
        if (ret_value)
        {
            return ret_value;
        }
    }

    // Search the 12 bit sync-word 0xff + 0xf0
    while (!(iBuffer[iPos] == 0xff &&
             (iBuffer[iPos+1] & 0xf0) == 0xf0 &&
             iBuffer[iPos+1] == iAACHeaderBuffer[1] &&
             iBuffer[iPos+2] == iAACHeaderBuffer[2] &&
             iBuffer[iPos+3] == iAACHeaderBuffer[3]))
    {
        if (iPos + 4 >= iActual_size)
        {
            ret_value = refill();
            if (ret_value)
            {
                return ret_value;
            }
        }
        iPos++;
        iBytesProcessed++;
    }
    if (iPos + ADTS_HEADER_LENGTH + 2 >= iActual_size)
    {
        ret_value = refill();
        if (ret_value)
        {
            return ret_value;
        }
    }

    // parse the header and get frame size plus the number of data blocks
    uint8 *pBuffer = &iBuffer[iPos];
    frame_size = (int32)((pBuffer[3] & 0x03) << 11)   | // take the lowest 2 bits in the 4th byte of the header
                 (int32)(pBuffer[4] << 3)         |     // take the whole 5th byte(8 bits) of the header
                 (int32)((pBuffer[5] & 0xe0) >> 5);     // take the highest 3 bits in the 6th byte of the header

    if (ibCRC_Check)
    {
        frame_size -= (ADTS_HEADER_LENGTH + 2);
    }
    else
    {
        frame_size -= ADTS_HEADER_LENGTH;
    }

    numDateBlocks = (pBuffer[6] & 0x03) + 1; // take the lowest 2 bits in the 7th byte of the header

    // update CRC check
    ibCRC_Check = ((pBuffer[1] & 0x01) ? false : true);

    PVMF_AACPARSER_LOGDEBUG((0, "AACBitstreamObject::getNextFrameInfo Out"));
    return ret_value;
}

//! most important function to get one frame data plus frame type, used in getNextBundledAccessUnits()
int32 AACBitstreamObject::getNextFrame(uint8* frameBuffer, int32& frame_size, int32& aHdrSize, bool bHeaderIncluded)
{
    PVMF_AACPARSER_LOGDEBUG((0, "AACBitstreamObject::getNextFrame In, iFileSize=%d, iPos=%d, frame_size=%d, iBytesRead=%d, iBytesProcessed=%d, iActualSize=%d", iFileSize, iPos, frame_size, iBytesRead, iBytesProcessed, iActual_size));
    aHdrSize = 0;
    if (!frameBuffer || (frame_size <= 0 || frame_size > MAX_AAC_FRAME_SIZE))
    {
        PVMF_AACPARSER_LOGERROR((0, "AACBitstreamObject::getNextFrame- Misc Error"));
        return AACBitstreamObject::MISC_ERROR;
    }

    int32 ret_value = AACBitstreamObject::EVERYTHING_OK;

    if (iAACFormat == EAACADTS) //ADTS
    {
        // Need to refill?
        if (iFileSize == 0 || iPos + ADTS_HEADER_LENGTH + 2 + frame_size >= iActual_size)
        {
            ret_value = refill();
            if (ret_value)
            {
                return ret_value;
            }
        }

        // copy the header to the buffer if needed
        uint8 *pBuffer = &iBuffer[iPos];
        int32 header_size = (ibCRC_Check ? ADTS_HEADER_LENGTH + 2 : ADTS_HEADER_LENGTH);
        if (bHeaderIncluded)
        {
            oscl_memcpy(frameBuffer, pBuffer, header_size);
            frameBuffer += header_size;
            aHdrSize = header_size;
        }

        // copy the data to the given buffer
        oscl_memcpy(frameBuffer, &pBuffer[header_size], frame_size);
        iPos += (header_size + frame_size);
        iBytesProcessed += (header_size + frame_size);
    }

    else if (iAACFormat == EAACADIF || iAACFormat == EAACRaw) //ADIF or raw bitstream
    {
        if (iFileSize == 0 || iPos + frame_size >= iActual_size)
        {
            ret_value = refill();
            if (ret_value)
            {
                return ret_value;
            }
        }

        uint8 *pBuffer = &iBuffer[iPos];
        if (((uint32)iBytesRead >= iFileSize) || (frame_size > (iBytesRead - iBytesProcessed)))
        {
            ret_value = refill();
            if (ret_value)
            {
                return ret_value;
            }
        }

        if (frame_size > (iBytesRead - iBytesProcessed))
            frame_size = iBytesRead - iBytesProcessed;

        PVMF_AACPARSER_LOGDEBUG((0, "AACBitstreamObject::getNextFrame Before Read, iFileSize=%d, iPos=%d, frame_size=%d, iBytesRead=%d, iBytesProcessed=%d, iActual_size=%d", iFileSize, iPos, frame_size, iBytesRead, iBytesProcessed, iActual_size));
        // copy the data to the given buffer
        oscl_memcpy(frameBuffer, pBuffer, frame_size);
        iPos += frame_size;
        iBytesProcessed += frame_size;
        PVMF_AACPARSER_LOGDEBUG((0, "AACBitstreamObject::getNextFrame after read, iFileSize=%d, iPos=%d, frame_size=%d, iBytesRead=%d, iBytesProcessed=%d, iActual_size=%d", iFileSize, iPos, frame_size, iBytesRead, iBytesProcessed, iActual_size));
    }

    PVMF_AACPARSER_LOGDEBUG((0, "AACBitstreamObject::getNextFrame Out, iFileSize=%d, iPos=%d, frame_size=%d, iBytesRead=%d, iBytesProcessed=%d, iActual_size=%d", iFileSize, iPos, frame_size, iBytesRead, iBytesProcessed, iActual_size));
    return ret_value;
}

void AACBitstreamObject::parseID3Header(PVFile& aFile)
{
    if (!ipAACFile
            || !ipAACFile->IsOpen())
        return;//error

    int32 curpos = (int32)aFile.Tell();
    AACUtils::SeektoOffset(&aFile, 0, Oscl_File::SEEKSET);
    iID3Parser->ParseID3Tag(&aFile);
    AACUtils::SeektoOffset(&aFile, curpos, Oscl_File::SEEKSET);
}

int32 AACBitstreamObject::isAACFile(PVFile* aFilePtr)
{
    OSCL_UNUSED_ARG(aFilePtr);
    PVFile* fpUsed = ipAACFile;

    if (!fpUsed || !fpUsed->IsOpen())
    {
        return AACBitstreamObject::READ_ERROR;
    }

    AACUtils::SeektoOffset(fpUsed, 0, Oscl_File::SEEKSET);

    int32 tagSize = 0;
    // check for ID3v2 tag
    if (true == iID3Parser->IsID3V2Present(fpUsed, tagSize) && tagSize > 0)
    {
        // store the metadata size
        iAudioStartOffset = tagSize;
    }

    if (AACUtils::SeektoOffset(fpUsed, iAudioStartOffset, Oscl_File::SEEKSET) != AAC_SUCCESS)
    {
        return AACBitstreamObject::INSUFFICIENT_DATA;
    }

    uint32 remainingBytes = 0;
    iAACFormat = EAACUnrecognized;
    int32 retVal = GENERIC_ERROR;
    TOsclFileOffset remBytes = 0;

    // File pointer should be at the audio data
    // ADTS - Takes 8192 bytes to confirm its a AAC Files (max AAC frame size)
    // ADIF - 4 bytes to confirm ADIF files
    if (fpUsed->GetRemainingBytes(remBytes))
    {
        remainingBytes = (uint32)remBytes;
        int32 reset_ret = reset(iAudioStartOffset);
        if (reset_ret != AACBitstreamObject::EVERYTHING_OK)
        {
            return reset_ret;
        }
        uint8 *pBuffer = &iBuffer[iPos];

        //check for ADIF first since we only need 4 bytes to know for sure
        if (remainingBytes >= AAC_ADIF_IDENTIFIER_LEN)
        {
            if (oscl_memcmp(AAC_ADIF_IDENTIFIER, pBuffer, AAC_ADIF_IDENTIFIER_LEN) == 0)
            {
                // definitely ADIF
                iAACFormat = EAACADIF;
                return AACBitstreamObject::EVERYTHING_OK;
            }
        }
        else
        {
            //we do not even have 4 bytes in the file - so no point checking for ADTS
            return AACBitstreamObject::INSUFFICIENT_DATA;
        }
        // Not ADIF - So check for ADTS
        // check for possible ADTS sync word
        int32 index = find_adts_syncword(pBuffer);

        if (index != -1)
        {
            // definitely ADTS
            iAACFormat = EAACADTS;
            return AACBitstreamObject::EVERYTHING_OK;
        }

        else
        {
            // no ADTS match was found, maybe more data is needed. We can give up here
            // or feed more data.
            return AACBitstreamObject::INSUFFICIENT_DATA;
        }
    }
    return retVal;
}


//! Search for adts synchronization word

int32 AACBitstreamObject::find_adts_syncword(uint8 *pBuffer)
{
    bool syncwordFound = false;
    uint32 i;
    uint32 bufLength;
    uint32 frameLen;

    iAvgFrameSize = 0;

    bufLength = OSCL_MIN(MAX_ADTS_PACKET_LENGTH, iActual_size);

    // Sync word is always byte aligned, sync word == 0xFFF
    for (i = 0; i < bufLength - 1; i++)
    {
        if (isValidSyncWord(&pBuffer[i]))
        {
            syncwordFound = true;
            break;
        }
    }

    if (true == syncwordFound)
    {
        uint32 index = i;
        uint32 nextIndex = i;
        // extract the aac frame length where the next sync word should be
        if ((index + 5) < bufLength)
        {
            uint8* buf = &pBuffer[index+3];
            frameLen = GetADTSFrameLength(buf);

            nextIndex += frameLen;
            iAvgFrameSize = frameLen;

            if ((frameLen > ADTS_HEADER_LENGTH && // frameLen is valid
                    frameLen < bufLength - index) && // data is available for next frame search
                    isValidSyncWord(&pBuffer[nextIndex])) // validate syncword
            {
                iAvgFrameSize += frameLen;

                buf = &pBuffer[nextIndex + 3];

                frameLen = GetADTSFrameLength(buf);
                nextIndex += frameLen;

                if ((frameLen > ADTS_HEADER_LENGTH && // frameLen is valid
                        frameLen < bufLength - index) && // data is available for next frame search
                        isValidSyncWord(&pBuffer[nextIndex])) // validate syncword
                {
                    iAvgFrameSize += frameLen;
                    iAvgFrameSize /= 3;
                    iAudioStartOffset = index;
                    return index;
                }

                iPosSyncAdtsFound = index - 1; // allow overlapping on extended search
                return (-1);  // false adts synchronization, it is adif or raw
            }
            else
            {
                iPosSyncAdtsFound = index - 1; // allow overlapping on extended search
                return (-1);    // it was a false adts synchronization, it could be adif or raw
            }
        }
        else
        {
            iPosSyncAdtsFound = index - 1; // allow overlapping on extended search
            return (-1);    // not enough data to validate synchronization
        }
    }
    else
    {
        iPosSyncAdtsFound = i - 1; // allow overlapping on extended search
        return (-1);    // no adts synchronization, it could be adif or raw
    }
    return (-1);
}

//! get clip information: file size, format(ADTS or ADIF) and sampling rate index
int32 AACBitstreamObject::getFileInfo(int32& fileSize, TAACFormat& format, uint8& sampleFreqIndex, uint32& bitRate, uint32& HeaderLen, OSCL_wString&/*aClip*/)
{
    uint32 id;
    uint32 bitstreamType;
    uint32 numProgConfigElem;
    int32 i;
    uint32 ADIFHeaderLen;
    uint32 numFrontChanElem;
    uint32 numSideChanElem;
    uint32 numBackChanElem;
    uint32 numLfeChanElem;
    uint32 numAssocDataElem;
    uint32 numValidCCElem;
    uint32 commentFieldBytes;
    uint32 offset;
    uint32 bitIndex;
    uint8 tmp;

    bitRate = 0;
    HeaderLen = 0;
    iChannelConfig = 0;

    //we do not attempt to recognize the file as ADIF or ADTS, if the caller specified the clip is raw aac
    if (format != EAACRaw)
    {
        format = EAACUnrecognized;
    }
    fileSize = sampleFreqIndex = 0;
    int32 ret_value = AACBitstreamObject::EVERYTHING_OK;

    // Get file size at the very first time
    if (iFileSize == 0)
    {
        AACUtils::getCurrentFileSize(ipAACFile, iFileSize);
        if (iFileSize <= 0)
        {
            PVMF_AACPARSER_LOGERROR((0, "AACBitstreamObject::refill- Misc Error"));
            return AACBitstreamObject::INSUFFICIENT_DATA;
        }
        // first-time read, set the initial value of iPos
        iPos = AACBitstreamObject::MAIN_BUFF_SIZE;

        if (ret_value == AACBitstreamObject::EVERYTHING_OK)
        {
            //retrieve the ID3 meta-data from the file
            parseID3Header(*ipAACFile);

            iMetadataSize = iID3Parser->GetByteOffsetToStartOfAudioFrames();
            if (iMetadataSize > 0)
            {
                //skip past the ID3 header.
                ret_value = reset(iMetadataSize);
                if (ret_value != AACBitstreamObject::EVERYTHING_OK)
                {
                    return ret_value;
                }
            }
            else
            {
                ret_value = reset(0);
            }

            fileSize = iFileSize;

            uint8 *pBuffer = &iBuffer[iPos];

            if (format == EAACRaw)
            {
                // Treat it as Raw AAC format, since caller specified it as such
                int32 config_header_size = iActual_size;
                uint32 samplesPerFrame;

                int32 status = GetActualAacConfig(pBuffer,
                                                  &iAudioObjectType, &config_header_size, &sampleFreqIndex, &iChannelConfig, &samplesPerFrame);
                if (status != SUCCESS) return AACBitstreamObject::MISC_ERROR;

                // Retrieve the audio object type
                if (iAudioObjectType != 2 &&
                        iAudioObjectType != 4 &&
                        iAudioObjectType != 5 &&
                        iAudioObjectType != 29)
                {
                    // Unsupported object type
                    PVMF_AACPARSER_LOGERROR((0, "AACBitstreamObject::getFileInfo- Misc Error"));
                    return AACBitstreamObject::MISC_ERROR;
                }

                iSampleFreqIndex = sampleFreqIndex;
                oscl_memcpy(iAACHeaderBuffer, pBuffer, config_header_size);
                iRawAACHeaderLen = (uint32)config_header_size;
                HeaderLen = (uint32)config_header_size << 3;

                iAACFormat = format = EAACRaw;
            }
            else if (iFileSize >= 4     &&
                     pBuffer[0] == 0x41 &&  // 'A'
                     pBuffer[1] == 0x44 &&  // 'D'
                     pBuffer[2] == 0x49 &&  // 'I'
                     pBuffer[3] == 0x46)    // 'F'
            {
                // ADIF format
                iAACFormat = format = EAACADIF;

                ADIFHeaderLen = 32; // adif_id 4 bytes

                // check copyright_id_present (1 bit)
                id = pBuffer[4] & 0x80;

                if (id != 0)    //copyright ID is presented
                {
                    ADIFHeaderLen += 75;    // copyright_id_present 1 bit
                    // copyright_id 72 bits,
                    // original_copy 1 bit,
                    // home 1 bit,

                    // check bitstream type
                    bitstreamType = pBuffer[13] & 0x10;

                    // get number of program config. element
                    numProgConfigElem = (pBuffer[16] & 0x1E) >> 1;

                    // get bitrate (max for variable rate bitstream)
                    iBitrate = bitRate = ((pBuffer[13] & 0xF0) << 15) |
                                         (pBuffer[14] << 11) |
                                         (pBuffer[15] << 3)  |
                                         ((pBuffer[16] & 0xE0) >> 5);

                    if (iBitrate == 0)   //bitrate is not known
                    {
                        PVMF_AACPARSER_LOGERROR((0, "AACBitstreamObject::getFileInfo- Misc Error"));
                        return AACBitstreamObject::MISC_ERROR;
                    }

                    ADIFHeaderLen += 28;    // bitstream_type 1 bit,
                    // bitrate 23 bits
                    // num_program_config_elements 4 bits

                    for (i = 0; i < (int32)numProgConfigElem + 1; i++)
                    {
                        if (bitstreamType == 0) //bistream type is constant rate bitstream
                        {
                            ADIFHeaderLen += 20;    //adif_buffer_fullness 20 bits

                            // get audio object type
                            iAudioObjectType = (uint8)(((pBuffer[19] & 0x1) << 1) | ((pBuffer[20] & 0x80) >> 7));

                            // get sampling rate index
                            iSampleFreqIndex = sampleFreqIndex = (uint8)((pBuffer[20] & 0x78) >> 3);

                            // get number of front channel elements
                            numFrontChanElem = (uint32)(((pBuffer[20] & 0x7) << 1) | ((pBuffer[21] & 0x80) >> 7));

                            // get number of side channel elements
                            numSideChanElem = (uint32)((pBuffer[21] & 0x78) >> 3);

                            // get number of back channel elements
                            numBackChanElem = (uint32)(((pBuffer[21] & 0x7) << 1) | ((pBuffer[22] & 0x80) >> 7));

                            // get number of LFE channel elements
                            numLfeChanElem = (uint32)((pBuffer[22] & 0x60) >> 5);

                            // get number of assoc data elements
                            numAssocDataElem = (uint32)((pBuffer[22] & 0x1C) >> 2);

                            // get number of valid CC elements
                            numValidCCElem = (uint32)(((pBuffer[22] & 0x3) << 2) | ((pBuffer[23] & 0xC0) >> 6));

                            ADIFHeaderLen += 31;    //element_instance_tag 4 bits,
                            //object_type 2 bits,
                            //sampling_frequency_index 4 bits,
                            //num_front_channel_elements 4 bits,
                            //num_side_channel_elements 4 bits,
                            //num_back_channel_elements 4 bits,
                            //num_lfe_channel_elements 2 bits,
                            //num_assoc_data_elements 3 bits,
                            //num_valid_cc_elements 4 bits

                            // check mono_mixdown_present
                            if ((pBuffer[23] & 0x20) != 0)  //mono mixdown is presented
                            {
                                ADIFHeaderLen += 5; //mono_mixdown_present 1 bit
                                //mono_mixdown_element_number 4 bits

                                //check stereo_mixdown_present
                                if ((pBuffer[23] & 0x1) != 0)   //stereo mixdown is presented
                                {
                                    ADIFHeaderLen += 5; //stereo_mixdown_present 1 bit
                                    //stereo_mixdown_element_number 4 bits

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[24] & 0x8) != 0)   //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }
                                else    //stereo mixdown is not presented
                                {
                                    ADIFHeaderLen += 1; //stereo_mixdown_present 1 bit

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[24] & 0x80) != 0)  //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }//if ((pBuffer[23] & 0x1) != 0)
                            }
                            else    //mono mixdown is not presented
                            {
                                ADIFHeaderLen += 1; //mono_mixdown_present 1 bit

                                //check stereo_mixdown_present
                                if ((pBuffer[23] & 0x10) != 0)  //stereo mixdown is presented
                                {
                                    ADIFHeaderLen += 5; //stereo_mixdown_present 1 bit
                                    //stereo_mixdown_element_number 4 bits

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[24] & 0x80) != 0)  //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }
                                else    //stereo mixdown is not presented
                                {
                                    ADIFHeaderLen += 1; //stereo_mixdown_present 1 bit

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[23] & 0x8) != 0)   //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }//if ((pBuffer[23] & 0x10) != 0)

                            }//if ((pBuffer[23] & 0x20) != 0)

                        }
                        else    //bistream type is variable rate bitstream
                        {
                            // get audio object type
                            iAudioObjectType = (uint8)((pBuffer[17] & 0x18) >> 3);

                            // get sampling rate index
                            iSampleFreqIndex = sampleFreqIndex = (uint8)(((pBuffer[17] & 0x7) << 1) | ((pBuffer[18] & 0x80) >> 7));

                            // get number of front channel elements
                            numFrontChanElem = (uint32)((pBuffer[18] & 0x78) >> 3);

                            // get number of side channel elements
                            numSideChanElem = (uint32)(((pBuffer[18] & 0x7) << 1) | ((pBuffer[19] & 0x80) >> 7));

                            // get number of back channel elements
                            numBackChanElem = (uint32)((pBuffer[19] & 0x78) >> 3);

                            // get number of LFE channel elements
                            numLfeChanElem = (uint32)((pBuffer[19] & 0x6) >> 1);

                            // get number of assoc data elements
                            numAssocDataElem = (uint32)(((pBuffer[19] & 0x1) << 2) | ((pBuffer[20] & 0xC0) >> 6));

                            // get number of valid CC elements
                            numValidCCElem = (uint32)((pBuffer[20] & 0x3C) >> 2);

                            ADIFHeaderLen += 31;    //element_instance_tag 4 bits,
                            //object_type 2 bits,
                            //sampling_frequency_index 4 bits,
                            //num_front_channel_elements 4 bits,
                            //num_side_channel_elements 4 bits,
                            //num_back_channel_elements 4 bits,
                            //num_lfe_channel_elements 2 bits,
                            //num_assoc_data_elements 3 bits,
                            //num_valid_cc_elements 4 bits

                            // check mono_mixdown_present
                            if ((pBuffer[20] & 0x2) != 0)   //mono mixdown is presented
                            {
                                ADIFHeaderLen += 5; //mono_mixdown_present 1 bit
                                //mono_mixdown_element_number 4 bits

                                //check stereo_mixdown_present
                                if ((pBuffer[21] & 0x10) != 0)  //stereo mixdown is presented
                                {
                                    ADIFHeaderLen += 5; //stereo_mixdown_present 1 bit
                                    //stereo_mixdown_element_number 4 bits

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[22] & 0x80) != 0)  //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }
                                else    //stereo mixdown is not presented
                                {
                                    ADIFHeaderLen += 1; //stereo_mixdown_present 1 bit

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[21] & 0x8) != 0)   //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }//if ((pBuffer[21] & 0x10) != 0)
                            }
                            else    //mono mixdown is not presented
                            {
                                ADIFHeaderLen += 1; //mono_mixdown_present 1 bit

                                //check stereo_mixdown_present
                                if ((pBuffer[20] & 0x1) != 0)   //stereo mixdown is presented
                                {
                                    ADIFHeaderLen += 5; //stereo_mixdown_present 1 bit
                                    //stereo_mixdown_element_number 4 bits

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[21] & 0x8) != 0)   //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }
                                else    //stereo mixdown is not presented
                                {
                                    ADIFHeaderLen += 1; //stereo_mixdown_present 1 bit

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[21] & 0x80) != 0)  //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }//if ((pBuffer[20] & 0x1) != 0)

                            }//if ((pBuffer[20] & 0x2) != 0)

                        }// if (bitstreamType == 0)

                        for (i = 0; i < (int32)numFrontChanElem; i++)
                        {
                            //calculate channel configuration
                            offset = ADIFHeaderLen >> 3;
                            bitIndex = ADIFHeaderLen & 0x7;
                            tmp = (uint8)((pBuffer[offset] << bitIndex) | (pBuffer[offset+1] >> (8 - bitIndex)));
                            tmp >>= (8 - 1); //front channel element takes 1 bit
                            iChannelConfig += tmp;

                            //update ADIF variable header length
                            ADIFHeaderLen += 5; //front_element_is_cpe[i] 1 bit,
                            //front_element_tag_select[i] 4 bits
                        }

                        for (i = 0; i < (int32)numSideChanElem; i++)
                        {
                            //calculate channel configuration
                            offset = ADIFHeaderLen >> 3;
                            bitIndex = ADIFHeaderLen & 0x7;
                            tmp = (uint8)((pBuffer[offset] << bitIndex) | (pBuffer[offset+1] >> (8 - bitIndex)));
                            tmp >>= (8 - 1); //side channel element takes 1 bit
                            iChannelConfig += (tmp + 1);

                            //update ADIF variable header length
                            ADIFHeaderLen += 5; //side_element_is_cpe[i] 1 bit,
                            //side_element_tag_select[i] 4 bits
                        }

                        for (i = 0; i < (int32)numBackChanElem; i++)
                        {
                            //calculate channel configuration
                            offset = ADIFHeaderLen >> 3;
                            bitIndex = ADIFHeaderLen & 0x7;
                            tmp = (uint8)((pBuffer[offset] << bitIndex) | (pBuffer[offset+1] >> (8 - bitIndex)));
                            tmp >>= (8 - 1); //back channel element takes 1 bit
                            iChannelConfig += (tmp + 1);

                            //update ADIF variable header length
                            ADIFHeaderLen += 5; //back_element_is_cpe[i] 1 bit,
                            //back_element_tag_select[i] 4 bits
                        }

                        if (numLfeChanElem != 0)
                        {
                            iChannelConfig++;   //1 front low frequency effects speaker
                        }

                        for (i = 0; i < (int32)numLfeChanElem; i++)
                        {
                            ADIFHeaderLen += 4; //lfe_element_tag_select[i] 4 bits
                        }

                        for (i = 0; i < (int32)numAssocDataElem; i++)
                        {
                            ADIFHeaderLen += 4; //assoc_data_element_tag_select[i] 4 bits
                        }

                        for (i = 0; i < (int32)numValidCCElem; i++)
                        {
                            ADIFHeaderLen += 5; //cc_element_is_ind_sw[i] 1 bit,
                            //valid_cc_element_tag_select[i] 4 bits
                        }

                        // byte_allignment
                        ADIFHeaderLen += 7;
                        ADIFHeaderLen &= 0xF8;

                        // comment_field_bytes (8 bits)
                        offset = ADIFHeaderLen >> 3;
                        bitIndex = ADIFHeaderLen & 0x7;
                        commentFieldBytes = (pBuffer[offset] << bitIndex) | (pBuffer[offset+1] >> (8 - bitIndex));

                        ADIFHeaderLen += 8; //comment_field_bytes 8 bits

                        for (i = 0; i < (int32)commentFieldBytes; i++)
                        {
                            ADIFHeaderLen += 8; //comment_field_data 8 bits
                        }

                    }// for (i = 0; i < (int32)numProgConfigElem + 1; i++)

                }
                else    //copyright ID is not presented
                {
                    ADIFHeaderLen += 3;     // copyright_id_present 1 bit
                    // original_copy 1 bit,
                    // home 1 bit,

                    // check bitstream type
                    bitstreamType = pBuffer[4] & 0x10;

                    // get number of program config. element
                    numProgConfigElem = (pBuffer[7] & 0x1E) >> 1;

                    // get bitrate (max for variable rate bitstream)
                    iBitrate  = bitRate = ((pBuffer[4] & 0xF0) << 15) |
                                          (pBuffer[5] << 11) |
                                          (pBuffer[6] << 3)  |
                                          ((pBuffer[7] & 0xE0) >> 5);

                    if (iBitrate == 0)  //bitrate is not known
                    {
                        PVMF_AACPARSER_LOGERROR((0, "AACBitstreamObject::getFileInfo- Misc Error"));
                        return AACBitstreamObject::MISC_ERROR;
                    }

                    ADIFHeaderLen += 28;    // bitstream_type 1 bit,
                    // bitrate 23 bits
                    // num_program_config_elements 4 bits

                    for (i = 0; i < (int32)numProgConfigElem + 1; i++)
                    {
                        if (bitstreamType == 0) //bistream type is constant rate bitstream
                        {
                            ADIFHeaderLen += 20;    //adif_buffer_fullness 20 bits

                            // get audio object type
                            iAudioObjectType = (uint8)(((pBuffer[10] & 0x1) << 1) | ((pBuffer[11] & 0x80) >> 7));

                            // get sampling rate index
                            iSampleFreqIndex = sampleFreqIndex = (uint8)((pBuffer[11] & 0x78) >> 3);

                            // get number of front channel elements
                            numFrontChanElem = (uint32)(((pBuffer[11] & 0x7) << 1) | ((pBuffer[12] & 0x80) >> 7));

                            // get number of side channel elements
                            numSideChanElem = (uint32)((pBuffer[12] & 0x78) >> 3);

                            // get number of back channel elements
                            numBackChanElem = (uint32)(((pBuffer[12] & 0x7) << 1) | ((pBuffer[13] & 0x80) >> 7));

                            // get number of LFE channel elements
                            numLfeChanElem = (uint32)((pBuffer[13] & 0x60) >> 5);

                            // get number of assoc data elements
                            numAssocDataElem = (uint32)((pBuffer[13] & 0x1C) >> 2);

                            // get number of valid CC elements
                            numValidCCElem = (uint32)(((pBuffer[13] & 0x3) << 2) | ((pBuffer[14] & 0xC0) >> 6));

                            ADIFHeaderLen += 31;    //element_instance_tag 4 bits,
                            //object_type 2 bits,
                            //sampling_frequency_index 4 bits,
                            //num_front_channel_elements 4 bits,
                            //num_side_channel_elements 4 bits,
                            //num_back_channel_elements 4 bits,
                            //num_lfe_channel_elements 2 bits,
                            //num_assoc_data_elements 3 bits,
                            //num_valid_cc_elements 4 bits

                            // check mono_mixdown_present
                            if ((pBuffer[14] & 0x20) != 0)  //mono mixdown is presented
                            {
                                ADIFHeaderLen += 5; //mono_mixdown_present 1 bit
                                //mono_mixdown_element_number 4 bits

                                //check stereo_mixdown_present
                                if ((pBuffer[14] & 0x1) != 0)   //stereo mixdown is presented
                                {
                                    ADIFHeaderLen += 5; //stereo_mixdown_present 1 bit
                                    //stereo_mixdown_element_number 4 bits

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[15] & 0x8) != 0)   //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }
                                else    //stereo mixdown is not presented
                                {
                                    ADIFHeaderLen += 1; //stereo_mixdown_present 1 bit

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[15] & 0x80) != 0)  //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }//if ((pBuffer[14] & 0x1) != 0)
                            }
                            else    //mono mixdown is not presented
                            {
                                ADIFHeaderLen += 1; //mono_mixdown_present 1 bit

                                //check stereo_mixdown_present
                                if ((pBuffer[14] & 0x10) != 0)  //stereo mixdown is presented
                                {
                                    ADIFHeaderLen += 5; //stereo_mixdown_present 1 bit
                                    //stereo_mixdown_element_number 4 bits

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[15] & 0x80) != 0)  //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }
                                else    //stereo mixdown is not presented
                                {
                                    ADIFHeaderLen += 1; //stereo_mixdown_present 1 bit

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[14] & 0x8) != 0)   //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }//if ((pBuffer[14] & 0x10) != 0)

                            }//if ((pBuffer[14] & 0x20) != 0)

                        }
                        else    //bistream type is variable rate bitstream
                        {
                            // get audio object type
                            iAudioObjectType = (uint8)((pBuffer[8] & 0x18) >> 3);

                            // get sampling rate index
                            iSampleFreqIndex = sampleFreqIndex = (uint8)(((pBuffer[8] & 0x7) << 1) | ((pBuffer[9] & 0x80) >> 7));

                            // get number of front channel elements
                            numFrontChanElem = (uint32)((pBuffer[9] & 0x78) >> 3);

                            // get number of side channel elements
                            numSideChanElem = (uint32)(((pBuffer[9] & 0x7) << 1) | ((pBuffer[10] & 0x80) >> 7));

                            // get number of back channel elements
                            numBackChanElem = (uint32)((pBuffer[10] & 0x78) >> 3);

                            // get number of LFE channel elements
                            numLfeChanElem = (uint32)((pBuffer[10] & 0x6) >> 1);

                            // get number of assoc data elements
                            numAssocDataElem = (uint32)(((pBuffer[10] & 0x1) << 2) | ((pBuffer[11] & 0xC0) >> 6));

                            // get number of valid CC elements
                            numValidCCElem = (uint32)((pBuffer[11] & 0x3C) >> 2);

                            ADIFHeaderLen += 31;    //element_instance_tag 4 bits,
                            //object_type 2 bits,
                            //sampling_frequency_index 4 bits,
                            //num_front_channel_elements 4 bits,
                            //num_side_channel_elements 4 bits,
                            //num_back_channel_elements 4 bits,
                            //num_lfe_channel_elements 2 bits,
                            //num_assoc_data_elements 3 bits,
                            //num_valid_cc_elements 4 bits

                            // check mono_mixdown_present
                            if ((pBuffer[11] & 0x2) != 0)   //mono mixdown is presented
                            {
                                ADIFHeaderLen += 5; //mono_mixdown_present 1 bit
                                //mono_mixdown_element_number 4 bits

                                //check stereo_mixdown_present
                                if ((pBuffer[12] & 0x10) != 0)  //stereo mixdown is presented
                                {
                                    ADIFHeaderLen += 5; //stereo_mixdown_present 1 bit
                                    //stereo_mixdown_element_number 4 bits

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[13] & 0x80) != 0)  //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }
                                else    //stereo mixdown is not presented
                                {
                                    ADIFHeaderLen += 1; //stereo_mixdown_present 1 bit

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[12] & 0x8) != 0)   //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }//if ((pBuffer[12] & 0x10) != 0)
                            }
                            else    //mono mixdown is not presented
                            {
                                ADIFHeaderLen += 1; //mono_mixdown_present 1 bit

                                //check stereo_mixdown_present
                                if ((pBuffer[11] & 0x1) != 0)   //stereo mixdown is presented
                                {
                                    ADIFHeaderLen += 5; //stereo_mixdown_present 1 bit
                                    //stereo_mixdown_element_number 4 bits

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[12] & 0x8) != 0)   //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }
                                else    //stereo mixdown is not presented
                                {
                                    ADIFHeaderLen += 1; //stereo_mixdown_present 1 bit

                                    //check matrix_mixdown_idx_present
                                    if ((pBuffer[12] & 0x80) != 0)  //matrix mixdown is presented
                                    {
                                        ADIFHeaderLen += 4; //matrix_mixdown_idx_present 1 bit
                                        //matrix_mixdown_idx 2 bits
                                        //pseudo_surround_enable 1 bit
                                    }
                                    else    //matrix mixdown is not presented
                                    {
                                        ADIFHeaderLen += 1; //matrix_mixdown_idx_present 1 bit
                                    }
                                }//if ((pBuffer[11] & 0x1) != 0)

                            }//if ((pBuffer[11] & 0x2) != 0)

                        }// if (bitstreamType == 0)

                        for (i = 0; i < (int32)numFrontChanElem; i++)
                        {
                            //calculate channel configuration
                            offset = ADIFHeaderLen >> 3;
                            bitIndex = ADIFHeaderLen & 0x7;
                            tmp = (uint8)((pBuffer[offset] << bitIndex) | (pBuffer[offset+1] >> (8 - bitIndex)));
                            tmp >>= (8 - 1); //front channel element takes 1 bit
                            iChannelConfig += tmp;

                            //update ADIF variable header length
                            ADIFHeaderLen += 5; //front_element_is_cpe[i] 1 bit,
                            //front_element_tag_select[i] 4 bits
                        }

                        for (i = 0; i < (int32)numSideChanElem; i++)
                        {
                            //calculate channel configuration
                            offset = ADIFHeaderLen >> 3;
                            bitIndex = ADIFHeaderLen & 0x7;
                            tmp = (uint8)((pBuffer[offset] << bitIndex) | (pBuffer[offset+1] >> (8 - bitIndex)));
                            tmp >>= (8 - 1); //side channel element takes 1 bit
                            iChannelConfig += (tmp + 1);

                            //update ADIF variable header length
                            ADIFHeaderLen += 5; //side_element_is_cpe[i] 1 bit,
                            //side_element_tag_select[i] 4 bits
                        }

                        for (i = 0; i < (int32)numBackChanElem; i++)
                        {
                            //calculate channel configuration
                            offset = ADIFHeaderLen >> 3;
                            bitIndex = ADIFHeaderLen & 0x7;
                            tmp = (uint8)((pBuffer[offset] << bitIndex) | (pBuffer[offset+1] >> (8 - bitIndex)));
                            tmp >>= (8 - 1); //back channel element takes 1 bit
                            iChannelConfig += (tmp + 1);

                            //update ADIF variable header length
                            ADIFHeaderLen += 5; //side_element_is_cpe[i] 1 bit,
                            //side_element_tag_select[i] 4 bits
                        }

                        if (numLfeChanElem != 0)
                        {
                            iChannelConfig++;   //1 front low frequency effects speaker
                        }

                        for (i = 0; i < (int32)numLfeChanElem; i++)
                        {
                            ADIFHeaderLen += 4; //lfe_element_tag_select[i] 4 bits
                        }

                        for (i = 0; i < (int32)numAssocDataElem; i++)
                        {
                            ADIFHeaderLen += 4; //assoc_data_element_tag_select[i] 4 bits
                        }

                        for (i = 0; i < (int32)numValidCCElem; i++)
                        {
                            ADIFHeaderLen += 5; //cc_element_is_ind_sw[i] 1 bit,
                            //valid_cc_element_tag_select[i] 4 bits
                        }

                        // byte_allignment
                        ADIFHeaderLen += 7;
                        ADIFHeaderLen &= 0xF8;

                        // comment_field_bytes (8 bits)
                        offset = ADIFHeaderLen >> 3;
                        bitIndex = ADIFHeaderLen & 0x7;
                        commentFieldBytes = (pBuffer[offset] << bitIndex) | (pBuffer[offset+1] >> (8 - bitIndex));

                        ADIFHeaderLen += 8; //comment_field_bytes 8 bits

                        for (i = 0; i < (int32)commentFieldBytes; i++)
                        {
                            ADIFHeaderLen += 8; //comment_field_data 8 bits
                        }

                    }// for (i = 0; i < (int32)numProgConfigElem + 1; i++)

                } // if(id!=0)

                // ADIF header length in bits
                iADIFHeaderLen = HeaderLen = ADIFHeaderLen;

                // get ADIF id header part to iAACHeaderBuffer (4 bytes)
                oscl_memcpy(iAACHeaderBuffer, pBuffer, PACKET_INDICATOR_LENGTH);
            }
            else
            {
                // Check for possible adts sync word
                int32 index = find_adts_syncword(pBuffer);
                if (index != -1)
                {
                    //ADTS format
                    iAACFormat = format = EAACADTS;
                    // get sample frequency index
                    iSampleFreqIndex = sampleFreqIndex = (uint8)((pBuffer[2 + index] & 0x3c) >> 2);

                    // check the crc_check field
                    ibCRC_Check = ((pBuffer[1 + index] & 0x01) ? false : true);

                    // get ADTS fixed header part to iAACHeaderBuffer
                    oscl_memcpy(iAACHeaderBuffer, &pBuffer[index], PACKET_INDICATOR_LENGTH);

                }
            }
        }
    }
    else
    {
        fileSize = iFileSize;
        format = iAACFormat;
        sampleFreqIndex = iSampleFreqIndex;
        bitRate = iBitrate;
    }
    return ret_value;
}


//! extended search to get clip information only for adts format
int32 AACBitstreamObject::extendedAdtsSearchForFileInfo(TAACFormat& format,
        uint8& sampleFreqIndex)
{
    sampleFreqIndex = 0;
    int32 ret_value = AACBitstreamObject::EVERYTHING_OK;

    iPos = iPosSyncAdtsFound;   /* overlap only needed data */
    ret_value = refill();
    if (ret_value == AACBitstreamObject::EVERYTHING_OK)
    {

        uint8 *pBuffer = &iBuffer[iPos];

        // Check for possible adts sync word
        int32 index = find_adts_syncword(pBuffer);
        if (index != -1)
        {
            //ADTS format
            iAACFormat = format = EAACADTS;
            // get sample frequency index
            iSampleFreqIndex = sampleFreqIndex = (uint8)((pBuffer[2 + index] & 0x3c) >> 2);

            // check the crc_check field
            ibCRC_Check = ((pBuffer[1 + index] & 0x01) ? false : true);

            // get ADTS fixed header part to iAACHeaderBuffer
            oscl_memcpy(iAACHeaderBuffer, &pBuffer[index], PACKET_INDICATOR_LENGTH);

        }
        else
        {
            if ((uint32)iBytesRead > ADTS_SYNC_SEARCH_LENGTH(iFileSize, 5))    // search over 3.13 % of the file
            {
                return AACBitstreamObject::MISC_ERROR;  // break the loop
            }
            //otherwise keep looking
        }

    }
    return ret_value;
}

int32 AACBitstreamObject::getDecoderConfigHeader(uint8* headerBuffer)
{
    if (iAACFormat == EAACADTS) //ADTS
    {
        if (!headerBuffer ||
                !(iAACHeaderBuffer[0] == 0xff &&
                  (iAACHeaderBuffer[1] & 0xf0) == 0xf0))
        {
            PVMF_AACPARSER_LOGERROR((0, "AACBitstreamObject::getDecoderConfigHeader- Misc Error"));
            return AACBitstreamObject::MISC_ERROR;
        }

        // parse the ADTS header of the first frame: iAACHeaderReferenceBuffer[] (got from the bitstream in InitAACFile()
        headerBuffer[0] = headerBuffer[1] = 0;

        // 1. construct auditoObjectType(bit1-5, 5 bits, MPEG-4) from profile(bit17-18, 2 bits, ADTS)
        uint8 profile = (uint8)(iAACHeaderBuffer[2] >> 6); // 2 bits long
        headerBuffer[0] |= ++profile << 3;   // put it into the highest 5 bits

        // 2. construct samplingFrequencyIndex(bit6-9, 4 bits, MPEG-4) from sampling_frequency_index(bit19-22, 4 bits, ADTS)
        uint8 sampling_frequency_index = (uint8)((iAACHeaderBuffer[2] >> 2) & 0x0f); // 4 bits long
        headerBuffer[0] |= (sampling_frequency_index >> 1);      // put 3 bits
        headerBuffer[1] |= ((sampling_frequency_index & 0x1) << 7); // put 1 bit

        // 3. construct channelConfiguration(bit10-13, 4 bits, MPEG-4) from channel_configuration(bit22-24, 3 bits, ADTS)
        uint8 channel_config = (uint8)(((iAACHeaderBuffer[2] & 0x01) << 2) |
                                       (iAACHeaderBuffer[3] >> 6));    // 3 bits long in ADTS => 4 valid bits in MPEG-4
        headerBuffer[1] |= (channel_config << 3);
    }
    else if (iAACFormat == EAACADIF) //ADIF
    {
        if (!headerBuffer ||
                !((iAACHeaderBuffer[0] == 0x41) &&  // 'A'
                  (iAACHeaderBuffer[1] == 0x44) &&  // 'D'
                  (iAACHeaderBuffer[2] == 0x49) &&  // 'I'
                  (iAACHeaderBuffer[3] == 0x46)))   // 'F'
        {
            PVMF_AACPARSER_LOGERROR((0, "AACBitstreamObject::getDecoderConfigHeader- Misc Error"));
            return AACBitstreamObject::MISC_ERROR;
        }

        // parse the ADIF header
        headerBuffer[0] = headerBuffer[1] = 0;

        // 1. construct audio object type (2 bits)
        headerBuffer[0] |= ((iAudioObjectType + 1) << 3);

        // 2. construct sampling frequency index (4 bits)
        headerBuffer[0] |= (iSampleFreqIndex >> 1); //put 3 bits in headerBuffer[0]
        headerBuffer[1] |= ((iSampleFreqIndex & 0x1) << 7); //put 1 bit in headerBuffer[1]

        // 3. construct channel configuration (4 bits)
        headerBuffer[1] |= ((iChannelConfig + 1) << 3);
    }
    else if (iAACFormat == EAACRaw)
    {
        // Just copy the audio specific config
        oscl_memcpy(headerBuffer, iAACHeaderBuffer, iRawAACHeaderLen);
    }

    return AACBitstreamObject::EVERYTHING_OK;
}

template <class PtrType>
class AutoPtrArrayContainer
{
    private:
        bool _Ownership;
        PtrType *_Ptr;

    public:
        // default constructors
        explicit AutoPtrArrayContainer(PtrType *inPtr = 0) :
                _Ownership(inPtr != 0), _Ptr(inPtr)   {};

        ~AutoPtrArrayContainer()
        {
            if (_Ownership && _Ptr)
            {
                OSCL_ARRAY_DELETE(_Ptr);
                _Ptr = NULL;
            }
            _Ownership = false;
        }
};


//----------------------------------------------------------------------------
// FUNCTION NAME: CAACFileParser::CAACFileParser
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
//  Inputs:
//    None
//
//  Outputs:
//    None
//
//  Returns:
//    None
//
//  Global Variables Used:
//    None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
//  Constructor for CAACFileParser class
//
//----------------------------------------------------------------------------
// REQUIREMENTS
//
//----------------------------------------------------------------------------
// REFERENCES
//
//------------------------------------------------------------------------------
// CAUTION
//
//------------------------------------------------------------------------------
OSCL_EXPORT_REF CAACFileParser::CAACFileParser(void) :
        iAACDuration(0),
        iAACSampleFrequency(0),
        iAACBitRate(0),
        iAACHeaderLen(0),
        iFirstTime(false),
        iAACFileSize(0),
        iTotalNumFramesRead(0),
        iAACFormat(EAACUnrecognized),
        iEndOfFileReached(false),
        iLogger(PVLogger::GetLoggerObject("pvaacparser")),
        iDiagnosticLogger(PVLogger::GetLoggerObject("playerdiagnostics.pvaac_parser")),
        ipBSO(NULL)
{}

//----------------------------------------------------------------------------
// FUNCTION NAME: CAACFileParser::~CAACFileParser
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
//  Inputs:
//    None
//
//  Outputs:
//    None
//
//  Returns:
//    None
//
//  Global Variables Used:
//    None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
//  Destructor for CAACFileParser class
//
//----------------------------------------------------------------------------
// REQUIREMENTS
//
//----------------------------------------------------------------------------
// REFERENCES
//
//------------------------------------------------------------------------------
// CAUTION
//
//------------------------------------------------------------------------------
OSCL_EXPORT_REF CAACFileParser::~CAACFileParser(void)
{

    if (iAACFile.IsOpen())
    {
        iAACFile.Close();
    }
    if (ipBSO != NULL)
    {
        PV_AAC_FF_DELETE(NULL, AACBitstreamObject, ipBSO);
        ipBSO = NULL;
    }

}

//----------------------------------------------------------------------------
// FUNCTION NAME: CAACFileParser::InitAACFile
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
//  Inputs:
//    aClip = pointer to the AAC file name to be played of type TPtrC
//
//  Outputs:
//    None
//
//  Returns:
//    returnValue = true if the init succeeds, else false.
//
//  Global Variables Used:
//    None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
//  This function opens the AAC file, checks for AAC format type, calculates
//  the track duration, and sets the AAC bitrate value.
//
//----------------------------------------------------------------------------
// REQUIREMENTS
//
//----------------------------------------------------------------------------
// REFERENCES
//
//------------------------------------------------------------------------------
// CAUTION
//
//------------------------------------------------------------------------------
OSCL_EXPORT_REF bool CAACFileParser::InitAACFile(CAACFileParams& aParams,
        bool aInitParsingEnable)
{
    iAACFile.SetCPM(aParams.iCPMAccess);
    iAACFile.SetFileHandle(aParams.iHandle);

    //For aac overwritte pvfile default settings in order to prevent
    //audio artifacts when playing files from MMC
    //use native cache (if supported by the platform) size 32KB.
    PVFileCacheParams cacheParams;
    cacheParams.iCacheSize = 32768; //32K
    cacheParams.iNativeAccessMode = 1;

    iAACFile.SetFileCacheParams(cacheParams);

    // Open the file (aClip)
    if (iAACFile.Open(aParams.iClip.get_cstr(), (Oscl_File::MODE_READ | Oscl_File::MODE_BINARY), *(aParams.iFileSession)) != 0)
    {
        return false;
    }

    if (aParams.iRawAACFile)
    {
        iAACFormat = EAACRaw;
    }
    else
    {
        iAACFormat = EAACUnrecognized;
    }

    ParserErrorCode errCode = AAC_SUCCESS;
    PV_AAC_FF_NEW(NULL, AACBitstreamObject, (&iAACFile, errCode), ipBSO);
    if (ipBSO->getFileInfo(iAACFileSize, iAACFormat, iSampleFreqTableIndex, iAACBitRate, iAACHeaderLen, aParams.iClip))
    {
        return false;
    }

    //ADTS/ADIF/RAW format
    if ((iSampleFreqTableIndex >= 12) && (iSampleFreqTableIndex < 16))
        return false;
    iAACSampleFrequency = ADTSSampleFreqTable[(uint16)iSampleFreqTableIndex];
    if (iAACSampleFrequency == -1)
        return false;

    if (iAACFormat != EAACUnrecognized)
    {
        iFirstTime = true;
    }
    else
    {
        return false;
    }

    // Determine file duration and set up random positioning table if needed
    if (aInitParsingEnable)
    {
        if (iAACFormat == EAACADTS)
        {
            // fully go through each frame to calculate duration
            int32 status = AACBitstreamObject::EVERYTHING_OK;
            int32 frame_size = 0;
            int32 numRawBlocks;


            uint8 *maxAACFrameBuffer = OSCL_ARRAY_NEW(uint8, MAX_AAC_FRAME_SIZE); // MAX_AAC_FRAME_SIZE=8192
            if (!maxAACFrameBuffer)
            {
                return false;
            }
            AutoPtrArrayContainer<uint8> autoPtr(maxAACFrameBuffer);

            iAACDuration = 0;
            int32 filePos = 0;
            iRPTable.push_back(filePos);

            while (status == AACBitstreamObject::EVERYTHING_OK)
            {
                // get the next frame
                status = ipBSO->getNextFrameInfo(frame_size, numRawBlocks);
                if (status == AACBitstreamObject::END_OF_FILE || status == AACBitstreamObject::INSUFFICIENT_DATA)
                {
                    break;
                }
                else if (status == AACBitstreamObject::EVERYTHING_OK && frame_size > 0)
                {
                    int32 hdrSize = 0;
                    status = ipBSO->getNextFrame(maxAACFrameBuffer, frame_size, hdrSize);

                    if (status == AACBitstreamObject::EVERYTHING_OK)
                    {
                        // calulate the number of frames
                        iAACDuration += numRawBlocks;

                        // set up the table for randow positioning
                        int32 frame_length = frame_size + ADTS_HEADER_LENGTH + (ipBSO->isCRCEnabled() ? 2 : 0);
                        filePos += frame_length;
                        iRPTable.push_back(filePos);
                    }
                    else if (status == AACBitstreamObject::END_OF_FILE)
                    {
                        break;
                    }
                    else if (status == AACBitstreamObject::INSUFFICIENT_DATA)
                    {
                        break;
                    }
                    else
                    {
                        // error happens!
                        PVMF_AACPARSER_LOGERROR((0, "Error InitAacfile"));
                        return false;

                    }
                }
                else
                {
                    // error happens!
                    PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::InitAACFile:Error in getting next frame "));
                    return false;
                }
            }

            // get the duration in millisec
            MediaClockConverter mcc;
            mcc.set_timescale(iAACSampleFrequency);
            mcc.set_clock(OSCL_STATIC_CAST(uint32, (iAACDuration*1024)), 0);
            iAACDuration = mcc.get_converted_ts(1000);

            if (ipBSO->reset(0))
                return false;
        }
        else if (iAACFormat == EAACADIF)
        {
            int32 raw_data_bits;

            iAACDuration = 0;
            iRPTable.push_back(iAACDuration);

            raw_data_bits = iAACFileSize * 8 - iAACHeaderLen;

            // rough duration calculation based on max bitrate for variable rate bitstream
            MediaClockConverter mcc;
            mcc.set_timescale(iAACBitRate);
            mcc.set_clock(OSCL_STATIC_CAST(uint32, raw_data_bits), 0);
            iAACDuration = mcc.get_converted_ts(1000);

            if (ipBSO->reset(ipBSO->GetByteOffsetToStartOfAudioFrames() + (iAACHeaderLen >> 3)))
                return false;
        }
        else if (iAACFormat == EAACRaw)
        {
            iAACDuration = 0;
            iRPTable.push_back(iAACDuration);

            // Duration cannot be calculated
            int32 hdrsize = iAACHeaderLen >> 3;
            if (iAACHeaderLen&0x7)
            {
                ++hdrsize;
            }
            if (ipBSO->reset(ipBSO->GetByteOffsetToStartOfAudioFrames() + hdrsize))
            {
                PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::InitAACFile:Error Bitstream object failed to reset"));
                return false;
            }
        }

    } // end of: if(aInitParsingEnable)


    return true;
}

//----------------------------------------------------------------------------
// FUNCTION NAME: CAACFileParser::RetrieveFileInfo
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
//  Inputs:
//
//  Outputs:
//    None
//
//  Returns:
//    false if an error happens, else true
//
//  Global Variables Used:
//    None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
//  This function opens the AAC file, checks for AAC format type, calculates
//  the track duration, and sets the AAC bitrate value.
//
//----------------------------------------------------------------------------
// REQUIREMENTS
//
//----------------------------------------------------------------------------
// REFERENCES
//
//------------------------------------------------------------------------------
// CAUTION
//
//------------------------------------------------------------------------------
OSCL_EXPORT_REF bool CAACFileParser::RetrieveFileInfo(TPVAacFileInfo& aInfo)
{
    if (iAACFormat == EAACUnrecognized)
    {
        // File is not open and parsed
        return false;
    }

    aInfo.iTimescale = 1000;
    aInfo.iDuration = iAACDuration;
    aInfo.iSampleFrequency = iAACSampleFrequency;
    aInfo.iBitrate = iAACBitRate;
    aInfo.iFormat = iAACFormat;
    aInfo.iFileSize = iAACFileSize;
    PVMF_AACPARSER_LOGDIAGNOSTICS((0, "CAACFileParser::RetrieveFileInfo- duration = %d, bitrate = %d, filesize = %d", iAACDuration, iAACBitRate, iAACFileSize));

    return true;
}

//----------------------------------------------------------------------------
// FUNCTION NAME: CAACFileParser::RetrieveID3Info
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
//  Inputs:
//      aID3MetaData: pointer to data structure for the output.
//
//  Outputs:
//    None
//
//  Returns:
//    false if an error happens, else true
//
//  Global Variables Used:
//    None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
//  This function retrieves the ID3 data if any was found in the file.
//
//----------------------------------------------------------------------------
// REQUIREMENTS
//
//----------------------------------------------------------------------------
// REFERENCES
//
//------------------------------------------------------------------------------
// CAUTION
//
//------------------------------------------------------------------------------
OSCL_EXPORT_REF bool CAACFileParser::RetrieveID3Info(PvmiKvpSharedPtrVector& aID3MetaData)
{
    if (ipBSO)
    {
        ipBSO->ID3MetaData(aID3MetaData);
        if (aID3MetaData.size() > 0)
            return true;
        else
            return false;
    }
    else
    {
        return false;
    }
}

OSCL_EXPORT_REF bool CAACFileParser::IsID3Frame(const OSCL_String &frameType)
{
    return ipBSO->IsID3Frame(frameType);
}

OSCL_EXPORT_REF void CAACFileParser::GetID3Frame(const OSCL_String& aFrameType, PvmiKvpSharedPtrVector& aFrame)
{
    ipBSO->GetID3Frame(aFrameType, aFrame);
}

//----------------------------------------------------------------------------
// FUNCTION NAME: CAACFileParser::ResetPlayback
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
//  Inputs:
//    aStartTime = integer value as where to move the playback positioning to.
//
//  Outputs:
//    None
//
//  Returns:
//    0 if success, -1 if failure
//
//  Global Variables Used:
//    None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
//  This function sets the file pointer to the location that aStartTime would
//  point to in the file.
//
//----------------------------------------------------------------------------
// REQUIREMENTS
//
//----------------------------------------------------------------------------
// REFERENCES
//
//------------------------------------------------------------------------------
// CAUTION
//
//------------------------------------------------------------------------------

OSCL_EXPORT_REF int32 CAACFileParser::ResetPlayback(uint32 aStartTime, uint32& aActualStartTime)
{
    // Check if the file is opened
    int32 result;
    if (!iAACFile.IsOpen())
    {
        PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::ResetPlayback- Misc error-"));
        return AACBitstreamObject::MISC_ERROR;
    }

    // initialize "iTotalNumFramesRead"
    // +1 means we choose the next frame(ts>=aStartTime)
    //iTotalNumFramesRead = aStartTime/(1024000/iAACSampleFrequency);
    iTotalNumFramesRead = (int32)((OsclFloat)aStartTime * iAACSampleFrequency / 1024000.0) + (aStartTime > 0) * 1;
    PVMF_AACPARSER_LOGDIAGNOSTICS((0, "CAACFileParser::resetplayback - TotalNumFramesRead=%d", iTotalNumFramesRead));

    if (iAACFormat == EAACADTS)
    {
        // set new file position
        int32 newPosition = 0;
        if (iAACDuration != 0 && iRPTable.size() <= 0)
        {
            newPosition = (iAACFileSize * aStartTime) / iAACDuration;
            PVMF_AACPARSER_LOGDIAGNOSTICS((0, "CAACFileParser::resetplayback - newPosition=%d", newPosition));
            if (newPosition < 0)
            {
                newPosition = 0; // if we have no duration information, reset the file position at 0.
            }
        }
        else if (iRPTable.size() > 0)
        {
            // use the randow positioning table to determine the file position
            if (iTotalNumFramesRead > (int32)iRPTable.size())
            {
                iTotalNumFramesRead = ((int32)iRPTable.size()) - 2;
            }
            newPosition = iRPTable[iTotalNumFramesRead];
        }
        result = ipBSO->reset(ipBSO->GetByteOffsetToStartOfAudioFrames() + newPosition);
        if (newPosition >= 0 && result)
        {
            PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::ResetPlayback- Misc error-"));
            return result;
        }
        iEndOfFileReached = false;
    }
    else if (iAACFormat == EAACADIF)
    {
        int32 newPosition = (iAACHeaderLen >> 3);

        if (newPosition >= 0 && ipBSO->reset(ipBSO->GetByteOffsetToStartOfAudioFrames() + newPosition))
        {
            PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::ResetPlayback- Misc error-"));
            return AACBitstreamObject::MISC_ERROR;
        }
        iEndOfFileReached = false;
        iFirstTime = true;
        iTotalNumFramesRead = 0; // For ADIF reposition to time 0 always
    }
    else if (iAACFormat == EAACRaw)
    {
        int32 newPosition = (iAACHeaderLen >> 3);
        if (iAACHeaderLen&0x7)
        {
            ++newPosition;
        }

        if (newPosition >= 0 && ipBSO->reset(ipBSO->GetByteOffsetToStartOfAudioFrames() + newPosition))
        {
            PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::ResetPlayback- Misc error-"));
            return AACBitstreamObject::MISC_ERROR;
        }
        iEndOfFileReached = false;
        iFirstTime = true;
        iTotalNumFramesRead = 0; // For AAC raw bitstream reposition to time 0 always
    }

    MediaClockConverter mcc;
    mcc.set_timescale(iAACSampleFrequency);
    mcc.set_clock(OSCL_STATIC_CAST(uint32, (iTotalNumFramesRead*1024)), 0);
    aActualStartTime = mcc.get_converted_ts(1000);

    PVMF_AACPARSER_LOGDIAGNOSTICS((0, "CAACFileParser::resetplayback - aActualStartTime=%d", aActualStartTime));
    return AACBitstreamObject::EVERYTHING_OK;
}

//----------------------------------------------------------------------------
// FUNCTION NAME: CAACFileParser::SeekPointFromTimestamp
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
//  Inputs:
//    aStartTime = integer value as for the specified start time
//
//  Outputs:
//    None
//
//  Returns:
//    Timestamp in milliseconds of the actual position
//
//  Global Variables Used:
//    None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
//  This function returns the timestamp for an actual position corresponding
//  to the specified start time
//
//----------------------------------------------------------------------------
// REQUIREMENTS
//
//----------------------------------------------------------------------------
// REFERENCES
//
//------------------------------------------------------------------------------
// CAUTION
//
//------------------------------------------------------------------------------
OSCL_EXPORT_REF uint32 CAACFileParser::SeekPointFromTimestamp(uint32 aStartTime)
{
    // Check if the file is opened
    if (!iAACFile.IsOpen())
    {
        return 0;
    }

    // Determine the frame number corresponding to timestamp
    // note: +1 means we choose the next frame(ts>=aStartTime)
    uint32 startframenum = (int32)((OsclFloat)aStartTime * iAACSampleFrequency / 1024000.0) + (aStartTime > 0) * 1;

    // Correct the frame number if necessary
    if (iAACFormat == EAACADTS)
    {
        // set new file position
        if (iAACDuration != 0 && iRPTable.size() <= 0)
        {
            // Duration not known and reposition table not available so go to first frame
            startframenum = 0;
        }
        else if (iRPTable.size() > 0)
        {
            if (startframenum >= iRPTable.size())
            {
                // Requesting past the end of table so set to (end of table-1)
                // to be at the last sample
                startframenum = ((int32)iRPTable.size()) - 2;
            }
        }
    }
    else if (iAACFormat == EAACADIF || iAACFormat == EAACRaw)
    {
        // Not enough info in file to reposition so go to time 0
        return 0;
    }

    return (int32)((OsclFloat)startframenum*1024000.0 / iAACSampleFrequency);
}

//----------------------------------------------------------------------------
// FUNCTION NAME: CAACFileParser::GetNextBundledAccessUnits
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
//  Inputs:
//    aNumSamples = requested number of frames to be read from file
//    aGau        = frame information structure of type GAU
//
//  Outputs:
//    None
//
//  Returns:
//    0 if success, -1 if failure
//  Global Variables Used:
//    None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
//  This function attempts to read in the number of AAC frames specified by
//  aNumSamples. It formats the read data to WMF bit order and stores it in
//  the GAU structure.
//
//----------------------------------------------------------------------------
// REQUIREMENTS
//
//----------------------------------------------------------------------------
// REFERENCES
//
//------------------------------------------------------------------------------
// CAUTION
//
//------------------------------------------------------------------------------
OSCL_EXPORT_REF int32
CAACFileParser::GetNextBundledAccessUnits(uint32 *aNumSamples,
        GAU *aGau,
        bool bADTSHeaderIncluded)
{
    // AAC format has already been identified in InitAACFile function.
    // Check if AAC format is valid as the safeguard
    if (iAACFormat == EAACUnrecognized)
    {
        PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::GetNextBundledAccessUnits- Misc error-"));
        return AACBitstreamObject::MISC_ERROR;
    }

    int32 returnValue = AACBitstreamObject::EVERYTHING_OK;

    if (iAACFormat == EAACADTS)
    {
        if (iEndOfFileReached)
        {
            *aNumSamples = 0;
            return AACBitstreamObject::END_OF_FILE;
        }

        uint8* pTempGau = (uint8 *)aGau->buf.fragments[0].ptr;
        uint32 gauBufferSize = aGau->buf.fragments[0].len;
        uint32 i, bytesReadInGau = 0, numSamplesRead = 0;
        int32 frame_size = 0, numRawBlocks;
        int32 prev_iTotalNumFramesRead = iTotalNumFramesRead; // BX

        for (i = 0; i < *aNumSamples && !iEndOfFileReached; i++)
        {
            // get the frame size and number of data blocks
            returnValue = ipBSO->getNextFrameInfo(frame_size, numRawBlocks);
            PVMF_AACPARSER_LOGDIAGNOSTICS((0, "CAACFileParser::GetNextBundledAccessUnits - frame_size=%d", frame_size));
            if (returnValue == AACBitstreamObject::END_OF_FILE)
            {
                iEndOfFileReached = true;
                break;
            }
            else if (returnValue == AACBitstreamObject::INSUFFICIENT_DATA)
            {
                *aNumSamples = 0;
                return returnValue;
            }
            else if (returnValue == AACBitstreamObject::EVERYTHING_OK && frame_size > 0)
            {
                // Check whether the gau buffer will be overflow or the requested number
                // of samples will be met
                if (bytesReadInGau + frame_size >= gauBufferSize ||
                        numSamplesRead + numRawBlocks > MAX_NUM_RAW_BLOCKS_PER_ADTS_HEADER)
                    break;

                // At this point, we can get the next frame
                int32 hdrSize = 0;
                returnValue = ipBSO->getNextFrame(pTempGau, frame_size, hdrSize, bADTSHeaderIncluded);
                if (returnValue == AACBitstreamObject::END_OF_FILE)
                {
                    iEndOfFileReached = true;
                    break;
                }
                else if (returnValue == AACBitstreamObject::EVERYTHING_OK)
                {
                    // update infomation
                    pTempGau += frame_size;
                    bytesReadInGau += frame_size;
                    aGau->info[i].len = frame_size + hdrSize;
                    aGau->info[i].ts  = (int32)(((OsclFloat)(iTotalNumFramesRead++) * 1024000.0) / (OsclFloat)iAACSampleFrequency); // BX
                    numSamplesRead += numRawBlocks;
                }
                else if (returnValue == AACBitstreamObject::INSUFFICIENT_DATA)
                {
                    *aNumSamples = 0;
                    return returnValue;
                }
                else
                { // error happens!!
                    PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::GetNextBundledAccessUnits- Read error-"));
                    *aNumSamples = 0;
                    return AACBitstreamObject::READ_ERROR;
                }
            }
            else
            {
                // error happens!!
                PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::GetNextBundledAccessUnits- Read error-"));
                *aNumSamples = 0;
                return AACBitstreamObject::READ_ERROR;
            }
        } // end of: for(i = 0; i < *aNumSamples && !iEndOfFileReached; i++)

        aGau->info[0].ts = (int32)(((OsclFloat)prev_iTotalNumFramesRead * 1024000.0) / (OsclFloat)iAACSampleFrequency); // BX
        *aNumSamples = numSamplesRead;
    }

    else if (iAACFormat == EAACADIF || iAACFormat == EAACRaw)
    {
        *aNumSamples = 0;

        uint8* pTempGau = (uint8 *)aGau->buf.fragments[0].ptr;  //point to the current data location in StreamingBuffer
        uint32 gauBufferSize = aGau->buf.fragments[0].len;
        uint32 bytesReadInGau = 0;
        uint32 bytestoread = 0;
        uint32 i;

        if (iFirstTime == true)
        {
            // read from file to get two guranteed AAC decoder frames in streaming buffer
            for (i = 0; i < 2; i++)  //AAC Streaming Buffer Max Data Size is 15359 (9*1536 + 1535)
            {
                // At this point, we can get the next frame
                if (bytesReadInGau >= gauBufferSize)
                {
                    // No more buffer space to read
                    break;
                }
                bytestoread = gauBufferSize - bytesReadInGau;
                if (bytestoread > AAC_DECODER_INPUT_BUFF_SIZE)
                {
                    bytestoread = AAC_DECODER_INPUT_BUFF_SIZE;
                }
                int32 hdrSize = 0;
                returnValue = ipBSO->getNextFrame(pTempGau, (int32 &)bytestoread, hdrSize, bADTSHeaderIncluded);

                if (returnValue == AACBitstreamObject::END_OF_FILE)
                {
                    iEndOfFileReached = true;
                    break;
                }
                else if (returnValue == AACBitstreamObject::EVERYTHING_OK)
                {
                    // update infomation
                    pTempGau += bytestoread;
                    aGau->info[i].len = bytestoread;
                    aGau->info[i].ts = 0; // First block of AAC data read has timestamp 0
                    bytesReadInGau += bytestoread;
                    *aNumSamples += 1;
                }
                else if (returnValue == AACBitstreamObject::INSUFFICIENT_DATA)
                { // error happens!!
                    PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::GetNextBundledAccessUnits- Under flow-"));
                    return AACBitstreamObject::INSUFFICIENT_DATA;
                }
                else
                {
                    // error happens!!
                    PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::GetNextBundledAccessUnits- Read error-"));
                    return AACBitstreamObject::READ_ERROR;
                }
            }
            iFirstTime = false;
        }
        else    // read from file to get one guranteed AAC decoder frame in streaming buffer
        {
            // At this point, we can get the next frame
            bytestoread = gauBufferSize;
            if (bytestoread > AAC_DECODER_INPUT_BUFF_SIZE)
            {
                bytestoread = AAC_DECODER_INPUT_BUFF_SIZE;
            }

            int32 hdrSize = 0;
            returnValue = ipBSO->getNextFrame(pTempGau, (int32 &)bytestoread, hdrSize, bADTSHeaderIncluded);

            if (returnValue == AACBitstreamObject::END_OF_FILE)
            {
                iEndOfFileReached = true;
            }
            else if (returnValue == AACBitstreamObject::EVERYTHING_OK)
            {
                // update infomation
                aGau->info[0].len = bytestoread;
                aGau->info[0].ts = 0xFFFFFFFF; // Unknown timestamp
//              aGau->info[0].ts=(int32)(((OsclFloat)(iTotalNumFramesRead++) * 1024000.0) / (OsclFloat)iAACSampleFrequency); // BX
                bytesReadInGau += bytestoread;
                *aNumSamples += 1;
            }
            else if (returnValue == AACBitstreamObject::INSUFFICIENT_DATA)
            { // error happens!!
                PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::GetNextBundledAccessUnits- Under flow-"));
                return AACBitstreamObject::INSUFFICIENT_DATA;
            }
            else
            {
                // error happens!!
                PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::GetNextBundledAccessUnits- Read error-"));
                return AACBitstreamObject::READ_ERROR;
            }
        }
    }

    //We may have reached EOF but also found some samples.
    //don't return EOF until there are no samples left.
    if (returnValue == AACBitstreamObject::END_OF_FILE
            && *aNumSamples > 0)
    {
        return AACBitstreamObject::EVERYTHING_OK;
    }

    return returnValue;
}

//----------------------------------------------------------------------------
// FUNCTION NAME: CAACFileParser::PeekNextTimestamp
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
//  Inputs:
//    None
//
//  Outputs:
//    None
//
//  Returns:
//    return = status EVERYTHING_OK.
//
//  Global Variables Used:
//    None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
//  This function returns the next timestamp without processing any data.
//
//----------------------------------------------------------------------------
// REQUIREMENTS
//
//----------------------------------------------------------------------------
// REFERENCES
//
//------------------------------------------------------------------------------
// CAUTION
//
//------------------------------------------------------------------------------
OSCL_EXPORT_REF int32 CAACFileParser::PeekNextTimestamp(uint32& ts)
{
    MediaClockConverter mcc;
    mcc.set_timescale(iAACSampleFrequency);
    mcc.set_clock(OSCL_STATIC_CAST(uint32, ((iTotalNumFramesRead + 1)*1024)), 0);
    ts = mcc.get_converted_ts(1000);

    return AACBitstreamObject::EVERYTHING_OK;
}

//----------------------------------------------------------------------------
// FUNCTION NAME: CAACFileParser::GetTrackDecoderSpecificInfoSize
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
//  Inputs:
//    None
//
//  Outputs:
//    None
//
//  Returns:
//    return = AAC_DECODER_SPECIFIC_INFO_SIZE
//
//  Global Variables Used:
//    None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
//  This function returns the value defined by AAC_DECODER_SPECIFIC_INFO_SIZE.
//
//----------------------------------------------------------------------------
// REQUIREMENTS
//
//----------------------------------------------------------------------------
// REFERENCES
//
//------------------------------------------------------------------------------
// CAUTION
//
//------------------------------------------------------------------------------
OSCL_EXPORT_REF int32 CAACFileParser::GetTrackDecoderSpecificInfoSize(void)
{
    if (iAACFormat == EAACRaw)
    {
        int32 infosize = iAACHeaderLen >> 3;
        if (iAACHeaderLen&0x7)
        {
            ++infosize;
        }
        return infosize;
    }
    else
    {
        return AAC_DECODER_SPECIFIC_INFO_SIZE;
    }
}

//----------------------------------------------------------------------------
// FUNCTION NAME: CAACFileParser::GetTrackDecoderSpecificInfoContent
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
//  Inputs:
//    None
//
//  Outputs:
//    None
//
//  Returns:
//    return = address to location of iAACFrameBuffer[PACKET_INDICATOR_LENGTH]
//
//  Global Variables Used:
//    None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
//  This function populates iAACFrameBuffer with the two byte of decoder
//  specific info and returns the address to the values.
//
//----------------------------------------------------------------------------
// REQUIREMENTS
//
//----------------------------------------------------------------------------
// REFERENCES
//
//------------------------------------------------------------------------------
// CAUTION
//
//------------------------------------------------------------------------------
OSCL_EXPORT_REF uint8* CAACFileParser::GetTrackDecoderSpecificInfoContent(void)
{
    iAACFrameBuffer[PACKET_INDICATOR_LENGTH]     = 0x12;
    iAACFrameBuffer[PACKET_INDICATOR_LENGTH + 1] = 0x10;

    ipBSO->getDecoderConfigHeader(&iAACFrameBuffer[PACKET_INDICATOR_LENGTH]);
    return &iAACFrameBuffer[PACKET_INDICATOR_LENGTH];
}

//----------------------------------------------------------------------------
// FUNCTION NAME: CAACFileParser::GetAACFormat
//----------------------------------------------------------------------------
// INPUT AND OUTPUT DEFINITIONS
//
//  Inputs:
//    None
//
//  Outputs:
//    None
//
//  Returns:
//    return = iAACFormat
//
//  Global Variables Used:
//    None
//
//----------------------------------------------------------------------------
// FUNCTION DESCRIPTION
//
//  This function returns iAACFormat value.
//
//----------------------------------------------------------------------------
// REQUIREMENTS
//
//----------------------------------------------------------------------------
// REFERENCES
//
//------------------------------------------------------------------------------
// CAUTION
//
//------------------------------------------------------------------------------
OSCL_EXPORT_REF TAACFormat CAACFileParser::GetAACFormat(void)
{
    return iAACFormat;
}

OSCL_EXPORT_REF  PVID3Version CAACFileParser::GetID3Version() const
{
    return ipBSO->GetID3Version();
}

OSCL_EXPORT_REF ParserErrorCode CAACFileParser::getAACHeaderLen(CAACFileParams& aParams,
        bool aInitParsingEnable,
        uint32* HeaderLenValue)
{
    PVFile iAACFileTemp;
    OSCL_UNUSED_ARG(aInitParsingEnable);

    iAACFileTemp.SetCPM(aParams.iCPMAccess);
    iAACFileTemp.SetFileHandle(aParams.iHandle);

    // Open the file (aClip)
    if (iAACFileTemp.Open(aParams.iClip.get_cstr(), (Oscl_File::MODE_READ | Oscl_File::MODE_BINARY), *(aParams.iFileSession)) != 0)
    {
        PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::getAACHeaderLen- File open error-"));
        return FILE_OPEN_ERROR;
    }
    AACBitstreamObject *ipBSOTemp;
    ParserErrorCode errCode = AAC_SUCCESS;
    PV_AAC_FF_NEW(NULL, AACBitstreamObject, (&iAACFileTemp, errCode), ipBSOTemp);


    if (!ipBSOTemp || ipBSOTemp->get())
    {
        PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::getAACHeaderLen- Memory allocation failed-"));
        // release temp storage, file control block..
        iAACFileTemp.Close();
        PV_AAC_FF_DELETE(NULL, AACBitstreamObject, ipBSOTemp);
        return MEMORY_ERROR;
    }

    uint32 bitRateValueTemp;
    uint32 tempHeaderLenValue = 0;

    int32 iAACFileSizeTemp;
    uint8 sampleFreqTableValueTemp;
    TAACFormat formatTemp = EAACUnrecognized;
    if (aParams.iRawAACFile)
    {
        formatTemp = EAACRaw;
    }
    if (ipBSOTemp->getFileInfo(iAACFileSizeTemp, formatTemp, sampleFreqTableValueTemp, bitRateValueTemp, tempHeaderLenValue, aParams.iClip))
    {
        iAACFileTemp.Close();
        PV_AAC_FF_DELETE(NULL, AACBitstreamObject, ipBSOTemp);
        return FILE_OPEN_ERROR;
    }
    if (formatTemp == EAACADTS)
    {
        tempHeaderLenValue = ADTS_HEADER_LENGTH;
    }
    iAACFileTemp.Close();
    PV_AAC_FF_DELETE(NULL, AACBitstreamObject, ipBSOTemp);
    ipBSOTemp = NULL;
    *HeaderLenValue = tempHeaderLenValue;
    return AAC_SUCCESS;
}

OSCL_EXPORT_REF ParserErrorCode CAACFileParser::IsAACFile(CAACFileParams& aParams)
{
    PVFile iAACFileTemp;
    iAACFileTemp.SetCPM(aParams.iCPMAccess);
    iAACFileTemp.SetFileHandle(aParams.iHandle);

    // Open the file (aClip)
    if (iAACFileTemp.Open(aParams.iClip.get_cstr(),
                          (Oscl_File::MODE_READ | Oscl_File::MODE_BINARY),
                          *(aParams.iFileSession)) != 0)
    {
        PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::IsAACFile- File open error-"));
        return FILE_OPEN_ERROR;
    }

    AACBitstreamObject *ipBSOTemp;
    ParserErrorCode errCode = AAC_SUCCESS;
    PV_AAC_FF_NEW(NULL, AACBitstreamObject, (&iAACFileTemp, errCode), ipBSOTemp);

    if (!ipBSOTemp || ipBSOTemp->get())
    {
        PVMF_AACPARSER_LOGERROR((0, "CAACFileParser::IsAACFile- Memory allocation failed-"));
        // release temp storage, file control block..
        iAACFileTemp.Close();
        PV_AAC_FF_DELETE(NULL, AACBitstreamObject, ipBSOTemp);
        return MEMORY_ERROR;
    }

    int32 result = ipBSOTemp->isAACFile();

    // release temp storage, file control block and the file
    iAACFileTemp.Close();
    PV_AAC_FF_DELETE(NULL, AACBitstreamObject, ipBSOTemp);
    ipBSOTemp = NULL;

    if (AACBitstreamObject::EVERYTHING_OK == result)
    {
        return AAC_SUCCESS;
    }
    else if (AACBitstreamObject::INSUFFICIENT_DATA == result)
    {
        return INSUFFICIENT_DATA;
    }
    return GENERIC_ERROR;
}


OSCL_EXPORT_REF int32 CAACFileParser::GetMetadataSize()
{
    return ipBSO->GetMetadataSize();
}

OSCL_EXPORT_REF void CAACFileParser::SetDownloadFileSize(uint32 aDownloadFileSize)
{
    iDownloadFileSize = aDownloadFileSize;
}

void AACBitstreamObject::SetDownloadFileSize(uint32 aDownloadFileSize)
{
    iDownloadFileSize = aDownloadFileSize;
}

bool AACBitstreamObject::isValidSyncWord(uint8* aBuffer)
{
    if ((aBuffer[0] == 0xFF) &&
            ((aBuffer[1] & 0xF0) == 0xF0))
    {
        return true;
    }
    return false;
}

int32 AACBitstreamObject::GetMetadataSize()
{
    if (iMetadataSize > 0)
        return iMetadataSize;
    return 0;
}

uint32 AACBitstreamObject::GetAvgFrameSize()
{
    return iAvgFrameSize;
}

int32 AACBitstreamObject::GetADTSFrameLength(uint8* aBuffer)
{
    int32 frameLen = 0;
    // lowest 2 bits in the 4th byte of the header
    frameLen = (uint32)((aBuffer[0] & 0x03) << 11);
    // whole 5th byte(8 bits) of the header
    frameLen |= (uint32)(aBuffer[1] << 3);
    // highest 3 bits in the 6th byte of the header
    frameLen |= (uint32)((aBuffer[2] & 0xe0) >> 5);

    return frameLen;
}
