/*****************************************************************************
 "This software module was originally developed by:

	Noboru Yamaguchi (TOSHIBA CORPORATION), 
	Takashi Ida (TOSHIBA CORPORATION) 

	and edited by:

 	Toshiaki Watanabe (TOSHIBA CORPORATION), 
	Yoshihiro Kikuchi (TOSHIBA CORPORATION), 
	Noel Brady (TELTEC IRELAND)

	in the course of development of the <MPEG-4 Video(ISO/IEC 14496-2)>. 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)
  >. ISO/IEC gives users of the <MPEG-4 Video(ISO/IEC 14496-2)> 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
  )>. 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)>
  conforming products. TOSHIBA CORPORATION retains 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)> conforming products. This copyright notice must be included in
  all copies or derivative works. Copyright (c)1996".
 *****************************************************************************/

/***********************************************************HeaderBegin*******
 *                                                                         
 * File:	alp_code_decisions.c
 *
 * Author:	TOSHIBA + Noel Brady Teltec Irl.
 * Created:	11-04-97
 *                                                                         
 * Description: Contains functions implementing encoder decisions for
 *							binary shape coding.
 *								- The update/no-update decision
 *								- determination of CR
 *
 *
 *                                 
 ***********************************************************HeaderEnd*********/

/********* include ********/

#include<stdio.h>
#ifndef WIN32
#include<values.h>
#endif
#include <string.h>
#include "momusys.h"
#include "alp_common_def.h"
#include "alp_common_util.h"
#include "alp_code_decisions.h"
#include "alp_common_cae.h"

#define MEDIAN_FILTER_BAB

/***********************************************************CommentBegin******
 *
 * -- DetectCR -- Determines the value of CR (conversion ratio) for a BAB.
 *
 * Author :		
 *	Noel Brady Teltec Irl.
 *
 * Created :		
 *	11-04-97
 * 
 * Arguments In: 	
 *					vop - the reconstructed vop containing the reconstructed binary
 *									alpha map
 *					x,y - the top-left pixel coordinate of the BAB
 *					alpha_th - alpha threshold
 *
 * Arguments In/Out:
 *					alpha_mb - the original BAB on input/the interpolated BAB on output
 *
 * Arguments Out:
 *					alpha_smb - the size converted(subsampled) BAB.
 *
 * Return values :
 *					mb_type: contains the mb_type information comprising the
 *											value of CR.
 *
 * Side effects :	
 *	-
 *
 * Description : As per VM7
 *
 * See also :
 *
 ***********************************************************CommentEnd********/

