/******************************************************************************
 *
 * This software module was originally developed by
 *
 *   J.Ignacio Ronda (UPM-GTI / ACTS-MoMuSys)
 *   Angel Pacheco (UPM-GTI / ACTS-MoMuSys)
 *   Fernando Jaureguizar (UPM-GTI / ACTS-MoMuSys)
 *
 * and edited by
 *
 *   Angel Pacheco (UPM-GTI / ACTS-MoMuSys)
 *   Fernando Jaureguizar (UPM-GTI / ACTS-MoMuSys)
 *   Robert Danielsen (Telenor / ACTS-MoMuSys)
 *   Ferran Marques (UPC / ACTS-MoMuSys)
 *   Minhua Zhou (HHI / ACTS-MoMuSys)
 *   C.S. Boon (Matsushita Corporation)
 *   J. Takahashi
 *
 * 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:        mot_padding.c
 *
 * Authors:     UPM - J.Ignacio Ronda / Angel Pacheco
 * Created:     02.02.96
 *
 * Description: Repetitive padding for vops (Y/YUV images) and separate images
 *
 * Flags:       -D_DEBUG_        :  debugging messages are printed
 *              -D_NO_PADDING_   :  no padding is performed
 *              -D_NO_TEXTURE_PADDING_ : TexturePadding() is not carried out
 *
 * Modified:
 *      version 1.1: Angel Pacheco: changes in the interface to allow
 *               one Vop as input, and to develop the padding over YUV values
 *               or only over Y, depending on the lumi field
 *                 lumi==1 only pad Y field
 *                 lumi!=1 pad YUV fields
 *      version 1.2: Angel Pacheco: fixes a bug that produces
 *               incorrect accesses in *_FinalVerticalPadding
 *      version 1.2.1: Angel Pacheco (UPM-GTI): bypassed a bug that produces
 *               incorrect padding if the shape is one pixel width and is
 *               touching the right side.
 *               THIS WILL BE FIXED IN THE NEXT VERSION (coming soon)
 *      21.04.96 Robert Danielsen: Reformatted. New headers.
 *      version 2.0: Angel Pacheco: fixed the bug bypassed of
 *               version 1.2.1 and modified the alpha plane subsampling for
 *               the chrominaces, acording to the VM2.x
 *      30.08.96 Angel Pacheco & Fernando Jaureguizar:
 *               Padding modification to perform TexturePadding as required
 *               for VM3.0.
 *      22.10.96 Angel Pacheco: New MB-based padding scheme as
 *               VM 4.0 describes.
 *      28.11.96 Ferran Marques: introduces changes of (22.10.96)
 *      05.02.97 Angel Pacheco: modified to include the new low
 *               pass extrapolation padding technique of the VM5.1
 *      05.02.97 Angel Pacheco: modified to fill the pixels
 *               acording the original (=!reconstructed) alpha values (VM5.1)
 *      17.04.97 Minhua Zhou: added vm_compos.h, modified
 *               MacroblockBasedPadding.
 *      09.04.97 MInhua Zhou: rewrote MacroblockBasedImagePadding
 *      09.04.97 Minhua Zhou: modified BlockRepetitivePadding
 *      26.05.97 Minhua Zhou: removed DoAlphaAndStatusPlanes(),
 *               Removed DoAlphaUVPlane(), added VopPadding().
 *      16.06.97 Angel Pacheco: renaming the B_* modes by MBM_ modes.
 *               default initialization of some variables to avoid warnings.
 *      13.11.97 Angel Pacheco: formating and new header.
 *      09.03.98 Fernando Jaureguizar: New formating. Deleted some not used
 *               variables and parameters.
 *      10.03.98 Fernando Jaureguizar: Deleted not used routines
 *               MacroblockBasedImagePadding(), BlockDefaultImagePadding()
 *               BlockRepetitiveImagePadding(), BlockImagePadding()
 *
 ***********************************************************HeaderEnd*********/

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

#include "mot_padding.h"
#include "mot_util.h"
#include "mot_est.h"
#include "vm_compos.h"
#include "mom_image.h"

#ifdef _DEBUG_
#define INDEX(h,v,hdim,vdim)   ( (((h)<(hdim))&&((v)<(vdim)))? \
   ((h)+(v)*(hdim)) : fprintf(stderr,"out of bounds: (i,j,k) (%d,%d,%d); \
   (%d,%d)>(%d,%d)\n",(int)i,(int)j,(int)k,(int)h,(int)v,(int)hdim,(int)vdim) )
#else
#define INDEX(h,v,hdim,vdim)   ( (h)+(v)*(hdim) )
#endif

/***********************************************************CommentBegin******
 *
 * -- Y_HorizontalPadding -- Horizontal padding of the Y data
 *
 * Author :
 *      UPM-GTI - Angel Pacheco
 *
 * Created :
 *      02.02.96
 *
 * Purpose :
 *      Horizontal padding of the Y data
 *
 * Arguments in :
 *      SInt   *alpha_plane,    alpha plane data
 *      Int    w,               alpha width
 *      Int    h,               alpha height
 *
 * Arguments in/out :
 *      SInt   *status_plane,   status plane data
 *      SInt   *y_plane         Y plane data
 *
 * Arguments out :
 *
 *
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
Y_HorizontalPadding (
   SInt   *alpha_plane,  /* <-- alpha plane data  */
   Int    w,             /* <-- alpha width       */
   Int    h,             /* <-- alpha height      */
   SInt   *status_plane, /* --> status plane data */
   SInt   *y_plane       /* --> Y plane data      */
   )
{
  Int    i, j;
  Int    k=0;
  Int    status;
  Int    previous;
  SInt   value;

  i=0;
  while(i<h)
    {
    j=previous=0;

    status=(alpha_plane[INDEX(j,i,w,h)]!=0) ? INSIDE : FIRST_PAD;
    if(status==INSIDE)
      status_plane[INDEX(j,i,w,h)]=INSIDE;

    j++;
    while(j<w)
      {
      if(alpha_plane[INDEX(j,i,w,h)]!=0)
        {
        if(status==FIRST_PAD)
          {
          value=y_plane[INDEX(j,i,w,h)];
          for(k=0;k<j;k++)
            {
            y_plane[INDEX(k,i,w,h)]=value;
            status_plane[INDEX(k,i,w,h)]=HOR_PAD;
            }
          status=INSIDE;
          status_plane[INDEX(j,i,w,h)]=INSIDE;
          }
        else if (status==MIDDLE_PAD)
          {
          value=((Int)y_plane[INDEX(previous,i,w,h)]+
                      (Int)y_plane[INDEX(j,i,w,h)]) >> 1;
          for(k=previous+1;k<j;k++)
            {
            y_plane[INDEX(k,i,w,h)] = value;
            status_plane[INDEX(k,i,w,h)]=HOR_PAD;
            }
          status_plane[INDEX(j,i,w,h)]=INSIDE;
          status=INSIDE;
          }
        else /* INSIDE */
          {
          status_plane[INDEX(j,i,w,h)]=INSIDE;
          }
        }
      else /* alpha_plane[INDEX(j,i,w,h)]==0 */
        {
        if(status==INSIDE)
          {
          status=MIDDLE_PAD;
          previous=j-1;
          }/* MIDDLE_PAD or FIRST_PAD do nothig */
        }
        j++;
      } /* while j */

    /* last part of the line */
    if(status==FIRST_PAD)
      {
      /* all line long */
      for(k=0;k<w;k++)
        {
        y_plane[INDEX(k,i,w,h)]=0;
        /* NO_PAD is the default for status_plane */
        }
      }
    else if(status==MIDDLE_PAD)
      {
      value=y_plane[INDEX(previous,i,w,h)];
      for(k=previous+1;k<w;k++)
        {
        y_plane[INDEX(k,i,w,h)]=value;
        status_plane[INDEX(k,i,w,h)]=HOR_PAD;
        }
      } /* if INSIDE, do nothing */
    i++;
  } /* while i */
}

/***********************************************************CommentBegin******
 *
 * -- Y_VerticalOverlapedPadding -- Vertical and overlapped padding
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / J. Ignacio Ronda
 *
 * Created :
 *      02.02.96
 *
 * Purpose :
 *      Vertical and overlapped (horizontal and vertical zones) padding of the
 *      Y data
 *
 * Arguments in :
 *      SInt   *alpha_plane,    original alpha plane
 *      Int    w,               original width  (Y or Alpha)
 *      Int    h,               original height (Y or Alpha)
 *
 * Arguments in/out :
 *      SInt   *status_plane,   status plane
 *      SInt   *y_plane         Y plane
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 *
 * Side effects :
 *
 *
 * Description :
 *      It would be possible to compute here the padding of the null (zero)
 *      values in the vertical direction
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
Y_VerticalOverlapedPadding (
   SInt   *alpha_plane,  /* <-- original alpha plane         */
   Int    w,             /* <-- original width  (Y or Alpha) */
   Int    h,             /* <-- original height (Y or Alpha) */
   SInt   *status_plane, /* --> status plane                 */
   SInt   *y_plane       /* --> y plane                      */
   )
{
  Int    i, j;
  Int    k=0;
  Int    status;
  Int    previous;
  SInt   value;

  j=0;
  while(j<w)
    {
    i=previous=0;

    status=(alpha_plane[INDEX(j,i,w,h)]!=0) ? INSIDE:FIRST_PAD;
    /* status_plane[j,i] is updated if INSIDE */

    i++;
    while(i<h)
      {
      if(alpha_plane[INDEX(j,i,w,h)]!=0)
        {
        if(status==FIRST_PAD)
          {
          value=y_plane[INDEX(j,i,w,h)];
          for(k=0;k<i;k++)
            {
            if(status_plane[INDEX(j,k,w,h)]==HOR_PAD)
              {
              y_plane[INDEX(j,k,w,h)]=((Int)y_plane[INDEX(j,k,w,h)]+
                                         (Int)value)>>1;
              }
            else
              {
              y_plane[INDEX(j,k,w,h)]=value;
              status_plane[INDEX(j,k,w,h)]=VER_PAD;
              }
            }
          status=INSIDE;
          }
        else if (status==MIDDLE_PAD)
          {
          value=((Int)y_plane[INDEX(j,previous,w,h)]+
                      (Int)y_plane[INDEX(j,i,w,h)]) >> 1;
          for(k=previous+1;k<i;k++)
            {
            if(status_plane[INDEX(j,k,w,h)]==HOR_PAD)
              {
              y_plane[INDEX(j,k,w,h)]=((Int)y_plane[INDEX(j,k,w,h)]+
                                              (Int)value)>>1;
              }
            else if (status_plane[INDEX(j,k,w,h)]==NO_PAD)
              {
              y_plane[INDEX(j,k,w,h)]=value;
              status_plane[INDEX(j,k,w,h)]=VER_PAD;
              } /*else is INSIDE, do nothing */
            }
          status=INSIDE;
          } /* INSIDE do nothing */
        }
      else /* alpha_plane[INDEX(j,i,w,h)]==0 */
        {
        if(status==INSIDE)
          {
          status=MIDDLE_PAD;
          previous=i-1;
          }/* MIDDLE_PAD or FIRST_PAD do nothig */
        }
      i++;
      } /* while i */

    /* last part of the column */
    if(status==MIDDLE_PAD)
      {
      value=y_plane[INDEX(j,previous,w,h)];
      for(k=previous+1;k<h;k++)
        {
        if(status_plane[INDEX(j,k,w,h)]==HOR_PAD)
          {
          y_plane[INDEX(j,k,w,h)]=((Int)y_plane[INDEX(j,k,w,h)]+
                                     (Int)value)>>1;
          }
        else if (status_plane[INDEX(j,k,w,h)]==NO_PAD)
          {
          y_plane[INDEX(j,k,w,h)]=value;
          status_plane[INDEX(j,k,w,h)]=VER_PAD;
          }/* else INSIDE no change in the y_value */
        }/*for*/
      } /* else if(status==FIRST_PAD) */
    /* here we could perform the vertical padding in this column, i.e.,
       the same process made inside the first while of the
       Y_FinalVerticalPadding() fuction. The process would be the filling
       of the empty regions corresponding to the zones padded in the
       last part of the padding process (only the vertical value, which
       will be used to padd the region with the mean between the nearest
       horizontal&vertical values */

    j++;
    } /* while j */
}

/***********************************************************CommentBegin******
 *
 * -- Y_FinalHorizontalPadding -- Final horizontal zero padding
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / J. Ignacio Ronda
 *
 * Created :
        02.02.96
 *
 * Purpose :
 *      Final zero padding in the horizontal direction of the Y data
 *
 * Arguments in :
 *      Int    w,               original width  (Y or Alpha)
 *      Int    h,               original height (Y or Alpha)
 *
 * Arguments in/out :
 *      SInt   *status_plane,   status plane
 *      SInt   *y_plane         Y plane
 *
 * Arguments out :
 *
 *
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *      It would be modified if VerticalOverlapedPadding() performs the
 *      vertical padding in the null (zero) values.
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
Y_FinalHorizontalPadding (
   Int    w,             /* <-- original width  (Y or Alpha) */
   Int    h,             /* <-- original height (Y or Alpha) */
   SInt   *status_plane, /* --> status plane                 */
   SInt   *y_plane       /* --> y plane                      */
   )
{
  Int    i, j;
  Int    k=0;
  Int    status;
  Int    previous;
  SInt   value;
  Int    middle;

  i=0;
  while(i<h)
    {
    j=previous=0;

    /* perhaps, the first part of the line */
    if((status_plane[INDEX(j,i,w,h)]==HOR_PAD)||
          (status_plane[INDEX(j,i,w,h)]==INSIDE))
      {
      i++;
      }
    else
      {
      if(status_plane[INDEX(j,i,w,h)]==NO_PAD)
        {
        /* first part of the line */

        j++;
        while(j<(w-1))
          {
          if(status_plane[INDEX(j,i,w,h)]==VER_PAD)
            {
            value=y_plane[INDEX(j,i,w,h)];
            for(k=0;k<j;k++)
              y_plane[INDEX(k,i,w,h)]=value;
            j++;
            break;
            }
          else
            j++;
          }
        }

      /* the inner parts */

      status=VER_PAD;
      while(j<(w-1))
        {
        if (status==VER_PAD)
          {
          j++;
          if ((status=status_plane[INDEX(j,i,w,h)])==NO_PAD)
            {
            previous=j-1;
            }
          }
        else /* NO_PAD */
          {
          j++;
          if ((status=status_plane[INDEX(j,i,w,h)])==VER_PAD)
            {
            /*from the begin to the middle */
            middle=(previous+j) >> 1;
            value=y_plane[INDEX(previous,i,w,h)];
            for(k=previous+1;k<middle;k++)
              y_plane[INDEX(k,i,w,h)]=value;
            /*from the middle to the end */
            value=y_plane[INDEX(j,i,w,h)];
            for(k=middle;k<j;k++)
              y_plane[INDEX(k,i,w,h)]=value;
            }
          }
        }   /* while j */

      /* the last part of the line */
      if(status==VER_PAD)
        {
        if(status_plane[INDEX(j,i,w,h)]==NO_PAD)
          {
          y_plane[INDEX(j,i,w,h)]=y_plane[INDEX(j-1,i,w,h)];
          }
        else if(status_plane[INDEX(j,i,w,h)]==VER_PAD)
          {
          /* the case of an empty line with a pixel object at the
             last column */
          value=y_plane[INDEX(j,i,w,h)];
          for(k=0;k<j;k++)
            y_plane[INDEX(k,i,w,h)]=value;
          }
       }
     else
       {
       if(status_plane[INDEX(j,i,w,h)]==NO_PAD)
         {
         value=y_plane[INDEX(previous,i,w,h)];
         for(k=previous+1;k<w;k++)
           y_plane[INDEX(k,i,w,h)]=value;
         }
       else
         {
         /*from the begin to the middle */
         middle=(previous+j) >> 1;
         value=y_plane[INDEX(previous,i,w,h)];
         for(k=previous+1;k<middle;k++)
           y_plane[INDEX(k,i,w,h)]=value;
         /*from the middle to the end */
         value=y_plane[INDEX(j,i,w,h)];
         for(k=middle;k<w;k++)
           y_plane[INDEX(k,i,w,h)]=value;
         }
       } /* else VER_PAD */

     i++;
     }
   } /* while i */
}

