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


#define OSCL_DISABLE_WARNING_CONDITIONAL_IS_CONSTANT
#include "osclconfig_compiler_warnings.h"
/* to mask the n least significant bits of an integer */
static const uint32 msk[33] =
{
    0x00000000, 0x00000001, 0x00000003, 0x00000007,
    0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
    0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
    0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
    0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
    0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
    0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
    0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
    0xffffffff
};


/* ======================================================================== */
/*  Function : BitstreamFillCache()                                         */
/*  Date     : 08/29/2000                                                   */
/*  Purpose  : Read more bitstream data into buffer & the 24-byte cache.    */
/*              This function is different from BitstreamFillBuffer in      */
/*              that the buffer is the frame-based buffer provided by       */
/*              the application.                                            */
/*  In/out   :                                                              */
/*  Return   : PV_SUCCESS if successed, PV_FAIL if failed.                  */
/*  Modified : 4/16/01  : removed return of PV_END_OF_BUFFER                */
/* ======================================================================== */
PV_STATUS BitstreamFillCache(BitstreamDecVideo *stream)
{
    uint8 *bitstreamBuffer = stream->bitstreamBuffer;
    uint8 *v;
    int num_bits, i;

    stream->curr_word |= (stream->next_word >> stream->incnt);   // stream->incnt cannot be 32
    stream->next_word <<= (31 - stream->incnt);
    stream->next_word <<= 1;
    num_bits = stream->incnt_next + stream->incnt;
    if (num_bits >= 32)
    {
        stream->incnt_next -= (32 - stream->incnt);
        stream->incnt = 32;
        return PV_SUCCESS;
    }
    /* this check can be removed if there is additional extra 4 bytes at the end of the bitstream */
    v = bitstreamBuffer + stream->read_point;

    if (stream->read_point > stream->data_end_pos - 4)
    {
        if (stream->data_end_pos <= stream->read_point)
        {
            stream->incnt = num_bits;
            stream->incnt_next = 0;
            return PV_SUCCESS;
        }

        stream->next_word = 0;

        for (i = 0; i < stream->data_end_pos - stream->read_point; i++)
        {
            stream->next_word |= (v[i] << ((3 - i) << 3));
        }

        stream->read_point = stream->data_end_pos;
        stream->curr_word |= (stream->next_word >> num_bits); // this is safe

        stream->next_word <<= (31 - num_bits);
        stream->next_word <<= 1;
        num_bits = i << 3;
        stream->incnt += stream->incnt_next;
        stream->incnt_next = num_bits - (32 - stream->incnt);
        if (stream->incnt_next < 0)
        {
            stream->incnt +=  num_bits;
            stream->incnt_next = 0;
        }
        else
        {
            stream->incnt = 32;
        }
        return PV_SUCCESS;
    }

    stream->next_word = ((uint32)v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3];
    stream->read_point += 4;

    stream->curr_word |= (stream->next_word >> num_bits); // this is safe
    stream->next_word <<= (31 - num_bits);
    stream->next_word <<= 1;
    stream->incnt_next += stream->incnt;
    stream->incnt = 32;
    return PV_SUCCESS;
}


/* ======================================================================== */
/*  Function : BitstreamReset()                                             */
/*  Date     : 08/29/2000                                                   */
/*  Purpose  : Initialize the bitstream buffer for frame-based decoding.    */
/*  In/out   :                                                              */
/*  Return   :                                                              */
/*  Modified :                                                              */
/* ======================================================================== */
void BitstreamReset(BitstreamDecVideo *stream, uint8 *buffer, int32 buffer_size)
{
    /* set up frame-based bitstream buffer */
    oscl_memset(stream, 0, sizeof(BitstreamDecVideo));
    stream->data_end_pos = buffer_size;
    stream->bitstreamBuffer = buffer;
}