Int DetectCR( Image *alpha, 
							Int x, 
							Int y, 
							UChar *alpha_mb, 
							UChar *alpha_smb, 
							Int alpha_th, 
						/*** SAIT begin ****/
             					Image *bordered_smb_data,
             					Image *top_border_data,
             					Image *left_border_data
						/*** SAIT end ****/
							)
{
/* SAIT begin */
  Image *tmp1, *top_sborder, *left_sborder;
  SInt *p;
/* SAIT end */

  Int i, j, k, cr, width, height, org_w, org_h, size, org_s;
  Int mb_s, cnt_w, cnt_b, mb_type, flag;
  UChar alpha_dmb[MB_SIZE*MB_SIZE];

  org_w = MB_SIZE;
  org_h = MB_SIZE;
  org_s = MB_SIZE*MB_SIZE;

  flag = NO;

  for( k=0; k<2; k++) {
    cr = 2-k;
    mb_s = MB_SIZE >> cr;
    width = mb_s;
    height = mb_s;
    size = mb_s*mb_s;

#ifndef _VM7_FILTER_
   	DownSampling( alpha_mb, alpha_smb, org_w, org_h, MB_SIZE, mb_s );
#else
    /* down sampling */
    ChangeSamplingRate( alpha_mb, alpha_smb, org_w, org_h, MB_SIZE, mb_s );
#endif

    cnt_w = cnt_b = 0;
    for( i=0; i<mb_s; i++ ) for( j=0; j<mb_s; j++ ) {
      if( alpha_smb[i*mb_s+j] == 0 ) cnt_w++;
      else                           cnt_b++;
    }
    if( cnt_b == size && cnt_w == 0 )      mb_type = 0;
    else if( cnt_w == size && cnt_b == 0 ) mb_type = 1;
    else                                   mb_type = 2;

#ifndef _VM7_FILTER_
    if(mb_type==0){
      for( i=0; i<org_s; i++ ) alpha_dmb[i]=1;
    }else if(mb_type==1){
      for( i=0; i<org_s; i++ ) alpha_dmb[i]=0;
    }else{
      /* up sampling */
      /***** SAIT begin *****/
      /******* comment out
      UpSampling(alpha_smb, alpha_dmb, width, height,
		 alpha,
		 GetImageSizeX(alpha),GetImageSizeY(alpha),
		 x, y,
		 mb_s, MB_SIZE );
      *********************/
      FreeImage(bordered_smb_data);
      bordered_smb_data = AllocImage(mb_s+4,mb_s+4,SHORT_TYPE);
 
      top_sborder=TopBorderDecimate(top_border_data,MB_SIZE/mb_s);
      left_sborder=LeftBorderDecimate(left_border_data,MB_SIZE/mb_s);
 
      PutSubImage(bordered_smb_data,top_sborder,0,0);
      PutSubImage(bordered_smb_data,left_sborder,0,2);
 
      FreeImage(top_sborder);
      FreeImage(left_sborder);
 
      p = (SInt *) GetImageData(bordered_smb_data)
        + 2*GetImageSizeX(bordered_smb_data) + 2;
      for( i=0; i<mb_s; i++)
        for( j=0; j<mb_s; j++) {
          p[GetImageSizeX(bordered_smb_data)*i+j] = (SInt) alpha_smb[i*mb_s+j];
        }
 
      tmp1 = AllocImage(2,1,SHORT_TYPE);
      GetSubImage(bordered_smb_data,tmp1,0,mb_s+1);
      PutSubImage(bordered_smb_data,tmp1,0,mb_s+2);
      PutSubImage(bordered_smb_data,tmp1,0,mb_s+3);
      FreeImage(tmp1);
 
      UpSampling(bordered_smb_data, alpha_dmb, width, height,
                 GetImageSizeX(alpha),
                 GetImageSizeY(alpha),
                 x, y,
                 mb_s, MB_SIZE);

      /***** SAIT end *****/
    }
#else
    /* up sampling */
    ChangeSamplingRate( alpha_smb, alpha_dmb, width, height, mb_s,
			 MB_SIZE );

		#ifdef MEDIAN_FILTER_BAB
		/* SAIT begin */
		/**** comment out
		if (mb_type==2) MedianFilterBAB(GetVopA(vop), x, y, alpha_dmb);
		******/
		if (mb_type==2) MedianFilterBAB(alpha, x, y, alpha_dmb);
		/* SAIT end */
		#endif 
#endif

    flag = Compare( alpha_mb, alpha_dmb, alpha_th, cr );

    if( flag == YES ) {
      for( i=0; i<org_s; i++ ) alpha_mb[i] = alpha_dmb[i];
      if( mb_type == 2 ) mb_type += cr;
      return mb_type;
    }
    mb_type = 2;
  }

  for( i=0; i<org_s; i++ ) alpha_smb[i] = alpha_mb[i];

  /* SAIT begin */
  FreeImage(bordered_smb_data);
  bordered_smb_data = AllocImage(MB_SIZE+4,MB_SIZE+4,SHORT_TYPE);
  PutSubImage(bordered_smb_data,top_border_data,0,0);
  PutSubImage(bordered_smb_data,left_border_data,0,2);
  p = (SInt *) GetImageData(bordered_smb_data)
    + 2*GetImageSizeX(bordered_smb_data) + 2;
  for( i=0; i<MB_SIZE; i++)
    for( j=0; j<MB_SIZE; j++) {
      p[GetImageSizeX(bordered_smb_data)*i+j] = (SInt) alpha_smb[i*MB_SIZE+j];
    }
  tmp1 = AllocImage(2,1,SHORT_TYPE);
  GetSubImage(bordered_smb_data,tmp1,0,MB_SIZE+1);
  PutSubImage(bordered_smb_data,tmp1,0,MB_SIZE+2);
  PutSubImage(bordered_smb_data,tmp1,0,MB_SIZE+3);
  FreeImage(tmp1);
  /* SAIT end */

  return mb_type;
}

