/* The copyright in this software is being made available under the BSD
 * License, included below. This software may be subject to other third party
 * and contributor rights, including patent rights, and no such rights are
 * granted under this license.  
 *
 * Copyright (c) 2010-2012, ITU/ISO/IEC
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
 *    be used to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */


/*!
 *************************************************************************************
 * \file depth_based_mvp.c
 *
 * \brief
 *    depth based motion vector prediction 
 *
 * \author
 *      - Wenyi Su         <suwy@mail.ustc.edu.cn>
 *      - Dmytro           <Dmytro.Rusanovskyy@nokia.com>
 *
 *************************************************************************************
*/



#include "global.h"
#include "cabac.h"
#include "macroblock.h"
#include "image.h"
#include "elements.h"
#include "block.h"
#include "memalloc.h"
#include "depth_based_mvp.h"
#include "mc_depth_prediction.h"



#if DEPTH_BASED_MVP && !MTK_SKIP_DIRECT_A0045
static void Group_MV(Macroblock* currMB,int list_idx,MotionGroup** direction_mv_group);
static int  Get_Direct_MV_Spatial_MVC_LX(Macroblock*currMB,int list_idx,MotionGroup**direction_mv_group);
static int Get_Best_Direction(Macroblock* currMB,MotionGroup** direction_mv_group_list0,MotionGroup** direction_mv_group_list1);
static void get_reference_depth_pixel(Macroblock* currMB,StorablePicture* depth_picture,int block_y,int block_x,
									  int blocksize_y,int blocksize_x,
									  MotionVector mv,imgpel** ref_pixel);
static int get_depth_distortion(Macroblock* currMB,MotionVector mv[],int ref_idx[], 
									  int block_y,int block_x,int blocksize_y,int blocksize_x);


/*!
************************************************************************
* \brief
*    Group the MVs according to their prediction direction: temporal, inter-view, and view synthesis prediction 
************************************************************************
*/
static void Group_MV(Macroblock* currMB,int list_idx,MotionGroup** direction_mv_group)
{
	VideoParameters *p_Vid = currMB->p_Vid;
	PicMotionParams **motion = p_Vid->dec_picture->mv_info;
	int pre_direction[4];
	PixelPos mb[4];
	int i=0,j=0,m=0,n=0;

	get_neighbors(currMB, mb, 0, 0, 16);

	get_pre_dir(currMB,mb,motion,list_idx,pre_direction);

  for(i=0;i<3;++i)
  {
    //!<three neighbors: A, B, C
#if NOKIA_USTC_B_VSP_M26069
    if(mb[i].available&&(pre_direction[i]!=2))
#else
    if(mb[i].available)
#endif
    {
      int mv_x=0,mv_y=0,ref_idx=-1;

			mv_x=motion[mb[i].pos_y][mb[i].pos_x].mv[list_idx].mv_x;
			mv_y=motion[mb[i].pos_y][mb[i].pos_x].mv[list_idx].mv_y;
			ref_idx = motion[mb[i].pos_y][mb[i].pos_x].ref_idx[list_idx];
			if(ref_idx>=0)
			{
				direction_mv_group[pre_direction[i]]->mv_info[direction_mv_group[pre_direction[i]]->num_of_candidates].direction
					=pre_direction[i];
				direction_mv_group[pre_direction[i]]->mv_info[direction_mv_group[pre_direction[i]]->num_of_candidates].list_idx
					=list_idx;
				direction_mv_group[pre_direction[i]]->mv_info[direction_mv_group[pre_direction[i]]->num_of_candidates].mv.mv_x
					=mv_x;
				direction_mv_group[pre_direction[i]]->mv_info[direction_mv_group[pre_direction[i]]->num_of_candidates].mv.mv_y
					=mv_y;
				direction_mv_group[pre_direction[i]]->mv_info[direction_mv_group[pre_direction[i]]->num_of_candidates].ref_idx
					=ref_idx;
				++direction_mv_group[pre_direction[i]]->num_of_candidates;
			}
		}
	}

	for(i=0;i<NUM_OF_MV_GROUP;++i)
	{
		//!<delete the same MV for each direction
		if(direction_mv_group[i]->num_of_candidates>1)
		{
			for(j=0;j<direction_mv_group[i]->num_of_candidates;++j)
			{
				for(m=j+1;m<direction_mv_group[i]->num_of_candidates;)
				{
					if((direction_mv_group[i]->mv_info[m].ref_idx==direction_mv_group[i]->mv_info[j].ref_idx)&&
						(direction_mv_group[i]->mv_info[m].mv.mv_x==direction_mv_group[i]->mv_info[j].mv.mv_x)&&
						(direction_mv_group[i]->mv_info[m].mv.mv_y==direction_mv_group[i]->mv_info[j].mv.mv_y))
					{
						for( n=m+1;n<direction_mv_group[i]->num_of_candidates;++n)
						{
							direction_mv_group[i]->mv_info[n-1]=direction_mv_group[i]->mv_info[n];
						}
						--direction_mv_group[i]->num_of_candidates;
					}
					else 
						++m;
				}
			}
		}
		currMB->num_of_valid_candidates[list_idx]+=direction_mv_group[i]->num_of_candidates;
	}
}

