/******************************************************************************
 *                                                                          
 * This software module was originally developed by 
 *
 * Cor Quist (KPN / ACTS-MoMuSys).     			              	
 *
 * and edited by 
 *
 * Robert Danielsen (Telenor / ACTS-MoMuSys). 	    	              	
 * Noel Brady (TELTEC IRELAND / ACTS-MoMuSys). 
 * Jan De Lameillieure (HHI / ACTS-MoMuSys).     	              	
 * Michael Wollborn (TUH / ACTS-MoMuSys). 	    	              	
 * Minhua Zhou (HHI / ACTS-MoMuSys)
 * Bob Eifrig (NextLevel Systems)
 * Michael Frater (UNSW)
 * Claudia Billotet-Hoffmann (T-Berkom / ACTS-MoMuSys)
 *
 * in the course of development of the MPEG-4 Video (ISO/IEC 14496-2) standard.
 * This software module is an implementation of a part of one or more MPEG-4 
 * Video (ISO/IEC 14496-2) tools as specified by the MPEG-4 Video (ISO/IEC 
 * 14496-2) standard. 
 *
 * ISO/IEC gives users of the MPEG-4 Video (ISO/IEC 14496-2) standard free 
 * license to this software module or modifications thereof for use in hardware
 * or software products claiming conformance to the MPEG-4 Video (ISO/IEC 
 * 14496-2) standard. 
 *
 * Those intending to use this software module in hardware or software products
 * are advised that its use may infringe existing patents. The original 
 * developer of this software module and his/her company, the subsequent 
 * editors and their companies, and ISO/IEC have no liability for use of this 
 * software module or modifications thereof in an implementation. Copyright is 
 * not released for non MPEG-4 Video (ISO/IEC 14496-2) standard conforming 
 * products. 
 *
 * ACTS-MoMuSys partners retain full right to use the code for his/her own 
 * purpose, assign or donate the code to a third party and to inhibit third 
 * parties from using the code for non MPEG-4 Video (ISO/IEC 14496-2) standard
 * conforming products. This copyright notice must be included in all copies or
 * derivative works. 
 *
 * Copyright (c) 1997
 *
 *****************************************************************************/


/***********************************************************HeaderBegin*******
 *                                                                         
 * File: text_code_mb.c
 *
 * Author: Telenor, TMN
 * Created: 
 *                                                                         
 * Description: texture encoding  
 *
 * Notes:  
 *
 * Modified:
 *	Robert Danielsen, Feb 14, 1996
 *  	Cor Quist -- 26-Feb-96
 *  	Cor Quist -- 11-Apr-96
 *  	Cor Quist -- 16 April 96
 *   	21.04.96 Robert Danielsen: Reformatted. New headers.
 *   	23.09.96 Cor Quist: Added MPEG-2 DCT-function
 *	23.10.96 Robert Danielsen: Removed Dct(), also did some other
 *			cleaning up.
 *		04.02.97 Noel O'Connor: removed all calls to assert()
 *      14-MAR-97 Jan De Lameillieure : integrated SA-DCT
 *      20-MAR-97 Jan De Lameillieure : added "conservative" subsampling of chroma
 *      16-JUN-97 Jan De Lameillieure : renaming some include files to sadct_*
 *      16-JUN-97 Jan De Lameillieure : added Kaup-SADCT
 *      04.01.98 Michael Frater: support for non-8-bit video
 *      7. 3. 98 C.Billotet-Hoffmann: cleaning
 *
 ***********************************************************HeaderEnd*********/

/************************    INCLUDE FILES    ********************************/

#include <stdlib.h>
#include "text_util.h"		/* Added 19-JUN-1996, IC */
#include "text_defs.h"
#include "text_code_mb.h"
#include "mom_access.h"
#include "vm_config.h"		/* Added 20-MAR-97, JDL, because of "GRAY_SCALE" */

/* include files necessary for the SA-DCT */

#ifndef _WD_MODE_
#include "sadct_bsnrmem.h"
#include "sadct.h"
#include "sadct_momusys.h"
#include "sadct_momusys_kaup.h"
#endif

#define BLOCK_SIZE 8

