/*****************************************************************************
 *
 * This software module was originally developed by
 *
 *   Isabelle Corset (Philips / ACTS-MoMuSyS)
 *   Michael Wollborn (TUH / ACTS-MoMuSyS)
 *   Cor Quist (KPN / ACTS-MoMuSyS)
 *   Angel Pacheco (UPM / ACTS-MoMuSyS)
 *   J.Ignacio Ronda (UPM / ACTS-MoMuSyS)
 *
 * and edited by
 * 
 *   Paulo Nunes (IST / ACTS-MoMuSyS) 
 *   Robert Danielsen (Telenor / ACTS-MoMuSyS)
 *   Aasmund Sandvand (Telenor / ACTS-MoMuSyS)
 *   Michael Frater (UNSW)
 *
 * 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) 1996
 *
 *****************************************************************************/

/***********************************************************HeaderBegin*******
 *                                                                         
 * File:	text_decode.c
 *
 * Author:	Isabelle Corset (LEP) <corset@lep-philips.fr>
 * Created:	5-Mar-96
 *                                                                         
 * Description: Decoding VOP texture (and motion when combined mode)
 *		includes the Motion Compensation of the VOP in INTER.
 *
 * Notes: 	
 *
 * Modified:
 *	09-May-1996 Paulo Nunes: Reformatted. New headers.
 *	13-AUG-1996 M.Wollborn: Changed for VM3.0 compliance
 *	16-SEP-1996 M.Wollborn: Changed INTRADCPREDDISABLE from
 *			compiler flag to bitstream level
 *	23.10.96 Robert Danielsen: Added DC/AC prediction. Not tested.
 *      04.02.97 Noel O'Connor: removed all calls to assert()
 *	07-Feb-1997, M.Wollborn: changed in order to treat skipped MBs
 *	        		 correctly
 * 16.06.97 Angel Pacheco: unified the TRANSPARENT modes.
 *      03.01.98 Michael Frater: support for non-8-bit video
 *
 ***********************************************************HeaderEnd*********/

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

#include "io_generic.h"
#include "text_decode.h"
#include "text_decode_mb.h"
#include "mot_decode.h"
#include "mot_comp.h"
#include "vm_common_defs.h"


/***********************************************************CommentBegin******
 *
 * -- VopTextureUpdate -- Add the decoded texture on the MC image
 *
 * Author :		
 *	Michael Wollborn (TUH)
 *
 * Created :		
 *	15-Aug-1996
 *
 * Purpose :		
 *	The decoded texture from the temporal VOP is added to the motion
 *	compensated image
 *
 * 
 * Arguments in : 
 *	Vop *tmp_vop	VOP with the decoded texture	
 *
 *
 * Arguments in/out :	
 *	Vop *curr_vop	motion compensated VOP to reconstruct
 *	
 *
 * Arguments out :	
 *
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified : 
 *	    23.06.97 Minhua Zhou: added Trace
 *
 ***********************************************************CommentEnd********/

