/*****************************************************************************
 *
 * This software module was originally developed by
 *
 *   Ryuji Kitaura  (Sharp Corporation)
 *   Hisashi Saiga  (Sharp Corporation)
 *   Tomoko Aono    (Sharp Corporation)
 *   Hiroyuki Katata(Sharp Corporation)
 *
 * 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
 *
 *****************************************************************************/




/* =============================================================================
Background Composition (June 7, 1996)

Copyright (C) 1996 Sharp Corporation
Modified:
  Nov 28th, 1996 Hisashi Saiga
  25.07.97 F. Jaureguizar: Delete PictImage *InitImage(); declaration.
           Change new variable by nnew to avoid C++ problems.
============================================================================= */
/* bg_comp.c, background compostition for temporal scalabilty                  */

#define float2uchar(x)   (((x+0.5)<0) ? 0 : ((0xff<(x+0.5)) ? 0xff : (x+0.5)))

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "momusys.h"
#include "mom_vop.h"
#include "mom_bitstream_i.h"
#include "mom_access.h"
#include "mom_putbits.h"
#include "io_generic.h"
#include "putvlc.h"
#include "text_code_mb.h"
#include "vm_vop_code.h"
#include "vm_compos.h"
#include "vm_stats.h"
#include "vm_config.h"
#include "vm_enc_main.h"
#include "vm_enc_defs.h"
#include "vm_vop_bound.h"
#include "mot_padding.h"

#include "do_bgc.h"
#include "post_filter.h"
/***********************************************************CommentBegin******
 *
 * -- do_bgc
 *
 * Author : Hiroyuki Katata(SHARP)	
 *
***********************************************************CommentBegin******/
void
do_bgc(Vop *rec_vop,                      /* current reconst. VOP    */
       Vop *disp_for,                     /* previous composit image */ 
       Vop *disp_back,                    /* future composit image   */ 
       Vop *display_vop ,                 /* display size image      */
       Int temp_ref , 
       Int for_temp_ref ,
       Int back_temp_ref )
{
  PictImage *curr_recon,                  /* current reconst. VOP    */
            *for_image,                   /* previous composit image */ 
            *back_image,                  /* future composit image   */ 
            *full_image,                  /* display size image      */
            *mask_recon,                  /* current VOP mask        */
            *mask_for,                    /* previous display mask   */
            *mask_back;                   /* future display mask     */
  Int x,y;

  /* get VOP size */
  x=GetVopWidth(rec_vop);
  y=GetVopHeight(rec_vop);

  /* memory allocate */
  curr_recon=InitImage(x*y);
  mask_recon=InitImage(x*y);

  /* format change Vop -> PictImage */
  trsVtoP(rec_vop,curr_recon,mask_recon);

  /* get full size */
  x=GetVopWidth(display_vop);
  y=GetVopHeight(display_vop);

  /* memory allocate */
  full_image=InitImage(x*y);
  for_image=InitImage(x*y);
  back_image=InitImage(x*y);
  mask_for=InitImage(x*y);
  mask_back=InitImage(x*y);

  /* format change Vop -> PictImage */
  trsVtoP(disp_for,   for_image,   mask_for);
  
  if(rec_vop->back_comp == 1)
    trsVtoP(disp_back,  back_image,  mask_back);

  /* background composition */
  bg_comp(curr_recon, for_image,       back_image,              full_image,         mask_recon,    mask_for,
          mask_back,  rec_vop->width,  rec_vop->height,         display_vop->width,
          display_vop->height,         temp_ref,       for_temp_ref ,
          back_temp_ref ,              rec_vop->hor_spat_ref,   rec_vop->ver_spat_ref, 
          rec_vop->binary_shape,       rec_vop-> back_comp );
  
  /* format change PictImage -> VOP */
  trsPtoV(full_image,display_vop);

  /* memory free */
  FreeImg(curr_recon);
  FreeImg(for_image);
  FreeImg(back_image);
  FreeImg(full_image);
  FreeImg(mask_recon);
  FreeImg(mask_for);
  FreeImg(mask_back);

  return;
}

/***********************************************************CommentBegin******
 *
 * -- trsVtoP
 * format change VOP -> PictImage
 *
 * Author :Hiroyuki Katata(SHARP)
 *
***********************************************************CommentBegin******/
void
trsVtoP(Vop *vop_in,
	PictImage *img,
	PictImage *msk)
{
  Int xsize, ysize, x, y, i;

  /* get image size */
  xsize=GetVopWidth(vop_in);
  ysize=GetVopHeight(vop_in);

  /* copy image from VOP to PictImage */
  for (y=0;y<ysize;y++) {
	for (x=0;x<xsize;x++) {
	  i=y*xsize+x;
	  msk->lum[i]=(UChar)vop_in->a_chan->f[i];
	  img->lum[i]=(UChar)vop_in->y_chan->f[i];
	}
  }
  for (y=0;y<ysize/2;y++)
	for (x=0;x<xsize/2;x++) {
	  i=y*xsize/2+x;
	  img->Cb[i]=(UChar)vop_in->u_chan->f[i];
	  img->Cr[i]=(UChar)vop_in->v_chan->f[i];
	}
  return;
}

/***********************************************************CommentBegin******
 *
 * -- trsVtoP
 * format change PictImage -> VOP
 *
 * Author :Hiroyuki Katata(SHARP)
 *
***********************************************************CommentBegin******/
void
trsPtoV(PictImage *img,
	Vop *vop_out)
{
  Int xsize, ysize, x, y, i;

  /* get image size */
  xsize=GetVopWidth(vop_out);
  ysize=GetVopHeight(vop_out);

  /* copy image from VOP to PictImage */
  for (y=0;y<ysize;y++)
	for (x=0;x<xsize;x++) {
	  i=y*xsize+x;
	  vop_out->y_chan->f[i]=img->lum[i];
	}
  for (y=0;y<ysize/2;y++)
	for (x=0;x<xsize/2;x++) {
	  i=y*xsize/2+x;
	  vop_out->u_chan->f[i]=img->Cb[i];
	  vop_out->v_chan->f[i]=img->Cr[i];
	}
  return;
}

