
/*!
 *************************************************************************************
 * \file input.c
 *
 * \brief
 *    Input related functions
 *
 * \author
 *    Main contributors (see contributors.h for copyright, address and affiliation details)
 *     - Karsten Sühring                 <suehring@hhi.de>
 *     - Alexis Michael Tourapis         <alexismt@ieee.org>
 *     
 *************************************************************************************
 */
#include "contributors.h"

#include <math.h>
#include <time.h>

#include "global.h"
#include "input.h"
#include "img_io.h"
#include "memalloc.h"

void buf2img_basic    ( imgpel** imgX, unsigned char* buf, int size_x, int size_y, int o_size_x, int o_size_y, int symbol_size_in_bytes, int bitshift);
void buf2img_endian   ( imgpel** imgX, unsigned char* buf, int size_x, int size_y, int o_size_x, int o_size_y, int symbol_size_in_bytes, int bitshift);
void buf2img_bitshift ( imgpel** imgX, unsigned char* buf, int size_x, int size_y, int o_size_x, int o_size_y, int symbol_size_in_bytes, int bitshift);
void fillPlane        ( imgpel** imgX, int nVal, int size_x, int size_y);

/*!
 ************************************************************************
 * \brief
 *      checks if the System is big- or little-endian
 * \return
 *      0, little-endian (e.g. Intel architectures)
 *      1, big-endian (e.g. SPARC, MIPS, PowerPC)
 ************************************************************************
 */
void initInput(VideoParameters *p_Vid, FrameFormat *source, FrameFormat *output)
{
  if (source->bit_depth[0] == output->bit_depth[0] && source->bit_depth[1] == output->bit_depth[1])
  {
    if (( sizeof(char) != sizeof (imgpel)) && testEndian())
      p_Vid->buf2img = buf2img_endian;
    else
      p_Vid->buf2img = buf2img_basic;
  }
  else
    p_Vid->buf2img = buf2img_bitshift;
}


/*!
 ************************************************************************
 * \brief
 *      checks if the System is big- or little-endian
 * \return
 *      0, little-endian (e.g. Intel architectures)
 *      1, big-endian (e.g. SPARC, MIPS, PowerPC)
 ************************************************************************
 */
int testEndian(void)
{
  short s;
  byte *p;

  p=(byte*)&s;

  s=1;

  return (*p==0);
}

#if (DEBUG_BITDEPTH)
/*!
 ************************************************************************
 * \brief
 *    Masking to ensure data within appropriate range
 ************************************************************************
 */
static void MaskMSBs (imgpel** imgX, int mask, int width, int height)
{
  int i,j;

  for (j=0; j < height; j++)
  {
    for (i=0; i < width; i++)
    {
      imgX[j][i]=(imgpel) (imgX[j][i] & mask);
    }
  }
}
#endif

/*!
 ************************************************************************
 * \brief
 *    Fill plane with constant value
 ************************************************************************
 */
void fillPlane ( imgpel** imgX,                 //!< Pointer to image plane
                int nVal,                       //!< Fill value (currently 0 <= nVal < 256)
                int size_x,                     //!< horizontal size of picture
                int size_y                      //!< vertical size of picture
                )
{
  int j, i;

  if (sizeof(imgpel) == sizeof(char))
  {
    memset(imgX[0], nVal, size_y * size_x);
  }
  else
  {
    for (j = 0; j < size_y; j++) 
    {
      for (i = 0; i < size_x; i++) 
      {
        imgX[j][i] = (imgpel) nVal;
      }
    }
  }
}

/*!
 ************************************************************************
 * \brief
 *    Deinterleave file read buffer to source picture structure
 ************************************************************************
 */