/*!
************************************************************************
* \brief
*    Get the best MVP for each direction according to their mismatch error in depth map
************************************************************************
*/
static int  Get_Direct_MV_Spatial_MVC_LX(Macroblock*currMB,int list_idx,
								  MotionGroup**direction_mv_group)
{

	int best_direction=-1;
	double global_min_dis=MAX_VALUE;
	int i=0,j=0;


	for(i=0;i<NUM_OF_MV_GROUP;++i)
	{
		MotionVector mv_test[2];
		int ref_test[2]={-1,-1};
		double dis=MAX_VALUE,min_dis=MAX_VALUE;

		mv_test[0]=zero_mv;
		mv_test[1]=zero_mv;

		direction_mv_group[i]->best_idx=-1;

		for(j=0;j<direction_mv_group[i]->num_of_candidates;++j)
		{
			mv_test[list_idx]=direction_mv_group[i]->mv_info[j].mv;
			ref_test[list_idx]=direction_mv_group[i]->mv_info[j].ref_idx;
			dis=get_depth_distortion(currMB,mv_test,ref_test,0,0,16,16);
			direction_mv_group[i]->mv_info[j].match_error=dis;
			if(dis<min_dis)
			{
				min_dis=dis;
				direction_mv_group[i]->best_idx=j;
			}
		}
		if(min_dis<global_min_dis)
		{
			global_min_dis=min_dis;
			best_direction=i;
		}
	}

	return best_direction;

}

/*!
************************************************************************
* \brief
*    select the best MVP among all directions according to their mismatch error in depth map
************************************************************************
*/
static int Get_Best_Direction(Macroblock* currMB,MotionGroup** direction_mv_group_list0,MotionGroup** direction_mv_group_list1)
{
	MotionVector mv_test[2];
	int ref_test[2]={-1,-1};
	int i=0;
	double dis=MAX_VALUE,min_dis=MAX_VALUE;
	int best_direction=-1;

	for(i=0;i<NUM_OF_MV_GROUP;++i)
	{
		mv_test[0]=direction_mv_group_list0[i]->best_idx>=0?direction_mv_group_list0[i]->mv_info[direction_mv_group_list0[i]->best_idx].mv:zero_mv;
		ref_test[0]=direction_mv_group_list0[i]->best_idx>=0?direction_mv_group_list0[i]->mv_info[direction_mv_group_list0[i]->best_idx].ref_idx:-1;
		mv_test[1]=direction_mv_group_list1[i]->best_idx>=0?direction_mv_group_list1[i]->mv_info[direction_mv_group_list1[i]->best_idx].mv:zero_mv;
		ref_test[1]=direction_mv_group_list1[i]->best_idx>=0?direction_mv_group_list1[i]->mv_info[direction_mv_group_list1[i]->best_idx].ref_idx:-1;
		if((ref_test[0]==-1)&&(ref_test[1]==-1))
			continue;
		else if((ref_test[0]!=-1)&&(ref_test[1]==-1))
			dis=direction_mv_group_list0[i]->mv_info[direction_mv_group_list0[i]->best_idx].match_error;
		else if((ref_test[0]==-1)&&(ref_test[1]!=-1))
			dis=direction_mv_group_list1[i]->mv_info[direction_mv_group_list1[i]->best_idx].match_error;
		else
		{
			dis=get_depth_distortion(currMB,mv_test,ref_test,0,0,16,16);
		}
		if(dis<min_dis)
		{
			min_dis=dis;
			best_direction=i;
		}
	}

	return best_direction;
}



