//==========================================================================
//
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
//  PURPOSE.
//
//  Copyright (c) 1999 - 2001  On2 Technologies Inc. All Rights Reserved.
//
//--------------------------------------------------------------------------


/****************************************************************************
*
*   Module Title :     DCT_Decode.c
*
*   Description  :     DCT block expansion, decode and reconstruction functions
*
*
*****************************************************************************
*/

/****************************************************************************
*  Header Frames
*****************************************************************************
*/

#define STRICT              /* Strict type checking. */
#include "config.h"
#include "pbdll.h"
#include "dct.h"
#include "Huffman.h"
#include "Quantize.h"
#include "Reconstruct.h"
#include <math.h>
#include <stdio.h>
#include <string.h>

/****************************************************************************
*  Module constants.
*****************************************************************************
*/        
#define GOLDEN_FRAME_THRESH_Q   50

/****************************************************************************
*  Explicit Imports
*****************************************************************************
*/              


//extern AverageBlock( UINT8 *, UINT8 *, INT16 *, UINT32 );
//extern UnpackBlock ( UINT8 *, INT16 *, UINT32 );
//extern ReconBlock ( INT16 *, INT16 *, UINT8 *, UINT32);

extern void ReconMotionBlock(PB_INSTANCE *pbi, UINT32 FragmentNumber, INT32 MvShift, INT32 MvModMask, 
                      UINT32 ReconPixelIndex, UINT32 ReconPixelsPerLine);
/* Last Inter frame DC values */
/*
extern Q_LIST_ENTRY InvLastInterDC;
extern Q_LIST_ENTRY InvLastIntraDC;
*/

/****************************************************************************
*  Exported Global Variables
*****************************************************************************
*/

/****************************************************************************
*  Exported Functions
*****************************************************************************
*/              

/****************************************************************************
*  Module Statics
*****************************************************************************
*/              
//****************************************************************************
// Copied From DCT_decode.c 

UINT32 LoopFilterLimitValuesV1[Q_TABLE_SIZE] = {  30, 25, 20, 20, 15, 15, 14, 14,
                                                  13, 13, 12, 12, 11, 11, 10, 10, 
                                                  9,  9,  8,  8,  7,  7,  7,  7,
                                                  6,  6,  6,  6,  5,  5,  5,  5,
                                                  4,  4,  4,  4,  3,  3,  3,  3,  
                                                  2,  2,  2,  2,  2,  2,  2,  2,  
                                                  0,  0,  0,  0,  0,  0,  0,  0,  
                                                  0,  0,  0,  0,  0,  0,  0,  0 };

UINT32 LoopFilterLimitValuesV2[Q_TABLE_SIZE] = {  30, 25, 20, 20, 15, 15, 14, 14,
                                                  13, 13, 12, 12, 11, 11, 10, 10, 
                                                  9,  9,  8,  8,  7,  7,  7,  7,
                                                  6,  6,  6,  6,  5,  5,  5,  5,
                                                  4,  4,  4,  4,  3,  3,  3,  3,  
                                                  2,  2,  2,  2,  2,  2,  2,  2,  
                                                  2,  2,  2,  2,  2,  2,  2,  2,  
                                                  1,  1,  1,  1,  1,  1,  1,  1 };


/****************************************************************************
*  Foreward References
*****************************************************************************
*/              
void ExpandBlock2 ( PB_INSTANCE *pbi, INT32 FragmentNumber );
void CopyRecon( PB_INSTANCE *pbi, UINT8 * DestReconPtr, UINT8 * SrcReconPtr );
void CopyNotRecon( PB_INSTANCE *pbi, UINT8 * DestReconPtr, UINT8 * SrcReconPtr );
void UpdateUMVBorder( PB_INSTANCE *pbi, UINT8 * DestReconPtr );
void UpdateUMV_HBorders( PB_INSTANCE *pbi, UINT8 * DestReconPtr, UINT32  PlaneFragOffset );
void UpdateUMV_VBorders( PB_INSTANCE *pbi, UINT8 * DestReconPtr, UINT32  PlaneFragOffset );
void ApplyReconLoopFilter(PB_INSTANCE *pbi);
void LoopFilter(PB_INSTANCE *pbi);

/****************************************************************************
 * 
 *  ROUTINE       :     SetupLoopFilter
 *
 *  INPUTS        :     None
 *                               
 *  OUTPUTS       :     None
 *
 *  RETURNS       :     None
 *
 *  FUNCTION      :     prepares to Apply a loop filter 
 *
 *  SPECIAL NOTES :     
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void SetupLoopFilter(PB_INSTANCE *pbi)
{
    INT32 FLimit; 

	FLimit = LoopFilterLimitValuesV2[pbi->FrameQIndex];
	
	pbi->BoundingValuePtr = pbi->SetupBoundingValueArray(pbi, FLimit);
}

/****************************************************************************
 * 
 *  ROUTINE       :     CopyBlock
 *
 *  INPUTS        :     None
 *
 *  OUTPUTS       :     None
 *
 *  RETURNS       :     None.
 *
 *  FUNCTION      :     Copies a block from source to destination
 *
 *  SPECIAL NOTES :     None. 
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void CopyBlock(unsigned char *src, unsigned char *dest, unsigned int srcstride)
{
	unsigned char *s = src;
	unsigned char *d = dest;
	unsigned int stride = srcstride;

	int j;
    for ( j = 0; j < 8; j++ )
	{
		((UINT32*)d)[0] = ((UINT32*)s)[0];
		((UINT32*)d)[1] = ((UINT32*)s)[1];
		s+=stride;
		d+=stride;
	}
}

/****************************************************************************
 * 
 *  ROUTINE       :     ReconRefFrames
 *
 *  INPUTS        :     None
 *
 *  OUTPUTS       :     None
 *
 *  RETURNS       :     None.
 *
 *  FUNCTION      :     Reconstructs the various reference frames
 *
 *  SPECIAL NOTES :     None. 
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/

void ReconRefFrames (PB_INSTANCE *pbi)
{
    INT32 i;
	INT32 FragIndex;			    // Fragment number
	UINT8 *SwapReconBuffersTemp;

#define PUL 8
#define PU 4
#define PUR 2
#define PL 1


	short pc[16][6]=
	{
		{0,0,0,0,0,0},	
		{0,0,0,1,0,0},		// PL
		{0,0,1,0,0,0},		// PUR
		{0,0,53,75,7,127},	// PUR|PL
		{0,1,0,0,0,0},		// PU
		{0,1,0,1,1,1},		// PU|PL
		{0,1,0,0,0,0},		// PU|PUR
		{0,0,53,75,7,127},	// PU|PUR|PL
		{1,0,0,0,0,0},		// PUL|
		{0,0,0,1,0,0},		// PUL|PL
		{1,0,1,0,1,1},		// PUL|PUR
		{0,0,53,75,7,127},	// PUL|PUR|PL
		{0,1,0,0,0,0},		// PUL|PU
		{-26,29,0,29,5,31}, // PUL|PU|PL
		{3,10,3,0,4,15},	// PUL|PU|PUR
		{-26,29,0,29,5,31}	// PUL|PU|PUR|PL
	};
	// fragment left fragment up-left, fragment up, fragment up-right
	int fl,ful,fu,fur;

	// value left value up-left, value up, value up-right
	int vl,vul,vu,vur;

	// fragment number left, up-left, up, up-right
	int l,ul,u,ur;

	//which predictor constants to use
	short wpc;

	short Mode2Frame[] =
	{
		1,	// CODE_INTER_NO_MV		0 => Encoded diff from same MB last frame 
		0,	// CODE_INTRA			1 => DCT Encoded Block
		1,	// CODE_INTER_PLUS_MV	2 => Encoded diff from included MV MB last frame
		1,	// CODE_INTER_LAST_MV	3 => Encoded diff from MRU MV MB last frame
		1,	// CODE_INTER_PRIOR_MV	4 => Encoded diff from included 4 separate MV blocks
		2,	// CODE_USING_GOLDEN	5 => Encoded diff from same MB golden frame
		2,	// CODE_GOLDEN_MV		6 => Encoded diff from included MV MB golden frame
		1	// CODE_INTER_FOUR_MV	7 => Encoded diff from included 4 separate MV blocks
	};
	short Last[3];	// last value used for given frame
	short PredictedDC;
	void (*ExpandBlockA) ( PB_INSTANCE *pbi, INT32 FragmentNumber );
	

#define HIGHBITDUPPED(X) (((signed short) X)  >> 15)

	int FragsAcross=pbi->HFragments;	
	int FromFragment,ToFragment;
	int FragsDown = pbi->VFragments;

	int WhichFrame;
	int WhichCase;

	int j,k,m,n;

	/* Search Points are ordered by distance from 0,0 only DCSearchpointCount positions checked!
		-4 -3 -2 -1  0  1  2  3  4 
	-4	         21 19 22         
	-3     24 15 11  9 12 16 25   
	-2     14  6  3  1  4  7 17   
	-1  20 10  2  z  z  z  5 13 23
	 0	18  8  0  z  z	z  z  z  z
	*/
	struct SearchPoints
	{
		int RowOffset;
		int ColOffset;
	} DCSearchPoints[]=
	{
		{0,-2},{-2,0},{-1,-2},{-2,-1},{-2,1},{-1,2},{-2,-2},{-2,2},{0,-3},
		{-3,0},{-1,-3},{-3,-1},{-3,1},{-1,3},{-2,-3},{-3,-2},{-3,2},{-2,3},
		{0,-4},{-4,0},{-1,-4},{-4,-1},{-4,1},{-1,4},{-3,-3},{-3,3}
	};
	//int DCSearchPointCount = sizeof(DCSearchPoints) / ( 2 * sizeof(int));
	int DCSearchPointCount = 0;

