/* ------------------------------------------------------------------
 * Copyright (C) 1998-2009 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.
 * -------------------------------------------------------------------
 */
#include "log/log.h"

#include "mp4dec_lib.h"
#include "bitstream.h"
#include "vlc_decode.h"
#include "zigzag.h"

#define OSCL_DISABLE_WARNING_CONV_POSSIBLE_LOSS_OF_DATA

/* INTRA */
const static int mpeg_iqmat_def[NCOEFF_BLOCK] =
{
    8, 17, 18, 19, 21, 23, 25, 27,
    17, 18, 19, 21, 23, 25, 27, 28,
    20, 21, 22, 23, 24, 26, 28, 30,
    21, 22, 23, 24, 26, 28, 30, 32,
    22, 23, 24, 26, 28, 30, 32, 35,
    23, 24, 26, 28, 30, 32, 35, 38,
    25, 26, 28, 30, 32, 35, 38, 41,
    27, 28, 30, 32, 35, 38, 41, 45
};

/* INTER */
const static int mpeg_nqmat_def[64]  =
{
    16, 17, 18, 19, 20, 21, 22, 23,
    17, 18, 19, 20, 21, 22, 23, 24,
    18, 19, 20, 21, 22, 23, 24, 25,
    19, 20, 21, 22, 23, 24, 26, 27,
    20, 21, 22, 23, 25, 26, 27, 28,
    21, 22, 23, 24, 26, 27, 28, 30,
    22, 23, 24, 26, 27, 28, 30, 31,
    23, 24, 25, 27, 28, 30, 31, 33
};

/* ======================================================================== */
/*  Function : CalcNumBits()                                                */
/*  Purpose  :                                                              */
/*  In/out   :                                                              */
/*  Return   : Calculate the minimum number of bits required to             */
/*              represent x.                                                */
/*  Note     : This is an equivalent implementation of                      */
/*                      (long)ceil(log((double)x)/log(2.0))                 */
/*  Modified :                                                              */
/* ======================================================================== */
int CalcNumBits(uint x)
{
    int i = 1;
    while (x >>= 1) i++;
    return i;
}