/* ======================================================================== */
/*  Function : BitstreamOpen()                                              */
/*  Purpose  : Initialize the bitstream data structure.                     */
/*  In/out   :                                                              */
/*  Return   :                                                              */
/*  Modified :                                                              */
/* ======================================================================== */
int BitstreamOpen(BitstreamDecVideo *stream, int layer)
{
    OSCL_UNUSED_ARG(layer);
    int buffer_size = 0;
    /* set up linear bitstream buffer */
//  stream->currentBytePos = 0;
    stream->data_end_pos = 0;

    stream->incnt = 0;
    stream->incnt_next = 0;
    stream->bitcnt = 0;
    stream->curr_word = stream->next_word = 0;
    stream->read_point = stream->data_end_pos;
    return buffer_size;
}


/* ======================================================================== */
/*  Function : BitstreamClose()                                             */
/*  Purpose  : Cleanup the bitstream data structure.                        */
/*  In/out   :                                                              */
/*  Return   :                                                              */
/*  Modified :                                                              */
/* ======================================================================== */
void BitstreamClose(BitstreamDecVideo * stream)
{
    OSCL_UNUSED_ARG(stream);
    return;
}


/***********************************************************CommentBegin******
*
* -- BitstreamShowBits32HC
* Shows 32 bits
***********************************************************CommentEnd********/

PV_STATUS BitstreamShowBits32HC(BitstreamDecVideo *stream, uint32 *code)
{
    PV_STATUS status = PV_SUCCESS;

    if (stream->incnt < 32)
    {
        /* frame-based decoding */
        status = BitstreamFillCache(stream);
    }
    *code = stream->curr_word;
    return status;
}

/***********************************************************CommentBegin******
*
* -- BitstreamShowBits32
* Shows upto and including 31 bits
***********************************************************CommentEnd********/
PV_STATUS BitstreamShowBits32(BitstreamDecVideo *stream, int nbits, uint32 *code)
{
    PV_STATUS status = PV_SUCCESS;

    if (stream->incnt < nbits)
    {
        /* frame-based decoding */
        status = BitstreamFillCache(stream);
    }
    *code = stream->curr_word >> (32 - nbits);
    return status;
}


#ifndef PV_BS_INLINE
/*========================================================================= */
/*  Function:   BitstreamShowBits16()                                       */
/*  Date:       12/18/2000                                                  */
/*  Purpose:    To see the next "nbits"(nbits<=16) bitstream bits           */
/*              without advancing the read pointer                          */
/*                                                                          */
/* =========================================================================*/
PV_STATUS BitstreamShowBits16(BitstreamDecVideo *stream, int nbits, uint *code)
{
    PV_STATUS status = PV_SUCCESS;


    if (stream->incnt < nbits)
    {
        /* frame-based decoding */
        status = BitstreamFillCache(stream);
    }

    *code = stream->curr_word >> (32 - nbits);
    return status;
}


/*========================================================================= */
/*  Function:   BitstreamShow15Bits()                                       */
/*  Date:       01/23/2001                                                  */
/*  Purpose:    To see the next 15 bitstream bits                           */
/*              without advancing the read pointer                          */
/*                                                                          */
/* =========================================================================*/
PV_STATUS BitstreamShow15Bits(BitstreamDecVideo *stream, uint *code)
{
    PV_STATUS status = PV_SUCCESS;

    if (stream->incnt < 15)
    {
        /* frame-based decoding */
        status = BitstreamFillCache(stream);
    }
    *code = stream->curr_word >> 17;
    return status;
}
/*========================================================================= */
/*  Function: BitstreamShow13Bits                                           */
/*  Date:       050923                                              */
/*  Purpose:    Faciliate and speed up showing 13 bit from bitstream        */
/*              used in VlcTCOEFF decoding                                  */
/*  Modified:                            */
/* =========================================================================*/
PV_STATUS BitstreamShow13Bits(BitstreamDecVideo *stream, uint *code)
{
    PV_STATUS status = PV_SUCCESS;

    if (stream->incnt < 13)
    {
        /* frame-based decoding */
        status = BitstreamFillCache(stream);
    }
    *code = stream->curr_word >> 19;
    return status;
}