/***********************************************************CommentBegin******
 *
 * -- Y_FinalVerticalPadding -- Final zero padding in the vertical direction
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / J. Ignacio Ronda
 *
 * Created :
 *      02.02.96
 *
 * Purpose :
 *      Final zero padding in the vertical direction of the Y data
 *
 * Arguments in :
 *      Int    w,               original width  (Y or Alpha)
 *      Int    h,               original height (Y or Alpha)
 *
 * Arguments in/out :
 *      SInt   *status_plane,   status plane
 *      SInt   *y_plane         Y plane
 *
 * Arguments out :
 *
 *
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *      It would disapear if VerticalOverlapedPadding() performs the vertical
 *      zero padding (see the comment in the last part of the that function
 *      code)
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
Y_FinalVerticalPadding (
   Int    w,             /* <-- original width  (Y or Alpha) */
   Int    h,             /* <-- original height (Y or Alpha) */
   SInt   *status_plane, /* --> status plane                 */
   SInt   *y_plane       /* --> y plane                      */

   )
{
  Int    i, j;
  Int    k=0;
  Int    status;
  Int    previous;
  SInt   value;
  Int    middle;

  j=0;
  while(j<w)
    {
    i=previous=0;

    /* perhaps, the first part of the column */
    if((status_plane[INDEX(j,i,w,h)]==VER_PAD)||
          (status_plane[INDEX(j,i,w,h)]==INSIDE))
      {
      j++;
      }
    else
      {
      if(status_plane[INDEX(j,i,w,h)]==NO_PAD)
        {
        /* first part of the column */

        i++;
        while(i<(h-1))
          {
          if(status_plane[INDEX(j,i,w,h)]==HOR_PAD)
            {
            value=y_plane[INDEX(j,i,w,h)];
            for(k=0;k<i;k++)
              y_plane[INDEX(j,k,w,h)]=(y_plane[INDEX(j,k,w,h)]+value)>>1;
            i++;
            break;
            }
          else
            i++;
          }
        }

      /* the inner parts */
      status=HOR_PAD;
      while(i<(h-1))
        {
        i++;
        if (status==HOR_PAD)
          {
          if ((status=status_plane[INDEX(j,i,w,h)])==NO_PAD)
            {
            previous=i-1;
            }
          }
        else if(status==NO_PAD) /* NO_PAD */
          {
          if ((status=status_plane[INDEX(j,i,w,h)])==HOR_PAD)
            {
            /*from the begin to the middle */
            middle=(previous+i) >> 1;
            value=y_plane[INDEX(j,previous,w,h)];
            for(k=previous+1;k<middle;k++)
              y_plane[INDEX(j,k,w,h)]=(value+y_plane[INDEX(j,k,w,h)])>>1;
            /*from the middle to the end */
            value=y_plane[INDEX(j,i,w,h)];
            for(k=middle;k<i;k++)
              y_plane[INDEX(j,k,w,h)]=(value+y_plane[INDEX(j,k,w,h)])>>1;
            }
          }/* else VER_PAD */
        } /* while i */

      /* the last part of the column */
      if(status==HOR_PAD)
        {
        if(status_plane[INDEX(j,i,w,h)]==NO_PAD)
        y_plane[INDEX(j,i,w,h)]=y_plane[INDEX(j,i-1,w,h)];
        }
      else
        {
        if(status_plane[INDEX(j,i,w,h)]==NO_PAD)
          {
          value=y_plane[INDEX(j,previous,w,h)];
          for(k=previous+1;k<h;k++)
            y_plane[INDEX(j,k,w,h)]=(value+y_plane[INDEX(j,k,w,h)])>>1;
          }
        } /* else HOR_PAD */

      j++;
    } /* else skip the column */

  } /* while j */
}

/***********************************************************CommentBegin******
 *
 * -- UV_HorizontalPadding -- Horizontal padding of the Y data
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / J. Ignacio Ronda
 *
 * Created :
 *      02.02.96
 *
 * Purpose :
 *      Horizontal padding of the Y data
 *
 * Arguments in :
 *      SInt   *alpha_plane,    subsampled alpha plane
 *      Int    w,               subsampled width  (U or V)
 *      Int    h,               subsampled height (U or V)
 *
 * Arguments in/out :
 *      SInt   *status_plane,   subsampled status plane
 *      SInt   *u_plane,        U plane
 *      SInt   *v_plane         V plane
 *
 * Arguments out :
 *
 *
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
UV_HorizontalPadding (
   SInt   *alpha_plane,  /* <-- subsampled alpha plane     */
   Int    w,             /* <-- subsampled width  (U or V) */
   Int    h,             /* <-- subsampled height (U or V) */
   SInt   *status_plane, /* --> subsampled status plane    */
   SInt   *u_plane,      /* --> u plane                    */
   SInt   *v_plane       /* --> v plane                    */
   )
{
  Int    i, j;
  Int    k=0;
  Int    status;
  Int    previous;
  SInt   value1,value2;

  i=0;
  while(i<h)
    {
    j=previous=0;

    status=(alpha_plane[INDEX(j,i,w,h)]!=0) ? INSIDE:FIRST_PAD;
    if(status==INSIDE)
      status_plane[INDEX(j,i,w,h)]=INSIDE;

    j++;
    while(j<w)
      {
      if(alpha_plane[INDEX(j,i,w,h)]!=0)
        {
        if(status==FIRST_PAD)
          {
          value1=u_plane[INDEX(j,i,w,h)];
          value2=v_plane[INDEX(j,i,w,h)];
          for(k=0;k<j;k++)
            {
            u_plane[INDEX(k,i,w,h)]=value1;
            v_plane[INDEX(k,i,w,h)]=value2;
            status_plane[INDEX(k,i,w,h)]=HOR_PAD;
            }
          status=INSIDE;
          status_plane[INDEX(j,i,w,h)]=INSIDE;
          }
        else if (status==MIDDLE_PAD)
          {
          value1=((Int)u_plane[INDEX(previous,i,w,h)]+
                    (Int)u_plane[INDEX(j,i,w,h)]) >> 1;
          value2=((Int)v_plane[INDEX(previous,i,w,h)]+
                    (Int)v_plane[INDEX(j,i,w,h)]) >> 1;
          for(k=previous+1;k<j;k++)
            {
            u_plane[INDEX(k,i,w,h)] = value1;
            v_plane[INDEX(k,i,w,h)] = value2;
            status_plane[INDEX(k,i,w,h)]=HOR_PAD;
            }
          status_plane[INDEX(j,i,w,h)]=INSIDE;
          status=INSIDE;
          }
        else /* INSIDE */
          {
          status_plane[INDEX(j,i,w,h)]=INSIDE;
          }
        }
      else /* alpha_plane[INDEX(j,i,w,h)]==0 */
        {
        if(status==INSIDE)
          {
          status=MIDDLE_PAD;
          previous=j-1;
          }/* MIDDLE_PAD or FIRST_PAD do nothig */
        }
      j++;
      } /* while j */

    /* last part of the line */
    if(status==FIRST_PAD)
      {
      /* all line long */
      for(k=0;k<w;k++)
        {
        u_plane[INDEX(k,i,w,h)]=0;
        v_plane[INDEX(k,i,w,h)]=0;
        /* NO_PAD is the default for status_plane */
        }
      }
    else if(status==MIDDLE_PAD)
      {
      value1=u_plane[INDEX(previous,i,w,h)];
      value2=v_plane[INDEX(previous,i,w,h)];
      for(k=previous+1;k<w;k++)
        {
        u_plane[INDEX(k,i,w,h)]=value1;
        v_plane[INDEX(k,i,w,h)]=value2;
        status_plane[INDEX(k,i,w,h)]=HOR_PAD;
        }
      } /* if INSIDE, do nothing */
    i++;
    } /* while i */
}

/***********************************************************CommentBegin******
 *
 * -- UV_VerticalOverlapedPadding -- Vertical and overlapped padding
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / J. Ignacio Ronda
 *
 * Created :
 *      02.02.96
 *
 * Purpose :
 *      Vertical and overlapped (horizontal and vertical zones) padding of the
 *      Y data
 *
 * Arguments in :
 *      SInt   *alpha_plane,    subsampled alpha plane
 *      Int    w,               subsampled width  (U or V)
 *      Int    h,               subsampled height (U or V)
 *
 * Arguments in/out :
 *      SInt   *status_plane,   subsampled status plane
 *      SInt   *u_plane,        U plane
 *      SInt   *v_plane         V plane
 *
 * Arguments out :
 *
 *
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *      It would be possible to compute here the zero padding in the vertical
 *      direction
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
UV_VerticalOverlapedPadding (
   SInt   *alpha_plane,  /* <-- subsampled alpha plane     */
   Int    w,             /* <-- subsampled width  (U or V) */
   Int    h,             /* <-- subsampled height (U or V) */
   SInt   *status_plane, /* --> subsampled status plane    */
   SInt   *u_plane,      /* --> u plane                    */
   SInt   *v_plane       /* --> v plane                    */
   )
{
  Int    i, j;
  Int    k=0;
  Int    status;
  Int    previous;
  SInt   value1,value2;

  j=0;
  while(j<w)
    {
    i=previous=0;

    status=(alpha_plane[INDEX(j,i,w,h)]!=0) ? INSIDE:FIRST_PAD;
    /* status_plane[j,i] is updated if INSIDE */

    i++;
    while(i<h)
      {
      if(alpha_plane[INDEX(j,i,w,h)]!=0)
        {
        if(status==FIRST_PAD)
          {
          value1=u_plane[INDEX(j,i,w,h)];
          value2=v_plane[INDEX(j,i,w,h)];

          for(k=0;k<i;k++)
            {
            if(status_plane[INDEX(j,k,w,h)]==HOR_PAD)
              {
              u_plane[INDEX(j,k,w,h)]=((Int)u_plane[INDEX(j,k,w,h)]+
                                         (Int)value1)>>1;
              v_plane[INDEX(j,k,w,h)]=((Int)v_plane[INDEX(j,k,w,h)]+
                                         (Int)value2)>>1;
              }
            else
              {
              u_plane[INDEX(j,k,w,h)]=value1;
              v_plane[INDEX(j,k,w,h)]=value2;
              status_plane[INDEX(j,k,w,h)]=VER_PAD;
              }
            }
          status=INSIDE;
          }
        else if (status==MIDDLE_PAD)
          {
          value1=((Int)u_plane[INDEX(j,previous,w,h)]+
                    (Int)u_plane[INDEX(j,i,w,h)]) >> 1;
          value2=((Int)v_plane[INDEX(j,previous,w,h)]+
                    (Int)v_plane[INDEX(j,i,w,h)]) >> 1;
          for(k=previous+1;k<i;k++)
            {
            if(status_plane[INDEX(j,k,w,h)]==HOR_PAD)
              {
              u_plane[INDEX(j,k,w,h)]=((Int)u_plane[INDEX(j,k,w,h)]+
                                         (Int)value1)>>1;
              v_plane[INDEX(j,k,w,h)]=((Int)v_plane[INDEX(j,k,w,h)]+
                                         (Int)value2)>>1;
              }
            else
              {
              u_plane[INDEX(j,k,w,h)]=value1;
              v_plane[INDEX(j,k,w,h)]=value2;
              status_plane[INDEX(j,k,w,h)]=VER_PAD;
              }
            }
          status=INSIDE;
          } /* INSIDE do nothing */

        }
      else /* alpha_plane[INDEX(j,i,w,h)]==0 */
        {
        if(status==INSIDE)
          {
          status=MIDDLE_PAD;
          previous=i-1;
          }/* MIDDLE_PAD or FIRST_PAD do nothig */
        }
      i++;
      } /* while i */

    /* last part of the column */
    if(status==MIDDLE_PAD)
      {
      value1=u_plane[INDEX(j,previous,w,h)];
      value2=v_plane[INDEX(j,previous,w,h)];
      for(k=previous+1;k<h;k++)
        {
        if(status_plane[INDEX(j,k,w,h)]==HOR_PAD)
          {
          u_plane[INDEX(j,k,w,h)]=((Int)u_plane[INDEX(j,k,w,h)]
                                    +(Int)value1)>>1;
          v_plane[INDEX(j,k,w,h)]=((Int)v_plane[INDEX(j,k,w,h)]
                                    +(Int)value2)>>1;
          }
        else if (status_plane[INDEX(j,k,w,h)]==NO_PAD)
          {
          u_plane[INDEX(j,k,w,h)]=value1;
          v_plane[INDEX(j,k,w,h)]=value2;
          status_plane[INDEX(j,k,w,h)]=VER_PAD;
          }/* else INSIDE no change in the y_value */
        }/*for*/
      } /*else if(status==FIRST_PAD) */
    /* here we could perform the vertical padding in this column, i.e.,
       the same process made inside the first while of the
       UV_FinalVerticalPadding() fuction. The process would be the filling
       of the empty regions corresponding to the zones padded in the
       last part of the padding process (only the vertical value, which
       will be used to padd the region with the mean between the nearest
       horizontal&vertical values */

    j++;
    } /* while j */
}

