/* ------------------------------------------------------------------
 * 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"
#include "scaling.h"
#include "mbtype_mode.h"
#include "idct.h"

#define OSCL_DISABLE_WARNING_CONDITIONAL_IS_CONSTANT
/* ======================================================================== */
/*  Function : DecodeFrameDataPartMode()                                    */
/*  Purpose  : Decode a frame of MPEG4 bitstream in datapartitioning mode.  */
/*  In/out   :                                                              */
/*  Return   :                                                              */
/*  Modified :                                                              */
/*                                                                          */
/*      04/25/2000 : Rewrite the data partitioning path completely  */
/*                           according to the pseudo codes in MPEG-4        */
/*                           standard.                                      */
/*  Modified : 09/18/2000 add fast VlcDecode+Dequant                    */
/*             04/17/2001 cleanup                                       */
/* ======================================================================== */
PV_STATUS DecodeFrameDataPartMode(VideoDecData *video)
{
    PV_STATUS status;
    Vop *currVop = video->currVop;
    BitstreamDecVideo *stream = video->bitstream;

    int nMBPerRow = video->nMBPerRow;

    int vopType = currVop->predictionType;
    int mbnum;
    int nTotalMB = video->nTotalMB;
    int slice_counter;
    int resync_marker_length;

    /* copy and pad to prev_Vop for INTER coding */
    switch (vopType)
    {
        case I_VOP :
//      oscl_memset(Mode, MODE_INTRA, sizeof(uint8)*nTotalMB);
            resync_marker_length = 17;
            break;
        case P_VOP :
            oscl_memset(video->motX, 0, sizeof(MOT)*4*nTotalMB);
            oscl_memset(video->motY, 0, sizeof(MOT)*4*nTotalMB);
//      oscl_memset(Mode, MODE_INTER, sizeof(uint8)*nTotalMB);
            resync_marker_length = 16 + currVop->fcodeForward;
            break;
        default :
            mp4dec_log("DecodeFrameDataPartMode(): Vop type not supported.\n");
            return PV_FAIL;
    }

    /** Initialize sliceNo ***/
    mbnum = slice_counter = 0;
//  oscl_memset(video->sliceNo, 0, sizeof(uint8)*nTotalMB);

    do
    {
        /* This section is equivalent to motion_shape_texture() */
        /* in the MPEG-4 standard.            04/13/2000      */
        video->mbnum = mbnum;
        video->mbnum_row = PV_GET_ROW(mbnum, nMBPerRow);   /*  This is needed if nbnum is read from the packet header */
        video->mbnum_col = mbnum - video->mbnum_row * nMBPerRow;

        switch (vopType)
        {
            case I_VOP :
                status = DecodeDataPart_I_VideoPacket(video, slice_counter);
                break;

            case P_VOP :
                status = DecodeDataPart_P_VideoPacket(video, slice_counter);
                break;

            default :
                mp4dec_log("DecodeFrameDataPartMode(): Vop type not supported.\n");
                return PV_FAIL;
        }

        while ((status = PV_ReadVideoPacketHeader(video, &mbnum)) == PV_FAIL)
        {
            if ((status = quickSearchVideoPacketHeader(stream, resync_marker_length)) != PV_SUCCESS)
            {
                break;
            }
        }

        if (status == PV_END_OF_VOP)
        {
            mbnum = nTotalMB;
        }

        if (mbnum > video->mbnum + 1)
        {
            ConcealPacket(video, video->mbnum, mbnum, slice_counter);
        }
        slice_counter++;
        if (mbnum >= nTotalMB)
        {
            break;
        }


    }
    while (TRUE);

    return PV_SUCCESS;
}


