/* $Id: wavelet.c,v 1.5 1998/03/12 23:22:11 shipeng Exp $ */
/****************************************************************************/
/*   MPEG4 Visual Texture Coding (VTC) Mode Software                        */
/*                                                                          */
/*   This software was developed by                                         */
/*   Sarnoff Coporation                   and    Texas Instruments          */
/*   Iraj Sodagar   (iraj@sarnoff.com)           Jie Liang (liang@ti.com)   */
/*   Hung-Ju Lee    (hjlee@sarnoff.com)                                     */
/*   Paul Hatrack   (hatrack@sarnoff.com)                                   */
/*   Shipeng Li     (shipeng@sarnoff.com)                                   */
/*   Bing-Bing Chai (bchai@sarnoff.com)                                     */
/*                                                                          */
/* In the course of development of the MPEG-4 standard. This software       */
/* module is an implementation of a part of one or more MPEG-4 tools as     */
/* specified by the MPEG-4 standard.                                        */
/*                                                                          */
/* The copyright of this software belongs to ISO/IEC. ISO/IEC gives use     */
/* of the MPEG-4 standard free license to use this  software module or      */
/* modifications thereof for hardware or software products claiming         */
/* conformance to the MPEG-4 standard.                                      */
/*                                                                          */
/* Those intending to use this software module in hardware or software      */
/* products are advised that use may infringe existing  patents. The        */
/* original developers of this software module and their companies, the     */
/* subsequent editors and their companies, and ISO/IEC have no liability    */
/* and ISO/IEC have no liability for use of this software module or         */
/* modification thereof in an implementation.                               */
/*                                                                          */
/* Permission is granted to MPEG memebers to use, copy, modify,             */
/* and distribute the software modules ( or portions thereof )              */
/* for standardization activity within ISO/IEC JTC1/SC29/WG11.              */
/*                                                                          */
/* Copyright (C) 1998  Sarnoff Coporation and Texas Instruments             */ 
/****************************************************************************/

/************************************************************/
/*     Sarnoff Very Low Bit Rate Still Image Coder          */
/*     Copyright 1995, 1996, 1997, 1998 Sarnoff Corporation */
/************************************************************/

/****************************************************************************/
/*     Texas Instruments Predictive Embedded Zerotree (PEZW) Image Codec    */
/*     Copyright 1996, 1997, 1998 Texas Instruments	      		    */
/****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "dataStruct.h"

#include "globals.h"

#include "dwt.h"
#include "default.h"
#include "download_filter.h"
#include "errorHandler.h"
#include "main.h"
#include "wavelet.h"
#include "write_image.h"
#include "computePSNR.h"
#include "ShapeCodec.h"

extern Int decoder;
/*-----------------------------------------------------------------------*/
/********************************************************************/
/* Select a wavelet filter banks from the ones defined in default.h */
/* There are currently 10 filter banks available                    */
/********************************************************************/
Void choose_wavelet_filter(FILTER **anafilter,FILTER **synfilter,
			   Int type)
{
  switch(type){
    case 0:  /* default int filter, odd symmetric */
      *anafilter=&DefaultAnalysisFilterInt;
      *synfilter=&DefaultSynthesisFilterInt;
      return;
    case 1: /* default double filter, odd symmetric */
      *anafilter=&DefaultAnalysisFilterDbl;
      *synfilter=&DefaultSynthesisFilterDbl;
      return;
    case 2:  
      *anafilter=&DefaultEvenAnalysisFilterInt;
      *synfilter=&DefaultEvenSynthesisFilterInt;
      return;
    case 3:
      *anafilter=&DefaultEvenAnalysisFilterDbl;
      *synfilter=&DefaultEvenSynthesisFilterDbl;
      return;
     case 4:
      *anafilter=&HaarAna;
      *synfilter=&HaarSyn;
      return;
    case 5:
      *anafilter=&qmf9Ana;
      *synfilter=&qmf9Syn;
      return;
    case 6:
      *anafilter=&qmf9aAna;
      *synfilter=&qmf9aSyn;
      return;
    case 7:
      *anafilter=&fpr53Ana;
      *synfilter=&fpr53Syn;
      return;
    case 8:
      *anafilter=&fpr53aAna;
      *synfilter=&fpr53aSyn;
      return;
    case 9:
      *anafilter=&asd93Ana;
      *synfilter=&asd93Syn;
      return;
    default:
      errorHandler("Filter type %d is not available.",type);
  }
}