/***********************************************************CommentBegin******
 *
 * -- UV_FinalHorizontalPadding -- Final zero padding in horizontal direction
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / J. Ignacio Ronda
 *
 * Created :
 *      02.02.96
 *
 * Purpose :
 *      Final zero padding in the horizontal direction of the Y data
 *
 * Arguments in :
 *      Int    w,               subsampled width  (U or V)
 *      Int    h,               subsampled height (U or V)
 *
 * Arguments in/out :
 *      SInt   *status_plane,   subsampled status plane
 *      SInt   *u_plane,        U plane
 *      SInt   *v_plane         V plane
 *
 * Arguments out :
 *
 *
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *      It would be modified if VerticalOverlapedPadding() performs the
 *      vertical zero padding
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
UV_FinalHorizontalPadding (
   Int    w,             /* <-- subsampled width  (U or V) */
   Int    h,             /* <-- subsampled height (U or V) */
   SInt   *status_plane, /* --> subsampled status plane    */
   SInt   *u_plane,      /* --> u plane                    */
   SInt   *v_plane       /* --> v plane                    */
   )
{
  Int    i, j;
  Int    k=0;
  Int    status;
  Int    previous;
  SInt   value1,value2;
  Int    middle;

  i=0;
  while(i<h)
    {
    j=previous=0;

    /* perhaps, the first part of the line */
    if((status_plane[INDEX(j,i,w,h)]==HOR_PAD)||
         (status_plane[INDEX(j,i,w,h)]==INSIDE))
      {
      i++;
      }
    else
      {
      if(status_plane[INDEX(j,i,w,h)]==NO_PAD)
        {
        /* first part of the line */

        j++;
        while(j<(w-1))
          {
          if(status_plane[INDEX(j,i,w,h)]==VER_PAD)
            {
            value1=u_plane[INDEX(j,i,w,h)];
            value2=v_plane[INDEX(j,i,w,h)];
            for(k=0;k<j;k++)
              {
              u_plane[INDEX(k,i,w,h)]=value1;
              v_plane[INDEX(k,i,w,h)]=value2;
              }
            j++;
            break;
            }
          else
            j++;
          }
        }

      /* the inner parts */

      status=VER_PAD;
      while(j<(w-1))
        {
        if (status==VER_PAD)
          {
          j++;
          if ((status=status_plane[INDEX(j,i,w,h)])==NO_PAD)
            {
            previous=j-1;
            }
          }
        else /* NO_PAD */
          {
          j++;
          if ((status=status_plane[INDEX(j,i,w,h)])==VER_PAD)
            {
            /*from the begin to the middle */
            middle=(previous+j) >> 1;
            value1=u_plane[INDEX(previous,i,w,h)];
            value2=v_plane[INDEX(previous,i,w,h)];
            for(k=previous+1;k<middle;k++)
              {
              u_plane[INDEX(k,i,w,h)]=value1;
              v_plane[INDEX(k,i,w,h)]=value2;
              }
            /*from the middle to the end */
            value1=u_plane[INDEX(j,i,w,h)];
            value2=v_plane[INDEX(j,i,w,h)];
            for(k=middle;k<j;k++)
              {
              u_plane[INDEX(k,i,w,h)]=value1;
              v_plane[INDEX(k,i,w,h)]=value2;
              }
            }
          }
        }  /* while j */

      /* the last part of the line */
      if(status==VER_PAD)
        {
        if(status_plane[INDEX(j,i,w,h)]==NO_PAD)
          {
          u_plane[INDEX(j,i,w,h)]=u_plane[INDEX(j-1,i,w,h)];
          v_plane[INDEX(j,i,w,h)]=v_plane[INDEX(j-1,i,w,h)];
          }
        else if(status_plane[INDEX(j,i,w,h)]==VER_PAD)
          {
          /* the case of an empty line with a pixel object at the
             last column */
          value1=u_plane[INDEX(j,i,w,h)];
          value2=v_plane[INDEX(j,i,w,h)];
          for(k=0;k<j;k++)
            {
            u_plane[INDEX(k,i,w,h)]=value1;
            v_plane[INDEX(k,i,w,h)]=value2;
            }
          }

        }
      else
        {
        if(status_plane[INDEX(j,i,w,h)]==NO_PAD)
          {
          value1=u_plane[INDEX(previous,i,w,h)];
          value2=v_plane[INDEX(previous,i,w,h)];
          for(k=previous+1;k<w;k++)
            {
            u_plane[INDEX(k,i,w,h)]=value1;
            v_plane[INDEX(k,i,w,h)]=value2;
            }
          }
        else
          {
          /*from the begin to the middle */
          middle=(previous+j) >> 1;
          value1=u_plane[INDEX(previous,i,w,h)];
          value2=v_plane[INDEX(previous,i,w,h)];
          for(k=previous+1;k<middle;k++)
            {
            u_plane[INDEX(k,i,w,h)]=value1;
            v_plane[INDEX(k,i,w,h)]=value2;
            }
          /*from the middle to the end */
          value1=u_plane[INDEX(j,i,w,h)];
          value2=v_plane[INDEX(j,i,w,h)];
          for(k=middle;k<w;k++)
            {
            u_plane[INDEX(k,i,w,h)]=value1;
            v_plane[INDEX(k,i,w,h)]=value2;
            }
          }
        } /* else VER_PAD */

      i++;
      }
    } /* while i */
}

/***********************************************************CommentBegin******
 *
 * -- UV_FinalVerticalPadding -- Final zero padding in the vertical direction
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / J. Ignacio Ronda
 *
 * Created :
 *      02.02.96
 *
 * Purpose :
 *      Final zero padding in the vertical direction of the Y data
 *
 * Arguments in :
 *      Int    w,               subsampled width  (U or V)
 *      Int    h,               subsampled height (U or V)
 *
 * Arguments in/out :
 *      SInt   *status_plane,   subsampled status plane
 *      SInt   *u_plane,        U plane
 *      SInt   *v_plane         V plane
 *
 * Arguments out :
 *
 *
 * Return values :
 *      none
 *
 * Side effects :
 *
 *
 * Description :
 *      It would disapear if VerticalOverlapedPadding() performs the vertical
 *      zero padding
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
UV_FinalVerticalPadding (
   Int    w,             /* <-- subsampled width  (U or V) */
   Int    h,             /* <-- subsampled height (U or V) */
   SInt   *status_plane, /* --> subsampled status plane    */
   SInt   *u_plane,      /* --> u plane                    */
   SInt   *v_plane       /* --> v plane                    */
   )
{
  Int    i, j;
  Int    k=0;
  Int    status;
  Int    previous;
  SInt   value1,value2;
  Int    middle;

  j=0;
  while(j<w)
    {
    i=previous=0;

    /* perhaps, the first part of the column */
    if((status_plane[INDEX(j,i,w,h)]==VER_PAD)||
         (status_plane[INDEX(j,i,w,h)]==INSIDE))
      {
      j++;
      }
    else
      {
      if(status_plane[INDEX(j,i,w,h)]==NO_PAD)
        {
        /* first part of the column */

        i++;
        while(i<(h-1))
          {
          if(status_plane[INDEX(j,i,w,h)]==HOR_PAD)
            {
            value1=u_plane[INDEX(j,i,w,h)];
            value2=v_plane[INDEX(j,i,w,h)];
            for(k=0;k<i;k++)
              {
              u_plane[INDEX(j,k,w,h)]=(u_plane[INDEX(j,k,w,h)]+value1)>>1;
              v_plane[INDEX(j,k,w,h)]=(v_plane[INDEX(j,k,w,h)]+value2)>>1;
              }
            i++;
            break;
            }
          else
            i++;
          }
        }

      /* the inner parts */
      status=HOR_PAD;
      while(i<(h-1))
        {
        i++;
        if (status==HOR_PAD)
          {
          if ((status=status_plane[INDEX(j,i,w,h)])==NO_PAD)
            {
            previous=i-1;
            }
          }
        else if(status==NO_PAD) /* NO_PAD */
          {
          if ((status=status_plane[INDEX(j,i,w,h)])==HOR_PAD)
            {
            /*from the begin to the middle */
            middle=(previous+i) >> 1;
            value1=u_plane[INDEX(j,previous,w,h)];
            value2=v_plane[INDEX(j,previous,w,h)];
            for(k=previous+1;k<middle;k++)
              {
              u_plane[INDEX(j,k,w,h)]=(value1+u_plane[INDEX(j,k,w,h)])>>1;
              v_plane[INDEX(j,k,w,h)]=(value2+v_plane[INDEX(j,k,w,h)])>>1;
              }
            /*from the middle to the end */
            value1=u_plane[INDEX(j,i,w,h)];
            value2=v_plane[INDEX(j,i,w,h)];
            for(k=middle;k<i;k++)
              {
              u_plane[INDEX(j,k,w,h)]=(value1+u_plane[INDEX(j,k,w,h)])>>1;
              v_plane[INDEX(j,k,w,h)]=(value2+v_plane[INDEX(j,k,w,h)])>>1;
              }
            }
          }
        } /* while i */

      /* the last part of the column */
      if(status==HOR_PAD)
        {
        if(status_plane[INDEX(j,i,w,h)]==NO_PAD)
          {
          u_plane[INDEX(j,i,w,h)]=u_plane[INDEX(j,i-1,w,h)];
          v_plane[INDEX(j,i,w,h)]=v_plane[INDEX(j,i-1,w,h)];
          }
        }
      else
        {
        if(status_plane[INDEX(j,i,w,h)]==NO_PAD)
          {
          value1=u_plane[INDEX(j,previous,w,h)];
          value2=v_plane[INDEX(j,previous,w,h)];
          for(k=previous+1;k<h;k++)
            {
            u_plane[INDEX(j,k,w,h)]=(value1+u_plane[INDEX(j,k,w,h)])>>1;
            v_plane[INDEX(j,k,w,h)]=(value2+v_plane[INDEX(j,k,w,h)])>>1;
            }

          }
        } /* else HOR_PAD */

      j++;
      } /* else skip the column */

    }/* while j */
}

/********************************************************** *CommentBegin******
 *
 * -- RepetitivePadding -- Repetitive padding of the YUV images
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / J. Ignacio Ronda
 *
 * Created :
 *      02.02.96
 *
 * Purpose :
 *      Repetitive padding of the YUV images of vop_ima depending on lumi field
 *
 * Arguments in :
 *      Int   lumi,      1=only padd Y image, !=1 padd YUV images
 *
 * Arguments in/out :
 *      Vop   *vop_ima   Vop to pad
 *
 * Arguments out :
 *
 *
 * Return values :
 *      1 on success, <0 on error
 *
 * Side effects :
 *
 *
 * Description :
 *      The downsampling of the alpha plane is done, if necesary, acording
 *      VM 2.x (valid alpha values are only the odd columns/files ones)
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Int
RepetitivePadding (
   Int   lumi,    /* <-- 1=only padd Y image, !=1 padd YUV images  */
   Vop   *vop_ima /* --> Vop to pad                                */
   )
{
  SInt    *alpha_plane;
  SInt    *y_plane;
  SInt    *u_plane;
  SInt    *v_plane;
  SInt    *status_plane;
  SInt    *alp_plane;
  Int     i, j, base;
  Image   *alpha_ima;
  Image   *y_ima;
  Image   *u_ima;
  Image   *v_ima;

  Int     y_x, y_y;
  Int     u_x, u_y;
  Int     v_x, v_y;

  Int     h;
  Int     w;

  /* checkings */

#ifdef _NO_PADDING_
  return(2);
#endif

  if( (vop_ima==NULL) || ((alpha_ima=vop_ima->a_chan)==NULL) ||
      ((y_ima=vop_ima->y_chan)==NULL) || ((u_ima=vop_ima->u_chan)==NULL) ||
      ((v_ima=vop_ima->v_chan)==NULL) ||
      ((alpha_plane=(SInt *)GetImageData(alpha_ima))==NULL) ||
      ((y_plane=(SInt *)GetImageData(y_ima))==NULL) ||
      ((u_plane=(SInt *)GetImageData(u_ima))==NULL)||
      ((v_plane=(SInt *)GetImageData(v_ima))==NULL) )
    {
    fprintf(stderr,"RepetitivePadding: NULL input pointers\n");
    return(0);
    }

  if ( (alpha_ima->grid=='h') || (y_ima->grid=='h') ||
       (u_ima->grid=='h')||(v_ima->grid=='h') )
    {
    fprintf(stderr,"RepetitivePadding: hexadecimal grid not supported\n");
    return(-1);
    }

  w=y_x=(Int)GetImageSizeX(y_ima);
  h=y_y=(Int)GetImageSizeY(y_ima);

  if ( (y_x!=GetImageSizeX(alpha_ima)) || (y_y!=GetImageSizeY(alpha_ima)) )
    {
    fprintf(stderr,"RepetitivePadding: different image dimensions \n");
    return(0);
    }


  if(lumi!=1)
    { /* do YUV padding */
    u_x=(Int)GetImageSizeX(u_ima);
    u_y=(Int)GetImageSizeY(u_ima);
    v_x=(Int)GetImageSizeX(v_ima);
    v_y=(Int)GetImageSizeY(v_ima);

    if ( (u_x!=v_x) || (u_y!=v_y) || ((y_y/2)!=u_y) ||
       (!((y_x/2==u_x)||(y_x==u_x)))  )
      {
      fprintf(stderr,"RepetitivePadding: different image dimensions \n");
      return(0);
      }
    }

  if ((status_plane= (SInt*)malloc(h*w*sizeof(SInt)))==NULL)
    {
    fprintf(stderr,"RepetitivePadding: malloc failed\n");
    return(-3);
    }

  for(j=0;j<h;j++)
    {
    base=j*w;
    for(i=0;i<w;i++)
      status_plane[base+i]= NO_PAD;
    }

  /* do Y padding */

  Y_HorizontalPadding (alpha_plane, w, h, status_plane, y_plane);

  Y_VerticalOverlapedPadding (alpha_plane, w, h, status_plane, y_plane);

  Y_FinalHorizontalPadding (w, h, status_plane, y_plane);

  Y_FinalVerticalPadding (w, h, status_plane, y_plane);

  if (lumi!=1)
    {
    free ((Char*)status_plane);

    /* do UV padding */

    h=h/2;
    w=w/2;
    if ((status_plane= (SInt*)malloc(h*w*sizeof(SInt)))==NULL)
      {
      fprintf(stderr,"RepetitivePadding: malloc failed\n");
      return(-3);
      }

    for(j=0;j<h;j++)
      {
      base=j*w;
      for(i=0;i<w;i++)
        status_plane[base+i]= NO_PAD;
      }
    alp_plane = (SInt *)GetImageData(vop_ima->a_uv_chan);

    UV_HorizontalPadding (alp_plane, w, h, status_plane, u_plane,v_plane);

    UV_VerticalOverlapedPadding (alp_plane, w, h, status_plane,u_plane,v_plane);

    UV_FinalHorizontalPadding (w, h, status_plane, u_plane,v_plane);

    UV_FinalVerticalPadding (w, h, status_plane, u_plane,v_plane);

    free ((Char*)status_plane);

    return(1);
    }
  else
    {
    free ((Char*)status_plane);

    return(-4);
    }
}