/* ======================================================================== */
/*  Function : DecodeDataPart_I_VideoPacket()                               */
/*  Date     : 04/25/2000                                                   */
/*  Purpose  : Decode Data Partitioned Mode Video Packet in I-VOP           */
/*  In/out   :                                                              */
/*  Return   : PV_SUCCESS if successed, PV_FAIL if failed.                  */
/*  Modified : 09/18/2000 add fast VlcDecode+Dequant                    */
/*             04/01/2001 fixed MB_stuffing, removed unnecessary code   */
/* ======================================================================== */
PV_STATUS DecodeDataPart_I_VideoPacket(VideoDecData *video, int slice_counter)
{
    PV_STATUS status;
    uint8 *Mode = video->headerInfo.Mode;
    BitstreamDecVideo *stream = video->bitstream;
    int  nTotalMB = video->nTotalMB;
    int  mbnum, mb_start, mb_end;
    int16 QP, *QPMB = video->QPMB;
    int  MBtype, MCBPC, CBPY;
    uint32 tmpvar;
    uint code;
    int nMBPerRow = video->nMBPerRow;
    Bool valid_stuffing;
    int32 startSecondPart, startFirstPart = getPointer(stream);

    /* decode the first partition */
    QP = video->currVop->quantizer;
    mb_start = mbnum = video->mbnum;
    video->usePrevQP = 0;         /*  04/27/01 */


    BitstreamShowBits16(stream, 9, &code);
    while (code == 1)
    {
        PV_BitstreamFlushBits(stream, 9);
        BitstreamShowBits16(stream, 9, &code);
    }

    do
    {
        /* decode COD, MCBPC, ACpred_flag, CPBY and DQUANT */
        MCBPC = PV_VlcDecMCBPC_com_intra(stream);

        if (!VLC_ERROR_DETECTED(MCBPC))
        {
            Mode[mbnum] = (uint8)(MBtype = MBtype_mode[MCBPC & 7]);
            video->headerInfo.CBP[mbnum] = (uint8)((MCBPC >> 4) & 3);
            status = GetMBheaderDataPart_DQUANT_DC(video, &QP);
            video->usePrevQP = 1;        /* set it after the first coded MB      04/27/01 */
        }
        else
        {
            /* Report the error to the application.   06/20/2000 */
            VideoDecoderErrorDetected(video);
            video->mbnum = mb_start;
            movePointerTo(stream, startFirstPart);
            return PV_FAIL;
        }

        video->sliceNo[mbnum] = (uint8) slice_counter;
        QPMB[mbnum] = QP;
        video->mbnum = ++mbnum;

        BitstreamShowBits16(stream, 9, &code);
        while (code == 1)
        {
            PV_BitstreamFlushBits(stream, 9);
            BitstreamShowBits16(stream, 9, &code);
        }
        /* have we reached the end of the video packet or vop? */
        status = BitstreamShowBits32(stream, DC_MARKER_LENGTH, &tmpvar);

    }
    while (tmpvar != DC_MARKER && video->mbnum < nTotalMB);

    if (tmpvar == DC_MARKER)
    {
        PV_BitstreamFlushBits(stream, DC_MARKER_LENGTH);
    }
    else
    {
        status = quickSearchDCM(stream);
        if (status == PV_SUCCESS)
        {
            /* only way you can end up being here is in the last packet,and there is stuffing at
            the end of the first partition */
            PV_BitstreamFlushBits(stream, DC_MARKER_LENGTH);
        }
        else
        {
            /* Report the error to the application.   06/20/2000 */
            VideoDecoderErrorDetected(video);
            movePointerTo(stream, startFirstPart);
            video->mbnum = mb_start;
            /* concealment will be taken care of in the upper layer */
            return PV_FAIL;
        }
    }

    /* decode the second partition */
    startSecondPart = getPointer(stream);

    mb_end = video->mbnum;

    for (mbnum = mb_start; mbnum < mb_end; mbnum++)
    {
        MBtype = Mode[mbnum];
        /* No skipped mode in I-packets  3/1/2001    */
        video->mbnum = mbnum;

        video->mbnum_row = PV_GET_ROW(mbnum, nMBPerRow);   /*  This is needed if nbnum is read from the packet header */
        video->mbnum_col = mbnum - video->mbnum_row * nMBPerRow;
        /* there is always acdcpred in DataPart mode  04/10/01 */
        video->acPredFlag[mbnum] = (uint8) BitstreamRead1Bits(stream);

        CBPY = PV_VlcDecCBPY(stream, MBtype & INTRA_MASK); /* MODE_INTRA || MODE_INTRA_Q */
        if (CBPY < 0)
        {
            /* Report the error to the application.   06/20/2000 */
            VideoDecoderErrorDetected(video);
            movePointerTo(stream, startSecondPart); /*  */
            /* Conceal packet,  05/15/2000 */
            ConcealTexture_I(video, startFirstPart, mb_start, mb_end, slice_counter);
            return PV_FAIL;
        }

        video->headerInfo.CBP[mbnum] |= (uint8)(CBPY << 2);
    }

    video->usePrevQP = 0;

    for (mbnum = mb_start; mbnum < mb_end; mbnum++)
    {
        video->mbnum = mbnum;

        video->mbnum_row = PV_GET_ROW(mbnum , nMBPerRow);  /*  This is needed if nbnum is read from the packet header */
        video->mbnum_col = mbnum - video->mbnum_row * nMBPerRow;
        /* No skipped mode in I-packets  3/1/2001    */
        /* decode the DCT coeficients for the MB */
        status = GetMBData_DataPart(video);
        if (status != PV_SUCCESS)
        {
            /* Report the error to the application.   06/20/2000 */
            VideoDecoderErrorDetected(video);
            movePointerTo(stream, startSecondPart); /*  */
            /* Conceal packet,  05/15/2000 */
            ConcealTexture_I(video, startFirstPart, mb_start, mb_end, slice_counter);
            return status;
        }
        video->usePrevQP = 1;           /*  04/27/01 should be set after decoding first MB */
    }

    valid_stuffing = validStuffing(stream);
    if (!valid_stuffing)
    {
        VideoDecoderErrorDetected(video);
        movePointerTo(stream, startSecondPart);
        ConcealTexture_I(video, startFirstPart, mb_start, mb_end, slice_counter);
        return PV_FAIL;
    }
    return PV_SUCCESS;
}