/***********************************************************CommentBegin******
 *
 * -- FreeImg
 *
 * Author :Hiroyuki Katata(SHARP)		
 *
***********************************************************CommentBegin******/
void
FreeImg(PictImage *image)
{
  free(image->lum);
  free(image->Cr);
  free(image->Cb);
  free(image);
}

/***********************************************************CommentBegin******
 *
 * -- InitImage
 *
 * Author :Hiroyuki Katata(SHARP)		
 *
***********************************************************CommentBegin******/
PictImage
*InitImage(Int size)
{
  PictImage *nnew;

  if ((nnew = (PictImage *)malloc(sizeof(PictImage))) == NULL) {
    fprintf(stderr,"Couldn't allocate (PictImage *)\n");
    exit(-1);
  }
  if ((nnew->lum = (UChar *)malloc(sizeof(Char)*size)) 
      == NULL) {
    fprintf(stderr,"Couldn't allocate memory for luminance\n");
    exit(-1);
  }
  if ((nnew->Cr = (UChar *)malloc(sizeof(Char)*size/4)) 
      == NULL) {
    fprintf(stderr,"Couldn't allocate memory for Cr\n");
    exit(-1);
  }
  if ((nnew->Cb = (UChar *)malloc(sizeof(Char)*size/4)) 
      == NULL) {
    fprintf(stderr,"Couldn't allocate memory for Cb\n");
    exit(-1);
  }

  return nnew;
}

/***********************************************************CommentBegin******
 *
 * -- bg_comp
 *
 * Author :Hiroyuki Katata(SHARP)		
 *
***********************************************************CommentBegin******/
void
bg_comp(f_curr, f_prev, f_next, out_image, a_curr, a_prev, a_next, 
	curr_x, curr_y, prev_x, prev_y,
	curr_t, prev_t, next_t, spatial_ref_x, spatial_ref_y,
	binary_shape, background_comp)

	 PictImage *f_curr,  *f_prev,  *f_next; /* YUV data                                                          */
	 PictImage *out_image;                  /* YUV data for output image                                         */
	 PictImage *a_curr;                     /* alpha data for Y (binary/gray)                                    */
	 PictImage *a_prev, *a_next;            /* alpha data for Y (binary)                                         */
	 Int curr_x, curr_y, prev_x, prev_y;    /* image size (Size of f_next,out_image is same as f_prev)           */
	 Int curr_t, prev_t, next_t;            /* temporal reference                                                */
	 Int spatial_ref_x, spatial_ref_y;      /* spatial reference of f_curr in f_prev                             */
	 Int binary_shape;                      /* flag  1:binary, 0:gray (This flag is only for a_curr.)            */
	 Int background_comp;                   /* flag  1:compose a background, 0:use nearest frame as a background */
{
  Int i, j;
  UChar *gray_curr, *gray_prev, *gray_next; /* gray alpha plane */
  
  if( background_comp == 0)       fprintf(stdout,"BGC OFF     \n");
  else if( background_comp == 1)  fprintf(stdout,"BGC COMPOSE \n");
  else                            fprintf(stdout,"BGC ERROR   \n");
  
  /* ----- process for Y ----- */
  gray_curr = (UChar *)malloc(curr_x*curr_y);
  gray_prev = (UChar *)malloc(prev_x*prev_y);
  
  if(background_comp == 1)
    gray_next = (UChar *)malloc(prev_x*prev_y); /* Size of f_next is same as f_prev */
  
  if(binary_shape){ /* a_curr[] is 0 or 1 */
	for(i=0; i<curr_x*curr_y; i++)
	  gray_curr[i]   = a_curr->lum[i];
  }
  else{             /* a_curr is 0 -- 255 */
	for(i=0; i<curr_x*curr_y; i++)
	  gray_curr[i]   = a_curr->lum[i];
  }
  for(i=0; i<prev_x*prev_y; i++){
    gray_prev[i] = a_prev->lum[i];
    if(background_comp == 1)
      gray_next[i] = a_next->lum[i];
  }

  bg_comp_each(f_curr->lum, f_prev->lum, f_next->lum, out_image->lum,
	       gray_curr, gray_prev, gray_next, 
	       curr_x, curr_y, prev_x, prev_y,
	       curr_t, prev_t, next_t, spatial_ref_x, spatial_ref_y, background_comp);
  free(gray_curr);
  free(gray_prev);

  if(background_comp == 1)
    free(gray_next);

  /* ----- process for C ----- */
  curr_x /= 2;  curr_y /= 2;
  prev_x /= 2;  prev_y /= 2;
  spatial_ref_x /= 2;
  spatial_ref_y /= 2;
  gray_curr = (UChar *)malloc(curr_x*curr_y);
  gray_prev = (UChar *)malloc(prev_x*prev_y);

  if(background_comp == 1)
    gray_next = (UChar *)malloc(prev_x*prev_y); /* Size of f_next is same as f_prev */

  if(binary_shape){ /* a_curr[] is 0 or 1 */
	for(j=0; j<curr_y; j++)
	  for(i=0; i<curr_x; i++)
		if(a_curr->lum[(2*j  )*(2*curr_x)+(2*i)]+a_curr->lum[(2*j  )*(2*curr_x)+(2*i+1)]+
		   a_curr->lum[(2*j+1)*(2*curr_x)+(2*i)]+a_curr->lum[(2*j+1)*(2*curr_x)+(2*i+1)])
		  gray_curr[j*curr_x+i] = 255;
		else
		  gray_curr[j*curr_x+i] = 0;
  }
  else{             /* a_curr is 0 -- 255 */
	for(j=0; j<curr_y; j++)
	  for(i=0; i<curr_x; i++)
		gray_curr[j*curr_x+i] = float2uchar( ((float)a_curr->lum[(2*j  )*(2*curr_x)+(2*i)]+
						      (float)a_curr->lum[(2*j  )*(2*curr_x)+(2*i+1)]+
						      (float)a_curr->lum[(2*j+1)*(2*curr_x)+(2*i)]
						      +(float)a_curr->lum[(2*j+1)*(2*curr_x)+(2*i+1)])/4.0 );
  }
  for(j=0; j<prev_y; j++)
	for(i=0; i<prev_x; i++){
	  if(a_prev->lum[(2*j  )*(2*prev_x)+(2*i)]+a_prev->lum[(2*j  )*(2*prev_x)+(2*i+1)]+
		 a_prev->lum[(2*j+1)*(2*prev_x)+(2*i)]+a_prev->lum[(2*j+1)*(2*prev_x)+(2*i+1)])
		gray_prev[j*prev_x+i] = 255;
	  else
		gray_prev[j*prev_x+i] = 0;

	  if(background_comp == 1){
	    if(a_next->lum[(2*j  )*(2*prev_x)+(2*i)]+a_next->lum[(2*j  )*(2*prev_x)+(2*i+1)]+
	       a_next->lum[(2*j+1)*(2*prev_x)+(2*i)]+a_next->lum[(2*j+1)*(2*prev_x)+(2*i+1)])
	       gray_next[j*prev_x+i] = 255;
	    else
		gray_next[j*prev_x+i] = 0;
	  }
       }

  bg_comp_each(f_curr->Cr, f_prev->Cr, f_next->Cr, out_image->Cr, gray_curr, gray_prev, gray_next, 
			   curr_x, curr_y, prev_x, prev_y,
			   curr_t, prev_t, next_t, spatial_ref_x, spatial_ref_y, background_comp);
  bg_comp_each(f_curr->Cb, f_prev->Cb, f_next->Cb, out_image->Cb, gray_curr, gray_prev, gray_next, 
			   curr_x, curr_y, prev_x, prev_y,
			   curr_t, prev_t, next_t, spatial_ref_x, spatial_ref_y, background_comp);
  free(gray_curr);
  free(gray_prev);

  if(background_comp == 1)
    free(gray_next);
}