/***********************************************************CommentBegin******
 *
 * -- CodeMB -- Code, decode and reconstruct Macroblock
 *
 * Author :		
 *	Robert Danielsen, Telenor R&D, <Robert.Danielsen@nta.no>
 *
 * Created :		
 *	28.06.96
 *
 * Purpose :		
 *	Code, decode and reconstruct Macroblock
 * 
 * Arguments in : 	
 *	Int x_pos	x_position of Macroblock
 *	Int y_pos	y_position of Macroblock
 *	UInt width	width of Vop bounding box
 *	Int QP		Quantization parameter
 *	Int Mode	Macroblock coding mode
 *	Int transp_pattern[] Pattern of transparent blocks in MB
 *
 * Arguments in/out :	
 *	Vop *curr	current Vop, uncoded
 *	Vop *rec_curr	current Vop, decoded and reconstructed
 *
 * Arguments out :	
 *  Int *fieldDCT : field DCT permutation (if non-zero)
 *
 * Return values :	
 *	Int *		array of quantized coefficients
 *
 * Side effects :	
 *
 * Description :	
 *
 * See also :
 *
 * Modified :		
 *	27.02.97  Robert Danielsen: Added type parameter to signal luma or
 *			  chroma to the nonlinear quantization.
 *  	14-MAR-97 Jan De Lameillieure : integrated SA-DCT
 *  	20-MAR-97 Jan De Lameillieure : added "conservative" subsampling
 *			  of chroma
 *	22-APR-97 Michael Wollborn: changed name of BlockQuant to 
 *			  BlockQuantH263 (and for dequant. also) and changed
 *			  stuff for MPEG-like quantization
 *  	14-05-97  Minhua Zhou: let SADCT use the reconstructed shape  
 *  	14-05-97  Minhua Zhou: disable SADCT when rectangular VOP
 *  	11-08-97  Minhua Zhou: added clipping for MODE_INTRA_Q mode 
 *  	11.12.97  Bob Eifrig: Field DCT test & permutation
 *
 ***********************************************************CommentEnd********/