/* ======================================================================== */
/*  Function : DecodeDataPart_P_VideoPacket()                               */
/*  Date     : 04/25/2000                                                   */
/*  Purpose  : Decode Data Partitioned Mode Video Packet in P-VOP           */
/*  In/out   :                                                              */
/*  Return   : PV_SUCCESS if successed, PV_FAIL if failed.                  */
/*  Modified :   09/18/2000,  fast VlcDecode+Dequant                        */
/*              04/13/2001,  fixed MB_stuffing, new ACDC pred structure,  */
/*                              cleanup                                     */
/*              08/07/2001,  remove MBzero                              */
/* ======================================================================== */
PV_STATUS DecodeDataPart_P_VideoPacket(VideoDecData *video, int slice_counter)
{
    PV_STATUS status;
    uint8 *Mode = video->headerInfo.Mode;
    BitstreamDecVideo *stream = video->bitstream;
    int nTotalMB = video->nTotalMB;
    int mbnum, mb_start, mb_end;
    int16 QP, *QPMB = video->QPMB;
    int MBtype, CBPY;
    Bool valid_stuffing;
    int intra_MB;
    uint32 tmpvar;
    uint code;
    int32  startFirstPart, startSecondPart;
    int nMBPerRow = video->nMBPerRow;
    uint8 *pbyte;
    /* decode the first partition */
    startFirstPart = getPointer(stream);
    mb_start = video->mbnum;
    video->usePrevQP = 0;            /*  04/27/01 */

    BitstreamShowBits16(stream, 10, &code);
    while (code == 1)
    {
        PV_BitstreamFlushBits(stream, 10);
        BitstreamShowBits16(stream, 10, &code);
    }

    do
    {
        /* decode COD, MCBPC, ACpred_flag, CPBY and DQUANT */
        /* We have to discard stuffed MB header */

        status = GetMBheaderDataPart_P(video);

        if (status != PV_SUCCESS)
        {
            /* Report the error to the application.   06/20/2000 */
            VideoDecoderErrorDetected(video);
            movePointerTo(stream, startFirstPart);
            video->mbnum = mb_start;
            return PV_FAIL;
        }

        /* we must update slice_counter before motion vector decoding.   */
        video->sliceNo[video->mbnum] = (uint8) slice_counter;

        if (Mode[video->mbnum] & INTER_MASK) /* INTER || INTER_Q || INTER_4V */
        {
            /* decode the motion vector (if there are any) */
            status = PV_GetMBvectors(video, Mode[video->mbnum]);
            if (status != PV_SUCCESS)
            {
                /* Report the error to the application.   06/20/2000 */
                VideoDecoderErrorDetected(video);
                movePointerTo(stream, startFirstPart);
                video->mbnum = mb_start;
                return PV_FAIL;
            }
        }
        video->mbnum++;

        video->mbnum_row = PV_GET_ROW(video->mbnum, nMBPerRow);   /*  This is needed if mbnum is read from the packet header */
        video->mbnum_col = video->mbnum - video->mbnum_row * nMBPerRow;

        BitstreamShowBits16(stream, 10, &code);
        while (code == 1)
        {
            PV_BitstreamFlushBits(stream, 10);
            BitstreamShowBits16(stream, 10, &code);
        }
        /* have we reached the end of the video packet or vop? */
        status = BitstreamShowBits32(stream, MOTION_MARKER_COMB_LENGTH, &tmpvar);
        /*      if (status != PV_SUCCESS && status != PV_END_OF_BUFFER) return status;  */
    }
    while (tmpvar != MOTION_MARKER_COMB && video->mbnum < nTotalMB);

    if (tmpvar == MOTION_MARKER_COMB)
    {
        PV_BitstreamFlushBits(stream, MOTION_MARKER_COMB_LENGTH);
    }
    else
    {
        status = quickSearchMotionMarker(stream);
        if (status == PV_SUCCESS)
        {
            /* only way you can end up being here is in the last packet,and there is stuffing at
            the end of the first partition */
            PV_BitstreamFlushBits(stream, MOTION_MARKER_COMB_LENGTH);
        }
        else
        {
            /* Report the error to the application.   06/20/2000 */
            VideoDecoderErrorDetected(video);
            movePointerTo(stream, startFirstPart);
            video->mbnum = mb_start;
            /* concealment will be taken care of in the upper layer  */
            return PV_FAIL;
        }
    }

    /* decode the second partition */
    startSecondPart = getPointer(stream);
    QP = video->currVop->quantizer;

    mb_end = video->mbnum;

    for (mbnum = mb_start; mbnum < mb_end; mbnum++)
    {
        MBtype = Mode[mbnum];

        if (MBtype == MODE_SKIPPED)
        {
            QPMB[mbnum] = QP; /*  03/01/01 */
            continue;
        }
        intra_MB = (MBtype & INTRA_MASK); /* (MBtype == MODE_INTRA || MBtype == MODE_INTRA_Q) */
        video->mbnum = mbnum;
        video->mbnum_row = PV_GET_ROW(mbnum, nMBPerRow);   /*  This is needed if nbnum is read from the packet header */
        video->mbnum_col = mbnum - video->mbnum_row * nMBPerRow;

        /* there is always acdcprediction in DataPart mode    04/10/01 */
        if (intra_MB)
        {
            video->acPredFlag[mbnum] = (uint8) BitstreamRead1Bits_INLINE(stream);
        }

        CBPY = PV_VlcDecCBPY(stream, intra_MB);
        if (CBPY < 0)
        {
            /* Report the error to the application.   06/20/2000 */
            VideoDecoderErrorDetected(video);
            /* Conceal second partition,  5/15/2000 */
            movePointerTo(stream, startSecondPart);
            ConcealTexture_P(video, mb_start, mb_end, slice_counter);
            return PV_FAIL;
        }

        video->headerInfo.CBP[mbnum] |= (uint8)(CBPY << 2);
        if (intra_MB || MBtype == MODE_INTER_Q)                     /*  04/26/01 */
        {
            status = GetMBheaderDataPart_DQUANT_DC(video, &QP);
            if (status != PV_SUCCESS) return status;
        }
        video->usePrevQP = 1;        /*  04/27/01 */
        QPMB[mbnum] = QP;
    }

    video->usePrevQP = 0;  /*  04/27/01 */

    for (mbnum = mb_start; mbnum < mb_end; mbnum++)
    {
        video->mbnum = mbnum;
        video->mbnum_row = PV_GET_ROW(mbnum, nMBPerRow);  /*  This is needed if nbnum is read from the packet header */
        video->mbnum_col = mbnum - video->mbnum_row * nMBPerRow;


        if (Mode[mbnum] != MODE_SKIPPED)
        {
            /* decode the DCT coeficients for the MB */
            status = GetMBData_DataPart(video);
            if (status != PV_SUCCESS)
            {
                /* Report the error to the application.   06/20/2000 */
                VideoDecoderErrorDetected(video);

                /* Conceal second partition,  5/15/2000 */
                movePointerTo(stream, startSecondPart);
                ConcealTexture_P(video, mb_start, mb_end, slice_counter);
                return status;
            }
            video->usePrevQP = 1;  /*  04/27/01 */
        }
        else
        {   // SKIPPED

            /* Motion compensation and put it to video->mblock->pred_block */
            SkippedMBMotionComp(video);

            //oscl_memset(video->predDCAC_row + video->mbnum_col, 0, sizeof(typeDCACStore)); /*  SKIPPED_ACDC */
            //oscl_memset(video->predDCAC_col, 0, sizeof(typeDCACStore));
            /*  08/08/2005 */
            pbyte = (uint8*)(video->predDCAC_row + video->mbnum_col);
            ZERO_OUT_64BYTES(pbyte);
            pbyte = (uint8*)(video->predDCAC_col);
            ZERO_OUT_64BYTES(pbyte);

        }
    }

    valid_stuffing = validStuffing(stream);   /*  */
    if (!valid_stuffing)
    {
        VideoDecoderErrorDetected(video);
        movePointerTo(stream, startSecondPart); /*  */
        ConcealTexture_P(video, mb_start, mb_end, slice_counter);

        return PV_FAIL;
    }
    return PV_SUCCESS;
}