/***********************************************************CommentBegin******
 *
 * -- bg_comp_each
 *
 * Author :Hiroyuki Katata(SHARP)		
 *
***********************************************************CommentBegin******/
Void
bg_comp_each(f_curr, f_prev, f_next, out_image, gray_curr, gray_prev, gray_next, 
	     curr_x, curr_y, prev_x, prev_y,
	     curr_t, prev_t, next_t, spatial_ref_x, spatial_ref_y, background_comp)
  UChar *f_curr, *f_prev, *f_next;          /* pixel data                                                        */
  UChar *out_image;                         /* pixel data for output image                                       */
  UChar *gray_curr, *gray_prev, *gray_next; /* alpha data (gray)                                                 */
  Int curr_x, curr_y, prev_x, prev_y;       /* image size (Size of f_next,out_image is also (prev_x,prev_y))     */
  Int curr_t, prev_t, next_t;               /* temporal reference                                                */
  Int spatial_ref_x, spatial_ref_y;         /* spatial reference of f_curr in f_prev                             */
  Int background_comp;                      /* flag  1:compose a background, 0:use nearest frame as a background */
{
  Int i, j;
  UChar* mask_overlap;
  Void pre_pad(UChar *mask, UChar *curr, Int width, Int height);

  /* ----- put nearest frame ----- */
  if(background_comp){
     mask_overlap = (UChar *)malloc(prev_x*prev_y);
     if((abs(curr_t-prev_t) > abs(curr_t-next_t) ) && (abs(abs(curr_t-prev_t) - abs(curr_t-next_t) ) < 1 ))
	for(i=0; i<prev_x*prev_y; i++)
		out_image[i]=f_next[i];
     else
	for(i=0; i<prev_x*prev_y; i++)
	  out_image[i]=f_prev[i];
     
     /* ----- perform background composition ----- */
     for(i=0; i<prev_x*prev_y; i++){
	  if(gray_prev[i] > 0 && gray_next[i] == 0)	 /* ----- f_next is used ----- */
		out_image[i]=f_next[i];
	  else if(gray_prev[i] == 0 && gray_next[i] > 0) /* ----- f_prev is used ----- */
		out_image[i]=f_prev[i];
	  if(gray_prev[i] > 0 && gray_next[i] > 0)       /* ----- overlapped area ----- */
		mask_overlap[i]=0;
	  else
		mask_overlap[i]=1;
      }
      pre_pad(mask_overlap, out_image, prev_x, prev_y);  /* for padding */
      free(mask_overlap);
  }
  else
    for(i=0; i<prev_x*prev_y; i++)
      out_image[i]=f_prev[i];
     
  /* ----- overlap current frame to back ground ----- */
  for(j=0; j<curr_y; j++)
    for(i=0; i<curr_x; i++)
      out_image[(j+spatial_ref_y)*prev_x+(i+spatial_ref_x)] =
	float2uchar(((float)gray_curr[j*curr_x+i]*(float)f_curr[j*curr_x+i] +
		     (255.0-(float)gray_curr[j*curr_x+i])*(float)out_image[(j+spatial_ref_y)*prev_x+
									   (i+spatial_ref_x)])/255.0 );
}