Int *CodeMB(Vop *curr, Vop *rec_curr, Int x_pos, Int y_pos, UInt width,
            Int QP, Int Mode, Int MB_transp_pattern[], Int *fieldDCT)
{
    Int k;
    Int fblock[6][8][8];
    Int coeff[384];
    Int *coeff_ind;
    Int *qcoeff;
    Int *qcoeff_ind;
    Int* rcoeff_ind;
    Int x, y;
    SInt *current, *recon = NULL;
    UInt xwidth;
    Int iblock[6][8][8];
    Int rcoeff[6*64];
    Int i, j;
    Int type;                   /* luma = 1, chroma = 2 */
    Int *qmat;

    /* variables for the SADCT */

    Short *alpha_pntr = (Short *)(GetImageData(GetVopA(rec_curr)));
    Short alpha_block[BLOCK_SIZE][BLOCK_SIZE];
    Short nrpix = GetImageSizeX(GetVopA(rec_curr));
    Short tmp;  

    qcoeff = (Int *) malloc (sizeof (Int) * 384);
    coeff_ind = coeff;
    qcoeff_ind = qcoeff;
    rcoeff_ind = rcoeff;

    for (k = 0; k < 6; k++) {
        switch (k) {
        case 0:
            x = x_pos;
            y = y_pos;
            xwidth = width;
            current = (SInt *) GetImageData (GetVopY (curr));
            break;
        case 1:
            x = x_pos + 8;
            y = y_pos;
            xwidth = width;
            current = (SInt *) GetImageData (GetVopY (curr));
            break;
        case 2:
            x = x_pos;
            y = y_pos + 8;
            xwidth = width;
            current = (SInt *) GetImageData (GetVopY (curr));
            break;
        case 3:
            x = x_pos + 8;
            y = y_pos + 8;
            xwidth = width;
            current = (SInt *) GetImageData (GetVopY (curr));
            break;
        case 4:
            x = x_pos / 2;
            y = y_pos / 2;
            xwidth = width / 2;
            current = (SInt *) GetImageData (GetVopU (curr));
            break;
        case 5:
            x = x_pos / 2;
            y = y_pos / 2;
            xwidth = width / 2;
            current = (SInt *) GetImageData (GetVopV (curr));
            break;
        default:
            fprintf (stdout, "CodeMB (): Non-existing case in switch statement\n");
            exit (-1);
            break;
        }
        BlockPredict (current, recon, x, y, xwidth, fblock[k]);
    }
    if (curr->interlaced && (fieldDCT != NULL))
        *fieldDCT = FrameFieldDCTDecide(&fblock[0][0][0]);

    for (k = 0; k < 6; k++) {
      if ((GetVopSADCTDisable(curr)==0)&&(GetVopShape(curr)!=0)) {
        switch(k) {
          case 0 :
            for (i=0; i<BLOCK_SIZE; i++)
              for (j=0; j<BLOCK_SIZE; j++)
                alpha_block[i][j] = alpha_pntr[(y_pos+i)*nrpix + (x_pos+j)];
            break;
          case 1 :
            for (i=0; i<BLOCK_SIZE; i++)
              for (j=0; j<BLOCK_SIZE; j++)
                alpha_block[i][j] = alpha_pntr[(y_pos+i)*nrpix + (x_pos+8+j)];
            break;
          case 2 :
            for (i=0; i<BLOCK_SIZE; i++)
              for (j=0; j<BLOCK_SIZE; j++)
                alpha_block[i][j] = alpha_pntr[(y_pos+8+i)*nrpix + (x_pos+j)];
            break;
          case 3 :
            for (i=0; i<BLOCK_SIZE; i++)
              for (j=0; j<BLOCK_SIZE; j++)
                alpha_block[i][j] = alpha_pntr[(y_pos+8+i)*nrpix + (x_pos+8+j)];
            break;
          case 4 :
          case 5 :
            for (i=0; i<BLOCK_SIZE; i++)
              for (j=0; j<BLOCK_SIZE; j++) {
                if (GetVopShape(curr) == GREY_SCALE) {
                  tmp = alpha_pntr[(y_pos+2*i)*nrpix + (x_pos+2*j)];
                  tmp += alpha_pntr[(y_pos+2*i)*nrpix + (x_pos+2*j+1)];
                  tmp += alpha_pntr[(y_pos+2*i+1)*nrpix + (x_pos+2*j)];
                  tmp += alpha_pntr[(y_pos+2*i+1)*nrpix + (x_pos+2*j+1)];
                  tmp += 2;
                  tmp /= 4;
                  alpha_block[i][j] = (tmp > BINARY_ALPHA/2) ? BINARY_ALPHA : 0;
                }
                else { /* "conservative" subsampling (JDL - 20-MAR-97) */
                  alpha_block[i][j] = 
                   ((alpha_pntr[(y_pos+2*i)*nrpix + (x_pos+2*j)] == BINARY_ALPHA) ||
                    (alpha_pntr[(y_pos+2*i)*nrpix + (x_pos+2*j+1)] == BINARY_ALPHA) ||
                    (alpha_pntr[(y_pos+2*i+1)*nrpix + (x_pos+2*j)] == BINARY_ALPHA) ||
                    (alpha_pntr[(y_pos+2*i+1)*nrpix + (x_pos+2*j+1)] == BINARY_ALPHA))
                      ? BINARY_ALPHA : 0 ; 
                }
              }
            break;
          default :
            for (i=0; i<BLOCK_SIZE; i++)
              for (j=0; j<BLOCK_SIZE; j++)
                alpha_block[i][j] = BINARY_ALPHA;
        }
      }
      if ((k < 4 && MB_transp_pattern[k] != 1) || (k > 3))
      {
            if ((GetVopSADCTDisable(curr)!=0)||(GetVopShape(curr)==0)) 
              BlockDCT (fblock[k], coeff_ind);
#ifndef _WD_MODE_
            else
              if ((Mode == MODE_INTRA) || (Mode == MODE_INTRA_Q))
                BlockSADCT (fblock[k], coeff_ind, alpha_block);
              else
                BlockSADCT_Kaup (fblock[k], coeff_ind, alpha_block);
#endif
            if (k < 4) type = 1;
            else type = 2;

            /* MW 22-APR-1997 Changes for MPEG quantization */
            if(GetVopQuantType(curr))
              {
                if(Mode==MODE_INTRA || Mode==MODE_INTRA_Q)
                  qmat = GetVopIntraQuantMat(curr);
                else
                  qmat = GetVopNonintraQuantMat(curr);

                BlockQuantMPEG(coeff_ind,QP,Mode,type,qmat,qcoeff_ind,
			       GetVopBrightWhite(curr));
                BlockDequantMPEG(qcoeff_ind,QP,Mode,type,qmat,rcoeff_ind);
              }
            else
              {
                BlockQuantH263(coeff_ind,QP,Mode,type,qcoeff_ind,
			       GetVopBrightWhite(curr)); 
                BlockDequantH263(qcoeff_ind,QP,Mode,type,rcoeff_ind); 
              }

            if ((GetVopSADCTDisable(curr)!=0)||(GetVopShape(curr)==0)) 
              BlockIDCT (rcoeff_ind, iblock[k],GetVopBrightWhite(curr)); 
#ifndef _WD_MODE_
            else
              if ((Mode == MODE_INTRA) || (Mode == MODE_INTRA_Q))
                BlockSAIDCT (rcoeff_ind, iblock[k], alpha_block); 
              else
                BlockSAIDCT_Kaup (rcoeff_ind, iblock[k], alpha_block);
#endif
        }
          else                  /* Transparent block */
        {
            for (i = 0; i < 64; i++)
                qcoeff_ind[i] = 0;
            for (i = 0; i < 8; i++)
                for (j = 0; j < 8; j++)
                    iblock[k][i][j] = 0;
        }

        coeff_ind += 64;
        qcoeff_ind += 64;
        rcoeff_ind += 64;

        if (Mode == MODE_INTRA||Mode==MODE_INTRA_Q)
            for (i = 0; i < 8; i++)
                for (j = 0; j < 8; j ++)
                    iblock[k][i][j] = MIN (GetVopBrightWhite(curr), MAX (0, iblock[k][i][j]));
        if ((GetVopPredictionType(curr)==B_VOP)&&(Mode==4))
           for (i = 0; i < 8; i++)
                for (j = 0; j < 8; j ++)
                    iblock[k][i][j] = 0;

        switch (k) {
        case 0:
        case 1:
        case 2:
            continue;

        case 3:
            if (curr->interlaced && (fieldDCT != NULL) && *fieldDCT)
               fieldDCTtoFrame(&iblock[0][0][0]);
            recon = (SInt *) GetImageData (GetVopY (rec_curr));
            BlockRebuild (recon, x_pos,     y_pos,     width, iblock[0]);
            BlockRebuild (recon, x_pos + 8, y_pos,     width, iblock[1]);
            BlockRebuild (recon, x_pos,     y_pos + 8, width, iblock[2]);
            BlockRebuild (recon, x_pos + 8, y_pos + 8, width, iblock[3]);
            continue;

        case 4:
            BlockRebuild ((SInt *) GetImageData (GetVopU (rec_curr)),
                x_pos/2, y_pos/2, width/2, iblock[4]);
            continue;

        case 5:
            BlockRebuild ((SInt *) GetImageData (GetVopV (rec_curr)),
                x_pos/2, y_pos/2, width/2, iblock[5]);
            continue;
        }
    }
    return qcoeff;
}