/***********************************************************CommentBegin******
 *
 * -- RepetitiveImagePadding --
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / J. Ignacio Ronda
 *
 * Created :
 *      02.02.96
 *
 * Purpose :
 *      Repetitive padding of the SInt data of ima
 *
 * Arguments in :
 *      Image   *alpha_ima,   alpha plane to check for shape
 *
 * Arguments in/out :
 *      Image   *ima          image to pad
 *
 * Arguments out :
 *
 *
 * Return values :
 *      1 on success, <0 on error
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Int
RepetitiveImagePadding (
   Image   *alpha_ima, /* <-- alpha plane to check for shape */
   Image   *ima        /* --> image to pad                   */
   )
{
  SInt    *alpha_plane;
  SInt    *y_plane;
  SInt    *status_plane;
  Int     i, j, base;
  Int     y_x,y_y;
  Int     h;
  Int     w;

#ifdef _NO_PADDING_
  return 2;
#endif

  /* checkings */
  if( (ima==NULL) || (alpha_ima==NULL) ||
      ((alpha_plane=(SInt *)GetImageData(alpha_ima))==NULL) ||
      ((y_plane=(SInt *)GetImageData(ima))==NULL) )
    {
    fprintf(stderr,"RepetitivePadding: NULL input pointers\n");
    return(0);
    }

  if ( (alpha_ima->grid=='h') || (ima->grid=='h') )
    {
    fprintf(stderr,"RepetitivePadding: hexadecimal grid not supported\n");
    return(-1);
    }

  w=y_x=(Int)GetImageSizeX(ima);
  h=y_y=(Int)GetImageSizeY(ima);

  if ( (y_x!=GetImageSizeX(alpha_ima)) || (y_y!=GetImageSizeY(alpha_ima)) )
    {
    fprintf(stderr,"RepetitivePadding: different image dimensions \n");
    return(0);
    }

  if ((status_plane= (SInt*)malloc(h*w*sizeof(SInt)))==NULL)
    {
    fprintf(stderr,"RepetitivePadding: malloc failed\n");
    return(-3);
    }

  for(j=0;j<h;j++)
    {
    base=j*w;
    for(i=0;i<w;i++)
      status_plane[base+i]= NO_PAD;
    }

  /* do Y padding */

  Y_HorizontalPadding (alpha_plane, w, h, status_plane, y_plane);

  Y_VerticalOverlapedPadding (alpha_plane, w, h, status_plane, y_plane);

  Y_FinalHorizontalPadding (w, h, status_plane, y_plane);

  Y_FinalVerticalPadding (w, h, status_plane, y_plane);

  free ((Char*)status_plane);

  return (1);
}

/***********************************************************CommentBegin******
 *
 * -- CheckParameters --
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / J. Ignacio Ronda
 *
 * Created :
 *      30.08.96
 *
 * Purpose :
 *      Checks the Input Parameters the TexturePadding fuction.
 *
 * Arguments in :
 *      Image   *prev_rec_alpha,   previous reconstructed alpha plane data
 *      Image   *alpha_decisions,  the previous reconstructed alpha plane
 *                                 subsampled (in block units) which values
 *                                 are:
 *                                  MBM_TRANSPARENT = all pixels are transparent
 *                                        (outside the shape)
 *                                  MBM_OPAQUE      = all pixels are not transp.
 *                                        (inside the shape)
 *                                  MBM_BOUNDARY    = transparent and not
 *                                        transparent pixels at the same time
 *                                        (in the boundary of the shape)
 *      Image   *MB_decisions,     encoding mode for each MB. If this Image is
 *                                  NULL      => Frame based repetitive padd.
 *                                  otherwise => Block based repetitive and
 *                                               zero padding.
 *
 * Arguments in/out :
 *      Vop     *cur_vop           Vop to pad
 *
 * Arguments out :
 *
 *
 * Return values :
 *      1 on success, <0 on error
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Int
CheckParameters (
   Image   *prev_rec_alpha,  /* <-- previous reconstructed alpha plane data */
   Image   *alpha_decisions, /* <-- subsampled (per block) prev_rec_alpha   */
   Image   *MB_decisions,    /* <-- encoding mode for each MB               */
   Vop     *cur_vop          /* <-> Vop to pad                              */
   )
{

  Image   *y_ima,*u_ima,*v_ima;
  Int     y_x,y_y,u_x,v_x,u_y,v_y;

  if( (cur_vop==NULL) ||
      ((y_ima=cur_vop->y_chan)==NULL) ||((u_ima=cur_vop->u_chan)==NULL) ||
      ((v_ima=cur_vop->v_chan)==NULL) ||
      (GetImageData(prev_rec_alpha)==NULL) ||
      (GetImageData(y_ima)==NULL) ||
      (GetImageData(u_ima)==NULL) ||
      (GetImageData(v_ima)==NULL) ||
      (alpha_decisions==NULL) || (MB_decisions==NULL)  ||
      (GetImageData(alpha_decisions)==NULL) ||
      (GetImageData(MB_decisions)==NULL) )
    {
    fprintf(stderr,"CheckParameters: NULL input pointers\n");
    return(0);
    }

  if ( (prev_rec_alpha->grid=='h') || (y_ima->grid=='h') ||
       (u_ima->grid=='h')||(v_ima->grid=='h') )
    {
    fprintf(stderr,"CheckParameters: hexadecimal grid not supported\n");
    return(-1);
    }

  y_x=(Int)GetImageSizeX(y_ima);
  y_y=(Int)GetImageSizeY(y_ima);

  if ( (y_x!=GetImageSizeX(y_ima)) || (y_y!=GetImageSizeY(y_ima)) )
    {
    fprintf(stderr,"CheckParameters: different image dimensions \n");
    return(-1);
    }

  u_x=(Int)GetImageSizeX(u_ima);
  u_y=(Int)GetImageSizeY(u_ima);
  v_x=(Int)GetImageSizeX(v_ima);
  v_y=(Int)GetImageSizeY(v_ima);

  if ( (u_x!=v_x) || (u_y!=v_y) || ((y_y/2)!=u_y) ||
     (!((y_x/2==u_x)||(y_x==u_x)))  )
     {
     fprintf(stderr,"CheckParameters: different image dimensions \n");
     return(-1);
     }

  return 1;
}

/***********************************************************CommentBegin******
 *
 * -- MacroblockBasedPadding --
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / J. Ignacio Ronda
 *
 * Created :
 *      21.10.96
 *
 * Purpose :
 *      Macroblock-based padding of the Vop images, according to the
 *      VM 5.1
 *
 * Arguments in :
 *      Image   *prev_rec_alpha,   Previous reconstructed alpha plane data
 *
 * Arguments in/out :
 *      Vop     *cur_vop,          Vop to pad
 *
 * Arguments out :
 *
 * Return values :
 *      1 on success, <0 on error
 *
 * Side effects :
 *
 *
 * Description :
 *      This function performs the padding of the YUV images of a given VOP
 *      needed in the motion estimation and compensation (see section 3.3.1).
 *
 *      1) The padded Vop is NOT extended 16 pixels in all directions (it is
 *         supposed that this extension has been previously done).
 *      2) Padding is performed SEPARATELY FOR EACH of the Y, U/V bands, but
 *         grouped in MB/B units.
 *      3) Padding of the MB/B uses the RECONSTRUCTED ALPHA values of the
 *         luminance or chrominance in this block (input parameter).
 *      4) Padding of chroma 8x8 block is performed by decimating the 16x16
 *         alpha block (by descarding every other row and column of pixels,
 *         starting from the second row and column, with an OR operation
 *         over the alpha pixel values).
 *
 * See also :
 *
 *
 * Modified :
 *      28-01-97 Robert Danielsen: Fix for freeing alpha_modes. Fix by
 *                Noel O'Connor.
 *      06.02.97 Angel Pacheco: the padding of the transparent blocks
 *                 is made looking at the most recently padded boundary block.
 *      17.04.97 Minhua Zhou: rewrote this program
 *      27.07.97 C.S. Boon: Changed to VM8.0 padding -- simplified padding
 *
 ***********************************************************CommentEnd********/

Int
MacroblockBasedPadding (
   Image   *prev_rec_alpha,/* <-- previous reconstructed alpha plane data  */
   Vop     *cur_vop       /* <-> Vop to pad                                */
   )
{
  Image   *alpha_sub_ima,
          *y_ima, *u_ima, *v_ima;
  SInt    *alpha_modes;
  SInt    *alpha,
          *alpha_uv,
          *alpha_sub,
          *buf;
  Int     a_w,a_h,i,j,i_ref,j_ref, padding_type;
  Int     h_size,w_size;
  Int     default_padding_value =1<<(GetVopBitsPerPixel(cur_vop) -1);
 
#ifdef _NO_PADDING_
  return(2);
#endif

  /*
   * MACROBLOCK-BASED REPETITIVE PADDING
   */

  /* checkings */
  if ( (cur_vop==NULL) || (prev_rec_alpha==NULL) ||
       ((y_ima=GetVopY(cur_vop))==NULL) || ((u_ima=GetVopU(cur_vop))==NULL) ||
       ((v_ima=GetVopV(cur_vop))==NULL) ||
       ((a_w=GetImageSizeX(GetVopY(cur_vop)))<1)  ||
       ((a_h=GetImageSizeY(GetVopY(cur_vop)))<1)  ||
       ((alpha=(SInt*)GetImageData(prev_rec_alpha))==NULL) ||
       (a_w!=GetImageSizeX(prev_rec_alpha)) ||
       (a_h!=GetImageSizeY(prev_rec_alpha)) ||
       (GetVopShape(cur_vop)==0) )
    {
    fprintf(stderr,"MacroblockBasedPadding: incorrect input parameters\n\n");
    return(-1);
    }
  w_size=a_w/MB_SIZE;
  h_size=a_h/MB_SIZE;
  alpha_sub_ima=GetVopAuv(cur_vop);

  /* array with MBM_TRANSPARENT/MBM_OPAQUE/MBM_BOUNDARY modes per MB */
  alpha_modes=(SInt*)malloc(sizeof(SInt)*w_size*h_size);
  subsamp_alpha(alpha,a_w,a_h,0/*MB-based*/,alpha_modes);

  alpha_uv= (SInt*)malloc(sizeof(SInt)*w_size*h_size);
  alpha_sub=(SInt*)GetImageData(alpha_sub_ima);
  subsamp_alpha(alpha_sub,a_w/2,a_h/2,1/*B-based*/,alpha_uv);

  buf = (SInt *)GetImageData(GetVopY(cur_vop));
  for (i=0;i<a_w*a_h;i++)
    if (alpha[i]==0)  buf[i]=default_padding_value;
  buf = (SInt *)GetImageData(GetVopU(cur_vop));
  for (i=0;i<a_w*a_h/4;i++)
    if (alpha_sub[i]==0)  buf[i]=default_padding_value;
  buf = (SInt *)GetImageData(GetVopV(cur_vop));
  for (i=0;i<a_w*a_h/4;i++)
    if (alpha_sub[i]==0)  buf[i]=default_padding_value;

  padding_type=1; /*==repetitive padding */

  /* Padding of boundary blocks */
  for(j=1;j<(h_size-1);j++)
    for(i=1;i<(w_size-1);i++)
      {
      if(alpha_modes[w_size*j+i]==MBM_BOUNDARY)
        BlockPadding(j,i,padding_type, MB_SIZE, prev_rec_alpha,0,cur_vop);
      if(alpha_uv[w_size*j+i]==MBM_BOUNDARY)
        BlockPadding(j,i,padding_type, B_SIZE, alpha_sub_ima,1,cur_vop);
      }

  /* Blocks surrounded by transparent blocks should be also
     treated as boundary blocks in the next step of block repetiting */
  for(j=1;j<(h_size-1);j++)
    for(i=1;i<(w_size-1);i++)
      {
      if ((alpha_modes[w_size*j+i]==MBM_OPAQUE)&&
          ((alpha_modes[w_size*j+i-1]==MBM_TRANSPARENT)||
          (alpha_modes[w_size*j+i+1]==MBM_TRANSPARENT)||
          (alpha_modes[w_size*(j+1)+i]==MBM_TRANSPARENT)||
          (alpha_modes[w_size*(j-1)+i]==MBM_TRANSPARENT)))
        alpha_modes[w_size*j+i]=MBM_BOUNDARY;
      if ((alpha_uv[w_size*j+i]==MBM_OPAQUE)&&
          ((alpha_uv[w_size*j+i-1]==MBM_TRANSPARENT)||
          (alpha_uv[w_size*j+i+1]==MBM_TRANSPARENT)||
          (alpha_uv[w_size*(j+1)+i]==MBM_TRANSPARENT)||
          (alpha_uv[w_size*(j-1)+i]==MBM_TRANSPARENT)))
        alpha_uv[w_size*j+i]=MBM_BOUNDARY;
      }

  /* priority order for extended padding according to VM8.0. boon */
  for (j=0;j<h_size;j++)
    for (i=0;i<w_size;i++)
      {
      if(alpha_modes[w_size*j+i]==MBM_TRANSPARENT)
        {
        i_ref=j_ref=-1;
        if ((i-1>=0)&&(alpha_modes[w_size*j+i-1]==MBM_BOUNDARY))
          {     /*LEFT*/
          j_ref =j;i_ref =i-1;
          }
        else if ((j-1>=0)&&(alpha_modes[w_size*(j-1)+i]==MBM_BOUNDARY))
          {   /*TOP*/
          j_ref =j-1;i_ref =i;
          }
        else if ((i+1<=w_size-1)&&(alpha_modes[w_size*j+i+1]==MBM_BOUNDARY))
          { /*RIGHT*/
          j_ref =j;i_ref =i+1;
          }
        else if ((j+1<=h_size-1)&&(alpha_modes[w_size*(j+1)+i]==MBM_BOUNDARY))
          { /*BOTTOM*/
          j_ref =j+1;i_ref =i;
          }
        if (i_ref!=-1)
          BlockRepetitivePadding(j,i,j_ref,i_ref,MB_SIZE,
                                 prev_rec_alpha,0,cur_vop);
        }

      if (alpha_uv[w_size*j+i]==MBM_TRANSPARENT)
        {
        i_ref=j_ref=-1;
        if ((i-1>=0)&&(alpha_uv[w_size*j+i-1]==MBM_BOUNDARY))
          {  /*LEFT*/
          j_ref =j;i_ref =i-1;
          }
        else if ((j-1>=0)&&(alpha_uv[w_size*(j-1)+i]==MBM_BOUNDARY))
          {   /*TOP*/
          j_ref =j-1;i_ref =i;
          }
        else if ((i+1<=w_size-1)&&(alpha_uv[w_size*j+i+1]==MBM_BOUNDARY))
          { /*RIGHT*/
          j_ref =j;i_ref =i+1;
          }
        else if ((j+1<=h_size-1)&&(alpha_uv[w_size*(j+1)+i]==MBM_BOUNDARY))
          { /*BOTTOM*/
          j_ref =j+1;i_ref =i;
          }
        if (i_ref!=-1)
          BlockRepetitivePadding(j,i,j_ref,i_ref,B_SIZE,
                                 alpha_sub_ima,1,cur_vop);
        }

      }

  /* Free alpha_sub_ima  & alpha_uv before return - NO'C, 13/Sep/96 */
  free((Char *)alpha_uv);
  free((Char *)alpha_modes);
  return 1;
}

