/*****************************************************************************
 *
 * This software module was originally developed by
 *
 *   Noel Brady (TELTEC IRELAND / 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:	alp_common_cae.c
 *
 * Author:	Noel Brady Teltec Irl.
 * Created:	11-04-97
 *                                                                         
 * Description: Contains functions used to implement block-based CAE
 *								coding and decoding.
 *
 *
 *                                 
 ***********************************************************HeaderEnd*********/

#include <math.h>
#include "momusys.h"
#include "mom_structs.h"
#include "mom_image.h"
#include "mom_vop.h"
#include "alp_common_cae.h"

#define MB_SIZE 16

/***********************************************************CommentBegin******
 *
 * -- GetBorderedMC -- Extracts the subsampled border of the 
 *														MC binary alpha block.
 *
 * Author :		
 *	Noel Brady Teltec Irl.
 *
 * Created :		
 *	11-04-97
 * 
 * Arguments: 	
 *		prev_alpha 		: previously reconstructed binary alpha plane
 *    x0,y0 				: address of macroblock in pixels
 *		mvx,mvy				: motion vector offset with differential spatial ref.
 *		N							: subsampling factor =1,2, or 4.
 *		alpha_smb_mc  :	the border of the MB binary alpha block
 *
 * Return values :	
 *
 * Side effects :	
 *	-
 *
 * Description : Extracts data from the previously reconstucted alpha map
 *								under simple MV displacement. This data corresponds to the
 *								border pixels surrounding the MB binary alpha block.
 *								Subsampling of the border pixels is performed if appropriate.
 *
 * See also :
 *
 ***********************************************************CommentEnd********/