/***********************************************************CommentBegin******
*
* -- DecodeVolHeader -- Decode the header of a VOL
*
*   04/10/2000 : initial modification to the new PV-Decoder Lib format.
*   10/12/2001 : reject non compliant bitstreams
*
***********************************************************CommentEnd********/
PV_STATUS DecodeVOLHeader(VideoDecData *video, int layer)
{
    PV_STATUS status;
    Vol *currVol;
    BitstreamDecVideo *stream;
    uint32 tmpvar, vol_shape;
    uint32 startCode;
    int *qmat, i, j;
    int version_id = 1;
#ifdef PV_TOLERATE_VOL_ERRORS
    uint32 profile = 0x01;
#endif
    /*  There's a "currLayer" variable inside videoDecData.          */
    /*   However, we don't maintain it until we decode frame data.  04/05/2000 */
    currVol = video->vol[layer];
    stream  = currVol->bitstream;
    currVol->moduloTimeBase = 0;

    /* Determine which start code for the decoder to begin with */
    status = BitstreamShowBits32HC(stream, &startCode);

    if (startCode == VISUAL_OBJECT_SEQUENCE_START_CODE)
    {   /*  Bitstream Exhchange Fix 9/99 */
        /* Bitstream Exchange requires we allow start with Video Object Sequence */
        /* visual_object_sequence_start_code            */
        (void) BitstreamReadBits32HC(stream);
        tmpvar = (uint32) BitstreamReadBits16(stream,  8); /* profile */
#ifndef PV_TOLERATE_VOL_ERRORS
        if (layer)                                                      /*    */
        {
            switch (tmpvar)
            {
                /* Simple Scalable Profile Levels */
                case 0x10:
                case 0x11:
                case 0x12:
                /* Core Scalable Profile Levels */
                case 0xA1:
                case 0xA2:
                case 0xA3:
                    // Do Nothing, the cases listed above are supported values
                    break;
                default:
                    // Unsupport profile level
                    return PV_FAIL;
              }
        }
        else
        {
            switch (tmpvar)
            {
                /* Simple Profile Levels */
                case 0x01:
                case 0x02:
                case 0x03:
                case 0x04:
                case 0x05:
                case 0x06:
                case 0x08:
                case 0x09:
                case 0x10:
                case 0x11:
                case 0x12:
                /* Core Profile Levels */
                case 0x21:
                case 0x22:
                case 0xA1:
                case 0xA2:
                case 0xA3:
                /* Advanced Simple Profile Levels*/
                case 0xF0:
                case 0xF1:
                case 0xF2:
                case 0xF3:
                case 0xF4:
                case 0xF5:
                    // Do Nothing, the cases listed above are supported values
                    break;
                default:
                    // Unsupport profile level
                    return PV_FAIL;
            }
        }
#else
        profile = tmpvar;
#endif

        // save the profile and level for the query
        currVol->profile_level_id = (uint)tmpvar; //  6/10/04



        status = BitstreamShowBits32HC(stream, &tmpvar);
        if (tmpvar == USER_DATA_START_CODE)
        {
            /* Something has to be done with user data  11/11/99 */
            status = DecodeUserData(stream);
            if (status != PV_SUCCESS) return PV_FAIL;
        }
        /* visual_object_start_code                     */
        BitstreamShowBits32HC(stream, &tmpvar);
        if (tmpvar != VISUAL_OBJECT_START_CODE)
        {
            do
            {
                /* Search for VOL_HEADER */
                status = PVSearchNextM4VFrame(stream); /* search 0x00 0x00 0x01 */
                if (status != PV_SUCCESS) return PV_FAIL; /* breaks the loop */
                BitstreamShowBits32(stream, VOL_START_CODE_LENGTH, &tmpvar);
                PV_BitstreamFlushBits(stream, 8);
            }
            while (tmpvar != VOL_START_CODE);
            goto decode_vol;
        }
        else
        {
            BitstreamReadBits32HC(stream);
        }

        /*  is_visual_object_identifier            */
        tmpvar = (uint32) BitstreamRead1Bits(stream);
        if (tmpvar)
        {
            /* visual_object_verid                            */
            tmpvar = (uint32) BitstreamReadBits16(stream, 4);
            /* visual_object_priority                         */
            tmpvar = (uint32) BitstreamReadBits16(stream, 3);
        }
        /* visual_object_type                                 */
        BitstreamShowBits32(stream, 4, &tmpvar);
        if (tmpvar == 1)
        { /* video_signal_type */
            PV_BitstreamFlushBits(stream, 4);
            tmpvar = (uint32) BitstreamRead1Bits(stream);
            if (tmpvar == 1)
            {
                /* video_format */
                tmpvar = (uint32) BitstreamReadBits16(stream, 3);
                /* video_range  */
                tmpvar = (uint32) BitstreamRead1Bits(stream);
                /* color_description */
                tmpvar = (uint32) BitstreamRead1Bits(stream);
                if (tmpvar == 1)
                {
                    /* color_primaries */
                    tmpvar = (uint32) BitstreamReadBits16(stream, 8);
                    /* transfer_characteristics */
                    tmpvar = (uint32) BitstreamReadBits16(stream, 8);
                    /* matrix_coefficients */
                    tmpvar = (uint32) BitstreamReadBits16(stream, 8);
                }
            }
        }
        else
        {
            do
            {
                /* Search for VOL_HEADER */
                status = PVSearchNextM4VFrame(stream); /* search 0x00 0x00 0x01 */
                if (status != PV_SUCCESS) return PV_FAIL; /* breaks the loop */
                BitstreamShowBits32(stream, VOL_START_CODE_LENGTH, &tmpvar);
                PV_BitstreamFlushBits(stream, 8);
            }
            while (tmpvar != VOL_START_CODE);
            goto decode_vol;
        }

        /* next_start_code() */
        status = PV_BitstreamByteAlign(stream);                            /*  10/12/01 */
        status = BitstreamShowBits32HC(stream, &tmpvar);

        if (tmpvar == USER_DATA_START_CODE)
        {
            /* Something has to be done to deal with user data (parse it)  11/11/99 */
            status = DecodeUserData(stream);
            if (status != PV_SUCCESS) return PV_FAIL;
        }
        status = BitstreamShowBits32(stream, 27, &tmpvar);   /*  10/12/01 */
    }
    else
    {
        /*      tmpvar = 0;   */                                             /*  10/12/01 */
        status = BitstreamShowBits32(stream, 27, &tmpvar);     /* uncomment this line if you want
                                                                     to start decoding with a
                                                                     video_object_start_code */
    }

    if (tmpvar == VO_START_CODE)
    {
        /*****
        *
        *   Read the VOL header entries from the bitstream
        *
        *****/
        /* video_object_start_code                         */
        tmpvar = BitstreamReadBits32(stream, 27);
        tmpvar = (uint32) BitstreamReadBits16(stream, 5);


        /* video_object_layer_start_code                   */
        BitstreamShowBits32(stream, VOL_START_CODE_LENGTH, &tmpvar);
        if (tmpvar != VOL_START_CODE)
        {
            status = BitstreamCheckEndBuffer(stream);
            if (status == PV_END_OF_VOP)
            {
                video->shortVideoHeader = TRUE;
                return PV_SUCCESS;
            }
            else
            {
                do
                {
                    /* Search for VOL_HEADER */
                    status = PVSearchNextM4VFrame(stream);/* search 0x00 0x00 0x01 */
                    if (status != PV_SUCCESS) return PV_FAIL; /* breaks the loop */
                    BitstreamShowBits32(stream, VOL_START_CODE_LENGTH, &tmpvar);
                    PV_BitstreamFlushBits(stream, 8); /* advance the byte ptr */
                }
                while (tmpvar != VOL_START_CODE);
            }
        }
        else
        {
            PV_BitstreamFlushBits(stream, 8);
        }

decode_vol:
        PV_BitstreamFlushBits(stream, VOL_START_CODE_LENGTH - 8);
        video->shortVideoHeader = 0;

        /* vol_id (4 bits) */
        currVol->volID = (int) BitstreamReadBits16(stream, 4);

        /* RandomAccessible flag */
        tmpvar = (uint32) BitstreamRead1Bits(stream);

        /* object type */
        tmpvar = (uint32) BitstreamReadBits16(stream, 8);                /*  */

#ifdef PV_TOLERATE_VOL_ERRORS
        if (tmpvar == 0)
        {
            if (layer)                                                      /*    */
            {
                /* support SSPL0-2  */
                if (profile != 0x10 && profile != 0x11 && profile != 0x12)
                    return PV_FAIL;
                tmpvar = 0x02;
            }
            else
            {
                /* support SPL0-3 & SSPL0-2   */
                if (profile != 0x01 && profile != 0x02 && profile != 0x03 && profile != 0x08 &&
                        profile != 0x10 && profile != 0x11 && profile != 0x12)
                    return PV_FAIL;
                tmpvar = 0x01;
            }
            profile |= 0x0100;
        }
#endif

        if (layer)
        {
            if (tmpvar != 0x02) return PV_FAIL;
        }
        else
        {
            // Simple and advanced simple (for quant-type 1)
            if (tmpvar != 0x01 && tmpvar != 0x11) return PV_FAIL;
        }

        /* version id specified? */
        tmpvar = (uint32) BitstreamRead1Bits(stream);
        if (tmpvar == 1)
        {
            /* version ID */
            version_id = (uint32) BitstreamReadBits16(stream, 4);
            /* priority */
            tmpvar = (uint32) BitstreamReadBits16(stream, 3);

        }

        /* aspect ratio info */
        tmpvar = (uint32) BitstreamReadBits16(stream, 4);
        if (tmpvar == 0) return PV_FAIL;
        if (tmpvar == 0xf /* extended_par */)
        {
            /* width */
            tmpvar = (uint32) BitstreamReadBits16(stream, 8);
            /* height */
            tmpvar = (uint32) BitstreamReadBits16(stream, 8);
        }


        /* control parameters present? */
        tmpvar = (uint32) BitstreamRead1Bits(stream);

        /*  Get the parameters (skipped) */
        /*  03/10/99 */
        if (tmpvar)
        {
            /* chroma_format                    */
            tmpvar = BitstreamReadBits16(stream, 2);
            if (tmpvar != 1) return PV_FAIL;
            /* low_delay  */
            tmpvar = BitstreamRead1Bits(stream);

            /* vbv_parameters present? */
            tmpvar = (uint32) BitstreamRead1Bits(stream);
            if (tmpvar)
            {
                /* first_half_bit_rate    */
                BitstreamReadBits16(stream, 15);
                if (!BitstreamRead1Bits(stream)) return PV_FAIL;
                /* latter_half_bit_rate   */
                BitstreamReadBits16(stream, 15);
                if (!BitstreamRead1Bits(stream)) return PV_FAIL;
                /* first_half_vbv_buffer_size   */
                BitstreamReadBits16(stream, 15);
                if (!BitstreamRead1Bits(stream)) return PV_FAIL;
                /* latter_half_vbv_buffer_size   */
                BitstreamReadBits16(stream,  3);
                /* first_half_vbv_occupancy     */
                BitstreamReadBits16(stream, 11);
                if (!BitstreamRead1Bits(stream)) return PV_FAIL;
                /* latter_half_vbv_occupancy  */
                BitstreamReadBits16(stream, 15);
                if (!BitstreamRead1Bits(stream)) return PV_FAIL;
            }
        }

        /* video_object_layer_shape (2 bits), only 00 (rect) is supported for now */
        vol_shape = (uint32) BitstreamReadBits16(stream, 2);
        if (vol_shape) return PV_FAIL;

        /* marker bit,  03/10/99 */
        if (!BitstreamRead1Bits(stream)) return PV_FAIL;

        /* vop_time_increment_resolution   */
        currVol->timeIncrementResolution = BitstreamReadBits16(stream, 16);
        if (currVol->timeIncrementResolution == 0) return PV_FAIL;

        /* . since nbitsTimeIncRes will be used over and over again, */
        /*    we should put it in Vol structure.  04/12/2000.          */
        currVol->nbitsTimeIncRes = CalcNumBits((uint)currVol->timeIncrementResolution - 1);

        if (!BitstreamRead1Bits(stream)) return PV_FAIL;

        /* fixed_vop_rate */
        currVol->fixedVopRate = (int) BitstreamRead1Bits(stream);
        if (currVol->fixedVopRate)
        {
            /* fixed_vop_time_increment */
            tmpvar = BitstreamReadBits16(stream, currVol->nbitsTimeIncRes);
        }

        /* marker bit */
        if (!BitstreamRead1Bits(stream)) return PV_FAIL;

        /* video_object_layer_width (13 bits) */
        tmpvar = BitstreamReadBits16(stream, 13);
        if (!tmpvar) return PV_FAIL;
        video->displayWidth = video->width = tmpvar;

        /* round up to a multiple of MB_SIZE.   08/09/2000 */
        video->width = (video->width + 15) & -16;
//      video->displayWidth += (video->displayWidth & 0x1);  /* displayed image should be even size */

        /* marker bit */
        if (!BitstreamRead1Bits(stream)) return PV_FAIL;

        /* video_object_layer_height (13 bits) */
        tmpvar = BitstreamReadBits16(stream, 13);
        if (!tmpvar) return PV_FAIL;
        video->displayHeight = video->height = tmpvar;

        /* round up to a multiple of MB_SIZE.   08/09/2000 */
        video->height = (video->height + 15) & -16;
//      video->displayHeight += (video->displayHeight & 0x1); /* displayed image should be even size */
        if (!BitstreamRead1Bits(stream)) return PV_FAIL;

        /*  03/10/99 */
        /* interlaced */
        tmpvar = (uint32) BitstreamRead1Bits(stream);
        if (tmpvar != 0)
        {
            mp4dec_log("DecodeVOLHeader(): Interlaced video is not supported.\n");
            return PV_FAIL;
        }

        /* obmc_disable */
        tmpvar = (uint32) BitstreamRead1Bits(stream);
        if (tmpvar == 0) return PV_FAIL;

        if (version_id == 1)
        {
            /*  sprite_enable (1 bits) */
            tmpvar = (uint32) BitstreamRead1Bits(stream);
            if (tmpvar)
            {
                mp4dec_log("DecodeVOLHeader(): Sprite is not supported.\n");
                return PV_FAIL;
            }
        }
        else
        {
            /* For version 2, vol_sprite_usage has two bits. */
            /* sprite_enable */
            tmpvar = (uint32) BitstreamReadBits16(stream, 2);
            if (tmpvar)
            {
                mp4dec_log("DecodeVOLHeader(): Sprite is not supported.\n");
                return PV_FAIL;
            }
        }

        /* not_8_bit */
        if (BitstreamRead1Bits(stream))
        {
            /* quant_precision */
            currVol->quantPrecision = BitstreamReadBits16(stream, 4);
            /* bits_per_pixel  */
            currVol->bitsPerPixel = BitstreamReadBits16(stream, 4);
            mp4dec_log("DecodeVOLHeader(): not an 8-bit stream.\n");    // For the time being we do not support != 8 bits

            return PV_FAIL;
        }
        else
        {
            currVol->quantPrecision = 5;
            currVol->bitsPerPixel = 8;
        }

        /* quant_type (1 bit) */
        currVol->quantType = BitstreamRead1Bits(stream);
        if (currVol->quantType)
        {
            /* load quantization matrices.   5/22/2000 */
            /* load_intra_quant_mat (1 bit) */
            qmat = currVol->iqmat;
            currVol->loadIntraQuantMat = BitstreamRead1Bits(stream);
            if (currVol->loadIntraQuantMat)
            {
                /* intra_quant_mat (8*64 bits) */
                i = 0;
                do
                {
                    qmat[*(zigzag_inv+i)] = (int) BitstreamReadBits16(stream, 8);
                }
                while ((qmat[*(zigzag_inv+i)] != 0) && (++i < 64));

                /* qmatrix must have at least one non-zero value, which means
                   i would be non-zero in valid cases */
                if (i == 0)
                {
                    return PV_FAIL;
                }

                for (j = i; j < 64; j++)
                    qmat[*(zigzag_inv+j)] = qmat[*(zigzag_inv+i-1)];
            }
            else
            {
                oscl_memcpy(qmat, mpeg_iqmat_def, 64*sizeof(int));
            }

            qmat[0] = 0;             /* necessary for switched && MPEG quant  07/09/01 */

            /* load_nonintra_quant_mat (1 bit) */
            qmat = currVol->niqmat;
            currVol->loadNonIntraQuantMat = BitstreamRead1Bits(stream);
            if (currVol->loadNonIntraQuantMat)
            {
                /* nonintra_quant_mat (8*64 bits) */
                i = 0;
                do
                {
                    qmat[*(zigzag_inv+i)] = (int) BitstreamReadBits16(stream, 8);
                }
                while ((qmat[*(zigzag_inv+i)] != 0) && (++i < 64));

                /* qmatrix must have at least one non-zero value, which means
                   i would be non-zero in valid cases */
                if (i == 0)
                {
                    return PV_FAIL;
                }

                for (j = i; j < 64; j++)
                    qmat[*(zigzag_inv+j)] = qmat[*(zigzag_inv+i-1)];
            }
            else
            {
                oscl_memcpy(qmat, mpeg_nqmat_def, 64*sizeof(int));
            }
        }

        if (version_id != 1)
        {
            /* quarter_sample enabled */
            tmpvar = BitstreamRead1Bits(stream);
            if (tmpvar) return PV_FAIL;
        }

        /* complexity_estimation_disable */
        currVol->complexity_estDisable = BitstreamRead1Bits(stream);
        if (currVol->complexity_estDisable == 0)
        {
            currVol->complexity_estMethod = BitstreamReadBits16(stream, 2);

            if (currVol->complexity_estMethod < 2)
            {
                /* shape_complexity_estimation_disable */
                tmpvar = BitstreamRead1Bits(stream);
                if (tmpvar == 0)
                {
                    mp4dec_log("DecodeVOLHeader(): Shape Complexity estimation is not supported.\n");
                    return PV_FAIL;
                }
                /* texture_complexity_estimation_set_1_disable */
                tmpvar = BitstreamRead1Bits(stream);
                if (tmpvar == 0)
                {
                    currVol->complexity.text_1 = BitstreamReadBits16(stream, 4);
                }
                /* marker bit */
                if (!BitstreamRead1Bits(stream)) return PV_FAIL;
                /* texture_complexity_estimation_set_2_disable */
                tmpvar = BitstreamRead1Bits(stream);
                if (tmpvar == 0)
                {
                    currVol->complexity.text_2 = BitstreamReadBits16(stream, 4);
                }
                /* motion_compensation_complexity_disable */
                tmpvar = BitstreamRead1Bits(stream);
                if (tmpvar == 0)
                {
                    currVol->complexity.mc = BitstreamReadBits16(stream, 6);
                }
                /* marker bit */
                if (!BitstreamRead1Bits(stream)) return PV_FAIL;

                if (currVol->complexity_estMethod == 1)
                {   /* version2_complexity_estimation_disable */
                    tmpvar = BitstreamRead1Bits(stream);
                    if (tmpvar == 0)
                    {
                        mp4dec_log("DecodeVOLHeader(): sadct, quarter pel not supported.\n");
                        return PV_FAIL;
                    }
                }
            }
        }

        /*  03/10/99 */
        /* resync_marker_disable */
        currVol->errorResDisable = (int) BitstreamRead1Bits(stream);
        /* data_partititioned    */
        currVol->dataPartitioning = (int) BitstreamRead1Bits(stream);

        video->vlcDecCoeffIntra = &VlcDecTCOEFIntra;
        video->vlcDecCoeffInter = &VlcDecTCOEFInter;

        if (currVol->dataPartitioning)
        {
            if (layer) return PV_FAIL;                              /*  */
            /* reversible_vlc */
            currVol->useReverseVLC = (int)BitstreamRead1Bits(stream);
            if (currVol->useReverseVLC)
            {
                video->vlcDecCoeffIntra = &RvlcDecTCOEFIntra;
                video->vlcDecCoeffInter = &RvlcDecTCOEFInter;
            }
            currVol->errorResDisable = 0;
        }
        else
        {
            currVol->useReverseVLC = 0;
        }

        if (version_id != 1)
        {
            /* newpred_enable */
            tmpvar = BitstreamRead1Bits(stream);
            if (tmpvar) return PV_FAIL;

            /* reduced_resolution_vop */
            tmpvar = BitstreamRead1Bits(stream);
            if (tmpvar) return PV_FAIL;

        }

        /* Intra AC/DC prediction is always true */
        video->intra_acdcPredDisable = 0;
        /* scalability */
        currVol->scalability = (int) BitstreamRead1Bits(stream);

        if (currVol->scalability)
        {
            if (layer == 0)  return PV_FAIL;                     /*  */
            /* hierarchy_type: 1 : temporal, 0 : spatial */
            /*  03/10/99 */
            currVol->scalType = (int) BitstreamRead1Bits(stream);              /*  */
            if (!currVol->scalType) return PV_FAIL;

            /* ref_layer_id (4 bits) */
            currVol->refVolID = (int) BitstreamReadBits16(stream, 4);
            if (layer)                                                      /*  */
            {
                if (currVol->refVolID != video->vol[0]->volID) return PV_FAIL;
            }
            /* ref_layer_sampling_direc (1 bits)              */
            /*   1 : ref. layer has higher resolution         */
            /*   0 : ref. layer has equal or lower resolution */
            currVol->refSampDir = (int) BitstreamRead1Bits(stream);
            if (currVol->refSampDir) return PV_FAIL;

            /* hor_sampling_factor_n (5 bits) */
            currVol->horSamp_n = (int) BitstreamReadBits16(stream, 5);

            /* hor_sampling_factor_m (5 bits) */
            currVol->horSamp_m = (int) BitstreamReadBits16(stream, 5);

            if (currVol->horSamp_m == 0) return PV_FAIL;
            if (currVol->horSamp_n != currVol->horSamp_m) return PV_FAIL;

            /* ver_sampling_factor_n (5 bits) */
            currVol->verSamp_n = (int) BitstreamReadBits16(stream, 5);

            /* ver_sampling_factor_m (5 bits) */
            currVol->verSamp_m = (int) BitstreamReadBits16(stream, 5);

            if (currVol->verSamp_m == 0) return PV_FAIL;
            if (currVol->verSamp_n != currVol->verSamp_m) return PV_FAIL;


            /* enhancement_type: 1 : partial region, 0 : full region */
            /* 04/10/2000: we only support full region enhancement layer. */
            if (BitstreamRead1Bits(stream)) return PV_FAIL;
        }

        PV_BitstreamByteAlign(stream);

        status = BitstreamShowBits32HC(stream, &tmpvar);

        /* if we hit the end of buffer, tmpvar == 0.   08/30/2000 */
        if (tmpvar == USER_DATA_START_CODE)
        {
            status = DecodeUserData(stream);
            /* you should not check for status here  03/19/2002 */
            status = PV_SUCCESS;
        }

        /* Compute some convenience variables:   04/13/2000 */
        video->nMBPerRow = video->width / MB_SIZE;
        video->nMBPerCol = video->height / MB_SIZE;
        video->nTotalMB = video->nMBPerRow * video->nMBPerCol;
        video->nBitsForMBID = CalcNumBits((uint)video->nTotalMB - 1);
#ifdef PV_ANNEX_IJKT_SUPPORT
        video->modified_quant = 0;
        video->advanced_INTRA = 0;
        video->deblocking = 0;
        video->slice_structure = 0;
#endif
    }
    else
    {
        /* SHORT_HEADER */
        status = BitstreamShowBits32(stream, SHORT_VIDEO_START_MARKER_LENGTH, &tmpvar);

        if (tmpvar == SHORT_VIDEO_START_MARKER)
        {
            video->shortVideoHeader = TRUE;
        }
        else
        {
            do
            {
                /* Search for VOL_HEADER */
                status = PVSearchNextM4VFrame(stream); /* search 0x00 0x00 0x01 */
                if (status != PV_SUCCESS) return PV_FAIL; /* breaks the loop */
                BitstreamShowBits32(stream, VOL_START_CODE_LENGTH, &tmpvar);
                PV_BitstreamFlushBits(stream, 8);
            }
            while (tmpvar != VOL_START_CODE);
            goto decode_vol;
        }
    }
#ifdef PV_TOLERATE_VOL_ERRORS
    if (profile > 0xFF || profile == 0)
    {
        return PV_BAD_VOLHEADER;
    }
#endif

    return status;
}