uint BitstreamReadBits16_INLINE(BitstreamDecVideo *stream, int nbits)
{
    uint code;
    PV_STATUS status;

    if (stream->incnt < nbits)
    {
        /* frame-based decoding */
        status = BitstreamFillCache(stream);
    }
    code = stream->curr_word >> (32 - nbits);
    PV_BitstreamFlushBits(stream, nbits);
    return code;
}


uint BitstreamRead1Bits_INLINE(BitstreamDecVideo *stream)
{
    PV_STATUS status = PV_SUCCESS;
    uint    code;


    if (stream->incnt < 1)
    {
        /* frame-based decoding */
        status = BitstreamFillCache(stream);
    }
    code = stream->curr_word >> 31;
    PV_BitstreamFlushBits(stream, 1);

    return code;
}

#endif

/* ======================================================================== */
/*  Function : BitstreamReadBits16()                                        */
/*  Purpose  : Read bits (nbits <=16) from bitstream buffer.                */
/*  In/out   :                                                              */
/*  Return   :                                                              */
/* ======================================================================== */
uint BitstreamReadBits16(BitstreamDecVideo *stream, int nbits)
{
    uint code;

    if (stream->incnt < nbits)
    {
        /* frame-based decoding */
        BitstreamFillCache(stream);
    }
    code = stream->curr_word >> (32 - nbits);
    PV_BitstreamFlushBits(stream, nbits);
    return code;
}

/* ======================================================================== */
/*  Function : BitstreamRead1Bits()                                         */
/*  Date     : 10/23/2000                                                   */
/*  Purpose  : Faciliate and speed up reading 1 bit from bitstream.         */
/*  In/out   :                                                              */
/*  Return   :                                                              */
/* ======================================================================== */

uint BitstreamRead1Bits(BitstreamDecVideo *stream)
{
    uint    code;

    if (stream->incnt < 1)
    {
        /* frame-based decoding */
        BitstreamFillCache(stream);
    }
    code = stream->curr_word >> 31;
    PV_BitstreamFlushBits(stream, 1);

    return code;
}

/* ======================================================================== */
/*  Function : PV_BitstreamFlushBitsCheck()                                 */
/*  Purpose  : Flush nbits bits from bitstream buffer. Check for cache      */
/*  In/out   :                                                              */
/*  Return   :                                                              */
/*  Modified :                                                              */
/* ======================================================================== */
PV_STATUS PV_BitstreamFlushBitsCheck(BitstreamDecVideo *stream, int nbits)
{
    PV_STATUS status = PV_SUCCESS;

    stream->bitcnt += nbits;
    stream->incnt -= nbits;
    if (stream->incnt < 0)
    {
        /* frame-based decoding */
        status = BitstreamFillCache(stream);

        if (stream->incnt < 0)
        {
            stream->bitcnt += stream->incnt;
            stream->incnt = 0;
        }
    }
    stream->curr_word <<= nbits;
    return status;
}

/* ======================================================================== */
/*  Function : BitstreamReadBits32()                                        */
/*  Purpose  : Read bits from bitstream buffer.                             */
/*  In/out   :                                                              */
/*  Return   :                                                              */
/* ======================================================================== */
uint32 BitstreamReadBits32(BitstreamDecVideo *stream, int nbits)
{
    uint32 code;

    if (stream->incnt < nbits)
    {
        /* frame-based decoding */
        BitstreamFillCache(stream);
    }
    code = stream->curr_word >> (32 - nbits);
    PV_BitstreamFlushBits(stream, nbits);
    return code;
}

uint32 BitstreamReadBits32HC(BitstreamDecVideo *stream)
{
    uint32 code;

    BitstreamShowBits32HC(stream, &code);
    stream->bitcnt += 32;
    stream->incnt = 0;
    stream->curr_word = 0;
    return code;
}