/*!
************************************************************************
* \brief
*    prepare parameters for MC in depth maps
************************************************************************
*/
static void get_reference_depth_pixel(Macroblock* currMB,StorablePicture* depth_picture,  
							   int block_y,int block_x,int blocksize_y,int blocksize_x,
							   MotionVector mv,imgpel** ref_pixel)
{

	VideoParameters *p_Vid = currMB->p_Vid; 
	Slice *currSlice = currMB->p_Slice;
	StorablePicture *text_picture=currSlice->dec_picture;
	static const int mv_mul = 16; // 4 * 4
	int i4   = currMB->block_x + block_x;
	int vec1_x, vec1_y;
	int low_res_depth=(depth_picture->size_y<text_picture->size_y)||(depth_picture->size_x<text_picture->size_x);

#if NOKIA_USTC_B_VSP_M26069
  int max_x = depth_picture->size_x_m1;
  int max_y = (currMB->mb_field) ? (depth_picture->size_y >> 1) - 1 : depth_picture->size_y_m1; 
  int shift_x  = depth_picture->iLumaStride;
  int subblock_size=BLOCK_SIZE_8x8;
#else
  int max_x = text_picture->size_x_m1;
  int max_y = (currMB->mb_field) ? (text_picture->size_y >> 1) - 1 : text_picture->size_y_m1; 
  int shift_x  = text_picture->iLumaStride;
#endif
  int max_imgpel_value = p_Vid->max_depth_map_value;//!<just luma
  imgpel** img_ref_Y=NULL;

  vec1_x = i4 * mv_mul + mv.mv_x;
  vec1_y = (currMB->block_y_aff + block_y) * mv_mul + mv.mv_y;
  img_ref_Y=depth_picture->imgY;

#if NOKIA_USTC_B_VSP_M26069
  if(low_res_depth)
  {
    vec1_x = (vec1_x+4)>>3;
    vec1_y = (vec1_y+4)>>3;
    subblock_size=subblock_size>>1;
  }
  else
  {
    vec1_x = (vec1_x+2)>>2;
    vec1_y = (vec1_y+2)>>2;
  }
  if (blocksize_y > (p_Vid->iLumaPadY-4) && CheckVertMV(currMB, vec1_y, blocksize_y))
  {
    get_depth_mc_luma(img_ref_Y,vec1_x,vec1_y,blocksize_x,subblock_size,ref_pixel,shift_x,max_x,max_y,max_imgpel_value);
    get_depth_mc_luma(img_ref_Y,vec1_x,vec1_y+subblock_size,blocksize_x,blocksize_y-subblock_size,
      ref_pixel+subblock_size,shift_x,max_x,max_y,max_imgpel_value);
  }
  else
  {
    get_depth_mc_luma(img_ref_Y,vec1_x,vec1_y,blocksize_x,blocksize_y,ref_pixel,shift_x,max_x,max_y,max_imgpel_value);
  }
#else
#if REDUCED_RES
	if(low_res_depth&&(depth_picture->norm_res_depth_ok==0))
	{
		generic_upsampler(p_Vid->p_switch_upsample_params,depth_picture->imgY,NULL,NULL,
			depth_picture->imgY_norm_res_depth,NULL,NULL,
			0,BI_LINEAR);
		pad_buf(*(depth_picture->imgY_norm_res_depth), text_picture->size_x, text_picture->size_y, 
			text_picture->iLumaStride, p_Vid->iLumaPadX, p_Vid->iLumaPadY);
		depth_picture->norm_res_depth_ok=1;
	}

	if(low_res_depth)
		img_ref_Y=depth_picture->imgY_norm_res_depth;
#endif
	if (blocksize_y > (p_Vid->iLumaPadY-4) && CheckVertMV(currMB, vec1_y, blocksize_y))
	{
		get_depth_mc_luma(img_ref_Y,vec1_x,vec1_y,blocksize_x,BLOCK_SIZE_8x8,ref_pixel,shift_x,max_x,max_y,max_imgpel_value);
		get_depth_mc_luma(img_ref_Y,vec1_x,vec1_y+(BLOCK_SIZE_8x8<<2),blocksize_x,blocksize_y-BLOCK_SIZE_8x8,
			ref_pixel+BLOCK_SIZE_8x8,shift_x,max_x,max_y,max_imgpel_value);
	}
	else
	{

		get_depth_mc_luma(img_ref_Y,vec1_x,vec1_y,blocksize_x,blocksize_y,ref_pixel,shift_x,max_x,max_y,max_imgpel_value);
	}
#endif

}