/***********************************************************CommentBegin******
*
* -- DecodeGOV -- Decodes the Group of VOPs from bitstream
*
*   04/20/2000  initial modification to the new PV-Decoder Lib format.
*
***********************************************************CommentEnd********/
PV_STATUS DecodeGOVHeader(BitstreamDecVideo *stream, uint32 *time_base)
{
    uint32 tmpvar, time_s;
    int closed_gov, broken_link;

    /* group_start_code (32 bits) */
//   tmpvar = BitstreamReadBits32(stream, 32);

    /* hours */
    tmpvar = (uint32) BitstreamReadBits16(stream, 5);
    time_s = tmpvar * 3600;

    /* minutes */
    tmpvar = (uint32) BitstreamReadBits16(stream, 6);
    time_s += tmpvar * 60;

    /* marker bit */
    tmpvar = (uint32) BitstreamRead1Bits(stream);

    /* seconds */
    tmpvar = (uint32) BitstreamReadBits16(stream, 6);
    time_s += tmpvar;

    /* We have to check the timestamp here.  If the sync timestamp is */
    /*    earlier than the previous timestamp or longer than 60 sec.  */
    /*    after the previous timestamp, assume the GOV header is      */
    /*    corrupted.                                 05/12/2000     */
    *time_base = time_s;   /*  02/27/2002 */
//  *time_base = *time_base/1000;
//  tmpvar = time_s - *time_base;
//  if (tmpvar <= 60) *time_base = time_s;
//  else return PV_FAIL;

    tmpvar = (uint32) BitstreamRead1Bits(stream);
    closed_gov = tmpvar;
    tmpvar = (uint32) BitstreamRead1Bits(stream);
    broken_link = tmpvar;

    if ((closed_gov == 0) && (broken_link == 1))
    {
        return PV_SUCCESS;        /*  03/15/2002  you can also return PV_FAIL */
    }

    PV_BitstreamByteAlign(stream);

    BitstreamShowBits32HC(stream, &tmpvar);

    while (tmpvar == USER_DATA_START_CODE)       /*  03/15/2002 */
    {
        DecodeUserData(stream);
        BitstreamShowBits32HC(stream, &tmpvar);
    }

    return PV_SUCCESS;
}

