/*****************************************************************************
 *
 * This software module was originally developed by
 *
 *   Luis Ducla-Soares (IST / 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) 1996
 *
 *****************************************************************************/

/***********************************************************HeaderBegin*******
 *                                                                         
 * File:	concealment.c
 *
 * Author:	Luis Ducla-Soares (IST) - lds@lx.it.pt
 *
 * Created:	28-Nov-97
 *                                                                         
 * Description: Concealment of lost data
 *
 * Notes: 	
 * 
 *
 * Modified:
 *
 ***********************************************************HeaderEnd*********/

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

#include "momusys.h"
#include "vm_common_defs.h"
#include "concealment.h"
#include "combined_decode.h"
#include "mot_padding.h"

/***********************************************************CommentBegin******
 *
 * -- ConcealVideoPacket --
 *
 * Author :		
 *	Luis Ducla-Soares (IST) - lds@lx.it.pt
 *
 * Created :		
 *	2-Dec-97
 *
 * Purpose : conceals an entire video packet by copying the shape and
 *           texture of the corresponding macroblocks in the previous VOP.		
 *
 *
 * Arguments in : 	
 *	Vop *prev        pointer to the previous VOP
 *      Int curr_first     first macroblock in the current video packet
 *	Int next_first     first macroblock in the next video packet
 *
 * Arguments in/out :	
 *	Vop *curr        pointer to the current VOP
 *      Image *mot_x, *mot_y    components of the motion vectors of the VOP
 *      Image *MB_decisions     modes of the macroblocks in the current VOP
 *      Image *alpha_decisions  alpha modes in the current VOP
 *
 * Arguments out :	
 *
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description : copies the Binary Alpha Blocks of the corresponding
 *               macroblocks in the previous VOP and sets the macroblock 
 *               coding mode to TRANSPARENT or SKIPPED accordingly.
 *
 * Note : 
 *
 *
 * See also :
 *	
 *
 * Modified : 
 *
 ***********************************************************CommentEnd********/
Void
ConcealVideoPacket(Vop   *curr, 
		   Vop   *prev, 
		   Image *mot_x,
		   Image *mot_y,
		   Image *MB_decisions, 
		   Image *alpha_decisions,
		   Int   curr_first, 
		   Int   next_first)
{
  Int i;
  Int mbx, mby;
  Int MB_in_width;
  SInt *pMB_decisions;
  Macroblock    *mblock;                    
  Image *Y_rec, *U_rec, *V_rec;             
  
  MB_in_width = GetVopWidth(curr) / MB_SIZE;
  pMB_decisions = (SInt *)GetImageData(MB_decisions);

  mblock = (Macroblock *) malloc (sizeof (Macroblock));       
  
  if (mblock == NULL)                           
    {                                                
      printf (" Error allocating macroblock\n");           
      exit(1);                                      
    }                                                 
  Y_rec = GetVopY(curr);    
  U_rec = GetVopU(curr);    
  V_rec = GetVopV(curr);     

  
  if (prev == NULL)
    return;
  
  for (i = curr_first; i < next_first; i++)
    {
      CopyBABfromPrevVop(curr, prev, i);
      if (TransparentMacroblock(curr,i))
	pMB_decisions[i] = MBM_TRANSPARENT;
      else
	{
	  pMB_decisions[i] = MBM_SKIPPED;
	  SetVecToZero(mot_x, mot_y, i);
    	  MBzero(mblock);                           
	  FillVop (mblock, i, Y_rec, U_rec, V_rec);   
	}
    }

  if (alpha_decisions != NULL)
    for (i = curr_first; i < next_first; i++)
      {
	mbx = i % MB_in_width;
	mby = i / MB_in_width;
	SetAlphaDecisions(GetVopA(curr), mbx, mby, alpha_decisions);
      }

  free ((Char *)mblock);           

  return;
}


/***********************************************************CommentBegin******
 *
 * -- ConcealTexture -- 
 *
 * Author :		
 *	Luis Ducla-Soares (IST) - lds@lx.it.pt
 *
 * Created :		
 *	3-Dec-97
 *
 * Purpose : conceals the texture of an entire video packet. 
 *    
 *
 * Arguments in : 	
 *      Int curr_first     first macroblock in the current video packet
 *	Int next_first     first macroblock in the next video packet
 *
 * Arguments in/out :	
 *	Vop *rec_vop           pointer to the current VOP
 *      Image *mot_x, *mot_y    components of the motion vectors of the VOP
 *      Image *MB_decisions    modes of the macroblocks in the current VOP
 *
 * Arguments out :	
 *
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description : If the macroblock is of the type INTRA then it is set to
 *               SKIPPED. Otherwise the prediction error is set to
 *               zero. This way the macroblock is replaced with the 'closest' 
 *               one in the previous VOP due to the motion compensation.	
 *
 *
 * Note : 
 *      
 *
 * See also :
 *	
 *
 * Modified : 
 *	
 *
 ***********************************************************CommentEnd********/