/* ======================================================================== */
/*  Function : BitstreamCheckEndBuffer()                                    */
/*  Date     : 03/30/2001                                                   */
/*  Purpose  : Check to see if we are at the end of buffer                  */
/*  In/out   :                                                              */
/*  Return   :                                                              */
/*  Modified :                                                              */
/* ======================================================================== */
PV_STATUS BitstreamCheckEndBuffer(BitstreamDecVideo *stream)
{
    if (stream->read_point >= stream->data_end_pos && stream->incnt <= 0) return PV_END_OF_VOP;
    return PV_SUCCESS;
}


PV_STATUS PV_BitstreamShowBitsByteAlign(BitstreamDecVideo *stream, int nbits, uint32 *code)
{
    PV_STATUS status = PV_SUCCESS;

    int n_stuffed;

    n_stuffed = 8 - (stream->bitcnt & 0x7); /*  07/05/01 */

    if (stream->incnt < (nbits + n_stuffed))
    {
        /* frame-based decoding */
        status = BitstreamFillCache(stream);
    }

    *code = (stream->curr_word << n_stuffed) >> (32 - nbits);
    return status;
}

#ifdef PV_ANNEX_IJKT_SUPPORT
PV_STATUS PV_BitstreamShowBitsByteAlignNoForceStuffing(BitstreamDecVideo *stream, int nbits, uint32 *code)
{
    PV_STATUS status = PV_SUCCESS;

    int n_stuffed;

    n_stuffed = (8 - (stream->bitcnt & 0x7)) & 7;

    if (stream->incnt < (nbits + n_stuffed))
    {
        /* frame-based decoding */
        status = BitstreamFillCache(stream);
    }

    *code = (stream->curr_word << n_stuffed) >> (32 - nbits);
    return status;
}
#endif

PV_STATUS PV_BitstreamByteAlign(BitstreamDecVideo *stream)
{
    PV_STATUS status = PV_SUCCESS;
    int n_stuffed;

    n_stuffed = 8 - (stream->bitcnt & 0x7); /*  07/05/01 */

    /* We have to make sure we have enough bits in the cache.   08/15/2000 */
    if (stream->incnt < n_stuffed)
    {
        /* frame-based decoding */
        status = BitstreamFillCache(stream);
    }


    stream->bitcnt += n_stuffed;
    stream->incnt -= n_stuffed;
    stream->curr_word <<= n_stuffed;
    if (stream->incnt < 0)
    {
        stream->bitcnt += stream->incnt;
        stream->incnt = 0;
    }
    return status;
}


PV_STATUS BitstreamByteAlignNoForceStuffing(BitstreamDecVideo *stream)
{
    uint n_stuffed;

    n_stuffed = (8 - (stream->bitcnt & 0x7)) & 0x7; /*  07/05/01 */

    stream->bitcnt += n_stuffed;
    stream->incnt -= n_stuffed;

    if (stream->incnt < 0)
    {
        stream->bitcnt += stream->incnt;
        stream->incnt = 0;
    }
    stream->curr_word <<= n_stuffed;
    return PV_SUCCESS;
}


/* ==================================================================== */
/*  Function : getPointer()                                             */
/*  Date     : 10/98                                                    */
/*  Purpose  : get current position of file pointer                     */
/*  In/out   :                                                          */
/*  Return   :                                                          */
/* ==================================================================== */
int32 getPointer(BitstreamDecVideo *stream)
{
    return stream->bitcnt;
}