static void deinterleave ( unsigned char** input,       //!< input buffer
                           unsigned char** output,      //!< output buffer
                           FrameFormat *source,         //!< format of source buffer
                           int symbol_size_in_bytes     //!< number of bytes per symbol
                          )
{
  // original buffer
  unsigned char *icmp0 = *input;
  // final buffer
  unsigned char *ocmp0 = *output;

  unsigned char *ocmp1 = ocmp0 + symbol_size_in_bytes * source->size_cmp[0];
  unsigned char *ocmp2 = ocmp1 + symbol_size_in_bytes * source->size_cmp[1];

  int i;
  
  if (source->yuv_format == YUV420) // UYYVYY 
  {
    for (i = 0; i < source->size_cmp[1]; i++)
    {
      memcpy(ocmp1, icmp0, symbol_size_in_bytes);
      ocmp1 += symbol_size_in_bytes;
      icmp0 += symbol_size_in_bytes;
      memcpy(ocmp0, icmp0, 2 * symbol_size_in_bytes);
      ocmp0 += 2 * symbol_size_in_bytes;
      icmp0 += 2 * symbol_size_in_bytes;
      memcpy(ocmp2, icmp0, symbol_size_in_bytes);
      ocmp2 += symbol_size_in_bytes;
      icmp0 += symbol_size_in_bytes;
      memcpy(ocmp0, icmp0, 2 * symbol_size_in_bytes);
      ocmp0 += 2 * symbol_size_in_bytes;
      icmp0 += 2 * symbol_size_in_bytes;
    }

    // flip buffers
    icmp0  = *input;
    *input  = *output;
    *output = icmp0;
  }
  if (source->yuv_format == YUV422) // YUYV/YUY2. We should also maybe add UYVY given it's popularity
  {
    for (i = 0; i < source->size_cmp[1]; i++)
    {
      // Y
      memcpy(ocmp0, icmp0, symbol_size_in_bytes);
      ocmp0 += symbol_size_in_bytes;
      icmp0 += symbol_size_in_bytes;
      // U
      memcpy(ocmp1, icmp0, symbol_size_in_bytes);
      ocmp1 += symbol_size_in_bytes;
      icmp0 += symbol_size_in_bytes;
      // Y
      memcpy(ocmp0, icmp0, symbol_size_in_bytes);
      ocmp0 += symbol_size_in_bytes;
      icmp0 += symbol_size_in_bytes;
      // V
      memcpy(ocmp2, icmp0, symbol_size_in_bytes);
      ocmp2 += symbol_size_in_bytes;
      icmp0 += symbol_size_in_bytes;
    }

    // flip buffers
    icmp0  = *input;
    *input  = *output;
    *output = icmp0;
  }
  else if (source->yuv_format == YUV444)
  {
    for (i = 0; i < source->size_cmp[0]; i++)
    {
      memcpy(ocmp0, icmp0, symbol_size_in_bytes);
      ocmp0 += symbol_size_in_bytes;
      icmp0 += symbol_size_in_bytes;
      memcpy(ocmp1, icmp0, symbol_size_in_bytes);
      ocmp1 += symbol_size_in_bytes;
      icmp0 += symbol_size_in_bytes;
      memcpy(ocmp2, icmp0, symbol_size_in_bytes);
      ocmp2 += symbol_size_in_bytes;
      icmp0 += symbol_size_in_bytes;
    }
    // flip buffers
    icmp0  = *input;
    *input  = *output;
    *output = icmp0;
  }
}

/*!
 ************************************************************************
 * \brief
 *    Convert file read buffer to source picture structure
 ************************************************************************
 */