/***********************************************************CommentBegin******
*
* -- DecodeVopHeader -- Decodes the VOPheader information from the bitstream
*
*   04/12/2000  Initial port to the new PV decoder library format.
*   05/10/2000  Error resilient decoding of vop header.
*
***********************************************************CommentEnd********/
PV_STATUS DecodeVOPHeader(VideoDecData *video, Vop *currVop, Bool use_ext_timestamp)
{
    PV_STATUS status = PV_SUCCESS;
    Vol *currVol = video->vol[video->currLayer];
    BitstreamDecVideo *stream = currVol->bitstream;
    uint32 tmpvar;
    int time_base;

    /*****
    *   Read the VOP header from the bitstream (No shortVideoHeader Mode here!)
    *****/
    BitstreamShowBits32HC(stream, &tmpvar);

    /* check if we have a GOV header here.   08/30/2000 */
    if (tmpvar == GROUP_START_CODE)
    {
        tmpvar = BitstreamReadBits32HC(stream);
//      rewindBitstream(stream, START_CODE_LENGTH); /* for backward compatibility */
        status = DecodeGOVHeader(stream, &tmpvar);
        if (status != PV_SUCCESS)
        {
            return status;
        }
//      use_ext_timestamp = TRUE;   /*  02/08/2002 */
        /* We should have a VOP header following the GOV header.  03/15/2001 */
        BitstreamShowBits32HC(stream, &tmpvar);
    }
#ifdef PV_SUPPORT_TEMPORAL_SCALABILITY
    currVop->timeStamp = -1;
#endif
    if (tmpvar == VOP_START_CODE)
    {
        tmpvar = BitstreamReadBits32HC(stream);
    }
    else
    {
        PV_BitstreamFlushBits(stream, 8); // advance by a byte
        status = PV_FAIL;
        goto return_point;
    }



    /* vop_prediction_type (2 bits) */
    currVop->predictionType = (int) BitstreamReadBits16(stream, 2);

    /* modulo_time_base (? bits) */
    time_base = -1;
    do
    {
        time_base++;
        tmpvar = (uint32) BitstreamRead1Bits(stream);
    }
    while (tmpvar == 1);



    if (!use_ext_timestamp)
    {
        currVol->moduloTimeBase += 1000 * time_base; /* milliseconds based MTB  11/12/01 */
    }

    /* marker_bit (1 bit) */
    if (!BitstreamRead1Bits(stream))
    {
        status = PV_FAIL;
        goto return_point;
    }

    /* vop_time_increment (1-15 bits) in Nov_Compliant (1-16 bits) */
    /*    we always assumes fixed vop rate here */
    currVop->timeInc = BitstreamReadBits16(stream, currVol->nbitsTimeIncRes);


    /* marker_bit (1 bit) */
    if (!BitstreamRead1Bits(stream))
    {
        status = PV_FAIL;
        goto return_point;
    }

    /* vop_coded */
    currVop->vopCoded = (int) BitstreamRead1Bits(stream);


    if (currVop->vopCoded == 0)
    {
        status = PV_SUCCESS;
        goto return_point;
    }


    /* read vop_rounding_type */
    if (currVop->predictionType == P_VOP)
    {
        currVop->roundingType = (int) BitstreamRead1Bits(stream);
    }
    else
    {
        currVop->roundingType = 0;
    }

    if (currVol->complexity_estDisable == 0)
    {
        if (currVol->complexity_estMethod < 2)   /*   OCT 2002 */
        {
            if ((currVol->complexity.text_1 >> 3) & 0x1)    /* intra        */
                BitstreamReadBits16(stream, 8);
            if (currVol->complexity.text_1 & 0x1)           /* not_coded    */
                BitstreamReadBits16(stream, 8);
            if ((currVol->complexity.text_2 >> 3) & 0x1)    /* dct_coefs    */
                BitstreamReadBits16(stream, 8);
            if ((currVol->complexity.text_2 >> 2) & 0x1)    /* dct_lines    */
                BitstreamReadBits16(stream, 8);
            if ((currVol->complexity.text_2 >> 1) & 0x1)    /* vlc_symbols  */
                BitstreamReadBits16(stream, 8);
            if (currVol->complexity.text_2 & 0x1)           /* vlc_bits     */
                BitstreamReadBits16(stream, 4);

            if (currVop->predictionType != I_VOP)
            {
                if ((currVol->complexity.text_1 >> 2) & 0x1)    /* inter    */
                    BitstreamReadBits16(stream, 8);
                if ((currVol->complexity.text_1 >> 1) & 0x1)    /* inter_4v */
                    BitstreamReadBits16(stream, 8);
                if ((currVol->complexity.mc >> 5) & 0x1)        /* apm      */
                    BitstreamReadBits16(stream, 8);
                if ((currVol->complexity.mc >> 4) & 0x1)        /* npm      */
                    BitstreamReadBits16(stream, 8);
                /* interpolate_mc_q */
                if ((currVol->complexity.mc >> 2) & 0x1)        /* forw_back_mc_q */
                    BitstreamReadBits16(stream, 8);
                if ((currVol->complexity.mc >> 1) & 0x1)        /* halfpel2 */
                    BitstreamReadBits16(stream, 8);
                if (currVol->complexity.mc & 0x1)               /* halfpel4 */
                    BitstreamReadBits16(stream, 8);
            }
            if (currVop->predictionType == B_VOP)
            {
                if ((currVol->complexity.mc >> 3) & 0x1)        /* interpolate_mc_q */
                    BitstreamReadBits16(stream, 8);
            }
        }
    }

    /* read intra_dc_vlc_thr */
    currVop->intraDCVlcThr = (int) BitstreamReadBits16(stream, 3);

    /* read vop_quant (currVol->quantPrecision bits) */
    currVop->quantizer = (int16) BitstreamReadBits16(stream, currVol->quantPrecision);
    if (currVop->quantizer == 0)
    {
        currVop->quantizer = video->prevVop->quantizer;
        status = PV_FAIL;
        goto return_point;
    }


    /* read vop_fcode_forward */
    if (currVop->predictionType != I_VOP)
    {
        tmpvar = (uint32) BitstreamReadBits16(stream, 3);
        if (tmpvar < 1)
        {
            currVop->fcodeForward = 1;
            status = PV_FAIL;
            goto return_point;
        }
        currVop->fcodeForward = tmpvar;
    }
    else
    {
        currVop->fcodeForward = 0;
    }

    /* read vop_fcode_backward */
    if (currVop->predictionType == B_VOP)
    {
        tmpvar = (uint32) BitstreamReadBits16(stream, 3);
        if (tmpvar < 1)
        {
            currVop->fcodeBackward = 1;
            status = PV_FAIL;
            goto return_point;
        }
        currVop->fcodeBackward = tmpvar;
    }
    else
    {
        currVop->fcodeBackward = 0;
    }

    if (currVol->scalability)
    {
        currVop->refSelectCode = (int) BitstreamReadBits16(stream, 2);
    }

return_point:
    return status;
}