/* ====================================================================== /
Function : movePointerTo()
Date     : 05/14/2004
Purpose  : move bitstream pointer to a desired position
In/out   :
Return   :
Modified :
/ ====================================================================== */
PV_STATUS movePointerTo(BitstreamDecVideo *stream, int32 pos)
{
    int32 byte_pos;
    if (pos < 0)
    {
        pos = 0;
    }

    byte_pos = pos >> 3;

    if (byte_pos > stream->data_end_pos)
    {
        byte_pos = stream->data_end_pos;
    }

    stream->read_point = byte_pos & -4;
    stream->bitcnt = stream->read_point << 3;;
    stream->curr_word = 0;
    stream->next_word = 0;
    stream->incnt = 0;
    stream->incnt_next = 0;
    BitstreamFillCache(stream);
    PV_BitstreamFlushBits(stream, ((pos & 0x7) + ((byte_pos & 0x3) << 3)));
    return PV_SUCCESS;
}


/* ======================================================================== */
/*  Function : validStuffing()                                              */
/*  Date     : 04/11/2000                                                   */
/*  Purpose  : Check whether we have valid stuffing at current position.    */
/*  In/out   :                                                              */
/*  Return   : PV_TRUE if successed, PV_FALSE if failed.                    */
/*  Modified : 12/18/2000 : changed the pattern type to uint    */
/*             04/01/2001 : removed PV_END_OF_BUFFER                        */
/* ======================================================================== */
Bool validStuffing(BitstreamDecVideo *stream)
{
    uint n_stuffed;
    uint pattern;


    n_stuffed = 8 - (stream->bitcnt & 0x7);
    BitstreamShowBits16(stream, n_stuffed, &pattern);
    if (pattern == msk[n_stuffed-1]) return PV_TRUE;
    return PV_FALSE;
}
#ifdef PV_ANNEX_IJKT_SUPPORT
Bool validStuffing_h263(BitstreamDecVideo *stream)
{
    uint n_stuffed;
    uint pattern;


    n_stuffed = (8 - (stream->bitcnt & 0x7)) & 7;  //  stream->incnt % 8
    if (n_stuffed == 0)
    {
        return PV_TRUE;
    }
    BitstreamShowBits16(stream, n_stuffed, &pattern);
    if (pattern == 0) return PV_TRUE;
    return PV_FALSE;
}
#endif


/* ======================================================================== */
/*  Function : PVSearchNextH263Frame()                                      */
/*  Date     : 04/08/2005                                                   */
/*  Purpose  : search for 0x00 0x00 0x80                                    */
/*  In/out   :                                                              */
/*  Return   : PV_SUCCESS if succeeded  or PV_END_OF_VOP if failed          */
/*  Modified :                                                              */
/* ======================================================================== */
PV_STATUS PVSearchNextH263Frame(BitstreamDecVideo *stream)
{
    PV_STATUS status = PV_SUCCESS;
    uint8 *ptr;
    int32 i;
    int32 initial_byte_aligned_position = (stream->bitcnt + 7) >> 3;

    ptr = stream->bitstreamBuffer + initial_byte_aligned_position;

    i = PVLocateH263FrameHeader(ptr, stream->data_end_pos - initial_byte_aligned_position);
    if (stream->data_end_pos <= initial_byte_aligned_position + i)
    {
        status = PV_END_OF_VOP;
    }
    (void)movePointerTo(stream, ((i + initial_byte_aligned_position) << 3)); /* ptr + i */
    return status;
}


/* ======================================================================== */
/*  Function : PVSearchNextM4VFrame()                                       */
/*  Date     : 04/08/2005                                                   */
/*  Purpose  : search for 0x00 0x00 0x01 and move the pointer to the        */
/*  beginning of the start code                                             */
/*  In/out   :                                                              */
/*  Return   : PV_SUCCESS if succeeded  or PV_END_OF_VOP if failed          */
/*  Modified :                                                              */
/* ======================================================================== */