/***********************************************************CommentBegin******
 *
 * -- SelectBGMode
 * decide whether BGC is necessary
 *
 * Author :Hiroyuki Katata(SHARP)		
 *
***********************************************************CommentBegin******/
Int
SelectBGMode(Vop *rec_vop ,           /* current reconst. VOP 			*/
 	     Vop *disp_for ,          /* previous composit image 		*/ 
             Vop *disp_back ,         /* future composit image 			*/
             Int *mode ,	      /* == 1 if BGC is necessary : otherwise 0 */
             Int temp_ref,
	     Int for_temp_ref ,
	     Int back_temp_ref)   				
{
	PictImage *curr_recon,        /* current reconst. VOP    */
	*for_image,                   /* previous composit image */ 
	*back_image,                  /* future composit image   */ 
	*mask_recon,                  /* current VOP mask        */
	*mask_for,                    /* previous display mask   */
	*mask_back;                   /* future display mask     */
	Int x,y;
	Int	ret;

	*mode = 0;
	/* get VOP size */
	x=GetVopWidth(rec_vop);
	y=GetVopHeight(rec_vop);
	
	/* memory allocate */
	curr_recon=InitImage(x*y);
	mask_recon=InitImage(x*y);

	/* format change Vop -> PictImage */
	trsVtoP(rec_vop,curr_recon,mask_recon);
	
	/* The way bg_select() is coded, it is meaningless to have disp_for decide the size of for_image */
	x=GetVopWidth( disp_back );
	y=GetVopHeight( disp_back );
	
	/* memory allocate */
	for_image=InitImage(x*y);
	back_image=InitImage(x*y);
	mask_for=InitImage(x*y);
	mask_back=InitImage(x*y);
	
	/* format change Vop -> PictImage */
	trsVtoP(disp_for,for_image,mask_for);
	trsVtoP(disp_back,back_image,mask_back);
	ret = bg_select( mask_recon , mask_for ,   mask_back ,
			 rec_vop -> width ,        rec_vop -> height ,
			 disp_back -> width ,      disp_back -> height ,
			 temp_ref ,     for_temp_ref , back_temp_ref ,
			 rec_vop -> hor_spat_ref , rec_vop -> ver_spat_ref ,
			 rec_vop -> binary_shape , 50 );
	
	if ( ret == 1 ) {/* BGC necessary : code shapes */
	  *mode = 1;
	}
	FreeImg(curr_recon);
	FreeImg(for_image);
	FreeImg(back_image);
	FreeImg(mask_recon);
	FreeImg(mask_for);
	FreeImg(mask_back);
	return( 0 );
}

/***********************************************************CommentBegin******
 *
 * -- bg_select
 *
 * Author :Hiroyuki Katata(SHARP)		
 *
***********************************************************CommentBegin******/
Int
bg_select(PictImage *curr_mask,
	  PictImage *prev_mask,
	  PictImage *next_mask,
	  Int curr_x, Int curr_y,
	  Int prev_x, Int prev_y,
	  Int curr_t, Int prev_t, Int next_t,
	  Int spatial_ref_x, Int spatial_ref_y, 
	  Int binary_shape, Int bg_threshold)
{
  Int background_comp, /* flag  1:compose a background, 0:use nearest frame as a background */
      i, j, error;
  UChar *gray_curr,    /* gray alpha plane */
        *gray_prev,
        *gray_next; 

  /* ----- set gray values ----- */
  gray_curr = (UChar *)malloc(curr_x*curr_y);
  gray_prev = (UChar *)malloc(prev_x*prev_y);
  gray_next = (UChar *)malloc(prev_x*prev_y); /* Size of gray_next is same as gray_prev */
  
  if(binary_shape){ /* a_curr[] is 0 or 1 */
	for(i=0; i<curr_x*curr_y; i++)
	  gray_curr[i] = 255*curr_mask->lum[i];
  }
  else{             /* a_curr is 0 -- 255 */
	for(i=0; i<curr_x*curr_y; i++)
	  gray_curr[i] = curr_mask->lum[i];
  }
  
  for(i=0; i<prev_x*prev_y; i++){
	gray_prev[i] = 255*prev_mask->lum[i];
	gray_next[i] = 255*next_mask->lum[i];
  }

  /* ----- get errror by putting nearest frame ----- */
  error = 0;
  if( (abs(curr_t-prev_t) > abs(curr_t-next_t) ) && (abs(abs(curr_t-prev_t) - abs(curr_t-next_t) ) < 1 )){
	for(j=0; j<prev_y; j++)
	  for(i=0; i<prev_x; i++)
		if(i >= spatial_ref_x && i < spatial_ref_x+curr_x &&
		   j >= spatial_ref_y && j < spatial_ref_y+curr_y &&
		   gray_curr[(j-spatial_ref_y)*curr_x+(i-spatial_ref_x)] == 0 &&
		   gray_next[j*prev_x+i] > 0)
		  error ++;
  }
  else{
	for(j=0; j<prev_y; j++)
	  for(i=0; i<prev_x; i++)
		if(i >= spatial_ref_x && i < spatial_ref_x+curr_x &&
		   j >= spatial_ref_y && j < spatial_ref_y+curr_y &&
		   gray_curr[(j-spatial_ref_y)*curr_x+(i-spatial_ref_x)] == 0 &&
		   gray_prev[j*prev_x+i] > 0)
		  error ++;
  }
  free(gray_curr);
  free(gray_prev);
  free(gray_next);

  printf("error pixels by not using background composition = %d\n", error);
  if(error > bg_threshold)
	background_comp = 1;
  else
	background_comp = 0;

  return background_comp;
}


/* for deblock */
/***********************************************************CommentBegin******
 *
 * -- DeblockVop : Deblocking and deringing filter.
 *                 pixel values(Y,U,V) where alpha==0 are changed to (0, 128, 128)
 *
 * Author :		
 *	Hiroyuki Katata
 *
 * Created :		
 *	June 11, 1997
 *
 * Return values :	
 *	 Vop   - output filtered image
 *
 * Side effects :	
 *	none
 *
 ***********************************************************CommentEnd********/