/*-----------------------------------------------------------------------*/
Void perform_DWT(FILTER *wvtfilter)
{
  Int col,j,k,x,y;
  UChar *inimage[3];
  UChar *inmask[3], *outmask[3];
  DATA *outcoeff[3];
  Int Nx[3], Ny[3];
  Int width[3], height[3];
  Int useint=1, usemask=0;
  Int nLevels[3], ret;

  /* for 4:2:0 YUV image only */
  Nx[0] = Ny[0]=2;
  for(col=1; col<mzte_codec.colors; col++) Nx[col]=Ny[col]=1;


  nLevels[0] = mzte_codec.wvtDecompLev ;
  nLevels[1] = nLevels[2] = nLevels[0]-1;
  width[0] = mzte_codec.width;
  width[1] = width[2] = (width[0] >> 1);
  height[0] = mzte_codec.height;
  height[1] = height[2] = (height[0] >> 1);

  useint  = 1;
  usemask = mzte_codec.sa_dwt;

  
  Nx[0] = Ny[0]= 2;
  for(col=1;col<3;col++)
    Nx[col]=Ny[col]=1;
  
  for (col=0; col<mzte_codec.colors; col++) {

    inimage[col] = (UChar *)mzte_codec.Image[col].data;
    inmask[col] = mzte_codec.Image[col].mask;
    
    if ((outcoeff[col] = 
      (DATA *)malloc(sizeof(DATA)*width[col]*height[col]))==NULL)
      errorHandler("Memory error: outcoeff\n");
    if ((outmask[col] = 
      (UChar *)malloc(sizeof(Char)*width[col]*height[col]))==NULL)
      errorHandler("Memory error: outmask\n");

    ret = do_DWT(inimage[col], inmask[col], width[col], height[col], 
		 nLevels[col], 0,wvtfilter, outcoeff[col], outmask[col]);
    
    if (ret!=DWT_OK) 
      errorHandler("DWT Error Code %d\n", ret);
    
    mzte_codec.mean[col] = RemoveDCMean(outcoeff[col], outmask[col], 
					width[col], height[col], nLevels[col]);
    
    for (j=0; j<width[col]*height[col]; j++)
      if (outmask[col][j] != IN)
	outcoeff[col][j]=0;
    
    for (k=0, y = 0; y < height[col]; ++y)
      for (x = 0; x < width[col]; ++x,++k) {
	COEFF_ORGVAL(x,y,col) = outcoeff[col][k];
	COEFF_MASK(x,y,col) = outmask[col][k];
      }
  }
  
  for (col=0; col<mzte_codec.colors; col++) {
    if (outmask[col]) free(outmask[col]);
    if (outcoeff[col]) free(outcoeff[col]);
  }
}