/* ======================================================================== */
/*  Function : GetMBheaderDataPart_DQUANT_DC()                              */
/*  Date     : 04/26/2000                                                   */
/*  Purpose  : Decode DQUANT and DC in Data Partitioned Mode for both       */
/*             I-VOP and P-VOP.                                             */
/*  In/out   :                                                              */
/*  Return   : PV_SUCCESS if successed, PV_FAIL if failed.                  */
/*  Modified : 02/13/2001 new ACDC prediction structure,        */
/*                                       cleanup                            */
/* ======================================================================== */
PV_STATUS GetMBheaderDataPart_DQUANT_DC(VideoDecData *video, int16 *QP)
{
    PV_STATUS status = PV_SUCCESS;
    BitstreamDecVideo *stream = video->bitstream;
    int mbnum = video->mbnum;
    int intra_dc_vlc_thr = video->currVop->intraDCVlcThr;
    uint8 *Mode = video->headerInfo.Mode;
    int  MBtype = Mode[mbnum];
    typeDCStore *DC = video->predDC + mbnum;
    int  comp;
    Bool switched;
    uint  DQUANT;
    int16 QP_tmp;

    const static int  DQ_tab[4] = { -1, -2, 1, 2};

    if (MBtype & Q_MASK)             /* INTRA_Q || INTER_Q */
    {
        DQUANT = BitstreamReadBits16(stream, 2);
        *QP += DQ_tab[DQUANT];

        if (*QP < 1) *QP = 1;
        else if (*QP > 31) *QP = 31;
    }
    if (MBtype & INTRA_MASK)  /* INTRA || INTRA_Q */ /* no switch, code DC separately */
    {
        QP_tmp = *QP;                      /* running QP  04/26/01*/
        switched = 0;
        if (intra_dc_vlc_thr)                 /*  04/27/01 */
        {
            if (video->usePrevQP)
                QP_tmp = video->QPMB[mbnum-1];
            switched = (intra_dc_vlc_thr == 7 || QP_tmp >= intra_dc_vlc_thr * 2 + 11);
        }
        if (!switched)
        {
            for (comp = 0; comp < 6; comp++)
            {
                status = PV_DecodePredictedIntraDC(comp, stream, (*DC + comp));   /*  03/01/01 */
                if (status != PV_SUCCESS) return PV_FAIL;
            }
        }
        else
        {
            for (comp = 0; comp < 6; comp++)
            {
                (*DC)[comp] = 0;   /*  04/26/01 needed for switched case*/
            }
        }
    }
    return status;
}


