
/*!
 ************************************************************************
 * \file ferc_proposed.c
 *
 * \brief
 *     Unused code
 *
 * \author
 *       - Joao Carreira
 *
 ************************************************************************
 */

static int computeSADNeighborsWithoutEdges(StorablePicture *Destination, StorablePicture *BlockState, int x, int y, int Block_Size)
{
  int ii, jj;
  int sad = 0;
  int yBlock4x4 = y / Block_Size, xBlock4x4 = x / Block_Size;
  int discard;

  //  ***** *****
  //  ***** *   *
  //  ***** *   *
  //  ***** *****

  //! Left Neighbor
  if (xBlock4x4 != 0 && BlockState->imgY[yBlock4x4][xBlock4x4 - 1] != 0)
  {
    for (ii = 0; ii < Block_Size; ii++)
    {
      sad += iabs(Destination->imgY[y + ii][x - 1] - Destination->imgY[y + ii][x]);
    }
  }
  //! Right Neighbor
  if ((x + BLOCK_SIZE) != Destination->size_x && BlockState->imgY[yBlock4x4][xBlock4x4 + 1] != 0)
  {
    for (ii = 0; ii < BLOCK_SIZE; ii++)
    {
      sad += iabs(Destination->imgY[y + ii][x + BLOCK_SIZE - 1] - Destination->imgY[y + ii][x + BLOCK_SIZE]);
    }
  }

  //  *****
  //  *****
  //  *****
  //  *****
  //  *****
  //  *   *
  //  *   *
  //  *****

  //! Top Neighbor
  if (y != 0 && BlockState->imgY[yBlock4x4 - 1][xBlock4x4] != 0)
  {
    for (jj = 0; jj < Block_Size; jj++)
    {
      sad += iabs(Destination->imgY[y - 1][x + jj] - Destination->imgY[y][x + jj]);
    }
  }
  //! Bottom Neighbor
  if ((y + BLOCK_SIZE) != Destination->size_y && BlockState->imgY[yBlock4x4 + 1][xBlock4x4] != 0)
  {
    for (jj = 0; jj < BLOCK_SIZE; jj++)
    {
      sad += iabs(Destination->imgY[y + BLOCK_SIZE][x + jj] - Destination->imgY[y + BLOCK_SIZE - 1][x + jj]);
    }
  }

  if (sad == 0)
  {
    int a = 0;
  }
  return sad;
}

static int computeSADNeighborsWithEdges(StorablePicture *Destination, StorablePicture *BlockState, int x, int y, int Block_Size, StorablePicture *Edges)
{
  int ii, jj;
  int sad = 0;
  int yBlock4x4 = y / Block_Size, xBlock4x4 = x / Block_Size;
  int discard;

  //  ***** *****
  //  ***** *   *
  //  ***** *   *
  //  ***** *****

  //! Left Neighbor
  if (xBlock4x4 != 0 && BlockState->imgY[yBlock4x4][xBlock4x4 - 1] != 0)
  {
    for (ii = 0; ii < Block_Size; ii++)
    {
      //! Check the egdes
      discard = 0;
      for (jj = -Block_Size / 2; jj <= Block_Size / 2; jj++)
      {
        if (Edges->imgY[y + ii][x + jj] >= 128)
        {
          discard = 1;
          break;
        }
      }
      if (discard)
        continue;
      sad += iabs(Destination->imgY[y + ii][x - 1] - Destination->imgY[y + ii][x]);
    }
  }
  //! Right Neighbor
  if ((x + BLOCK_SIZE) != Destination->size_x && BlockState->imgY[yBlock4x4][xBlock4x4 + 1] != 0)
  {
    for (ii = 0; ii < BLOCK_SIZE; ii++)
    {
      //! Check the egdes
      discard = 0;
      for (jj = -Block_Size / 2; jj <= Block_Size / 2; jj++)
      {
        if (Edges->imgY[y + ii][x + BLOCK_SIZE + jj] >= 128)
        {
          discard = 1;
          break;
        }
      }
      if (discard)
        continue;
      sad += iabs(Destination->imgY[y + ii][x + BLOCK_SIZE - 1] - Destination->imgY[y + ii][x + BLOCK_SIZE]);
    }
  }

  //  *****
  //  *****
  //  *****
  //  *****
  //  *****
  //  *   *
  //  *   *
  //  *****

  //! Top Neighbor
  if (y != 0 && BlockState->imgY[yBlock4x4 - 1][xBlock4x4] != 0)
  {
    for (jj = 0; jj < Block_Size; jj++)
    {
      //! Check the egdes
      discard = 0;
      for (ii = -Block_Size / 2; ii <= Block_Size / 2; ii++)
      {
        if (Edges->imgY[y + ii][x + jj] >= 128)
        {
          discard = 1;
          break;
        }
      }
      if (discard)
        continue;
      sad += iabs(Destination->imgY[y - 1][x + jj] - Destination->imgY[y][x + jj]);
    }
  }
  //! Bottom Neighbor
  if ((y + BLOCK_SIZE) != Destination->size_y && BlockState->imgY[yBlock4x4 + 1][xBlock4x4] != 0)
  {
    for (jj = 0; jj < BLOCK_SIZE; jj++)
    {
      //! Check the egdes
      discard = 0;
      for (ii = -Block_Size / 2; ii <= Block_Size / 2; ii++)
      {
        if (Edges->imgY[y + BLOCK_SIZE + ii][x + jj] >= 128)
        {
          discard = 1;
          break;
        }
      }
      if (discard)
        continue;
      sad += iabs(Destination->imgY[y + BLOCK_SIZE][x + jj] - Destination->imgY[y + BLOCK_SIZE - 1][x + jj]);
    }
  }
  return sad;
}