/***********************************************************CommentBegin******
 *
 * -- BlockPredict -- Get prediction for an Intra block
 *
 * Author :		
 *	Robert Danielsen, Telenor R&D, <Robert.Danielsen@nta.no>
 *
 * Created :		
 *	28.06.96
 *
 * Purpose :		
 *	Get prediction for an Intra block
 * 
 * Arguments in : 	
 *	Int x_pos	x_position of Macroblock
 *	Int y_pos	y_position of Macroblock
 *	UInt width	width of Vop bounding box
 *
 * Arguments in/out :	
 *	SInt *curr	current uncoded Vop data
 *	SInt *rec_curr	reconstructed Vop data area
 *
 * Arguments out :	
 *	Int fblock[][8]	the prediction block to be coded for bitstream
 *
 * Return values :	
 *	Void
 *
 * Side effects :	
 *
 * Description :	
 *	
 * See also :
 *
 * Modified :		
 *
 ***********************************************************CommentEnd********/
Void
BlockPredict (SInt *curr, SInt *rec_curr, Int x_pos, Int y_pos,
	      UInt width, Int fblock[][8])
{
    Int i, j;
  
    for (i = 0; i < 8; i++)
    {
	for (j = 0; j < 8; j++)
	{
	    fblock[i][j] = curr[(y_pos+i)*width + x_pos+j];
	}
    }
}