Void
ConcealTexture(Vop *rec_vop, 
	       Image *mot_x,
	       Image *mot_y,
	       Image *MB_decisions, 
	       Int curr_first, 
	       Int next_first)
{

  Int i;
  Macroblock    *mblock;
  SInt *pMB_decisions;
  Image *Y_rec, *U_rec, *V_rec;


  mblock = (Macroblock *) malloc (sizeof (Macroblock));
  
  if (mblock == NULL)
    {
      printf (" Error allocating macroblock\n");
      exit(1);
    }
  
  pMB_decisions = (SInt *)GetImageData(MB_decisions);
  
  Y_rec = GetVopY(rec_vop);
  U_rec = GetVopU(rec_vop);
  V_rec = GetVopV(rec_vop);
  
  
  for (i = curr_first; i < next_first; i++)
    {
      if (pMB_decisions[i] == MBM_INTRA || pMB_decisions[i] == MBM_OPAQUE)
	{
	  pMB_decisions[i] = MBM_SKIPPED;
	  SetVecToZero(mot_x, mot_y, i);
	  MBzero(mblock);                                
	  FillVop (mblock, i, Y_rec, U_rec, V_rec);         
	}      
      else
	{
	  MBzero(mblock);
	  FillVop (mblock, i, Y_rec, U_rec, V_rec);
	}
    }
  
  free ((Char *)mblock);

  return;
}


/***********************************************************CommentBegin******
 *
 * -- CopyBABfromPrevVop --
 *
 * Author :		
 *	Luis Ducla-Soares (IST) - lds@lx.it.pt
 *
 * Created :		
 *	2-Dec-97
 *
 * Purpose : copies a given Binary Alpha Block (BAB) from the previous VOP.		
 *    
 *
 * Arguments in : 	
 *	Vop *prev        pointer to the previous VOP
 *      Int mbnum        number of the macroblock to be copied
 *
 * Arguments in/out :	
 *	Vop *curr        pointer to the current VOP
 *
 * Arguments out :	
 *
 *
 * Return values :	
 *	
 *
 * Side effects :	
 *	
 *
 * Description : the BAB with the number 'mbnum' will be copied from the
 *               previous VOP to the current VOP.	
 *
 *
 * Note : 
 *      
 *
 * See also :
 *	
 *
 * Modified : 
 *	
 *
 ***********************************************************CommentEnd********/
Void
CopyBABfromPrevVop(Vop *curr, Vop *prev, Int mbnum)
{

  Image    *bab;
  Image    *bab_uv;
  Int      mbx, mby;
  Int      ofx, ofy;
  Int      x, y;
  Int      MB_in_width;

  /*****
   *
   *   Allocate memory for the necessary structures
   *
   *****/
  bab = AllocImage(MB_SIZE,MB_SIZE,SHORT_TYPE);
  bab_uv = AllocImage(B_SIZE,B_SIZE,SHORT_TYPE);
  

  /*****
   *
   *   Set some useful parameters
   *
   *****/
  SetConstantImage(bab,0);
  SetConstantImage(bab_uv,0);
  ofx = GetVopHorSpatRef(curr) - GetVopHorSpatRef(prev);
  ofy = GetVopVerSpatRef(curr) - GetVopVerSpatRef(prev);
  MB_in_width = GetVopWidth(curr) / MB_SIZE;
  mbx = mbnum % MB_in_width ;
  mby = mbnum / MB_in_width;


  /*****
   *
   *   Copy BAB from previous VOP
   *
   *****/
   
  printf("Concealing MB %d\n",mbnum);
  
  x=mbx*MB_SIZE;
  y=mby*MB_SIZE;
  GetSubImage(GetVopA(prev),bab,x+ofx,y+ofy);
  PutSubImage(GetVopA(curr),bab,x,y);
  
					
  x=mbx*B_SIZE;
  y=mby*B_SIZE;
  GetSubImage(GetVopAuv(prev),bab_uv,x+ofx/2,y+ofy/2);
  PutSubImage(GetVopAuv(curr),bab_uv,x,y);
   

  /******
   *
   *   Deallocate memory
   *
   *****/
  FreeImage(bab);
  FreeImage(bab_uv);
  
  return;
}