static double BlockVariance(StorablePicture *Picture, int BlockSize, int xPel, int yPel)
{
  int i, j;
  double n_elem, average_n, average_n_minus1, variance_n;
  imgpel **ImgY = Picture->imgY;

  if (xPel + BlockSize > Picture->size_x || yPel + BlockSize > Picture->size_y)
    return INT_MAX;

  n_elem = 0.0;
  average_n = 0;
  variance_n = 0;

  for (i = yPel; i < yPel + BlockSize; i++)
  {
    for (j = xPel; j < xPel + BlockSize; j++)
    {
      /* On-line average and population variation */
      n_elem++;
      average_n_minus1 = average_n;
      average_n = average_n_minus1 + ((ImgY[i][j] - average_n_minus1) / n_elem);
      variance_n = (n_elem - 1) * variance_n + (ImgY[i][j] - average_n) * (ImgY[i][j] - average_n_minus1);
      variance_n = variance_n / n_elem;
    }
  }
  return variance_n;
}

static int ConcealmentDecision(VideoParameters *p_Vid, int ConcealmentMethod, StorablePicture *IntraRefFrame, StorablePicture *InterRefFrame,
    StorablePicture *Disparity, StorablePicture *Disparity_4x4, MotionPropInfo Matrix_MV_Info, int y_block4x4, int x_block4x4, int Block_Size)
{
  int use_IntraMotionCopy = 1, use_InterMotionCopy = 1;
  int mv_info_count, src_mv_y, src_mv_x;
  int DispDir = p_Vid->p_Inp->DisparityDirection;

  if (ConcealmentMethod != MOTION_INTERVIEW_FIRST && ConcealmentMethod != MOTION_INTRA_INTER_SAD)
    return ConcealmentMethod;

  src_mv_y = y_block4x4;
  src_mv_x = x_block4x4;

  //! Check wich concealment strategies are valid
  if ((mv_info_count = Matrix_MV_Info.mv_info_count[y_block4x4][x_block4x4]) < 0)
  {
    use_IntraMotionCopy = 0;
  }

  src_mv_y = y_block4x4;
  src_mv_x = i_min_max(x_block4x4 * Block_Size + DispDir * (int) (Disparity_4x4->imgY[y_block4x4][x_block4x4]), 0, p_Vid->width - 1);
  src_mv_x = src_mv_x / Block_Size + (((src_mv_x % Block_Size) & 0x2) >> 1);

  if (InterRefFrame->mv_info[src_mv_y][src_mv_x].ref_idx[LIST_0] < 0
      && (InterRefFrame->slice_type != B_SLICE || InterRefFrame->mv_info[src_mv_y][src_mv_x].ref_idx[LIST_1] < 0))
    use_InterMotionCopy = 0;

  if ((use_IntraMotionCopy + use_InterMotionCopy) == 0)
  {
    //return MOTION_INTERVIEW_COPY;
    return CONCEALMV;
  }
  else if ((use_IntraMotionCopy + use_InterMotionCopy) == 1)
  {
    if (use_IntraMotionCopy)
      return MOTION_INTRAVIEW;
    else
      return MOTION_INTERVIEW;
  }
  else
  {
    if (ConcealmentMethod == MOTION_INTERVIEW_FIRST)
      return MOTION_INTERVIEW;

    if (InterRefFrame->mv_info[src_mv_y][src_mv_x].mv[LIST_0].mv_x == Matrix_MV_Info.mv_info[y_block4x4][x_block4x4][mv_info_count].mv[LIST_0].mv_x
        && InterRefFrame->mv_info[src_mv_y][src_mv_x].mv[LIST_0].mv_y == Matrix_MV_Info.mv_info[y_block4x4][x_block4x4][mv_info_count].mv[LIST_0].mv_y
        && InterRefFrame->mv_info[src_mv_y][src_mv_x].ref_idx[LIST_0])
    {
      //Same vectors
      return MOTION_INTERVIEW;
    }

    return (MOTION_INTRAVIEW + MOTION_INTERVIEW);

  }
}