/***********************************************************CommentBegin******
 *
 * -- BlockRebuild -- Reconstructs a block into data area of Vop
 *
 * Author :		
 *	Robert Danielsen, Telenor R&D, <Robert.Danielsen@nta.no>
 *
 * Created :		
 *	28.06.96
 *
 * Purpose :		
 *	Reconstructs a block into data area of Vop
 * 
 * Arguments in : 	
 *	Int x_pos	x_position of Macroblock
 *	Int y_pos	y_position of Macroblock
 *	UInt width	width of Vop bounding box
 *
 * Arguments in/out :	
 *	SInt *rec_curr	current Vop data area to be reconstructed
 *
 * Arguments out :	
 *
 * Return values :	
 *	Void
 *
 * Side effects :	
 *
 * Description :	
 *	Does reconstruction for Intra predicted blocks also
 *
 * See also :
 *
 * Modified :		
 *
 ***********************************************************CommentEnd********/
  
Void
BlockRebuild (SInt *rec_curr, Int x_pos, Int y_pos, UInt width,
	      Int fblock[][8])
{
    Int i, j;

    for (i = 0; i < 8; i++)
    {
	for (j = 0; j < 8; j++)
	{
	    rec_curr[(y_pos+i)*width + x_pos+j] =
		fblock[i][j];
	}
    }
}
 

/***********************************************************CommentBegin******
 *
 * -- BlockDCT -- 8x8 block DCT
 *
 * Author :		
 *	Robert Danielsen, Telenor R&D, <Robert.Danielsen@nta.no>
 *
 * Created :		
 *	28.06.96
 *
 * Purpose :		
 *	8x8 block DCT
 * 
 * Arguments in : 	
 *	Int block[][8]	8x8 data block
 *
 * Arguments in/out :	
 *
 * Arguments out :	
 *	Int *coeff	transform coefficients
 *
 * Return values :	
 *	Int		status (0 for OK only)
 *
 * Side effects :	
 *
 * Description :	
 *	This is an implementation originally done by Gisle Bjontegaard
 *	in FORTRAN.
 *
 * See also :
 *
 * Modified :
 *	27.02.97 Robert Danielsen: Changed from truncating to rounding of
 *			coefficient values. This was decided in the
 *			38.MPEG-meeting in Sevilla.
 *
 ***********************************************************CommentEnd********/