void buf2img_bitshift ( imgpel** imgX,           //!< Pointer to image plane
                       unsigned char* buf,       //!< Buffer for file output
                       int size_x,               //!< horizontal size of picture
                       int size_y,               //!< vertical size of picture
                       int o_size_x,             //!< horizontal size of picture
                       int o_size_y,             //!< vertical size of picture
                       int symbol_size_in_bytes, //!< number of bytes in file used for one pixel
                       int bitshift              //!< variable for bitdepth expansion
                       )
{
  int i,j;

  uint16 tmp16, ui16;
  unsigned long  tmp32, ui32;
  // This test should be done once.
  if (((symbol_size_in_bytes << 3) - bitshift) > (sizeof(imgpel)<< 3))
  {
    error ("Source picture has higher bit depth than imgpel data type. \nPlease recompile with larger data type for imgpel.", 500);
  }

  if (testEndian())
  {
    if (size_x != o_size_x || size_y != o_size_y)
    {
      error ("Rescaling not supported in big endian architectures. ", 500);
    }

    // big endian
    switch (symbol_size_in_bytes)
    {
    case 1:
      {
        for(j = 0; j < o_size_y; j++)
          for(i = 0; i < o_size_x; i++)
          {
            imgX[j][i]= (imgpel) rshift_rnd(buf[i + j*size_x], bitshift);
          }
          break;
      }
    case 2:
      {
        for(j = 0; j < o_size_y; j++)
          for(i = 0; i < o_size_x; i++)
          {
            memcpy(&tmp16, buf+((i+j*size_x)*2), 2);
            ui16  = (tmp16 >> 8) | ((tmp16&0xFF)<<8);
            imgX[j][i] = (imgpel) rshift_rnd(ui16, bitshift);
          }
          break;
      }
    case 4:
      {
        for(j = 0; j < o_size_y; j++)
          for(i = 0; i < o_size_x; i++)
          {
            memcpy(&tmp32, buf+((i+j*size_x)*4), 4);
            ui32  = ((tmp32&0xFF00)<<8) | ((tmp32&0xFF)<<24) | ((tmp32&0xFF0000)>>8) | ((tmp32&0xFF000000)>>24);
            imgX[j][i] = (imgpel) rshift_rnd(ui32, bitshift);
          }
      }
    default:
      {
        error ("reading only from formats of 8, 16 or 32 bit allowed on big endian architecture", 500);
        break;
      }
    }
  }
  else
  {
    // little endian
      int j_pos;
      if (size_x == o_size_x && size_y == o_size_y)
      {
        for (j = 0; j < o_size_y; j++)
        {
          j_pos = j*size_x;
          for (i = 0; i < o_size_x; i++)
          {
            ui16=0;
            memcpy(&(ui16), buf + ((i + j_pos) * symbol_size_in_bytes), symbol_size_in_bytes);
            imgX[j][i] = (imgpel) rshift_rnd(ui16,bitshift);
          }
        }  
      }
      else
      {
        int iminwidth   = imin(size_x, o_size_x);
        int iminheight  = imin(size_y, o_size_y);
        int dst_offset_x  = 0, dst_offset_y = 0;        
        int offset_x = 0, offset_y = 0; // currently not used

        // determine whether we need to center the copied frame or crop it
        if ( o_size_x >= size_x ) 
          dst_offset_x = ( o_size_x  - size_x  ) >> 1;

        if (o_size_y >= size_y) 
          dst_offset_y = ( o_size_y - size_y ) >> 1;

        // check copied area to avoid copying memory garbage
        // source
        iminwidth  =  ( (offset_x + iminwidth ) > size_x ) ? (size_x  - offset_x) : iminwidth;
        iminheight =  ( (offset_y + iminheight) > size_y ) ? (size_y - offset_y) : iminheight;
        // destination
        iminwidth  =  ( (dst_offset_x + iminwidth ) > o_size_x  ) ? (o_size_x  - dst_offset_x) : iminwidth;
        iminheight =  ( (dst_offset_y + iminheight) > o_size_y )  ? (o_size_y - dst_offset_y) : iminheight;

        for (j=0; j < iminheight; j++)
        {        
          j_pos = (j + offset_y) * size_x + offset_x;
          for (i=0; i < iminwidth; i++)
          {
            ui16=0;
            memcpy(&(ui16), buf + ((i + j_pos) * symbol_size_in_bytes), symbol_size_in_bytes);
            imgX[j + dst_offset_y][i + dst_offset_x] = (imgpel) rshift_rnd(ui16,bitshift);
          }
        }    
      }
  }
}


/*!
 ************************************************************************
 * \brief
 *    Convert file read buffer to source picture structure
 ************************************************************************
 */