static int ConcealCurrentClusterDisparitySearch(VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int x_pos, int y_pos, int BlockSize,
    int SearchRange, int Inter_NotIntra, int BLockWindow)
{
  StorablePicture *Disparity = IntraInterConc->DisparityBlockwiseAux;
  StorablePicture *BlockConcealmentState = IntraInterConc->BlockConcealmentState;
  StorablePicture *InterRefFrame = IntraInterConc->InterRefFrame;
  StorablePicture *Destination = IntraInterConc->Destination;
  StorablePicture *DifferenceMap = IntraInterConc->SpatialDifference;
  imgpel *storeYUV = IntraInterConc->storeYUV[LIST_0][0];
  int count, y, x, diff, curr_mb_idx, d, x_block, y_block, xx_b, yy_b, num, disp;
  double SAD, MinSAD = 999;
  int iRet = 0, MV[3], xFinalDisp;
  double CurrentDiff;
  int DifferenceThreshold;

  x_block = x_pos / BLOCK_SIZE;
  y_block = y_pos / BLOCK_SIZE;

  disp = 0;
  num = 0;
  for (yy_b = y_block; yy_b < y_block + BlockSize / BLOCK_SIZE; yy_b++)
  {
    for (xx_b = x_block; xx_b < x_block + BlockSize / BLOCK_SIZE; xx_b++)
    {
      disp += Disparity->imgY[yy_b][xx_b];
      if (disp == 255)
        return 0;
      num++;
    }
  }
  disp /= num;

  CurrentDiff = 0;
  count = 0;
  for (y = imax(0, y_block - BLockWindow) * BLOCK_SIZE; y < imin(DifferenceMap->size_y / BLOCK_SIZE, y_block + BLockWindow + 1) * BLOCK_SIZE; y++)
  {
    for (x = imax(0, x_block - BLockWindow) * BLOCK_SIZE; x < imin(DifferenceMap->size_x / BLOCK_SIZE, x_block + BLockWindow + 1) * BLOCK_SIZE; x++)
    {
      if (y >= 0 && y < DifferenceMap->size_y && x >= 0 && x < DifferenceMap->size_x)
      {
        diff = (int) (DifferenceMap->imgY[y][x]);
        CurrentDiff = ((double) (CurrentDiff * count + diff)) / ((double) count + 1);
        count++;
      }
    }
  }

  xFinalDisp = disp;
  //if( CurrentDiff > IntraInterConc->DifferenceThresholds[SPATIAL_DIFF] )
  {
    MinSAD = INT_MAX;
    for (d = -SearchRange; d <= SearchRange; d++)
    {
      if ((x_pos - (disp + d)) < 0 || (x_pos - (disp + d)) >= Destination->size_x)
        continue;
      SAD = computeSADOverlap(IntraInterConc, Destination, x_pos, y_pos, InterRefFrame, x_pos - (disp + d), y_pos, BlockSize, BlockSize + 4 * BLOCK_SIZE);
      if (SAD <= MinSAD)
      {
        MinSAD = SAD;
        xFinalDisp = disp + d;
      }
    }
  }

  if (Inter_NotIntra)
  {
    MV[0] = (-xFinalDisp) * 4;
    MV[1] = 0;
    MV[2] = 0;
  }
  else
  {
    //xFinalDisp /= /BLOCK_SIZE;
    //! For 4x4 blocks
    xFinalDisp = xFinalDisp / BLOCK_SIZE + (((xFinalDisp % BLOCK_SIZE) & 0x2) >> 1);
  }

  for (yy_b = y_block; yy_b < y_block + BlockSize / BLOCK_SIZE; yy_b++)
  {
    for (xx_b = x_block; xx_b < x_block + BlockSize / BLOCK_SIZE; xx_b++)
    {
      curr_mb_idx = yy_b * BLOCK_SIZE / MB_BLOCK_SIZE * IntraInterConc->Destination->PicWidthInMbs + xx_b * BLOCK_SIZE / MB_BLOCK_SIZE;

      if (!Inter_NotIntra)
      {
        getMVInter(IntraInterConc, LIST_0, y_block, x_block - xFinalDisp, MV);
        if (MV[2] < 0)
          continue;
      }

      EnhancedbuildPredblock4x4YUV(p_Vid, MV, xx_b * BLOCK_SIZE, yy_b * BLOCK_SIZE, storeYUV, LIST_0, curr_mb_idx, IntraInterConc->tmp_storeYUV);
      copyPredblockRegionYUVDestination(IntraInterConc->Destination, storeYUV, xx_b * BLOCK_SIZE, yy_b * BLOCK_SIZE, BLOCK_SIZE);

      // set motion vector in the concealed picture
      IntraInterConc->Destination->mv_info[yy_b][xx_b].mv[LIST_0].mv_x = MV[0];
      IntraInterConc->Destination->mv_info[yy_b][xx_b].mv[LIST_0].mv_y = MV[1];
      IntraInterConc->Destination->mv_info[yy_b][xx_b].ref_idx[LIST_0] = MV[2];

      IntraInterConc->BlockConcealmentState->imgY[yy_b][xx_b] = 1;
      iRet++;
    }
  }
  return iRet;
}