Void perform_layer_IDWT(Int spa_lev, Int snr_lev, Int usemask, Int colors,
			Int wvtDecompLev,  FILTER *wvtfilter, Int fullsize,
			Char *recImgFile)
{
  Int j,k,x,y,col;
  UChar *outimage[3];
  UChar *inmask[3], *outmask[3];
  DATA *incoeff[3];
  Int Mean[3];
  Int Nx[3], Ny[3];
  Int Width[3], Height[3];
  Int useint=1;
  Int nLevels[3], destLevel[3], ret;

  Width[0] = mzte_codec.width;
  Width[1] = Width[2] = (Width[0]+1)>>1;

  Height[0] = mzte_codec.height;
  Height[1] = Height[2] = (Height[0]+1)>>1;

   
  nLevels[0] = wvtDecompLev ;
  nLevels[1] = nLevels[2] = nLevels[0]-1;

  destLevel[0] = /* mzte_codec.wvtDecompLev -  */
                 mzte_codec.spatial_scalability_levels - 1 - spa_lev;
  destLevel[1] = destLevel[2] = destLevel[0];

  Mean[0] = mzte_codec.mean[0];
  Mean[1] = mzte_codec.mean[1];
  Mean[2] = mzte_codec.mean[2];

  useint  = 1;

  Nx[0] = Ny[0]= 2;
  for(col=1;col<colors;col++)
    Nx[col]=Ny[col]=1;


  for (col=0; col<colors; col++) {

    if ((inmask[col]=(UChar *)malloc(sizeof(UChar)*
					     Width[col]*Height[col]))==NULL)
      errorHandler("Memory Failed\n");
    
    if ((incoeff[col] = (DATA *)malloc(sizeof(DATA)*
				  Width[col]*Height[col]))==NULL)
      errorHandler("Memory Failed\n");
    
    /* copy dequantized coefficients to incoeff */
    for (k=0, y=0; y<Height[col]; y++) 
      for (x=0; x<Width[col]; x++,k++) {
	incoeff[col][k] = COEFF_RECVAL(x,y,col);
	inmask[col][k]  = COEFF_MASK(x,y,col);
      }
    for (j=0; j<Width[col]*Height[col];j++) 
      if (inmask[col][j]!=IN) 
	incoeff[col][j]=0;
    
    AddDCMean(incoeff[col], inmask[col], 
	      Width[col], Height[col], 
	      nLevels[col], Mean[col]);
    
    
    if ((outmask[col]  = (UChar *)malloc(sizeof(UChar)*
					    Width[col]*Height[col]))==NULL)
      errorHandler("Memory Failed\n");

    if ((outimage[col] = (UChar *)malloc(sizeof(UChar)*
					    Width[col]*Height[col]))== NULL)

      errorHandler("Memory Failed\n");

    
    ret = do_iDWT(incoeff[col], inmask[col], Width[col], Height[col], 
		  nLevels[col], destLevel[col], 0 /* byte */, 
		  wvtfilter, outimage[col], outmask[col], 0, fullsize);
    if (ret!=DWT_OK) 
      errorHandler("DWT Error Code %d\n", ret);

  }  /* col */



  /*--- Write out layer image and PSNR ---*/
  {
    Char layer_recImgFile[200];
    
    if (decoder==0)
      sprintf(layer_recImgFile,"encRec_%02d_%02d.yuv",spa_lev,snr_lev);
    else
      sprintf(layer_recImgFile,"decRec_%02d_%02d.yuv",spa_lev,snr_lev);

    WriteImage(layer_recImgFile, mzte_codec.colors,
		mzte_codec.width, mzte_codec.height,
		mzte_codec.real_width, mzte_codec.real_height,
		mzte_codec.origin_x, mzte_codec.origin_y,
		outimage, outmask,
		usemask, fullsize, destLevel[0]);
    
    if (decoder==0) {
      /* compute PSNR */
      if (colors==1)
	ComputePSNR(mzte_codec.Image[0].data, outimage[0], outmask[0],
		    NULL, NULL, NULL,
		    NULL, NULL, NULL,
		    mzte_codec.width, mzte_codec.height, 1);
      else
	ComputePSNR(mzte_codec.Image[0].data, outimage[0], outmask[0],
		    mzte_codec.Image[1].data, outimage[1], outmask[1],
		    mzte_codec.Image[2].data, outimage[2], outmask[2],
		    mzte_codec.width, mzte_codec.height, 1);
      
    }

  }
  
  for (col=0; col<colors; col++) {
    if (incoeff[col]) free(incoeff[col]);
    if (inmask[col]) free(inmask[col]);
    if (outmask[col]) free(outmask[col]);
    if (outimage[col]) free(outimage[col]);
  }
}