/***********************************************************CommentBegin******
 *
 * -- AlphaModeDecision -- Determines whether the BAB is
 *											- all0
 *											- all255
 *											- inter/no-update
 *											- coded by some other means
 *
 * Author :		
 *	Noel Brady Teltec Irl.
 *
 * Created :		
 *	11-04-97
 * 
 * Arguments In: 	
 *					alpha_mb_comp - the MC BAB
 *					shape_inter - flag indicating whether inter coding is applicable
 *					mvda - flag indicating whether the MVDs==0
 *					alpha_th - alpha threshold
 *
 * Arguments In/Out:
 *					alpha_mb - the original BAB on input/can be modified on output
 *
 * Arguments Out:
 *
 * Return values :
 *					mb_type: contains the mb_type information communicating the
 *											outcome of the decision.
 *
 * Side effects :	
 *	-
 *
 * Description : As per VM7
 *
 * See also :
 *
 ***********************************************************CommentEnd********/

Int AlphaModeDecision(
                      UChar *alpha_mb,       /* in/out */
                      UChar *alpha_mb_comp,  /* in     */
                      Int shape_inter,                 /* in     */
                      Int mvda,                      /* in     */
                      Int alpha_th                   /* in     */
                      )
{
  Int i, j, size;
  Int cnt_w, cnt_b;
  Int mb_type;
  UChar alpha_dmb[MB_SIZE*MB_SIZE];
  Int inter_not_coded;


 /** Patch provided by Minhua Zhou 14.05.1997 */
    {
     Int all_0=0,all_255=0,nb_255=0;
     for( i=0; i<MB_SIZE*MB_SIZE; i++ ) alpha_dmb[i] = 255;
        if( Compare( alpha_mb, alpha_dmb, alpha_th, 0 ) == YES ) 
           all_255 =1;
     for( i=0; i<MB_SIZE*MB_SIZE; i++ ) alpha_dmb[i] = 0;
        if( Compare( alpha_mb, alpha_dmb, alpha_th, 0 ) == YES ) 
           all_0 = 1;
     if (all_0&& all_255) {
       for( i=0; i<MB_SIZE*MB_SIZE; i++ ) 
         if (alpha_mb[i]) nb_255++;
       if (nb_255>=MB_SIZE*MB_SIZE/2) {
         for( i=0; i<MB_SIZE*MB_SIZE; i++ )
            alpha_mb[i] = 255;
            mb_type = 0;
         } else {
        for( i=0; i<MB_SIZE*MB_SIZE; i++ )
            alpha_mb[i] = 0;
            mb_type = 1;
         }
       return mb_type;
    }
         
  }  



  if(shape_inter)
		{
			inter_not_coded = AlphaBlockType( alpha_mb, alpha_mb_comp, 
							mvda, alpha_th );

      if(inter_not_coded) mb_type = -1;
      else mb_type = 2;
    }
	else
		{
      mb_type = 2;
    }


  if(mb_type==2)
		{

    	size = MB_SIZE*MB_SIZE;
    	cnt_w = cnt_b = 0;
    	for( i=0; i<MB_SIZE; i++ ) for( j=0; j<MB_SIZE; j++ ) 
				{
      		if( alpha_mb[i*MB_SIZE+j] == 0 ) cnt_w++;
      		else                             cnt_b++;
    		}

    	if( cnt_b == size && cnt_w == 0 )      mb_type = 0;
    	else if( cnt_w == size && cnt_b == 0 ) mb_type = 1;
    	else                                   mb_type = 2;

    	if( mb_type == 2 )
				{
      		for( i=0; i<MB_SIZE*MB_SIZE; i++ ) alpha_dmb[i] = 255;
      		if( Compare( alpha_mb, alpha_dmb, alpha_th, 0 ) == YES ) 
						{
       	 			for( i=0; i<MB_SIZE*MB_SIZE; i++ ) alpha_mb[i] = alpha_dmb[i];
        			mb_type = 0;
      			}
					else
						{
        			for( i=0; i<MB_SIZE*MB_SIZE; i++ )alpha_dmb[i] = 0;
        			if( Compare( alpha_mb, alpha_dmb, alpha_th, 0 ) == YES ) 
								{
          				for( i=0; i<MB_SIZE*MB_SIZE; i++ ) alpha_mb[i] = alpha_dmb[i];
         					 mb_type = 1;
        				}
      			}
    		}
  	}

  return mb_type;
  /* -1:inter    0:all255   1:all0   2:multi */
}


Int Compare( UChar *org_mb, UChar *dec_mb, Int alpha_th,
	    Int cr )
{
  Int 	ip, jp, i, j, v, h, th;
  Int	sum_dis, flag;

  th = 16*alpha_th;

  for( v=0; v<MB_SIZE/4; v++ ) for( h=0; h<MB_SIZE/4; h++ ) {
    sum_dis = 0;
    flag = YES;
    for( i=0; i<4; i++ ) for( j=0; j<4; j++ ) {
      ip = 4*v+i; jp = 4*h+j;
      sum_dis += ABS(f8bit(*(org_mb+ip*MB_SIZE+jp))
		     -f8bit(*(dec_mb+ip*MB_SIZE+jp)));
    }
    if( sum_dis > th ) {
      flag = NO;
      return flag;
    }
  }
  return flag;
}