#ifdef DEBUG
    vl = vul = vu = vur = 0;
#endif

    if ( GetFrameType(pbi) == BASE_FRAME )
		ExpandBlockA=ExpandKFBlock;
	else
    {
   		ExpandBlockA=ExpandBlock;
    }


    // testing ?
    SetupLoopFilter(pbi);

	// for y,u,v
	for ( j = 0; j < 3 ; j++)
	{
		// pick which fragments based on Y, U, V
		switch(j)
		{
		case 0: // y
			FromFragment = 0;
			ToFragment = pbi->YPlaneFragments;
			FragsAcross = pbi->HFragments;
			FragsDown = pbi->VFragments;
			break;
		case 1: // u
			FromFragment = pbi->YPlaneFragments;
			ToFragment = pbi->YPlaneFragments + pbi->UVPlaneFragments ;
			FragsAcross = pbi->HFragments >> 1;
			FragsDown = pbi->VFragments >> 1;
			break;
		case 2:	// v
		default: // Johns: to avoid uninitialized warnings
			FromFragment = pbi->YPlaneFragments + pbi->UVPlaneFragments;
			ToFragment = pbi->YPlaneFragments + (2 * pbi->UVPlaneFragments) ;
			FragsAcross = pbi->HFragments >> 1;
			FragsDown = pbi->VFragments >> 1;
			break;
		}

		// initialize our array of last used DC Components
		for(k=0;k<3;k++)
			Last[k]=0;

		i=FromFragment;

		// do prediction on all of Y, U or V
		for ( m = 0 ; m < FragsDown ; m++)
		{
			for ( n = 0 ; n < FragsAcross ; n++, i++)
			{
				
				// only do 2 prediction if fragment coded and on non intra or if all fragments are intra 
				if( pbi->display_fragments[i] || (GetFrameType(pbi) == BASE_FRAME) )
				{
					// Type of Fragment
					WhichFrame = Mode2Frame[pbi->FragCodingMethod[i]];

					// Check Borderline Cases
					WhichCase = (n==0) + ((m==0) << 1) + ((n+1 == FragsAcross) << 2);

					switch(WhichCase)
					{
					case 0: // normal case no border condition

						// calculate values left, up, up-right and up-left
						l = i-1;
						u = i - FragsAcross;
						ur = i - FragsAcross + 1;
						ul = i - FragsAcross - 1;

						// calculate values
						vl = pbi->QFragData[l][0];
						vu = pbi->QFragData[u][0];
						vur = pbi->QFragData[ur][0];
						vul = pbi->QFragData[ul][0];
						
						// fragment valid for prediction use if coded and it comes from same frame as the one we are predicting
						fl = pbi->display_fragments[l] && (Mode2Frame[pbi->FragCodingMethod[l]] == WhichFrame);
						fu = pbi->display_fragments[u] && (Mode2Frame[pbi->FragCodingMethod[u]] == WhichFrame);
						fur = pbi->display_fragments[ur] && (Mode2Frame[pbi->FragCodingMethod[ur]] == WhichFrame);
						ful = pbi->display_fragments[ul] && (Mode2Frame[pbi->FragCodingMethod[ul]] == WhichFrame);

						// calculate which predictor to use 
						wpc = (fl*PL) | (fu*PU) | (ful*PUL) | (fur*PUR);

						break;

					case 1: // n == 0 Left Column

						// calculate values left, up, up-right and up-left
						u = i - FragsAcross;
						ur = i - FragsAcross + 1;

						// calculate values
						vu = pbi->QFragData[u][0];
						vur = pbi->QFragData[ur][0];

						// fragment valid for prediction if coded and it comes from same frame as the one we are predicting
						fu = pbi->display_fragments[u] && (Mode2Frame[pbi->FragCodingMethod[u]] == WhichFrame);
						fur = pbi->display_fragments[ur] && (Mode2Frame[pbi->FragCodingMethod[ur]] == WhichFrame);

						// calculate which predictor to use 
						wpc = (fu*PU) | (fur*PUR);

						break;

					case 2: // m == 0 Top Row 
					case 6: // m == 0 and n+1 == FragsAcross or Top Row Right Column

						// calculate values left, up, up-right and up-left
						l = i-1;

						// calculate values
						vl = pbi->QFragData[l][0];

						// fragment valid for prediction if coded and it comes from same frame as the one we are predicting
						fl = pbi->display_fragments[l] && (Mode2Frame[pbi->FragCodingMethod[l]] == WhichFrame);

						// calculate which predictor to use 
						wpc = (fl*PL) ;

						break;

					case 3: // n == 0 & m == 0 Top Row Left Column

						wpc = 0;

						break;

					case 4: // n+1 == FragsAcross : Right Column
					default: // Johns: to avoid uninitialized warnings

						// calculate values left, up, up-right and up-left
						l = i-1;
						u = i - FragsAcross;
						ul = i - FragsAcross - 1;

						// calculate values
						vl = pbi->QFragData[l][0];
						vu = pbi->QFragData[u][0];
						vul = pbi->QFragData[ul][0];
						
						// fragment valid for prediction if coded and it comes from same frame as the one we are predicting
						fl = pbi->display_fragments[l] && (Mode2Frame[pbi->FragCodingMethod[l]] == WhichFrame);
						fu = pbi->display_fragments[u] && (Mode2Frame[pbi->FragCodingMethod[u]] == WhichFrame);
						ful = pbi->display_fragments[ul] && (Mode2Frame[pbi->FragCodingMethod[ul]] == WhichFrame);

						// calculate which predictor to use 
						wpc = (fl*PL) | (fu*PU) | (ful*PUL) ;

						break;

					}
					
					
					if(wpc==0)
					{
						FragIndex = 1;
						
						// find the nearest one that is coded 
						for( k = 0; k < DCSearchPointCount ; k++)
						{
							FragIndex = i + DCSearchPoints[k].RowOffset * FragsAcross + DCSearchPoints[k].ColOffset;
							
							if( FragIndex - FromFragment > 0 ) 
							{
								if(pbi->display_fragments[FragIndex] && (Mode2Frame[pbi->FragCodingMethod[FragIndex]] == WhichFrame))
								{
									pbi->QFragData[i][0] += pbi->QFragData[FragIndex][0];
									FragIndex = 0;
									break;
								}
							}
						}
						
						
						// if none matched fall back to the last one ever
						if(FragIndex)
						{
							pbi->QFragData[i][0] += Last[WhichFrame];
						}
						
					}
					else
					{
						
						// don't do divide if divisor is 1 or 0
						PredictedDC = (pc[wpc][0]*vul + pc[wpc][1] * vu + pc[wpc][2] * vur + pc[wpc][3] * vl );

						// if we need to do a shift
						if(pc[wpc][4] != 0 )
						{
							
							// If negative add in the negative correction factor
							PredictedDC += (HIGHBITDUPPED(PredictedDC) & pc[wpc][5]);
							
							// Shift in lieu of a divide
							PredictedDC >>= pc[wpc][4];
						}
						
                        // check for outranging on the two predictors that can outrange 
                        switch(wpc)
                        {
                        case 13: // pul pu pl
                        case 15: // pul pu pur pl
                            if( abs(PredictedDC - vu) > 128)
                                PredictedDC = vu;
                            else if( abs(PredictedDC - vl) > 128)
                                PredictedDC = vl;
                            else if( abs(PredictedDC - vul) > 128)
                                PredictedDC = vul;

                            break;
                        }
						
   						pbi->QFragData[i][0] += PredictedDC;
						
					}
					
					// Save the last fragment coded for whatever frame we are predicting from
					Last[WhichFrame] = pbi->QFragData[i][0];

					// Inverse DCT and reconstitute buffer in thisframe
					ExpandBlockA( pbi, i );

				} // if display fragments

			} // for n = 0 to columns across

		} // for m = 0 to rows down

	} // for j = 0 to 2 (y,u,v)


    // Copy the current reconstruction back to the last frame recon buffer.