Int
BlockDCT (Int block[][8], Int *coeff)
{
    Int   j1, i, j;
    Double b[8];
    Double b1[8];
    Double d[8][8];
    Double f0=0.7071068,f1=0.4903926,f2=0.4619398,f3=0.4157348,f4=0.3535534;
    Double f5=0.2777851,f6=0.1913417,f7=0.0975452;

    for (i = 0; i < 8; i++)
    {
	for (j = 0; j < 8; j++)
	{
	    b[j] = block[i][j];
	}
    
	/* Horizontal transform */
	for (j = 0; j < 4; j++)
	{
	    j1 = 7 - j;
	    b1[j] = b[j] + b[j1];
	    b1[j1] = b[j] - b[j1];
	}
    
	b[0] = b1[0] + b1[3];
	b[1] = b1[1] + b1[2];
	b[2] = b1[1] - b1[2];
	b[3] = b1[0] - b1[3];
	b[4] = b1[4];
	b[5] = (b1[6] - b1[5]) * f0;
	b[6] = (b1[6] + b1[5]) * f0;
	b[7] = b1[7];
	d[i][0] = (b[0] + b[1]) * f4;
	d[i][4] = (b[0] - b[1]) * f4;
	d[i][2] = b[2] * f6 + b[3] * f2;
	d[i][6] = b[3] * f6 - b[2] * f2;
	b1[4] = b[4] + b[5];
	b1[7] = b[7] + b[6];
	b1[5] = b[4] - b[5];
	b1[6] = b[7] - b[6];
	d[i][1] = b1[4] * f7 + b1[7] * f1;
	d[i][5] = b1[5] * f3 + b1[6] * f5;
	d[i][7] = b1[7] * f7 - b1[4] * f1;
	d[i][3] = b1[6] * f3 - b1[5] * f5;
    }
  
    /* Vertical transform */

    for (i = 0; i < 8; i++)
    {
	for (j = 0; j < 4; j++)
	{
	    j1 = 7 - j;
	    b1[j] = d[j][i] + d[j1][i];
	    b1[j1] = d[j][i] - d[j1][i];
	}
    
	b[0] = b1[0] + b1[3];
	b[1] = b1[1] + b1[2];
	b[2] = b1[1] - b1[2];
	b[3] = b1[0] - b1[3];
	b[4] = b1[4];
	b[5] = (b1[6] - b1[5]) * f0;
	b[6] = (b1[6] + b1[5]) * f0;
	b[7] = b1[7];
	d[0][i] = (b[0] + b[1]) * f4;
	d[4][i] = (b[0] - b[1]) * f4;
	d[2][i] = b[2] * f6 + b[3] * f2;
	d[6][i] = b[3] * f6 - b[2] * f2;
	b1[4] = b[4] + b[5];
	b1[7] = b[7] + b[6];
	b1[5] = b[4] - b[5];
	b1[6] = b[7] - b[6];
	d[1][i] = b1[4] * f7 + b1[7] * f1;
	d[5][i] = b1[5] * f3 + b1[6] * f5;
	d[7][i] = b1[7] * f7 - b1[4] * f1;
	d[3][i] = b1[6] * f3 - b1[5] * f5;
    }
  
    /* Do rounding instead of just truncating.
       Decided in 38.MPEG-meeting in Sevilla */
    
    for (i = 0; i < 8; i++)
	for (j = 0; j < 8; j++)
	    coeff[i*8+j] = (int)(floor((d[i][j]) + 0.499999));
   
    return 0;
}

/***********************************************************CommentBegin******
 *
 * -- FindCBP -- Find the CBP for a macroblock 
 *
 * Author :  
 * 
 *
 * Created :  
 * 
 *
 * Purpose :  
 * Find the CBP for a macroblock
 * 
 * Arguments in :  
 * Int *qcoeff : pointer to quantized coefficients
 *  Int Mode : macroblock encoding mode information
 *  Int ncoeffs : the number of coefficients
 *
 * Arguments in/out : 
 * 
 *
 * Arguments out : 
 * 
 *
 * Return values : 
 * Int CBP : The coded block pattern for a macroblock
 *
 * Side effects : 
 * 
 *
 * Description : 
 * 
 *
 * See also :
 * 
 *
 * Modified :  
 * 
 *
 ***********************************************************CommentEnd********/

Int 
FindCBP (Int* qcoeff, Int Mode, Int ncoeffs)
{
    Int i,j;
    Int CBP = 0;
    Int intra = (Mode == MODE_INTRA || Mode == MODE_INTRA_Q);

    /* Set CBP for this Macroblock */
   
    for (i = 0; i < 6; i++) 
    {
	for (j = i*ncoeffs + intra; j < (i+1)*ncoeffs; j++) 
	{
        
	    if (qcoeff[j]) 
	    {
		if (i == 0) {CBP |= 32;}
		else if (i == 1) {CBP |= 16;}
		else if (i == 2) {CBP |= 8;}
		else if (i == 3) {CBP |= 4;}
		else if (i == 4) {CBP |= 2;}
		else if (i == 5) {CBP |= 1;}
		else 
		{
		    fprintf (stderr, "Error in CBP assignment\n");
		    exit(-1);
		}
    
		break;
	    }
	}
    }

    return CBP;
}