/***********************************************************CommentBegin******
 *
 * -- TexturePadding --
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / J. Ignacio Ronda
 *
 * Created :
 *      30.08.96
 *
 * Purpose :
 *      LPE/zero block-based padding of the YUV images
 *
 * Arguments in :
 *      Image *prev_ori_alpha,   previous original alpha plane data
 *      Image *alpha_decisions,  the previous original alpha plane
 *                               subsampled (in block units) which values
 *                               are:
 *                                MBM_TRANSPARENT = all pixels are transparent
 *                                      (outside the shape)
 *                                MBM_OPAQUE      = all pixels are not transp.
 *                                      (inside the shape)
 *                                MBM_BOUNDARY    = transparent and not
 *                                      transparent pixels at the same time
 *                                      (in the boundary of the shape)
 *      Image *MB_decisions,   encoding mode for each MB. If this Image is
 *                                NULL      => Frame based repetitive padd.
 *                                otherwise => Block based LPE and zero padding.
 *
 * Arguments in/out :
 *      Vop   *cur_vop         Vop to pad
 *
 * Arguments out :
 *
 *
 * Return values :
 *      1 on success, <0 on error
 *
 * Side effects :
 *
 *
 * Description :
 *      This function performs the padding of the YUV images of a given VOP
 *      needed in the texture coding.
 *
 *      0) Padding is performed in those MB that lie on the boundary of
 *         the shape, and in some neihbourgs.
 *      1) Padding is performed SEPARATELY FOR EACH of the Y, U and V 8x8
 *         blocks.
 *      2) Padding of the block uses the ORIGINAL ALPHA values of the
 *         luminance or chrominance in this block.
 *      3) Padding of chroma 8x8 block is performed by decimating the 16x16
 *         alpha block (by descarding every other row and column of pixels,
 *         starting from the second row and column).
 *      4) If all the pixels in an 8x8 block are transparent, their values
 *         are replaced by zero (not strictly necessary).
 *      5) There are two cases depending on the MB type:
 *           o intra 8x8 blocks
 *              ==> LPE padding
 *           o residue 8x8 blocks (prediction error after the MC)
 *              ==> padding with zeroes
 *
 * See also :
 *
 *
 * Modified :
 *      05.02.97 A. Pacheco: modified to include the new low pass extrapolation
 *                 padding technique of the VM5.1
 *      05.02.97 A. Pacheco: modified to fill the pixels acording the original
 *                 alpha values (VM5.1)
 *      26.05.97 Minhua Zhou: Removed DoAlphaUVPlane()
 *
 ***********************************************************CommentEnd********/

Int
TexturePadding (
   Vop      *rec_vop,  /* <-- previous original alpha plane data */
   Image   *alpha_decisions, /* <-- subsampled (per block) prev_ori_alpha   */
   Image   *MB_decisions,    /* <-- encoding mode for each MB               */
   Vop     *cur_vop          /* <-> Vop to pad                              */
   )
{
  Image   *aux_a, *prev_ori_alpha=GetVopA(rec_vop);
  Image   *alpha_sub_ima;
  SInt    *mb_modes;
  SInt    *a_sub,
          *alpha_uv,
          *alpha_sub;
  Int     error,a_w,a_h,i,j,a_sub_pos, mb_pos,padding_type;
  Int     h_size,w_size,uv_w_size;


#ifdef _NO_TEXTURE_PADDING_
  return(2);
#endif


  /* choose between frame-based or block based repetitive padding */

  if(MB_decisions==NULL)
    {

    /*
     * FRAME-BASED REPETITIVE PADDING
     */

    /* update alpha plane to pad with */
    aux_a=GetVopA(cur_vop);
    cur_vop->a_chan=GetVopA(rec_vop);

    /* do the repetitive frame-based padding */
    error=RepetitivePadding(0,cur_vop);

    /* update the vop */
    cur_vop->a_chan=aux_a;
    if(error!=1)
      fprintf(stderr,"TexturePadding: error in RepetitivePadding\n");

    return (error);
    }

  /*
   * BLOCK-BASED REPETITIVE PADDING
   */

  /* checkings */
  if (CheckParameters(GetVopA(rec_vop),alpha_decisions,MB_decisions,cur_vop)!=1)
    {
    fprintf(stderr,"TexturePadding: incorrect input parameters\n\n");
    return(-1);
    }

  a_sub=   (SInt*)GetImageData(alpha_decisions);
  mb_modes=(SInt*)GetImageData(MB_decisions);
  a_w=GetImageSizeX(GetVopY(cur_vop));
  a_h=GetImageSizeY(GetVopY(cur_vop));

  alpha_sub=(SInt*)GetImageData(GetVopAuv(rec_vop));

  w_size=GetImageSizeX(GetVopY(cur_vop))/MB_SIZE;
  h_size=GetImageSizeY(GetVopY(cur_vop))/MB_SIZE;
  uv_w_size=a_w/B_SIZE/2;
  alpha_sub_ima= GetVopAuv(rec_vop);
  alpha_uv= (SInt*)malloc(sizeof(SInt)*w_size*h_size);
  alpha_sub=(SInt*)GetImageData(alpha_sub_ima);
  subsamp_alpha(alpha_sub,a_w/2,a_h/2,1/*B-based*/,alpha_uv);

  for(j=0;j<h_size;j++)
    for(i=0;i<w_size;i++)
      {
      mb_pos=w_size*j+i;
      if (mb_modes[mb_pos]==MBM_INTRA)
        padding_type=1;
      else /* MBM_INTER16) || MBM_INTER8 or (MBM_TRANSPARENT||MBM_OUT??*/
        padding_type=0;

      /* Y blocks */
      a_sub_pos=w_size*2*j*2+i*2;
      if(a_sub[a_sub_pos]==MBM_TRANSPARENT)
        AllZeroFillBlock(j*2  ,i*2  ,0,cur_vop);
      else if (a_sub[a_sub_pos]==MBM_BOUNDARY)
        TextureBlockPadding(j*2,i*2,padding_type,B_SIZE,prev_ori_alpha,
                            0,cur_vop);
      /* else MBM_OPAQUE, do nothing */

      a_sub_pos++;
      if(a_sub[a_sub_pos]==MBM_TRANSPARENT)
        AllZeroFillBlock(j*2  ,i*2+1,0,cur_vop);
      else if (a_sub[a_sub_pos]==MBM_BOUNDARY)
        TextureBlockPadding(j*2,i*2+1,padding_type,B_SIZE,prev_ori_alpha,
                            0,cur_vop);
      /* else MBM_OPAQUE, do nothing */

      a_sub_pos=w_size*2*(2*j+1)+i*2;
      if(a_sub[a_sub_pos]==MBM_TRANSPARENT)
        AllZeroFillBlock(j*2+1,i*2  ,0,cur_vop);
      else if (a_sub[a_sub_pos]==MBM_BOUNDARY)
        TextureBlockPadding(j*2+1,i*2,padding_type,B_SIZE,prev_ori_alpha,
                            0,cur_vop);
      /* else MBM_OPAQUE, do nothing */

      a_sub_pos++;
      if(a_sub[a_sub_pos]==MBM_TRANSPARENT)
        AllZeroFillBlock(j*2+1,i*2+1,0,cur_vop);
      else if (a_sub[a_sub_pos]==MBM_BOUNDARY)
        TextureBlockPadding(j*2+1,i*2+1,padding_type,B_SIZE, prev_ori_alpha,
                            0,cur_vop);
      /* else MBM_OPAQUE, do nothing */

      /* U-V blocks */
      a_sub_pos=uv_w_size*j+i;
      if(alpha_uv[a_sub_pos]==MBM_TRANSPARENT)
        AllZeroFillBlock(j,i,1,cur_vop);
      else if(alpha_uv[a_sub_pos]==MBM_BOUNDARY)
        /* has alpha_sub*/
        TextureBlockPadding(j,i ,padding_type,B_SIZE, alpha_sub_ima,1,cur_vop);
      /* else MBM_OPAQUE, do nothing */
    }

  /* Free alpha_sub_ima  & alpha_uv before return - NO'C, 13/Sep/96 */
  free((Char *)alpha_uv);

  return 1;
}

/***********************************************************CommentBegin******
 *
 * -- BlockRepetitivePadding --
 *
 * Author :
 *      UPM-GTI - Angel Pacheco
 *
 * Created :
 *      22.10.96
 *
 * Purpose :
 *      Repetitive padding of an image blocks (section 3.3.1 and figs. 2,3
 *      of VM4.0)
 *
 * Arguments in :
 *      Int   v,               vertical coord. (in block units) of the
 *                             block within the lumi image or chroma images
 *      Int   h,               horizontal coord. (in block units) of the
 *                             block within the lumi image or chroma images
 *      Int   vref,            vertical reference coord. (in block units) of the
 *                             block within the lumi image or chroma images
 *      Int   href,            horizontal reference coord. (in block units) of
 *                             the block within the lumi image or chroma images
 *      Int   block_size,      B_SIZE or MB_SIZE
 *      Image *prev_rec_alpha, previous reconstructed alpha plane (Y or
 *                             subsampled UV)
 *      Int   image_type,      0=Y; 1=U and V
 *
 * Arguments in/out :
 *      Vop   *cur_vop         Vop to pad
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 *
 * Side effects :
 *
 *
 * Description :
 *      This function performs the repetitive padding of an block (Y or U and V)
 *      of a given VOP. Needed in the estimation/compensation process.
 *
 *      1) Padding is performed for an luminance block (image_type=0)
 *         or for both chrominance blocks separately (image_type=1)
 *      2) Padding of the block must use the RECONSTRUCTED ALPHA values of the
 *         luminance or chrominance in this block.
 *      3) If image_type = 0, the prev_rec_alpha must be the previous
 *         reconstructed alpha plane.
 *         If image_type = 1, the prev_rec_alpha must be the previous
 *         reconstructed alpha plane decimated according to VM.
 *      4) The average of the values of the differents MB/Bs used to pad is
 *         performed in the calling code (here, it is no possible to know how
 *         many reference MB/Bs will infuence the current MB/B).
 *      5) No input checkings are performed!!
 *
 * See also :
 *
 *
 * Modified :
 *      09.05.97 Minhua Zhou: changed operation "+=" to "="
 *
 ***********************************************************CommentEnd********/

Void
BlockRepetitivePadding (
   Int     v,                /* <-- vertical coord. (in block units)        */
   Int     h,                /* <-- horizontal coord. (in block units)      */
   Int     vref,             /* <-- vertical ref. coord. (in block units)   */
   Int     href,             /* <-- horizontal ref. coord. (in block units) */
   Int     block_size,       /* <-- B_SIZE or MB_SIZE                       */
   Image   *prev_rec_alpha,  /* <-- previous reconstructed alpha plane data */
   Int     image_type,       /* <-- 0=Y; 1=U and V                          */
   Vop     *cur_vop          /* <-> Vop to pad                              */
   )

{
  SInt   *y_data,*y_block,*yref_block;
  SInt   *u_data,*u_block,*uref_block;
  SInt   *v_data,*v_block,*vref_block;
  Int    direction;
  Int    size_w,pos;
  Int    i,j;

  /* prev_rec_alpha has, depending on image_type, the right alpha plane
     subsampled for the UV data or for the Y data */

  /* block-based repetitive padding */

  y_data=(SInt*)GetImageData(GetVopY(cur_vop));
  u_data=(SInt*)GetImageData(GetVopU(cur_vop));
  v_data=(SInt*)GetImageData(GetVopV(cur_vop));

  if (vref==v)
    direction=((href-h)<0)?LEFT_REFERENCE:RIGHT_REFERENCE;
  else /* href==h */
    direction=((vref-v)<0)?UPPER_REFERENCE:LOWER_REFERENCE;

  if(image_type==0)  /* Y */
    {
    size_w=GetImageSizeX(GetVopY(cur_vop));

    /* Y repetitive-padding */
    y_block=(SInt*)LoadArea(y_data,h*block_size,v*block_size,
                            block_size,block_size,size_w);
    yref_block=(SInt*)LoadArea(y_data,href*block_size,vref*block_size,
                               block_size,block_size,size_w);

    if ((direction==UPPER_REFERENCE)||(direction==LOWER_REFERENCE))
      {
      pos=(direction==UPPER_REFERENCE)?block_size*(block_size-1):0;
      for(j=0;j<block_size;j++)
        for(i=0;i<block_size;i++)
          y_block[j*block_size+i]=yref_block[pos+i];
      }
    else
      {
      pos=(direction==LEFT_REFERENCE)?(block_size-1):0;
      for(j=0;j<block_size;j++)
        for(i=0;i<block_size;i++)
          y_block[j*block_size+i]=yref_block[j*block_size+pos];
      }

    SetArea(y_block,h*block_size,v*block_size,block_size,block_size,
            size_w,y_data);

    free((Char*)y_block);
    free((Char*)yref_block);
    }
   else              /* U-V */
    {
    size_w=GetImageSizeX(GetVopU(cur_vop));

    /* U-V repetitive-padding */
    u_block=(SInt*)LoadArea(u_data,h*block_size,v*block_size,
                            block_size,block_size,size_w);
    v_block=(SInt*)LoadArea(v_data,h*block_size,v*block_size,
                            block_size,block_size,size_w);
    uref_block=(SInt*)LoadArea(u_data,href*block_size,vref*block_size,
                               block_size,block_size, size_w);
    vref_block=(SInt*)LoadArea(v_data,href*block_size,vref*block_size,
                               block_size,block_size, size_w);

    if ((direction==UPPER_REFERENCE)||(direction==LOWER_REFERENCE))
      {
      pos=(direction==UPPER_REFERENCE)?block_size*(block_size-1):0;
      for(j=0;j<block_size;j++)
        for(i=0;i<block_size;i++)
          {
          u_block[j*block_size+i]=uref_block[pos+i];
          v_block[j*block_size+i]=vref_block[pos+i];
          }
      }
    else
      {
      pos=(direction==LEFT_REFERENCE)?(block_size-1):0;
      for(j=0;j<block_size;j++)
        for(i=0;i<block_size;i++)
          {
          u_block[j*block_size+i]=uref_block[j*block_size+pos];
          v_block[j*block_size+i]=vref_block[j*block_size+pos];
          }
      }

    SetArea(u_block,h*block_size,v*block_size,
            block_size,block_size,size_w,u_data);
    SetArea(v_block,h*block_size,v*block_size,
            block_size,block_size,size_w,v_data);

    free((Char*)u_block);
    free((Char*)v_block);
    free((Char*)uref_block);
    free((Char*)vref_block);
    }

} /* BlockRepetitivePadding */