/*------------------------------------------------*/
Void perform_IDWT(SOL_PARAMETERS_DEC *vm_param, FILTER *wvtfilter,
		  Char *recImgFile)
{
  Int j,k,x,y,col;
  UChar *outimage[3];
  UChar *inmask[3], *outmask[3];
  DATA *incoeff[3];
  Int Mean[3];
  Int Nx[3], Ny[3];
  Int Width[3], Height[3];
  Int useint=1, usemask=0;
  Int nLevels[3], ret, MinLevel=0;

  Int fullsize = 0;
 
  fullsize = FULLSIZE;
  Width[0] = mzte_codec.width;
  Width[1] = Width[2] = (Width[0]+1)>>1;

  Height[0] = mzte_codec.height;
  Height[1] = Height[2] = (Height[0]+1)>>1;

  nLevels[0] = mzte_codec.wvtDecompLev ;
  nLevels[1] = nLevels[2] = nLevels[0]-1;

  Mean[0] = mzte_codec.mean[0];
  Mean[1] = mzte_codec.mean[1];
  Mean[2] = mzte_codec.mean[2];

  useint  = 1;
  usemask = mzte_codec.sa_dwt;

  Nx[0] = Ny[0]= 2;
  for(col=1;col<mzte_codec.colors;col++)
    Nx[col]=Ny[col]=1;


  for (col=0; col<mzte_codec.colors; col++) {

    if ((inmask[col]=(UChar *)malloc(sizeof(UChar)*
					     Width[col]*Height[col]))==NULL)
      errorHandler("Memory Failed\n");
    
    if ((incoeff[col] = (DATA *)malloc(sizeof(DATA)*
				  Width[col]*Height[col]))==NULL)
      errorHandler("Memory Failed\n");

    
    /* copy dequantized coefficients to incoeff */
    for (k=0, y=0; y<Height[col]; y++) 
      for (x=0; x<Width[col]; x++,k++) {
	incoeff[col][k] = COEFF_RECVAL(x,y,col);
	inmask[col][k]  = COEFF_MASK(x,y,col);
      }
    for (j=0; j<Width[col]*Height[col];j++) 
      if (inmask[col][j]!=IN) 
	incoeff[col][j]=0;
    
    AddDCMean(incoeff[col], inmask[col], 
	      Width[col], Height[col], 
	      nLevels[col], Mean[col]);
    
    
    if ((outmask[col]  = (UChar *)malloc(sizeof(UChar)*
					    Width[col]*Height[col]))==NULL)
      errorHandler("Memory Failed\n");

    if ((outimage[col] = (UChar *)malloc(sizeof(UChar)*
					    Width[col]*Height[col]))==NULL)
      errorHandler("Memory Failed\n");

    
#if  PROGRESSIVE
    MinLevel = (nLevels[0] > nLevels[1])? nLevels[1]:nLevels[0];
    MinLevel = (MinLevel > nLevels[2])? nLevels[2]: MinLevel;
#else /*PROGRESSIVE*/
    MinLevel = mzte_codec.spatial_scalability_levels -
      mzte_codec.target_spatial_levels;
#endif /*PROGRESSIVE*/
    
    ret = do_iDWT(incoeff[col], inmask[col], Width[col], Height[col], 
		  nLevels[col], MinLevel, 0 /* byte */, 
		  wvtfilter, outimage[col], outmask[col], 0,  fullsize );
    if (ret!=DWT_OK) 
      errorHandler("DWT Error Code %d\n", ret);
    free(incoeff[col]);
    free(inmask[col]);
  }  /* col */
  
  WriteImage(recImgFile, mzte_codec.colors,
	      mzte_codec.width, mzte_codec.height,
	      mzte_codec.real_width, mzte_codec.real_height,
	      mzte_codec.origin_x, mzte_codec.origin_y,
	      outimage,outmask,
	      usemask,  fullsize, MinLevel);

  if (decoder==0) {
    /* compute PSNR */
    if (mzte_codec.colors == 1)
      ComputePSNR(mzte_codec.Image[0].data, outimage[0], outmask[0],
		  NULL, NULL, NULL,
		  NULL, NULL, NULL,
		  mzte_codec.width, mzte_codec.height, 0);
    else
      ComputePSNR(mzte_codec.Image[0].data, outimage[0], outmask[0],
		  mzte_codec.Image[1].data, outimage[1], outmask[1],
		  mzte_codec.Image[2].data, outimage[2], outmask[2],
		  mzte_codec.width, mzte_codec.height, 0);
  }
  
  for(col=0; col< mzte_codec.colors; col++) {
    free(outmask[col]);
    free(outimage[col]);
  }
}

