/* ------------------------------------------------------------------
 * 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 "mp4dec_lib.h"
#include "vlc_decode.h"
#include "bitstream.h"


/***********************************************************CommentBegin******
*       04/13/2000 : initial modification to the new PV-Decoder
*                            Lib format.
*       04/16/2001 : Removed PV_END_OF_BUFFER case, error resilience
***********************************************************CommentEnd********/
PV_STATUS PV_ReadVideoPacketHeader(VideoDecData *video, int *next_MB)
{
    PV_STATUS status;
    Vol *currVol = video->vol[video->currLayer];
    Vop *currVop = video->currVop;
    BitstreamDecVideo *stream = video->bitstream;
    int fcode_forward;
    int resync_marker_length;
    int nbits = video->nBitsForMBID;
    uint32 tmpvar32;
    uint tmpvar16;
    int16 quantizer;
    int nTotalMB = video->nTotalMB;

    fcode_forward = currVop->fcodeForward;
    resync_marker_length = 17;

    if (currVop->predictionType != I_VOP) resync_marker_length = 16 + fcode_forward;

    status = PV_BitstreamShowBitsByteAlign(stream, resync_marker_length, &tmpvar32);
    /*  if (status != PV_SUCCESS && status != PV_END_OF_BUFFER) return status; */
    if (tmpvar32 == RESYNC_MARKER)
    {
//      DecNextStartCode(stream);
        PV_BitstreamByteAlign(stream);
        BitstreamReadBits32(stream, resync_marker_length);

        int mbnum = (int) BitstreamReadBits16(stream, nbits);
        if (mbnum < 0) {
            return PV_FAIL;
        }
        *next_MB = mbnum;
//      if (*next_MB <= video->mbnum)   /*  needs more investigation */
//          *next_MB = video->mbnum+1;

        if (*next_MB >= nTotalMB)  /* fix  04/05/01 */
        {
            *next_MB = video->mbnum + 1;
            if (*next_MB >= nTotalMB)    /* this check is needed  */
                *next_MB = nTotalMB - 1;
        }
        quantizer = (int16) BitstreamReadBits16(stream, currVol->quantPrecision);
        if (quantizer == 0) return PV_FAIL;        /*  04/03/01 */

        currVop->quantizer = quantizer;

        /* if we have HEC, read some redundant VOP header information */
        /* this part needs improvement  04/05/01 */
        if (BitstreamRead1Bits(stream))
        {
            int time_base = -1;

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

            /* marker bit */
            BitstreamRead1Bits(stream);

            /* vop_time_increment (1-15 bits) */
            BitstreamReadBits16(stream, currVol->nbitsTimeIncRes);

            /* marker bit */
            BitstreamRead1Bits(stream);

            /* vop_prediction_type (2 bits) */
            BitstreamReadBits16(stream, 2);

            /* Added intra_dc_vlc_thr reading  */
            BitstreamReadBits16(stream, 3);

            /* fcodes */
            if (currVop->predictionType != I_VOP)
            {
                fcode_forward = (int) BitstreamReadBits16(stream, 3);

                if (currVop->predictionType == B_VOP)
                {
                    BitstreamReadBits16(stream, 3);
                }
            }

        }
    }
    else
    {
        PV_BitstreamByteAlign(stream);  /*  */
        status = BitstreamCheckEndBuffer(stream);   /* return end_of_VOP  03/30/01 */
        if (status != PV_SUCCESS)
        {
            return status;
        }
        status = BitstreamShowBits32HC(stream, &tmpvar32);   /*  07/07/01 */
        /* -16 = 0xFFFFFFF0*/
        if ((tmpvar32 & 0xFFFFFFF0) == VISUAL_OBJECT_SEQUENCE_START_CODE) /* start code mask 00 00 01 */

        {
            /* we don't have to check for legl stuffing here.   05/08/2000 */
            return PV_END_OF_VOP;
        }
        else
        {
            return PV_FAIL;
        }
    }

    return PV_SUCCESS;
}