/***********************************************************CommentBegin******
 *
 * -- BlockPadding --
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / Fernando Jaureguizar
 *
 * Created :
 *      30.08.96
 *
 * Purpose :
 *      Repetitive/zero padding of an 8x8/16x16 Y or UV image blocks
 *
 * Arguments in :
 *      Int     v,                  vertical coord. (in block units) of the
 *                                  block within the lumi image or chroma images
 *      Int     h,                  horizontal coord. (in block units) of the
 *                                  block within the lumi image or chroma images
 *      Int     padding_type,       0=zeroes padding; 1=repetitive padding
 *      Int     block_size,         B_SIZE or MB_SIZE
 *      Image   *prev_rec_alpha,    previous reconstructed alpha plane (Y or
 *                                  subsampled UV)
 *      Int     image_type,         0=Y; 1=U and v
 *
 * Arguments in/out :
 *      Vop     *cur_vop            Vop to pad
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 *
 * Side effects :
 *
 *
 * Description :
 *      This function performs the padding of an 8x8 block (Y or U and V) of a
 *      given VOP. Needed in the texture coding.
 *
 *      1) Padding is performed for an 8x8/16x16 luminance block (image_type=0)
 *         or for both chrominance blocks separately (image_type=1)
 *      2) Padding of the block uses the RECONSTRUCTED ALPHA values of the
 *         luminance or chrominance in this block.
 *      3) If image_type = 0, the prev_rec_alpha must be the previous
 *         reconstructed alpha plane.
 *         If image_type = 1, the prev_rec_alpha must be the previous
 *         reconstructed alpha plane decimated according to VM.
 *      4) If all the pixels in an 8x8 block are transparent, their values
 *         are replaced by zero.
 *      5) Performs two paddings depending on the padding_type parameter:
 *           0   ==> padding with zeroes; for residue 8x8 blocks (prediction
 *                   error after the MC)
 *           1   ==> Repetitive padding as in ME/MC; for intra 8x8 blocks
 *      No input checkings are performed
 *
 * See also :
 *
 *
 * Modified :
 *      22.10.96 A. Pacheco: modified to allow blocks of 8 and 16 units.
 *                  ATTENTION: if block_size==16 the padding_type must be 1!!
 *                  in the same way, there are combinations of parameters not
 *                  checked because they would be not used at all.
 *      27.07.97 C.S. Boon: Modified for VM8.0 padding -- simplified padding
 *
 ***********************************************************CommentEnd********/

Void
BlockPadding (
   Int     v,                /* <-- vertical coord. (in block units)        */
   Int     h,                /* <-- horizontal coord. (in block units)      */
   Int     padding_type,     /* <-- 0=zeroes padding; 1=repetitive padding  */
   Int     block_size,       /* <-- B_SIZE or MB_SIZE                       */
   Image   *prev_rec_alpha,  /* <-- previous reconstructed alpha plane data */
   Int     image_type,       /* <-- 0=Y; 1=U and V                          */
   Vop     *cur_vop          /* <-> Vop to pad                              */
   )
{
  SInt   *a_data,*a_block;
  SInt   *y_data,*y_block;
  SInt   *u_data,*u_block;
  SInt   *v_data,*v_block;
  SInt   *status_block;
  Int    size_w,j;

  Int    i;
  Byte   *ca_block;
  Byte   *cy_block;
  Byte   *cu_block;
  Byte   *cv_block;

  /* prev_rec_alpha has, depending on image_type, the right alpha plane
     subsampled for the UV data or for the Y data */

  if(padding_type==0) /* Zero pading */
    {
    ZeroFillBlock (v,h,image_type,prev_rec_alpha,cur_vop);
    return;
    }

  /* block-based repetitive padding */

  y_data=(SInt*)GetImageData(GetVopY(cur_vop));
  u_data=(SInt*)GetImageData(GetVopU(cur_vop));
  v_data=(SInt*)GetImageData(GetVopV(cur_vop));
  a_data=(SInt*)GetImageData(prev_rec_alpha);

  /* creates and inits status_block */
  if ((status_block=(SInt*)malloc(block_size*block_size*sizeof(SInt)))==NULL)
    {
    fprintf(stderr,"BlockPadding: malloc failed\n");
    return;
    }
  for (j=0;j<(block_size*block_size);j++)
    status_block[j]=NO_PAD;

  if(image_type==0)  /* Y */
    {
    size_w=GetImageSizeX(GetVopY(cur_vop));

    /* Y repetitive-padding */
    y_block=(SInt*)LoadArea(y_data,h*block_size,v*block_size,
                            block_size,block_size,size_w);
    a_block=(SInt*)LoadArea(a_data,h*block_size,v*block_size,
                            block_size,block_size,size_w);

    /* modified for VM8.0 padding. boon */
    cy_block=(Byte *)malloc(sizeof(Byte)*block_size*block_size);
    ca_block=(Byte *)malloc(sizeof(Byte)*block_size*block_size);

    for(i=0;i<block_size*block_size;i++)
      {
      cy_block[i]=(Byte)y_block[i];
      ca_block[i]=(Byte)a_block[i];
      }

    simpl_pad(cy_block,ca_block,block_size,block_size);

    for(i=0;i<block_size*block_size;i++)
      {
      y_block[i]=(SInt)cy_block[i];
      }

    free(cy_block);
    free(ca_block);

    SetArea(y_block,h*block_size,v*block_size,
            block_size,block_size,size_w,y_data);

    free((Char*)y_block);
    free((Char*)status_block);
    free((Char*)a_block);
    }
  else              /* U-V */
    {
    cu_block=(Byte *)malloc(sizeof(Byte)*block_size*block_size);
    cv_block=(Byte *)malloc(sizeof(Byte)*block_size*block_size);
    ca_block=(Byte *)malloc(sizeof(Byte)*block_size*block_size);
    size_w=GetImageSizeX(GetVopU(cur_vop));

    /* U-V repetitive-padding */
    u_block=(SInt*)LoadArea(u_data,h*block_size,v*block_size,
                            block_size,block_size,size_w);
    v_block=(SInt*)LoadArea(v_data,h*block_size,v*block_size,
                            block_size,block_size,size_w);
    a_block=(SInt*)LoadArea(a_data,h*block_size,v*block_size,
                            block_size,block_size,size_w);

    /* modified for VM8.0 padding. boon */
    for(i=0;i<block_size*block_size;i++)
      {
      cu_block[i]=(Byte)u_block[i];
      cv_block[i]=(Byte)v_block[i];
      ca_block[i]=(Byte)a_block[i];
      }

    simpl_pad(cu_block,ca_block,block_size,block_size); /*UV simplif. padding*/
    simpl_pad(cv_block,ca_block,block_size,block_size); /*UV simplif. padding*/

    for(i=0;i<block_size*block_size;i++)
      {
      u_block[i]=(SInt)cu_block[i];
      v_block[i]=(SInt)cv_block[i];
      }
    free(cu_block);
    free(cv_block);
    free(ca_block);

    SetArea(u_block,h*block_size,v*block_size,
            block_size,block_size,size_w,u_data);
    SetArea(v_block,h*block_size,v*block_size,
            block_size,block_size,size_w,v_data);

    free((Char*)a_block);
    free((Char*)u_block);
    free((Char*)v_block);
    free((Char*)status_block);
    }
} /* BlockPadding */

/***********************************************************CommentBegin******
 *
 * -- simpl_pad --
 *
 * Authors :
 *      C. S. Boon, J. Takahashi
 *
 * Created :
 *      31.07.97
 *
 * Purpose :
 *      Simplified padding of an 8x8/16x16 Y or UV image blocks
 *
 * Arguments in :
 *      Byte *org_shape    reference shape for padding
 *      int  width         size of image
 *      int  height        size of image
 *
 * Arguments in/out :
 *      Byte *dt           in-data to be padded, out-padded data
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
simpl_pad(
   Byte   *dt,
   Byte   *org_shape,
   int    width,
   int    height
   )
{
  int    size = width*height;
  int    v, h, adr, prev_adr, tmp_adr, start_adr;
  int    cnt=0, dest;
  Byte   other[2];
  Byte   fill_dt;
  Byte   src[16];
  Byte   *hrep_shp;

  hrep_shp=(Byte *)malloc(sizeof(Byte)*size);

  /* H phase */
  memcpy(hrep_shp, org_shape, size);

  adr = 0;
  for (v=0;v<height;v++)
    {
    tmp_adr = 0;
    prev_adr = -1;
    other[1] = 0;
    while (tmp_adr < width)
      {
      cnt = 0;
      while ( (tmp_adr < width) && (*(hrep_shp+adr+tmp_adr) == 0) )
        {
        cnt++;
        tmp_adr++;
        }

      if ( (cnt > 0) && (tmp_adr < width) )
        {
        start_adr = adr + prev_adr + 1;
        if (other[1])
          {            /* left & right */
          fill_dt = (other[0] + *(dt+adr+tmp_adr) + 1 )>>1;
          memset(dt+start_adr, fill_dt, cnt);
          memset(hrep_shp+start_adr, 255, cnt);
          }
        else
          {        /* right only */
          fill_dt = *(dt+adr+tmp_adr);
          memset(dt+start_adr, fill_dt, cnt);
          memset(hrep_shp+start_adr, 255, cnt);
          }
        }

      if (tmp_adr < width)
        {
        cnt = 0;
        other[0] = *(dt + adr + tmp_adr);
        other[1] = *(hrep_shp + adr + tmp_adr);
        prev_adr = tmp_adr;
        }
      tmp_adr++;
      }

    if ((cnt > 0)&&(other[1]))
      {  /* left only */
      start_adr = adr + prev_adr + 1;
      fill_dt = other[0];
      memset(dt+start_adr, fill_dt, cnt);
      memset(hrep_shp+start_adr, 255, cnt);
      }
    adr += width;
    } /*for*/


  /* V phase */
  adr = 0;
  prev_adr = -1;
  while (adr < size)
    {
    if ( *(hrep_shp+adr) != 0 )
      {
      if (prev_adr < 0)
        {
        prev_adr = 0;
        while (prev_adr < adr)
          {
          memcpy(dt+prev_adr, dt+adr, width);
          prev_adr += width;
          }
        }
      else
        {
        if (prev_adr+width < adr)
          {
          for (h=0;h<width;h++)
            {
            src[h] = (*(dt+prev_adr+h) + *(dt+adr+h) + 1 )/2;
            }
          prev_adr += width;
          while (prev_adr < adr)
            {
            memcpy(dt+prev_adr, src, width);
            prev_adr += width;
            }
          }
        prev_adr = adr;
        }
      }
    adr += width;
    }

  dest = prev_adr + width;
  while (dest < adr)
    {
    memcpy(dt+dest, dt+prev_adr, width);
    dest += width;
    }

  free(hrep_shp);
}

/***********************************************************CommentBegin******
 *
 * -- TextureBlockPadding --
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / Fernando Jaureguizar
 *
 * Created :
 *      30.08.96
 *
 * Purpose :
 *      LPE/zero padding of an 8x8/16x16 Y or UV image blocks
 *
 * Arguments in :
 *      Int     v,                  vertical coord. (in block units) of the
 *                                  block within the lumi image or chroma images
 *      Int     h,                  horizontal coord. (in block units) of the
 *                                  block within the lumi image or chroma images
 *      Int     padding_type,       0=zeroes padding; 1=repetitive padding
 *      Int     block_size,         B_SIZE or MB_SIZE
 *      Image   *prev_ori_alpha,    previous original alpha plane (Y or
 *                                  subsampled UV)
 *      Int     image_type,         0=Y; 1=U and v
 *
 * Arguments in/out :
 *      Vop     *cur_vop            Vop to pad
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 * Side effects :
 *
 *
 * Description :
 *      This function performs the padding of an 8x8 block (Y or U and V) of a
 *      given VOP. Needed in the texture coding.
 *
 *      1) Padding is performed for an 8x8/16x16 luminance block (image_type=0)
 *         or for both chrominance blocks separately (image_type=1)
 *      2) Padding of the block uses the ORIGINAL ALPHA values of the
 *         luminance or chrominance in this block.
 *      3) If image_type = 0, the prev_rec_alpha must be the previous
 *         original alpha plane.
 *         If image_type = 1, the prev_rec_alpha must be the previous
 *         original alpha plane decimated according to VM.
 *      4) If all the pixels in an 8x8 block are transparent, their values
 *         are replaced by zero.
 *      5) Performs two paddings depending on the padding_type parameter:
 *           0   ==> padding with zeroes; for residue 8x8 blocks (prediction
 *                   error after the MC)
 *           1   ==> Low Pass Extrapolation padding
 *      No input checkings are performed
 *
 * See also :
 *
 *
 * Modified :
 *      22.10.96 A. Pacheco: modified to allow blocks of 8 and 16 units.
 *               ATTENTION: if block_size==16 the padding_type must be 1!! in
 *               the same way, there are combinations of parameters not checked
 *               because they would be not used at all.
 *      05.02.97 A. Pacheco: modified to include the new low pass extrapolation
 *               padding technique of the VM5.1
 *      05.02.97 A. Pacheco: modified to fill the pixels acording the original
 *               alpha values (VM5.1)
 *
 ***********************************************************CommentEnd********/

Void
TextureBlockPadding (
   Int     v,                /* <-- vertical coord. (in block units)        */
   Int     h,                /* <-- horizontal coord. (in block units)      */
   Int     padding_type,     /* <-- 0=zeroes padding; 1=repetitive padding  */
   Int     block_size,       /* <-- B_SIZE or MB_SIZE                       */
   Image   *prev_ori_alpha,  /* <-- previous original alpha plane data */
   Int     image_type,       /* <-- 0=Y; 1=U and V                          */
   Vop     *cur_vop          /* <-> Vop to pad                              */
   )