/***********************************************************CommentBegin******
 *
 * -- FrameFieldDCTDecide -- Determine if field DCT is better & swizzle
 *
 * Author :
 *                      Bob Eifrig
 *
 * Created :
 *                      24-jan-97
 *
 * Purpose :
 *                      Determine if the macroblock should be field DCT code
 *
 * Arguments in :
 *
 * Arguments in/out :
 *                      fblock[][][]    An array of 6 8x8 blocks
 *
 * Arguments out :
 *
 * Return values :
 *                      Int FieldDCT : 0 if frame DCT, 1 if field DCT
 *
 * Side effects :
 *                      fblock[][][] is redefined if field DCT is indicated
 *
 * Description :
 *                      fblock can be indexed as fblock[6][8][8].  That is, flbock
 *                      consists of 64 elements of Y1, then 64 elements of Y2, ...
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/
 
Int
FrameFieldDCTDecide(Int *fblock)
{
    static unsigned char mbline[] = {
         0*BLOCK_SIZE,  2*BLOCK_SIZE,  4*BLOCK_SIZE,  6*BLOCK_SIZE,
        16*BLOCK_SIZE, 18*BLOCK_SIZE, 20*BLOCK_SIZE, 22*BLOCK_SIZE,
         8*BLOCK_SIZE, 10*BLOCK_SIZE, 12*BLOCK_SIZE, 14*BLOCK_SIZE,
        24*BLOCK_SIZE, 26*BLOCK_SIZE, 28*BLOCK_SIZE, 30*BLOCK_SIZE,  };
    static unsigned char fwd_shuffle[] = {
         1*BLOCK_SIZE, 0*BLOCK_SIZE,    2*BLOCK_SIZE, 1*BLOCK_SIZE,    4*BLOCK_SIZE, 2*BLOCK_SIZE,
        16*BLOCK_SIZE, 4*BLOCK_SIZE,    0*BLOCK_SIZE,16*BLOCK_SIZE,    3*BLOCK_SIZE, 0*BLOCK_SIZE,
         6*BLOCK_SIZE, 3*BLOCK_SIZE,   20*BLOCK_SIZE, 6*BLOCK_SIZE,   17*BLOCK_SIZE,20*BLOCK_SIZE,
         0*BLOCK_SIZE,17*BLOCK_SIZE,    5*BLOCK_SIZE, 0*BLOCK_SIZE,   18*BLOCK_SIZE, 5*BLOCK_SIZE,
         0*BLOCK_SIZE,18*BLOCK_SIZE,    7*BLOCK_SIZE, 0*BLOCK_SIZE,   22*BLOCK_SIZE, 7*BLOCK_SIZE,
        21*BLOCK_SIZE,22*BLOCK_SIZE,   19*BLOCK_SIZE,21*BLOCK_SIZE,    0*BLOCK_SIZE,19*BLOCK_SIZE,
         9*BLOCK_SIZE, 0*BLOCK_SIZE,   10*BLOCK_SIZE, 9*BLOCK_SIZE,   12*BLOCK_SIZE,10*BLOCK_SIZE,
        24*BLOCK_SIZE,12*BLOCK_SIZE,    0*BLOCK_SIZE,24*BLOCK_SIZE,   11*BLOCK_SIZE, 0*BLOCK_SIZE,
        14*BLOCK_SIZE,11*BLOCK_SIZE,   28*BLOCK_SIZE,14*BLOCK_SIZE,   25*BLOCK_SIZE,28*BLOCK_SIZE,
         0*BLOCK_SIZE,25*BLOCK_SIZE,   13*BLOCK_SIZE, 0*BLOCK_SIZE,   26*BLOCK_SIZE,13*BLOCK_SIZE,
         0*BLOCK_SIZE,26*BLOCK_SIZE,   15*BLOCK_SIZE, 0*BLOCK_SIZE,   30*BLOCK_SIZE,15*BLOCK_SIZE,
        29*BLOCK_SIZE,30*BLOCK_SIZE,   27*BLOCK_SIZE,29*BLOCK_SIZE,    0*BLOCK_SIZE,27*BLOCK_SIZE, };
    Double frame, field, d;
    Int tmp[BLOCK_SIZE], *p, *q, *plast;
    Int i;
 
    frame = field = 0.0;
    for (i = 0; i < sizeof(mbline)-1; i++) {
        if (i == (sizeof(mbline)/2 - 1))
            continue;
        p = &fblock[mbline[i + 0]];
        q = &fblock[mbline[i + 1]];
        for (plast = p + BLOCK_SIZE; p < plast; p++, q++) {
            d = p[0] - p[BLOCK_SIZE];
            frame += d * d;
            d = p[BLOCK_SIZE] - q[0];
            frame += d * d;
 
            d = p[0] - q[0];
            field += d * d;
            d = p[BLOCK_SIZE] - q[BLOCK_SIZE];
            field += d * d;
        }
    }
    if (frame <= field)
        return(0);
    /*
     * Re-order luminance macroblock lines
     */
    for (i = 0; i < sizeof(fwd_shuffle); i += 2)
        memcpy(fwd_shuffle[i+1] ? &fblock[fwd_shuffle[i+1]] : tmp,
               fwd_shuffle[i+0] ? &fblock[fwd_shuffle[i+0]] : tmp,
               BLOCK_SIZE * sizeof(Int));
    return(1);
}