Vop *DeblockVop(Vop *vop, Int deblock_filter_disable)
{
  Vop   *vop_out;
  Int   i, j;
  Int   width,  height;
  SInt	*ptr_y, *ptr_u, *ptr_v, *ptr_a;
  
  vop_out = CloneVop(vop);
  
  if(GetVopShape(vop_out)!=0){
	ptr_y = (SInt *)GetImageData(GetVopY(vop_out));
	ptr_a = (SInt *)GetImageData(GetVopA(vop_out));
	width = GetImageSizeX(GetVopY(vop_out));
	height= GetImageSizeY(GetVopY(vop_out));
	
	for(j=0; j<height; j++)
	  for(i=0; i<width; i++)
		if( ptr_a[j*width+i] == 0 )
		  ptr_y[j*width+i] = 0;
	
	ptr_u = (SInt *)GetImageData(GetVopU(vop_out));
	ptr_v = (SInt *)GetImageData(GetVopV(vop_out));
	ptr_a = (SInt *)GetImageData(GetVopAuv(vop_out));
	width = GetImageSizeX(GetVopU(vop_out));
	height= GetImageSizeY(GetVopU(vop_out));
	
	for(j=0; j<height; j++)
	  for(i=0; i<width; i++)
		if( ptr_a[j*width+i] == 0 ){
		  ptr_u[j*width+i] = 128;
		  ptr_v[j*width+i] = 128;
		}
  }

  if(GetVopShape(vop_out)!=0 && GetVopWidth(vop_out)==0)	;
  else if(deblock_filter_disable==0)
	PostFilter(vop_out,3);
  
  return vop_out;
}

/***********************************************************CommentBegin******
 *
 * -- CopyAlpha
 *
 * Author :Ryuji KITAURA (SHARP)	
 *
***********************************************************CommentBegin******/
Void
CopyAlpha(Vop *in, Vop *out)
{
  Int   width_in,  height_in,
        width_out, height_out,
        xref_in,      yref_in,
        xref_out,      yref_out,
        i,j;
  
  Image	*alpha_in,
        *alpha_out;
  
  SInt	*in_data;
  SInt	*out_data;
	
  width_in   = GetVopWidth(in);
  height_in  = GetVopHeight(in);
  width_out  = GetVopWidth(out);
  height_out = GetVopHeight(out);
  xref_in       = GetVopHorSpatRef(in);
  yref_in       = GetVopVerSpatRef(in);
  xref_out       = GetVopHorSpatRef(out);
  yref_out       = GetVopVerSpatRef(out);
  alpha_in   = GetVopA(in);
  alpha_out  = GetVopA(out);
  in_data    = GetImageIData(alpha_in);
  out_data   = GetImageIData(alpha_out);
  
  /* out >= in */
  if(width_in <= width_out || height_in <= height_out){
       for(j = 0; j < height_out; j++)
	    for(i = 0; i < width_out; i++)
                  *(out_data + i + j * width_out) = 0;
  
       for(j = 0; j < height_in ; j++){
	    for(i = 0; i < width_in ; i++){
		  if ( ( i + xref_in >=  width_out ) || ( j + yref_in >=  height_out ) ) continue;
                  *(out_data + (i + xref_in)  + (j + yref_in)  * width_out)
		       = *(in_data + (i) + (j) * width_in);
	   }
       }
  }
  /* in >= out */
  else
       for(j = 0; j < height_out ; j++) 
	    for(i = 0; i < width_out ; i++) 
		  *(out_data + i + j * width_out) = *(in_data + (i + xref_out)
						              + (j + yref_out) * width_in);
}
/***********************************************************CommentBegin******
 *
 * -- GetRefTimeBits_TPS
 *
 * Author :Ryuji KITAURA (SHARP)
 *
 ***********************************************************CommentEnd********/