/***********************************************************CommentBegin******
*
* -- VideoPlaneWithShortHeader -- Decodes the short_video_header information from the bitstream
* Modified :
             04/23/2001.  Remove the codes related to the
                 "first pass" decoding.  We use a different function
                 to set up the decoder now.
***********************************************************CommentEnd********/
PV_STATUS DecodeShortHeader(VideoDecData *video, Vop *currVop)
{
    PV_STATUS status = PV_SUCCESS;
    Vol *currVol = video->vol[0];
    BitstreamDecVideo *stream = currVol->bitstream;
    uint32 tmpvar;
    int32 size;

    int extended_PTYPE = FALSE;
    int UFEP = 0, custom_PFMT = 0, custom_PCF = 0;

    status = BitstreamShowBits32(stream, SHORT_VIDEO_START_MARKER_LENGTH, &tmpvar);

    if (tmpvar !=  SHORT_VIDEO_START_MARKER)
    {
        status = PV_FAIL;
        goto return_point;
    }


    PV_BitstreamFlushBits(stream, SHORT_VIDEO_START_MARKER_LENGTH);

    /* Temporal reference. Using vop_time_increment_resolution = 30000 */
    tmpvar = (uint32) BitstreamReadBits16(stream, 8);
    currVop->temporalRef = (int) tmpvar;


    currVop->timeInc = 0xff & (256 + currVop->temporalRef - video->prevVop->temporalRef);
    currVol->moduloTimeBase += currVop->timeInc; /* mseconds   11/12/01 */
    /* Marker Bit */
    if (!BitstreamRead1Bits(stream))
    {
        mp4dec_log("DecodeShortHeader(): Marker bit wrong.\n");
        status = PV_FAIL;
        goto return_point;
    }

    /* Zero Bit */
    if (BitstreamRead1Bits(stream))
    {
        mp4dec_log("DecodeShortHeader(): Zero bit wrong.\n");
        status = PV_FAIL;
        goto return_point;
    }

    /*split_screen_indicator*/
    if (BitstreamRead1Bits(stream))
    {
        mp4dec_log("DecodeShortHeader(): Split Screen not supported.\n");
        VideoDecoderErrorDetected(video);
    }

    /*document_freeze_camera*/
    if (BitstreamRead1Bits(stream))
    {
        mp4dec_log("DecodeShortHeader(): Freeze Camera not supported.\n");
        VideoDecoderErrorDetected(video);
    }

    /*freeze_picture_release*/
    if (BitstreamRead1Bits(stream))
    {
        mp4dec_log("DecodeShortHeader(): Freeze Release not supported.\n");
        VideoDecoderErrorDetected(video);
    }
    /* source format */
    switch (BitstreamReadBits16(stream, 3))
    {
        case 1:
            if (video->size < 128*96)
            {
                status = PV_FAIL;
                goto return_point;
            }
            video->displayWidth = video->width =  128;
            video->displayHeight = video->height  = 96;
            break;

        case 2:
            if (video->size < 176*144)
            {
                status = PV_FAIL;
                goto return_point;
            }
            video->displayWidth = video->width  = 176;
            video->displayHeight = video->height  = 144;
            break;

        case 3:
            if (video->size < 352*288)
            {
                status = PV_FAIL;
                goto return_point;
            }
            video->displayWidth = video->width = 352;
            video->displayHeight = video->height = 288;
            break;

        case 4:
            if (video->size < 704*576)
            {
                status = PV_FAIL;
                goto return_point;
            }
            video->displayWidth = video->width = 704;
            video->displayHeight = video->height = 576;
            break;

        case 5:
            if (video->size < 1408*1152)
            {
                status = PV_FAIL;
                goto return_point;
            }
            video->displayWidth = video->width = 1408;
            video->displayHeight = video->height = 1152;
            break;

        case 7:
            extended_PTYPE = TRUE;
            break;

        default:
            /* Msg("H.263 source format not legal\n"); */
            status = PV_FAIL;
            goto return_point;
    }


    currVop->roundingType = 0;

    if (extended_PTYPE == FALSE)
    {
        currVop->predictionType = (int) BitstreamRead1Bits(stream);

        /* four_reserved_zero_bits */
        if (BitstreamReadBits16(stream, 4))
        {
            mp4dec_log("DecodeShortHeader(): Reserved bits wrong.\n");
            status = PV_FAIL;
            goto return_point;
        }
    }
    else
    {
        UFEP = BitstreamReadBits16(stream, 3);
        if (UFEP == 1)
        {
            /* source format */
            switch (BitstreamReadBits16(stream, 3))
            {
                case 1:
                    if (video->size < 128*96)
                    {
                        status = PV_FAIL;
                        goto return_point;
                    }
                    video->displayWidth = video->width =  128;
                    video->displayHeight = video->height  = 96;
                    break;

                case 2:
                    if (video->size < 176*144)
                    {
                        status = PV_FAIL;
                        goto return_point;
                    }
                    video->displayWidth = video->width  = 176;
                    video->displayHeight = video->height  = 144;
                    break;

                case 3:
                    if (video->size < 352*288)
                    {
                        status = PV_FAIL;
                        goto return_point;
                    }
                    video->displayWidth = video->width = 352;
                    video->displayHeight = video->height = 288;
                    break;

                case 4:
                    if (video->size < 704*576)
                    {
                        status = PV_FAIL;
                        goto return_point;
                    }
                    video->displayWidth = video->width = 704;
                    video->displayHeight = video->height = 576;
                    break;

                case 5:
                    if (video->size < 1408*1152)
                    {
                        status = PV_FAIL;
                        goto return_point;
                    }
                    video->displayWidth = video->width = 1408;
                    video->displayHeight = video->height = 1152;
                    break;

                case 6:
                    custom_PFMT = TRUE;
                    break;

                default:
                    /* Msg("H.263 source format not legal\n"); */
                    status = PV_FAIL;
                    goto return_point;
            }

            custom_PCF = BitstreamRead1Bits(stream);
            /* unrestricted MV */
            if (BitstreamRead1Bits(stream))
            {
                status = PV_FAIL;
                goto return_point;
            }
            /* SAC */
            if (BitstreamRead1Bits(stream))
            {
                status = PV_FAIL;
                goto return_point;
            }

            /* AP */
            if (BitstreamRead1Bits(stream))
            {
                status = PV_FAIL;
                goto return_point;
            }

            video->advanced_INTRA = BitstreamRead1Bits(stream);

            video->deblocking = BitstreamRead1Bits(stream);

            video->slice_structure = BitstreamRead1Bits(stream);

            /* RPS, ISD, AIV */
            if (BitstreamReadBits16(stream, 3))
            {
                status = PV_FAIL;
                goto return_point;
            }
            video->modified_quant = BitstreamRead1Bits(stream);

            /* Marker Bit and reserved*/
            if (BitstreamReadBits16(stream, 4) != 8)
            {
                status = PV_FAIL;
                goto return_point;
            }
        }
#ifndef PV_ANNEX_IJKT_SUPPORT
        if (video->advanced_INTRA | video->deblocking | video->modified_quant | video->modified_quant)
        {
            status = PV_FAIL;
            goto return_point;
        }
#endif

        if (UFEP == 0 || UFEP == 1)
        {
            tmpvar = BitstreamReadBits16(stream, 3);
            if (tmpvar > 1)
            {
                status = PV_FAIL;
                goto return_point;
            }
            currVop->predictionType = tmpvar;
            /* RPR */
            if (BitstreamRead1Bits(stream))
            {
                status = PV_FAIL;
                goto return_point;
            }

            /* RRU */
            if (BitstreamRead1Bits(stream))
            {
                status = PV_FAIL;
                goto return_point;
            }
            currVop->roundingType = (int) BitstreamRead1Bits(stream);
            if (BitstreamReadBits16(stream, 3) != 1)
            {
                status = PV_FAIL;
                goto return_point;
            }
        }
        else
        {
            status = PV_FAIL;
            goto return_point;
        }
        /* CPM */
        if (BitstreamRead1Bits(stream))
        {
            status = PV_FAIL;
            goto return_point;
        }
        /* CPFMT */
        if (custom_PFMT == 1 && UFEP == 1)
        {
            /* aspect ratio */
            tmpvar = BitstreamReadBits16(stream, 4);
            if (tmpvar == 0)
            {
                status = PV_FAIL;
                goto return_point;
            }
            /* Extended PAR */
            if (tmpvar == 0xF)
            {
                /* Read par_width and par_height but do nothing */
                /* par_width */
                tmpvar = BitstreamReadBits16(stream, 8);

                /* par_height */
                tmpvar = BitstreamReadBits16(stream, 8);
            }
            tmpvar = BitstreamReadBits16(stream, 9);

            int tmpDisplayWidth = (tmpvar + 1) << 2;
            /* marker bit */
            if (!BitstreamRead1Bits(stream))
            {
                status = PV_FAIL;
                goto return_point;
            }
            tmpvar = BitstreamReadBits16(stream, 9);
            if (tmpvar == 0)
            {
                status = PV_FAIL;
                goto return_point;
            }
            int tmpDisplayHeight = tmpvar << 2;
            int tmpHeight = (tmpDisplayHeight + 15) & -16;
            int tmpWidth = (tmpDisplayWidth + 15) & -16;

            if (tmpWidth > video->width)
            {
                // while allowed by the spec, this decoder does not actually
                // support an increase in size.
                ALOGE("width increase not supported");
                status = PV_FAIL;
                goto return_point;
            }
            if (tmpHeight * tmpWidth > video->size)
            {
                // This is just possibly "b/37079296".
                ALOGE("b/37079296");
                status = PV_FAIL;
                goto return_point;
            }
            video->displayWidth = tmpDisplayWidth;
            video->width = tmpWidth;
            video->displayHeight = tmpDisplayHeight;
            video->height = tmpHeight;

            video->nTotalMB = video->width / MB_SIZE * video->height / MB_SIZE;

            if (video->nTotalMB <= 48)
            {
                video->nBitsForMBID = 6;
            }
            else if (video->nTotalMB <= 99)
            {
                video->nBitsForMBID = 7;
            }
            else if (video->nTotalMB <= 396)
            {
                video->nBitsForMBID = 9;
            }
            else if (video->nTotalMB <= 1584)
            {
                video->nBitsForMBID = 11;
            }
            else if (video->nTotalMB <= 6336)
            {
                video->nBitsForMBID = 13 ;
            }
            else if (video->nTotalMB <= 9216)
            {
                video->nBitsForMBID = 14 ;
            }
            else
            {
                status = PV_FAIL;
                goto return_point;
            }
        }
        if (UFEP == 1 && custom_PCF == 1)
        {
            BitstreamRead1Bits(stream);

            tmpvar = BitstreamReadBits16(stream, 7);
            if (tmpvar == 0)
            {
                status = PV_FAIL;
                goto return_point;
            }
        }

        if (custom_PCF == 1)
        {
            currVop->ETR = BitstreamReadBits16(stream, 2);
        }

        if (UFEP == 1 && video->slice_structure == 1)
        {
            /* SSS */
            tmpvar = BitstreamReadBits16(stream, 2);
            if (tmpvar != 0)
            {
                status = PV_FAIL;
                goto return_point;
            }
        }
    }

    /* Recalculate number of macroblocks per row & col since */
    /*  the frame size can change.           04/23/2001.   */
    video->nMBinGOB = video->nMBPerRow = video->width / MB_SIZE;
    video->nGOBinVop = video->nMBPerCol = video->height / MB_SIZE;
    video->nTotalMB = video->nMBPerRow * video->nMBPerCol;
    if (custom_PFMT == 0  || UFEP == 0)
    {
        video->nBitsForMBID = CalcNumBits((uint)video->nTotalMB - 1); /* otherwise calculate above */
    }
    size = (int32)video->width * video->height;
    if (currVop->predictionType == P_VOP && size > video->videoDecControls->size)
    {
        status = PV_FAIL;
        goto return_point;
    }
    video->videoDecControls->size = size;
    video->currVop->uChan = video->currVop->yChan + size;
    video->currVop->vChan = video->currVop->uChan + (size >> 2);
    video->prevVop->uChan = video->prevVop->yChan + size;
    video->prevVop->vChan = video->prevVop->uChan + (size >> 2);


    currVop->quantizer = (int16) BitstreamReadBits16(stream, 5);

    if (currVop->quantizer == 0)                          /*  04/03/01 */
    {
        currVop->quantizer = video->prevVop->quantizer;
        status = PV_FAIL;
        goto return_point;
    }


    /* Zero bit */
    if (extended_PTYPE == FALSE)
    {
        if (BitstreamRead1Bits(stream))
        {
            mp4dec_log("DecodeShortHeader(): Zero bit wrong.\n");
            status = PV_FAIL;
            goto return_point;
        }
    }
    /* pei */
    tmpvar = (uint32) BitstreamRead1Bits(stream);

    while (tmpvar)
    {
        tmpvar = (uint32) BitstreamReadBits16(stream, 8); /* "PSPARE" */
        tmpvar = (uint32) BitstreamRead1Bits(stream); /* "PEI" */
    }

    if (video->slice_structure)  /* ANNEX_K */
    {
        if (!BitstreamRead1Bits(stream))  /* SEPB1 */
        {
            status = PV_FAIL;
            goto return_point;
        }

        //  if (currVol->nBitsForMBID //
        if (BitstreamReadBits16(stream, video->nBitsForMBID))
        {
            status = PV_FAIL;             /* no ASO, RS support for Annex K */
            goto return_point;
        }

        if (!BitstreamRead1Bits(stream))  /*SEPB3 */
        {
            status = PV_FAIL;
            goto return_point;
        }

    }
    /* Setting of other VOP-header parameters */
    currVop->gobNumber = 0;
    currVop->vopCoded = 1;

    currVop->intraDCVlcThr = 0;
    currVop->gobFrameID = 0; /* initial value,  05/22/00 */
    currVol->errorResDisable = 0;
    /*PutVopInterlaced(0,curr_vop); no implemented yet */
    if (currVop->predictionType != I_VOP)
        currVop->fcodeForward = 1;
    else
        currVop->fcodeForward = 0;

return_point:

    return status;
}
/***********************************************************CommentBegin******
*
* -- PV_DecodeVop -- Decodes the VOP information from the bitstream
*
*   04/12/2000
*                   Initial port to the new PV decoder library format.
*                   This function is different from the one in MoMuSys MPEG-4
*                   visual decoder.  We handle combined mode with or withput
*                   error resilience and H.263 mode through the sam path now.
*
*   05/04/2000
*                   Added temporal scalability to the decoder.
*
***********************************************************CommentEnd********/
PV_STATUS PV_DecodeVop(VideoDecData *video)
{
    Vol *currVol = video->vol[video->currLayer];
    PV_STATUS status;
    uint32 tmpvar;

    /*****
    *   Do scalable or non-scalable decoding of the current VOP
    *****/

    if (!currVol->scalability)
    {
        if (currVol->dataPartitioning)
        {
            /* Data partitioning mode comes here */
            status = DecodeFrameDataPartMode(video);
        }
        else
        {
            /* Combined mode with or without error resilience */
            /*    and short video header comes here.          */
            status = DecodeFrameCombinedMode(video);
        }
    }
    else
    {
#ifdef DO_NOT_FOLLOW_STANDARD
        /* according to the standard, only combined mode is allowed */
        /*    in the enhancement layer.          06/01/2000.        */
        if (currVol->dataPartitioning)
        {
            /* Data partitioning mode comes here */
            status = DecodeFrameDataPartMode(video);
        }
        else
        {
            /* Combined mode with or without error resilience */
            /*    and short video header comes here.          */
            status = DecodeFrameCombinedMode(video);
        }
#else
        status = DecodeFrameCombinedMode(video);
#endif
    }

    /* This part is for consuming Visual_object_sequence_end_code and EOS Code */   /*  10/15/01 */
    if (!video->shortVideoHeader)
    {
        /* at this point bitstream is expected to be byte aligned */
        BitstreamByteAlignNoForceStuffing(currVol->bitstream);

        status = BitstreamShowBits32HC(currVol->bitstream, &tmpvar);  /*  07/07/01 */
        if (tmpvar == VISUAL_OBJECT_SEQUENCE_END_CODE)/* VOS_END_CODE */
        {
            PV_BitstreamFlushBits(currVol->bitstream, 16);
            PV_BitstreamFlushBits(currVol->bitstream, 16);
        }

    }
    else
    {
#ifdef PV_ANNEX_IJKT_SUPPORT
        if (video->deblocking)
        {
            H263_Deblock(video->currVop->yChan, video->width, video->height, video->QPMB, video->headerInfo.Mode, 0, 0);
            H263_Deblock(video->currVop->uChan, video->width >> 1, video->height >> 1, video->QPMB, video->headerInfo.Mode, 1, video->modified_quant);
            H263_Deblock(video->currVop->vChan, video->width >> 1, video->height >> 1, video->QPMB, video->headerInfo.Mode, 1, video->modified_quant);
        }
#endif
        /* Read EOS code for shortheader bitstreams    */
        status = BitstreamShowBits32(currVol->bitstream, 22, &tmpvar);
        if (tmpvar == SHORT_VIDEO_END_MARKER)
        {
            PV_BitstreamFlushBits(currVol->bitstream, 22);
        }
        else
        {
            status = PV_BitstreamShowBitsByteAlign(currVol->bitstream, 22, &tmpvar);
            if (tmpvar == SHORT_VIDEO_END_MARKER)
            {
                PV_BitstreamByteAlign(currVol->bitstream);
                PV_BitstreamFlushBits(currVol->bitstream, 22);
            }
        }
    }
    return status;
}


/***********************************************************CommentBegin******
*
* -- CalcVopDisplayTime -- calculate absolute time when VOP is to be displayed
*
*   04/12/2000 Initial port to the new PV decoder library format.
*
***********************************************************CommentEnd********/
uint32 CalcVopDisplayTime(Vol *currVol, Vop *currVop, int shortVideoHeader)
{
    uint32 display_time;


    /*****
    *   Calculate the time when the VOP is to be displayed next
    *****/

    if (!shortVideoHeader)
    {
        display_time = (uint32)(currVol->moduloTimeBase + (((int32)currVop->timeInc - (int32)currVol->timeInc_offset) * 1000) / ((int32)currVol->timeIncrementResolution));  /*  11/12/2001 */
        if (currVop->timeStamp >= display_time)
        {
            display_time += 1000;  /* this case is valid if GOVHeader timestamp is ignored */
        }
    }
    else
    {
        display_time = (uint32)(currVol->moduloTimeBase * 33 + (currVol->moduloTimeBase * 11) / 30); /*  11/12/2001 */
    }

    return(display_time);
}