static int ConcealCurrentClusterMotionSearch(VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int x_pos, int y_pos, int BlockSize, int SearchRange)
{
  StorablePicture *Disparity = IntraInterConc->DisparityBlockwiseAux;
  StorablePicture *BlockConcealmentState = IntraInterConc->BlockConcealmentState;
  StorablePicture *IntraRefFrame = IntraInterConc->IntraRefFrame;
  StorablePicture *Destination = IntraInterConc->Destination;
  imgpel *storeYUV = IntraInterConc->storeYUV[LIST_0][0];
  int curr_mb_idx, i, d, x_block, y_block, xx_b, yy_b, num, disp;
  double SAD, MinSAD;
  int y_final, x_final;
  int iRet = 0, MVCandidate[2], MV[3], MVFinal[3];

  x_block = x_pos / BLOCK_SIZE;
  y_block = y_pos / BLOCK_SIZE;

  disp = 0;
  num = 0;
  for (yy_b = y_block; yy_b < y_block + BlockSize / BLOCK_SIZE; yy_b++)
  {
    for (xx_b = x_block; xx_b < x_block + BlockSize / BLOCK_SIZE; xx_b++)
    {
      disp += Disparity->imgY[yy_b][xx_b];
      num++;
    }
  }
  disp /= num;

  MVCandidate[0] = 0;
  MVCandidate[1] = 0;
  num = 0;
  getMVInter(IntraInterConc, LIST_0, y_block, x_block - disp / BLOCK_SIZE, MV);
  if (MV[2] >= 0)
  {
    MVCandidate[0] += MV[0];
    MVCandidate[1] += MV[1];
    num++;
  }
  getMVIntra(IntraInterConc, LIST_0, y_block, x_block, MV);
  if (MV[2] >= 0)
  {
    MVCandidate[0] += MV[0];
    MVCandidate[1] += MV[1];
    num++;
  }
  num = num ? num : 1;
  MVCandidate[0] = MV[0] / num;
  MVCandidate[1] = MV[1] / num;

  MinSAD = INT_MAX;
  for (MV[1] = -SearchRange; MV[1] <= SearchRange; MV[1]++)
  {
    for (MV[0] = -SearchRange; MV[0] <= SearchRange; MV[0]++)
    {
      // if( x_pos + MVCandidate[0] + MV[0] )
      SAD = computeSADOverlap(IntraInterConc, Destination, x_pos, y_pos, IntraRefFrame, x_pos + MVCandidate[0] + MV[0], y_pos + MVCandidate[1] + MV[1],
          BlockSize, BlockSize + 4 * BLOCK_SIZE);
      if (SAD < MinSAD)
      {
        MinSAD = SAD;
        MVFinal[0] = MVCandidate[0] + MV[0];
        MVFinal[1] = MVCandidate[1] + MV[1];
      }
    }
  }
  MVFinal[0] *= 4;
  MVFinal[1] *= 4;
  MVFinal[2] = IntraInterConc->MVExtrapolationRefIdx[0];

  for (yy_b = y_block; yy_b < y_block + BlockSize / BLOCK_SIZE; yy_b++)
  {
    for (xx_b = x_block; xx_b < x_block + BlockSize / BLOCK_SIZE; xx_b++)
    {
      curr_mb_idx = yy_b * BLOCK_SIZE / MB_BLOCK_SIZE * IntraInterConc->Destination->PicWidthInMbs + xx_b * BLOCK_SIZE / MB_BLOCK_SIZE;

      EnhancedbuildPredblock4x4YUV(p_Vid, MVFinal, xx_b * BLOCK_SIZE, yy_b * BLOCK_SIZE, storeYUV, LIST_0, curr_mb_idx, IntraInterConc->tmp_storeYUV);
      copyPredblockRegionYUVDestination(IntraInterConc->Destination, storeYUV, xx_b * BLOCK_SIZE, yy_b * BLOCK_SIZE, BLOCK_SIZE);

      // set motion vector in the concealed picture
      IntraInterConc->Destination->mv_info[yy_b][xx_b].mv[LIST_0].mv_x = MVFinal[0];
      IntraInterConc->Destination->mv_info[yy_b][xx_b].mv[LIST_0].mv_y = MVFinal[1];
      IntraInterConc->Destination->mv_info[yy_b][xx_b].ref_idx[LIST_0] = MVFinal[2];

      IntraInterConc->BlockConcealmentState->imgY[yy_b][xx_b] = 1;
      iRet++;
    }
  }
  return iRet;
}
  