Int
GetRefTimeBits_TPS(Vop *vop)
{
  Int bits;
  
  bits = ceil(log((double)GetVopTimeIncrementResolution(vop))/log(2.0));
  if (bits<1) bits=1;
  return(bits);
}
/***********************************************************CommentBegin******
 *
 * -- PostFilter_TPS
 *
 * Author :Ryuji KITAURA (SHARP)
 *
***********************************************************CommentBegin******/
Vop
*PostFilter_TPS(Vop *curr_vop, Int deblock_filter,
	     Int image_width, Int image_height)
{
    Vop *local      = NULL,
	*file_vop   = NULL,
        *tmp_vop    = NULL,
        *curr_vop_tmp = NULL;
       
    
    file_vop = AllocVop( image_width , image_height );

    SetConstantImage(GetVopA(file_vop),0);
    SetConstantImage(GetVopY(file_vop),0);
    SetConstantImage(GetVopU(file_vop),128);
    SetConstantImage(GetVopV(file_vop),128);
    
    curr_vop_tmp = CloneVop(curr_vop);
    CopyVopNonImageField_TPS(curr_vop, curr_vop_tmp);
    
    if(GetVopShape(curr_vop_tmp) == 0)
	SetConstantImage(GetVopA(curr_vop_tmp), 255);
    
    if(!(GetVopShape(curr_vop_tmp)!=0 && GetVopWidth(curr_vop_tmp) == 0)){

        if(deblock_filter==0)
            BlendVops(curr_vop_tmp, file_vop);
        else {
            tmp_vop=CloneVop(curr_vop_tmp);
            VopPadding(tmp_vop);
	    if (GetImageSizeX(GetVopQP(tmp_vop))==GetVopWidth(tmp_vop)/16)
	        local=CloneVop(tmp_vop);
	    else
	        local=CloneVop_TMP(tmp_vop);
	    
	    PostFilter(local, 3);
	    FreeVop(tmp_vop);

	    BlendVops(local, file_vop);
            FreeVop(local);
        }
    }
    
    CopyAlpha(curr_vop, file_vop);
    CopyVopNonImageField_TPS(curr_vop, file_vop);
    
    FreeVop(curr_vop_tmp);
    return(file_vop);
}
/***********************************************************CommentBegin******
 *
 * -- CopyVopNonImageField_TPS
 *
 * Author :		
 *      Ryuji KITAURA (SHARP)
 *      04.11.97 Minhua Zhou: added flags according to CD
 *
***********************************************************CommentBegin******/
Void
CopyVopNonImageField_TPS(Vop *in,Vop *out)
{
  Int i;
  Int *iqmat_in,*iqmat_out,*nqmat_in,*nqmat_out,
      *gl_iqmat_in,*gl_iqmat_out,*gl_nqmat_in,*gl_nqmat_out;
  
  PutVopModTimeBase(GetVopModTimeBase(in),out);
  PutVopTimeInc(GetVopTimeInc(in),out);
  PutVopPredictionType(GetVopPredictionType(in),out);
  PutVopRoundingType(GetVopRoundingType(in),out);
  PutVopIsObjectLayerIdentifier(GetVopIsObjectLayerIdentifier(in),out);
  PutVopVisualObjectLayerVerid(GetVopVisualObjectLayerVerid(in),out); 
  PutVopVisualObjectLayerPriority(GetVopVisualObjectLayerPriority(in),out);
  PutVopVolControlParameters(GetVopVolControlParameters(in),out); 
  PutVopFixedVopRate(GetVopFixedVopRate(in),out); 
  PutVopQuantPrecision(GetVopQuantPrecision(in),out);
  PutVopBitsPerPixel(GetVopBitsPerPixel(in),out);
  PutVopComplexityEstimationDisable(GetVopComplexityEstimationDisable(in),out);
  PutVopRandomAccessibleVol(GetVopRandomAccessibleVol(in),out);
  PutVopConstantAlpha(GetVopConstantAlpha(in),out);
  PutVopConstantAlphaValue(GetVopConstantAlphaValue(in),out);
  PutVopInterlaced(GetVopInterlaced(in),out);
  PutVopTopFieldFirst(GetVopTopFieldFirst(in),out);
  PutVopAlternateScan(GetVopAlternateScan(in),out);
  PutVopBQuantizer(GetVopBQuantizer(in),out);
  PutVopBackComp(GetVopBackComp(in),out);
  PutVopQuantizer(GetVopQuantizer(in),out);
  PutVopIntraQuantizer(GetVopIntraQuantizer(in),out);
  PutVopGLQuantizer(GetVopGLQuantizer(in),out);
  PutVopTimeIncrementResolution(GetVopTimeIncrementResolution(in),out);
  PutVopLoadBackShape(GetVopLoadBackShape(in),out);
  PutVopLoadForShape(GetVopLoadForShape(in),out);
  PutVopRefSelCode(GetVopRefSelCode(in),out);
  PutVopForTempRef(GetVopForTempRef(in),out);
  PutVopBackTempRef(GetVopBackTempRef(in),out);

  PutVopVOId(GetVopVOId(in),out);
  PutVopId(GetVopId(in),out);
  PutVopArbitraryShape(GetVopArbitraryShape(in),out);
  PutVopShapeEffects(GetVopShapeEffects(in),out);
  PutVopQuantType(GetVopQuantType(in),out);

  PutVopLoadIntraQuantMat(GetVopLoadIntraQuantMat(in),out);
  PutVopLoadNonintraQuantMat(GetVopLoadNonintraQuantMat(in),out);
  PutVopDisableGrayQuantUpdate(GetVopDisableGrayQuantUpdate(in),out);
  PutVopLoadGrayIntraQuantMat(GetVopLoadGrayIntraQuantMat(in),out);
  PutVopLoadGrayNonintraQuantMat(GetVopLoadGrayNonintraQuantMat(in),out);
  
  if(GetVopQuantType(in))
    {
      iqmat_in  = GetVopIntraQuantMat(in);
      iqmat_out = GetVopIntraQuantMat(out);
      nqmat_in  = GetVopNonintraQuantMat(in);
      nqmat_out = GetVopNonintraQuantMat(out);

      gl_iqmat_in  = GetVopGrayIntraQuantMat(in);
      gl_iqmat_out = GetVopGrayIntraQuantMat(out);
      gl_nqmat_in  = GetVopGrayNonintraQuantMat(in);
      gl_nqmat_out = GetVopGrayNonintraQuantMat(out);

      for(i=0; i<64; i++)
        {
	  *(iqmat_out++) = *(iqmat_in++);
	  *(nqmat_out++) = *(nqmat_in++);
	  *(gl_iqmat_out++) = *(gl_iqmat_in++);
	  *(gl_nqmat_out++) = *(gl_nqmat_in++);
	}
    }

  PutVopIntraACDCPredDisable(GetVopIntraACDCPredDisable(in),out);
  PutVopErrorResDisable(GetVopErrorResDisable(in),out);
  PutVopDataPartEnable(GetVopDataPartEnable(in),out);
  PutVopReverseVlc(GetVopReverseVlc(in),out);
  PutVopFCodeFor(GetVopFCodeFor(in),out);
  PutVopFCodeBack(GetVopFCodeBack(in),out);
  PutVopSearchRangeFor(GetVopSearchRangeFor(in),out);
  PutVopSearchRangeBack(GetVopSearchRangeBack(in),out);

  PutVopScalability(GetVopScalability(in),out);
  PutVopSADCTDisable(GetVopSADCTDisable(in),out);
  PutVopOBMCDisable(GetVopOBMCDisable(in), out);
  PutVopIntraDCVlcThr(GetVopIntraDCVlcThr(in),out);

  PutVopRefId(GetVopRefId(in),out);
  PutVopRefSampDir(GetVopRefSampDir(in),out);
  PutVopHorSampN(GetVopHorSampN(in),out);
  PutVopHorSampM(GetVopHorSampM(in),out);
  PutVopVerSampN(GetVopVerSampN(in),out);
  PutVopVerSampM(GetVopVerSampM(in),out);
  PutVopEnhanceType(GetVopEnhanceType(in),out);

  PutVopScaling(GetVopScaling(in),out);
  PutVopVisibility(GetVopVisibility(in),out);
  PutVopBinaryShape(GetVopBinaryShape(in),out);
  PutVopCompOrder(GetVopCompOrder(in),out);	

  PutVopSpriteUsage(GetVopSpriteUsage(in),out);
  if (GetVopSpriteUsage(in))
  	{
	PutVopSpriteHdim(GetVopSpriteHdim(in), out);
	PutVopSpriteVdim(GetVopSpriteVdim(in), out);
	PutVopSpriteLeftEdge(GetVopSpriteLeftEdge(in), out);
	PutVopSpriteTopEdge(GetVopSpriteTopEdge(in), out);
	PutVopSprite(GetVopSprite(in),out);
	PutVopWarpParam(GetVopWarpParam(in),out);
	PutVopWarpingAccuracy(GetVopWarpingAccuracy(in),out);
	PutVopBlendFact(GetVopBlendFact(in),out);
	PutVopNoOfSpritePoints(GetVopNoOfSpritePoints(in),out);
	PutVopRefPointCoord(GetVopRefPointCoord(in),out);
	PutVopTrajPointCoord(GetVopTrajPointCoord(in),out);
	PutVopBrightnessChangeFactor(GetVopBrightnessChangeFactor(in),out);
	PutVopLowLatencySpriteEnable(GetVopLowLatencySpriteEnable(in),out);
	}
  PutVopChangeCRDisable(GetVopChangeCRDisable(in),out);
  PutVopErrorResDisable(GetVopErrorResDisable(in),out);
  PutVopShapeCodingType(GetVopShapeCodingType(in),out);


}