/***********************************************************CommentBegin******
*       3/10/00  : initial modification to the
*                new PV-Decoder Lib format.
*       04/17/01 : remove PV_END_OF_BUFFER, error checking
***********************************************************CommentEnd********/
PV_STATUS PV_GobHeader(VideoDecData *video)
{
    uint32 tmpvar;
    Vop *currVop = video->currVop;
    BitstreamDecVideo *stream = video->bitstream;
    int quantPrecision = 5;
    int16 quantizer;

    BitstreamShowBits32(stream, GOB_RESYNC_MARKER_LENGTH, &tmpvar);

    if (tmpvar != GOB_RESYNC_MARKER)
    {
        PV_BitstreamShowBitsByteAlign(stream, GOB_RESYNC_MARKER_LENGTH, &tmpvar);

        if (tmpvar != GOB_RESYNC_MARKER)
        {
            return PV_FAIL;
        }
        else
            PV_BitstreamByteAlign(stream);  /* if bytealigned GOBHEADER search is performed */
        /* then no more noforcestuffing  */
    }

    /* we've got a GOB header info here */
    BitstreamShowBits32(stream, GOB_RESYNC_MARKER_LENGTH + 5, &tmpvar);
    tmpvar &= 0x1F;

    if (tmpvar == 0)
    {
        return PV_END_OF_VOP;
    }

    if (tmpvar == 31)
    {
        PV_BitstreamFlushBits(stream, GOB_RESYNC_MARKER_LENGTH + 5);
        BitstreamByteAlignNoForceStuffing(stream);
        return PV_END_OF_VOP;
    }

    PV_BitstreamFlushBits(stream, GOB_RESYNC_MARKER_LENGTH + 5);
    currVop->gobNumber = (int) tmpvar;
    if (currVop->gobNumber >= video->nGOBinVop) return PV_FAIL;
    currVop->gobFrameID = (int) BitstreamReadBits16(stream, 2);
    quantizer = (int16) BitstreamReadBits16(stream, quantPrecision);
    if (quantizer == 0)   return PV_FAIL;         /*  04/03/01 */

    currVop->quantizer = quantizer;
    return PV_SUCCESS;
}
#ifdef PV_ANNEX_IJKT_SUPPORT
PV_STATUS PV_H263SliceHeader(VideoDecData *video, int *next_MB)
{
    PV_STATUS status;
    uint32 tmpvar;
    Vop *currVop = video->currVop;
    BitstreamDecVideo *stream = video->bitstream;
    int nTotalMB = video->nTotalMB;
    int16 quantizer;

    PV_BitstreamShowBitsByteAlignNoForceStuffing(stream, 17, &tmpvar);
    if (tmpvar == RESYNC_MARKER)
    {
        BitstreamByteAlignNoForceStuffing(stream);
        PV_BitstreamFlushBits(stream, 17);
        if (!BitstreamRead1Bits(stream))
        {
            return PV_FAIL;
        }
        *next_MB = BitstreamReadBits16(stream, video->nBitsForMBID);
        if (*next_MB >= nTotalMB)  /* fix  04/05/01 */
        {
            *next_MB = video->mbnum + 1;
            if (*next_MB >= nTotalMB)    /* this check is needed  */
                *next_MB = nTotalMB - 1;
        }
        /* we will not parse sebp2 for large pictures 3GPP */
        quantizer = (int16) BitstreamReadBits16(stream, 5);
        if (quantizer == 0) return PV_FAIL;

        currVop->quantizer = quantizer;
        if (!BitstreamRead1Bits(stream))
        {
            return PV_FAIL;
        }
        currVop->gobFrameID = (int) BitstreamReadBits16(stream, 2);
    }
    else
    {
        status = BitstreamCheckEndBuffer(stream);   /* return end_of_VOP  03/30/01 */
        if (status != PV_SUCCESS)
        {
            return status;
        }
        PV_BitstreamShowBitsByteAlign(stream, SHORT_VIDEO_START_MARKER_LENGTH, &tmpvar);

        if (tmpvar == SHORT_VIDEO_START_MARKER)
        {
            /* we don't have to check for legal stuffing here.   05/08/2000 */
            return PV_END_OF_VOP;
        }
        else
        {
            return PV_FAIL;
        }
    }
    return PV_SUCCESS;
}
#endif