Void VopTextureUpdate(Vop *tmp_vop, Vop *curr_vop,Trace *trace)
{
  Image *Y_tmp, *U_tmp, *V_tmp, *Y_curr, *U_curr, *V_curr;
#ifdef _DEBUG_
  SInt mb_pred[6][64],mb_rec[6][64],mb_shape[6][64];
  Char level_3_trace=0;
  SInt *y_data,*u_data,*v_data;
  Int npix=GetVopWidth(curr_vop);
  Int nlin=GetVopHeight(curr_vop);
  Int sum,MB_nb=-1;
  Int i,j,k,i_mb,j_mb;
  Int MB_non_trans_count=0;

  /*****
   *
   *	Get the images from the VOPs and add texture update to 
   *	the motion compensated VOP images. Then clip the result
   *
   *****/
  SetTraceLevelsDefault(trace);
  if (GetVopPredictionType(curr_vop)!=I_VOP)
     level_3_trace = trace->MB_tdata_predicted||trace->MB_tdata_reconstructed;
  if (level_3_trace) {
     fprintf(trace->fp_trace,"\n\n **************************************************\n");  
     fprintf(trace->fp_trace,"\n\n *        Predictions and  reconstructions        *\n");
     fprintf(trace->fp_trace,"\n\n **************************************************\n\n"); 
     for (i_mb=0;i_mb<nlin/16;i_mb++)
      for (j_mb=0;j_mb<npix/16;j_mb++) {
        if (MB_non_trans_count>=MB_trace_thres) break;
        y_data = (SInt *)GetImageData(GetVopA(curr_vop));
        u_data = (SInt *)GetImageData(GetVopAuv(curr_vop));
        for (i=0;i<4;i++)
          for (j=0;j<8;j++)
            for (k=0;k<8;k++)
              mb_shape[i][j*8+k] = y_data[(i_mb*16+(i/2)*8+j)*npix+j_mb*16+(i%2)*8+k];
        sum=0;
        for (i=0;i<4;i++)
          for(j=0;j<64;j++) sum+=mb_shape[i][j];
        MB_nb++;
        if (sum==0) continue;
        MB_non_trans_count++;
         for (j=0;j<8;j++)
          for (k=0;k<8;k++)
            mb_shape[4][j*8+k]=mb_shape[5][j*8+k]
                = u_data[(i_mb*8+j)*npix/2+j_mb*8+k];

        y_data = (SInt *)GetImageData(GetVopY(tmp_vop));
        u_data = (SInt *)GetImageData(GetVopU(tmp_vop));
        v_data = (SInt *)GetImageData(GetVopV(tmp_vop));
        for (i=0;i<4;i++)
          for (j=0;j<8;j++)
            for (k=0;k<8;k++)
              mb_pred[i][j*8+k] = y_data[(i_mb*16+(i/2)*8+j)*npix+j_mb*16+(i%2)*8+k];
         for (j=0;j<8;j++)
          for (k=0;k<8;k++) {
            mb_pred[4][j*8+k]= u_data[(i_mb*8+j)*npix/2+j_mb*8+k]; 
            mb_pred[5][j*8+k]= v_data[(i_mb*8+j)*npix/2+j_mb*8+k]; 
        }
    
        y_data = (SInt *)GetImageData(GetVopY(curr_vop));
        u_data = (SInt *)GetImageData(GetVopU(curr_vop));
        v_data = (SInt *)GetImageData(GetVopV(curr_vop));
        for (i=0;i<4;i++)
          for (j=0;j<8;j++)
            for (k=0;k<8;k++)
              mb_rec[i][j*8+k] = y_data[(i_mb*16+(i/2)*8+j)*npix+j_mb*16+(i%2)*8+k];
         for (j=0;j<8;j++)
          for (k=0;k<8;k++) {
            mb_rec[4][j*8+k]= u_data[(i_mb*8+j)*npix/2+j_mb*8+k]; 
            mb_rec[5][j*8+k]= v_data[(i_mb*8+j)*npix/2+j_mb*8+k]; 
        }
        
      for (i=0;i<6;i++)
        for (j=0;j<64;j++) {
          mb_rec[i][j]+=mb_pred[i][j];
          if (mb_rec[i][j]<0) mb_rec[i][j]=0;
            else if (mb_rec[i][j]>255) mb_rec[i][j]=255;
         }
     if (level_3_trace)
     fprintf(trace->fp_trace,"\n\n____MB%d_____ at (%d,%d)\n",MB_nb,j_mb*16,i_mb*16);
     if (trace->MB_tdata_predicted)
       PrintOutMBData("MB_tdata_predicted",mb_shape,mb_pred,trace->fp_trace);
     if (trace->MB_tdata_reconstructed)
        PrintOutMBData("MB_tdata_reconstructed",mb_shape,mb_rec,trace->fp_trace);
     }
   }
#endif   
        
  



    
  Y_tmp = GetVopY(tmp_vop);
  U_tmp = GetVopU(tmp_vop);
  V_tmp = GetVopV(tmp_vop);

  Y_curr = GetVopY(curr_vop);
  U_curr = GetVopU(curr_vop);
  V_curr = GetVopV(curr_vop);
  
  AddImage(Y_tmp,Y_curr,Y_curr);
  AddImage(U_tmp,U_curr,U_curr);
  AddImage(V_tmp,V_curr,V_curr);

  ClipImage (Y_curr,GetVopBrightWhite(curr_vop));
  ClipImage (U_curr,GetVopBrightWhite(curr_vop));
  ClipImage (V_curr,GetVopBrightWhite(curr_vop));

  return;
}





