PV_STATUS EncodeVopNotCoded(VideoEncData *video, UChar *bstream, Int *size, ULong modTime)
{
    PV_STATUS status;
    Vol *currVol = video->vol[0];
    Vop *currVop = video->currVop;
    BitstreamEncVideo *stream = currVol->stream;
    UInt frameTick;
    Int timeInc;

    stream->bitstreamBuffer = bstream;
    stream->bufferSize = *size;
    BitstreamEncReset(stream);

    status = BitstreamPutGT16Bits(stream, 32, VOP_START_CODE); /*Start Code for VOP*/
    status = BitstreamPutBits(stream, 2, P_VOP);/* VOP Coding Type*/

    modTime += video->wrapModTime; /* wrapModTime is non zero after wrap-around */
    frameTick = (Int)(((double)(modTime - video->modTimeRef) * currVol->timeIncrementResolution + 500) / 1000);
    timeInc = frameTick - video->refTick[0];
    while (timeInc >= currVol->timeIncrementResolution)
    {
        timeInc -= currVol->timeIncrementResolution;
        status = BitstreamPut1Bits(stream, 1);
        /* do not update refTick and modTimeRef yet, do it after encoding!! */
    }
    status = BitstreamPut1Bits(stream, 0);
    status = BitstreamPut1Bits(stream, 1); /* marker bit */
    status = BitstreamPutBits(stream, currVol->nbitsTimeIncRes, timeInc); /* vop_time_increment */
    status = BitstreamPut1Bits(stream, 1); /* marker bit */
    status = BitstreamPut1Bits(stream, 0); /* vop_coded bit */
    BitstreamMpeg4ByteAlignStuffing(stream);

    return status;
}
/* ======================================================================== */
PV_STATUS EncodeFrameCombinedMode(VideoEncData *video)
{
    PV_STATUS status = PV_SUCCESS;
    Vol *currVol = video->vol[video->currLayer];
    Vop *currVop = video->currVop;
    VideoEncParams *encParams = video->encParams;
    Int width = currVop->width; /* has to be Vop, for multiple of 16 */
    Int lx = currVop->pitch; /* with padding */
    Int offset = 0;
    Int ind_x, ind_y;
    Int start_packet_header = 0;
    UChar *QPMB = video->QPMB;
    Int QP;
    Int mbnum = 0, slice_counter = 0, curr_slice_counter = 0;
    Int num_bits, packet_size = encParams->ResyncPacketsize;
    Int GOB_Header_Interval = encParams->GOB_Header_Interval;
    BitstreamEncVideo *bs1 = video->bitstream1;
    Int numHeaderBits;
    approxDCT fastDCTfunction;
    Int ncoefblck[6] = {64, 64, 64, 64, 64, 64}; /* for FastCodeMB,  5/18/2001 */
    PV_STATUS(*CodeMB)(VideoEncData *, approxDCT *, Int, Int[]);
    void (*MBVlcEncode)(VideoEncData*, Int[], void *);
    void (*BlockCodeCoeff)(RunLevelBlock*, BitstreamEncVideo*, Int, Int, UChar);

    /* for H263 GOB changes */
//MP4RateControlType rc_type = encParams->RC_Type;

    video->QP_prev = currVop->quantizer;

    numHeaderBits = BitstreamGetPos(bs1);

    /* determine type of quantization   */
#ifndef NO_MPEG_QUANT
    if (currVol->quantType == 0)
        CodeMB = &CodeMB_H263;
    else
        CodeMB = &CodeMB_MPEG;
#else
    CodeMB = &CodeMB_H263;
#endif

    /* determine which functions to be used, in MB-level */
    if (currVop->predictionType == P_VOP)
        MBVlcEncode = &MBVlcEncodeCombined_P_VOP;
    else if (currVop->predictionType == I_VOP)
        MBVlcEncode = &MBVlcEncodeCombined_I_VOP;
    else /* B_VOP not implemented yet */
        return PV_FAIL;

    /* determine which VLC table to be used */
#ifndef H263_ONLY
    if (currVol->shortVideoHeader)
        BlockCodeCoeff = &BlockCodeCoeff_ShortHeader;
#ifndef NO_RVLC
    else if (currVol->useReverseVLC)
        BlockCodeCoeff = &BlockCodeCoeff_RVLC;
#endif
    else
        BlockCodeCoeff = &BlockCodeCoeff_Normal;
#else
    BlockCodeCoeff = &BlockCodeCoeff_ShortHeader;
#endif

    /* gob_frame_id is the same for different vop types - the reason should be SCD */
    if (currVol->shortVideoHeader && currVop->gobFrameID != currVop->predictionType)
        currVop->gobFrameID = currVop->predictionType;


    video->usePrevQP = 0;

    for (ind_y = 0; ind_y < currVol->nMBPerCol; ind_y++)    /* Col MB Loop */
    {

        video->outputMB->mb_y = ind_y; /*  5/28/01 */

        if (currVol->shortVideoHeader)  /* ShortVideoHeader Mode */
        {

            if (slice_counter && GOB_Header_Interval && (ind_y % GOB_Header_Interval == 0))     /* Encode GOB Header */
            {
                QP = QPMB[mbnum];    /* Get quant_scale */
                video->header_bits -= BitstreamGetPos(currVol->stream); /* Header Bits */
                status = EncodeGOBHeader(video, slice_counter, QP, 0);  //ind_y     /* Encode GOB Header */
                video->header_bits += BitstreamGetPos(currVol->stream); /* Header Bits */
                curr_slice_counter = slice_counter;
            }
        }

        for (ind_x = 0; ind_x < currVol->nMBPerRow; ind_x++)  /* Row MB Loop */
        {
            video->outputMB->mb_x = ind_x; /*  5/28/01 */
            video->mbnum = mbnum;
            QP = QPMB[mbnum];   /* always read new QP */

            if (GOB_Header_Interval)
                video->sliceNo[mbnum] = curr_slice_counter; /* Update MB slice number */
            else
                video->sliceNo[mbnum] = slice_counter;

            /****************************************************************************************/
            /* MB Prediction:Put into MC macroblock, substract from currVop, put in predMB */
            /****************************************************************************************/
            getMotionCompensatedMB(video, ind_x, ind_y, offset);

#ifndef H263_ONLY
            if (start_packet_header)
            {
                slice_counter++;                        /* Increment slice counter */
                video->sliceNo[mbnum] = slice_counter;  /* Update MB slice number*/
                video->header_bits -= BitstreamGetPos(bs1); /* Header Bits */
                video->QP_prev = currVop->quantizer;
                status = EncodeVideoPacketHeader(video, mbnum, video->QP_prev, 0);
                video->header_bits += BitstreamGetPos(bs1); /* Header Bits */
                numHeaderBits = BitstreamGetPos(bs1);
                start_packet_header = 0;
                video->usePrevQP = 0;
            }
#endif
            /***********************************************/
            /* Code_MB:  DCT, Q, Q^(-1), IDCT, Motion Comp */
            /***********************************************/

            status = (*CodeMB)(video, &fastDCTfunction, (offset << 5) + QP, ncoefblck);

            /************************************/
            /* MB VLC Encode: VLC Encode MB     */
            /************************************/

            (*MBVlcEncode)(video, ncoefblck, (void*)BlockCodeCoeff);

            /*************************************************************/
            /* Assemble Packets:  Assemble the MB VLC codes into Packets */
            /*************************************************************/

            /* Assemble_Packet(video) */
#ifndef H263_ONLY
            if (!currVol->shortVideoHeader) /* Not in ShortVideoHeader mode */
            {
                if (!currVol->ResyncMarkerDisable) /* RESYNC MARKER MODE */
                {
                    num_bits = BitstreamGetPos(bs1) - numHeaderBits;
                    if (num_bits > packet_size)
                    {
                        video->header_bits += BitstreamMpeg4ByteAlignStuffing(bs1); /* Byte align Packet */

                        status = BitstreamAppendPacket(currVol->stream, bs1); /* Put Packet to Buffer */
                        /* continue even if status == PV_END_OF_BUF, to get the stats */

                        BitstreamEncReset(bs1);

                        start_packet_header = 1;
                    }
                }
                else   /* NO RESYNC MARKER MODE */
                {
                    status = BitstreamAppendEnc(currVol->stream, bs1); /* Initialize to 0 */
                    /* continue even if status == PV_END_OF_BUF, to get the stats */

                    BitstreamEncReset(bs1);
                }
            }
            else
#endif /* H263_ONLY */
            {   /* ShortVideoHeader Mode */
                status = BitstreamAppendEnc(currVol->stream, bs1);  /* Initialize to 0 */
                /* continue even if status == PV_END_OF_BUF, to get the stats */

                BitstreamEncReset(bs1);
            }
            mbnum++;
            offset += 16;
        } /* End of For ind_x */

        offset += (lx << 4) - width;
        if (currVol->shortVideoHeader)  /* ShortVideoHeader = 1 */
        {

            if (GOB_Header_Interval)  slice_counter++;
        }

    } /* End of For ind_y */

    if (currVol->shortVideoHeader) /* ShortVideoHeader = 1 */
    {

        video->header_bits += BitstreamShortHeaderByteAlignStuffing(currVol->stream); /* Byte Align */
    }
#ifndef H263_ONLY
    else   /* Combined Mode*/
    {
        if (!currVol->ResyncMarkerDisable) /* Resync Markers */
        {

            if (!start_packet_header)
            {
                video->header_bits += BitstreamMpeg4ByteAlignStuffing(bs1);/* Byte Align  */

                status = BitstreamAppendPacket(currVol->stream, bs1);   /* Put Packet to Buffer */
                /* continue even if status == PV_END_OF_BUF, to get the stats */

                BitstreamEncReset(bs1);
            }
        }
        else   /* No Resync Markers */
        {
            video->header_bits += BitstreamMpeg4ByteAlignStuffing(currVol->stream); /* Byte Align */
        }
    }
#endif /* H263_ONLY */

    return status; /* if status == PV_END_OF_BUF, this frame will be pre-skipped */
}
/* ======================================================================== */
PV_STATUS EncodeSliceCombinedMode(VideoEncData *video)
{
    PV_STATUS status = PV_SUCCESS;
    Vol *currVol = video->vol[video->currLayer];
    Vop *currVop = video->currVop;
    UChar mode = MODE_INTRA;
    UChar *Mode = video->headerInfo.Mode;
    VideoEncParams *encParams = video->encParams;
    Int nTotalMB = currVol->nTotalMB;
    Int width = currVop->width; /* has to be Vop, for multiple of 16 */
    Int lx = currVop->pitch; /* , with padding */
//  rateControl *rc = encParams->rc[video->currLayer];
    UChar *QPMB = video->QPMB;
    Int QP;
    Int ind_x = video->outputMB->mb_x, ind_y = video->outputMB->mb_y;
    Int offset = video->offset;                 /* get current MB location */
    Int mbnum = video->mbnum, slice_counter = video->sliceNo[mbnum]; /* get current MB location */
    Int firstMB = mbnum;
    Int start_packet_header = 0;
    Int num_bits = 0;
    Int packet_size = encParams->ResyncPacketsize - 1;
    Int resync_marker = ((!currVol->shortVideoHeader) && (!currVol->ResyncMarkerDisable));
    BitstreamEncVideo *bs1 = video->bitstream1;
    Int byteCount = 0, byteCount1 = 0, bitCount = 0;
    Int numHeaderBits = 0;
    approxDCT fastDCTfunction;
    Int ncoefblck[6] = {64, 64, 64, 64, 64, 64}; /* for FastCodeMB,  5/18/2001 */
    UChar CBP = 0;
    Short outputMB[6][64];
    Int k;
    PV_STATUS(*CodeMB)(VideoEncData *, approxDCT *, Int, Int[]);
    void (*MBVlcEncode)(VideoEncData*, Int[], void *);
    void (*BlockCodeCoeff)(RunLevelBlock*, BitstreamEncVideo*, Int, Int, UChar);

    video->QP_prev = 31;

#define H263_GOB_CHANGES


    if (video->end_of_buf) /* left-over from previous run */
    {
        status = BitstreamAppendPacketNoOffset(currVol->stream, bs1);
        if (status != PV_END_OF_BUF)
        {
            BitstreamEncReset(bs1);
            video->end_of_buf = 0;
        }
        return status;
    }


    if (mbnum == 0) /* only do this at the start of a frame */
    {
        QPMB[0] = video->QP_prev = QP = currVop->quantizer;
        video->usePrevQP = 0;

        numHeaderBits = BitstreamGetPos(bs1);
    }

    /* Re-assign fast functions on every slice, don't have to put it in the memory */
    QP = QPMB[mbnum];
    if (mbnum > 0)   video->QP_prev = QPMB[mbnum-1];

    /* determine type of quantization   */
#ifndef NO_MPEG_QUANT
    if (currVol->quantType == 0)
        CodeMB = &CodeMB_H263;
    else
        CodeMB = &CodeMB_MPEG;
#else
    CodeMB = &CodeMB_H263;
#endif

    /* determine which functions to be used, in MB-level */
    if (currVop->predictionType == P_VOP)
        MBVlcEncode = &MBVlcEncodeCombined_P_VOP;
    else if (currVop->predictionType == I_VOP)
        MBVlcEncode = &MBVlcEncodeCombined_I_VOP;
    else /* B_VOP not implemented yet */
        return PV_FAIL;

    /* determine which VLC table to be used */
#ifndef H263_ONLY
    if (currVol->shortVideoHeader)
        BlockCodeCoeff = &BlockCodeCoeff_ShortHeader;
#ifndef NO_RVLC
    else if (currVol->useReverseVLC)
        BlockCodeCoeff = &BlockCodeCoeff_RVLC;
#endif
    else
        BlockCodeCoeff = &BlockCodeCoeff_Normal;
#else
    BlockCodeCoeff = &BlockCodeCoeff_ShortHeader;
#endif

    /*  (gob_frame_id is the same for different vop types) The reason should be SCD */
    if (currVol->shortVideoHeader && currVop->gobFrameID != currVop->predictionType)
        currVop->gobFrameID = currVop->predictionType;


    if (mbnum != 0)
    {
        if (currVol->shortVideoHeader)
        {
            /* Encode GOB Header */
            bitCount = BitstreamGetPos(bs1);
            byteCount1 = byteCount = bitCount >> 3; /* save the position before GOB header */
            bitCount = bitCount & 0x7;

#ifdef H263_GOB_CHANGES
            video->header_bits -= BitstreamGetPos(bs1); /* Header Bits */
            status = EncodeGOBHeader(video, slice_counter, QP, 1);  //ind_y    /* Encode GOB Header */
            video->header_bits += BitstreamGetPos(bs1); /* Header Bits */
#endif
            goto JUMP_IN_SH;
        }
        else if (currVol->ResyncMarkerDisable)
/* ======================================================================== */
PV_STATUS EncodeVideoPacketHeader(VideoEncData *video, int MB_number,
                                  int quant_scale, Int insert)
{
//	PV_STATUS status=PV_SUCCESS;
    int fcode;
    Vop *currVop = video->currVop;
    Vol *currVol = video->vol[video->currLayer];
    BitstreamEncVideo *bs, tmp;
    UChar buffer[30];

    if (insert) /* insert packet header to the beginning of bs1 */
    {
        tmp.bitstreamBuffer = buffer; /* use temporary buffer */
        tmp.bufferSize = 30;
        BitstreamEncReset(&tmp);
        bs = &tmp;
    }
    else
        bs = video->bitstream1;


    if (currVop->predictionType == I_VOP)
        BitstreamPutGT16Bits(bs, 17, 1);	/* resync_marker I_VOP */
    else if (currVop->predictionType == P_VOP)
    {
        fcode = currVop->fcodeForward;
        BitstreamPutGT16Bits(bs, 16 + fcode, 1);	/* resync_marker P_VOP */

    }
    else
    {
        fcode = currVop->fcodeForward;
        if (currVop->fcodeBackward > fcode)
            fcode = currVop->fcodeBackward;
        BitstreamPutGT16Bits(bs, 16 + fcode, 1);	/* resync_marker B_VOP */
    }

    BitstreamPutBits(bs, currVol->nBitsForMBID, MB_number); /* resync_marker */
    BitstreamPutBits(bs, 5, quant_scale); /* quant_scale */
    BitstreamPut1Bits(bs, 0); /* header_extension_code = 0 */

    if (0) /* header_extension_code = 1 */
    {
        /* NEED modulo_time_base code here ... default 0x01  belo*/
        /*status =*/ BitstreamPut1Bits(bs, 1);
        /*status = */
        BitstreamPut1Bits(bs, 0);

        /*status = */
        BitstreamPut1Bits(bs, 1); /* marker bit */
        /*status = */
        BitstreamPutBits(bs, currVol->nbitsTimeIncRes, currVop->timeInc); /* vop_time_increment */
        /*status = */
        BitstreamPut1Bits(bs, 1); /* marker bit */

        /*status = */
        BitstreamPutBits(bs, 2, currVop->predictionType);/* VOP Coding Type*/

        /*status = */
        BitstreamPutBits(bs, 3, currVop->intraDCVlcThr); /* intra_dc_vlc_thr */

        if (currVop->predictionType != I_VOP)
            /*status = */ BitstreamPutBits(bs, 3, currVop->fcodeForward);
        if (currVop->predictionType == B_VOP)
            /*status = */ BitstreamPutBits(bs, 3, currVop->fcodeBackward);
    }
#ifndef NO_SLICE_ENCODE
    if (insert)
        BitstreamPrependPacket(video->bitstream1, bs);
#endif
    return PV_SUCCESS;
}