void buf2img_basic (imgpel** imgX,            //!< Pointer to image plane
                    unsigned char* buf,       //!< Buffer for file output
                    int size_x,               //!< horizontal size of picture
                    int size_y,               //!< vertical size of picture
                    int o_size_x,             //!< horizontal size of picture
                    int o_size_y,             //!< vertical size of picture
                    int symbol_size_in_bytes, //!< number of bytes in file used for one pixel
                    int dummy                 //!< dummy variable used for allowing function pointer use
                    )
{
  int i,j;
  unsigned char* temp_buf = buf;

  if (symbol_size_in_bytes> sizeof(imgpel))
  {
    error ("Source picture has higher bit depth than imgpel data type. \nPlease recompile with larger data type for imgpel.", 500);
  }

  if (( sizeof (imgpel) == symbol_size_in_bytes))
  {    
    // imgpel == pixel_in_file -> simple copy
    if (size_x == o_size_x && size_y == o_size_y)
      memcpy(&imgX[0][0], temp_buf, size_x * size_y * sizeof(imgpel));
    else
    {
      int iminwidth   = imin(size_x, o_size_x);
      int iminheight  = imin(size_y, o_size_y);
      int dst_offset_x  = 0, dst_offset_y = 0;
      int offset_x = 0, offset_y = 0; // currently not used
      
      // determine whether we need to center the copied frame or crop it
      if ( o_size_x >= size_x ) 
        dst_offset_x = ( o_size_x  - size_x  ) >> 1;

      if (o_size_y >= size_y) 
        dst_offset_y = ( o_size_y - size_y ) >> 1;

      // check copied area to avoid copying memory garbage
      // source
      iminwidth  =  ( (offset_x + iminwidth ) > size_x ) ? (size_x  - offset_x) : iminwidth;
      iminheight =  ( (offset_y + iminheight) > size_y ) ? (size_y - offset_y) : iminheight;
      // destination
      iminwidth  =  ( (dst_offset_x + iminwidth ) > o_size_x  ) ? (o_size_x  - dst_offset_x) : iminwidth;
      iminheight =  ( (dst_offset_y + iminheight) > o_size_y )  ? (o_size_y - dst_offset_y) : iminheight;

      for (i=0; i<iminheight;i++) {
        memcpy(&imgX[i + dst_offset_y][dst_offset_x], &(temp_buf[(i + offset_y) * size_x + offset_x]), iminwidth * sizeof(imgpel));
      }
    }
  }
  else
  {
    int j_pos;
    uint16 ui16;
    if (size_x == o_size_x && size_y == o_size_y)
    {
      for (j=0; j < o_size_y; j++)
      {
        j_pos = j * size_x;
        for (i=0; i < o_size_x; i++)
        {
          ui16=0;          
          memcpy(&(ui16), buf + ((i + j_pos) * symbol_size_in_bytes), symbol_size_in_bytes);
          imgX[j][i]= (imgpel) ui16;
        }
      }    
    }
    else
    {
      int iminwidth   = imin(size_x, o_size_x);
      int iminheight  = imin(size_y, o_size_y);
      int dst_offset_x  = 0, dst_offset_y = 0;
      int offset_x = 0, offset_y = 0; // currently not used
      
      // determine whether we need to center the copied frame or crop it
      if ( o_size_x >= size_x ) 
        dst_offset_x = ( o_size_x  - size_x  ) >> 1;

      if (o_size_y >= size_y) 
        dst_offset_y = ( o_size_y - size_y ) >> 1;

      // check copied area to avoid copying memory garbage
      // source
      iminwidth  =  ( (offset_x + iminwidth ) > size_x ) ? (size_x  - offset_x) : iminwidth;
      iminheight =  ( (offset_y + iminheight) > size_y ) ? (size_y - offset_y) : iminheight;
      // destination
      iminwidth  =  ( (dst_offset_x + iminwidth ) > o_size_x  ) ? (o_size_x  - dst_offset_x) : iminwidth;
      iminheight =  ( (dst_offset_y + iminheight) > o_size_y )  ? (o_size_y - dst_offset_y) : iminheight;

      for (j = 0; j < iminheight; j++) {
        memcpy(&imgX[j + dst_offset_y][dst_offset_x], &(temp_buf[(j + offset_y) * size_x + offset_x]), iminwidth * sizeof(imgpel));
      }
      for (j=0; j < iminheight; j++)
      {        
        j_pos = (j + offset_y) * size_x + offset_x;
        for (i=0; i < iminwidth; i++)
        {
          ui16 = 0;
          memcpy(&(ui16), buf + ((i + j_pos) * symbol_size_in_bytes), symbol_size_in_bytes);
          imgX[j + dst_offset_y][i + dst_offset_x]= (imgpel) ui16;
        }
      }    
    }
  }
}

/*!
 ************************************************************************
 * \brief
 *    Convert file read buffer to source picture structure
 ************************************************************************
 */