/***********************************************************CommentBegin******
 *
 * -- TransparentMacroblock --
 *
 * Author :		
 *	Luis Ducla-Soares (IST) - lds@lx.it.pt
 *
 * Created :		
 *	2-Dec-97
 *
 * Purpose : checks if a macroblock is transparent or not.		
 *    
 *
 * Arguments in : 	
 *	Vop *curr_vop      current VOP
 *      Int mbnum          macroblock to be checked
 *
 * Arguments in/out :	
 *	
 *
 * Arguments out :	
 *
 *
 * Return values :	
 *	If the macroblock is transparent returns 1, otherwise it returns 0.
 *
 * Side effects :	
 *	
 *
 * Description : checks if that Binary Alpha Block has at least one pixel
 *               that is not transparent.	
 *
 *
 * Note : 
 *      
 *
 * See also :
 *	
 *
 * Modified : 
 *	
 *
 ***********************************************************CommentEnd********/
Int
TransparentMacroblock(Vop *curr_vop, Int mbnum)
{
  Int i, j;
  Int x_pos, y_pos;
  Int rec_width;
  Int MB_in_width;
  Int MB_transp_pattern[4];
  SInt *alpha;


  /* calculating MB_transp_pattern */
  for(i=0;i<4;i++)
    MB_transp_pattern[i]=1;
  
  alpha = (SInt *) GetImageData(GetVopA(curr_vop));
  rec_width = GetVopWidth(curr_vop);
  MB_in_width = rec_width / MB_SIZE;

  x_pos = mbnum % MB_in_width;
  y_pos = mbnum / MB_in_width;
    

  for(i=0;i<B_SIZE;i++)
    for(j=0;j<B_SIZE;j++)
      if (alpha[((y_pos * MB_SIZE) +i)*rec_width + 
	       (x_pos * MB_SIZE) +j] != 0)
	MB_transp_pattern[0]=0;
  
  for(i=0;i<B_SIZE;i++)
    for(j=B_SIZE;j<2*B_SIZE;j++)
      if (alpha[((y_pos * MB_SIZE) +i)*rec_width + 
	       (x_pos * MB_SIZE) +j] != 0)
	MB_transp_pattern[1]=0;
  
  for(i=B_SIZE;i<2*B_SIZE;i++)
    for(j=0;j<B_SIZE;j++)
      if (alpha[((y_pos * MB_SIZE) +i)*rec_width + 
	       (x_pos * MB_SIZE) +j] != 0)
	MB_transp_pattern[2]=0;
  
  for(i=B_SIZE;i<2*B_SIZE;i++)
    for(j=B_SIZE;j<2*B_SIZE;j++)
      if (alpha[((y_pos * MB_SIZE) +i)*rec_width + 
	       (x_pos * MB_SIZE) +j] != 0)
	MB_transp_pattern[3]=0;
  
  
  if ((MB_transp_pattern[0] + 	
       MB_transp_pattern[1] +
       MB_transp_pattern[2] +
       MB_transp_pattern[3]) == 4)
    return 1;
  else
    return 0;
}


/***********************************************************CommentBegin******
 *
 * -- SetVecToZero --
 * 
 *
 * Author :        
 *    Luis Ducla Soares (IST) - lds@lx.it.pt
 *
 * Created :        
 *    24-July-1997
 *
 * Purpose :        
 *   The purpose of this function is to set to zero the Motion Vectors of ONE macroblock.
 * 
 * Arguments in :     
 *      Int mbnum        number of the macroblock for which the vectors
 *                       should be set to zero.
 *
 * Arguments in/out :    
 *      Image *mot_x, *mot_y    components of the motion vectors of the VOP
 *
 *
 * Arguments out :    
 *   
 *
 * Return values :    
 *   
 *
 * Side effects :    
 *    
 *
 * Description :    sets to zero both components of the motion vectors of
 *                  ONE macroblock, which is indicated by mbnum.
 *   
 *
 * See also :
 *    
 *
 * Modified :        
 *    
 *    
 ***********************************************************CommentEnd********/

Void
SetVecToZero(Image *mot_x, Image *mot_y, Int mbnum)
{
  
  Int     B_in_width, B_in_height;
  Int     MB_in_width, MB_in_height;
  Int     b, bx, by;
  Float   *pmot_x, *pmot_y;


  

  pmot_x = (Float *) GetImageData(mot_x);
  pmot_y = (Float *) GetImageData(mot_y);
  B_in_width = GetImageSizeX(mot_x);
  B_in_height = GetImageSizeY(mot_y);
  MB_in_width = B_in_width/2;
  MB_in_height = B_in_height/2;
  

  bx = 2 * (mbnum % MB_in_width);
  by = 2 * (mbnum / MB_in_width);
  b = bx + by*B_in_width;
  
  pmot_x[b] = pmot_x[b+1] 
    = pmot_x[b + B_in_width] 
    = pmot_x[b + B_in_width +1] = 0.0;
  pmot_y[b] = pmot_y[b+1] 
    = pmot_y[b + B_in_width] 
    = pmot_y[b + B_in_width +1] = 0.0;
  
      
}