/***********************************************************CommentBegin******
 *
 * -- pre_pad
 *
 * Author : Hiroyuki Katata(SHARP)	
 *
***********************************************************CommentBegin******/
Void
pre_pad(UChar *mask,
	UChar *curr,
	Int width,
	Int height)
{
  int		i, j;
  int		flag_cnt = 0;
  int *flag_blk, *mask_blk;
  double *curr_blk;
  double	pad_val=0;
  int		ic, jc;

  double *hori_blk, *vert_blk;
	int *hori_flag_blk, *vert_flag_blk;
  
  flag_blk = (int *)malloc(sizeof(int)*width*height);
  mask_blk = (int *)malloc(sizeof(int)*width*height);
  curr_blk = (double *)malloc(sizeof(double)*width*height);

  hori_blk = (double *)malloc(sizeof(double)*width*height);
  vert_blk = (double *)malloc(sizeof(double)*width*height);
  hori_flag_blk = (int *)malloc(sizeof(int)*width*height);
  vert_flag_blk = (int *)malloc(sizeof(int)*width*height);
  
  
  for(j = 0; j < height; j++)
    for(i = 0; i < width; i++) {
      mask_blk[j * width + i] = (mask[j * width + i] != 0);
      if(mask_blk[j * width + i])
	hori_blk[j * width + i] = vert_blk[j * width + i] = curr_blk[j * width + i] = (double) curr[j * width + i];
      else
        hori_blk[j * width + i] = vert_blk[j * width + i] = curr_blk[j * width + i] = 0;
    }
  
  for(j = 0; j < height; j++)
	for(i = 0; i < width; i++)
	  flag_cnt+= (flag_blk[j * width + i] = mask_blk[j * width + i]);
  
  if(flag_cnt == 0)  return;

  
	while(flag_cnt != 0) {

	for(j = 0; j < height; j++)
		for(i = 0; i < width; i++)
			hori_flag_blk[j * width + i] = vert_flag_blk[j * width + i] = flag_blk[j * width + i];

	for(j = 0; j < height; j++)
		for(i = 0; i < width; i++){
		  mask_blk[j * width + i] = flag_blk[j * width + i];
			hori_blk[j * width + i] = vert_blk[j * width + i] = curr_blk[j * width + i];
	}

	for(j = 0; j < height; j++) {/* horizontal scan */
		for(ic = 1; ic < width; ic++)
			if(mask_blk[j * width + ic-1] - mask_blk[j * width + ic] == 1)  break;
		for(i = ic; i < width; i++) {
			if(mask_blk[j * width + i-1] - mask_blk[j * width + i] == 1)
				pad_val = hori_blk[j * width + i-1];
			if(!mask_blk[j * width + i]) {
				hori_blk[j * width + i]+= pad_val;
				hori_flag_blk[j * width + i]++;
			}
	  }
	  for(ic = width-2; ic >= 0; ic--)
			if(mask_blk[j * width + ic+1] - mask_blk[j * width + ic] == 1)  break;
	  for(i = ic; i >= 0; i--) {
			if(mask_blk[j * width + i+1] - mask_blk[j * width + i] == 1)
				pad_val = hori_blk[j * width + i+1];
			if(!mask_blk[j * width + i]) {
				hori_blk[j * width + i]+= pad_val;
				hori_flag_blk[j * width + i]++;
			}
	  }
	}/* end of horizontal scan */

	for(j = 0; j < height; j++)
	  for(i = 0; i < width; i++)
			if(hori_flag_blk[j * width + i] != 0) {
			  hori_blk[j * width + i] = (int)(hori_blk[j * width + i]/(double) hori_flag_blk[j * width + i]);
			  hori_flag_blk[j * width + i]/= hori_flag_blk[j * width + i];
			}

	for(i = 0; i < width; i++) {/* vertical scan */
	  for(jc = 1; jc < height; jc++)
			if(mask_blk[(jc-1) * width + i] - mask_blk[jc * width + i] == 1)  break;
	  for(j = jc; j < height; j++) {
			if(mask_blk[(j-1) * width + i] - mask_blk[j * width + i] == 1)
			  pad_val = vert_blk[(j-1) * width + i];
			if(!mask_blk[j * width + i]) {
				vert_blk[j * width + i]+= pad_val;
				vert_flag_blk[j * width + i]++;
			}
	  }
	  for(jc = height-2; jc >= 0; jc--)
			if(mask_blk[(jc+1) * width + i] - mask_blk[jc * width + i] == 1)  break;
	  for(j = jc; j >= 0; j--) {
			if(mask_blk[(j+1) * width + i] - mask_blk[j * width + i] == 1)
			  pad_val = vert_blk[(j+1) * width + i];
			if(!mask_blk[j * width + i]) {
				vert_blk[j * width + i]+= pad_val;
				vert_flag_blk[j * width + i]++;
			}
	  }
	}/* end of vertical scan */
	
	for(j = 0; j < height; j++)
	  for(i = 0; i < width; i++)
		if(vert_flag_blk[j * width + i] != 0) {
		  vert_blk[j * width + i] = (int)(vert_blk[j * width + i]/(double) vert_flag_blk[j * width + i]);
		  vert_flag_blk[j * width + i]/= vert_flag_blk[j * width + i];
		}

	for(j = 0; j < height; j++)
	  for(i = 0; i < width; i++)
			if(hori_flag_blk[j * width + i] == 1 && vert_flag_blk[j * width + i] == 1)
				curr_blk[j * width + i] = (int)((hori_blk[j * width + i] + vert_blk[j * width + i])/2.0);
			else if (hori_flag_blk[j * width + i] == 1)
				curr_blk[j * width + i] = hori_blk[j * width + i];
			else if (vert_flag_blk[j * width + i] == 1)
				curr_blk[j * width + i] = vert_blk[j * width + i];


	flag_cnt = width * height;
	for(j = 0; j < height; j++)
	  for(i = 0; i < width; i++)
			if(hori_flag_blk[j * width + i] == 1 || vert_flag_blk[j * width + i] == 1){
				flag_blk[j * width + i] = 1;
			  flag_cnt--;
			}

  }/* end of while() */
  
  for(j = 0; j < height; j++)
	for(i = 0; i < width; i++)
	  curr[j * width + i] = (unsigned char) curr_blk[j * width + i];

  free(flag_blk);
  free(mask_blk);
  free(curr_blk);
  free(hori_blk);
  free(vert_blk);
  free(hori_flag_blk);
  free(vert_flag_blk);
}
/* 4/19 changed by SHARP for debug */
/***********************************************************CommentBegin******
 *
 * -- CheckMBType
 *
 ***********************************************************CommentEnd********/