void buf2img_endian (imgpel** imgX,            //!< Pointer to image plane
                     unsigned char* buf,       //!< Buffer for file output
                     int size_x,               //!< horizontal size of picture
                     int size_y,               //!< vertical size of picture
                     int o_size_x,             //!< horizontal size of picture
                     int o_size_y,             //!< vertical size of picture
                     int symbol_size_in_bytes, //!< number of bytes in file used for one pixel
                     int dummy                 //!< dummy variable used for allowing function pointer use
                     )
{
  int i,j;

  uint16 tmp16, ui16;
  unsigned long  tmp32, ui32;

  if (symbol_size_in_bytes > sizeof(imgpel))
  {
    error ("Source picture has higher bit depth than imgpel data type. \nPlease recompile with larger data type for imgpel.", 500);
  }

  if (size_x != o_size_x || size_y != o_size_y)
  {
    error ("Rescaling not supported in big endian architectures. ", 500);
  }

  // big endian
  switch (symbol_size_in_bytes)
  {
  case 1:
    {
      for(j=0;j<size_y;j++)
      {
        for(i=0;i<size_x;i++)
        {
          imgX[j][i]= (imgpel) buf[i + j*size_x];
        }
      }
      break;
    }
  case 2:
    {
      for(j=0;j<size_y;j++)
      {
        for(i=0;i<size_x;i++)
        {
          memcpy(&tmp16, buf+((i+j*size_x)*2), 2);
          ui16  = (tmp16 >> 8) | ((tmp16&0xFF)<<8);
          imgX[j][i] = (imgpel) ui16;
        }
      }
      break;
    }
  case 4:
    {
      for(j=0;j<size_y;j++)
      {
        for(i=0;i<size_x;i++)
        {
          memcpy(&tmp32, buf+((i+j*size_x)*4), 4);
          ui32  = ((tmp32&0xFF00)<<8) | ((tmp32&0xFF)<<24) | ((tmp32&0xFF0000)>>8) | ((tmp32&0xFF000000)>>24);
          imgX[j][i] = (imgpel) ui32;
        }
      }
      break;
    }
  default:
    {
      error ("reading only from formats of 8, 16 or 32 bit allowed on big endian architecture", 500);
      break;
    }
  }   
}

/*!
 ************************************************************************
 * \brief
 *    Create Frame Memory buffer
 *
 ************************************************************************
 */
void AllocateFrameMemory (VideoParameters *p_Vid, InputParameters *p_Inp, FrameFormat *source)
{
  if (NULL == (p_Vid->buf = malloc (source->size * source->pic_unit_size_shift3)))
    no_mem_exit("AllocateFrameMemory: p_Vid->buf");
  if (p_Inp->input_file1.is_interleaved)
  {
    if (NULL == (p_Vid->ibuf = malloc (source->size * source->pic_unit_size_shift3)))
      no_mem_exit("AllocateFrameMemory: p_Vid->ibuf");
  }
}

/*!
 ************************************************************************
 * \brief
 *    Delete Frame Memory buffer
 *
 ************************************************************************
 */
void DeleteFrameMemory (VideoParameters *p_Vid)
{
  if (p_Vid->buf != NULL)
    free (p_Vid->buf);
  if (p_Vid->ibuf != NULL)
    free (p_Vid->ibuf);
}

/*!
 ************************************************************************
 * \brief
 *    Reads one new frame from file
 *
 * \param input_file
 *    structure containing information (filename, format) about the source file
 * \param FrameNoInFile
 *    Frame number in the source file
 * \param HeaderSize
 *    Number of bytes in the source file to be skipped
 * \param source
 *    source file (on disk) information 
 * \param output
 *    output file (for encoding) information
 * \param pImage
 *    Image planes
 ************************************************************************
 */