{
  SInt   *a_data,*a_block;
  SInt   *y_data,*y_block;
  SInt   *u_data,*u_block;
  SInt   *v_data,*v_block;
  Int    size_w;

  /* prev_ori_alpha has, depending on image_type, the right alpha plane
     subsampled for the UV data or for the Y data */

  if(padding_type==0) /* Zero pading */
    {
    ZeroFillBlock (v,h,image_type,prev_ori_alpha,cur_vop);
    return;
    }

  /* block-based repetitive padding */

  y_data=(SInt*)GetImageData(GetVopY(cur_vop));
  u_data=(SInt*)GetImageData(GetVopU(cur_vop));
  v_data=(SInt*)GetImageData(GetVopV(cur_vop));
  a_data=(SInt*)GetImageData(prev_ori_alpha);

  if(image_type==0)  /* Y */
    {
    size_w=GetImageSizeX(GetVopY(cur_vop));

    /* Y repetitive-padding */
    y_block=(SInt*)LoadArea(y_data,h*block_size,v*block_size,
                            block_size,block_size,size_w);
    a_block=(SInt*)LoadArea(a_data,h*block_size,v*block_size,
                            block_size,block_size,size_w);

    LPEPaddingYBlock(a_block,y_block);

    SetArea(y_block,h*block_size,v*block_size,
            block_size,block_size,size_w,y_data);

    free((Char*)y_block);
    free((Char*)a_block);
    }
  else              /* U-V */
    {
    size_w=GetImageSizeX(GetVopU(cur_vop));

    /* U-V repetitive-padding */
    u_block=(SInt*)LoadArea(u_data,h*block_size,v*block_size,
                            block_size,block_size,size_w);
    v_block=(SInt*)LoadArea(v_data,h*block_size,v*block_size,
                            block_size,block_size,size_w);
    a_block=(SInt*)LoadArea(a_data,h*block_size,v*block_size,
                            block_size,block_size,size_w);

    LPEPaddingUVBlock(a_block,u_block,v_block);

    SetArea(u_block,h*block_size,v*block_size,
            block_size,block_size,size_w,u_data);
    SetArea(v_block,h*block_size,v*block_size,
            block_size,block_size,size_w,v_data);

    free((Char*)a_block);
    free((Char*)u_block);
    free((Char*)v_block);
    }

} /* TextureBlockPadding */

/***********************************************************CommentBegin******
 *
 * -- ZeroFillBlock --
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / Fernando Jaureguizar
 *
 * Created :
 *      30.08.96
 *
 * Purpose :
 *      Fills an 8x8 block of the Y image or the 8x8 blocks of the U and V
 *      images with zeroes, depending on the prev_ori_alpha
 *
 * Arguments in :
 *      Int     v,                  vertical coord. (in block units) of the
 *                                  block within the image
 *      Int     h,                  horizontal coord. (in block units) of the
 *                                  block within the image
 *      Int     image_type,         0=Y; 1=U and V
 *      Image   *prev_ori_alpha,    original reconstructed alpha plane data
 *
 * Arguments in/out :
 *      Vop     *cur_vop            Vop to pad
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 *
 * Side effects :
 *
 *
 * Description :
 *      This function performs the zeroes filling of an 8x8 block of the Y
 *      image or the 8x8 blocks of the U and V images of a given VOP, depending
 *      on the prev_ori_alpha values.
 *      Needed in the texture coding.
 *
 *      1) Filling is performed for an 8x8 luminance block (image_type=0)
 *         or for both chrominance blocks separately (image_type=1)
 *
 *      No input checkings are performed
 *
 * See also :
 *
 *
 * Modified :
 *      05.02.97 A. Pacheco: modified to fill the pixels acording the original
 *               alpha values (VM5.1)
 *
 ***********************************************************CommentEnd********/

Void
ZeroFillBlock (
   Int     v,                /* <-- vertical coord. (in block units)        */
   Int     h,                /* <-- horizontal coord. (in block units)      */
   Int     image_type,       /* <-- 0=Y; 1=U and V                          */
   Image   *prev_ori_alpha,  /* <-- previous original alpha plane data */
   Vop     *cur_vop          /* <-> Vop to pad                              */
   )
{
  SInt   *a_data;
  SInt   *y_data;
  SInt   *u_data;
  SInt   *v_data;
  Int    size_w,pos,j;

  if(image_type==0)
    {
    /* Y zero-padding */
    size_w=GetImageSizeX(GetVopY(cur_vop));

    y_data=(SInt*)GetImageData(GetVopY(cur_vop));
    a_data=(SInt*)GetImageData(prev_ori_alpha);

    for(j=0;j<B_SIZE;j++)
      {
      pos=(v*B_SIZE+j)*size_w+h*B_SIZE;

      if(a_data[pos]==0)
        y_data[pos]=0;
      pos++;
      if(a_data[pos]==0)
        y_data[pos]=0;
      pos++;
      if(a_data[pos]==0)
        y_data[pos]=0;
      pos++;
      if(a_data[pos]==0)
        y_data[pos]=0;
      pos++;

      if(a_data[pos]==0)
        y_data[pos]=0;
      pos++;
      if(a_data[pos]==0)
        y_data[pos]=0;
      pos++;
      if(a_data[pos]==0)
        y_data[pos]=0;
      pos++;
      if(a_data[pos]==0)
        y_data[pos]=0;
      }
    }
  else
    {
    /* U-V zero-padding */
    size_w=GetImageSizeX(GetVopU(cur_vop));

    u_data=(SInt*)GetImageData(GetVopU(cur_vop));
    v_data=(SInt*)GetImageData(GetVopV(cur_vop));
    a_data=(SInt*)GetImageData(prev_ori_alpha);

    for(j=0;j<B_SIZE;j++)
      {
      pos=(v*B_SIZE+j)*size_w+h*B_SIZE;

      if(a_data[pos]==0)
        u_data[pos]=v_data[pos]=0;
      pos++;
      if(a_data[pos]==0)
        u_data[pos]=v_data[pos]=0;
      pos++;
      if(a_data[pos]==0)
        u_data[pos]=v_data[pos]=0;
      pos++;
      if(a_data[pos]==0)
        u_data[pos]=v_data[pos]=0;
      pos++;

      if(a_data[pos]==0)
        u_data[pos]=v_data[pos]=0;
      pos++;
      if(a_data[pos]==0)
        u_data[pos]=v_data[pos]=0;
      pos++;
      if(a_data[pos]==0)
        u_data[pos]=v_data[pos]=0;
      pos++;
      if(a_data[pos]==0)
        u_data[pos]=v_data[pos]=0;
      }
    }

} /* ZeroFillBlock */

/***********************************************************CommentBegin******
 *
 * -- AllZeroFillBlock --
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / Fernando Jaureguizar
 *
 * Created :
 *      30.08.96
 *
 * Purpose :
 *      Fills an 8x8 block of the Y image or the 8x8 blocks of the U and V
 *      images with zeroes.
 *
 * Arguments in :
 *      Int     v,                  vertical coord. (in block units) of the
 *                                  block within the image
 *      Int     h,                  horizontal coord. (in block units) of the
 *                                  block within the image
 *      Int     image_type,         0=Y; 1=U and V
 *
 * Arguments in/out :
 *      Vop     *cur_vop            Vop to pad
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 *
 * Side effects :
 *
 *
 * Description :
 *      This function performs the zeroes filling of an 8x8 block of the Y
 *      image or the 8x8 blocks of the U and V images of a given VOP.
 *      Needed in the texture coding.
 *
 *      1) Filling is performed for an 8x8 luminance block (image_type=0)
 *         or for both chrominance blocks separately (image_type=1)
 *
 *      No input checkings are performed
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
AllZeroFillBlock (
   Int     v,                /* <-- vertical coord. (in block units)        */
   Int     h,                /* <-- horizontal coord. (in block units)      */
   Int     image_type,       /* <-- 0=Y; 1=U and V                          */
   Vop     *cur_vop          /* <-> Vop to pad                              */
   )
{
  SInt   *y_data;
  SInt   *u_data;
  SInt   *v_data;
  Int    size_w,pos,j;


  if(image_type==0)
    {
    /* Y zero-padding */
    size_w=GetImageSizeX(GetVopY(cur_vop));

    y_data=(SInt*)GetImageData(GetVopY(cur_vop));

    for(j=0;j<B_SIZE;j++)
      {
      pos=(v*B_SIZE+j)*size_w+h*B_SIZE;

      y_data[pos++]=0;
      y_data[pos++]=0;
      y_data[pos++]=0;
      y_data[pos++]=0;

      y_data[pos++]=0;
      y_data[pos++]=0;
      y_data[pos++]=0;
      y_data[pos  ]=0;
      }
    }
  else
    {
    /* U-V zero-padding */
    size_w=GetImageSizeX(GetVopU(cur_vop));

    u_data=(SInt*)GetImageData(GetVopU(cur_vop));
    v_data=(SInt*)GetImageData(GetVopV(cur_vop));

    for(j=0;j<B_SIZE;j++)
      {
      pos=(v*B_SIZE+j)*size_w+h*B_SIZE;

      u_data[pos]=v_data[pos]=0;
      pos++;
      u_data[pos]=v_data[pos]=0;
      pos++;
      u_data[pos]=v_data[pos]=0;
      pos++;
      u_data[pos]=v_data[pos]=0;
      pos++;

      u_data[pos]=v_data[pos]=0;
      pos++;
      u_data[pos]=v_data[pos]=0;
      pos++;
      u_data[pos]=v_data[pos]=0;
      pos++;
      u_data[pos]=v_data[pos]=0;
      }
    }

} /* AllZeroFillBlock */

/***********************************************************CommentBegin******
 *
 * -- LPEPaddingYBlock --
 *
 * Authors :
 *      UPM-GTI - Angel Pacheco / Fernando Jaureguizar
 *
 * Created :
 *      5.02.97
 *
 * Purpose :
 *      Fills an 8x8 block of the Y data following the LPE technique
 *
 * Arguments in :
 *      SInt*   a_data,             Alpha block
 *
 * Arguments in/out :
 *      SInt*   y_data,             Y block to pad
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 *
 * Side effects :
 *
 *
 * Description :
 *      This function performs the LPE filling of an 8x8 block of the Y
 *      data. Needed in the texture coding.
 *
 *      No input checkings are performed
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
LPEPaddingYBlock (
   SInt*   a_data,  /* Alpha block                                      */
   SInt*   y_data   /* Y block to pad                                   */
   )
{
  Int    i,j,mean,cont;
  SInt   *a_aux,*y_aux;

  /* compute the block mean */
  mean=cont=0;
  a_aux=a_data;y_aux=y_data;

  for(i=0;i<64;i++,a_data++,y_data++)
    if (*a_data!=0)
      {
      mean+=*y_data;
      cont++;
      }

  if(cont==0)
    {
    fprintf(stdout,"\nERROR: cont==0 and the shape cannot be transparent!\n");
    fflush(stdout);
    }
  else
    {
    mean= mean/cont;
    }

  a_data=a_aux;y_data=y_aux;

  /* assign the mean value to the transparent pixels */
  for(i=0;i<64;i++,a_data++,y_data++)
    if (*a_data==0)
      *y_data=mean;

  a_data=a_aux;y_data=y_aux;

  /* perform the low pass extrapolation operator over the transparent pixels */

  /* first column, first line */
  if(a_data[0]==0)
    y_data[0]=(y_data[8]+y_data[1])/2;
  /* rest, first line */
  for(i=1;i<7;i++)
    if(a_data[i]==0)
      y_data[i]=(y_data[i-1]+y_data[i+1]+y_data[i+8])/3;
  /* last column, first line */
  if(a_data[7]==0)
    y_data[7]=(y_data[6]+y_data[15])/2;

  for(j=1;j<7;j++)
    {
    /* first column */
    if(a_data[j*8]==0)
      y_data[j*8]=(y_data[(j-1)*8]+y_data[j*8+1]+y_data[(j+1)*8])/3;

    for(i=1;i<7;i++)
      if(a_data[j*8+i]==0)
        y_data[j*8+i]=(y_data[(j-1)*8+i]+y_data[j*8+i-1]+y_data[j*8+i+1]+
                       y_data[(j+1)*8+i])/4;

    /* last column */
    if(a_data[j*8+7]==0)
      y_data[j*8+7]=(y_data[(j-1)*8+7]+y_data[j*8+6]+y_data[(j+1)*8+7])/3;
    }

  /* first column, last line*/
  if(a_data[56]==0)
    y_data[56]=(y_data[48]+y_data[57])/2;
  /* rest, last line*/
  for(i=1;i<7;i++)
    if(a_data[56+i]==0)
      y_data[56+i]=(y_data[48+i]+y_data[56+i-1]+y_data[56+i+1])/3;
  /* last column, last line*/
  if(a_data[63]==0)
    y_data[63]=(y_data[55]+y_data[62])/2;

} /* LPEPaddingYBlock */