/*!
************************************************************************
* \brief
*    calculate the SAD between current collocated block and MC block in depth map 
************************************************************************
*/
static int get_depth_distortion(Macroblock* currMB,MotionVector mv[],int ref_idx[], 
							int block_y,int block_x,int blocksize_y,int blocksize_x)
{
	VideoParameters* p_Vid=currMB->p_Vid;
	Slice* currSlice=currMB->p_Slice;

	StorablePicture* p_texture_cb=currSlice->dec_picture;
	StorablePicture* p_depth_cb=p_Vid->p_dual_picture;
	StorablePicture* p_depth_ref_l0=NULL;
	StorablePicture* p_depth_ref_l1=NULL;

	imgpel** cb_ref=NULL;
	imgpel** l0_depth=NULL;
	imgpel** l1_depth=NULL;

	StorablePicture ***listX=currSlice->listX;

	int x,y;
	int pix_x,pix_y;

	int distortion=0;

#if NOKIA_USTC_B_VSP_M26069
  int low_res_depth_l0=0,low_res_depth_l1=0,low_res_depth=0;
  int pix_x_start,pix_y_start;
  p_depth_ref_l0=(ref_idx[0]>=0)?listX[0][ref_idx[0]]->dual_picture:NULL;
  p_depth_ref_l1=(ref_idx[1]>=0)?listX[1][ref_idx[1]]->dual_picture:NULL;
#if QC_GVSP_B0054
  if (p_depth_ref_l0==NULL && p_depth_ref_l1==NULL)
  {
    free_mem2Dpel(cb_ref);
    free_mem2Dpel(l0_depth);
    free_mem2Dpel(l1_depth);
    return MAX_VALUE;
  }
#else
  assert(p_depth_ref_l0||p_depth_ref_l1);
#endif

  if(p_depth_ref_l1&&p_depth_ref_l0)
  {
    if((p_depth_ref_l0->size_x<listX[0][ref_idx[0]]->size_x)||(p_depth_ref_l0->size_y<listX[0][ref_idx[0]]->size_y))
    {
      low_res_depth_l0=1;
    }
    else
    {
      low_res_depth_l0=0;
    }
    if((p_depth_ref_l1->size_x<listX[1][ref_idx[1]]->size_x)||(p_depth_ref_l1->size_y<listX[1][ref_idx[1]]->size_y))
    {
      low_res_depth_l1=1;
    }
    else
    {
      low_res_depth_l1=0;
    }
    assert(low_res_depth_l0==low_res_depth_l1);
  }
  else if(p_depth_ref_l0)
  {
    if((p_depth_ref_l0->size_x<listX[0][ref_idx[0]]->size_x)||(p_depth_ref_l0->size_y<listX[0][ref_idx[0]]->size_y))
    {
      low_res_depth_l0=1;
    }
    else
    {
      low_res_depth_l0=0;
    }
  }
  else if(p_depth_ref_l1)
  {
    if((p_depth_ref_l1->size_x<listX[1][ref_idx[1]]->size_x)||(p_depth_ref_l1->size_y<listX[1][ref_idx[1]]->size_y))
    {
      low_res_depth_l1=1;
    }
    else
    {
      low_res_depth_l1=0;
    }
  }

  low_res_depth=low_res_depth_l0||low_res_depth_l1;

  if(low_res_depth)
  {
    blocksize_x=(blocksize_x>>1);
    blocksize_y=(blocksize_y>>1);
  }

  get_mem2Dpel(&cb_ref,blocksize_y,blocksize_x);
  get_mem2Dpel(&l0_depth,blocksize_y,blocksize_x);
  get_mem2Dpel(&l1_depth,blocksize_y,blocksize_x);
#else
  get_mem2Dpel(&cb_ref,blocksize_y,blocksize_x);
  get_mem2Dpel(&l0_depth,blocksize_y,blocksize_x);
  get_mem2Dpel(&l1_depth,blocksize_y,blocksize_x);

  p_depth_ref_l0=(ref_idx[0]>=0)?listX[0][ref_idx[0]]->dual_picture:NULL;
  p_depth_ref_l1=(ref_idx[1]>=0)?listX[1][ref_idx[1]]->dual_picture:NULL;
  assert(p_depth_ref_l0||p_depth_ref_l1);
#endif


	if(p_depth_ref_l0)
	{
		get_reference_depth_pixel(currMB,p_depth_ref_l0,block_y,block_x,blocksize_y,blocksize_x,mv[0],l0_depth);
		memcpy(&(cb_ref[0][0]),&(l0_depth[0][0]),blocksize_y*blocksize_x*sizeof(imgpel));
	}
	if(p_depth_ref_l1)
	{
		get_reference_depth_pixel(currMB,p_depth_ref_l1,block_y,block_x,blocksize_y,blocksize_x,mv[1],l1_depth);
		memcpy(&(cb_ref[0][0]),&(l1_depth[0][0]),blocksize_y*blocksize_x*sizeof(imgpel));

		if(ref_idx[0]>=0)
		{
			for(y=0;y<blocksize_y;++y)
			{
				for(x=0;x<blocksize_x;++x)
					cb_ref[y][x]=(l0_depth[y][x]+l1_depth[y][x]+1)>>1;
			}
		}
	}
#if NOKIA_USTC_B_VSP_M26069
  pix_y_start=(currMB->pix_y+block_y)>>1;
  pix_x_start=(currMB->pix_x+block_x)>>1;
#endif
	for(y=0;y<blocksize_y;++y)
	{
#if NOKIA_USTC_B_VSP_M26069
    pix_y=pix_y_start+y;
#else
		pix_y=((currMB->block_y+block_y)<<2)+y;
#endif
		for(x=0;x<blocksize_x;++x)
		{
#if NOKIA_USTC_B_VSP_M26069
      pix_x=pix_x_start+x;
#else
			pix_x=((currMB->block_x+block_x)<<2)+x;
#endif
#if REDUCED_RES && !NOKIA_USTC_B_VSP_M26069
			assert(!currSlice->is_depth);
			if(p_Vid->mixed_res)
			{
				if(p_depth_cb->norm_res_depth_ok==0)
				{
					generic_upsampler(p_Vid->p_switch_upsample_params,p_depth_cb->imgY,NULL,NULL,
						p_depth_cb->imgY_norm_res_depth,NULL,NULL,
						0,BI_LINEAR);
					pad_buf(*(p_depth_cb->imgY_norm_res_depth), p_texture_cb->size_x, p_texture_cb->size_y, 
						p_texture_cb->iLumaStride, p_Vid->iLumaPadX, p_Vid->iLumaPadY);
					p_depth_cb->norm_res_depth_ok=1;
				}
#if SAIT_DISP_BASED_SAD_M24824  // Approximation
#if SAIT_SHIFT_SAD_COMMENT_M24824
#if NOKIA_DISP_CALC_B0150
				distortion+=(iabs(cb_ref[y][x]-p_depth_cb->imgY_norm_res_depth[pix_y][pix_x])*currSlice->disparity_coeff
					+(1<<(p_Vid->disparity_param_prec+p_Vid->bitdepth_luma)))
					>>(p_Vid->disparity_param_prec+1+p_Vid->bitdepth_luma);
#else
				distortion+=(int)(iabs(cb_ref[y][x]-p_depth_cb->imgY_norm_res_depth[pix_y][pix_x])*currSlice->disparity_coeff+0.5);
#endif
#else
				distortion+=(iabs(cb_ref[y][x]-p_depth_cb->imgY_norm_res_depth[pix_y][pix_x])>>currSlice->disparity_coeff);
#endif
#else
				distortion+=iabs(cb_ref[y][x]-p_depth_cb->imgY_norm_res_depth[pix_y][pix_x]);
#endif
			}
			else
#else
      {
#if SAIT_DISP_BASED_SAD_M24824
#if SAIT_SHIFT_SAD_COMMENT_M24824
#if NOKIA_DISP_CALC_B0150
			distortion+=(iabs(cb_ref[y][x]-p_depth_cb->imgY[pix_y][pix_x])*currSlice->disparity_coeff
				+(1<<(p_Vid->disparity_param_prec+p_Vid->bitdepth_luma)))
				>>(p_Vid->disparity_param_prec+1+p_Vid->bitdepth_luma);
#else
			distortion+=(int)(iabs(cb_ref[y][x]-p_depth_cb->imgY[pix_y][pix_x])*currSlice->disparity_coeff+0.5);
#endif
#else
			distortion+=(iabs(cb_ref[y][x]-p_depth_cb->imgY[pix_y][pix_x])>>currSlice->disparity_coeff);
#endif
#else
			distortion+=iabs(cb_ref[y][x]-p_depth_cb->imgY[pix_y][pix_x]);
#endif
#endif
      }
		}
	}

	free_mem2Dpel(cb_ref);
	free_mem2Dpel(l0_depth);
	free_mem2Dpel(l1_depth);
	return distortion;
}
#endif