/***********************************************************CommentBegin******
*       04/25/2000 : Initial modification to the new PV Lib format.
*       04/17/2001 : new ACDC pred structure
***********************************************************CommentEnd********/
PV_STATUS GetMBheaderDataPart_P(VideoDecData *video)
{
    BitstreamDecVideo *stream = video->bitstream;
    int mbnum = video->mbnum;
    uint8 *Mode = video->headerInfo.Mode;
    typeDCStore *DC = video->predDC + mbnum;
    uint no_dct_flag;
    int comp;
    int MCBPC;

    no_dct_flag = BitstreamRead1Bits_INLINE(stream);

    if (no_dct_flag)
    {
        /* skipped macroblock */
        Mode[mbnum] = MODE_SKIPPED;

        for (comp = 0; comp < 6; comp++)
        {
            (*DC)[comp] = mid_gray;
            /*  ACDC REMOVE AC coefs are set in DecodeDataPart_P */
        }
    }
    else
    {
        /* coded macroblock */
        MCBPC = PV_VlcDecMCBPC_com_inter(stream);

        if (VLC_ERROR_DETECTED(MCBPC))
        {
            return PV_FAIL;
        }

        Mode[mbnum] = (uint8)MBtype_mode[MCBPC & 7];
        video->headerInfo.CBP[mbnum] = (uint8)((MCBPC >> 4) & 3);
    }

    return PV_SUCCESS;
}