PV_STATUS PVSearchNextM4VFrame(BitstreamDecVideo *stream)
{
    PV_STATUS status = PV_SUCCESS;
    uint8 *ptr;
    int32 i;
    int32 initial_byte_aligned_position = (stream->bitcnt + 7) >> 3;

    ptr = stream->bitstreamBuffer + initial_byte_aligned_position;

    i = PVLocateFrameHeader(ptr, stream->data_end_pos - initial_byte_aligned_position);
    if (stream->data_end_pos <= initial_byte_aligned_position + i)
    {
        status = PV_END_OF_VOP;
    }
    (void)movePointerTo(stream, ((i + initial_byte_aligned_position) << 3)); /* ptr + i */
    return status;
}



void PVLocateM4VFrameBoundary(BitstreamDecVideo *stream)
{
    uint8 *ptr;
    int32 byte_pos = (stream->bitcnt >> 3);

    stream->searched_frame_boundary = 1;
    ptr = stream->bitstreamBuffer + byte_pos;

    stream->data_end_pos = PVLocateFrameHeader(ptr, (int32)stream->data_end_pos - byte_pos) + byte_pos;
}

void PVLocateH263FrameBoundary(BitstreamDecVideo *stream)
{
    uint8 *ptr;
    int32 byte_pos = (stream->bitcnt >> 3);

    stream->searched_frame_boundary = 1;
    ptr = stream->bitstreamBuffer + byte_pos;

    stream->data_end_pos = PVLocateH263FrameHeader(ptr, (int32)stream->data_end_pos - byte_pos) + byte_pos;
}

/* ======================================================================== */
/*  Function : quickSearchVideoPacketHeader()               */
/*  Date     : 05/08/2000                           */
/*  Purpose  : Quick search for the next video packet header        */
/*  In/out   :                              */
/*  Return   : PV_TRUE if successed, PV_FALSE if failed.            */
/*  Modified :                              */
/* ======================================================================== */
PV_STATUS quickSearchVideoPacketHeader(BitstreamDecVideo *stream, int marker_length)
{
    PV_STATUS status = PV_SUCCESS;
    uint32 tmpvar;


    if (stream->searched_frame_boundary == 0)
    {
        PVLocateM4VFrameBoundary(stream);
    }

    do
    {
        status = BitstreamCheckEndBuffer(stream);
        if (status == PV_END_OF_VOP) break;
        PV_BitstreamShowBitsByteAlign(stream, marker_length, &tmpvar);
        if (tmpvar == RESYNC_MARKER) break;
        PV_BitstreamFlushBits(stream, 8);
    }
    while (status == PV_SUCCESS);

    return status;
}
#ifdef PV_ANNEX_IJKT_SUPPORT
PV_STATUS quickSearchH263SliceHeader(BitstreamDecVideo *stream)
{
    PV_STATUS status = PV_SUCCESS;
    uint32 tmpvar;


    if (stream->searched_frame_boundary == 0)
    {
        PVLocateH263FrameBoundary(stream);
    }

    do
    {
        status = BitstreamCheckEndBuffer(stream);
        if (status == PV_END_OF_VOP) break;
        PV_BitstreamShowBitsByteAlignNoForceStuffing(stream, 17, &tmpvar);
        if (tmpvar == RESYNC_MARKER) break;
        PV_BitstreamFlushBits(stream, 8);
    }
    while (status == PV_SUCCESS);

    return status;
}
#endif
/* ======================================================================== */
/*          The following functions are for Error Concealment.              */
/* ======================================================================== */

/****************************************************/
//  01/22/99 Quick search of Resync Marker
// (actually the first part of it, i.e. 16 0's and a 1.

/* We are not using the fastest algorithm possible. What this function does is
to locate 11 consecutive 0's and then check if the 5 bits before them and
the 1 bit after them are all 1's.
*/

//  Table used for quick search of markers. Gives the last `1' in
// 4 bits. The MSB is bit #1, the LSB is bit #4.
const int lastOne[] =
{
    0,  4,  3,  4,  2,  4,  3,  4,
    1,  4,  3,  4,  2,  4,  3,  4
};