static void getCurrentCluster(VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int SameCondition, int x_block, int y_block, int *BlockSize)
{
  StorablePicture *BlockConcealmentState = IntraInterConc->BlockConcealmentState;
  int i, j;
  int Stop, currBlockSize = 1;
  int *curr_mv, mv_intra[3] = { 0, 0, 0 }, mv_inter[3] = { 0, 0, 0 };
  int prev_condition = -1, condition;

  *BlockSize = 0;
  //! Find the first block to conceal
  if (BlockConcealmentState->imgY[y_block][x_block] == 0 && (x_block == 0 || BlockConcealmentState->imgY[y_block][x_block - 1] != 0)
      && (y_block == 0 || BlockConcealmentState->imgY[y_block - 1][x_block] != 0))
  {
    Stop = 0;
    currBlockSize = 0;
    while (1)
    {
      //! Check Vertical side
      for (i = 0; i < currBlockSize + 1; i++)
      {
        if (y_block + i >= BlockConcealmentState->size_y || x_block + currBlockSize >= BlockConcealmentState->size_x
            || BlockConcealmentState->imgY[y_block + i][x_block + currBlockSize] == 1)
        {
          Stop = 1;
          break;
        }

        if (SameCondition)
        {
          getMVIntra(IntraInterConc, LIST_0, y_block + i, x_block + currBlockSize, mv_intra);
          getMVInter(IntraInterConc, LIST_0, y_block + i, x_block + currBlockSize, mv_inter);
          condition = (mv_intra[2] > 0) + (mv_inter[2] > 0) * 10;
          if (prev_condition != -1 && condition != prev_condition)
          {
            Stop = 1;
            break;
          }
          prev_condition = condition;
        }
      }
      //! Check Horizontal side
      for (i = 0; i < currBlockSize + 1; i++)
      {
        if (y_block + currBlockSize >= BlockConcealmentState->size_y || x_block + i >= BlockConcealmentState->size_x
            || BlockConcealmentState->imgY[y_block + currBlockSize][x_block + i] == 1)
        {
          Stop = 1;
          break;
        }

        if (SameCondition)
        {
          getMVIntra(IntraInterConc, LIST_0, y_block + currBlockSize, x_block + i, mv_intra);
          getMVInter(IntraInterConc, LIST_0, y_block + currBlockSize, x_block + i, mv_inter);
          condition = (mv_intra[2] > 0) + (mv_inter[2] > 0) * 10;
          if (prev_condition != -1 && condition != prev_condition)
          {
            Stop = 1;
            break;
          }
          prev_condition = condition;
        }
      }
      if (Stop)
        break;

      currBlockSize++;
    }
    currBlockSize *= BLOCK_SIZE;
    *BlockSize = currBlockSize;
    return;
  }
}