/***********************************************************CommentBegin******
*       04/17/01  new ACDC pred structure, reorganized code, cleanup
***********************************************************CommentEnd********/
PV_STATUS GetMBData_DataPart(VideoDecData *video)
{
    int mbnum = video->mbnum;
    int16 *dataBlock;
    MacroBlock *mblock = video->mblock;
    int QP = video->QPMB[mbnum];
    int32 offset;
    PIXEL *c_comp;
    int width = video->width;
    int intra_dc_vlc_thr = video->currVop->intraDCVlcThr;
    uint CBP = video->headerInfo.CBP[mbnum];
    uint8 mode = video->headerInfo.Mode[mbnum];
    int x_pos = video->mbnum_col;
    typeDCStore *DC = video->predDC + mbnum;
    int  ncoeffs[6], *no_coeff = mblock->no_coeff;
    int  comp;
    Bool  switched;
    int QP_tmp = QP;

    int y_pos = video->mbnum_row;




    /*  oscl_memset(mblock->block, 0, sizeof(typeMBStore));    Aug 9,2005 */

    if (mode & INTRA_MASK) /* MODE_INTRA || mode == MODE_INTRA_Q */
    {
        switched = 0;
        if (intra_dc_vlc_thr)
        {
            if (video->usePrevQP)
                QP_tmp = video->QPMB[mbnum-1];   /* running QP  04/26/01 */

            switched = (intra_dc_vlc_thr == 7 || QP_tmp >= intra_dc_vlc_thr * 2 + 11);
        }

        mblock->DCScalarLum = cal_dc_scaler(QP, LUMINANCE_DC_TYPE);     /*   ACDC 03/01/01 */
        mblock->DCScalarChr = cal_dc_scaler(QP, CHROMINANCE_DC_TYPE);

        for (comp = 0; comp < 6; comp++)
        {
            dataBlock = mblock->block[comp];    /*, 10/20/2000 */

            dataBlock[0] = (*DC)[comp];

            ncoeffs[comp] = VlcDequantH263IntraBlock(video, comp,
                            switched, mblock->bitmapcol[comp], &mblock->bitmaprow[comp]);

            if (VLC_ERROR_DETECTED(ncoeffs[comp]))         /*  */
            {
                if (switched)
                    return PV_FAIL;
                else
                {
                    ncoeffs[comp] = 1;
                    oscl_memset((dataBlock + 1), 0, sizeof(int16)*63);
                }
            }
            no_coeff[comp] = ncoeffs[comp];
            /*  modified to new semaphore for post-proc */
            // Future work:: can be combined in the dequant function
            // @todo Deblocking Semaphore for INTRA block
        }
        MBlockIDCT(video);
    }
    else /* MODE INTER*/
    {




        MBMotionComp(video, CBP);
        offset = (int32)(y_pos << 4) * width + (x_pos << 4);
        c_comp  = video->currVop->yChan + offset;


        for (comp = 0; comp < 4; comp++)
        {
            (*DC)[comp] = mid_gray;

            if (CBP & (1 << (5 - comp)))
            {
                ncoeffs[comp] = VlcDequantH263InterBlock(video, comp,
                                mblock->bitmapcol[comp], &mblock->bitmaprow[comp]);
                if (VLC_ERROR_DETECTED(ncoeffs[comp]))
                    return PV_FAIL;


                BlockIDCT(c_comp + (comp&2)*(width << 2) + 8*(comp&1), mblock->pred_block + (comp&2)*64 + 8*(comp&1), mblock->block[comp], width, ncoeffs[comp],
                          mblock->bitmapcol[comp], mblock->bitmaprow[comp]);

            }
            else
            {
                ncoeffs[comp] = 0;
            }

            /*  @todo Deblocking Semaphore for INTRA block, for inter just test for ringing  */
        }

        (*DC)[4] = mid_gray;
        if (CBP & 2)
        {
            ncoeffs[4] = VlcDequantH263InterBlock(video, 4,
                                                  mblock->bitmapcol[4], &mblock->bitmaprow[4]);
            if (VLC_ERROR_DETECTED(ncoeffs[4]))
                return PV_FAIL;

            BlockIDCT(video->currVop->uChan + (offset >> 2) + (x_pos << 2), mblock->pred_block + 256, mblock->block[4], width >> 1, ncoeffs[4],
                      mblock->bitmapcol[4], mblock->bitmaprow[4]);

        }
        else
        {
            ncoeffs[4] = 0;
        }
        (*DC)[5] = mid_gray;
        if (CBP & 1)
        {
            ncoeffs[5] = VlcDequantH263InterBlock(video, 5,
                                                  mblock->bitmapcol[5], &mblock->bitmaprow[5]);
            if (VLC_ERROR_DETECTED(ncoeffs[5]))
                return PV_FAIL;

            BlockIDCT(video->currVop->vChan + (offset >> 2) + (x_pos << 2), mblock->pred_block + 264, mblock->block[5], width >> 1, ncoeffs[5],
                      mblock->bitmapcol[5], mblock->bitmaprow[5]);

        }
        else
        {
            ncoeffs[5] = 0;
        }




        /* Motion compensation and put it to video->mblock->pred_block */
    }
    return PV_SUCCESS;
}
