/******************************************************************************
 *
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *****************************************************************************
 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/
/**
*******************************************************************************
* @file
*  impeg2d_mcu.c
*
* @brief
*  Contains MC function definitions for MPEG2 decoder
*
* @author
*  Harish
*
* @par List of Functions:
* - impeg2_copy_mb()
* - impeg2_interpolate()
* - impeg2_mc_halfx_halfy_8x8()
* - impeg2_mc_halfx_fully_8x8()
* - impeg2_mc_fullx_halfy_8x8()
* - impeg2_mc_fullx_fully_8x8()
*
* @remarks
*  None
*
*******************************************************************************
*/

#include <stdio.h>
#include <string.h>
#include "iv_datatypedef.h"
#include "iv.h"
#include "impeg2_buf_mgr.h"
#include "impeg2_disp_mgr.h"
#include "impeg2_defs.h"
#include "impeg2_platform_macros.h"

#include "impeg2_inter_pred.h"
#include "impeg2_globals.h"
#include "impeg2_macros.h"
#include "impeg2_idct.h"

/*******************************************************************************
*  Function Name   : impeg2_copy_mb
*
*  Description     : copies 3 components to the frame from mc_buf
*
*  Arguments       :
*  src_buf         : Source Buffer
*  dst_buf         : Destination Buffer
*  src_offset_x    : X offset for source
*  src_offset_y    : Y offset for source
*  dst_offset_x    : X offset for destination
*  dst_offset_y    : Y offset for destination
*  src_wd          : Source Width
*  dst_wd          : destination Width
*  rows            : Number of rows
*  cols            : Number of columns
*
*  Values Returned : None
*******************************************************************************/
void impeg2_copy_mb(yuv_buf_t *ps_src_buf,
                    yuv_buf_t *ps_dst_buf,
                    UWORD32 u4_src_wd,
                    UWORD32 u4_dst_wd)
{
    UWORD8 *pu1_src;
    UWORD8 *pu1_dst;
    UWORD32 i;
    UWORD32 u4_rows = MB_SIZE;
    UWORD32 u4_cols = MB_SIZE;

    /*******************************************************/
    /* copy Y                                              */
    /*******************************************************/
    pu1_src = ps_src_buf->pu1_y;
    pu1_dst = ps_dst_buf->pu1_y;
    for(i = 0; i < u4_rows; i++)
    {
        memcpy(pu1_dst, pu1_src, u4_cols);
        pu1_src += u4_src_wd;
        pu1_dst += u4_dst_wd;
    }

    u4_src_wd >>= 1;
    u4_dst_wd >>= 1;
    u4_rows >>= 1;
    u4_cols >>= 1;

    /*******************************************************/
    /* copy U                                              */
    /*******************************************************/
    pu1_src = ps_src_buf->pu1_u;
    pu1_dst = ps_dst_buf->pu1_u;
    for(i = 0; i < u4_rows; i++)
    {
        memcpy(pu1_dst, pu1_src, u4_cols);

        pu1_src += u4_src_wd;
        pu1_dst += u4_dst_wd;
    }
    /*******************************************************/
    /* copy V                                              */
    /*******************************************************/
    pu1_src = ps_src_buf->pu1_v;
    pu1_dst = ps_dst_buf->pu1_v;
    for(i = 0; i < u4_rows; i++)
    {
        memcpy(pu1_dst, pu1_src, u4_cols);

        pu1_src += u4_src_wd;
        pu1_dst += u4_dst_wd;
    }

}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : impeg2_interpolate                                       */
/*                                                                           */
/*  Description   : averages the contents of buf_src1 and buf_src2 and stores*/
/*                  result in buf_dst                                        */
/*                                                                           */
/*  Inputs        : buf_src1 -  First Source                                 */
/*                  buf_src2 -  Second Source                                */
/*                                                                           */
/*  Globals       : None                                                     */
/*                                                                           */
/*  Processing    : Avg the values from two sources and store the result in  */
/*                  destination buffer                                       */
/*                                                                           */
/*  Outputs       : buf_dst  -  Avg of contents of buf_src1 and buf_src2     */
/*                                                                           */
/*  Returns       : None                                                     */
/*                                                                           */
/*  Issues        : Assumes that all 3 buffers are of same size              */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         14 09 2005   Harish M        First Version                        */
/*         15 09 2010   Venkat          Added stride                         */
/*                                                                           */
/*****************************************************************************/
void impeg2_interpolate(yuv_buf_t *ps_buf_src1,
                        yuv_buf_t *ps_buf_src2,
                        yuv_buf_t *ps_buf_dst,
                        UWORD32 u4_stride)
{

    UWORD32 i,j;
    UWORD8 *pu1_src1,*pu1_src2,*pu1_dst;
    pu1_src1 = ps_buf_src1->pu1_y;
    pu1_src2 = ps_buf_src2->pu1_y;
    pu1_dst  = ps_buf_dst->pu1_y;
    for(i = MB_SIZE; i > 0; i--)
    {
        for(j = MB_SIZE; j > 0; j--)
        {
            *pu1_dst++ = ((*pu1_src1++) + (*pu1_src2++) + 1) >> 1;
        }

        pu1_dst += u4_stride - MB_SIZE;

    }

    u4_stride >>= 1;

    pu1_src1 = ps_buf_src1->pu1_u;
    pu1_src2 = ps_buf_src2->pu1_u;
    pu1_dst  = ps_buf_dst->pu1_u;
    for(i = MB_CHROMA_SIZE; i > 0 ; i--)
    {
        for(j = MB_CHROMA_SIZE; j > 0; j--)
        {
            *pu1_dst++ = ((*pu1_src1++) + (*pu1_src2++) + 1) >> 1;
        }

        pu1_dst += u4_stride - MB_CHROMA_SIZE;
    }

    pu1_src1 = ps_buf_src1->pu1_v;
    pu1_src2 = ps_buf_src2->pu1_v;
    pu1_dst  = ps_buf_dst->pu1_v;
    for(i = MB_CHROMA_SIZE; i > 0 ; i--)
    {
        for(j = MB_CHROMA_SIZE; j > 0; j--)
        {
            *pu1_dst++ = ((*pu1_src1++) + (*pu1_src2++) + 1) >> 1;
        }

        pu1_dst += u4_stride - MB_CHROMA_SIZE;
    }

}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : impeg2_mc_halfx_halfy_8x8()                                 */
/*                                                                           */
/*  Description   : Gets the buffer from (0.5,0.5) to (8.5,8.5)              */
/*                  and the above block of size 8 x 8 will be placed as a    */
/*                  block from the current position of out_buf               */
/*                                                                           */
/*  Inputs        : ref - Reference frame from which the block will be       */
/*                        block will be extracted.                           */
/*                  ref_wid - WIdth of reference frame                       */
/*                  out_wid - WIdth of the output frame                      */
/*                  blk_width  - width of the block                          */
/*                  blk_width  - height of the block                         */
/*                                                                           */
/*  Globals       : None                                                     */
/*                                                                           */
/*  Processing    : Point to the (0,0),(1,0),(0,1),(1,1) position in         */
/*                  the ref frame.Interpolate these four values to get the   */
/*                  value at(0.5,0.5).Repeat this to get an 8 x 8 block      */
/*                  using 9 x 9 block from reference frame                   */
/*                                                                           */
/*  Outputs       : out -  Output containing the extracted block             */
/*                                                                           */
/*  Returns       : None                                                     */
/*                                                                           */
/*  Issues        : None                                                     */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         05 09 2005   Harish M        First Version                        */
/*                                                                           */
/*****************************************************************************/
void impeg2_mc_halfx_halfy_8x8(UWORD8 *pu1_out,
                            UWORD8 *pu1_ref,
                            UWORD32 u4_ref_wid,
                            UWORD32 u4_out_wid)
{
    UWORD8 *pu1_ref_p0,*pu1_ref_p1,*pu1_ref_p2,*pu1_ref_p3;
    UWORD32 i,j;
    /* P0-P3 are the pixels in the reference frame and Q is the value being */
    /* estimated                                                            */
    /*
       P0 P1
         Q
       P2 P3
    */

    pu1_ref_p0 = pu1_ref;
    pu1_ref_p1 = pu1_ref + 1;
    pu1_ref_p2 = pu1_ref + u4_ref_wid;
    pu1_ref_p3 = pu1_ref + u4_ref_wid + 1;

    for(i = 0; i < BLK_SIZE; i++)
    {
        for(j = 0; j < BLK_SIZE; j++)
        {
            *pu1_out++ =   (( (*pu1_ref_p0++ )
                        + (*pu1_ref_p1++ )
                        + (*pu1_ref_p2++ )
                        + (*pu1_ref_p3++ ) + 2 ) >> 2);
        }
        pu1_ref_p0 += u4_ref_wid - BLK_SIZE;
        pu1_ref_p1 += u4_ref_wid - BLK_SIZE;
        pu1_ref_p2 += u4_ref_wid - BLK_SIZE;
        pu1_ref_p3 += u4_ref_wid - BLK_SIZE;

        pu1_out    += u4_out_wid - BLK_SIZE;
    }
    return;
}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : impeg2_mc_halfx_fully_8x8()                                 */
/*                                                                           */
/*  Description   : Gets the buffer from (0.5,0) to (8.5,8)                  */
/*                  and the above block of size 8 x 8 will be placed as a    */
/*                  block from the current position of out_buf               */
/*                                                                           */
/*  Inputs        : ref - Reference frame from which the block will be       */
/*                        block will be extracted.                           */
/*                  ref_wid - WIdth of reference frame                       */
/*                  out_wid - WIdth of the output frame                      */
/*                  blk_width  - width of the block                          */
/*                  blk_width  - height of the block                         */
/*                                                                           */
/*  Globals       : None                                                     */
/*                                                                           */
/*  Processing    : Point to the (0,0) and (1,0) position in the ref frame   */
/*                  Interpolate these two values to get the value at(0.5,0)  */
/*                  Repeat this to get an 8 x 8 block using 9 x 8 block from */
/*                  reference frame                                          */
/*                                                                           */
/*  Outputs       : out -  Output containing the extracted block             */
/*                                                                           */
/*  Returns       : None                                                     */
/*                                                                           */
/*  Issues        : None                                                     */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         05 09 2005   Harish M        First Version                        */
/*                                                                           */
/*****************************************************************************/
void impeg2_mc_halfx_fully_8x8(UWORD8 *pu1_out,
                            UWORD8 *pu1_ref,
                            UWORD32 u4_ref_wid,
                            UWORD32 u4_out_wid)
{
    UWORD8 *pu1_ref_p0, *pu1_ref_p1;
    UWORD32 i,j;

    /* P0-P3 are the pixels in the reference frame and Q is the value being */
    /* estimated                                                            */
    /*
       P0 Q P1
    */

    pu1_ref_p0 = pu1_ref;
    pu1_ref_p1 = pu1_ref + 1;

    for(i = 0; i < BLK_SIZE; i++)
    {
        for(j = 0; j < BLK_SIZE; j++)
        {
            *pu1_out++ =   ((( *pu1_ref_p0++ )
                        + (*pu1_ref_p1++) + 1 ) >> 1);
        }
        pu1_ref_p0 += u4_ref_wid - BLK_SIZE;
        pu1_ref_p1 += u4_ref_wid - BLK_SIZE;

        pu1_out    += u4_out_wid - BLK_SIZE;
    }
    return;
}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : impeg2_mc_fullx_halfy_8x8()                                 */
/*                                                                           */
/*  Description   : Gets the buffer from (0,0.5) to (8,8.5)                  */
/*                  and the above block of size 8 x 8 will be placed as a    */
/*                  block from the current position of out_buf               */
/*                                                                           */
/*  Inputs        : ref - Reference frame from which the block will be       */
/*                        block will be extracted.                           */
/*                  ref_wid - WIdth of reference frame                       */
/*                  out_wid - WIdth of the output frame                      */
/*                  blk_width  - width of the block                          */
/*                  blk_width  - height of the block                         */
/*                                                                           */
/*  Globals       : None                                                     */
/*                                                                           */
/*  Processing    : Point to the (0,0) and (0,1)   position in the ref frame */
/*                  Interpolate these two values to get the value at(0,0.5)  */
/*                  Repeat this to get an 8 x 8 block using 8 x 9 block from */
/*                  reference frame                                          */
/*                                                                           */
/*  Outputs       : out -  Output containing the extracted block             */
/*                                                                           */
/*  Returns       : None                                                     */
/*                                                                           */
/*  Issues        : None                                                     */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         05 09 2005   Harish M        First Version                        */
/*                                                                           */
/*****************************************************************************/
void impeg2_mc_fullx_halfy_8x8(UWORD8 *pu1_out,
                            UWORD8 *pu1_ref,
                            UWORD32 u4_ref_wid,
                            UWORD32 u4_out_wid)
{

    UWORD8 *pu1_ref_p0, *pu1_ref_p1;
    UWORD32 i,j;
    /* P0-P3 are the pixels in the reference frame and Q is the value being */
    /* estimated                                                            */
    /*
       P0
        x
       P1
    */
    pu1_ref_p0 = pu1_ref;
    pu1_ref_p1 = pu1_ref + u4_ref_wid;

    for(i = 0; i < BLK_SIZE; i++)
    {
        for(j = 0; j < BLK_SIZE; j++)
        {
            *pu1_out++ =   ((( *pu1_ref_p0++)
                        + (*pu1_ref_p1++) + 1 ) >> 1);
        }
        pu1_ref_p0 += u4_ref_wid - BLK_SIZE;
        pu1_ref_p1 += u4_ref_wid - BLK_SIZE;

        pu1_out    += u4_out_wid - BLK_SIZE;
    }

    return;
}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : impeg2_mc_fullx_fully_8x8()                                 */
/*                                                                           */
/*  Description   : Gets the buffer from (x,y) to (x+8,y+8)                  */
/*                  and the above block of size 8 x 8 will be placed as a    */
/*                  block from the current position of out_buf               */
/*                                                                           */
/*  Inputs        : ref - Reference frame from which the block will be       */
/*                        block will be extracted.                           */
/*                  ref_wid - WIdth of reference frame                       */
/*                  out_wid - WIdth of the output frame                      */
/*                  blk_width  - width of the block                          */
/*                  blk_width  - height of the block                         */
/*                                                                           */
/*  Globals       : None                                                     */
/*                                                                           */
/*  Processing    : Point to the (0,0) position in the ref frame             */
/*                  Get an 8 x 8 block from reference frame                  */
/*                                                                           */
/*  Outputs       : out -  Output containing the extracted block             */
/*                                                                           */
/*  Returns       : None                                                     */
/*                                                                           */
/*  Issues        : None                                                     */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         05 09 2005   Harish M        First Version                        */
/*                                                                           */
/*****************************************************************************/
void impeg2_mc_fullx_fully_8x8(UWORD8 *pu1_out,
                            UWORD8 *pu1_ref,
                            UWORD32 u4_ref_wid,
                            UWORD32 u4_out_wid)
{

    UWORD32 i;

    for(i = 0; i < BLK_SIZE; i++)
    {
        memcpy(pu1_out, pu1_ref, BLK_SIZE);
        pu1_ref += u4_ref_wid;
        pu1_out += u4_out_wid;
    }
    return;
}