//  Table used for quick search of markers. Gives the last `0' in
// 4 bits. The MSB is bit #1, the LSB is bit #4.
/*const int lastZero[]=
{
    4,  3,  4,  2,  4,  3,  4,  1,
        4,  3,  4,  2,  4,  3,  4,  0
};
*/
//  Table used for quick search of markers. Gives the first `0' in
// 4 bits. The MSB is bit #1, the LSB is bit #4.
const int firstZero[] =
{
    1, 1, 1, 1, 1, 1, 1, 1,
    2, 2, 2, 2, 3, 3, 4, 0
};

//  Table used for quick search of markers. Gives the first `1' in
// 4 bits. The MSB is bit #1, the LSB is bit #4.
const int firstOne[] =
{
    0, 4, 3, 3, 2, 2, 2, 2,
    1, 1, 1, 1, 1, 1, 1, 1
};


/* ======================================================================== */
/*  Function : quickSearchMarkers()                                         */
/*  Date     : 01/25/99                                                     */
/*  Purpose  : Quick search for Motion marker                               */
/*  In/out   :                                                              */
/*  Return   : Boolean true of false                                        */
/*  Modified : 12/18/2000 : 32-bit version                    */
/* ======================================================================== */
PV_STATUS quickSearchMotionMarker(BitstreamDecVideo *stream)
// MM: (11111000000000001)
{
    PV_STATUS status;
    uint32 tmpvar, tmpvar2;

    if (stream->searched_frame_boundary == 0)
    {
        PVLocateM4VFrameBoundary(stream);
    }

    while (TRUE)
    {
        status = BitstreamCheckEndBuffer(stream);
        if (status == PV_END_OF_VOP) return PV_END_OF_VOP;

        BitstreamShowBits32(stream, 17, &tmpvar);
        if (!tmpvar) return PV_FAIL;

        if (tmpvar & 1) //  Check if the 17th bit from the curr bit pos is a '1'
        {
            if (tmpvar == MOTION_MARKER_COMB)
            {
                return PV_SUCCESS; //  Found
            }
            else
            {
                tmpvar >>= 1;
                tmpvar &= 0xF;
                PV_BitstreamFlushBits(stream, (int)(12 + firstZero[tmpvar]));
            }
        }
        else
        {
            //  01/25/99 Get the first 16 bits
            tmpvar >>= 1;
            tmpvar2 = tmpvar & 0xF;

            //  01/26/99 Check bits #13 ~ #16
            if (tmpvar2)
            {
                PV_BitstreamFlushBits(stream, (int)(7 + lastOne[tmpvar2]));
            }
            else
            {
                tmpvar >>= 4;
                tmpvar2 = tmpvar & 0xF;

                //  01/26/99 Check bits #9 ~ #12
                if (tmpvar2)
                {
                    PV_BitstreamFlushBits(stream, (int)(3 + lastOne[tmpvar2]));
                }
                else
                {
                    tmpvar >>= 4;
                    tmpvar2 = tmpvar & 0xF;

                    //  01/26/99 Check bits #5 ~ #8
                    // We don't need to check further
                    // for the first 5 bits should be all 1's
                    if (lastOne[tmpvar2] < 2)
                    {
                        /* we already have too many consecutive 0's. */
                        /* Go directly pass the last of the 17 bits. */
                        PV_BitstreamFlushBits(stream, 17);
                    }
                    else
                    {
                        PV_BitstreamFlushBits(stream, (int)(lastOne[tmpvar2] - 1));
                    }
                }
            }
        }

    }
}