//printf("%d\n",pbi->CodedBlockIndex);
	if(pbi->CodedBlockIndex > (INT32) (pbi->UnitFragments >> 1))
	{
		SwapReconBuffersTemp = pbi->ThisFrameRecon;
		pbi->ThisFrameRecon = pbi->LastFrameRecon;
		pbi->LastFrameRecon = SwapReconBuffersTemp;
		CopyNotRecon( pbi, pbi->LastFrameRecon, pbi->ThisFrameRecon );
	}
	else
    {
		CopyRecon( pbi, pbi->LastFrameRecon, pbi->ThisFrameRecon );
    }
        
    // We may need to update the UMV border
    //UpdateUMVBorder(pbi, pbi->LastFrameRecon );
    
    // Apply a loop filter to edge pixels of updated blocks	
	if( pbi->Vp3VersionNo == 0 )
		ApplyReconLoopFilter(pbi);
    else
        LoopFilter(pbi);
	

    // Reconstruct the golden frame if necessary. 
    // For VFW codec only on key frames
    if ( GetFrameType(pbi) == BASE_FRAME )
    {
        CopyRecon( pbi, pbi->GoldenFrame, pbi->LastFrameRecon );
    }

    // If appropriate clear the MMX state.
    pbi->ClearSysState();

}