#if DEPTH_BASED_MVP
/*!
************************************************************************
* \brief
*    check the availability of neighbor blocks according to their reference direction(inter prediction, interview prediction, VSP)
************************************************************************
*/
void check_neighbors(Macroblock* currMB,PixelPos* block,PicMotionParams**mv_info,int list,int ref)
{
	Slice* p_Slice=currMB->p_Slice;
	struct storable_picture* *listX=p_Slice->listX[list];

	int ref_view_id=listX[ref]->view_id;
#if VISBD_VSP
	int is_virtual_ref_view=listX[ref]->is_virtual_view;
#endif

	int i=0;

	int neighbor_ref_idx=-1;
	int neighbor_view_id=-1;

#if QC_GVSP_B0054
  int neighbor_uses_vsp = 0;
  VideoParameters *p_Vid = currMB->p_Vid;
#endif

	if(!p_Slice->depth_based_mvp_flag)
		return ;

	for(i=0;i<4;++i)
	{
		if(block[i].available)
		{
			neighbor_ref_idx=mv_info[block[i].pos_y][block[i].pos_x].ref_idx[list];
#if !QC_GVSP_B0054
      if(neighbor_ref_idx==-1)
        continue;
#endif
#if VISBD_VSP
			if(is_virtual_ref_view)
			{
				//!<current reference is virtual view, test if the neighbor block is also
				//!<virtual view prediction.
#if !QC_GVSP_B0054
        if(!listX[neighbor_ref_idx]->is_virtual_view)
          block[i].available=0;
#else
        if (!neighbor_uses_vsp)
          block[i].available=0;
#endif
			}
			else
#endif
			{
#if QC_GVSP_B0054
        if (neighbor_ref_idx>=0)
        {
          neighbor_view_id=listX[neighbor_ref_idx]->view_id;
          if(ref_view_id!=neighbor_view_id)
            block[i].available=0;
        }
        else
        {
          if (neighbor_uses_vsp)
            block[i].available=0;
        }
#else
        neighbor_view_id=listX[neighbor_ref_idx]->view_id;
        if(ref_view_id!=neighbor_view_id)
          block[i].available=0;
#endif
			}
		}
	}

}
#endif
#if DEPTH_BASED_MVP && !MTK_SKIP_DIRECT_A0045
/*!
************************************************************************
* \brief
*    Get the View reference direction(inter, interview,VSP) for each reference block
************************************************************************
*/
void get_pre_dir(Macroblock* currMB,const PixelPos *mb,PicMotionParams**mv_info,int list_idx,int direction[])
{
	Slice* currSlice=currMB->p_Slice;

	StorablePicture**listX=currSlice->listX[list_idx];
	int i;
	int ref_idx=-1;

	for(i=0;i<3;++i)
	{
		direction[i]=-1;

		if(mb[i].available)
		{
			ref_idx=mv_info[mb[i].pos_y][mb[i].pos_x].ref_idx[list_idx];
			if(ref_idx==-1)
				continue;
			else
			{
#if VISBD_VSP
				if(listX[ref_idx]->is_virtual_view)
					direction[i]=2;
				else
#endif
				{
					if(listX[ref_idx]->view_id!=currSlice->view_id)
						direction[i]=1;
					else 
						direction[i]=0;	 
				}
			}
		}
	}
}