static int ConcealCurrentClusterOnePredictor(VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int x_pos, int y_pos, int BlockSize)
{
  imgpel ***storeYUV = IntraInterConc->storeYUV;
  int *curr_mv, mv_intra[3] = { 0, 0, 0 }, mv_inter[3] = { 0, 0, 0 };
  int curr_mb_idx, x_block, y_block, xx_b, yy_b;
  int prev_case_metric = -1, case_metric;
  int iRet = 0;
  void
  (*getMV)(INTER_INTRA_CONC_T *IntraInterConc, int list, int y_block, int x_block, int MV[3]);

  x_block = x_pos / BLOCK_SIZE;
  y_block = y_pos / BLOCK_SIZE;

  for (xx_b = x_block; xx_b < x_block + BlockSize / BLOCK_SIZE; xx_b++)
  {
    for (yy_b = y_block; yy_b < y_block + BlockSize / BLOCK_SIZE; yy_b++)
    {
      getMVIntra(IntraInterConc, LIST_0, yy_b, xx_b, mv_intra);
      getMVInter(IntraInterConc, LIST_0, yy_b, xx_b, mv_inter);

      case_metric = (mv_intra[2] > 0) + (mv_inter[2] > 0) * 10;

      if (prev_case_metric != -1 && case_metric != prev_case_metric)
      {
        return iRet;
      }
      prev_case_metric = case_metric;
    }
  }

  switch (case_metric)
  {
  case 0: // nothing
    return iRet;
  case 1: // only INTRA
    getMV = getMVIntra;
    break;
  case 10: // only INTER
    getMV = getMVInter;
    break;
  case 11: // both
    //getMV = getMVInter;
    return iRet;
    break;
  default:
    case_metric = 0;
    return iRet;
  }

  for (xx_b = x_block; xx_b < x_block + BlockSize / BLOCK_SIZE; xx_b++)
  {
    for (yy_b = y_block; yy_b < y_block + BlockSize / BLOCK_SIZE; yy_b++)
    {
      getMV(IntraInterConc, LIST_0, yy_b, xx_b, mv_inter);

      curr_mb_idx = yy_b * BLOCK_SIZE / MB_BLOCK_SIZE * IntraInterConc->Destination->PicWidthInMbs + xx_b * BLOCK_SIZE / MB_BLOCK_SIZE;

      EnhancedbuildPredblock4x4YUV(p_Vid, mv_inter, xx_b * BLOCK_SIZE, yy_b * BLOCK_SIZE, storeYUV[LIST_0][0], LIST_0, curr_mb_idx,
          IntraInterConc->tmp_storeYUV);
      copyPredblockRegionYUVDestination(IntraInterConc->Destination, storeYUV[LIST_0][0], xx_b * BLOCK_SIZE, yy_b * BLOCK_SIZE, BLOCK_SIZE);

      // set motion vector in the concealed picture
      IntraInterConc->Destination->mv_info[yy_b][xx_b].mv[LIST_0].mv_x = mv_inter[0];
      IntraInterConc->Destination->mv_info[yy_b][xx_b].mv[LIST_0].mv_y = mv_inter[1];
      IntraInterConc->Destination->mv_info[yy_b][xx_b].ref_idx[LIST_0] = mv_inter[2];

      IntraInterConc->BlockConcealmentState->imgY[yy_b][xx_b] = 1;
      iRet++;
    }
  }
  return iRet;
}

static void getImageEdges(VideoParameters *p_Vid, StorablePicture *BaseviewFrame, StorablePicture *Disparity, StorablePicture *EdgesAuxView)
{
  StorablePicture *EdgesBaseView = NULL;

  EdgesBaseView = alloc_storable_picture(p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1);

  cvFindImageContours(p_Vid, BaseviewFrame, EdgesBaseView);

  DisparityCompensation(p_Vid, EdgesBaseView, EdgesAuxView, Disparity, LEFT);

  //showStorablePicture( p_Vid, EdgesBaseView, 0, 0, "Edges Base", 0 );
  //saveStorablePicture( p_Vid , "EdgesBaseView.bmp" , EdgesBaseView , 0 , 0 );
  //showStorablePicture( p_Vid, EdgesAuxView, 0, 0, "Edges Aux", 0 );
  //saveStorablePicture( p_Vid , "EdgesAuxView.bmp" , EdgesAuxView , 0 , 0 );

  free_storable_picture(EdgesBaseView);

  return;
}