/****************************************************************************
 * 
 *  ROUTINE       :     ExpandKFBlock
 *
 *  INPUTS        :     INT32	FragIndex 
 *                      
 *  OUTPUTS       :     None
 *
 *  RETURNS       :     None.
 *
 *  FUNCTION      :     Reverses quantisation and dc and reconstructs pixel 
 *                      data for an "Intra" frame block.
 *
 *  SPECIAL NOTES :     
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void ExpandKFBlock ( PB_INSTANCE *pbi, INT32 FragmentNumber )
{
    UINT32		ReconPixelsPerLine;	// Pixels per line
    INT32       ReconPixelIndex;    // Offset for block into a reconstruction buffer
	//INT32       i;

    // Select the appropriate inverse Q matrix and line stride
	if ( FragmentNumber<(INT32)pbi->YPlaneFragments )
	{
		ReconPixelsPerLine = pbi->Configuration.YStride;
		select_Y_dequantiser(pbi);
	}
	else
	{
		ReconPixelsPerLine = pbi->Configuration.UVStride;
		select_UV_dequantiser(pbi);
    }
    
    // Set up pointer into the quantisation buffer.
    pbi->quantized_list = (Q_LIST_ENTRY *)(&pbi->QFragData[FragmentNumber][0]);

    // Invert quantisation and DCT to get pixel data.                       
    pbi->idct[pbi->FragCoefEOB[FragmentNumber]]( pbi->quantized_list, pbi->dequant_coeffs, pbi->ReconDataBuffer );

    // Convert fragment number to a pixel offset in a reconstruction buffer.
    ReconPixelIndex = ReconGetFragIndex ( pbi->recon_pixel_index_table, FragmentNumber );

    // Get the pixel index for the first pixel in the fragment.
    pbi->ReconIntra( pbi, (UINT8 *)(&pbi->ThisFrameRecon[ReconPixelIndex]), (UINT16 *)pbi->ReconDataBuffer, ReconPixelsPerLine );

}

/****************************************************************************
 * 
 *  ROUTINE       :     ExpandBlock
 *
 *  INPUTS        :     INT32	FragIndex 
 *                      
 *  OUTPUTS       :     None
 *
 *  RETURNS       :     None.
 *
 *  FUNCTION      :     Reverses quantisation and dc and reconstructs pixel data.
 *
 *  SPECIAL NOTES :     
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void ExpandBlock ( PB_INSTANCE *pbi, INT32 FragmentNumber )
{
    UINT8       *LastFrameRecPtr;   // Pointer into previous frame reconstruction.
    UINT8       *LastFrameRecPtr2;  // Pointer into previous frame reconstruction for 1/2 pixel MC.
	
    UINT32		ReconPixelsPerLine;	// Pixels per line
    INT32       ReconPixelIndex;    // Offset for block into a reconstruction buffer
    INT32       ReconPtr2Offset;    // Offset for second reconstruction in half pixel MC

    INT32       MVOffset;           // Baseline motion vector offset
    INT32       MvShift  ;          // Shift to correct to 1/2 or 1/4 pixel
    INT32       MvModMask;          // Mask to determine whether 1/2 pixel is used

    // TEST
    //INT32       mmask;
    //INT32       ReconPtr2OffsetB;    // Offset for second reconstruction in half pixel MC
    //INT32       MVOffsetB;

	// Get coding mode for this block
    if ( GetFrameType(pbi) == BASE_FRAME )
	{
		pbi->CodingMode = CODE_INTRA;
	}
	else
	{
	    // Get Motion vector and mode for this block.
        pbi->CodingMode = pbi->FragCodingMethod[FragmentNumber];
	}

    // Select the appropriate inverse Q matrix and line stride
	if ( FragmentNumber<(INT32)pbi->YPlaneFragments )
	{
		ReconPixelsPerLine = pbi->Configuration.YStride;
        MvShift = 1;
        MvModMask = 0x00000001;

        //mmask = 1;

		// Select appropriate dequantiser matrix.
        if ( pbi->CodingMode == CODE_INTRA )
		    select_Y_dequantiser(pbi);
        else
            select_Inter_dequantiser(pbi);
	}
	else
	{
		ReconPixelsPerLine = pbi->Configuration.UVStride;
        MvShift = 2;
        MvModMask = 0x00000003;

        //mmask = 3;

		// Select appropriate dequantiser matrix.
        if ( pbi->CodingMode == CODE_INTRA )
		    select_UV_dequantiser(pbi);
        else
            select_Inter_dequantiser(pbi);
    }
    
    // Set up pointer into the quantisation buffer.
    pbi->quantized_list = (Q_LIST_ENTRY *)(&pbi->QFragData[FragmentNumber][0]);

    // Invert quantisation and DCT to get pixel data.                       
    pbi->idct[pbi->FragCoefEOB[FragmentNumber]]( pbi->quantized_list, pbi->dequant_coeffs, pbi->ReconDataBuffer );

    // Convert fragment number to a pixel offset in a reconstruction buffer.
    ReconPixelIndex = ReconGetFragIndex ( pbi->recon_pixel_index_table, FragmentNumber );

    // Action depends on decode mode.
	if ( pbi->CodingMode == CODE_INTER_NO_MV )       // Inter with no motion vector
    {
		// Reconstruct the pixel data using the last frame reconstruction and change data
        // when the motion vector is (0,0), the recon is based on the lastframe without
        // loop filtering---- for testing
        pbi->ReconInter( pbi, (UINT8 *)&pbi->ThisFrameRecon[ReconPixelIndex], 
            (UINT8 *)&pbi->LastFrameRecon[ReconPixelIndex], 
            pbi->ReconDataBuffer, ReconPixelsPerLine );
            
    }
	else if ( ModeUsesMC[pbi->CodingMode] )          // The mode uses a motion vector.
	{
        {
            // Get vector from list
            pbi->MVector.x = pbi->FragMVect[FragmentNumber].x;
            pbi->MVector.y = pbi->FragMVect[FragmentNumber].y;
            
            // Work out the base motion vector offset and the 1/2 pixel offset if any.
            // For the U and V planes the MV specifies 1/4 pixel accuracy. This is adjusted to
            // 1/2 pixel as follows ( 0->0, 1/4->1/2, 1/2->1/2, 3/4->1/2 ).
            MVOffset = 0;
            ReconPtr2Offset = 0;
            if ( pbi->MVector.x > 0 )
            {
                MVOffset = pbi->MVector.x >> MvShift;
                if ( pbi->MVector.x & MvModMask )
                    ReconPtr2Offset += 1;
            }
            else if ( pbi->MVector.x < 0 )
            {
                MVOffset -= (-pbi->MVector.x) >> MvShift;
                if ( (-pbi->MVector.x) & MvModMask )
                    ReconPtr2Offset -= 1;
            }
            if ( pbi->MVector.y > 0 )
            {
                MVOffset += (pbi->MVector.y >>  MvShift) * ReconPixelsPerLine;
                if ( pbi->MVector.y & MvModMask )
                    ReconPtr2Offset += ReconPixelsPerLine;
            }
            else if ( pbi->MVector.y < 0 )
            {
                MVOffset -= ((-pbi->MVector.y) >> MvShift) * ReconPixelsPerLine;
                if ( (-pbi->MVector.y) & MvModMask )
                    ReconPtr2Offset -= ReconPixelsPerLine;
            }
            
            // Set up the first of the two reconstruction buffer pointers.
            if ( pbi->CodingMode==CODE_GOLDEN_MV ) 
            {
                LastFrameRecPtr = (UINT8 * )( &pbi->GoldenFrame[ReconPixelIndex] + MVOffset);
            }
            else
            {
                LastFrameRecPtr = (UINT8 * )( &pbi->LastFrameRecon[ReconPixelIndex] + MVOffset);
            }
            
            // Set up the second of the two reconstruction pointers.
            LastFrameRecPtr2 = LastFrameRecPtr + ReconPtr2Offset;
            
            // Select the appropriate reconstruction function
            if ( (int)(LastFrameRecPtr - LastFrameRecPtr2) == 0 ) 
            {
                // Reconstruct the pixel dats from the reference frame and change data
                // (no half pixel in this case as the two references were the same.
                pbi->ReconInter( pbi, (UINT8 *)&pbi->ThisFrameRecon[ReconPixelIndex], 
                    LastFrameRecPtr, pbi->ReconDataBuffer, ReconPixelsPerLine );
            }
            // Fractional pixel reconstruction.
            // Note that we only use two pixels per reconstruction even for the diagonal.
            else 
            {
                pbi->ReconInterHalfPixel2( pbi, (UINT8 *)&pbi->ThisFrameRecon[ReconPixelIndex], 
                    LastFrameRecPtr, LastFrameRecPtr2, pbi->ReconDataBuffer, ReconPixelsPerLine );
            }
        }
    }
	else if ( pbi->CodingMode == CODE_USING_GOLDEN )     // Golden frame with motion vector
    {
		// Reconstruct the pixel data using the golden frame reconstruction and change data
        pbi->ReconInter( pbi, (UINT8 *)&pbi->ThisFrameRecon[ReconPixelIndex], 
                    (UINT8 *)&pbi->GoldenFrame[ ReconPixelIndex ], 
                    pbi->ReconDataBuffer, ReconPixelsPerLine );
    }
	else                                            // Simple Intra coding
	{
        // Get the pixel index for the first pixel in the fragment.
        pbi->ReconIntra( pbi, (UINT8 *)&pbi->ThisFrameRecon[ReconPixelIndex], (UINT16 *)pbi->ReconDataBuffer, ReconPixelsPerLine );
	}
}


/****************************************************************************
 * 
 *  ROUTINE       :     ExpandToken
 *
 *  INPUTS        :     Q_LIST_ENTRY * ExpandedBlock
 *                                     Pointer to block structure into which the token
 *                                     should be expanded.
 *
 *                      INT32 * CoeffIndex
 *                             Where we are in the current block.
 *
 *                      INT32 Token, ExtraBits
 *
 *  OUTPUTS       :     
 *
 *  RETURNS       :     None
 *
 *  FUNCTION      :     Expands a DCT token into a data structure.
 *
 *  SPECIAL NOTES :     
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void ExpandToken( PB_INSTANCE *pbi __attribute__((unused)), Q_LIST_ENTRY * ExpandedBlock, UINT8 * CoeffIndex, UINT32 Token, INT32 ExtraBits )
{
    // Is the token is a combination run and value token. 
    if ( Token >= DCT_RUN_CATEGORY1 )
    {
        // Expand the token and additional bits to a zero run length and data value. 
        if ( Token < DCT_RUN_CATEGORY2 )
        {   
            // Decoding method depends on token
            if ( Token < DCT_RUN_CATEGORY1B )
            {
                // Step on by the zero run length
                *CoeffIndex += (UINT8)((Token - DCT_RUN_CATEGORY1) + 1);

                // The extra bit determines the sign.
                if ( ExtraBits & 0x01 )
                    ExpandedBlock[*CoeffIndex] = -1;
                else
                    ExpandedBlock[*CoeffIndex] = 1;
            }
            else if ( Token == DCT_RUN_CATEGORY1B )
            {
                // Bits 0-1 determines the zero run length
                *CoeffIndex += (6 + (ExtraBits & 0x03));

                // Bit 2 determines the sign
                if ( ExtraBits & 0x04 )
                    ExpandedBlock[*CoeffIndex] = -1;
                else
                    ExpandedBlock[*CoeffIndex] = 1;
            }
            else
            {
                // Bits 0-2 determines the zero run length
                *CoeffIndex += (10 + (ExtraBits & 0x07));

                // Bit 3 determines the sign
                if ( ExtraBits & 0x08 )
                    ExpandedBlock[*CoeffIndex] = -1;
                else
                    ExpandedBlock[*CoeffIndex] = 1;
            }
        }   
        else 
        {   
            // If token == DCT_RUN_CATEGORY2 we have a single 0 followed by a value
            if ( Token == DCT_RUN_CATEGORY2 )
            {
                // Step on by the zero run length
                *CoeffIndex += 1;

                // Bit 1 determines sign, bit 0 the value
                if ( ExtraBits & 0x02 )
                    ExpandedBlock[*CoeffIndex] = -(2 + (ExtraBits & 0x01));
                else
                    ExpandedBlock[*CoeffIndex] = 2 + (ExtraBits & 0x01);
            }
            // else we have 2->3 zeros followed by a value
            else
            {
                // Bit 0 determines the zero run length
                *CoeffIndex += 2 + (ExtraBits & 0x01);

                // Bit 2 determines the sign, bit 1 the value
                if ( ExtraBits & 0x04 )
                    ExpandedBlock[*CoeffIndex] = -(2 + ((ExtraBits & 0x02) >> 1));
                else
                    ExpandedBlock[*CoeffIndex] = 2 + ((ExtraBits & 0x02) >> 1);
            }
        }

        // Step on over value
        *CoeffIndex += 1;

    }
    // Token is a ZRL token so step on by the appropriate number of zeros
    else if ( Token == DCT_SHORT_ZRL_TOKEN )
    {
        *CoeffIndex += ExtraBits + 1;
    }
    // Token is a ZRL token so step on by the appropriate number of zeros
    else if ( Token == DCT_ZRL_TOKEN )
    {
        *CoeffIndex += ExtraBits + 1;
    }
    // Token is a small single value token.
    else if ( Token < LOW_VAL_TOKENS )
    {
        switch ( Token )
        {
        case ONE_TOKEN:
            ExpandedBlock[*CoeffIndex] = 1;
            break;
        case MINUS_ONE_TOKEN:
            ExpandedBlock[*CoeffIndex] = -1;
            break;
        case TWO_TOKEN:
            ExpandedBlock[*CoeffIndex] = 2;
            break;
        case MINUS_TWO_TOKEN:
            ExpandedBlock[*CoeffIndex] = -2;
            break;
        }

        // Step on the coefficient index.
        *CoeffIndex += 1;
    }
    // Token is a larger single value token
    else 
    {
        // Expand the token and additional bits to a data value. 
        if ( Token < DCT_VAL_CATEGORY3 )
        {   
            // Offset from LOW_VAL_TOKENS determines value
            Token = Token - LOW_VAL_TOKENS;

            // Extra bit determines sign
            if ( ExtraBits )
                ExpandedBlock[*CoeffIndex] = -((Q_LIST_ENTRY)(Token + DCT_VAL_CAT2_MIN));
            else
                ExpandedBlock[*CoeffIndex] = (Q_LIST_ENTRY)(Token + DCT_VAL_CAT2_MIN);
        }
        else if ( Token == DCT_VAL_CATEGORY3 )
        {   
            // Bit 1 determines sign, Bit 0 the value
            if ( ExtraBits & 0x02 )
                ExpandedBlock[*CoeffIndex] = -(DCT_VAL_CAT3_MIN + (ExtraBits & 0x01));
            else
                ExpandedBlock[*CoeffIndex] = DCT_VAL_CAT3_MIN + (ExtraBits & 0x01);
        }
        else if ( Token == DCT_VAL_CATEGORY4 )
        {   
            // Bit 2 determines sign, Bit 0-1 the value
            if ( ExtraBits & 0x04 )
                ExpandedBlock[*CoeffIndex] = -(DCT_VAL_CAT4_MIN + (ExtraBits & 0x03));
            else
                ExpandedBlock[*CoeffIndex] = DCT_VAL_CAT4_MIN + (ExtraBits & 0x03);
        }
        else if ( Token == DCT_VAL_CATEGORY5 )
        {
            // Bit 3 determines sign, Bit 0-2 the value
            if ( ExtraBits & 0x08 )
                ExpandedBlock[*CoeffIndex] = -(DCT_VAL_CAT5_MIN + (ExtraBits & 0x07));
            else
                ExpandedBlock[*CoeffIndex] = DCT_VAL_CAT5_MIN + (ExtraBits & 0x07);
        }
        else if ( Token == DCT_VAL_CATEGORY6 )
        {
            // Bit 4 determines sign, Bit 0-3 the value
            if ( ExtraBits & 0x10 )
                ExpandedBlock[*CoeffIndex] = -(DCT_VAL_CAT6_MIN + (ExtraBits & 0x0F));
            else
                ExpandedBlock[*CoeffIndex] = DCT_VAL_CAT6_MIN + (ExtraBits & 0x0F);
        }
        else if ( Token == DCT_VAL_CATEGORY7 )
        {
            // Bit 5 determines sign, Bit 0-4 the value
            if ( ExtraBits & 0x20 )
                ExpandedBlock[*CoeffIndex] = -(DCT_VAL_CAT7_MIN + (ExtraBits & 0x1F));
            else
                ExpandedBlock[*CoeffIndex] = DCT_VAL_CAT7_MIN + (ExtraBits & 0x1F);
        }
        else if ( Token == DCT_VAL_CATEGORY8 )
        {
            // Bit 9 determines sign, Bit 0-8 the value
            if ( ExtraBits & 0x200 )
                ExpandedBlock[*CoeffIndex] = -(DCT_VAL_CAT8_MIN + (ExtraBits & 0x1FF));
            else
                ExpandedBlock[*CoeffIndex] = DCT_VAL_CAT8_MIN + (ExtraBits & 0x1FF);
        }

        // Step on the coefficient index.
        *CoeffIndex += 1;
    }


}

/****************************************************************************
 * 
 *  ROUTINE       :     CopyRecon
 *
 *  INPUTS        :     UINT8 * DestReconPtr
 *                      UINT8 * SrcReconPtr
 *                               
 *  OUTPUTS       :     None
 *
 *  RETURNS       :     None
 *
 *  FUNCTION      :     Copies the current reconstruction to the last frame
 *                      reconstruction buffer.
 *
 *  SPECIAL NOTES :     
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void CopyRecon( PB_INSTANCE *pbi, UINT8 * DestReconPtr, UINT8 * SrcReconPtr )
{
    UINT32  i;
    UINT32	PlaneLineStep;		// Pixels per line
    UINT32  PixelIndex;

	UINT8  *SrcPtr;	            // Pointer to line of source image data
	UINT8  *DestPtr;            // Pointer to line of destination image data

    //static Temp = 0;

    // Copy over only updated blocks.

    // First Y plane
    PlaneLineStep = pbi->Configuration.YStride;
    for ( i = 0; i < pbi->YPlaneFragments; i++ )
    {
        if ( pbi->display_fragments[i] )
        {
            PixelIndex = ReconGetFragIndex ( pbi->recon_pixel_index_table, i );
            SrcPtr = &SrcReconPtr[ PixelIndex ];
            DestPtr = &DestReconPtr[ PixelIndex ];

			pbi->CopyBlock(SrcPtr, DestPtr, PlaneLineStep);
        }
    }

    // Then U and V
    PlaneLineStep = pbi->Configuration.UVStride;
    for ( i = pbi->YPlaneFragments; i < pbi->UnitFragments; i++ )
    {
        if ( pbi->display_fragments[i] )
        {
            PixelIndex = ReconGetFragIndex ( pbi->recon_pixel_index_table, i );
            SrcPtr = &SrcReconPtr[ PixelIndex ];
            DestPtr = &DestReconPtr[ PixelIndex ];

			pbi->CopyBlock(SrcPtr, DestPtr, PlaneLineStep);
			
        }
    }

    // We may need to update the UMV border
    UpdateUMVBorder(pbi, DestReconPtr);

}
/****************************************************************************
 * 
 *  ROUTINE       :     CopyRecon
 *
 *  INPUTS        :     UINT8 * DestReconPtr
 *                      UINT8 * SrcReconPtr
 *                               
 *  OUTPUTS       :     None
 *
 *  RETURNS       :     None
 *
 *  FUNCTION      :     Copies the current reconstruction to the last frame
 *                      reconstruction buffer.
 *
 *  SPECIAL NOTES :     
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void CopyNotRecon( PB_INSTANCE *pbi, UINT8 * DestReconPtr, UINT8 * SrcReconPtr )
{
    UINT32  i;
    UINT32	PlaneLineStep;		// Pixels per line
    UINT32  PixelIndex;

	UINT8  *SrcPtr;	            // Pointer to line of source image data
	UINT8  *DestPtr;            // Pointer to line of destination image data

    //static Temp = 0;

    // Copy over only updated blocks.

    // First Y plane
    PlaneLineStep = pbi->Configuration.YStride;
    for ( i = 0; i < pbi->YPlaneFragments; i++ )
    {
        if ( !pbi->display_fragments[i] )
        {
            PixelIndex = ReconGetFragIndex ( pbi->recon_pixel_index_table, i );
            SrcPtr = &SrcReconPtr[ PixelIndex ];
            DestPtr = &DestReconPtr[ PixelIndex ];

			pbi->CopyBlock(SrcPtr, DestPtr, PlaneLineStep);
        }
    }

    // Then U and V
    PlaneLineStep = pbi->Configuration.UVStride;
    for ( i = pbi->YPlaneFragments; i < pbi->UnitFragments; i++ )
    {
        if ( !pbi->display_fragments[i] )
        {
            PixelIndex = ReconGetFragIndex ( pbi->recon_pixel_index_table, i );
            SrcPtr = &SrcReconPtr[ PixelIndex ];
            DestPtr = &DestReconPtr[ PixelIndex ];

			pbi->CopyBlock(SrcPtr, DestPtr, PlaneLineStep);
			
        }
    }

    // We may need to update the UMV border
    UpdateUMVBorder(pbi, DestReconPtr);

}

/****************************************************************************
 * 
 *  ROUTINE       :     UpdateUMVBorder
 *
 *  INPUTS        :     UINT8 * DestReconPtr
 *                               
 *  OUTPUTS       :     None
 *
 *  RETURNS       :     None
 *
 *  FUNCTION      :     Updates the UMV border for the given reconstruction 
 *                      buffer.
 *
 *  SPECIAL NOTES :     
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void UpdateUMVBorder( PB_INSTANCE *pbi, UINT8 * DestReconPtr )
{
    UINT32  PlaneFragOffset;

    // Y plane
    PlaneFragOffset = 0;
    UpdateUMV_VBorders( pbi, DestReconPtr, PlaneFragOffset );
    UpdateUMV_HBorders( pbi, DestReconPtr, PlaneFragOffset );

    // Then the U and V Planes
    PlaneFragOffset = pbi->YPlaneFragments;
    UpdateUMV_VBorders( pbi, DestReconPtr, PlaneFragOffset );
    UpdateUMV_HBorders( pbi, DestReconPtr, PlaneFragOffset );

    PlaneFragOffset = pbi->YPlaneFragments + pbi->UVPlaneFragments;   
    UpdateUMV_VBorders( pbi, DestReconPtr, PlaneFragOffset );
    UpdateUMV_HBorders( pbi, DestReconPtr, PlaneFragOffset );
}


/****************************************************************************
 * 
 *  ROUTINE       :     UpdateUMV_HBorders
 *
 *  INPUTS        :     UINT8 * DestReconPtr
 *                      UINT32  PlaneFragOffset
 *                      
 *  OUTPUTS       :     None
 *
 *  RETURNS       :     None
 *
 *  FUNCTION      :     Fills in the Horizontal UMV borders for the given 
 *                      reconstruction buffer.
 *
 *  SPECIAL NOTES :     
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void UpdateUMV_HBorders( PB_INSTANCE *pbi, UINT8 * DestReconPtr, UINT32  PlaneFragOffset )
{
    UINT32  i;
    UINT32  PixelIndex;

    UINT32  PlaneStride;
    UINT32  BlockVStep;
    UINT32  PlaneFragments;
    UINT32  LineFragments;
    UINT32  PlaneBorderWidth;

	UINT8   *SrcPtr1;            // Pointer into destination buffer
	UINT8   *SrcPtr2;            // Pointer into destination buffer
	UINT8   *DestPtr1;           // Pointer into destination buffer
	UINT8   *DestPtr2;           // Pointer into destination buffer

    // Work out various plane specific values
    if ( PlaneFragOffset == 0 )
    {
        // Y Plane
        BlockVStep = (pbi->Configuration.YStride * (pbi->Configuration.VFragPixels - 1));
        PlaneStride = pbi->Configuration.YStride;
        PlaneBorderWidth = UMV_BORDER;
        PlaneFragments = pbi->YPlaneFragments;
        LineFragments = pbi->HFragments;
    }
    else
    {
        // U or V plane.
        BlockVStep = (pbi->Configuration.UVStride * (pbi->Configuration.VFragPixels - 1));
        PlaneStride = pbi->Configuration.UVStride;
        PlaneBorderWidth = UMV_BORDER / 2;
        PlaneFragments = pbi->UVPlaneFragments;
        LineFragments = pbi->HFragments / 2;
    }

    // Setup the source and destination pointers for the top and bottom borders
    PixelIndex = ReconGetFragIndex ( pbi->recon_pixel_index_table, PlaneFragOffset );
    SrcPtr1 = &DestReconPtr[ PixelIndex - PlaneBorderWidth ];
    DestPtr1 = SrcPtr1 - (PlaneBorderWidth * PlaneStride);

    PixelIndex = ReconGetFragIndex ( pbi->recon_pixel_index_table, PlaneFragOffset + PlaneFragments - LineFragments ) + BlockVStep;
    SrcPtr2 = &DestReconPtr[ PixelIndex - PlaneBorderWidth];
    DestPtr2 = SrcPtr2 + PlaneStride;

    // Now copy the top and bottom source lines into each line of the respective borders
    for ( i = 0; i < PlaneBorderWidth; i++ )
    {
        memcpy( DestPtr1, SrcPtr1, PlaneStride );
        memcpy( DestPtr2, SrcPtr2, PlaneStride );
        DestPtr1 += PlaneStride;
        DestPtr2 += PlaneStride;
    }
}


/****************************************************************************
 * 
 *  ROUTINE       :     UpdateUMV_VBorders
 *
 *  INPUTS        :     UINT8 * DestReconPtr
 *                      UINT32  PlaneFragOffset
 *                      
 *  OUTPUTS       :     None
 *
 *  RETURNS       :     None
 *
 *  FUNCTION      :     Fills in the vertical UMV borders for the given 
 *                      reconstruction buffer.
 *
 *  SPECIAL NOTES :     
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void UpdateUMV_VBorders( PB_INSTANCE *pbi, UINT8 * DestReconPtr, UINT32  PlaneFragOffset )
{
    UINT32  i;
    UINT32  PixelIndex;

    UINT32  PlaneStride;
    UINT32  LineFragments;
    UINT32  PlaneBorderWidth;
    UINT32  PlaneHeight;

	UINT8   *SrcPtr1;            // Pointer into destination buffer
	UINT8   *SrcPtr2;            // Pointer into destination buffer
	UINT8   *DestPtr1;           // Pointer into destination buffer
	UINT8   *DestPtr2;           // Pointer into destination buffer

    // Work out various plane specific values
    if ( PlaneFragOffset == 0 )
    {
        // Y Plane
        PlaneStride = pbi->Configuration.YStride;
        PlaneBorderWidth = UMV_BORDER;
        LineFragments = pbi->HFragments;
        PlaneHeight = pbi->Configuration.VideoFrameHeight;
    }
    else
    {
        // U or V plane.
        PlaneStride = pbi->Configuration.UVStride;
        PlaneBorderWidth = UMV_BORDER / 2;
        LineFragments = pbi->HFragments / 2;
        PlaneHeight = pbi->Configuration.VideoFrameHeight / 2;
    }

    // Setup the source data values and destination pointers for the left and right edge borders
    PixelIndex = ReconGetFragIndex ( pbi->recon_pixel_index_table, PlaneFragOffset );
    SrcPtr1 = &DestReconPtr[ PixelIndex ];
    DestPtr1 = &DestReconPtr[ PixelIndex - PlaneBorderWidth ];

    PixelIndex = ReconGetFragIndex ( pbi->recon_pixel_index_table, PlaneFragOffset + LineFragments - 1 ) + (pbi->Configuration.HFragPixels - 1);
    SrcPtr2 = &DestReconPtr[ PixelIndex ];
    DestPtr2 = &DestReconPtr[ PixelIndex + 1 ];

    // Now copy the top and bottom source lines into each line of the respective borders
    for ( i = 0; i < PlaneHeight; i++ )
    {
        memset( DestPtr1, SrcPtr1[0], PlaneBorderWidth );
        memset( DestPtr2, SrcPtr2[0], PlaneBorderWidth );
        SrcPtr1 += PlaneStride;
        SrcPtr2 += PlaneStride;
        DestPtr1 += PlaneStride;
        DestPtr2 += PlaneStride;
    }
}

/****************************************************************************
 * 
 *  ROUTINE       :     ClearDownQFragData
 *
 *  INPUTS        :     None. 
 *                      
 *  OUTPUTS       :     None.
 *
 *  RETURNS       :     None.
 *
 *  FUNCTION      :     Clears down the data structure that is used
 *                      to store quantised dct coefficients for each block.
 *
 *  SPECIAL NOTES :     None. 
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void ClearDownQFragData(PB_INSTANCE *pbi)
{
    INT32       i,j;
    UINT16 *    QFragPtr;
	
	for ( i = 0; i < pbi->CodedBlockIndex; i++ )
	{
		// Get the linear index for the current fragment.
		QFragPtr = (UINT16*)(&pbi->QFragData[pbi->CodedBlockList[i]]);
		for ( j = 0; j < 8; j++ )
		{
			QFragPtr[0]  = 0;
			QFragPtr[1]  = 0;
			QFragPtr[2]  = 0;
			QFragPtr[3]  = 0;
			QFragPtr[4]  = 0;
			QFragPtr[5]  = 0;
			QFragPtr[6]  = 0;
			QFragPtr[7]  = 0;
			QFragPtr += 8;
		}
	}
}

/****************************************************************************
 * 
 *  ROUTINE       :     FilterHoriz_Generic
 *
 *  INPUTS        :     None
 *                               
 *  OUTPUTS       :     None
 *
 *  RETURNS       :     None
 *
 *  FUNCTION      :     Applies a loop filter to the vertical edge horizontally
 *
 *  SPECIAL NOTES :     
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void FilterHoriz_Generic(PB_INSTANCE *pbi __attribute__((unused)), UINT8 * PixelPtr, INT32 LineLength, INT32 *BoundingValuePtr)
{
	INT32 j;
	INT32 FiltVal;
    UINT8 * LimitTable = &LimitVal_VP31[VAL_RANGE];
	for ( j = 0; j < 8; j++ )
	{            
		FiltVal =  ( PixelPtr[0] ) - 
			( PixelPtr[1] * 3 ) +
			( PixelPtr[2] * 3 ) - 
			( PixelPtr[3] );
		
		FiltVal = BoundingValuePtr[(FiltVal + 4) >> 3];
		
		PixelPtr[1] = LimitTable[(INT32)PixelPtr[1] + FiltVal];
		PixelPtr[2] = LimitTable[(INT32)PixelPtr[2] - FiltVal];
		
		PixelPtr += LineLength;
	}
}

/****************************************************************************
 * 
 *  ROUTINE       :     FilterVert_Generic
 *
 *  INPUTS        :     None
 *                               
 *  OUTPUTS       :     None
 *
 *  RETURNS       :     None
 *
 *  FUNCTION      :     Applies a loop filter to a horizontal edge vertically
 *
 *  SPECIAL NOTES :     
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void FilterVert_Generic(PB_INSTANCE *pbi __attribute__((unused)), UINT8 * PixelPtr, INT32 LineLength, INT32 *BoundingValuePtr)
{
	INT32 j;
	INT32 FiltVal;
    UINT8 * LimitTable = &LimitVal_VP31[VAL_RANGE];
	for ( j = 0; j < 8; j++ )
	{            
		FiltVal = ( (INT32)PixelPtr[- (2 * LineLength)] ) - 
			( (INT32)PixelPtr[- LineLength] * 3 ) + 
			( (INT32)PixelPtr[0] * 3 ) - 
			( (INT32)PixelPtr[LineLength] );
		
		FiltVal = BoundingValuePtr[(FiltVal + 4) >> 3];
		
		PixelPtr[- LineLength] = LimitTable[(INT32)PixelPtr[- LineLength] + FiltVal];
		PixelPtr[0] = LimitTable[(INT32)PixelPtr[0] - FiltVal];
		
		PixelPtr ++;
	}
}

/****************************************************************************
 * 
 *  ROUTINE       :     SetupBoundingValueArray
 *
 *  INPUTS        :     None
 *                               
 *  OUTPUTS       :     None
 *
 *  RETURNS       :     None
 *
 *  FUNCTION      :     Set up the bounding value array.
 *
 *  SPECIAL NOTES :     
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
INT32 *SetupBoundingValueArray_Generic(PB_INSTANCE *pbi, INT32 FLimit)
{
    INT32 * BoundingValuePtr;
    INT32 i;

    BoundingValuePtr = &pbi->FiltBoundingValue[256];
    // Set up the bounding value array.
    memset ( pbi->FiltBoundingValue, 0, (512*sizeof(*pbi->FiltBoundingValue)) );
    for ( i = 0; i < FLimit; i++ )
    {
        BoundingValuePtr[-i-FLimit] = (-FLimit+i);
        BoundingValuePtr[-i] = -i;
        BoundingValuePtr[i] = i;
        BoundingValuePtr[i+FLimit] = FLimit-i;
    }

    return BoundingValuePtr;
}
/****************************************************************************
 * 
 *  ROUTINE       :     ApplyReconLoopFilter
 *
 *  INPUTS        :     None
 *                               
 *  OUTPUTS       :     None
 *
 *  RETURNS       :     None
 *
 *  FUNCTION      :     Applies a loop filter to the edge pixels of coded blocks.
 *
 *  SPECIAL NOTES :     
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void ApplyReconLoopFilter(PB_INSTANCE *pbi)
{
    INT32 i;

    INT32 * BoundingValuePtr;
    //UINT8 * LimitTable = &LimitVal_VP31[VAL_RANGE];
	int FragsAcross=pbi->HFragments;	
	int FromFragment,ToFragment;
	int FragsDown = pbi->VFragments;
    INT32 LineFragments;
    INT32 LineLength;
    //UINT8 BlockHeight = (UINT8)pbi->Configuration.VFragPixels;
    //UINT8 BlockWidth = (UINT8)pbi->Configuration.HFragPixels;
    INT32 FLimit; 
    INT32 QIndex;
	int j,m,n;

	// Set the limit value for the loop filter based upon the current quantizer.
    QIndex = Q_TABLE_SIZE - 1;
    while ( QIndex >= 0 )
    {
        if ( (QIndex == 0) || ( pbi->QThreshTable[QIndex] >= pbi->ThisFrameQualityValue) )
            break;
        QIndex --;
    }
    FLimit = LoopFilterLimitValuesV1[QIndex];
    if ( FLimit == 0 )
        return;
        
    BoundingValuePtr = pbi->SetupBoundingValueArray(pbi, FLimit);
 

	for ( j = 0; j < 3 ; j++)
	{
		switch(j)
		{
		case 0: // y
			FromFragment = 0;
			ToFragment = pbi->YPlaneFragments;
			FragsAcross = pbi->HFragments;
			FragsDown = pbi->VFragments;
			LineLength = pbi->Configuration.YStride;
			LineFragments = pbi->HFragments;
			break;
		case 1: // u
			FromFragment = pbi->YPlaneFragments;
			ToFragment = pbi->YPlaneFragments + pbi->UVPlaneFragments ;
			FragsAcross = pbi->HFragments >> 1;
			FragsDown = pbi->VFragments >> 1;
			LineLength = pbi->Configuration.UVStride;
			LineFragments = pbi->HFragments / 2;
			break;
		case 2:	// v
		default: // Johns: to avoid uninitialized warnings
			FromFragment = pbi->YPlaneFragments + pbi->UVPlaneFragments;
			ToFragment = pbi->YPlaneFragments + (2 * pbi->UVPlaneFragments) ;
			FragsAcross = pbi->HFragments >> 1;
			FragsDown = pbi->VFragments >> 1;
			LineLength = pbi->Configuration.UVStride;
			LineFragments = pbi->HFragments / 2;
			break;
		}

		i=FromFragment;

		//****************************************************************************************************************
		// First Row 
		//****************************************************************************************************************

		//******************************************************************
		// first column conditions
		
		// only do 2 prediction if fragment coded and on non intra or if all fragments are intra 
		if( pbi->display_fragments[i])
		{
			
			// Filter right hand border only if the block to the right is not coded
			if ( !pbi->display_fragments[ i + 1 ] )
			{
				pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) + 6 ], LineLength, BoundingValuePtr);
			}
			
			// Bottom done if next row set
			if( !pbi->display_fragments[ i + LineFragments] )
			{
				pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i + LineFragments) ], LineLength, BoundingValuePtr);
			}
			
		} // if( pbi->display_fragments[i])
		
		i++; // next i
		
		//******************************************************************
		// middle columns 
		for ( n = 1 ; n < FragsAcross - 1 ; n++, i++)
		{
			if( pbi->display_fragments[i])
			{
				// Filter Left edge always
				pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) - 2 ], LineLength, BoundingValuePtr);
				
				// Filter right hand border only if the block to the right is not coded
				if ( !pbi->display_fragments[ i + 1 ] )
				{
					pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) + 6 ], LineLength, BoundingValuePtr);
				}
				
				// Bottom done if next row set
				if( !pbi->display_fragments[ i + LineFragments] )
				{
					pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i + LineFragments) ], LineLength, BoundingValuePtr);
				}
				
				
			} // if( pbi->display_fragments[i])
			
		} // for ( n = 1 ; n < FragsAcross - 1 ; n++, i++)
		
		//******************************************************************
		// Last Column
		if( pbi->display_fragments[i])
		{
			// Filter Left edge always
			pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) - 2 ], LineLength, BoundingValuePtr);
			
			// Bottom done if next row set
			if( !pbi->display_fragments[ i + LineFragments] )
			{
				pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i + LineFragments) ], LineLength, BoundingValuePtr);
			}
			
		} // if( pbi->display_fragments[i])
		
		i++; // next i

		//****************************************************************************************************************
		// Middle Rows
		//****************************************************************************************************************
		for ( m = 1 ; m < FragsDown-1 ; m++)
		{

			//******************************************************************
			// first column conditions
			
			// only do 2 prediction if fragment coded and on non intra or if all fragments are intra 
			if( pbi->display_fragments[i])
			{

				// TopRow is always done
				pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) ], LineLength, BoundingValuePtr);

				// Filter right hand border only if the block to the right is not coded
				if ( !pbi->display_fragments[ i + 1 ] )
				{
					pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) + 6 ], LineLength, BoundingValuePtr);
				}

				// Bottom done if next row set
				if( !pbi->display_fragments[ i + LineFragments] )
				{
					pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i + LineFragments) ], LineLength, BoundingValuePtr);
				}
				
			} // if( pbi->display_fragments[i])

			i++; // next i

			//******************************************************************
			// middle columns 
			for ( n = 1 ; n < FragsAcross - 1 ; n++, i++)
			{
				if( pbi->display_fragments[i])
				{
					// Filter Left edge always
					pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) - 2 ], LineLength, BoundingValuePtr);

					// TopRow is always done
					pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) ], LineLength, BoundingValuePtr);

					// Filter right hand border only if the block to the right is not coded
					if ( !pbi->display_fragments[ i + 1 ] )
					{
						pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) + 6 ], LineLength, BoundingValuePtr);
					}

					// Bottom done if next row set
					if( !pbi->display_fragments[ i + LineFragments] )
					{
						pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i + LineFragments) ], LineLength, BoundingValuePtr);
					}
					
					
				} // if( pbi->display_fragments[i])

			} // for ( n = 1 ; n < FragsAcross - 1 ; n++, i++)

			//******************************************************************
			// Last Column
			if( pbi->display_fragments[i])
			{
				// Filter Left edge always
				pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) - 2 ], LineLength, BoundingValuePtr);
				
				// TopRow is always done
				pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) ], LineLength, BoundingValuePtr);
				
				// Bottom done if next row set
				if( !pbi->display_fragments[ i + LineFragments] )
				{
					pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i + LineFragments) ], LineLength, BoundingValuePtr);
				}

			} // if( pbi->display_fragments[i])

			i++; // next i


		} // for ( m = 0 ; m < FragsDown ; m++)

	} // for ( j = 0; j < 3 ; j++)
		
	//****************************************************************************************************************
	// Last Row 
	//****************************************************************************************************************
	
	//******************************************************************
	// first column conditions
	
	// only do 2 prediction if fragment coded and on non intra or if all fragments are intra 
	if( pbi->display_fragments[i])
	{
		
		// TopRow is always done
		pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) ], LineLength, BoundingValuePtr);
		
		// Filter right hand border only if the block to the right is not coded
		if ( !pbi->display_fragments[ i + 1 ] )
		{
			pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) + 6 ], LineLength, BoundingValuePtr);
		}
		
	} // if( pbi->display_fragments[i])
	
	i++; // next i
	
	//******************************************************************
	// middle columns 
	for ( n = 1 ; n < FragsAcross - 1 ; n++, i++)
	{
		if( pbi->display_fragments[i])
		{
			// Filter Left edge always
			pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) - 2 ], LineLength, BoundingValuePtr);
			
			// TopRow is always done
			pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) ], LineLength, BoundingValuePtr);
			
			// Filter right hand border only if the block to the right is not coded
			if ( !pbi->display_fragments[ i + 1 ] )
			{
				pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) + 6 ], LineLength, BoundingValuePtr);
			}
			
		} // if( pbi->display_fragments[i])
		
	} // for ( n = 1 ; n < FragsAcross - 1 ; n++, i++)
	
	//******************************************************************
	// Last Column
	if( pbi->display_fragments[i])
	{
		// Filter Left edge always
		pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) - 2 ], LineLength, BoundingValuePtr);
		
		// TopRow is always done
		pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) ], LineLength, BoundingValuePtr);
		
	} // if( pbi->display_fragments[i])
	
	i++; // next i
	

}


/****************************************************************************
 * 
 *  ROUTINE       :     LoopFilter
 *
 *  INPUTS        :     None
 *                               
 *  OUTPUTS       :     None
 *
 *  RETURNS       :     None
 *
 *  FUNCTION      :     Applies a loop filter to the edge pixels of coded blocks.
 *
 *  SPECIAL NOTES :     
 *
 *
 *  ERRORS        :     None.
 *
 ****************************************************************************/