/***********************************************************CommentBegin******
 *
 * -- FillVop -- Fills the mbnum-th macroblock of VOP y,u,v components
 *
 * Author :		
 *	Isabelle Corset (LEP) <corset@lep-philips.fr>
 *
 * Created :		
 *	26-Feb-96
 *
 * Purpose :		
 *	To fills the mbnum-th macroblock of VOP y,u,v components.
 * 
 * Arguments in : 	
 *	Macroblock * mblock,	decoded macroblock.
 *	Int mbnum,		macroblock number.

 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	Image *y_chan,		Y component of the VOP to fill.
 *	Image *u_chan,		U component of the VOP to fill.
 *	Image *v_chan,		V component of the VOP to fill.
 *
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/

Void
FillVop (Macroblock * mblock,
	 Int mbnum,
	 Image * y_chan,
	 Image * u_chan,
	 Image * v_chan)

{
  Int                 lumstart, chrstart;
  Int                 n, m;
  UInt                MB_in_width;
  UInt                image_x;
  SInt               *y_point, *u_point, *v_point;

  image_x = GetImageSizeX (y_chan);

  MB_in_width = image_x / MB_SIZE;
  lumstart = (mbnum / MB_in_width) * image_x * MB_SIZE +
    (mbnum % MB_in_width) * MB_SIZE;

  chrstart = (mbnum / MB_in_width) * image_x / 2 * MB_SIZE / 2 +
    (mbnum % MB_in_width) * MB_SIZE / 2;

  y_point = (SInt *) GetImageData (y_chan) + lumstart;
  u_point = (SInt *) GetImageData (u_chan) + chrstart;
  v_point = (SInt *) GetImageData (v_chan) + chrstart;

  for (n = 0; n < MB_SIZE; n++)
    for (m = 0; m < MB_SIZE; m++)
      *(y_point + n * image_x + m) = mblock->lum[n][m];

  for (n = 0; n < (MB_SIZE >> 1); n++)
    for (m = 0; m < (MB_SIZE >> 1); m++)
      {
	*(u_point + n * image_x / 2 + m) = mblock->Cr[n][m];
	*(v_point + n * image_x / 2 + m) = mblock->Cb[n][m];
      }

}				/* FillVop */


/***********************************************************CommentBegin******
 *
 * -- subsamp_alpha_dec --
 *
 * Author :
 *      UPM - J.Ignacio Ronda / Angel Pacheco
 *
 * Created :
 *      2/2/96
 *
 * Purpose :
 *      generates an array with the alpha plane subsampled in block
 *      pixel units. This array is used to see if the block/macroblock
 *      is transparent
 *
 * Arguments in :
 *      SInt*  alpha,          alpha plane data
 *      Int     br_width,        width of the alpha plane data
 *      Int     br_height        height  of the alpha plane data
 *
 * Arguments in/out :
 *      SInt*  alpha_sub,      subsampled alpha data
 *
 * Arguments out :
 *
 *
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *      It does not allocate memory for the subsampled array
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
subsamp_alpha_dec(
     SInt  *alpha,       /* <-- alpha plane data                */
     Int    br_width,     /* <-- width of the alpha plane data   */
     Int    br_height,    /* <-- height  of the alpha plane data */
     SInt  *alpha_sub    /* --> subsampled alpha data           */
     )   
{
  Int  h, v;

  for (v=0;v<br_height/B_SIZE;v++)
    for (h=0;h<br_width/B_SIZE;h++)
      alpha_sub[v*br_width/B_SIZE+h] = 0;

  for (v=0;v<br_height;v++)
    for (h=0;h<br_width;h++)
      alpha_sub[(v/8)*br_width/B_SIZE+(h/B_SIZE)] =
   alpha_sub[(v/B_SIZE)*br_width/B_SIZE+(h/B_SIZE)] ||
   alpha[v*br_width+h];

  for (v=0;v<br_height/B_SIZE;v++)
    for (h=0;h<br_width/B_SIZE;h++)
      if (alpha_sub[v*br_width/B_SIZE+h]==0)
   		alpha_sub[v*br_width/B_SIZE+h] = MBM_TRANSPARENT;
      else 
   		alpha_sub[v*br_width/B_SIZE+h] = 1;

}


/***********************************************************CommentBegin******
 *
 * -- BoutVop -- Determines which blocks contains points of the VOP
 *
 * Author :		
 *	Isabelle Corset (LEP) <corset@lep-philips.fr>
 *
 * Created :		
 *	27-Feb-96
 *
 * Purpose :		
 *	To determine which blocks contains points of the VOP.
 * 
 * Arguments in : 	
 *	Image * A_chan,		 alpha channel of a VOP.
 *
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	Image * B_mot_decis,	 block-based motion decision (2: MBM_TRANSPARENT).
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/

Void
BoutVop (Image * B_mot_decis,
	 Image * A_chan)

{
  UInt                vop_size;
  Int                 i, j, b_ind, total_B, alpha_x, B_in_width;
  SInt               *decis_ptr;
  SInt               *alpha_ptr, *begin_add;
  SInt                one_point, one_point_flag;

  vop_size = GetImageSize (A_chan);
  total_B = vop_size / (B_SIZE * B_SIZE);
  alpha_ptr = (SInt *) GetImageData (A_chan);
  decis_ptr = (SInt *) GetImageData (B_mot_decis);
  alpha_x = GetImageSizeX (A_chan);
  B_in_width = alpha_x / B_SIZE;

  for (b_ind = 0; b_ind < total_B; b_ind ++)
  {
    	i = 0;
     	one_point_flag = 0;
      	begin_add = alpha_ptr + (b_ind / B_in_width) * alpha_x * B_SIZE
                        + (b_ind % B_in_width) * B_SIZE;
     	for (i = 0; i< B_SIZE; i++)
	{
      		for (j = 0; j< B_SIZE; j++)
		{
        		one_point = *(begin_add + j);
          		if (one_point != 0)
          		{
            			one_point_flag = 1;
              			break;
            		}
            	}
          	if (one_point_flag) break;
          	begin_add += alpha_x; /* next line ! */
       	}
 
      	if (!one_point_flag) *(decis_ptr + b_ind) = MBM_TRANSPARENT;
  }
}				/* BoutVop */