/*!
************************************************************************
* \brief
*    alloc memory for D-MVP in slice level
************************************************************************
*/

void alloc_depth_based_mvp_buffer(Slice* currSlice)
{
	int i;

	currSlice->direction_mv_group_l0=NULL;
	currSlice->direction_mv_group_l1=NULL;

	if(!currSlice->depth_based_mvp_flag)
		return ;

	
	if((currSlice->slice_type!=I_SLICE)&&(currSlice->slice_type!=SI_SLICE))
	{
		currSlice->direction_mv_group_l0=calloc(NUM_OF_MV_GROUP,sizeof(MotionGroup*));
		if(currSlice->slice_type==B_SLICE)
			currSlice->direction_mv_group_l1=calloc(NUM_OF_MV_GROUP,sizeof(MotionGroup*));

		for(i=0;i<NUM_OF_MV_GROUP;++i)
		{
			currSlice->direction_mv_group_l0[i]=calloc(1,sizeof(MotionGroup));
			currSlice->direction_mv_group_l0[i]->mv_info=calloc(NUM_OF_INIT_CANDIDATE_MVP,sizeof(MotionInfo));
			if(currSlice->slice_type==B_SLICE)
			{
				currSlice->direction_mv_group_l1[i]=calloc(1,sizeof(MotionGroup));
				currSlice->direction_mv_group_l1[i]->mv_info=calloc(NUM_OF_INIT_CANDIDATE_MVP,sizeof(MotionInfo));
			}
		}
	}
}

/*!
************************************************************************
* \brief
*    initialize the parameters for D-MVP in MB level
************************************************************************
*/
void free_depth_based_mvp_buffer(Slice* currSlice)
{
	int i;
	for(i=0;i<NUM_OF_MV_GROUP;++i)
	{
		if(currSlice->direction_mv_group_l0&&(currSlice->direction_mv_group_l0[i]))
		{
			free(currSlice->direction_mv_group_l0[i]->mv_info);
			free(currSlice->direction_mv_group_l0[i]);
		}
		if(currSlice->direction_mv_group_l1&&(currSlice->direction_mv_group_l1[i]))
		{
			free(currSlice->direction_mv_group_l1[i]->mv_info);
			free(currSlice->direction_mv_group_l1[i]);
		}
	}
	if(currSlice->direction_mv_group_l0)
	{
		free(currSlice->direction_mv_group_l0);
		currSlice->direction_mv_group_l0=NULL;
	}
	if(currSlice->direction_mv_group_l1)
	{
		free(currSlice->direction_mv_group_l1);
		currSlice->direction_mv_group_l1=NULL;
	}
}

/*!
************************************************************************
* \brief
*    free the memory for D-MVP
************************************************************************
*/

void reset_depth_based_mvp_params(Macroblock* currMB)
{
	int i,j;
	Slice* currSlice=currMB->p_Slice;

	currMB->direction_mv_group_l0=currSlice->direction_mv_group_l0;
	currMB->direction_mv_group_l1=currSlice->direction_mv_group_l1;
	currMB->best_mv_group_l0=NULL;
	currMB->best_mv_group_l1=NULL;
	currMB->best_ref[0]=currMB->best_ref[1]=-1;
	currMB->best_mvp[0]=currMB->best_mvp[1]=zero_mv;
	currMB->best_direction[0]=currMB->best_direction[1]=currMB->best_direction[2]=-1;
	currMB->num_of_valid_candidates[0]=currMB->num_of_valid_candidates[1]=0;
	currMB->d_mvp_been_prepared=0;


	for(i=0;i<NUM_OF_MV_GROUP;++i)
	{
		currMB->direction_mv_group_l0[i]->best_idx=-1;
		currMB->direction_mv_group_l0[i]->num_of_candidates=0;
		if(currSlice->slice_type==B_SLICE)
		{
			currMB->direction_mv_group_l1[i]->best_idx=-1;
			currMB->direction_mv_group_l1[i]->num_of_candidates=0;
		}
		for(j=0;j<NUM_OF_INIT_CANDIDATE_MVP;++j)
		{
			currMB->direction_mv_group_l0[i]->mv_info[j].direction=-1;
			currMB->direction_mv_group_l0[i]->mv_info[j].list_idx=-1;
			currMB->direction_mv_group_l0[i]->mv_info[j].match_error=MAX_VALUE;
			currMB->direction_mv_group_l0[i]->mv_info[j].ref_idx=-1;
			currMB->direction_mv_group_l0[i]->mv_info[j].mv=zero_mv;
			if(currSlice->slice_type==B_SLICE)
			{
				currMB->direction_mv_group_l1[i]->mv_info[j].direction=-1;
				currMB->direction_mv_group_l1[i]->mv_info[j].list_idx=-1;
				currMB->direction_mv_group_l1[i]->mv_info[j].match_error=MAX_VALUE;
				currMB->direction_mv_group_l1[i]->mv_info[j].ref_idx=-1;
				currMB->direction_mv_group_l1[i]->mv_info[j].mv=zero_mv;
			}
		}
	}

}