Int AlphaBlockType( UChar *mb_now, UChar *mb_prev,
                      Int mvda, Int alpha_th )
{
  Int   i, j, m, n, th;
  Int   alpha_block_type;
  Int   ip, jp, cnt_prev_w, sum_dis;
  Int   condition1, condition2, condition3, condition4, condition5, mb_total;
  Int condition6, condition7,cnt_prev_b,cnt_now;

  th = 16*alpha_th;
  mb_total = MB_SIZE*MB_SIZE;
  
	/* check for all zero in the MC block */

  cnt_prev_w = cnt_prev_b = cnt_now = 0;
  for( i=0; i<MB_SIZE; i++ ) for( j=0; j<MB_SIZE; j++ ) {
    *(mb_now+i*MB_SIZE+j) = BINARISE(*(mb_now+i*MB_SIZE+j));
		if (*(mb_now+i*MB_SIZE+j) != 0) cnt_now++;
	
    if( (*(mb_prev+i*MB_SIZE+j) = BINARISE(*(mb_prev+i*MB_SIZE+j))) == 0 )
      cnt_prev_w++;
		else cnt_prev_b++;
  }
  if( cnt_prev_w == mb_total ) condition2 = TRUE;
  else                         condition2 = FALSE;

  if( cnt_prev_b == mb_total ) condition6 = TRUE;
  else                         condition6 = FALSE;
  if( cnt_now == mb_total ) condition7 = TRUE;
  else                       condition7 = FALSE;


	/* check error in each 4x4 block assuming that the 
     MC block is all zero */

  condition1 = TRUE;
  for( i=0; i<MB_SIZE/4; i++ ) for( j=0; j<MB_SIZE/4; j++ ) {
    sum_dis = 0;
    for( m=0; m<4; m++ ) for( n=0; n<4; n++ ) {
      ip = 4*i+m; jp = 4*j+n;
      sum_dis += *(mb_now+ip*MB_SIZE+jp);
    }
    if( sum_dis > th ) {
      condition1 = FALSE;
      goto EXIT;
    }
  }
 EXIT:

	/* check error in each 4x4 block assuming that the MC block is
     all 255 */

  condition3 = TRUE;
  for( i=0; i<MB_SIZE/4; i++ ) for( j=0; j<MB_SIZE/4; j++ ) {
    sum_dis = 0;
    for( m=0; m<4; m++ ) for( n=0; n<4; n++ ) {
      ip = 4*i+m; jp = 4*j+n;
      sum_dis += ABS(*(mb_now+ip*MB_SIZE+jp) - 255);
    }
    if( sum_dis > th ) {
      condition3 = FALSE;
      goto EXIT2;
    }
  }
 EXIT2:

	/* check the actual error in each 4x4 block */

  condition4 = FALSE;
  for( i=0; i<MB_SIZE/4; i++ ) for( j=0; j<MB_SIZE/4; j++ ) {
    sum_dis = 0;
    for( m=0; m<4; m++ ) for( n=0; n<4; n++ ) {
      ip = 4*i+m; jp = 4*j+n;
      sum_dis += ABS(*(mb_now+ip*MB_SIZE+jp) - (*(mb_prev+ip*MB_SIZE+jp)));
    }
    if( sum_dis > th ) {
      condition4 = TRUE;
      goto EXIT3;
    }
  }
 EXIT3:

  if( condition3 && ( mvda == 0 || condition4 ) ) {
    condition5 = TRUE;
    for( i=0; i<MB_SIZE; i++ ) for( j=0; j<MB_SIZE; j++ )
      *(mb_now+i*MB_SIZE+j) = 255;
  } else
    condition5 = FALSE;

	
  if ( condition1 )
    for( i=0; i<MB_SIZE; i++ ) for( j=0; j<MB_SIZE; j++ )
      *(mb_now+i*MB_SIZE+j) = 0;

  alpha_block_type = TRUE;
  if( condition1 || condition2 || condition4 || condition5 
			|| (condition7 && (!condition6)) )
    alpha_block_type = FALSE;

  return alpha_block_type;
}