int read_one_frame (VideoParameters *p_Vid, VideoDataFile *input_file, int FrameNoInFile, int HeaderSize, FrameFormat *source, FrameFormat *output, imgpel **pImage[3])
{
  InputParameters *p_Inp = p_Vid->p_Inp;
  int file_read = 0;
	unsigned int symbol_size_in_bytes = source->pic_unit_size_shift3;

	const int bytes_y = source->size_cmp[0] * symbol_size_in_bytes;
	const int bytes_uv = source->size_cmp[1] * symbol_size_in_bytes;
	int bit_scale;  

	Boolean rgb_input = (Boolean) (source->color_model == CM_RGB && source->yuv_format == YUV444);

	if (input_file->is_concatenated == 0)
	{    
		if (input_file->vdtype == VIDEO_TIFF)
    {
			file_read = ReadTIFFImage     (p_Inp, input_file, FrameNoInFile, source, p_Vid->buf);
    }
		else
    {
			file_read = ReadFrameSeparate (p_Inp, input_file, FrameNoInFile, HeaderSize, source, p_Vid->buf);
    }
	}
	else
	{
		file_read = ReadFrameConcatenated (p_Inp, input_file, FrameNoInFile, HeaderSize, source, p_Vid->buf);
	}
  if ( !file_read )
  {
    return 0;
  }

	// Deinterleave input source
	if (input_file->is_interleaved)
	{
		deinterleave ( &p_Vid->buf, &p_Vid->ibuf, source, symbol_size_in_bytes);
	}

	bit_scale = source->bit_depth[0] - output->bit_depth[0];  

	if(rgb_input)
		p_Vid->buf2img(pImage[0], p_Vid->buf + bytes_y, source->width[0], source->height[0], output->width[0], output->height[0], symbol_size_in_bytes, bit_scale);
	else
		p_Vid->buf2img(pImage[0], p_Vid->buf, source->width[0], source->height[0], output->width[0], output->height[0], symbol_size_in_bytes, bit_scale);

#if (DEBUG_BITDEPTH)
	MaskMSBs(pImage[0], ((1 << output->bit_depth[0]) - 1), output->width[0], output->height[0]);
#endif

	if (p_Vid->yuv_format != YUV400)
	{
		bit_scale = source->bit_depth[1] - output->bit_depth[1];
#if (ALLOW_GRAYSCALE)
		if (!p_Inp->grayscale) 
#endif
		{
			if(rgb_input)
				p_Vid->buf2img(pImage[1], p_Vid->buf + bytes_y + bytes_uv, source->width[1], source->height[1], output->width[1], output->height[1], symbol_size_in_bytes, bit_scale);
			else 
				p_Vid->buf2img(pImage[1], p_Vid->buf + bytes_y, source->width[1], source->height[1], output->width[1], output->height[1], symbol_size_in_bytes, bit_scale);

			bit_scale = source->bit_depth[2] - output->bit_depth[2];
			if(rgb_input)
				p_Vid->buf2img(pImage[2], p_Vid->buf, source->width[1], source->height[1], output->width[1], output->height[1], symbol_size_in_bytes, bit_scale);
			else
				p_Vid->buf2img(pImage[2], p_Vid->buf + bytes_y + bytes_uv, source->width[1], source->height[1], output->width[1], output->height[1], symbol_size_in_bytes, bit_scale);
		}
#if (DEBUG_BITDEPTH)
		MaskMSBs(pImage[1], ((1 << output->bit_depth[1]) - 1), output->width[1], output->height[1]);
		MaskMSBs(pImage[2], ((1 << output->bit_depth[2]) - 1), output->width[1], output->height[1]);
#endif
	}

	return file_read;
}

/*!
 ************************************************************************
 * \brief
 *    Padding of automatically added border for picture sizes that are not
 *     multiples of macroblock/macroblock pair size
 *
 * \param output
 *    Image dimensions
 * \param img_size_x
 *    coded image horizontal size (luma)
 * \param img_size_y
 *    code image vertical size (luma)
 * \param img_size_x_cr
 *    coded image horizontal size (chroma)
 * \param img_size_y_cr
 *    code image vertical size (chroma)
 * \param pImage
 *    image planes
 ************************************************************************
 */
void pad_borders (FrameFormat output, int img_size_x, int img_size_y, int img_size_x_cr, int img_size_y_cr, imgpel **pImage[3])
{
  int x, y;

  // Luma or 1st component
  //padding right border
  if (output.width[0] < img_size_x)
    for (y=0; y < output.height[0]; y++)
      for (x = output.width[0]; x < img_size_x; x++)
        pImage[0] [y][x] = pImage[0][y][x-1];

  //padding bottom border
  if (output.height[0] < img_size_y)
    for (y = output.height[0]; y<img_size_y; y++)
      memcpy(pImage[0][y], pImage[0][y - 1], img_size_x * sizeof(imgpel));

  // Chroma or all other components
  if (output.yuv_format != YUV400)
  {
    int k;

    for (k = 1; k < 3; k++)
    {
      //padding right border
      if (output.width[1] < img_size_x_cr)
        for (y=0; y < output.height[1]; y++)
          for (x = output.width[1]; x < img_size_x_cr; x++)
            pImage [k][y][x] = pImage[k][y][x-1];

      //padding bottom border
      if (output.height[1] < img_size_y_cr)
        for (y = output.height[1]; y < img_size_y_cr; y++)
          memcpy(pImage[k][y], pImage[k][y - 1], img_size_x_cr * sizeof(imgpel));
    }
  }
}