void LoopFilter(PB_INSTANCE *pbi)
{
    INT32 i;

    INT32 * BoundingValuePtr;
    //UINT8 * LimitTable = &LimitVal_VP31[VAL_RANGE];
	int FragsAcross=pbi->HFragments;	
	int FromFragment,ToFragment;
	int FragsDown = pbi->VFragments;
    INT32 LineFragments;
    INT32 LineLength;
    //UINT8 BlockHeight = (UINT8)pbi->Configuration.VFragPixels;
    //UINT8 BlockWidth = (UINT8)pbi->Configuration.HFragPixels;
    INT32 FLimit; 
    INT32 QIndex;
	int j,m,n;

	// Set the limit value for the loop filter based upon the current quantizer.
    QIndex = Q_TABLE_SIZE - 1;
    while ( QIndex >= 0 )
    {
        if ( (QIndex == 0) || ( pbi->QThreshTable[QIndex] >= pbi->ThisFrameQualityValue) )
            break;
        QIndex --;
    }

	// Encoder version specific clause
	FLimit = LoopFilterLimitValuesV1[QIndex];

    if ( FLimit == 0 )
        return;
        
    BoundingValuePtr = pbi->SetupBoundingValueArray(pbi, FLimit);
 

	for ( j = 0; j < 3 ; j++)
	{
		switch(j)
		{
		case 0: // y
			FromFragment = 0;
			ToFragment = pbi->YPlaneFragments;
			FragsAcross = pbi->HFragments;
			FragsDown = pbi->VFragments;
			LineLength = pbi->Configuration.YStride;
			LineFragments = pbi->HFragments;
			break;
		case 1: // u
			FromFragment = pbi->YPlaneFragments;
			ToFragment = pbi->YPlaneFragments + pbi->UVPlaneFragments ;
			FragsAcross = pbi->HFragments >> 1;
			FragsDown = pbi->VFragments >> 1;
			LineLength = pbi->Configuration.UVStride;
			LineFragments = pbi->HFragments / 2;
			break;
		case 2:	// v
		default: // Johns: to avoid uninitialized warnings
			FromFragment = pbi->YPlaneFragments + pbi->UVPlaneFragments;
			ToFragment = pbi->YPlaneFragments + (2 * pbi->UVPlaneFragments) ;
			FragsAcross = pbi->HFragments >> 1;
			FragsDown = pbi->VFragments >> 1;
			LineLength = pbi->Configuration.UVStride;
			LineFragments = pbi->HFragments / 2;
			break;
		}

		i=FromFragment;

		//****************************************************************************************************************
		// First Row 
		//****************************************************************************************************************

		//******************************************************************
		// first column conditions
		
		// only do 2 prediction if fragment coded and on non intra or if all fragments are intra 
		if( pbi->display_fragments[i])
		{
			
			// Filter right hand border only if the block to the right is not coded
			if ( !pbi->display_fragments[ i + 1 ] )
			{
				pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) + 6 ], LineLength, BoundingValuePtr);
			}
			
			// Bottom done if next row set
			if( !pbi->display_fragments[ i + LineFragments] )
			{
				pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i + LineFragments) ], LineLength, BoundingValuePtr);
			}
			
		} // if( pbi->display_fragments[i])
		
		i++; // next i
		
		//******************************************************************
		// middle columns 
		for ( n = 1 ; n < FragsAcross - 1 ; n++, i++)
		{
			if( pbi->display_fragments[i])
			{
				// Filter Left edge always
				pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) - 2 ], LineLength, BoundingValuePtr);
				
				// Filter right hand border only if the block to the right is not coded
				if ( !pbi->display_fragments[ i + 1 ] )
				{
					pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) + 6 ], LineLength, BoundingValuePtr);
				}
				
				// Bottom done if next row set
				if( !pbi->display_fragments[ i + LineFragments] )
				{
					pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i + LineFragments) ], LineLength, BoundingValuePtr);
				}
				
				
			} // if( pbi->display_fragments[i])
			
		} // for ( n = 1 ; n < FragsAcross - 1 ; n++, i++)
		
		//******************************************************************
		// Last Column
		if( pbi->display_fragments[i])
		{
			// Filter Left edge always
			pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) - 2 ], LineLength, BoundingValuePtr);
			
			// Bottom done if next row set
			if( !pbi->display_fragments[ i + LineFragments] )
			{
				pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i + LineFragments) ], LineLength, BoundingValuePtr);
			}
			
		} // if( pbi->display_fragments[i])
		
		i++; // next i

		//****************************************************************************************************************
		// Middle Rows
		//****************************************************************************************************************
		for ( m = 1 ; m < FragsDown-1 ; m++)
		{

			//******************************************************************
			// first column conditions
			
			// only do 2 prediction if fragment coded and on non intra or if all fragments are intra 
			if( pbi->display_fragments[i])
			{

				// TopRow is always done
				pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) ], LineLength, BoundingValuePtr);

				// Filter right hand border only if the block to the right is not coded
				if ( !pbi->display_fragments[ i + 1 ] )
				{
					pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) + 6 ], LineLength, BoundingValuePtr);
				}

				// Bottom done if next row set
				if( !pbi->display_fragments[ i + LineFragments] )
				{
					pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i + LineFragments) ], LineLength, BoundingValuePtr);
				}
				
			} // if( pbi->display_fragments[i])

			i++; // next i

			//******************************************************************
			// middle columns 
			for ( n = 1 ; n < FragsAcross - 1 ; n++, i++)
			{
				if( pbi->display_fragments[i])
				{
					// Filter Left edge always
					pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) - 2 ], LineLength, BoundingValuePtr);

					// TopRow is always done
					pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) ], LineLength, BoundingValuePtr);

					// Filter right hand border only if the block to the right is not coded
					if ( !pbi->display_fragments[ i + 1 ] )
					{
						pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) + 6 ], LineLength, BoundingValuePtr);
					}

					// Bottom done if next row set
					if( !pbi->display_fragments[ i + LineFragments] )
					{
						pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i + LineFragments) ], LineLength, BoundingValuePtr);
					}
					
					
				} // if( pbi->display_fragments[i])

			} // for ( n = 1 ; n < FragsAcross - 1 ; n++, i++)

			//******************************************************************
			// Last Column
			if( pbi->display_fragments[i])
			{
				// Filter Left edge always
				pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) - 2 ], LineLength, BoundingValuePtr);
				
				// TopRow is always done
				pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) ], LineLength, BoundingValuePtr);
				
				// Bottom done if next row set
				if( !pbi->display_fragments[ i + LineFragments] )
				{
					pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i + LineFragments) ], LineLength, BoundingValuePtr);
				}

			} // if( pbi->display_fragments[i])

			i++; // next i


		} // for ( m = 0 ; m < FragsDown ; m++)

		
		//****************************************************************************************************************
		// Last Row 
		//****************************************************************************************************************
		
		//******************************************************************
		// first column conditions
		
		// only do 2 prediction if fragment coded and on non intra or if all fragments are intra 
		if( pbi->display_fragments[i])
		{
			
			// TopRow is always done
			pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) ], LineLength, BoundingValuePtr);
			
			// Filter right hand border only if the block to the right is not coded
			if ( !pbi->display_fragments[ i + 1 ] )
			{
				pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) + 6 ], LineLength, BoundingValuePtr);
			}
			
		} // if( pbi->display_fragments[i])
		
		i++; // next i
		
		//******************************************************************
		// middle columns 
		for ( n = 1 ; n < FragsAcross - 1 ; n++, i++)
		{
			if( pbi->display_fragments[i])
			{
				// Filter Left edge always
				pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) - 2 ], LineLength, BoundingValuePtr);
				
				// TopRow is always done
				pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) ], LineLength, BoundingValuePtr);
				
				// Filter right hand border only if the block to the right is not coded
				if ( !pbi->display_fragments[ i + 1 ] )
				{
					pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) + 6 ], LineLength, BoundingValuePtr);
				}
				
			} // if( pbi->display_fragments[i])
			
		} // for ( n = 1 ; n < FragsAcross - 1 ; n++, i++)
		
		//******************************************************************
		// Last Column
		if( pbi->display_fragments[i])
		{
			// Filter Left edge always
			pbi->FilterHoriz(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) - 2 ], LineLength, BoundingValuePtr);
			
			// TopRow is always done
			pbi->FilterVert(pbi, &pbi->LastFrameRecon[ ReconGetFragIndex(pbi->recon_pixel_index_table, i) ], LineLength, BoundingValuePtr);
			
		} // if( pbi->display_fragments[i])
		
		i++; // next i

	} // for ( j = 0; j < 3 ; j++)

}