/* ======================================================================== */
/*  Function : quickSearchDCM()                                             */
/*  Date     : 01/22/99                                                     */
/*  Purpose  : Quick search for DC Marker                                   */
/*              We are not using the fastest algorithm possible.  What this */
/*              function does is to locate 11 consecutive 0's and then      */
/*              check if the 7 bits before them and the 1 bit after them    */
/*              are correct.  (actually the first part of it, i.e. 16 0's   */
/*              and a 1.                                                    */
/*  In/out   :                                                              */
/*  Return   : Boolean true of false                                        */
/*  Modified : 12/18/2000 : 32-bit version                    */
/* ======================================================================== */
PV_STATUS quickSearchDCM(BitstreamDecVideo *stream)
// DCM: (110 1011 0000 0000 0001)
{
    PV_STATUS status;
    uint32 tmpvar, tmpvar2;

    if (stream->searched_frame_boundary == 0)
    {
        PVLocateM4VFrameBoundary(stream);
    }

    while (TRUE)
    {
        status = BitstreamCheckEndBuffer(stream);
        if (status == PV_END_OF_VOP) return PV_END_OF_VOP;
        BitstreamShowBits32(stream, 19, &tmpvar);

        if (tmpvar & 1) //  Check if the 17th bit from the curr bit pos is a '1'
        {
            if (tmpvar == DC_MARKER)
            {
                return PV_SUCCESS; //  Found
            }
            else
            {
                //  01/25/99 We treat the last of the 19 bits as its 7th bit (which is
                // also a `1'
                PV_BitstreamFlushBits(stream, 12);
            }
        }
        else
        {
            tmpvar >>= 1;
            tmpvar2 = tmpvar & 0xF;

            if (tmpvar2)
            {
                PV_BitstreamFlushBits(stream, (int)(7 + lastOne[tmpvar2]));
            }
            else
            {
                tmpvar >>= 4;
                tmpvar2 = tmpvar & 0xF;
                if (tmpvar2)
                {
                    PV_BitstreamFlushBits(stream, (int)(3 + lastOne[tmpvar2]));
                }
                else
                {
                    tmpvar >>= 4;
                    tmpvar2 = tmpvar & 0xF;
                    if (lastOne[tmpvar2] < 2)
                    {
                        /* we already have too many consecutive 0's. */
                        /* Go directly pass the last of the 17 bits. */
                        PV_BitstreamFlushBits(stream, 19);
                    }
                    else
                    {
                        PV_BitstreamFlushBits(stream, (int)(lastOne[tmpvar2] - 1));
                    }
                }
            }
        }
    }
}

/* ======================================================================== */
/*  Function : quickSearchGOBHeader()   0000 0000 0000 0000 1               */
/*  Date     : 07/06/01                                                     */
/*  Purpose  : Quick search of GOBHeader (not byte aligned)                 */
/*  In/out   :                                                              */
/*  Return   : Integer value indicates type of marker found                 */
/*  Modified :                                                              */
/* ======================================================================== */
PV_STATUS quickSearchGOBHeader(BitstreamDecVideo *stream)
{
    PV_STATUS status;
    int byte0, byte1, byte2, shift, tmpvar;

    BitstreamByteAlignNoForceStuffing(stream);

    if (stream->searched_frame_boundary == 0)
    {
        PVLocateH263FrameBoundary(stream);
    }

    while (TRUE)
    {
        status = BitstreamCheckEndBuffer(stream);
        if (status == PV_END_OF_VOP) return PV_END_OF_VOP;

        if (stream->incnt < 24)
        {
            status = BitstreamFillCache(stream);
        }


        byte1 = (stream->curr_word << 8) >> 24;
        if (byte1 == 0)
        {
            byte2 = (stream->curr_word << 16) >> 24;
            if (byte2)
            {
                tmpvar = byte2 >> 4;

                if (tmpvar)
                {
                    shift = 9 - firstOne[tmpvar];
                }
                else
                {
                    shift = 5 - firstOne[byte2];
                }
                byte0 = stream->curr_word >> 24;
                if ((byte0 & msk[shift]) == 0)
                {
                    PV_BitstreamFlushBits(stream, 8 - shift);
                    return PV_SUCCESS;
                }
                PV_BitstreamFlushBits(stream, 8);    /* third_byte is not zero */
            }
        }

        PV_BitstreamFlushBits(stream, 8);
    }
}