Void GetBorderedMC(Image *prev_alpha,
									Int x0,
									Int y0,
									Int mvx,
									Int mvy,
									Int N,
									Image *alpha_smb_mc)
{
	Image *mc_block = AllocImage(MB_SIZE+4,MB_SIZE+4,SHORT_TYPE),
				*temp_image,
				*temp_simage;

	SInt *p_in, *p_out, *p_ins;

	Int sx_in = GetImageSizeX(prev_alpha),
			sy_in = GetImageSizeY(prev_alpha);

	Int x,y,k,
			xx,yy,
			tmp;

	p_out = (SInt *) GetImageData(mc_block);
	p_in = (SInt *)GetImageData(prev_alpha);

	for (y=0;y<MB_SIZE+4;y++)
		for (x=0;x<MB_SIZE+4;x++)
			if ((x<=1) || (y<=1) || (x>=MB_SIZE+2) || (y>=MB_SIZE+2))
				{
					xx = mvx + x0 + x - 2;
					yy = mvy + y0 + y - 2;
					if ((xx>=0) && (yy>=0) && (xx<sx_in) && (yy<sy_in))
						{
							p_out[y*(MB_SIZE+4)+x] = (p_in[(yy)*sx_in+xx]>0);
						}
				}

		
	if (N != 1)
		{
	
			temp_image = AllocImage(MB_SIZE+4,2,SHORT_TYPE);
			temp_simage = AllocImage(MB_SIZE/N+4,2,SHORT_TYPE);
	
			GetSubImage(mc_block,temp_image,0,0);		/* top border */
			p_out = (SInt *) GetImageData(temp_simage);
			p_in = (SInt *) GetImageData(temp_image);

			for (y=0;y<2;y++) 
				{
					*p_out = *p_in; p_in++; p_out++;
					*p_out = *p_in; p_in++; p_out++;
					for (x=0;x<MB_SIZE/N;x++,p_out++)
						{
							tmp = 0;
							for (k=0;k<N;k++,p_in++) tmp += (*p_in > 0);
							*p_out = (tmp+N/2)/N;
						}
					*p_out = *p_in; p_in++; p_out++;
					*p_out = *p_in; p_in++; p_out++;
				}
			PutSubImage(alpha_smb_mc,temp_simage,0,0);
			
			GetSubImage(mc_block,temp_image,0,MB_SIZE+2);		/* bottom border */
			p_out = (SInt *) GetImageData(temp_simage);
			p_in = (SInt *) GetImageData(temp_image);

			for (y=0;y<2;y++) 
				{
					*p_out = *p_in; p_in++; p_out++;
					*p_out = *p_in; p_in++; p_out++;
					for (x=0;x<MB_SIZE/N;x++,p_out++)
						{
							tmp = 0;
							for (k=0;k<N;k++,p_in++) tmp += (*p_in > 0);
							*p_out = (tmp+N/2)/N;
						}
					*p_out = *p_in; p_in++; p_out++;
					*p_out = *p_in; p_in++; p_out++;
				}
			PutSubImage(alpha_smb_mc,temp_simage,0,MB_SIZE/N+2);

			FreeImage(temp_image);
			FreeImage(temp_simage);

			temp_image = AllocImage(2,MB_SIZE,SHORT_TYPE);
			temp_simage = AllocImage(2,MB_SIZE/N,SHORT_TYPE);
	
			GetSubImage(mc_block,temp_image,0,2);		/* left border */
			p_out = (SInt *) GetImageData(temp_simage);
			p_ins = (SInt *) GetImageData(temp_image);

			for (y=0;y<MB_SIZE/N;y++,p_ins+=N*2)
				{
					for (x=0;x<2;x++,p_out++)
						{
							p_in = p_ins+x;
							tmp = 0;
							for (k=0;k<N;k++,p_in+=2) tmp += (*p_in > 0);
							*p_out = (tmp+N/2)/N;
						}
				}
			PutSubImage(alpha_smb_mc,temp_simage,0,2);
			
			GetSubImage(mc_block,temp_image,MB_SIZE+2,2);		/* right border */
			p_out = (SInt *) GetImageData(temp_simage);
			p_ins = (SInt *) GetImageData(temp_image);

			for (y=0;y<MB_SIZE/N;y++,p_ins+=N*2)
				{
					for (x=0;x<2;x++,p_out++)
						{
							p_in = p_ins+x;
							tmp = 0;
							for (k=0;k<N;k++,p_in+=2) tmp += (*p_in > 0);
							*p_out = (tmp+N/2)/N;
						}
				}
			PutSubImage(alpha_smb_mc,temp_simage,MB_SIZE/N+2,2);

			FreeImage(temp_image);
			FreeImage(temp_simage);
		}
	else CopyImage(mc_block,alpha_smb_mc);
					
	FreeImage(mc_block);
}


/* Subsampling of the top-side border of the current binary alpha block */

Image *TopBorderDecimate(Image *top_border, Int N)
{
	Image 	*top_sborder=AllocImage(4+MB_SIZE/N,2,SHORT_TYPE);

	SInt 	*p_in,*p_out;

	Int i,j,k,tmp;

	p_in = (SInt *) GetImageData(top_border);
	p_out = (SInt *) GetImageData(top_sborder);

	for (j=0;j<2;j++) 
		{
			*p_out = (*p_in>0); p_in++, p_out++;
			*p_out = (*p_in>0); p_in++, p_out++;
		
			for (i=0;i<16/N;i++,p_out++) 
				{
 					tmp = 0;
  				for (k=0;k<N;k++,p_in++) tmp += ((*p_in)!=0);
  				*(p_out) = (tmp + N/2)/N;
 				}
			*p_out = (*p_in>0); p_in++, p_out++;
			*p_out = (*p_in>0); p_in++, p_out++;
		}

	return top_sborder;
}	


/* subsampling of the left-side border of the current binary alpha block */