/*!
************************************************************************
* \brief
*    calculate the D-MVP for skip mode
************************************************************************
*/

void prepare_mvc_skip_params(Macroblock *currMB)
{

	MotionGroup** direction_mv_group=currMB->direction_mv_group_l0;//!<time:0,interview:1, vsp:2

	Group_MV(currMB,0,direction_mv_group);
	if(currMB->num_of_valid_candidates[0]<=0)
		currMB->best_direction[0]=-1;
	else 
		currMB->best_direction[0]=Get_Direct_MV_Spatial_MVC_LX(currMB,0,direction_mv_group);

	if(currMB->best_direction[0]!=-1)
	{
		MotionGroup* best_mv_group=direction_mv_group[currMB->best_direction[0]]->num_of_candidates?
			direction_mv_group[currMB->best_direction[0]]:NULL;

		currMB->best_mv_group_l0=best_mv_group;
		
		currMB->best_ref[0]=best_mv_group->mv_info[best_mv_group->best_idx].ref_idx;
		currMB->best_mvp[0]=best_mv_group->mv_info[best_mv_group->best_idx].mv;
	}
	else
	{
		currMB->best_ref[0]=-1;
		currMB->best_mvp[0]=zero_mv;
	}


}

/*!
************************************************************************
* \brief
*    calculate the D-MVP for direct mode
************************************************************************
*/
void prepare_mvc_direct_params(Macroblock *currMB)
{

	MotionGroup** direction_mv_group_list0=currMB->direction_mv_group_l0;
	MotionGroup** direction_mv_group_list1=currMB->direction_mv_group_l1;
	int num_of_direction=0;
	int i=0, first_direction=-1;

	Group_MV(currMB,0,direction_mv_group_list0);
	Group_MV(currMB,1,direction_mv_group_list1);

	if(0==currMB->num_of_valid_candidates[0]+currMB->num_of_valid_candidates[1])
		currMB->best_direction[2]=-1;
	else
	{
		for(i=0;i<NUM_OF_MV_GROUP;++i)
		{
			if(direction_mv_group_list0[i]->num_of_candidates||direction_mv_group_list1[i]->num_of_candidates)
			{
				++num_of_direction;
				if(first_direction==-1)
					first_direction=i;
			}
		}
		if((num_of_direction==1)&&(currMB->num_of_valid_candidates[0]<=1)&&(currMB->num_of_valid_candidates[1]<=1))
		{
			currMB->best_direction[2]=first_direction;
			if(direction_mv_group_list0[first_direction]->num_of_candidates)
				direction_mv_group_list0[first_direction]->best_idx=0;
			if(direction_mv_group_list1[first_direction]->num_of_candidates)
				direction_mv_group_list1[first_direction]->best_idx=0;
		}
		else
		{
			currMB->best_direction[0]=Get_Direct_MV_Spatial_MVC_LX(currMB,0,direction_mv_group_list0);
			currMB->best_direction[1]=Get_Direct_MV_Spatial_MVC_LX(currMB,1,direction_mv_group_list1);
			currMB->best_direction[2]=Get_Best_Direction(currMB,direction_mv_group_list0,direction_mv_group_list1);
		}
	}




	if(currMB->best_direction[2]!=-1)
	{
		MotionGroup* best_direction_list0=direction_mv_group_list0[currMB->best_direction[2]]->num_of_candidates?
			direction_mv_group_list0[currMB->best_direction[2]]:NULL;
		MotionGroup* best_direction_list1=direction_mv_group_list1[currMB->best_direction[2]]->num_of_candidates?
			direction_mv_group_list1[currMB->best_direction[2]]:NULL;

		currMB->best_mv_group_l0=best_direction_list0;
		currMB->best_mv_group_l1=best_direction_list1;

		currMB->best_ref[0]=best_direction_list0?best_direction_list0->mv_info[best_direction_list0->best_idx].ref_idx:-1;
		currMB->best_ref[1]=best_direction_list1?best_direction_list1->mv_info[best_direction_list1->best_idx].ref_idx:-1;
		currMB->best_mvp[0]=best_direction_list0?best_direction_list0->mv_info[best_direction_list0->best_idx].mv:zero_mv;
		currMB->best_mvp[1]=best_direction_list1?best_direction_list1->mv_info[best_direction_list1->best_idx].mv:zero_mv;

	}
	else
	{
		currMB->best_ref[0]=currMB->best_ref[1]=-1;
		currMB->best_mvp[0]=currMB->best_mvp[1]=zero_mv;
	}


	
}