/***********************************************************CommentBegin******
 *
 * -- BToMBdecis -- Converts block-based decisions into MB-based decisions
 *
 * Author :		
 *	Isabelle Corset (LEP) <corset@lep-philips.fr>
 *
 * Created :		
 *	27-Feb-96
 *
 * Purpose :		
 *	To convert block-based decisions into MB-based decisions for texture
 *	decoding in the separate mode.
 * 
 * Arguments in : 	
 *	Image * B_mot_decis,	 block-based motion decision.
 *
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	Image * MB_mot_decis,	MB-based motion decision (MBM_TRANSPARENT not
 *				marked).
 *
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/

Void
BToMBdecis (Image * B_decis,
	    Image * MB_decis)

{
  Int                 mbnum, B_in_width, MB_in_width, totalMB, block, ypos,
                      xpos, bpos, offset;
  SInt               *MBdecis_ptr, *MBdecis_ini, *Bdecis_ptr, *Bdecis_ini;

  totalMB = GetImageSize (MB_decis);
  B_in_width = GetImageSizeX (B_decis);
  MB_in_width = GetImageSizeX (MB_decis);
  MBdecis_ini = (SInt *) GetImageData (MB_decis);
  Bdecis_ini = (SInt *) GetImageData (B_decis);

  for (mbnum = 0; mbnum < totalMB; mbnum++)
    {
      ypos = (mbnum / MB_in_width) * 2;
      xpos = (mbnum % MB_in_width) * 2;
      bpos = ypos * B_in_width + xpos;
      Bdecis_ptr = Bdecis_ini + bpos;
      MBdecis_ptr = MBdecis_ini + mbnum;
      block = 0;
      while (block < 4)
	{
	  offset = (block >> 1) * B_in_width + (block & 0x1);
	  if (*(Bdecis_ptr + offset) != MBM_TRANSPARENT)
	    {
	      *MBdecis_ptr = *(Bdecis_ptr + offset);
	      block = 4;
	    }
	  else
	    {
	      block++;
	    }
	}

    }

}				/* BToMBdecis */


/***********************************************************CommentBegin******
 *
 * -- MB_BToMBdecis -- Converts block-based decisions into MB-based decisions
 *
 * Author : Cor Quist (KPN)		
 *
 *
 * Created :		
 *	13-Jun-96
 *
 * Purpose :		
 *	To convert block-based decisions into MB-based decisions for texture
 *	decoding in the combined motion/texture mode.
 * 
 * Arguments in : 	
 *	Image * B_mot_decis,	 block-based motion decision.
 *      Int mbnum, macroblock number
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *	Image * MB_mot_decis,	MB-based motion decision (MBM_TRANSPARENT not
 *				marked).
 *
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description :	
 *	
 *
 * See also :
 *	
 *
 * Modified :		
 *	
 *
 ***********************************************************CommentEnd********/

Void
MB_BToMBdecis (Image * B_decis,
	       Image * MB_decis,
	       Int mbnum)

{
  Int                 B_in_width, MB_in_width, totalMB, block, ypos,
                      xpos, bpos, offset;
  SInt               *MBdecis_ptr, *MBdecis_ini, *Bdecis_ptr, *Bdecis_ini;

  totalMB = GetImageSize (MB_decis);
  B_in_width = GetImageSizeX (B_decis);
  MB_in_width = GetImageSizeX (MB_decis);
  MBdecis_ini = (SInt *) GetImageData (MB_decis);
  Bdecis_ini = (SInt *) GetImageData (B_decis);

  /* check mbnum out of range */
  MOMCHECK(mbnum >= 0 && mbnum < totalMB);
  
  ypos = (mbnum / MB_in_width) * 2;
  xpos = (mbnum % MB_in_width) * 2;
  bpos = ypos * B_in_width + xpos;
  Bdecis_ptr = Bdecis_ini + bpos;
  MBdecis_ptr = MBdecis_ini + mbnum;
  block = 0;
  while (block < 4)
    {
      offset = (block >> 1) * B_in_width + (block & 0x1);
      if (*(Bdecis_ptr + offset) != MBM_TRANSPARENT)
	{
	  *MBdecis_ptr = *(Bdecis_ptr + offset);
	  block = 4;
	}
      else
	{
	  block++;
	}
    }
  
  
}				/* MB_BToMBdecis */