Void
CheckMBType(Vop *curr_vop,
	    Vop *pre_vop,
	    Int frame, Int layer_type)
{
  SInt *curr_shape_mode, *pre_shape_mode;
  Int  curr_w, curr_h,   pre_w, pre_h;
  
  if(layer_type == 0){
    fprintf(stderr,"BASE   ");
    fprintf(stdout,"BASE   ");
  }
  else{
    fprintf(stderr,"ENHANCE");
    fprintf(stdout,"ENHANCE");
  }
  fprintf(stderr,"[%d]",frame);
  fprintf(stdout,"[%d]",frame);
  
  if(pre_vop != NULL){
    fprintf(stderr,"\n======================\nPRE_");
    fprintf(stdout,"\n======================\nPRE_");
    pre_shape_mode = (SInt *)GetImageData(GetVopShapeMode(pre_vop));
    pre_w          = GetImageSizeX(GetVopShapeMode(pre_vop));
    pre_h          = GetImageSizeY(GetVopShapeMode(pre_vop));
    Print_type(pre_shape_mode,pre_h, pre_w);
    fprintf(stderr,"\n======================\n");
    fprintf(stdout,"\n======================\n");
  }
  if(curr_vop != NULL){
    fprintf(stderr,"\n======================\ncurr_");
    fprintf(stdout,"\n======================\ncurr_");
    curr_shape_mode = (SInt *)GetImageData(GetVopShapeMode(curr_vop));
    curr_w          = GetImageSizeX(GetVopShapeMode(curr_vop));
    curr_h          = GetImageSizeY(GetVopShapeMode(curr_vop));
    Print_type(curr_shape_mode,curr_h, curr_w);
  }
}

/***********************************************************CommentBegin******
 *
 * -- Print_type
 *
 ***********************************************************CommentEnd********/
Void
Print_type(SInt *curr_shape_mode, int curr_h, int curr_w)
{
  int i,j;
  fprintf(stderr,"MB_TYPE[%d,%d]\n======================",curr_w,curr_h);
  fprintf(stdout,"MB_TYPE[%d,%d]\n======================",curr_w,curr_h);

  for(j = 0; j < curr_h; j++) {
    for(i = 0; i < curr_w; i++) {
      if(i == 0){
        fprintf(stderr,"\n");
        fprintf(stdout,"\n");
      }
      fprintf(stderr,"%d",curr_shape_mode[i + j * curr_w]);
      fprintf(stdout,"%d",curr_shape_mode[i + j * curr_w]);
    }
  }
  fprintf(stderr,"\n");
  fprintf(stdout,"\n");
}
/* 4/19 changed by SHARP for debug */