Image *LeftBorderDecimate(Image *left_border, Int N)
{
	Image 	*left_sborder=AllocImage(2,MB_SIZE/N,SHORT_TYPE);

	SInt 	*p_in,*p_out;

	Int i,j,k,tmp;

	p_in = (SInt *) GetImageData(left_border);
	p_out = (SInt *) GetImageData(left_sborder);

	for (j=0;j<2;j++) 
		{

			p_in = (SInt *) GetImageData(left_border) + j;
			p_out = (SInt *) GetImageData(left_sborder) + j;
		
			for (i=0;i<16/N;i++,p_out+=2) 
				{
 					tmp = 0;
  				for (k=0;k<N;k++,p_in+=2) tmp += ((*p_in)!=0);
  				*(p_out) = (tmp + N/2)/N;
 				}
		}

	return left_sborder;
}	

Void TransposeImage(Image *im_in, Image *im_out)
{
	Int x,y;

	Int 	size_x = GetImageSizeX(im_in),
				size_y = GetImageSizeY(im_in);

	SInt 	*p_out = (SInt *) GetImageData(im_out),
				*p_in;

	for (y=0;y<size_y;y++)
		{
			p_in = (SInt *) GetImageData(im_in) + y;

			for (x=0;x<size_x;x++,p_out++,p_in+=size_x) *p_out = *p_in;
		}
}

Void BinariseImage(Image *im_in)
{
	Int 	size_x = GetImageSizeX(im_in),
				size_y = GetImageSizeY(im_in);

	SInt 	*p_in = (SInt *) GetImageData(im_in),
				*pe = p_in + size_x*size_y;

	do 
		{
			*p_in = ((*p_in)!=0);
			p_in++;
		} 
	while (p_in < pe);
}

/* Computes a 10-bit INTRA context */

Int GetContextIntra(SInt* pim, Int x, Int y, Int last_col, 
															Int first_row, Int width) 
{
  Int t = 0;
	SInt *p = pim + (y-2) * width + x-1;

	t <<= 1;
  t |= *p;p++;				/* c9 */
	t <<= 1;
  t |= *p;p++;						/* c8 */

	t <<= 1;
	if ((y>first_row+1) && (x==last_col)) 
		{
		  t |= (t>>1) & 1;						/* c8 */
		}
  else 
		{
			t |= *p;			/* c7 */
		}
	p+=width-3;
		

	t <<= 1;
  t |= *p;p++;				/* c6 */
  t <<= 1;
  t |= *p;p++;				/* c5 */
  t <<= 1;
  t |= *p;p++;				/* c4 */

  t <<= 1;
	if ((y>first_row) && (x==last_col)) 
		{
		  t |= (t>>1) & 1;						/* c4 */
		}
	else t |= *p;
	p++;												/* c3 */

	t <<= 1;
	if ((y>first_row) && (x>=last_col-1)) 
		{
		  t |= (t>>1) & 1;						/* c3 */
		}
	else t |= *p;
	p+=width-4;												/* c2 */

  t <<= 1;
  t |= *p;p++;				/* c1 */
  t <<= 1;
  t |= *p;				/* c0 */

  return t;
}


/* Computes the 9-bit INTER context */

Int GetContextInter(SInt *pim, SInt *pmc_im, Int x, Int y, Int last_col
													, Int first_row, Int width) 
{
  Int t = 0;
	Int xx = x,
			yy = y;

	SInt *p = pmc_im + (yy-1)*width + xx;

	t <<= 1;
  t |= *p;			/* c8 */
	p += (width-1);

	t <<= 1;
  t |= *p;			/* c7 */
	p++;

	t <<= 1;
  t |= *p;			/* c6 */
	p++;

	t <<= 1;
  t |= *p;			/* c5 */
	p += (width-1);


	t <<= 1;
  t |= *p;					/* c4 */


	p = pim + (y-1)*width + (x-1);

	t <<= 1;
  t |= *p;					/* c3 */
	p++;

  t <<= 1;
  t |= *p;						/* c2 */
	p++;

  t <<= 1;
	if (x==last_col && y>first_row) 
  	t |= (t>>1) & 1;						/* c2 */
	else t |= *p;					/* c1 */
	p += width-2;

  t <<= 1;
  t |= *p;						/* c0 */

  return t;
}