static void getCurrentClusterSafer(VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int x_MB, int y_MB, int block_idx, int *block_size,
    double MSEThreshold, int MV[3])
{
  int cur_idx, max_clust, x_block, y_block, inter_src_block, intra_mv_cnt, tmp_block_size = BLOCK_SIZE;
  int mv_intra[3] = { 0, 0, 0 }, mv_inter[3] = { 0, 0, 0 };

  MV[0] = MV[1] = 0;
  MV[2] = -1;

  *block_size = 0;
  cur_idx = block_idx;

  max_clust = CLUSTER[block_idx];
  max_clust += block_idx;

  cur_idx = block_idx;
  while (cur_idx < max_clust)
  {
    do
    {
      y_block = (y_MB * MB_BLOCK_SIZE / BLOCK_SIZE) + BLOCK_IDX_MB[cur_idx][1];
      x_block = (x_MB * MB_BLOCK_SIZE / BLOCK_SIZE) + BLOCK_IDX_MB[cur_idx][0];

      getMVIntra(IntraInterConc, LIST_0, y_block, x_block, mv_intra);

      getMVInter(IntraInterConc, LIST_0, y_block, x_block, mv_inter);

      if (mv_inter[2] < 0 || mv_intra[2] < 0)
      {
        return; //!< Cannot conceal anymore
      }

      //! Compare mv candidates
      //! If MSE Threshold is equal to zero we do not need to compare MSE, just the prediction
      if (mv_intra[0] == mv_inter[0] && mv_intra[1] == mv_inter[1])
      {
        //! Check reference frames to confirm
        if (mv_intra[2] == mv_inter[2])
        {
          if ((*block_size) == 0 || (mv_intra[0] == MV[0] && mv_intra[1] == MV[1] && mv_intra[2] == MV[2]))
          {
            MV[0] = mv_intra[0];
            MV[1] = mv_intra[1];
            MV[2] = mv_intra[2];
            cur_idx++;
            continue;
          }
        }
      }

      return;
    } while (cur_idx < block_idx + target_cluster(*block_size));
    (*block_size) = (*block_size) ? (*block_size) * 2 : BLOCK_SIZE;
  }
  return;
}


/*!
 ************************************************************************
 * \brief
 *   Compute the block based disparity for each pixel using a square block
 *   for a symmetric window
 *
 *  The Disparity are normalized between
 *     [-WindowsSize, WindowsSize]
 *   Disp = Disp + GlobalWindowsSize + LocalWindowsSize;
 ************************************************************************
 */
static void FullSearchMotionEstimation(imgpel **currImg, imgpel**refImg, int size_x, int size_y, int window, int block_size, int pos_x, int pos_y,
    MotionVector *curr_mv)
{
  int x, y, xx, yy, count;
  int x_min, x_max, y_min, y_max;
  uint16 sad, **sad_vector;

  get_mem2Duint16(&sad_vector, window * 2, window * 2);

  x_min = imax(0, pos_x - window);
  y_max = imin(size_y - block_size, pos_y + window);

  y_min = imax(0, pos_y - window);
  x_max = imin(size_x - block_size, pos_x + window);

  count = 0;
  for (y = y_min; y < y_max; y++)
  {
    for (x = x_min; x < x_max; x++)
    {

      // SAD between the current block and a possible ref block
      for (yy = 0; yy <= block_size; yy++)
      {
        for (xx = 0; xx <= block_size; xx++)
        {
          sad += iabs(currImg[y + yy][x + xx] - refImg[y + yy][x + xx]);
        }
      }
      (*sad_vector)[count++] = sad;
    }
  }
  qsort(sad_vector, count, sizeof(uint16), sort_by_uint16_up);
  // uint16_min_position( sad_vector, unsigned int n_elem, uint16 *min_value, unsigned int *min_pos)
  free_mem2Duint16(sad_vector);
  return;
}