/***********************************************************CommentBegin******
 *
 * -- LPEPaddingUVBlock --
 *
 * Author :
 *      UPM-GTI - Angel Pacheco
 *
 * Created :
 *      5.02.97
 *
 * Purpose :
 *      Fills two 8x8 blocks of the UV data following the LPE technique
 *
 * Arguments in :
 *      SInt*   a_data,             Alpha block
 *
 * Arguments in/out :
 *      SInt*   u_data,             U block to pad
 *      SInt*   v_data,             V block to pad
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 *
 * Side effects :
 *
 *
 * Description :
 *      This function performs the LPE filling of two 8x8 blocks of the UV
 *      data. Needed in the texture coding.
 *
 *      No input checkings are performed
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
LPEPaddingUVBlock (
   SInt*   a_data,  /* Alpha block                                      */
   SInt*   u_data,  /* U block to pad                                   */
   SInt*   v_data   /* V block to pad                                   */
   )
{
  Int    i,j,mean_u, mean_v,cont;
  SInt   *a_aux,*u_aux,*v_aux;

  /* compute the block mean */
  mean_u=mean_v=cont=0;
  a_aux=a_data;
  u_aux=u_data;
  v_aux=v_data;

  for(i=0;i<64;i++,a_data++,u_data++,v_data++)
    if (*a_data!=0)
      {
      mean_u+=*u_data;
      mean_v+=*v_data;
      cont++;
      }
  if(cont==0)
    {
    fprintf(stdout,"\nERROR: cont==0 and the shape cannot be transparent!\n");
    fflush(stdout);
    }
  else
    {
    mean_u=mean_u/cont;
    mean_v=mean_v/cont;
    }
  a_data=a_aux;
  u_data=u_aux;
  v_data=v_aux;

  /* assign the mean value to the transparent pixels */
  for(i=0;i<64;i++,a_data++,u_data++,v_data++)
    if (*a_data==0)
      {
      *u_data=mean_u;
      *v_data=mean_v;
      }
  a_data=a_aux;
  u_data=u_aux;
  v_data=v_aux;

  /* perform the low pass extrapolation operator over the transparent pixels */

  /* first column, first line */
  if(a_data[0]==0)
    {
    u_data[0]=(u_data[8]+u_data[1])/2;
    v_data[0]=(v_data[8]+v_data[1])/2;
    }
  /* rest, first line */
  for(i=1;i<7;i++)
    if(a_data[i]==0)
      {
      u_data[i]=(u_data[i-1]+u_data[i+1]+u_data[i+8])/3;
      v_data[i]=(v_data[i-1]+v_data[i+1]+v_data[i+8])/3;
      }
  /* last column, first line */
  if(a_data[7]==0)
    {
    u_data[7]=(u_data[6]+u_data[15])/2;
    v_data[7]=(v_data[6]+v_data[15])/2;
    }

  for(j=1;j<7;j++)
    {
    /* first column */
    if(a_data[j*8]==0)
      {
      u_data[j*8]=(u_data[(j-1)*8]+u_data[j*8+1]+u_data[(j+1)*8])/3;
      v_data[j*8]=(v_data[(j-1)*8]+v_data[j*8+1]+v_data[(j+1)*8])/3;
      }

    for(i=1;i<7;i++)
      if(a_data[j*8+i]==0)
        {
        u_data[j*8+i]=(u_data[(j-1)*8+i]+u_data[j*8+i-1]+u_data[j*8+i+1]+
                       u_data[(j+1)*8+i])/4;
        v_data[j*8+i]=(v_data[(j-1)*8+i]+v_data[j*8+i-1]+v_data[j*8+i+1]+
                       v_data[(j+1)*8+i])/4;
        }

    /* last column */
    if(a_data[j*8+7]==0)
      {
      u_data[j*8+7]=(u_data[(j-1)*8+7]+u_data[j*8+6]+u_data[(j+1)*8+7])/3;
      v_data[j*8+7]=(v_data[(j-1)*8+7]+v_data[j*8+6]+v_data[(j+1)*8+7])/3;
      }
    }

  /* first column, last line*/
  if(a_data[56]==0)
    {
    u_data[56]=(u_data[48]+u_data[57])/2;
    v_data[56]=(v_data[48]+v_data[57])/2;
    }
  /* rest, last line*/
  for(i=1;i<7;i++)
    if(a_data[56+i]==0)
      {
      u_data[56+i]=(u_data[48+i]+u_data[56+i-1]+u_data[56+i+1])/3;
      v_data[56+i]=(v_data[48+i]+v_data[56+i-1]+v_data[56+i+1])/3;
      }
  /* last column, last line*/
  if(a_data[63]==0)
    {
    u_data[63]=(u_data[55]+u_data[62])/2;
    v_data[63]=(v_data[55]+v_data[62])/2;
    }

} /* LPEPaddingUVBlock */

/***********************************************************CommentBegin******
 *
 * -- VopPadding --
 *
 * Author :
 *      HHI - Minhua Zhou
 *
 * Created :
 *      26.05.97
 *
 * Purpose :
 *      padding a VOP
 *
 * Arguments in :
 *
 *
 * Arguments in/out :
 *      Vop *curr_vop
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *    14.04.1998:  Minhua Zhou added FreeImage(GetVopShapeMode(curr_vop_padded));
 *
 ***********************************************************CommentEnd********/

Void
VopPadding(
   Vop   *curr_vop
   )
{
  Int   edge = 16;
  Vop   *curr_vop_padded;

  curr_vop_padded = AllocVop (GetVopWidth(curr_vop) + 2 * edge,
                              GetVopHeight(curr_vop) + 2 * edge);
  curr_vop_padded->hor_spat_ref=curr_vop->hor_spat_ref-edge;
  curr_vop_padded->ver_spat_ref=curr_vop->ver_spat_ref-edge;

  /* Store width and height as integer multiples of 16 */
  PutVopWidth(GetVopWidth(curr_vop)+2*edge,curr_vop_padded);
  PutVopHeight(GetVopHeight(curr_vop)+2*edge,curr_vop_padded);

  MakeImageEdge(GetVopY(curr_vop), edge, GetVopY(curr_vop_padded));
  MakeImageEdge(GetVopU(curr_vop), edge/2, GetVopU(curr_vop_padded));
  MakeImageEdge(GetVopV(curr_vop), edge/2, GetVopV(curr_vop_padded));
  MakeImageEdge(GetVopA(curr_vop), edge, GetVopA(curr_vop_padded));
  MakeImageEdge(GetVopAuv(curr_vop), edge/2, GetVopAuv(curr_vop_padded));

  curr_vop_padded->arbitrary_shape=GetVopShape(curr_vop);
  PutVopBitsPerPixel(GetVopBitsPerPixel(curr_vop),curr_vop_padded);  

  if(GetVopShape(curr_vop)==0)
    RepetitivePadding (0, curr_vop_padded);
  else
    MacroblockBasedPadding (GetVopA(curr_vop_padded), curr_vop_padded);

  PutVopA(GetVopA(curr_vop_padded),curr_vop);
  PutVopAuv(GetVopAuv(curr_vop_padded),curr_vop);
  PutVopY(GetVopY(curr_vop_padded),curr_vop);
  PutVopU(GetVopU(curr_vop_padded),curr_vop);
  PutVopV(GetVopV(curr_vop_padded),curr_vop);
  FreeImage(GetVopQP(curr_vop_padded));
  FreeImage(GetVopShapeMode(curr_vop_padded));
  SfreeVop(curr_vop_padded);
  curr_vop->hor_spat_ref-=edge;
  curr_vop->ver_spat_ref-=edge;
  PutVopWidth(GetVopWidth(curr_vop)+2*edge,curr_vop);
  PutVopHeight(GetVopHeight(curr_vop)+2*edge,curr_vop);
}

/***********************************************************CommentBegin******
 *
 * -- CloneVop_TMP --
 *
 * Author :
 *      HHI - Minhua Zhou
 *
 * Created :
 *      29.05.97
 *
 * Purpose :
 *      Clone a VOP
 *
 * Arguments in :
 *     Vop *curr_vop
 *
 * Arguments in/out
 *
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *      17.04.1998 Minhua Zhou: added shape mode
 *
 ***********************************************************CommentEnd********/

Vop *
CloneVop_TMP(
   Vop   *curr_vop
   )
{
  Int    edge = 16;
  Vop    *curr_vop_cut;
  SInt   *data_in,*data_out;
  Int    height = GetVopHeight(curr_vop),i,j;
  Int    width  = GetVopWidth(curr_vop);

  curr_vop_cut = AllocVop (GetVopWidth(curr_vop) - 2 * edge,
                           GetVopHeight(curr_vop) - 2 * edge);
  PutVopHorSpatRef(GetVopHorSpatRef(curr_vop)+edge,curr_vop_cut);
  PutVopVerSpatRef(GetVopVerSpatRef(curr_vop)+edge,curr_vop_cut);

  data_in = (SInt *) GetImageData(GetVopA(curr_vop));
  data_out = (SInt *) GetImageData(GetVopA(curr_vop_cut));

  for (i=0;i<height-2*edge;i++)
    for (j=0;j<width-2*edge;j++)
      data_out[i*(width-2*edge)+j] = data_in[(i+edge)*width+j+edge];

  data_in = (SInt *) GetImageData(GetVopY(curr_vop));
  data_out = (SInt *) GetImageData(GetVopY(curr_vop_cut));

  for (i=0;i<height-2*edge;i++)
    for (j=0;j<width-2*edge;j++)
      data_out[i*(width-2*edge)+j] = data_in[(i+edge)*width+j+edge];

  width/=2;
  height/=2;

  data_in = (SInt *) GetImageData(GetVopU(curr_vop));
  data_out = (SInt *) GetImageData(GetVopU(curr_vop_cut));

  for (i=0;i<height-edge;i++)
    for (j=0;j<width-edge;j++)
      data_out[i*(width-edge)+j] = data_in[(i+edge/2)*width+j+edge/2];

  data_in = (SInt *) GetImageData(GetVopV(curr_vop));
  data_out = (SInt *) GetImageData(GetVopV(curr_vop_cut));

  for (i=0;i<height-edge;i++)
    for (j=0;j<width-edge;j++)
      data_out[i*(width-edge)+j] = data_in[(i+edge/2)*width+j+edge/2];

  data_in = (SInt *) GetImageData(GetVopAuv(curr_vop));
  data_out = (SInt *) GetImageData(GetVopAuv(curr_vop_cut));

  for (i=0;i<height-edge;i++)
    for (j=0;j<width-edge;j++)
      data_out[i*(width-edge)+j] = data_in[(i+edge/2)*width+j+edge/2];

  CopyImage(GetVopQP(curr_vop),GetVopQP(curr_vop_cut));
  CopyImage(GetVopShapeMode(curr_vop),GetVopShapeMode(curr_vop_cut));
  return curr_vop_cut;
}

/***********************************************************CommentBegin******
 *
 * -- PadMB --
 *
 * Author :
 *      Noel Brady
 *
 *
 * Created :
 *      14.11.97
 *
 * Purpose :
 *
 *
 * Arguments in :
 *      Vop     *rec_vop          alpha plane data
 *      Image   *MB_decisions     encoding mode for each MB
 *      Int     i
 *      Int     j
 *
 * Arguments in/out
 *      Vop     *cur_vop          Vop to pad
 *
 * Arguments out :
 *
 *
 * Return values :
 *
 *
 * Side effects :
 *
 *
 * Description :
 *      Pads the blocks of a MB. Should be used prior to encoding
 *      the MB.
 *
 *
 * See also :
 *
 *
 * Modified :
 *
 *
 ***********************************************************CommentEnd********/

Void
PadMB(
   Vop     *rec_vop,         /* <-- previous original alpha plane data */
   Image   *MB_decisions,    /* <-- encoding mode for each MB               */
   Vop     *cur_vop,         /* <-> Vop to pad                              */
   Int     i,
   Int     j
   )
{
  Image   *alpha = GetVopA(rec_vop);
  Image   *alpha_uv = GetVopAuv(rec_vop);
  Image   *block = AllocImage(8,8,SHORT_TYPE);
  SInt    *mb_modes = (SInt *)GetImageData(MB_decisions);
  SInt    *p = (SInt *)GetImageData(block);
  Int      w_size = GetImageSizeX(MB_decisions),
           mb_pos,
           padding_type,
           transparent_nb,
           mb_pos_x = i*MB_SIZE,
           mb_pos_y = j*MB_SIZE,
           type,k;

  mb_pos=w_size*j+i;

  if (mb_modes[mb_pos]==MBM_INTRA)
    padding_type=1;
  else /* MBM_INTER16) || MBM_INTER8 or (MBM_TRANSPARENT||MBM_OUT??*/
    padding_type=0;

  /* Y blocks */

  transparent_nb = 0;
  GetSubImage(alpha,block,mb_pos_x,mb_pos_y);
  for (k=0;k<64;k++)
    if (!p[k]) transparent_nb++;
  if (transparent_nb == 64)
    type = MBM_TRANSPARENT;
  else if (transparent_nb == 0)
    type = MBM_OPAQUE;
  else
    type = MBM_BOUNDARY;

  if(type==MBM_TRANSPARENT)
    AllZeroFillBlock(j*2  ,i*2  ,0,cur_vop);
  else if (type==MBM_BOUNDARY)
    TextureBlockPadding(j*2,i*2,padding_type,B_SIZE,alpha,
                        0,cur_vop);
  /* else MBM_OPAQUE, do nothing */

  transparent_nb = 0;
  GetSubImage(alpha,block,mb_pos_x+B_SIZE,mb_pos_y);
  for (k=0;k<64;k++)
    if (!p[k]) transparent_nb++;
  if (transparent_nb == 64)
    type = MBM_TRANSPARENT;
  else if (transparent_nb == 0)
    type = MBM_OPAQUE;
  else
    type = MBM_BOUNDARY;

  if(type==MBM_TRANSPARENT)
    AllZeroFillBlock(j*2  ,i*2+1  ,0,cur_vop);
  else if (type==MBM_BOUNDARY)
    TextureBlockPadding(j*2,i*2+1,padding_type,B_SIZE,alpha,
                        0,cur_vop);
  /* else MBM_OPAQUE, do nothing */

  transparent_nb = 0;
  GetSubImage(alpha,block,mb_pos_x,mb_pos_y+B_SIZE);
  for (k=0;k<64;k++)
    if (!p[k]) transparent_nb++;
  if (transparent_nb == 64)
    type = MBM_TRANSPARENT;
  else if (transparent_nb == 0)
    type = MBM_OPAQUE;
  else
    type = MBM_BOUNDARY;

  if(type==MBM_TRANSPARENT)
    AllZeroFillBlock(j*2+1  ,i*2  ,0,cur_vop);
  else if (type==MBM_BOUNDARY)
    TextureBlockPadding(j*2+1,i*2,padding_type,B_SIZE,alpha,
                        0,cur_vop);
  /* else MBM_OPAQUE, do nothing */

  transparent_nb = 0;
  GetSubImage(alpha,block,mb_pos_x+B_SIZE,mb_pos_y+B_SIZE);
  for (k=0;k<64;k++)
    if (!p[k]) transparent_nb++;
  if (transparent_nb == 64)
    type = MBM_TRANSPARENT;
  else if (transparent_nb == 0)
    type = MBM_OPAQUE;
  else
    type = MBM_BOUNDARY;

  if(type==MBM_TRANSPARENT)
    AllZeroFillBlock(j*2+1  ,i*2+1  ,0,cur_vop);
  else if (type==MBM_BOUNDARY)
    TextureBlockPadding(j*2+1,i*2+1,padding_type,B_SIZE,alpha,
                        0,cur_vop);
  /* else MBM_OPAQUE, do nothing */

  /* U-V blocks */
  transparent_nb = 0;
  GetSubImage(alpha_uv,block,mb_pos_x/2,mb_pos_y/2);
  for (k=0;k<64;k++)
    if (!p[k]) transparent_nb++;
  if (transparent_nb == 64)
    type = MBM_TRANSPARENT;
  else if (transparent_nb == 0)
    type = MBM_OPAQUE;
  else
    type = MBM_BOUNDARY;

  if(type==MBM_TRANSPARENT)
    AllZeroFillBlock(j,i,1,cur_vop);
  else if(type==MBM_BOUNDARY)
    /* has alpha_sub*/
    TextureBlockPadding(j,i ,padding_type,B_SIZE, alpha_uv,1,cur_vop);
  /* else MBM_OPAQUE, do nothing */

  FreeImage(block);
  return;
}