/*!
************************************************************************
* \brief
*    replace the zero inter-view MVP with disparity for skip mode
************************************************************************
*/
void set_mvc_skip_params(Macroblock* currMB)
{
	VideoParameters* p_Vid=currMB->p_Vid;
	Slice* currSlice=currMB->p_Slice;

	int				best_idx[2]			=	{-1,-1};
	int				best_ref[2]			=	{-1,-1};
	MotionVector	best_mv[2];
	int i=0,j=0;

	int zero_mv_check=0;


	best_idx[0]=currMB->best_mv_group_l0?currMB->best_mv_group_l0->best_idx:-1;
	best_ref[0]=(best_idx[0]!=-1)?currMB->best_mv_group_l0->mv_info[best_idx[0]].ref_idx:0;
	best_mv[0]=(best_idx[0]!=-1)?currMB->best_mv_group_l0->mv_info[best_idx[0]].mv:zero_mv;


	zero_mv_check=(best_ref[0]!=-1)&&(currSlice->listX[0][best_ref[0]]->view_id!=currSlice->view_id)&&(best_mv[0].mv_x==0)&&(best_mv[0].mv_y==0);
	if(zero_mv_check)
	{
		MotionVector disparity_mv=zero_mv;

#if SAIT_SKIP_MVP_COMMENT_M24824 || !SAIT_INTER_VIEW_MVP_M24824
		currMB->GetInterviewMVPrediction(currMB,&(disparity_mv),0,0,16,16,p_Vid->forward_disparity_table);
#else
		currMB->GetInterviewMVPredictionMax(currMB,&(disparity_mv),0,0,16,16,p_Vid->forward_disparity_table);
#endif

		best_mv[0]=disparity_mv;
	}

	for(j = currMB->block_y; j < currMB->block_y + BLOCK_SIZE; ++j)
	{
		for(i = currMB->block_x; i < currMB->block_x + BLOCK_SIZE; ++i)
		{
			PicMotionParams *motion = &currSlice->dec_picture->mv_info[j][i];
			motion->ref_pic[LIST_0] = currSlice->listX[0][best_ref[0]];
			motion->mv     [LIST_0] = best_mv[0];
			motion->ref_idx[LIST_0] = best_ref[0];
		}
	}
}
/*!
************************************************************************
* \brief
*    replace the zero inter-view MVP with disparity for direct mode in each direction
************************************************************************
*/
void set_mvc_direct_params(Macroblock* currMB, MotionVector *pmvl0, MotionVector *pmvl1, char *l0_rFrame, char *l1_rFrame)
{
	VideoParameters* p_Vid=currMB->p_Vid;
	Slice* currSlice=currMB->p_Slice;

	int				best_idx[2]			=	{-1,-1};
	int				best_ref[2]			=	{-1,-1};
	MotionVector	best_mv[2];

	int zero_mv_check=0;

	best_idx[0]=currMB->best_mv_group_l0&&(currMB->best_mv_group_l0->num_of_candidates)?currMB->best_mv_group_l0->best_idx:-1;
	best_idx[1]=currMB->best_mv_group_l1&&(currMB->best_mv_group_l1->num_of_candidates)?currMB->best_mv_group_l1->best_idx:-1;

	best_ref[0]=(best_idx[0]!=-1)?currMB->best_mv_group_l0->mv_info[best_idx[0]].ref_idx:-1;
	best_ref[1]=(best_idx[1]!=-1)?currMB->best_mv_group_l1->mv_info[best_idx[1]].ref_idx:-1;

	best_mv[0]=(best_idx[0]!=-1)?currMB->best_mv_group_l0->mv_info[best_idx[0]].mv:zero_mv;
	best_mv[1]=(best_idx[1]!=-1)?currMB->best_mv_group_l1->mv_info[best_idx[1]].mv:zero_mv;



	zero_mv_check=(best_ref[0]>=0)&&(currSlice->listX[0][best_ref[0]]->view_id!=currSlice->view_id)&&(best_mv[0].mv_x==0)&&(best_mv[0].mv_y==0);
	if(zero_mv_check)
	{
		MotionVector disparity_mv=zero_mv;

#if SAIT_SKIP_MVP_COMMENT_M24824 || !SAIT_INTER_VIEW_MVP_M24824
		currMB->GetInterviewMVPrediction(currMB,&(disparity_mv),0,0,16,16,p_Vid->forward_disparity_table);
#else
		currMB->GetInterviewMVPredictionMax(currMB,&(disparity_mv),0,0,16,16,p_Vid->forward_disparity_table);
#endif

		best_mv[0]=disparity_mv;
	}

	zero_mv_check=(best_ref[1]>=0)&&(currSlice->listX[1][best_ref[1]]->view_id!=currSlice->view_id)&&(best_mv[1].mv_x==0)&&(best_mv[1].mv_y==0);
	if(zero_mv_check)
	{
		MotionVector disparity_mv=zero_mv;

#if SAIT_SKIP_MVP_COMMENT_M24824 || !SAIT_INTER_VIEW_MVP_M24824
		currMB->GetInterviewMVPrediction(currMB,&(disparity_mv),0,0,16,16,p_Vid->backward_disparity_table);
#else
		currMB->GetInterviewMVPredictionMax(currMB,&(disparity_mv),0,0,16,16,p_Vid->backward_disparity_table);
#endif

		best_mv[1]=disparity_mv;
	}


	*pmvl0=best_mv[0];
	*pmvl1=best_mv[1];

	*l0_rFrame=best_ref[0];
	*l1_rFrame=best_ref[1];

}

#endif