/***********************************************************CommentBegin******
 *
 * -- fieldDCTtoFrame -- permute the field DCT block back to frame layout
 *
 * Author :
 *                      Bob Eifrig
 *
 * Created :
 *                      24-jan-97
 *
 * Purpose :
 *                      Undo the field DCT permutation
 *
 * Arguments in :
 *
 * Arguments in/out :
 *                      iblock[][][]    An array of 6 8x8 blocks
 *
 * Arguments out :
 *
 * Return values :
 *
 * Side effects :
 *                      iblock[][][] is re-defined
 *
 * Description :
 *                      iblock can be indexed as fblock[6][8][8].  That is, flbock
 *                      consists of 64 elements of Y1, then 64 elements of Y2, ...
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/
 
Void
fieldDCTtoFrame(Int *iblock)
{
    static unsigned char inv_shuffle[] = {
         1*BLOCK_SIZE, 0*BLOCK_SIZE, 16*BLOCK_SIZE, 1*BLOCK_SIZE,  4*BLOCK_SIZE,16*BLOCK_SIZE,
         2*BLOCK_SIZE, 4*BLOCK_SIZE,  0*BLOCK_SIZE, 2*BLOCK_SIZE,  3*BLOCK_SIZE, 0*BLOCK_SIZE,
        17*BLOCK_SIZE, 3*BLOCK_SIZE, 20*BLOCK_SIZE,17*BLOCK_SIZE,  6*BLOCK_SIZE,20*BLOCK_SIZE,
         0*BLOCK_SIZE, 6*BLOCK_SIZE,  5*BLOCK_SIZE, 0*BLOCK_SIZE, 18*BLOCK_SIZE, 5*BLOCK_SIZE,
         0*BLOCK_SIZE,18*BLOCK_SIZE,  7*BLOCK_SIZE, 0*BLOCK_SIZE, 19*BLOCK_SIZE, 7*BLOCK_SIZE,
        21*BLOCK_SIZE,19*BLOCK_SIZE, 22*BLOCK_SIZE,21*BLOCK_SIZE,  0*BLOCK_SIZE,22*BLOCK_SIZE,
         9*BLOCK_SIZE, 0*BLOCK_SIZE, 24*BLOCK_SIZE, 9*BLOCK_SIZE, 12*BLOCK_SIZE,24*BLOCK_SIZE,
        10*BLOCK_SIZE,12*BLOCK_SIZE,  0*BLOCK_SIZE,10*BLOCK_SIZE, 11*BLOCK_SIZE, 0*BLOCK_SIZE,
        25*BLOCK_SIZE,11*BLOCK_SIZE, 28*BLOCK_SIZE,25*BLOCK_SIZE, 14*BLOCK_SIZE,28*BLOCK_SIZE,
         0*BLOCK_SIZE,14*BLOCK_SIZE, 13*BLOCK_SIZE, 0*BLOCK_SIZE, 26*BLOCK_SIZE,13*BLOCK_SIZE,
         0*BLOCK_SIZE,26*BLOCK_SIZE, 15*BLOCK_SIZE, 0*BLOCK_SIZE, 27*BLOCK_SIZE,15*BLOCK_SIZE,
        29*BLOCK_SIZE,27*BLOCK_SIZE, 30*BLOCK_SIZE,29*BLOCK_SIZE,  0*BLOCK_SIZE,30*BLOCK_SIZE,  };
    Int tmp[BLOCK_SIZE];
    Int i;
  
    for (i = 0; i < sizeof(inv_shuffle); i += 2)
        memcpy(inv_shuffle[i+1] ? &iblock[inv_shuffle[i+1]] : tmp,
               inv_shuffle[i+0] ? &iblock[inv_shuffle[i+0]] : tmp,
                BLOCK_SIZE*sizeof(Int));
}

