
/*!
 ***********************************************************************
 *  \file
 *      mbuffer.c
 *
 *  \brief
 *      Frame buffer functions
 *
 *  \author
 *      Main contributors (see contributors.h for copyright, address and affiliation details)
 *      - Karsten Sühring                 <suehring@hhi.de>
 *      - Alexis Tourapis                 <alexismt@ieee.org>
 ***********************************************************************
 */

#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#include <string.h>

#include "global.h"
#include "mbuffer.h"
#include "memalloc.h"
#include "output.h"
#include "image.h"
#include "header.h"

static void insert_picture_in_dpb(FrameStore* fs, StorablePicture* p);
static void output_one_frame_from_dpb();
static int  is_used_for_reference(FrameStore* fs);
static void get_smallest_poc(int *poc,int * pos);
static int  remove_unused_frame_from_dpb();
static int  is_short_term_reference(FrameStore* fs);
static int  is_long_term_reference(FrameStore* fs);
void gen_field_ref_ids(StorablePicture *p);

DecodedPictureBuffer dpb;

StorablePicture **listX[6];

ColocatedParams *Co_located = NULL;

extern StorablePicture *dec_picture;

int listXsize[6];

#define MAX_LIST_SIZE 33

/*!
 ************************************************************************
 * \brief
 *    Print out list of pictures in DPB. Used for debug purposes.
 ************************************************************************
 */
void dump_dpb()
{
  unsigned i;

  return;
  
  for (i=0; i<dpb.used_size;i++)
  {
    printf("(");
    printf("fn=%d  ", dpb.fs[i]->frame_num);
    if (dpb.fs[i]->is_used & 1)
    {
      if (dpb.fs[i]->top_field)
        printf("T: poc=%d  ", dpb.fs[i]->top_field->poc);
      else
        printf("T: poc=%d  ", dpb.fs[i]->frame->top_poc);
    }
    if (dpb.fs[i]->is_used & 2)
    {
      if (dpb.fs[i]->bottom_field)
        printf("B: poc=%d  ", dpb.fs[i]->bottom_field->poc);
      else
        printf("B: poc=%d  ", dpb.fs[i]->frame->bottom_poc);
    }
    if (dpb.fs[i]->is_used == 3)
      printf("F: poc=%d  ", dpb.fs[i]->frame->poc);
    printf("G: poc=%d)  ", dpb.fs[i]->poc);
    if (dpb.fs[i]->is_reference) printf ("ref (%d) ", dpb.fs[i]->is_reference);
    if (dpb.fs[i]->is_long_term) printf ("lt_ref (%d) ", dpb.fs[i]->is_reference);
    if (dpb.fs[i]->is_output) printf ("out  ");
    if (dpb.fs[i]->is_used == 3)
    {
      if (dpb.fs[i]->frame->non_existing) printf ("ne  ");
    }
    printf ("\n");
  }
}

/*!
 ************************************************************************
 * \brief
 *    Returns the size of the dpb depending on level and picture size
 *
 *
 ************************************************************************
 */
int getDpbSize()
{
  int pic_size = (active_sps->pic_width_in_mbs_minus1 + 1) * (active_sps->pic_height_in_map_units_minus1 + 1) * (active_sps->frame_mbs_only_flag?1:2) * 384;

  int size = 0;

  switch (active_sps->level_idc)
  {
  case 10:
    size = 152064;
    break;
  case 11:
    size = 345600;
    break;
  case 12:
    size = 912384;
    break;
  case 13:
    size = 912384;
    break;
  case 20:
    size = 912384;
    break;
  case 21:
    size = 1824768;
    break;
  case 22:
    size = 3110400;
    break;
  case 30:
    size = 3110400;
    break;
  case 31:
    size = 6912000;
    break;
  case 32:
    size = 7864320;
    break;
  case 40:
    size = 12582912;
    break;
  case 41:
    size = 12582912;
    break;
  case 42:
    size = 12582912;
    break;
  case 50:
    size = 42393600;
    break;
  case 51:
    size = 70778880;
    break;
  default:
    error ("undefined level", 500);
    break;
  }

  size /= pic_size;
  size = min( size, 16);

  if (active_sps->vui_parameters_present_flag && active_sps->vui_seq_parameters.bitstream_restriction_flag)
  {
    if ((int)active_sps->vui_seq_parameters.max_dec_frame_buffering > size)
    {
      error ("max_dec_frame_buffering larger than MaxDpbSize", 500);
    }
    size = max (1, active_sps->vui_seq_parameters.max_dec_frame_buffering);
  }

  return size;
}

/*!
 ************************************************************************
 * \brief
 *    Check then number of frames marked "used for reference" and break 
 *    if maximum is exceeded
 *
 ************************************************************************
 */
void check_num_ref()
{
  if ((int)(dpb.ltref_frames_in_buffer +  dpb.ref_frames_in_buffer ) > (max(1,dpb.num_ref_frames)))
  {
    error ("Max. number of reference frames exceeded. Invalid stream.", 500);
  }
}


/*!
 ************************************************************************
 * \brief
 *    Allocate memory for decoded picture buffer and initialize with sane values.
 *
 ************************************************************************
 */
void init_dpb()
{
  unsigned i,j;

  if (dpb.init_done)
  {
    free_dpb();
  }

  dpb.size      = getDpbSize();

  dpb.num_ref_frames = active_sps->num_ref_frames;

  if (dpb.size < active_sps->num_ref_frames)
  {
    error ("DPB size at specified level is smaller than the specified number of reference frames. This is not allowed.\n", 1000);
  }

  dpb.used_size = 0;
  dpb.last_picture = NULL;

  dpb.ref_frames_in_buffer = 0;
  dpb.ltref_frames_in_buffer = 0;
  
  dpb.fs = calloc(dpb.size, sizeof (FrameStore*));
  if (NULL==dpb.fs) 
    no_mem_exit("init_dpb: dpb->fs");

  dpb.fs_ref = calloc(dpb.size, sizeof (FrameStore*));
  if (NULL==dpb.fs_ref) 
    no_mem_exit("init_dpb: dpb->fs_ref");

  dpb.fs_ltref = calloc(dpb.size, sizeof (FrameStore*));
  if (NULL==dpb.fs_ltref) 
    no_mem_exit("init_dpb: dpb->fs_ltref");

  for (i=0; i<dpb.size; i++)
  {
    dpb.fs[i]       = alloc_frame_store();
    dpb.fs_ref[i]   = NULL;
    dpb.fs_ltref[i] = NULL;
  }
  
  for (i=0; i<6; i++)
  {
    listX[i] = calloc(MAX_LIST_SIZE, sizeof (StorablePicture*)); // +1 for reordering
    if (NULL==listX[i]) 
      no_mem_exit("init_dpb: listX[i]");
  }

  for (j=0;j<6;j++)
  {
    for (i=0; i<MAX_LIST_SIZE; i++)
    {
      listX[j][i] = NULL;
    }
    listXsize[j]=0;
  }

  dpb.last_output_poc = INT_MIN;

  img->last_has_mmco_5 = 0;

  dpb.init_done = 1;
}


/*!
 ************************************************************************
 * \brief
 *    Free memory for decoded picture buffer.
 ************************************************************************
 */
void free_dpb()
{
  unsigned i;
  if (dpb.fs)
  {
    for (i=0; i<dpb.size; i++)
    {
      free_frame_store(dpb.fs[i]);
    }
    free (dpb.fs);
    dpb.fs=NULL;
  }
  if (dpb.fs_ref)
  {
    free (dpb.fs_ref);
  }
  if (dpb.fs_ltref)
  {
    free (dpb.fs_ltref);
  }
  dpb.last_output_poc = INT_MIN;

  for (i=0; i<6; i++)
    if (listX[i])
    {
      free (listX[i]);
      listX[i] = NULL;
    }

  dpb.init_done = 0;
}


/*!
 ************************************************************************
 * \brief
 *    Allocate memory for decoded picture buffer frame stores an initialize with sane values.
 *
 * \return
 *    the allocated FrameStore structure
 ************************************************************************
 */
FrameStore* alloc_frame_store()
{
  FrameStore *f;

  f = calloc (1, sizeof(FrameStore));
  if (NULL==f) 
    no_mem_exit("alloc_frame_store: f");

  f->is_used      = 0;
  f->is_reference = 0;
  f->is_long_term = 0;
  f->is_orig_reference = 0;

  f->is_output = 0;

  f->frame        = NULL;;
  f->top_field    = NULL;
  f->bottom_field = NULL;

  return f;
}

/*!
 ************************************************************************
 * \brief
 *    Allocate memory for a stored picture. 
 *
 * \param structure
 *    picture structure
 * \param size_x
 *    horizontal luma size
 * \param size_y
 *    vertical luma size
 * \param size_x_cr
 *    horizontal chroma size
 * \param size_y_cr
 *    vertical chroma size
 *
 * \return
 *    the allocated StorablePicture structure
 ************************************************************************
 */
StorablePicture* alloc_storable_picture(PictureStructure structure, int size_x, int size_y, int size_x_cr, int size_y_cr)
{
  StorablePicture *s;

  //printf ("Allocating (%s) picture (x=%d, y=%d, x_cr=%d, y_cr=%d)\n", (type == FRAME)?"FRAME":(type == TOP_FIELD)?"TOP_FIELD":"BOTTOM_FIELD", size_x, size_y, size_x_cr, size_y_cr);

  s = calloc (1, sizeof(StorablePicture));
  if (NULL==s) 
    no_mem_exit("alloc_storable_picture: s");

  if (structure!=FRAME)
  {
    size_y    /= 2;
    size_y_cr /= 2; 
  }

  s->PicSizeInMbs = (size_x*size_y)/256;
  s->imgUV = NULL;

  get_mem2Dpel (&(s->imgY), size_y, size_x);
  if (active_sps->chroma_format_idc != YUV400)
    get_mem3Dpel (&(s->imgUV), 2, size_y_cr, size_x_cr);

  s->mb_field = calloc (s->PicSizeInMbs, sizeof(int));
  if (NULL==s->mb_field) 
    no_mem_exit("alloc_storable_picture: s->mb_field");

  get_mem2Dshort (&(s->slice_id), size_y / MB_BLOCK_SIZE, size_x / MB_BLOCK_SIZE);

  get_mem3D      ((byte****)(&(s->ref_idx))   , 2, size_y / BLOCK_SIZE, size_x / BLOCK_SIZE);
  get_mem3Dint64 (&(s->ref_pic_id), 6, size_y / BLOCK_SIZE, size_x / BLOCK_SIZE);
  get_mem3Dint64 (&(s->ref_id)    , 6, size_y / BLOCK_SIZE, size_x / BLOCK_SIZE);
  get_mem4Dshort (&(s->mv)        , 2, size_y / BLOCK_SIZE, size_x / BLOCK_SIZE, 2);

  get_mem2D      (&(s->moving_block), size_y / BLOCK_SIZE, size_x / BLOCK_SIZE);
  get_mem2D      (&(s->field_frame) , size_y / BLOCK_SIZE, size_x / BLOCK_SIZE);

  s->pic_num=0;
  s->frame_num=0;
  s->long_term_frame_idx=0;
  s->long_term_pic_num=0;
  s->used_for_reference=0;
  s->is_long_term=0;
  s->non_existing=0;
  s->is_output = 0;
  s->max_slice_id = 0;

  s->structure=structure;

  s->size_x = size_x;
  s->size_y = size_y;
  s->size_x_cr = size_x_cr;
  s->size_y_cr = size_y_cr;
  
  s->top_field    = NULL;
  s->bottom_field = NULL;
  s->frame        = NULL;

  s->dec_ref_pic_marking_buffer = NULL;

  s->coded_frame                   = 0;
  s->MbaffFrameFlag                = 0;

  return s;
}

/*!
 ************************************************************************
 * \brief
 *    Free frame store memory.
 *
 * \param f
 *    FrameStore to be freed
 *
 ************************************************************************
 */
void free_frame_store(FrameStore* f)
{
  if (f)
  {
    if (f->frame)
    {
      free_storable_picture(f->frame);
      f->frame=NULL;
    }
    if (f->top_field)
    {
      free_storable_picture(f->top_field);
      f->top_field=NULL;
    }
    if (f->bottom_field)
    {
      free_storable_picture(f->bottom_field);
      f->bottom_field=NULL;
    }
    free(f);
  }
}

/*!
 ************************************************************************
 * \brief
 *    Free picture memory.
 *
 * \param p
 *    Picture to be freed
 *
 ************************************************************************
 */
void free_storable_picture(StorablePicture* p)
{
  if (p)
  {
    if (p->ref_idx)
    {
      free_mem3D ((byte***)p->ref_idx, 2);
      p->ref_idx = NULL;
    }
    
    if (p->ref_pic_id)
    {
      free_mem3Dint64 (p->ref_pic_id, 6);
      p->ref_pic_id = NULL;
    }
    if (p->ref_id)
    {
      free_mem3Dint64 (p->ref_id, 6);
      p->ref_id = NULL;
    }
    if (p->mv)
    {
      free_mem4Dshort (p->mv, 2, p->size_y / BLOCK_SIZE);
      p->mv = NULL;
    }

    if (p->moving_block)
    {
      free_mem2D (p->moving_block);
      p->moving_block=NULL;
    }
    
    if (p->field_frame)
    {
      free_mem2D (p->field_frame);
      p->field_frame=NULL;
    }

    
    if (p->imgY)
    {
      free_mem2Dpel (p->imgY);
      p->imgY=NULL;
    }
    if (p->imgUV)
    {
      free_mem3Dpel (p->imgUV, 2);
      p->imgUV=NULL;
    }
    
    if (p->mb_field)
    {
      free(p->mb_field);
      p->mb_field=NULL;
    }

    free(p);
    p = NULL;
  }
}

/*!
 ************************************************************************
 * \brief
 *    mark FrameStore unused for reference
 *
 ************************************************************************
 */
static void unmark_for_reference(FrameStore* fs)
{

  if (fs->is_used & 1)
  {
    if (fs->top_field)
    {
      fs->top_field->used_for_reference = 0;
    }
  }
  if (fs->is_used & 2)
  {
    if (fs->bottom_field)
    {
      fs->bottom_field->used_for_reference = 0;
    }
  }
  if (fs->is_used == 3)
  {
    if (fs->top_field && fs->bottom_field)
    {
      fs->top_field->used_for_reference = 0;
      fs->bottom_field->used_for_reference = 0;
    }
    fs->frame->used_for_reference = 0;
  }

  fs->is_reference = 0;

  if(fs->frame)
  {
    if (fs->frame->ref_pic_id)
    {
      free_mem3Dint64 (fs->frame->ref_pic_id, 6);
      fs->frame->ref_pic_id = NULL;
    }
    if (fs->frame->ref_id)
    {
      free_mem3Dint64 (fs->frame->ref_id, 6);
      fs->frame->ref_id = NULL;
    }
  }

  if (fs->top_field)
  {
    if (fs->top_field->ref_pic_id)
    {
      free_mem3Dint64 (fs->top_field->ref_pic_id, 6);
      fs->top_field->ref_pic_id = NULL;
    }
    if (fs->top_field->ref_id)
    {
      free_mem3Dint64 (fs->top_field->ref_id, 6);
      fs->top_field->ref_id = NULL;
    }

  }
  if (fs->bottom_field)
  {
    if (fs->bottom_field->ref_pic_id)
    {
      free_mem3Dint64 (fs->bottom_field->ref_pic_id, 6);
      fs->bottom_field->ref_pic_id = NULL;
    }
    if (fs->bottom_field->ref_id)
    {
      free_mem3Dint64 (fs->bottom_field->ref_id, 6);
      fs->bottom_field->ref_id = NULL;
    }
  }

}


/*!
 ************************************************************************
 * \brief
 *    mark FrameStore unused for reference and reset long term flags
 *
 ************************************************************************
 */
static void unmark_for_long_term_reference(FrameStore* fs)
{

  if (fs->is_used & 1)
  {
    if (fs->top_field)
    {
      fs->top_field->used_for_reference = 0;
      fs->top_field->is_long_term = 0;
    }
  }
  if (fs->is_used & 2)
  {
    if (fs->bottom_field)
    {
      fs->bottom_field->used_for_reference = 0;
      fs->bottom_field->is_long_term = 0;
    }
  }
  if (fs->is_used == 3)
  {
    if (fs->top_field && fs->bottom_field)
    {
      fs->top_field->used_for_reference = 0;
      fs->top_field->is_long_term = 0;
      fs->bottom_field->used_for_reference = 0;
      fs->bottom_field->is_long_term = 0;
    }
    fs->frame->used_for_reference = 0;
    fs->frame->is_long_term = 0;
  }

  fs->is_reference = 0;
  fs->is_long_term = 0;
}


/*!
 ************************************************************************
 * \brief
 *    compares two stored pictures by picture number for qsort in descending order
 *
 ************************************************************************
 */
static int compare_pic_by_pic_num_desc( const void *arg1, const void *arg2 )
{
  if ( (*(StorablePicture**)arg1)->pic_num < (*(StorablePicture**)arg2)->pic_num)
    return 1;
  if ( (*(StorablePicture**)arg1)->pic_num > (*(StorablePicture**)arg2)->pic_num)
    return -1;
  else
    return 0;
}

/*!
 ************************************************************************
 * \brief
 *    compares two stored pictures by picture number for qsort in descending order
 *
 ************************************************************************
 */
static int compare_pic_by_lt_pic_num_asc( const void *arg1, const void *arg2 )
{
  if ( (*(StorablePicture**)arg1)->long_term_pic_num < (*(StorablePicture**)arg2)->long_term_pic_num)
    return -1;
  if ( (*(StorablePicture**)arg1)->long_term_pic_num > (*(StorablePicture**)arg2)->long_term_pic_num)
    return 1;
  else
    return 0;
}

/*!
 ************************************************************************
 * \brief
 *    compares two frame stores by pic_num for qsort in descending order
 *
 ************************************************************************
 */
static int compare_fs_by_frame_num_desc( const void *arg1, const void *arg2 )
{
  if ( (*(FrameStore**)arg1)->frame_num_wrap < (*(FrameStore**)arg2)->frame_num_wrap)
    return 1;
  if ( (*(FrameStore**)arg1)->frame_num_wrap > (*(FrameStore**)arg2)->frame_num_wrap)
    return -1;
  else
    return 0;
}


/*!
 ************************************************************************
 * \brief
 *    compares two frame stores by lt_pic_num for qsort in descending order
 *
 ************************************************************************
 */
static int compare_fs_by_lt_pic_idx_asc( const void *arg1, const void *arg2 )
{
  if ( (*(FrameStore**)arg1)->long_term_frame_idx < (*(FrameStore**)arg2)->long_term_frame_idx)
    return -1;
  if ( (*(FrameStore**)arg1)->long_term_frame_idx > (*(FrameStore**)arg2)->long_term_frame_idx)
    return 1;
  else
    return 0;
}


/*!
 ************************************************************************
 * \brief
 *    compares two stored pictures by poc for qsort in ascending order
 *
 ************************************************************************
 */
static int compare_pic_by_poc_asc( const void *arg1, const void *arg2 )
{
  if ( (*(StorablePicture**)arg1)->poc < (*(StorablePicture**)arg2)->poc)
    return -1;
  if ( (*(StorablePicture**)arg1)->poc > (*(StorablePicture**)arg2)->poc)
    return 1;
  else
    return 0;
}


/*!
 ************************************************************************
 * \brief
 *    compares two stored pictures by poc for qsort in descending order
 *
 ************************************************************************
 */
static int compare_pic_by_poc_desc( const void *arg1, const void *arg2 )
{
  if ( (*(StorablePicture**)arg1)->poc < (*(StorablePicture**)arg2)->poc)
    return 1;
  if ( (*(StorablePicture**)arg1)->poc > (*(StorablePicture**)arg2)->poc)
    return -1;
  else
    return 0;
}


/*!
 ************************************************************************
 * \brief
 *    compares two frame stores by poc for qsort in ascending order
 *
 ************************************************************************
 */
static int compare_fs_by_poc_asc( const void *arg1, const void *arg2 )
{
  if ( (*(FrameStore**)arg1)->poc < (*(FrameStore**)arg2)->poc)
    return -1;
  if ( (*(FrameStore**)arg1)->poc > (*(FrameStore**)arg2)->poc)
    return 1;
  else
    return 0;
}


/*!
 ************************************************************************
 * \brief
 *    compares two frame stores by poc for qsort in descending order
 *
 ************************************************************************
 */
static int compare_fs_by_poc_desc( const void *arg1, const void *arg2 )
{
  if ( (*(FrameStore**)arg1)->poc < (*(FrameStore**)arg2)->poc)
    return 1;
  if ( (*(FrameStore**)arg1)->poc > (*(FrameStore**)arg2)->poc)
    return -1;
  else
    return 0;
}


/*!
 ************************************************************************
 * \brief
 *    returns true, if picture is short term reference picture
 *
 ************************************************************************
 */
int is_short_ref(StorablePicture *s)
{
  return ((s->used_for_reference) && (!(s->is_long_term)));
}


/*!
 ************************************************************************
 * \brief
 *    returns true, if picture is long term reference picture
 *
 ************************************************************************
 */
int is_long_ref(StorablePicture *s)
{
  return ((s->used_for_reference) && (s->is_long_term));
}


/*!
 ************************************************************************
 * \brief
 *    Generates a alternating field list from a given FrameStore list
 *
 ************************************************************************
 */
static void gen_pic_list_from_frame_list(PictureStructure currStrcture, FrameStore **fs_list, int list_idx, StorablePicture **list, int *list_size, int long_term)
{
  int top_idx = 0;
  int bot_idx = 0;

  int (*is_ref)(StorablePicture *s);

  if (long_term)
    is_ref=is_long_ref;
  else
    is_ref=is_short_ref;

  if (currStrcture == TOP_FIELD)
  {
    while ((top_idx<list_idx)||(bot_idx<list_idx))
    {
      for ( ; top_idx<list_idx; top_idx++)
      {
        if(fs_list[top_idx]->is_used & 1)
        {
          if(is_ref(fs_list[top_idx]->top_field))
          {
            // short term ref pic
            list[*list_size] = fs_list[top_idx]->top_field;
            (*list_size)++;
            top_idx++;
            break;
          }
        }
      }
      for ( ; bot_idx<list_idx; bot_idx++)
      {
        if(fs_list[bot_idx]->is_used & 2)
        {
          if(is_ref(fs_list[bot_idx]->bottom_field))
          {
            // short term ref pic
            list[*list_size] = fs_list[bot_idx]->bottom_field;
            (*list_size)++;
            bot_idx++;
            break;
          }
        }
      }
    }
  }
  if (currStrcture == BOTTOM_FIELD)
  {
    while ((top_idx<list_idx)||(bot_idx<list_idx))
    {
      for ( ; bot_idx<list_idx; bot_idx++)
      {
        if(fs_list[bot_idx]->is_used & 2)
        {
          if(is_ref(fs_list[bot_idx]->bottom_field))
          {
            // short term ref pic
            list[*list_size] = fs_list[bot_idx]->bottom_field;
            (*list_size)++;
            bot_idx++;
            break;
          }
        }
      }
      for ( ; top_idx<list_idx; top_idx++)
      {
        if(fs_list[top_idx]->is_used & 1)
        {
          if(is_ref(fs_list[top_idx]->top_field))
          {
            // short term ref pic
            list[*list_size] = fs_list[top_idx]->top_field;
            (*list_size)++;
            top_idx++;
            break;
          }
        }
      }
    }
  }
}


/*!
 ************************************************************************
 * \brief
 *    Initialize listX[0] and list 1 depending on current picture type
 *
 ************************************************************************
 */
void init_lists(int currSliceType, PictureStructure currPicStructure)
{
  int add_top = 0, add_bottom = 0;
  unsigned i;
  int j;
  int MaxFrameNum = 1 << (active_sps->log2_max_frame_num_minus4 + 4);
  int diff;

  int list0idx = 0;
  int list0idx_1 = 0;
  int listltidx = 0;

  FrameStore **fs_list0;
  FrameStore **fs_list1;
  FrameStore **fs_listlt;

  StorablePicture *tmp_s;

  if (currPicStructure == FRAME)  
  {
    for (i=0; i<dpb.ref_frames_in_buffer; i++)
    {
      if (dpb.fs_ref[i]->is_used==3)
      {
        if ((dpb.fs_ref[i]->frame->used_for_reference)&&(!dpb.fs_ref[i]->frame->is_long_term))
        {
          if( dpb.fs_ref[i]->frame_num > img->frame_num )
          {
            dpb.fs_ref[i]->frame_num_wrap = dpb.fs_ref[i]->frame_num - MaxFrameNum;
          }
          else
          {
            dpb.fs_ref[i]->frame_num_wrap = dpb.fs_ref[i]->frame_num;
          }
          dpb.fs_ref[i]->frame->pic_num = dpb.fs_ref[i]->frame_num_wrap;
        }
      }
    }
    // update long_term_pic_num
    for (i=0; i<dpb.ltref_frames_in_buffer; i++)
    {
      if (dpb.fs_ltref[i]->is_used==3)
      {
        if (dpb.fs_ltref[i]->frame->is_long_term)
        {
          dpb.fs_ltref[i]->frame->long_term_pic_num = dpb.fs_ltref[i]->frame->long_term_frame_idx;
        }
      }
    }
  }
  else
  {
    if (currPicStructure == TOP_FIELD)
    {
      add_top    = 1;
      add_bottom = 0;
    }
    else
    {
      add_top    = 0;
      add_bottom = 1;
    }
    
    for (i=0; i<dpb.ref_frames_in_buffer; i++)
    {
      if (dpb.fs_ref[i]->is_reference)
      {
        if( dpb.fs_ref[i]->frame_num > img->frame_num )
        {
          dpb.fs_ref[i]->frame_num_wrap = dpb.fs_ref[i]->frame_num - MaxFrameNum;
        }
        else
        {
          dpb.fs_ref[i]->frame_num_wrap = dpb.fs_ref[i]->frame_num;
        }
        if (dpb.fs_ref[i]->is_reference & 1)
        {
          dpb.fs_ref[i]->top_field->pic_num = (2 * dpb.fs_ref[i]->frame_num_wrap) + add_top;
        }
        if (dpb.fs_ref[i]->is_reference & 2)
        {
          dpb.fs_ref[i]->bottom_field->pic_num = (2 * dpb.fs_ref[i]->frame_num_wrap) + add_bottom;
        }
      }
    }
    // update long_term_pic_num
    for (i=0; i<dpb.ltref_frames_in_buffer; i++)
    {
      if (dpb.fs_ltref[i]->is_long_term & 1)
      {
        dpb.fs_ltref[i]->top_field->long_term_pic_num = 2 * dpb.fs_ltref[i]->top_field->long_term_frame_idx + add_top;
      }
      if (dpb.fs_ltref[i]->is_long_term & 2)
      {
        dpb.fs_ltref[i]->bottom_field->long_term_pic_num = 2 * dpb.fs_ltref[i]->bottom_field->long_term_frame_idx + add_bottom;
      }
    }
  }



  if ((currSliceType == I_SLICE)||(currSliceType == SI_SLICE))
  {
    listXsize[0] = 0;
    listXsize[1] = 0;
    return;
  }

  if ((currSliceType == P_SLICE)||(currSliceType == SP_SLICE))
  {
    // Calculate FrameNumWrap and PicNum
    if (currPicStructure == FRAME)  
    {
      for (i=0; i<dpb.ref_frames_in_buffer; i++)
      {
        if (dpb.fs_ref[i]->is_used==3)
        {
          if ((dpb.fs_ref[i]->frame->used_for_reference)&&(!dpb.fs_ref[i]->frame->is_long_term))
          {
            listX[0][list0idx++] = dpb.fs_ref[i]->frame;
          }
        }
      }
      // order list 0 by PicNum
      qsort((void *)listX[0], list0idx, sizeof(StorablePicture*), compare_pic_by_pic_num_desc);
      listXsize[0] = list0idx;
//      printf("listX[0] (PicNum): "); for (i=0; i<list0idx; i++){printf ("%d  ", listX[0][i]->pic_num);} printf("\n");

      // long term handling
      for (i=0; i<dpb.ltref_frames_in_buffer; i++)
      {
        if (dpb.fs_ltref[i]->is_used==3)
        {
          if (dpb.fs_ltref[i]->frame->is_long_term)
          {
            listX[0][list0idx++]=dpb.fs_ltref[i]->frame;
          }
        }
      }
      qsort((void *)&listX[0][listXsize[0]], list0idx-listXsize[0], sizeof(StorablePicture*), compare_pic_by_lt_pic_num_asc);
      listXsize[0] = list0idx;
    }
    else
    {
      fs_list0 = calloc(dpb.size, sizeof (FrameStore*));
      if (NULL==fs_list0) 
         no_mem_exit("init_lists: fs_list0");
      fs_listlt = calloc(dpb.size, sizeof (FrameStore*));
      if (NULL==fs_listlt) 
         no_mem_exit("init_lists: fs_listlt");

      for (i=0; i<dpb.ref_frames_in_buffer; i++)
      {
        if (dpb.fs_ref[i]->is_reference)
        {
          fs_list0[list0idx++] = dpb.fs_ref[i];
        }
      }

      qsort((void *)fs_list0, list0idx, sizeof(FrameStore*), compare_fs_by_frame_num_desc);

//      printf("fs_list0 (FrameNum): "); for (i=0; i<list0idx; i++){printf ("%d  ", fs_list0[i]->frame_num_wrap);} printf("\n");

      listXsize[0] = 0;
      gen_pic_list_from_frame_list(currPicStructure, fs_list0, list0idx, listX[0], &listXsize[0], 0);

//      printf("listX[0] (PicNum): "); for (i=0; i<listXsize[0]; i++){printf ("%d  ", listX[0][i]->pic_num);} printf("\n");

      // long term handling
      for (i=0; i<dpb.ltref_frames_in_buffer; i++)
      {
        fs_listlt[listltidx++]=dpb.fs_ltref[i];
      }

      qsort((void *)fs_listlt, listltidx, sizeof(FrameStore*), compare_fs_by_lt_pic_idx_asc);

      gen_pic_list_from_frame_list(currPicStructure, fs_listlt, listltidx, listX[0], &listXsize[0], 1);

      free(fs_list0);
      free(fs_listlt);
    }
    listXsize[1] = 0;
  }
  else
  {
    // B-Slice
    if (currPicStructure == FRAME)  
    {
      for (i=0; i<dpb.ref_frames_in_buffer; i++)
      {
        if (dpb.fs_ref[i]->is_used==3)
        {
          if ((dpb.fs_ref[i]->frame->used_for_reference)&&(!dpb.fs_ref[i]->frame->is_long_term))
          {
            if (img->framepoc > dpb.fs_ref[i]->frame->poc)
            {
              listX[0][list0idx++] = dpb.fs_ref[i]->frame;
            }
          }
        }
      }
      qsort((void *)listX[0], list0idx, sizeof(StorablePicture*), compare_pic_by_poc_desc);
      list0idx_1 = list0idx;
      for (i=0; i<dpb.ref_frames_in_buffer; i++)
      {
        if (dpb.fs_ref[i]->is_used==3)
        {
          if ((dpb.fs_ref[i]->frame->used_for_reference)&&(!dpb.fs_ref[i]->frame->is_long_term))
          {
            if (img->framepoc < dpb.fs_ref[i]->frame->poc)
            {
              listX[0][list0idx++] = dpb.fs_ref[i]->frame;
            }
          }
        }
      }
      qsort((void *)&listX[0][list0idx_1], list0idx-list0idx_1, sizeof(StorablePicture*), compare_pic_by_poc_asc);

      for (j=0; j<list0idx_1; j++)
      {
        listX[1][list0idx-list0idx_1+j]=listX[0][j];
      }
      for (j=list0idx_1; j<list0idx; j++)
      {
        listX[1][j-list0idx_1]=listX[0][j];
      }

      listXsize[0] = listXsize[1] = list0idx;

//      printf("listX[0] currPoc=%d (Poc): ", img->framepoc); for (i=0; i<listXsize[0]; i++){printf ("%d  ", listX[0][i]->poc);} printf("\n");
//      printf("listX[1] currPoc=%d (Poc): ", img->framepoc); for (i=0; i<listXsize[1]; i++){printf ("%d  ", listX[1][i]->poc);} printf("\n");

      // long term handling
      for (i=0; i<dpb.ltref_frames_in_buffer; i++)
      {
        if (dpb.fs_ltref[i]->is_used==3)
        {
          if (dpb.fs_ltref[i]->frame->is_long_term)
          {
            listX[0][list0idx]  =dpb.fs_ltref[i]->frame;
            listX[1][list0idx++]=dpb.fs_ltref[i]->frame;
          }
        }
      }
      qsort((void *)&listX[0][listXsize[0]], list0idx-listXsize[0], sizeof(StorablePicture*), compare_pic_by_lt_pic_num_asc);
      qsort((void *)&listX[1][listXsize[0]], list0idx-listXsize[0], sizeof(StorablePicture*), compare_pic_by_lt_pic_num_asc);
      listXsize[0] = listXsize[1] = list0idx;
    }
    else
    {
      fs_list0 = calloc(dpb.size, sizeof (FrameStore*));
      if (NULL==fs_list0) 
         no_mem_exit("init_lists: fs_list0");
      fs_list1 = calloc(dpb.size, sizeof (FrameStore*));
      if (NULL==fs_list1) 
         no_mem_exit("init_lists: fs_list1");
      fs_listlt = calloc(dpb.size, sizeof (FrameStore*));
      if (NULL==fs_listlt) 
         no_mem_exit("init_lists: fs_listlt");

      listXsize[0] = 0;
      listXsize[1] = 1;

      for (i=0; i<dpb.ref_frames_in_buffer; i++)
      {
        if (dpb.fs_ref[i]->is_used)
        {
          if (img->ThisPOC >= dpb.fs_ref[i]->poc)
          {
            fs_list0[list0idx++] = dpb.fs_ref[i];
          }
        }
      }
      qsort((void *)fs_list0, list0idx, sizeof(FrameStore*), compare_fs_by_poc_desc);
      list0idx_1 = list0idx;
      for (i=0; i<dpb.ref_frames_in_buffer; i++)
      {
        if (dpb.fs_ref[i]->is_used)
        {
          if (img->ThisPOC < dpb.fs_ref[i]->poc)
          {
            fs_list0[list0idx++] = dpb.fs_ref[i];
          }
        }
      }
      qsort((void *)&fs_list0[list0idx_1], list0idx-list0idx_1, sizeof(FrameStore*), compare_fs_by_poc_asc);

      for (j=0; j<list0idx_1; j++)
      {
        fs_list1[list0idx-list0idx_1+j]=fs_list0[j];
      }
      for (j=list0idx_1; j<list0idx; j++)
      {
        fs_list1[j-list0idx_1]=fs_list0[j];
      }
      
//      printf("fs_list0 currPoc=%d (Poc): ", img->ThisPOC); for (i=0; i<list0idx; i++){printf ("%d  ", fs_list0[i]->poc);} printf("\n");
//      printf("fs_list1 currPoc=%d (Poc): ", img->ThisPOC); for (i=0; i<list0idx; i++){printf ("%d  ", fs_list1[i]->poc);} printf("\n");

      listXsize[0] = 0;
      listXsize[1] = 0;
      gen_pic_list_from_frame_list(currPicStructure, fs_list0, list0idx, listX[0], &listXsize[0], 0);
      gen_pic_list_from_frame_list(currPicStructure, fs_list1, list0idx, listX[1], &listXsize[1], 0);

//      printf("listX[0] currPoc=%d (Poc): ", img->framepoc); for (i=0; i<listXsize[0]; i++){printf ("%d  ", listX[0][i]->poc);} printf("\n");
//      printf("listX[1] currPoc=%d (Poc): ", img->framepoc); for (i=0; i<listXsize[1]; i++){printf ("%d  ", listX[1][i]->poc);} printf("\n");

      // long term handling
      for (i=0; i<dpb.ltref_frames_in_buffer; i++)
      {
        fs_listlt[listltidx++]=dpb.fs_ltref[i];
      }

      qsort((void *)fs_listlt, listltidx, sizeof(FrameStore*), compare_fs_by_lt_pic_idx_asc);

      gen_pic_list_from_frame_list(currPicStructure, fs_listlt, listltidx, listX[0], &listXsize[0], 1);
      gen_pic_list_from_frame_list(currPicStructure, fs_listlt, listltidx, listX[1], &listXsize[1], 1);

      free(fs_list0);
      free(fs_list1);
      free(fs_listlt);
    }
  }

  if ((listXsize[0] == listXsize[1]) && (listXsize[0] > 1))
  {
    // check if lists are identical, if yes swap first two elements of listX[1]
    diff=0;
    for (j = 0; j< listXsize[0]; j++)
    {
      if (listX[0][j]!=listX[1][j])
        diff=1;
    }
    if (!diff)
    {
      tmp_s = listX[1][0];
      listX[1][0]=listX[1][1];
      listX[1][1]=tmp_s;
    }
  }
  // set max size
  listXsize[0] = min (listXsize[0], img->num_ref_idx_l0_active);
  listXsize[1] = min (listXsize[1], img->num_ref_idx_l1_active);

  // set the unused list entries to NULL
  for (i=listXsize[0]; i< (MAX_LIST_SIZE) ; i++)
  {
    listX[0][i] = NULL;
  }
  for (i=listXsize[1]; i< (MAX_LIST_SIZE) ; i++)
  {
    listX[1][i] = NULL;
  }
}

/*!
 ************************************************************************
 * \brief
 *    Initilaize listX[2..5] from lists 0 and 1
 *    listX[2]: list0 for current_field==top
 *    listX[3]: list1 for current_field==top
 *    listX[4]: list0 for current_field==bottom
 *    listX[5]: list1 for current_field==bottom
 *
 ************************************************************************
 */
void init_mbaff_lists()
{
  unsigned j;
  int i;

  for (i=2;i<6;i++)
  {
    for (j=0; j<MAX_LIST_SIZE; j++)
    {
      listX[i][j] = NULL;
    }
    listXsize[i]=0;
  }

  for (i=0; i<listXsize[0]; i++)
  {
    listX[2][2*i]  =listX[0][i]->top_field;
    listX[2][2*i+1]=listX[0][i]->bottom_field;
    listX[4][2*i]  =listX[0][i]->bottom_field;
    listX[4][2*i+1]=listX[0][i]->top_field;
  }
  listXsize[2]=listXsize[4]=listXsize[0] * 2;

  for (i=0; i<listXsize[1]; i++)
  {
    listX[3][2*i]  =listX[1][i]->top_field;
    listX[3][2*i+1]=listX[1][i]->bottom_field;
    listX[5][2*i]  =listX[1][i]->bottom_field;
    listX[5][2*i+1]=listX[1][i]->top_field;
  }
  listXsize[3]=listXsize[5]=listXsize[1] * 2;
}
 
 /*!
 ************************************************************************
 * \brief
 *    Returns short term pic with given picNum
 *
 ************************************************************************
 */
static StorablePicture*  get_short_term_pic(int picNum)
{
  unsigned i;

  for (i=0; i<dpb.ref_frames_in_buffer; i++)
  {
    if (img->structure==FRAME)
    {
      if (dpb.fs_ref[i]->is_reference == 3)
        if ((!dpb.fs_ref[i]->frame->is_long_term)&&(dpb.fs_ref[i]->frame->pic_num == picNum))
          return dpb.fs_ref[i]->frame;
    }
    else
    {
      if (dpb.fs_ref[i]->is_reference & 1)
        if ((!dpb.fs_ref[i]->top_field->is_long_term)&&(dpb.fs_ref[i]->top_field->pic_num == picNum))
          return dpb.fs_ref[i]->top_field;
      if (dpb.fs_ref[i]->is_reference & 2)
        if ((!dpb.fs_ref[i]->bottom_field->is_long_term)&&(dpb.fs_ref[i]->bottom_field->pic_num == picNum))
          return dpb.fs_ref[i]->bottom_field;
    }
  }
  return NULL;
}

/*!
 ************************************************************************
 * \brief
 *    Returns short term pic with given LongtermPicNum
 *
 ************************************************************************
 */
static StorablePicture*  get_long_term_pic(int LongtermPicNum)
{
  unsigned i;

  for (i=0; i<dpb.ltref_frames_in_buffer; i++)
  {
    if (img->structure==FRAME)
    {
      if (dpb.fs_ltref[i]->is_reference == 3)
        if ((dpb.fs_ltref[i]->frame->is_long_term)&&(dpb.fs_ltref[i]->frame->long_term_pic_num == LongtermPicNum))
          return dpb.fs_ltref[i]->frame;
    }
    else
    {
      if (dpb.fs_ltref[i]->is_reference & 1)
        if ((dpb.fs_ltref[i]->top_field->is_long_term)&&(dpb.fs_ltref[i]->top_field->long_term_pic_num == LongtermPicNum))
          return dpb.fs_ltref[i]->top_field;
      if (dpb.fs_ltref[i]->is_reference & 2)
        if ((dpb.fs_ltref[i]->bottom_field->is_long_term)&&(dpb.fs_ltref[i]->bottom_field->long_term_pic_num == LongtermPicNum))
          return dpb.fs_ltref[i]->bottom_field;
    }
  }
  return NULL;
}

/*!
 ************************************************************************
 * \brief
 *    Reordering process for short-term reference pictures
 *
 ************************************************************************
 */
static void reorder_short_term(StorablePicture **RefPicListX, int num_ref_idx_lX_active_minus1, int picNumLX, int *refIdxLX)
{
  int cIdx, nIdx;

  StorablePicture *picLX;

  picLX = get_short_term_pic(picNumLX);

  for( cIdx = num_ref_idx_lX_active_minus1+1; cIdx > *refIdxLX; cIdx-- )
    RefPicListX[ cIdx ] = RefPicListX[ cIdx - 1];
  
  RefPicListX[ (*refIdxLX)++ ] = picLX;

  nIdx = *refIdxLX;

  for( cIdx = *refIdxLX; cIdx <= num_ref_idx_lX_active_minus1+1; cIdx++ )
    if (RefPicListX[ cIdx ])
      if( (RefPicListX[ cIdx ]->is_long_term ) ||  (RefPicListX[ cIdx ]->pic_num != picNumLX ))
        RefPicListX[ nIdx++ ] = RefPicListX[ cIdx ];

}


/*!
 ************************************************************************
 * \brief
 *    Reordering process for short-term reference pictures
 *
 ************************************************************************
 */
static void reorder_long_term(StorablePicture **RefPicListX, int num_ref_idx_lX_active_minus1, int LongTermPicNum, int *refIdxLX)
{
  int cIdx, nIdx;

  StorablePicture *picLX;

  picLX = get_long_term_pic(LongTermPicNum);

  for( cIdx = num_ref_idx_lX_active_minus1+1; cIdx > *refIdxLX; cIdx-- )
    RefPicListX[ cIdx ] = RefPicListX[ cIdx - 1];
  
  RefPicListX[ (*refIdxLX)++ ] = picLX;

  nIdx = *refIdxLX;

  for( cIdx = *refIdxLX; cIdx <= num_ref_idx_lX_active_minus1+1; cIdx++ )
    if( (!RefPicListX[ cIdx ]->is_long_term ) ||  (RefPicListX[ cIdx ]->long_term_pic_num != LongTermPicNum ))
      RefPicListX[ nIdx++ ] = RefPicListX[ cIdx ];
}


/*!
 ************************************************************************
 * \brief
 *    Reordering process for reference picture lists
 *
 ************************************************************************
 */
void reorder_ref_pic_list(StorablePicture **list, int *list_size, int num_ref_idx_lX_active_minus1, int *remapping_of_pic_nums_idc, int *abs_diff_pic_num_minus1, int *long_term_pic_idx)
{
  int i;

  int maxPicNum, currPicNum, picNumLXNoWrap, picNumLXPred, picNumLX;
  int refIdxLX = 0;

  if (img->structure==FRAME)
  {
    maxPicNum  = img->MaxFrameNum;
    currPicNum = img->frame_num;
  }
  else
  {
    maxPicNum  = 2 * img->MaxFrameNum;
    currPicNum = 2 * img->frame_num + 1;
  }

  picNumLXPred = currPicNum;

  for (i=0; remapping_of_pic_nums_idc[i]!=3; i++)
  {
    if (remapping_of_pic_nums_idc[i]>3)
      error ("Invalid remapping_of_pic_nums_idc command", 500);

    if (remapping_of_pic_nums_idc[i] < 2)
    {
      if (remapping_of_pic_nums_idc[i] == 0)
      {
        if( picNumLXPred - ( abs_diff_pic_num_minus1[i] + 1 ) < 0 )
          picNumLXNoWrap = picNumLXPred - ( abs_diff_pic_num_minus1[i] + 1 ) + maxPicNum;
        else
          picNumLXNoWrap = picNumLXPred - ( abs_diff_pic_num_minus1[i] + 1 );
      }
      else // (remapping_of_pic_nums_idc[i] == 1)
      {
        if( picNumLXPred + ( abs_diff_pic_num_minus1[i] + 1 )  >=  maxPicNum )
          picNumLXNoWrap = picNumLXPred + ( abs_diff_pic_num_minus1[i] + 1 ) - maxPicNum;
        else
          picNumLXNoWrap = picNumLXPred + ( abs_diff_pic_num_minus1[i] + 1 );
      }
      picNumLXPred = picNumLXNoWrap;

      if( picNumLXNoWrap > currPicNum )
        picNumLX = picNumLXNoWrap - maxPicNum;
      else
        picNumLX = picNumLXNoWrap;

      reorder_short_term(list, num_ref_idx_lX_active_minus1, picNumLX, &refIdxLX);
    }
    else //(remapping_of_pic_nums_idc[i] == 2)
    {
      reorder_long_term(list, num_ref_idx_lX_active_minus1, long_term_pic_idx[i], &refIdxLX);
    }
    
  }
  // that's a definition
  *list_size = num_ref_idx_lX_active_minus1 + 1;
}



/*!
 ************************************************************************
 * \brief
 *    Update the list of frame stores that contain reference frames/fields
 *
 ************************************************************************
 */
void update_ref_list()
{
  unsigned i, j;
  for (i=0, j=0; i<dpb.used_size; i++)
  {
    if (is_short_term_reference(dpb.fs[i]))
    {
      dpb.fs_ref[j++]=dpb.fs[i];
    }
  }

  dpb.ref_frames_in_buffer = j;

  while (j<dpb.size)
  {
    dpb.fs_ref[j++]=NULL;
  }
}


/*!
 ************************************************************************
 * \brief
 *    Update the list of frame stores that contain long-term reference 
 *    frames/fields
 *
 ************************************************************************
 */
void update_ltref_list()
{
  unsigned i, j;
  for (i=0, j=0; i<dpb.used_size; i++)
  {
    if (is_long_term_reference(dpb.fs[i]))
    {
      dpb.fs_ltref[j++]=dpb.fs[i];
    }
  }

  dpb.ltref_frames_in_buffer=j;

  while (j<dpb.size)
  {
    dpb.fs_ltref[j++]=NULL;
  }
}

/*!
 ************************************************************************
 * \brief
 *    Perform Memory management for idr pictures
 *
 ************************************************************************
 */
static void idr_memory_management(StorablePicture* p)
{
  unsigned i;

  assert (p->idr_flag);

  if (p->no_output_of_prior_pics_flag)
  {
    // free all stored pictures
    for (i=0; i<dpb.used_size; i++)
    {
      // reset all reference settings
      free_frame_store(dpb.fs[i]);
      dpb.fs[i] = alloc_frame_store();
    }
    for (i=0; i<dpb.ref_frames_in_buffer; i++)
    {
      dpb.fs_ref[i]=NULL;
    }
    for (i=0; i<dpb.ltref_frames_in_buffer; i++)
    {
      dpb.fs_ltref[i]=NULL;
    }
    dpb.used_size=0;
  }
  else
  {
    flush_dpb();
  }
  dpb.last_picture = NULL;

  update_ref_list();
  update_ltref_list();
  dpb.last_output_poc = INT_MIN;
  
  if (p->long_term_reference_flag)
  {
    dpb.max_long_term_pic_idx = 0;
    p->is_long_term           = 1;
    p->long_term_frame_idx    = 0;
  }
  else
  {
    dpb.max_long_term_pic_idx = -1;
    p->is_long_term           = 0;
  }
}

/*!
 ************************************************************************
 * \brief
 *    Perform Sliding window decoded reference picture marking process
 *
 ************************************************************************
 */
static void sliding_window_memory_management(StorablePicture* p)
{
  unsigned i;

  assert (!p->idr_flag);
  // if this is a reference pic with sliding sliding window, unmark first ref frame
  if (dpb.ref_frames_in_buffer==dpb.num_ref_frames - dpb.ltref_frames_in_buffer)
  {
    for (i=0; i<dpb.used_size;i++)
    {
      if (dpb.fs[i]->is_reference  && (!(dpb.fs[i]->is_long_term)))
      {
        unmark_for_reference(dpb.fs[i]);
        update_ref_list();
        break;
      }
    }
  }

  p->is_long_term = 0;
}

/*!
 ************************************************************************
 * \brief
 *    Calculate picNumX
 ************************************************************************
 */
static int get_pic_num_x (StorablePicture *p, int difference_of_pic_nums_minus1)
{
  int currPicNum;

  if (p->structure == FRAME)
    currPicNum = p->frame_num;
  else 
    currPicNum = 2 * p->frame_num + 1;
  
  return currPicNum - (difference_of_pic_nums_minus1 + 1);
}


/*!
 ************************************************************************
 * \brief
 *    Adaptive Memory Management: Mark short term picture unused
 ************************************************************************
 */
static void mm_unmark_short_term_for_reference(StorablePicture *p, int difference_of_pic_nums_minus1)
{
  int picNumX;

  unsigned i;

  picNumX = get_pic_num_x(p, difference_of_pic_nums_minus1);

  for (i=0; i<dpb.ref_frames_in_buffer; i++)
  {
    if (p->structure == FRAME)
    {
      if ((dpb.fs_ref[i]->is_reference==3) && (dpb.fs_ref[i]->is_long_term==0))
      {
        if (dpb.fs_ref[i]->frame->pic_num == picNumX)
        {
          unmark_for_reference(dpb.fs_ref[i]);
          return;
        }
      }
    }
    else
    {
      if ((dpb.fs_ref[i]->is_reference & 1) && (!(dpb.fs_ref[i]->is_long_term & 1)))
      {
        if (dpb.fs_ref[i]->top_field->pic_num == picNumX)
        {
          dpb.fs_ref[i]->top_field->used_for_reference = 0;
          dpb.fs_ref[i]->is_reference &= 2;
          if (dpb.fs_ref[i]->is_used == 3)
          {
            dpb.fs_ref[i]->frame->used_for_reference = 0;
          }
          return;
        }
      }
      if ((dpb.fs_ref[i]->is_reference & 2) && (!(dpb.fs_ref[i]->is_long_term & 2)))
      {
        if (dpb.fs_ref[i]->bottom_field->pic_num == picNumX)
        {
          dpb.fs_ref[i]->bottom_field->used_for_reference = 0;
          dpb.fs_ref[i]->is_reference &= 1;
          if (dpb.fs_ref[i]->is_used == 3)
          {
            dpb.fs_ref[i]->frame->used_for_reference = 0;
          }
          return;
        }
      }
    }
  }
}


/*!
 ************************************************************************
 * \brief
 *    Adaptive Memory Management: Mark long term picture unused
 ************************************************************************
 */
static void mm_unmark_long_term_for_reference(StorablePicture *p, int long_term_pic_num)
{
  unsigned i;
  for (i=0; i<dpb.ltref_frames_in_buffer; i++)
  {
    if (p->structure == FRAME)
    {
      if ((dpb.fs_ltref[i]->is_reference==3) && (dpb.fs_ltref[i]->is_long_term==3))
      {
        if (dpb.fs_ltref[i]->frame->long_term_pic_num == long_term_pic_num)
        {
          unmark_for_long_term_reference(dpb.fs_ltref[i]);
        }
      }
    }
    else
    {
      if ((dpb.fs_ltref[i]->is_reference & 1) && ((dpb.fs_ltref[i]->is_long_term & 1)))
      {
        if (dpb.fs_ltref[i]->top_field->long_term_pic_num == long_term_pic_num)
        {
          dpb.fs_ltref[i]->top_field->used_for_reference = 0;
          dpb.fs_ltref[i]->top_field->is_long_term = 0;
          dpb.fs_ltref[i]->is_reference &= 2;
          dpb.fs_ltref[i]->is_long_term &= 2;
          if (dpb.fs_ltref[i]->is_used == 3)
          {
            dpb.fs_ltref[i]->frame->used_for_reference = 0;
            dpb.fs_ltref[i]->frame->is_long_term = 0;
          }
          return;
        }
      }
      if ((dpb.fs_ltref[i]->is_reference & 2) && ((dpb.fs_ltref[i]->is_long_term & 2)))
      {
        if (dpb.fs_ltref[i]->bottom_field->long_term_pic_num == long_term_pic_num)
        {
          dpb.fs_ltref[i]->bottom_field->used_for_reference = 0;
          dpb.fs_ltref[i]->bottom_field->is_long_term = 0;
          dpb.fs_ltref[i]->is_reference &= 1;
          dpb.fs_ltref[i]->is_long_term &= 1;
          if (dpb.fs_ltref[i]->is_used == 3)
          {
            dpb.fs_ltref[i]->frame->used_for_reference = 0;
            dpb.fs_ltref[i]->frame->is_long_term = 0;
          }
          return;
        }
      }
    }
  }
}


/*!
 ************************************************************************
 * \brief
 *    Mark a long-term reference frame or complementary field pair unused for referemce
 ************************************************************************
 */
static void unmark_long_term_frame_for_reference_by_frame_idx(int long_term_frame_idx)
{
  unsigned i;
  for(i=0; i<dpb.ltref_frames_in_buffer; i++)
  {
    if (dpb.fs_ltref[i]->long_term_frame_idx == long_term_frame_idx)
      unmark_for_long_term_reference(dpb.fs_ltref[i]);
  }
}

/*!
 ************************************************************************
 * \brief
 *    Mark a long-term reference field unused for reference only if it's not
 *    the complementary field of the picture indicated by picNumX
 ************************************************************************
 */
static void unmark_long_term_field_for_reference_by_frame_idx(PictureStructure structure, int long_term_frame_idx, int mark_current, unsigned curr_frame_num, int curr_pic_num)
{
  unsigned i;

  assert(structure!=FRAME);
  if (curr_pic_num<0)
    curr_pic_num+=(2*img->MaxFrameNum);

  for(i=0; i<dpb.ltref_frames_in_buffer; i++)
  {
    if (dpb.fs_ltref[i]->long_term_frame_idx == long_term_frame_idx)
    {
      if (structure == TOP_FIELD)
      {
        if ((dpb.fs_ltref[i]->is_long_term == 3))
        {
          unmark_for_long_term_reference(dpb.fs_ltref[i]);
        }
        else
        {
          if ((dpb.fs_ltref[i]->is_long_term == 1))
          {
            unmark_for_long_term_reference(dpb.fs_ltref[i]);
          }
          else
          {
            if (mark_current)
            {
              if (dpb.last_picture)
              {
                if ( ( dpb.last_picture != dpb.fs_ltref[i] )|| dpb.last_picture->frame_num != curr_frame_num)
                  unmark_for_long_term_reference(dpb.fs_ltref[i]);
              }
              else
              {
                unmark_for_long_term_reference(dpb.fs_ltref[i]);
              }
            }
            else
            {
              if ((dpb.fs_ltref[i]->frame_num) != (unsigned)(curr_pic_num/2))
              {
                unmark_for_long_term_reference(dpb.fs_ltref[i]);
              }
            }
          }
        }
      }
      if (structure == BOTTOM_FIELD)
      {
        if ((dpb.fs_ltref[i]->is_long_term == 3))
        {
          unmark_for_long_term_reference(dpb.fs_ltref[i]);
        }
        else
        {
          if ((dpb.fs_ltref[i]->is_long_term == 2))
          {
            unmark_for_long_term_reference(dpb.fs_ltref[i]);
          }
          else
          {
            if (mark_current)
            {
              if (dpb.last_picture)
              {
                if ( ( dpb.last_picture != dpb.fs_ltref[i] )|| dpb.last_picture->frame_num != curr_frame_num)
                  unmark_for_long_term_reference(dpb.fs_ltref[i]);
              }
              else
              {
                unmark_for_long_term_reference(dpb.fs_ltref[i]);
              }
            }
            else
            {
              if ((dpb.fs_ltref[i]->frame_num) != (unsigned)(curr_pic_num/2))
              {
                unmark_for_long_term_reference(dpb.fs_ltref[i]);
              }
            }
          }
        }
      }
    }
  }
}


/*!
 ************************************************************************
 * \brief
 *    mark a picture as long-term reference
 ************************************************************************
 */
static void mark_pic_long_term(StorablePicture* p, int long_term_frame_idx, int picNumX)
{
  unsigned i;
  int add_top, add_bottom;

  if (p->structure == FRAME)
  {
    for (i=0; i<dpb.ref_frames_in_buffer; i++)
    {
      if (dpb.fs_ref[i]->is_reference == 3)
      {
        if ((!dpb.fs_ref[i]->frame->is_long_term)&&(dpb.fs_ref[i]->frame->pic_num == picNumX))
        {
          dpb.fs_ref[i]->long_term_frame_idx = dpb.fs_ref[i]->frame->long_term_frame_idx
                                             = long_term_frame_idx;
          dpb.fs_ref[i]->frame->long_term_pic_num = long_term_frame_idx;
          dpb.fs_ref[i]->frame->is_long_term = 1;

          if (dpb.fs_ref[i]->top_field && dpb.fs_ref[i]->bottom_field)
          {
            dpb.fs_ref[i]->top_field->long_term_frame_idx = dpb.fs_ref[i]->bottom_field->long_term_frame_idx
                                                          = long_term_frame_idx;
            dpb.fs_ref[i]->top_field->long_term_pic_num = long_term_frame_idx;
            dpb.fs_ref[i]->bottom_field->long_term_pic_num = long_term_frame_idx;

            dpb.fs_ref[i]->top_field->is_long_term = dpb.fs_ref[i]->bottom_field->is_long_term
                                                   = 1;

          }
          dpb.fs_ref[i]->is_long_term = 3;
          return;
        }
      }
    }
    printf ("Warning: reference frame for long term marking not found\n");
  }
  else
  {
    if (p->structure == TOP_FIELD)
    {
      add_top    = 1;
      add_bottom = 0;
    }
    else
    {
      add_top    = 0;
      add_bottom = 1;
    }
    for (i=0; i<dpb.ref_frames_in_buffer; i++)
    {
      if (dpb.fs_ref[i]->is_reference & 1)
      {
        if ((!dpb.fs_ref[i]->top_field->is_long_term)&&(dpb.fs_ref[i]->top_field->pic_num == picNumX))
        {
          if ((dpb.fs_ref[i]->is_long_term) && (dpb.fs_ref[i]->long_term_frame_idx != long_term_frame_idx))
          {
              printf ("Warning: assigning long_term_frame_idx different from other field\n");
          }

          dpb.fs_ref[i]->long_term_frame_idx = dpb.fs_ref[i]->top_field->long_term_frame_idx 
                                             = long_term_frame_idx;
          dpb.fs_ref[i]->top_field->long_term_pic_num = 2 * long_term_frame_idx + add_top;
          dpb.fs_ref[i]->top_field->is_long_term = 1;
          dpb.fs_ref[i]->is_long_term |= 1;
          if (dpb.fs_ref[i]->is_long_term == 3)
          {
            dpb.fs_ref[i]->frame->is_long_term = 1;
            dpb.fs_ref[i]->frame->long_term_frame_idx = dpb.fs_ref[i]->frame->long_term_pic_num = long_term_frame_idx;
          }
          return;
        }
      }
      if (dpb.fs_ref[i]->is_reference & 2)
      {
        if ((!dpb.fs_ref[i]->bottom_field->is_long_term)&&(dpb.fs_ref[i]->bottom_field->pic_num == picNumX))
        {
          if ((dpb.fs_ref[i]->is_long_term) && (dpb.fs_ref[i]->long_term_frame_idx != long_term_frame_idx))
          {
              printf ("Warning: assigning long_term_frame_idx different from other field\n");
          }

          dpb.fs_ref[i]->long_term_frame_idx = dpb.fs_ref[i]->bottom_field->long_term_frame_idx 
                                             = long_term_frame_idx;
          dpb.fs_ref[i]->bottom_field->long_term_pic_num = 2 * long_term_frame_idx + add_top;
          dpb.fs_ref[i]->bottom_field->is_long_term = 1;
          dpb.fs_ref[i]->is_long_term |= 2;
          if (dpb.fs_ref[i]->is_long_term == 3)
          {
            dpb.fs_ref[i]->frame->is_long_term = 1;
            dpb.fs_ref[i]->frame->long_term_frame_idx = dpb.fs_ref[i]->frame->long_term_pic_num = long_term_frame_idx;
          }
          return;
        }
      }
    }
    printf ("Warning: reference field for long term marking not found\n");
  }
}


/*!
 ************************************************************************
 * \brief
 *    Assign a long term frame index to a short term picture
 ************************************************************************
 */
static void mm_assign_long_term_frame_idx(StorablePicture* p, int difference_of_pic_nums_minus1, int long_term_frame_idx)
{
  int picNumX;

  picNumX = get_pic_num_x(p, difference_of_pic_nums_minus1);

  // remove frames/fields with same long_term_frame_idx
  if (p->structure == FRAME)
  {
    unmark_long_term_frame_for_reference_by_frame_idx(long_term_frame_idx);
  }
  else
  {
    unsigned i;
    PictureStructure structure = FRAME;

    for (i=0; i<dpb.ref_frames_in_buffer; i++)
    {
      if (dpb.fs_ref[i]->is_reference & 1)
      {
        if (dpb.fs_ref[i]->top_field->pic_num == picNumX)
        {
          structure = TOP_FIELD;
          break;
        }
      }
      if (dpb.fs_ref[i]->is_reference & 2)
      {
        if (dpb.fs_ref[i]->bottom_field->pic_num == picNumX)
        {
          structure = BOTTOM_FIELD;
          break;
        }
      }
    }
    if (structure==FRAME)
    {
      error ("field for long term marking not found",200);
    }
    
    unmark_long_term_field_for_reference_by_frame_idx(structure, long_term_frame_idx, 0, 0, picNumX);
  }

  mark_pic_long_term(p, long_term_frame_idx, picNumX);
}

/*!
 ************************************************************************
 * \brief
 *    Set new max long_term_frame_idx
 ************************************************************************
 */
void mm_update_max_long_term_frame_idx(int max_long_term_frame_idx_plus1)
{
  unsigned i;

  dpb.max_long_term_pic_idx = max_long_term_frame_idx_plus1 - 1;

  // check for invalid frames
  for (i=0; i<dpb.ltref_frames_in_buffer; i++)
  {
    if (dpb.fs_ltref[i]->long_term_frame_idx > dpb.max_long_term_pic_idx)
    {
      unmark_for_long_term_reference(dpb.fs_ltref[i]);
    }
  }
}


/*!
 ************************************************************************
 * \brief
 *    Mark all long term reference pictures unused for reference
 ************************************************************************
 */
static void mm_unmark_all_long_term_for_reference ()
{
  mm_update_max_long_term_frame_idx(0);
}

/*!
 ************************************************************************
 * \brief
 *    Mark all short term reference pictures unused for reference
 ************************************************************************
 */
static void mm_unmark_all_short_term_for_reference ()
{
  unsigned int i;
  for (i=0; i<dpb.ref_frames_in_buffer; i++)
  {
    unmark_for_reference(dpb.fs_ref[i]);
  }
  update_ref_list();
}


/*!
 ************************************************************************
 * \brief
 *    Mark the current picture used for long term reference
 ************************************************************************
 */
static void mm_mark_current_picture_long_term(StorablePicture *p, int long_term_frame_idx)
{
  // remove long term pictures with same long_term_frame_idx
  if (p->structure == FRAME)
  {
    unmark_long_term_frame_for_reference_by_frame_idx(long_term_frame_idx);
  }
  else
  {
    unmark_long_term_field_for_reference_by_frame_idx(p->structure, long_term_frame_idx, 1, p->pic_num, 0);
  }

  p->is_long_term = 1;
  p->long_term_frame_idx = long_term_frame_idx;
}


/*!
 ************************************************************************
 * \brief
 *    Perform Adaptive memory control decoded reference picture marking process
 ************************************************************************
 */
static void adaptive_memory_management(StorablePicture* p)
{
  DecRefPicMarking_t *tmp_drpm;
  
  img->last_has_mmco_5 = 0;

  assert (!p->idr_flag);
  assert (p->adaptive_ref_pic_buffering_flag);

  while (p->dec_ref_pic_marking_buffer)
  {
    tmp_drpm = p->dec_ref_pic_marking_buffer;
    switch (tmp_drpm->memory_management_control_operation)
    {
      case 0:
        if (tmp_drpm->Next != NULL)
        {
          error ("memory_management_control_operation = 0 not last operation in buffer", 500);
        }
        break;
      case 1:
        mm_unmark_short_term_for_reference(p, tmp_drpm->difference_of_pic_nums_minus1);
        update_ref_list();
        break;
      case 2:
        mm_unmark_long_term_for_reference(p, tmp_drpm->long_term_pic_num);
        update_ltref_list();
        break;
      case 3:
        mm_assign_long_term_frame_idx(p, tmp_drpm->difference_of_pic_nums_minus1, tmp_drpm->long_term_frame_idx);
        update_ref_list();
        update_ltref_list();
        break;
      case 4:
        mm_update_max_long_term_frame_idx (tmp_drpm->max_long_term_frame_idx_plus1);
        update_ltref_list();
        break;
      case 5:
        mm_unmark_all_short_term_for_reference();
        mm_unmark_all_long_term_for_reference();
       img->last_has_mmco_5 = 1;
        break;
      case 6:
        mm_mark_current_picture_long_term(p, tmp_drpm->long_term_frame_idx);
        check_num_ref();
        break;
      default:
        error ("invalid memory_management_control_operation in buffer", 500);
    }
    p->dec_ref_pic_marking_buffer = tmp_drpm->Next;
    free (tmp_drpm);
  }
  if ( img->last_has_mmco_5 )
  {
    p->pic_num = p->frame_num = 0;
    
    switch (p->structure)
    {
    case TOP_FIELD:
      {
        p->poc = p->top_poc = img->toppoc =0;
        break;
      }
    case BOTTOM_FIELD:
      {
        p->poc = p->bottom_poc = img->bottompoc = 0;
        break;
      }
    case FRAME:
      {
        p->top_poc    -= p->poc;
        p->bottom_poc -= p->poc;

        img->toppoc = p->top_poc;
        img->bottompoc = p->bottom_poc;

        p->poc = min (p->top_poc, p->bottom_poc);
        img->framepoc = p->poc;
        break;
      }
    }
    img->ThisPOC = p->poc;
    flush_dpb();
  }
}


/*!
 ************************************************************************
 * \brief
 *    Store a picture in DPB. This includes cheking for space in DPB and 
 *    flushing frames.
 *    If we received a frame, we need to check for a new store, if we
 *    got a field, check if it's the second field of an already allocated
 *    store.
 *
 * \param p
 *    Picture to be stored
 *
 ************************************************************************
 */
void store_picture_in_dpb(StorablePicture* p)
{
  unsigned i;
  int poc, pos;
  // diagnostics
  //printf ("Storing (%s) non-ref pic with frame_num #%d\n", (p->type == FRAME)?"FRAME":(p->type == TOP_FIELD)?"TOP_FIELD":"BOTTOM_FIELD", p->pic_num);
  // if frame, check for new store, 
  assert (p!=NULL);

  img->last_has_mmco_5=0;
  img->last_pic_bottom_field = (p->structure == BOTTOM_FIELD);

  if (p->idr_flag)
    idr_memory_management(p);
  else
  {
    // adaptive memory management
    if (p->used_for_reference && (p->adaptive_ref_pic_buffering_flag))
      adaptive_memory_management(p);
  }

  if ((p->structure==TOP_FIELD)||(p->structure==BOTTOM_FIELD))
  {
    // check for frame store with same pic_number
    if (dpb.last_picture)
    {
      if ((int)dpb.last_picture->frame_num == p->pic_num)
      {
        if (((p->structure==TOP_FIELD)&&(dpb.last_picture->is_used==2))||((p->structure==BOTTOM_FIELD)&&(dpb.last_picture->is_used==1)))
        {
          if ((p->used_for_reference && (dpb.last_picture->is_orig_reference!=0))||
              (!p->used_for_reference && (dpb.last_picture->is_orig_reference==0)))
          {
            insert_picture_in_dpb(dpb.last_picture, p);
            update_ref_list();
            update_ltref_list();
            dump_dpb();
            dpb.last_picture = NULL;
            return;
          }
        }
      }
    }
  }
  
  // this is a frame or a field which has no stored complementary field

  // sliding window, if necessary
  if ((!p->idr_flag)&&(p->used_for_reference && (!p->adaptive_ref_pic_buffering_flag)))
  {
    sliding_window_memory_management(p);
  } 

  // first try to remove unused frames
  if (dpb.used_size==dpb.size)
  {
    remove_unused_frame_from_dpb();
  }
  
  // then output frames until one can be removed
  while (dpb.used_size==dpb.size)
  {
    // non-reference frames may be output directly
    if (!p->used_for_reference)
    {
      get_smallest_poc(&poc, &pos);
      if ((-1==pos) || (p->poc < poc))
      {
        direct_output(p, p_out);
        return;
      }
    }
    // flush a frame
    output_one_frame_from_dpb();
  }
  
  // check for duplicate frame number in short term reference buffer
  if ((p->used_for_reference)&&(!p->is_long_term))
  {
    for (i=0; i<dpb.ref_frames_in_buffer; i++)
    {
      if (dpb.fs_ref[i]->frame_num == p->frame_num)
      {
        error("duplicate frame_num im short-term reference picture buffer", 500);
      }
    }

  }
  // store at end of buffer
//  printf ("store frame/field at pos %d\n",dpb.used_size);
  insert_picture_in_dpb(dpb.fs[dpb.used_size],p);

  if (p->structure != FRAME)
  {
    dpb.last_picture = dpb.fs[dpb.used_size];
  }
  else
  {
    dpb.last_picture = NULL;
  }

  dpb.used_size++;

  update_ref_list();
  update_ltref_list();

  check_num_ref();

  dump_dpb();
}

/*!
 ************************************************************************
 * \brief
 *    Insert the picture into the DPB. A free DPB position is necessary
 *    for frames, .
 *
 * \param fs
 *    FrameStore into which the picture will be inserted
 * \param p
 *    StorablePicture to be inserted
 *
 ************************************************************************
 */
static void insert_picture_in_dpb(FrameStore* fs, StorablePicture* p)
{
//  printf ("insert (%s) pic with frame_num #%d, poc %d\n", (p->structure == FRAME)?"FRAME":(p->structure == TOP_FIELD)?"TOP_FIELD":"BOTTOM_FIELD", p->pic_num, p->poc);
  assert (p!=NULL);
  assert (fs!=NULL);
  switch (p->structure)
  {
  case FRAME: 
    fs->frame = p;
    fs->is_used = 3;
    if (p->used_for_reference)
    {
      fs->is_reference = 3;
      fs->is_orig_reference = 3;
      if (p->is_long_term)
      {
        fs->is_long_term = 3;
        fs->long_term_frame_idx = p->long_term_frame_idx;
      }
    }
    // generate field views
    dpb_split_field(fs);
    break;
  case TOP_FIELD:
    fs->top_field = p;
    fs->is_used |= 1;
    if (p->used_for_reference)
    {
      fs->is_reference |= 1;
      fs->is_orig_reference |= 1;
      if (p->is_long_term)
      {
        fs->is_long_term |= 1;
        fs->long_term_frame_idx = p->long_term_frame_idx;
      }
    }
    if (fs->is_used == 3)
    {
      // generate frame view
      dpb_combine_field(fs);
    } else
    {
      fs->poc = p->poc;
      gen_field_ref_ids(p);
    }
    break;
  case BOTTOM_FIELD:
    fs->bottom_field = p;
    fs->is_used |= 2;
    if (p->used_for_reference)
    {
      fs->is_reference |= 2;
      fs->is_orig_reference |= 2;
      if (p->is_long_term)
      {
        fs->is_long_term |= 2;
        fs->long_term_frame_idx = p->long_term_frame_idx;
      }
    }
    if (fs->is_used == 3)
    {
      // generate frame view
      dpb_combine_field(fs);
    } else
    {
      fs->poc = p->poc;
      gen_field_ref_ids(p);
    }
    break;
  }
  fs->frame_num = p->pic_num;
  fs->is_output = p->is_output;

  if (fs->is_used==3)
  {
    if (-1!=p_ref)
      find_snr(snr, fs->frame, p_ref);
  }
}

/*!
 ************************************************************************
 * \brief
 *    Check if one of the frames/fields in frame store is used for reference
 ************************************************************************
 */
static int is_used_for_reference(FrameStore* fs)
{
  if (fs->is_reference)
  {
    return 1;
  }
  
  if (fs->is_used == 3) // frame
  {
    if (fs->frame->used_for_reference)
    {
      return 1;
    }
  }

  if (fs->is_used & 1) // top field
  {
    if (fs->top_field)
    {
      if (fs->top_field->used_for_reference)
      {
        return 1;
      }
    }
  }

  if (fs->is_used & 2) // bottom field
  {
    if (fs->bottom_field)
    {
      if (fs->bottom_field->used_for_reference)
      {
        return 1;
      }
    }
  }
  return 0;
}


/*!
 ************************************************************************
 * \brief
 *    Check if one of the frames/fields in frame store is used for short-term reference
 ************************************************************************
 */
static int is_short_term_reference(FrameStore* fs)
{

  if (fs->is_used==3) // frame
  {
    if ((fs->frame->used_for_reference)&&(!fs->frame->is_long_term))
    {
      return 1;
    }
  }

  if (fs->is_used & 1) // top field
  {
    if (fs->top_field)
    {
      if ((fs->top_field->used_for_reference)&&(!fs->top_field->is_long_term))
      {
        return 1;
      }
    }
  }

  if (fs->is_used & 2) // bottom field
  {
    if (fs->bottom_field)
    {
      if ((fs->bottom_field->used_for_reference)&&(!fs->bottom_field->is_long_term))
      {
        return 1;
      }
    }
  }
  return 0;
}


/*!
 ************************************************************************
 * \brief
 *    Check if one of the frames/fields in frame store is used for short-term reference
 ************************************************************************
 */
static int is_long_term_reference(FrameStore* fs)
{

  if (fs->is_used==3) // frame
  {
    if ((fs->frame->used_for_reference)&&(fs->frame->is_long_term))
    {
      return 1;
    }
  }

  if (fs->is_used & 1) // top field
  {
    if (fs->top_field)
    {
      if ((fs->top_field->used_for_reference)&&(fs->top_field->is_long_term))
      {
        return 1;
      }
    }
  }

  if (fs->is_used & 2) // bottom field
  {
    if (fs->bottom_field)
    {
      if ((fs->bottom_field->used_for_reference)&&(fs->bottom_field->is_long_term))
      {
        return 1;
      }
    }
  }
  return 0;
}


/*!
 ************************************************************************
 * \brief
 *    remove one frame from DPB
 ************************************************************************
 */
static void remove_frame_from_dpb(int pos)
{
  FrameStore* fs = dpb.fs[pos];
  FrameStore* tmp;
  unsigned i;
  
//  printf ("remove frame with frame_num #%d\n", fs->frame_num);
  switch (fs->is_used)
  {
  case 3:
    free_storable_picture(fs->frame);
    free_storable_picture(fs->top_field);
    free_storable_picture(fs->bottom_field);
    fs->frame=NULL;
    fs->top_field=NULL;
    fs->bottom_field=NULL;
    break;
  case 2:
    free_storable_picture(fs->bottom_field);
    fs->bottom_field=NULL;
    break;
  case 1:
    free_storable_picture(fs->top_field);
    fs->top_field=NULL;
    break;
  case 0:
    break;
  default:
    error("invalid frame store type",500);
  }
  fs->is_used = 0;
  fs->is_long_term = 0;
  fs->is_reference = 0;
  fs->is_orig_reference = 0;

  // move empty framestore to end of buffer
  tmp = dpb.fs[pos];

  for (i=pos; i<dpb.used_size-1;i++)
  {
    dpb.fs[i] = dpb.fs[i+1];
  }
  dpb.fs[dpb.used_size-1] = tmp;
  dpb.used_size--;
}

/*!
 ************************************************************************
 * \brief
 *    find smallest POC in the DPB.
 ************************************************************************
 */
static void get_smallest_poc(int *poc,int * pos)
{
  unsigned i;

  if (dpb.used_size<1)
  {
    error("Cannot determine smallest POC, DPB empty.",150);
  }

  *pos=-1;
  *poc = INT_MAX;
  for (i=0; i<dpb.used_size; i++)
  {
    if ((*poc>dpb.fs[i]->poc)&&(!dpb.fs[i]->is_output))
    {
      *poc = dpb.fs[i]->poc;
      *pos=i;
    }
  }
}

/*!
 ************************************************************************
 * \brief
 *    Remove a picture from DPB which is no longer needed.
 ************************************************************************
 */
static int remove_unused_frame_from_dpb()
{
  unsigned i;

  // check for frames that were already output and no longer used for reference
  for (i=0; i<dpb.used_size; i++)
  {
    if (dpb.fs[i]->is_output && (!is_used_for_reference(dpb.fs[i])))
    {
      remove_frame_from_dpb(i);
      return 1;
    }
  }
  return 0;
}

/*!
 ************************************************************************
 * \brief
 *    Output one picture stored in the DPB.
 ************************************************************************
 */
static void output_one_frame_from_dpb()
{
  int poc, pos;
  //diagnostics
  if (dpb.used_size<1)
  {
    error("Cannot output frame, DPB empty.",150);
  }

  // find smallest POC
  get_smallest_poc(&poc, &pos);

  if(pos==-1)
  {
    error("no frames for output available", 150);
  }

  // call the output function
//  printf ("output frame with frame_num #%d, poc %d (dpb. dpb.size=%d, dpb.used_size=%d)\n", dpb.fs[pos]->frame_num, dpb.fs[pos]->frame->poc, dpb.size, dpb.used_size);

  write_stored_frame(dpb.fs[pos], p_out);

  if (dpb.last_output_poc >= poc)
  {
    error ("output POC must be in ascending order", 150);
  } 
  dpb.last_output_poc = poc;
  // free frame store and move empty store to end of buffer
  if (!is_used_for_reference(dpb.fs[pos]))
  {
    remove_frame_from_dpb(pos);
  }
}



/*!
 ************************************************************************
 * \brief
 *    All stored picture are output. Should be called to empty the buffer
 ************************************************************************
 */
void flush_dpb()
{
  unsigned i;

  //diagnostics
//  printf("Flush remaining frames from dpb. dpb.size=%d, dpb.used_size=%d\n",dpb.size,dpb.used_size);

  // mark all frames unused
  for (i=0; i<dpb.used_size; i++)
  {
    unmark_for_reference (dpb.fs[i]);
  }

  while (remove_unused_frame_from_dpb()) ;
  
  // output frames in POC order
  while (dpb.used_size)
  {
    output_one_frame_from_dpb();
  }

  dpb.last_output_poc = INT_MIN;
}

#define RSD(x) ((x&2)?(x|1):(x&(~1)))


void gen_field_ref_ids(StorablePicture *p)
{
  int i,j, dummylist0, dummylist1;
   //! Generate Frame parameters from field information.
  for (i=0 ; i<p->size_x/4 ; i++)
  {
    for (j=0 ; j<p->size_y/4 ; j++)
    {              
        dummylist0= p->ref_idx[LIST_0][j][i];
        dummylist1= p->ref_idx[LIST_1][j][i];
        //! association with id already known for fields.
        p->ref_id[LIST_0][j][i] = (dummylist0>=0)? p->ref_pic_num[p->slice_id[j>>2][i>>2]][LIST_0][dummylist0] : 0;
        p->ref_id[LIST_1][j][i] = (dummylist1>=0)? p->ref_pic_num[p->slice_id[j>>2][i>>2]][LIST_1][dummylist1] : 0;          
        p->field_frame[j][i]=1;
    }     
  }
}

/*!
 ************************************************************************
 * \brief
 *    Extract top field from a frame
 ************************************************************************
 */
void dpb_split_field(FrameStore *fs)
{
  int i, j, ii, jj, jj4;
  int idiv,jdiv;
  int currentmb;
  int dummylist0,dummylist1;
  int twosz16 = 2*(fs->frame->size_x/16);

  fs->poc = fs->frame->poc;

  if (!fs->frame->frame_mbs_only_flag)
  {
    fs->top_field    = alloc_storable_picture(TOP_FIELD,    fs->frame->size_x, fs->frame->size_y, fs->frame->size_x_cr, fs->frame->size_y_cr);
    fs->bottom_field = alloc_storable_picture(BOTTOM_FIELD, fs->frame->size_x, fs->frame->size_y, fs->frame->size_x_cr, fs->frame->size_y_cr);

    for (i=0; i<fs->frame->size_y/2; i++)
    {
      memcpy(fs->top_field->imgY[i], fs->frame->imgY[i*2], fs->frame->size_x*sizeof(imgpel));
    }
    
    for (i=0; i<fs->frame->size_y_cr/2; i++)
    {
      memcpy(fs->top_field->imgUV[0][i], fs->frame->imgUV[0][i*2], fs->frame->size_x_cr*sizeof(imgpel));
      memcpy(fs->top_field->imgUV[1][i], fs->frame->imgUV[1][i*2], fs->frame->size_x_cr*sizeof(imgpel));
    }
    
    for (i=0; i<fs->frame->size_y/2; i++)
    {
      memcpy(fs->bottom_field->imgY[i], fs->frame->imgY[i*2 + 1], fs->frame->size_x*sizeof(imgpel));
    }
    
    for (i=0; i<fs->frame->size_y_cr/2; i++)
    {
      memcpy(fs->bottom_field->imgUV[0][i], fs->frame->imgUV[0][i*2 + 1], fs->frame->size_x_cr*sizeof(imgpel));
      memcpy(fs->bottom_field->imgUV[1][i], fs->frame->imgUV[1][i*2 + 1], fs->frame->size_x_cr*sizeof(imgpel));
    }
    
    fs->top_field->poc = fs->frame->top_poc;
    fs->bottom_field->poc =  fs->frame->bottom_poc;
    
    fs->top_field->frame_poc =  fs->frame->frame_poc;
    
    fs->top_field->bottom_poc =fs->bottom_field->bottom_poc =  fs->frame->bottom_poc;
    fs->top_field->top_poc =fs->bottom_field->top_poc =  fs->frame->top_poc;
    fs->bottom_field->frame_poc =  fs->frame->frame_poc;
    
    fs->top_field->used_for_reference = fs->bottom_field->used_for_reference 
                                      = fs->frame->used_for_reference;
    fs->top_field->is_long_term = fs->bottom_field->is_long_term 
                                = fs->frame->is_long_term;
    fs->long_term_frame_idx = fs->top_field->long_term_frame_idx 
                            = fs->bottom_field->long_term_frame_idx 
                            = fs->frame->long_term_frame_idx;

    fs->top_field->coded_frame = fs->bottom_field->coded_frame = 1;
    fs->top_field->MbaffFrameFlag = fs->bottom_field->MbaffFrameFlag
                                  = fs->frame->MbaffFrameFlag;

    fs->frame->top_field    = fs->top_field;
    fs->frame->bottom_field = fs->bottom_field;

    fs->top_field->bottom_field = fs->bottom_field;
    fs->top_field->frame        = fs->frame;
    fs->bottom_field->top_field = fs->top_field;
    fs->bottom_field->frame     = fs->frame;
  
    fs->top_field->chroma_format_idc = fs->bottom_field->chroma_format_idc = fs->frame->chroma_format_idc;
    
    //store reference picture index
    for (j=0; j<=fs->frame->max_slice_id; j++)
    {
      for (i=0;i<listXsize[LIST_1];i++)
      {
        fs->top_field->ref_pic_num[j][LIST_1][2*i]     =fs->frame->ref_pic_num[j][2 + LIST_1][2*i];
        fs->top_field->ref_pic_num[j][LIST_1][2*i + 1] =fs->frame->ref_pic_num[j][2 + LIST_1][2*i+1];
        fs->bottom_field->ref_pic_num[j][LIST_1][2*i]  =fs->frame->ref_pic_num[j][4 + LIST_1][2*i];
        fs->bottom_field->ref_pic_num[j][LIST_1][2*i+1]=fs->frame->ref_pic_num[j][4 + LIST_1][2*i+1] ;
      }
      
      for (i=0;i<listXsize[LIST_0];i++)
      {
        fs->top_field->ref_pic_num[j][LIST_0][2*i]     =fs->frame->ref_pic_num[j][2 + LIST_0][2*i];
        fs->top_field->ref_pic_num[j][LIST_0][2*i + 1] =fs->frame->ref_pic_num[j][2 + LIST_0][2*i+1];
        fs->bottom_field->ref_pic_num[j][LIST_0][2*i]  =fs->frame->ref_pic_num[j][4 + LIST_0][2*i];
        fs->bottom_field->ref_pic_num[j][LIST_0][2*i+1]=fs->frame->ref_pic_num[j][4 + LIST_0][2*i+1] ;
      }
    }
  }
  else
  {
    fs->top_field=NULL;
    fs->bottom_field=NULL;
    fs->frame->top_field=NULL;
    fs->frame->bottom_field=NULL;
  }
  
  for (j=0 ; j<fs->frame->size_y/4 ; j++)      
  {           
    jdiv=j/4;
    for (i=0 ; i<fs->frame->size_x/4 ; i++)          
    {   
      idiv=i/4;
      currentmb = twosz16*(jdiv/2)+ (idiv)*2 + (jdiv%2);
      
      if (fs->frame->MbaffFrameFlag && fs->frame->mb_field[currentmb])
      {    
        int list_offset = currentmb%2? 4: 2;
        dummylist0 = fs->frame->ref_idx[LIST_0][j][i];
        dummylist1 = fs->frame->ref_idx[LIST_1][j][i];        
        //! association with id already known for fields.
        fs->frame->ref_id[LIST_0 + list_offset][j][i] = (dummylist0>=0)? fs->frame->ref_pic_num[fs->frame->slice_id[jdiv][idiv]][LIST_0 + list_offset][dummylist0] : 0;
        fs->frame->ref_id[LIST_1 + list_offset][j][i] = (dummylist1>=0)? fs->frame->ref_pic_num[fs->frame->slice_id[jdiv][idiv]][LIST_1 + list_offset][dummylist1] : 0;          
        //! need to make association with frames
        fs->frame->ref_id[LIST_0][j][i] = (dummylist0>=0)? fs->frame->frm_ref_pic_num[fs->frame->slice_id[jdiv][idiv]][LIST_0 + list_offset][dummylist0] : 0;
        fs->frame->ref_id[LIST_1][j][i] = (dummylist1>=0)? fs->frame->frm_ref_pic_num[fs->frame->slice_id[jdiv][idiv]][LIST_1 + list_offset][dummylist1] : 0;                   
        
      }
      else
      {
        dummylist0 = fs->frame->ref_idx[LIST_0][j][i];
        dummylist1 = fs->frame->ref_idx[LIST_1][j][i];        
        fs->frame->ref_id[LIST_0][j][i] = (dummylist0>=0)? fs->frame->ref_pic_num[fs->frame->slice_id[jdiv][idiv]][LIST_0][dummylist0] : -1;
        fs->frame->ref_id[LIST_1][j][i] = (dummylist1>=0)? fs->frame->ref_pic_num[fs->frame->slice_id[jdiv][idiv]][LIST_1][dummylist1] : -1;    
      }
    }      
  }
  
  if (!fs->frame->frame_mbs_only_flag && fs->frame->MbaffFrameFlag)
  {    
    for (j=0 ; j<fs->frame->size_y/8; j++)      
    { 
      jj = (j/4)*8 + j%4;
      jj4 = jj + 4;
      jdiv=j/2;
      for (i=0 ; i<fs->frame->size_x/4 ; i++)
      {                
        idiv=i/4;
        
        currentmb = twosz16*(jdiv/2)+ (idiv)*2 + (jdiv%2);
        // Assign field mvs attached to MB-Frame buffer to the proper buffer
        if (fs->frame->mb_field[currentmb])
        {
          fs->bottom_field->field_frame[j][i] = fs->top_field->field_frame[j][i]=1;
          fs->frame->field_frame[2*j][i] = fs->frame->field_frame[2*j+1][i]=1;
          
          fs->bottom_field->mv[LIST_0][j][i][0] = fs->frame->mv[LIST_0][jj4][i][0];
          fs->bottom_field->mv[LIST_0][j][i][1] = fs->frame->mv[LIST_0][jj4][i][1];
          fs->bottom_field->mv[LIST_1][j][i][0] = fs->frame->mv[LIST_1][jj4][i][0];
          fs->bottom_field->mv[LIST_1][j][i][1] = fs->frame->mv[LIST_1][jj4][i][1];
          fs->bottom_field->ref_idx[LIST_0][j][i] = fs->frame->ref_idx[LIST_0][jj4][i];
          fs->bottom_field->ref_idx[LIST_1][j][i] = fs->frame->ref_idx[LIST_1][jj4][i];
          fs->bottom_field->ref_id[LIST_0][j][i] = fs->frame->ref_id[LIST_0+4][jj4][i];
          fs->bottom_field->ref_id[LIST_1][j][i] = fs->frame->ref_id[LIST_1+4][jj4][i];
          
          
          fs->top_field->mv[LIST_0][j][i][0] = fs->frame->mv[LIST_0][jj][i][0];
          fs->top_field->mv[LIST_0][j][i][1] = fs->frame->mv[LIST_0][jj][i][1];
          fs->top_field->mv[LIST_1][j][i][0] = fs->frame->mv[LIST_1][jj][i][0];
          fs->top_field->mv[LIST_1][j][i][1] = fs->frame->mv[LIST_1][jj][i][1];
          fs->top_field->ref_idx[LIST_0][j][i] = fs->frame->ref_idx[LIST_0][jj][i];
          fs->top_field->ref_idx[LIST_1][j][i] = fs->frame->ref_idx[LIST_1][jj][i];
          fs->top_field->ref_id[LIST_0][j][i] = fs->frame->ref_id[LIST_0+2][jj][i];
          fs->top_field->ref_id[LIST_1][j][i] = fs->frame->ref_id[LIST_1+2][jj][i];          
        }
      }
    }             
  }
  
  //! Generate field MVs from Frame MVs
  if (!fs->frame->frame_mbs_only_flag)
  {
    for (j=0 ; j<fs->frame->size_y/8 ; j++)
    {
      jj = 2* RSD(j);
      jdiv = j/2;
      for (i=0 ; i<fs->frame->size_x/4 ; i++)
      {
        ii = RSD(i);
        idiv = i/4;
        
        currentmb = twosz16*(jdiv/2)+ (idiv)*2 + (jdiv%2);        
        
        if (!fs->frame->MbaffFrameFlag  || !fs->frame->mb_field[currentmb])    
        {
          fs->frame->field_frame[2*j+1][i] = fs->frame->field_frame[2*j][i]=0;
          
          fs->top_field->field_frame[j][i] = fs->bottom_field->field_frame[j][i] = 0;
          
          fs->top_field->mv[LIST_0][j][i][0] = fs->bottom_field->mv[LIST_0][j][i][0] = fs->frame->mv[LIST_0][jj][ii][0];
          fs->top_field->mv[LIST_0][j][i][1] = fs->bottom_field->mv[LIST_0][j][i][1] = fs->frame->mv[LIST_0][jj][ii][1];
          fs->top_field->mv[LIST_1][j][i][0] = fs->bottom_field->mv[LIST_1][j][i][0] = fs->frame->mv[LIST_1][jj][ii][0];
          fs->top_field->mv[LIST_1][j][i][1] = fs->bottom_field->mv[LIST_1][j][i][1] = fs->frame->mv[LIST_1][jj][ii][1];
          
          // Scaling of references is done here since it will not affect spatial direct (2*0 =0)
          if (fs->frame->ref_idx[LIST_0][jj][ii] == -1)      
            fs->top_field->ref_idx[LIST_0][j][i] = fs->bottom_field->ref_idx[LIST_0][j][i] = - 1;
          else
          {
            dummylist0=fs->top_field->ref_idx[LIST_0][j][i] = fs->bottom_field->ref_idx[LIST_0][j][i] = fs->frame->ref_idx[LIST_0][jj][ii] ;
            fs->top_field   ->ref_id[LIST_0][j][i] = (dummylist0>=0)? fs->frame->top_ref_pic_num[fs->frame->slice_id[jj>>2][ii>>2]][LIST_0][dummylist0] : 0;
            fs->bottom_field->ref_id[LIST_0][j][i] = (dummylist0>=0)? fs->frame->bottom_ref_pic_num[fs->frame->slice_id[jj>>2][ii>>2]][LIST_0][dummylist0] : 0;
          }
          
          if (fs->frame->ref_idx[LIST_1][jj][ii] == -1)      
            fs->top_field->ref_idx[LIST_1][j][i] = fs->bottom_field->ref_idx[LIST_1][j][i] = - 1;
          else
          {
            dummylist1=fs->top_field->ref_idx[LIST_1][j][i] = fs->bottom_field->ref_idx[LIST_1][j][i] = fs->frame->ref_idx[LIST_1][jj][ii];
            
            fs->top_field   ->ref_id[LIST_1][j][i] = (dummylist1>=0)? fs->frame->top_ref_pic_num[fs->frame->slice_id[jj>>2][ii>>2]][LIST_1][dummylist1] : 0;
            fs->bottom_field->ref_id[LIST_1][j][i] = (dummylist1>=0)? fs->frame->bottom_ref_pic_num[fs->frame->slice_id[jj>>2][ii>>2]][LIST_1][dummylist1] : 0;
          }
        }
        else
        {
          fs->frame->field_frame[2*j+1][i] = fs->frame->field_frame[2*j][i]= fs->frame->mb_field[currentmb];
        }
      }
    }
  }
  else
  {
    memset( &(fs->frame->field_frame[0][0]), 0, fs->frame->size_y * fs->frame->size_x /16 * sizeof(byte));
  }
}


/*!
 ************************************************************************
 * \brief
 *    Generate a frame from top and bottom fields, 
 *    YUV components and display information only
 ************************************************************************
 */
void dpb_combine_field_yuv(FrameStore *fs)
{
  int i;

  fs->frame = alloc_storable_picture(FRAME, fs->top_field->size_x, fs->top_field->size_y*2, fs->top_field->size_x_cr, fs->top_field->size_y_cr*2);

  for (i=0; i<fs->top_field->size_y; i++)
  {
    memcpy(fs->frame->imgY[i*2],     fs->top_field->imgY[i]   , fs->top_field->size_x*sizeof(imgpel));     // top field
    memcpy(fs->frame->imgY[i*2 + 1], fs->bottom_field->imgY[i], fs->bottom_field->size_x*sizeof(imgpel)); // bottom field
  }

  for (i=0; i<fs->top_field->size_y_cr; i++)
  {
    memcpy(fs->frame->imgUV[0][i*2],     fs->top_field->imgUV[0][i],    fs->top_field->size_x_cr*sizeof(imgpel));
    memcpy(fs->frame->imgUV[0][i*2 + 1], fs->bottom_field->imgUV[0][i], fs->bottom_field->size_x_cr*sizeof(imgpel));
    memcpy(fs->frame->imgUV[1][i*2],     fs->top_field->imgUV[1][i],    fs->top_field->size_x_cr*sizeof(imgpel));
    memcpy(fs->frame->imgUV[1][i*2 + 1], fs->bottom_field->imgUV[1][i], fs->bottom_field->size_x_cr*sizeof(imgpel));
  }
  
  
  fs->poc=fs->frame->poc =fs->frame->frame_poc = min (fs->top_field->poc, fs->bottom_field->poc);

  fs->bottom_field->frame_poc=fs->top_field->frame_poc=
  fs->bottom_field->top_poc=fs->frame->frame_poc=fs->frame->top_poc=fs->top_field->poc;
  fs->top_field->bottom_poc=fs->bottom_field->poc;

  fs->frame->bottom_poc=fs->bottom_field->poc;

  fs->frame->used_for_reference = (fs->top_field->used_for_reference && fs->bottom_field->used_for_reference );
  fs->frame->is_long_term = (fs->top_field->is_long_term && fs->bottom_field->is_long_term );

  if (fs->frame->is_long_term) 
    fs->frame->long_term_frame_idx = fs->long_term_frame_idx;

  fs->frame->top_field    = fs->top_field;
  fs->frame->bottom_field = fs->bottom_field;
  
  fs->frame->coded_frame = 0;

  fs->frame->chroma_format_idc = fs->top_field->chroma_format_idc;
  fs->frame->frame_cropping_flag = fs->top_field->frame_cropping_flag;
  if (fs->frame->frame_cropping_flag)
  {
    fs->frame->frame_cropping_rect_top_offset = fs->top_field->frame_cropping_rect_top_offset;
    fs->frame->frame_cropping_rect_bottom_offset = fs->top_field->frame_cropping_rect_bottom_offset;
    fs->frame->frame_cropping_rect_left_offset = fs->top_field->frame_cropping_rect_left_offset;
    fs->frame->frame_cropping_rect_right_offset = fs->top_field->frame_cropping_rect_right_offset;
  }
  
  fs->top_field->frame = fs->bottom_field->frame = fs->frame;
}


/*!
 ************************************************************************
 * \brief
 *    Generate a frame from top and bottom fields
 ************************************************************************
 */
void dpb_combine_field(FrameStore *fs)
{
  int i,j, jj, jj4;
  int dummylist0, dummylist1;

  dpb_combine_field_yuv(fs);

  
  //combine field for frame
  for (j=0; j<=(max(fs->top_field->max_slice_id, fs->bottom_field->max_slice_id)); j++)
  {
    for (i=0;i<(listXsize[LIST_1]+1)/2;i++)
    {
      fs->frame->ref_pic_num[j][LIST_1][i]=   min ((fs->top_field->ref_pic_num[j][LIST_1][2*i]/2)*2, (fs->bottom_field->ref_pic_num[j][LIST_1][2*i]/2)*2);
    }

    for (i=0;i<(listXsize[LIST_0]+1)/2;i++)
    {
      fs->frame->ref_pic_num[j][LIST_0][i] =   min ((fs->top_field->ref_pic_num[j][LIST_0][2*i]/2)*2, (fs->bottom_field->ref_pic_num[j][LIST_0][2*i]/2)*2);  
    }
  }
  
   //! Use inference flag to remap mvs/references 

  //! Generate Frame parameters from field information.
  for (j=0 ; j<fs->top_field->size_y/4 ; j++)
  {
    jj = 8*(j/4) + (j%4);
    jj4 = jj + 4;
    for (i=0 ; i<fs->top_field->size_x/4 ; i++)
    {
      fs->frame->field_frame[jj][i]= fs->frame->field_frame[jj4][i]=1;
      
      fs->frame->mv[LIST_0][jj][i][0] = fs->top_field->mv[LIST_0][j][i][0];
      fs->frame->mv[LIST_0][jj][i][1] = fs->top_field->mv[LIST_0][j][i][1] ;
      fs->frame->mv[LIST_1][jj][i][0] = fs->top_field->mv[LIST_1][j][i][0];
      fs->frame->mv[LIST_1][jj][i][1] = fs->top_field->mv[LIST_1][j][i][1] ; 
      
      dummylist0=fs->frame->ref_idx[LIST_0][jj][i]  = fs->top_field->ref_idx[LIST_0][j][i];
      dummylist1=fs->frame->ref_idx[LIST_1][jj][i]  = fs->top_field->ref_idx[LIST_1][j][i];
      
      //! association with id already known for fields.
      fs->top_field->ref_id[LIST_0][j][i] = (dummylist0>=0)? fs->top_field->ref_pic_num[fs->top_field->slice_id[j>>2][i>>2]][LIST_0][dummylist0] : 0;
      fs->top_field->ref_id[LIST_1][j][i] = (dummylist1>=0)? fs->top_field->ref_pic_num[fs->top_field->slice_id[j>>2][i>>2]][LIST_1][dummylist1] : 0;          
      
      //! need to make association with frames
      fs->frame->ref_id[LIST_0][jj][i] = (dummylist0>=0)? fs->top_field->frm_ref_pic_num[fs->top_field->slice_id[j>>2][i>>2]][LIST_0][dummylist0] : 0;
      fs->frame->ref_id[LIST_1][jj][i] = (dummylist1>=0)? fs->top_field->frm_ref_pic_num[fs->top_field->slice_id[j>>2][i>>2]][LIST_1][dummylist1] : 0;          
      
      fs->frame->mv[LIST_0][jj4][i][0] = fs->bottom_field->mv[LIST_0][j][i][0];
      fs->frame->mv[LIST_0][jj4][i][1] = fs->bottom_field->mv[LIST_0][j][i][1] ;
      fs->frame->mv[LIST_1][jj4][i][0] = fs->bottom_field->mv[LIST_1][j][i][0];
      fs->frame->mv[LIST_1][jj4][i][1] = fs->bottom_field->mv[LIST_1][j][i][1] ; 
      
      dummylist0=fs->frame->ref_idx[LIST_0][jj4][i]  = fs->bottom_field->ref_idx[LIST_0][j][i];
      dummylist1=fs->frame->ref_idx[LIST_1][jj4][i]  = fs->bottom_field->ref_idx[LIST_1][j][i];
      
      fs->bottom_field->ref_id[LIST_0][j][i] = (dummylist0>=0)? fs->bottom_field->ref_pic_num[fs->bottom_field->slice_id[j>>2][i>>2]][LIST_0][dummylist0] : 0;
      fs->bottom_field->ref_id[LIST_1][j][i] = (dummylist1>=0)? fs->bottom_field->ref_pic_num[fs->bottom_field->slice_id[j>>2][i>>2]][LIST_1][dummylist1] : 0;          
      
      //! need to make association with frames
      fs->frame->ref_id[LIST_0][jj4][i] = (dummylist0>=0)? fs->bottom_field->frm_ref_pic_num[fs->bottom_field->slice_id[j>>2][i>>2]][LIST_0][dummylist0] : -1;
      fs->frame->ref_id[LIST_1][jj4][i] = (dummylist1>=0)? fs->bottom_field->frm_ref_pic_num[fs->bottom_field->slice_id[j>>2][i>>2]][LIST_1][dummylist1] : -1;          

      fs->top_field->field_frame[j][i]=1;
      fs->bottom_field->field_frame[j][i]=1;      
    }
  }
}


/*!
 ************************************************************************
 * \brief
 *    Allocate memory for buffering of reference picture reordering commands
 ************************************************************************
 */
void alloc_ref_pic_list_reordering_buffer(Slice *currSlice)
{
  int size = img->num_ref_idx_l0_active+1;

  if (img->type!=I_SLICE && img->type!=SI_SLICE)
  {
    if ((currSlice->remapping_of_pic_nums_idc_l0 = calloc(size,sizeof(int)))==NULL) no_mem_exit("alloc_ref_pic_list_reordering_buffer: remapping_of_pic_nums_idc_l0");
    if ((currSlice->abs_diff_pic_num_minus1_l0 = calloc(size,sizeof(int)))==NULL) no_mem_exit("alloc_ref_pic_list_reordering_buffer: abs_diff_pic_num_minus1_l0");
    if ((currSlice->long_term_pic_idx_l0 = calloc(size,sizeof(int)))==NULL) no_mem_exit("alloc_ref_pic_list_reordering_buffer: long_term_pic_idx_l0");
  }
  else
  {
    currSlice->remapping_of_pic_nums_idc_l0 = NULL;
    currSlice->abs_diff_pic_num_minus1_l0 = NULL;
    currSlice->long_term_pic_idx_l0 = NULL;
  }
  
  size = img->num_ref_idx_l1_active+1;

  if (img->type==B_SLICE)
  {
    if ((currSlice->remapping_of_pic_nums_idc_l1 = calloc(size,sizeof(int)))==NULL) no_mem_exit("alloc_ref_pic_list_reordering_buffer: remapping_of_pic_nums_idc_l1");
    if ((currSlice->abs_diff_pic_num_minus1_l1 = calloc(size,sizeof(int)))==NULL) no_mem_exit("alloc_ref_pic_list_reordering_buffer: abs_diff_pic_num_minus1_l1");
    if ((currSlice->long_term_pic_idx_l1 = calloc(size,sizeof(int)))==NULL) no_mem_exit("alloc_ref_pic_list_reordering_buffer: long_term_pic_idx_l1");
  }
  else
  {
    currSlice->remapping_of_pic_nums_idc_l1 = NULL;
    currSlice->abs_diff_pic_num_minus1_l1 = NULL;
    currSlice->long_term_pic_idx_l1 = NULL;
  }
}


/*!
 ************************************************************************
 * \brief
 *    Free memory for buffering of reference picture reordering commands
 ************************************************************************
 */
void free_ref_pic_list_reordering_buffer(Slice *currSlice)
{

  if (currSlice->remapping_of_pic_nums_idc_l0) 
    free(currSlice->remapping_of_pic_nums_idc_l0);
  if (currSlice->abs_diff_pic_num_minus1_l0)
    free(currSlice->abs_diff_pic_num_minus1_l0);
  if (currSlice->long_term_pic_idx_l0)
    free(currSlice->long_term_pic_idx_l0);

  currSlice->remapping_of_pic_nums_idc_l0 = NULL;
  currSlice->abs_diff_pic_num_minus1_l0 = NULL;
  currSlice->long_term_pic_idx_l0 = NULL;
  
  if (currSlice->remapping_of_pic_nums_idc_l1)
    free(currSlice->remapping_of_pic_nums_idc_l1);
  if (currSlice->abs_diff_pic_num_minus1_l1)
    free(currSlice->abs_diff_pic_num_minus1_l1);
  if (currSlice->long_term_pic_idx_l1)
    free(currSlice->long_term_pic_idx_l1);
  
  currSlice->remapping_of_pic_nums_idc_l1 = NULL;
  currSlice->abs_diff_pic_num_minus1_l1 = NULL;
  currSlice->long_term_pic_idx_l1 = NULL;
}

/*!
 ************************************************************************
 * \brief
 *      Tian Dong
 *          June 13, 2002, Modifed on July 30, 2003
 *
 *      If a gap in frame_num is found, try to fill the gap
 * \param img
 *      
 ************************************************************************
 */
void fill_frame_num_gap(ImageParameters *img)
{
  int CurrFrameNum;
  int UnusedShortTermFrameNum;
  StorablePicture *picture = NULL;
  int tmp1 = img->delta_pic_order_cnt[0];
  int tmp2 = img->delta_pic_order_cnt[1];
  img->delta_pic_order_cnt[0] = img->delta_pic_order_cnt[1] = 0;

//  printf("A gap in frame number is found, try to fill it.\n");


  UnusedShortTermFrameNum = (img->pre_frame_num + 1) % img->MaxFrameNum;
  CurrFrameNum = img->frame_num;

  while (CurrFrameNum != UnusedShortTermFrameNum)
  {
    picture = alloc_storable_picture (FRAME, img->width, img->height, img->width_cr, img->height_cr);
    picture->coded_frame = 1;
    picture->pic_num = UnusedShortTermFrameNum;
    picture->frame_num = UnusedShortTermFrameNum;
    picture->non_existing = 1;
    picture->is_output = 1;
    picture->used_for_reference = 1;
    
    picture->adaptive_ref_pic_buffering_flag = 0;

    img->frame_num = UnusedShortTermFrameNum;
    if (active_sps->pic_order_cnt_type!=0)
    {
      decode_poc(img);
    }
    picture->top_poc=img->toppoc;
    picture->bottom_poc=img->bottompoc;
    picture->frame_poc=img->framepoc;
    picture->poc=img->framepoc;

    store_picture_in_dpb(picture);

    picture=NULL;
    img->pre_frame_num = UnusedShortTermFrameNum;
    UnusedShortTermFrameNum = (UnusedShortTermFrameNum + 1) % img->MaxFrameNum;
  }
  img->delta_pic_order_cnt[0] = tmp1;
  img->delta_pic_order_cnt[1] = tmp2;
  img->frame_num = CurrFrameNum;

}

/*!
 ************************************************************************
 * \brief
 *    Allocate co-located memory 
 *
 * \param size_x
 *    horizontal luma size
 * \param size_y
 *    vertical luma size
 * \param mb_adaptive_frame_field_flag
 *    flag that indicates macroblock adaptive frame/field coding
 *
 * \return
 *    the allocated StorablePicture structure
 ************************************************************************
 */
ColocatedParams* alloc_colocated(int size_x, int size_y, int mb_adaptive_frame_field_flag)
{
  ColocatedParams *s;

  s = calloc(1, sizeof(ColocatedParams)); 
  if (NULL == s)
    no_mem_exit("alloc_colocated: s");

  s->size_x = size_x;
  s->size_y = size_y;


  get_mem3D      ((byte****)(&(s->ref_idx))   , 2, size_y / BLOCK_SIZE, size_x / BLOCK_SIZE);
  get_mem3Dint64 (&(s->ref_pic_id), 2, size_y / BLOCK_SIZE, size_x / BLOCK_SIZE);
  get_mem4Dshort (&(s->mv)        , 2, size_y / BLOCK_SIZE, size_x / BLOCK_SIZE,2 );

  get_mem2D      (&(s->moving_block), size_y / BLOCK_SIZE, size_x / BLOCK_SIZE);
  get_mem2D      (&(s->field_frame) , size_y / BLOCK_SIZE, size_x / BLOCK_SIZE);

  if (mb_adaptive_frame_field_flag)
  {
    get_mem3D      ((byte****)(&(s->top_ref_idx))   , 2, size_y / BLOCK_SIZE/2, size_x / BLOCK_SIZE);
    get_mem3Dint64 (&(s->top_ref_pic_id), 2, size_y / BLOCK_SIZE/2, size_x / BLOCK_SIZE);
    get_mem4Dshort (&(s->top_mv),         2, size_y / BLOCK_SIZE/2, size_x / BLOCK_SIZE, 2);
    get_mem2D (&(s->top_moving_block),       size_y / BLOCK_SIZE/2, size_x / BLOCK_SIZE);
    
    get_mem3D      ((byte****)(&(s->bottom_ref_idx)),    2, size_y / BLOCK_SIZE/2, size_x / BLOCK_SIZE);
    get_mem3Dint64 (&(s->bottom_ref_pic_id), 2, size_y / BLOCK_SIZE/2, size_x / BLOCK_SIZE);
    get_mem4Dshort (&(s->bottom_mv),         2, size_y / BLOCK_SIZE/2, size_x / BLOCK_SIZE, 2);
    get_mem2D (&(s->bottom_moving_block),       size_y / BLOCK_SIZE/2, size_x / BLOCK_SIZE);
  }

  s->mb_adaptive_frame_field_flag  = mb_adaptive_frame_field_flag;

  return s;
}

/*!
 ************************************************************************
 * \brief
 *    Free co-located memory.
 *
 * \param p
 *    Picture to be freed
 *
 ************************************************************************
 */
void free_colocated(ColocatedParams* p)
{
  if (p)
  {
    free_mem3D      ((byte***)p->ref_idx, 2);
    free_mem3Dint64 (p->ref_pic_id, 2);
    free_mem4Dshort (p->mv, 2, p->size_y / BLOCK_SIZE);

    if (p->moving_block)
    {
      free_mem2D (p->moving_block);
      p->moving_block=NULL;
    }
    if (p->field_frame)
    {
      free_mem2D (p->field_frame);
      p->field_frame=NULL;
    }

    
    if (p->mb_adaptive_frame_field_flag)
    {
      free_mem3D      ((byte***)p->top_ref_idx, 2);
      free_mem3Dint64 (p->top_ref_pic_id, 2);
      free_mem4Dshort (p->top_mv, 2, p->size_y / BLOCK_SIZE / 2);
      
      
      if (p->top_moving_block)
      {
        free_mem2D (p->top_moving_block);
        p->top_moving_block=NULL;
      }
      
      free_mem3D      ((byte***)p->bottom_ref_idx, 2);
      free_mem3Dint64 (p->bottom_ref_pic_id, 2);
      free_mem4Dshort (p->bottom_mv, 2, p->size_y / BLOCK_SIZE / 2);
      
      
      if (p->bottom_moving_block)
      {
        free_mem2D (p->bottom_moving_block);
        p->bottom_moving_block=NULL;
      }    
      
    }

    free(p);

    p=NULL;
  }
}

/*!
 ************************************************************************
 * \brief
 *    Compute co-located motion info
 *
 ************************************************************************
 */

void compute_colocated(ColocatedParams* p, StorablePicture **listX[6])
{
  StorablePicture *fs, *fs_top, *fs_bottom;
  int i,j, ii, jj, jdiv;

  fs_top=fs_bottom=fs = listX[LIST_1 ][0];

  if (img->MbaffFrameFlag)
  {
    fs_top= listX[LIST_1 + 2][0];
    fs_bottom= listX[LIST_1 + 4][0];
  }
  else
  {
    if (img->field_pic_flag)
    {
      if ((img->structure != fs->structure) && (fs->coded_frame))
      {
        if (img->structure==TOP_FIELD)
        {
          fs_top=fs_bottom=fs = listX[LIST_1 ][0]->top_field;
        }
        else
        {
          fs_top=fs_bottom=fs = listX[LIST_1 ][0]->bottom_field;
        }
      }
    }
  }
  
  if (!active_sps->frame_mbs_only_flag || active_sps->direct_8x8_inference_flag)      
  {
    for (j=0 ; j<fs->size_y/4 ; j++)      
    {
      jdiv = j/2;
      jj = j/2 + 4 * (j/8);
      for (i=0 ; i<fs->size_x/4 ; i++)          
      {                

        if (img->MbaffFrameFlag && fs->field_frame[j][i])
        { 
          //! Assign frame buffers for field MBs   
          //! Check whether we should use top or bottom field mvs.
          //! Depending on the assigned poc values.
          
          if (abs(dec_picture->poc - fs_bottom->poc)> abs(dec_picture->poc -fs_top->poc) )
          {
            p->mv[LIST_0][j][i][0]    = fs_top->mv[LIST_0][jdiv][i][0];
            p->mv[LIST_0][j][i][1]    = fs_top->mv[LIST_0][jdiv][i][1] ;          
            p->mv[LIST_1][j][i][0]    = fs_top->mv[LIST_1][jdiv][i][0];
            p->mv[LIST_1][j][i][1]    = fs_top->mv[LIST_1][jdiv][i][1] ;           
            p->ref_idx[LIST_0][j][i]  = fs_top->ref_idx[LIST_0][jdiv][i];         
            p->ref_idx[LIST_1][j][i]  = fs_top->ref_idx[LIST_1][jdiv][i];  
            p->ref_pic_id[LIST_0][j][i]   = fs->ref_id[LIST_0][jj][i];
            p->ref_pic_id[LIST_1][j][i]   = fs->ref_id[LIST_1][jj][i];
            
            p->is_long_term             = fs_top->is_long_term;
          }
          else
          {
            p->mv[LIST_0][j][i][0]      = fs_bottom->mv[LIST_0][jdiv][i][0];
            p->mv[LIST_0][j][i][1]      = fs_bottom->mv[LIST_0][jdiv][i][1] ;          
            p->mv[LIST_1][j][i][0]      = fs_bottom->mv[LIST_1][jdiv][i][0];
            p->mv[LIST_1][j][i][1]      = fs_bottom->mv[LIST_1][jdiv][i][1] ;           
            p->ref_idx[LIST_0][j][i]    = fs_bottom->ref_idx[LIST_0][jdiv][i];
            p->ref_idx[LIST_1][j][i]    = fs_bottom->ref_idx[LIST_1][jdiv][i];
            p->ref_pic_id[LIST_0][j][i] = fs->ref_id[LIST_0][jj + 4][i];
            p->ref_pic_id[LIST_1][j][i] = fs->ref_id[LIST_1][jj + 4][i];
            
            p->is_long_term             = fs_bottom->is_long_term;
          }          
        }
        else
        {
          p->mv[LIST_0][j][i][0]      = fs->mv[LIST_0][j][i][0];
          p->mv[LIST_0][j][i][1]      = fs->mv[LIST_0][j][i][1] ;          
          p->mv[LIST_1][j][i][0]      = fs->mv[LIST_1][j][i][0];
          p->mv[LIST_1][j][i][1]      = fs->mv[LIST_1][j][i][1] ;           
          p->ref_idx[LIST_0][j][i]    = fs->ref_idx[LIST_0][j][i];         
          p->ref_idx[LIST_1][j][i]    = fs->ref_idx[LIST_1][j][i];                   
          p->ref_pic_id[LIST_0][j][i] = fs->ref_id[LIST_0][j][i];
          p->ref_pic_id[LIST_1][j][i] = fs->ref_id[LIST_1][j][i];
          
          p->is_long_term             = fs->is_long_term;
        }
      }      
    }
  }    
        

  //! Generate field MVs from Frame MVs
  if (img->structure || img->MbaffFrameFlag)
  {    
    for (j=0 ; j<fs->size_y/8 ; j++)
    {       
      jj = RSD(j);
      for (i=0 ; i<fs->size_x/4 ; i++)
      {
        ii = RSD(i);
        //! Do nothing if macroblock as field coded in MB-AFF        
        if (!img->MbaffFrameFlag )
        {
          p->mv[LIST_0][j][i][0] = fs->mv[LIST_0][jj][ii][0];
          p->mv[LIST_0][j][i][1] = fs->mv[LIST_0][jj][ii][1];
          p->mv[LIST_1][j][i][0] = fs->mv[LIST_1][jj][ii][0];
          p->mv[LIST_1][j][i][1] = fs->mv[LIST_1][jj][ii][1];
          
          // Scaling of references is done here since it will not affect spatial direct (2*0 =0)

          if (fs->ref_idx[LIST_0][jj][ii] == -1)      
          {
            p->ref_idx   [LIST_0][j][i] = -1;
            p->ref_pic_id[LIST_0][j][i] = -1;
          }
          else
          {
            p->ref_idx   [LIST_0][j][i] = fs->ref_idx[LIST_0][jj][ii] ;
            p->ref_pic_id[LIST_0][j][i] = fs->ref_id [LIST_0][jj][ii];
          }
          
          if (fs->ref_idx[LIST_1][jj][ii] == -1)      
          {
            p->ref_idx   [LIST_1][j][i] = -1;
            p->ref_pic_id[LIST_1][j][i] = -1;
          }
          else
          {
            p->ref_idx   [LIST_1][j][i] = fs->ref_idx[LIST_1][jj][ii];
            p->ref_pic_id[LIST_1][j][i] = fs->ref_id [LIST_1][jj][ii];
          }
          
          p->is_long_term = fs->is_long_term;

          if (img->direct_spatial_mv_pred_flag == 1)
          {
            p->moving_block[j][i] = 
              !((!p->is_long_term 
              && ((p->ref_idx[LIST_0][j][i] == 0) 
              &&  (abs(p->mv[LIST_0][j][i][0])>>1 == 0) 
              &&  (abs(p->mv[LIST_0][j][i][1])>>1 == 0))) 
              || ((p->ref_idx[LIST_0][j][i] == -1) 
              &&  (p->ref_idx[LIST_1][j][i] == 0) 
              &&  (abs(p->mv[LIST_1][j][i][0])>>1 == 0) 
              &&  (abs(p->mv[LIST_1][j][i][1])>>1 == 0)));
          }
        }
        else
        {
          p->bottom_mv[LIST_0][j][i][0] = fs_bottom->mv[LIST_0][jj][ii][0];
          p->bottom_mv[LIST_0][j][i][1] = fs_bottom->mv[LIST_0][jj][ii][1];
          p->bottom_mv[LIST_1][j][i][0] = fs_bottom->mv[LIST_1][jj][ii][0];
          p->bottom_mv[LIST_1][j][i][1] = fs_bottom->mv[LIST_1][jj][ii][1];
          p->bottom_ref_idx[LIST_0][j][i] = fs_bottom->ref_idx[LIST_0][jj][ii]; 
          p->bottom_ref_idx[LIST_1][j][i] = fs_bottom->ref_idx[LIST_1][jj][ii]; 
          p->bottom_ref_pic_id[LIST_0][j][i] = fs_bottom->ref_id[LIST_0][jj][ii];
          p->bottom_ref_pic_id[LIST_1][j][i] = fs_bottom->ref_id[LIST_1][jj][ii];

          if (img->direct_spatial_mv_pred_flag == 1)
          {
            p->bottom_moving_block[j][i] = 
              !((!fs_bottom->is_long_term 
              && ((p->bottom_ref_idx[LIST_0][j][i] == 0) 
              &&  (abs(p->bottom_mv[LIST_0][j][i][0])>>1 == 0) 
              &&  (abs(p->bottom_mv[LIST_0][j][i][1])>>1 == 0))) 
              || ((p->bottom_ref_idx[LIST_0][j][i] == -1) 
              &&  (p->bottom_ref_idx[LIST_1][j][i] == 0) 
              &&  (abs(p->bottom_mv[LIST_1][j][i][0])>>1 == 0) 
              &&  (abs(p->bottom_mv[LIST_1][j][i][1])>>1 == 0)));
          }

          p->top_mv[LIST_0][j][i][0] = fs_top->mv[LIST_0][jj][ii][0];
          p->top_mv[LIST_0][j][i][1] = fs_top->mv[LIST_0][jj][ii][1];
          p->top_mv[LIST_1][j][i][0] = fs_top->mv[LIST_1][jj][ii][0];
          p->top_mv[LIST_1][j][i][1] = fs_top->mv[LIST_1][jj][ii][1];
          p->top_ref_idx[LIST_0][j][i] = fs_top->ref_idx[LIST_0][jj][ii]; 
          p->top_ref_idx[LIST_1][j][i] = fs_top->ref_idx[LIST_1][jj][ii]; 
          p->top_ref_pic_id[LIST_0][j][i] = fs_top->ref_id[LIST_0][jj][ii];
          p->top_ref_pic_id[LIST_1][j][i] = fs_top->ref_id[LIST_1][jj][ii]; 

          if (img->direct_spatial_mv_pred_flag == 1)
          {
            p->top_moving_block[j][i] = 
              !((!fs_top->is_long_term 
              && ((p->top_ref_idx[LIST_0][j][i] == 0) 
              &&  (abs(p->top_mv[LIST_0][j][i][0])>>1 == 0) 
              &&  (abs(p->top_mv[LIST_0][j][i][1])>>1 == 0))) 
              || ((p->top_ref_idx[LIST_0][j][i] == -1) 
              &&  (p->top_ref_idx[LIST_1][j][i] == 0) 
              &&  (abs(p->top_mv[LIST_1][j][i][0])>>1 == 0) 
              &&  (abs(p->top_mv[LIST_1][j][i][1])>>1 == 0)));
          }

          if ((img->direct_spatial_mv_pred_flag == 0 ) && !fs->field_frame[2*j][i])
          {
            p->top_mv[LIST_0][j][i][1] /= 2;        
            p->top_mv[LIST_1][j][i][1] /= 2;
            p->bottom_mv[LIST_0][j][i][1] /= 2;        
            p->bottom_mv[LIST_1][j][i][1] /= 2;
          }

        }
      }
    }
  }

  
  if (!active_sps->frame_mbs_only_flag || active_sps->direct_8x8_inference_flag)      
  {       
    //! Use inference flag to remap mvs/references
    //! Frame with field co-located
    
    if (!img->structure)
    {
      for (j=0 ; j<fs->size_y/4 ; j++)      
      {                
        jdiv = j/2;
        jj = j/2 + 4*(j/8);
        for (i=0 ; i<fs->size_x/4 ; i++)          
        {                
          
          if (fs->field_frame[j][i])
          {
            if (abs(dec_picture->poc - fs->bottom_field->poc) > abs(dec_picture->poc - fs->top_field->poc))
            {
              p->mv[LIST_0][j][i][0] = fs->top_field->mv[LIST_0][jdiv][i][0];
              p->mv[LIST_0][j][i][1] = fs->top_field->mv[LIST_0][jdiv][i][1] ;
              p->mv[LIST_1][j][i][0] = fs->top_field->mv[LIST_1][jdiv][i][0];
              p->mv[LIST_1][j][i][1] = fs->top_field->mv[LIST_1][jdiv][i][1] ; 
              
              p->ref_idx[LIST_0][j][i]  = fs->top_field->ref_idx[LIST_0][jdiv][i];
              p->ref_idx[LIST_1][j][i]  = fs->top_field->ref_idx[LIST_1][jdiv][i];
              p->ref_pic_id[LIST_0][j][i]   = fs->ref_id[LIST_0][jj][i];
              p->ref_pic_id[LIST_1][j][i]   = fs->ref_id[LIST_1][jj][i];                     
              p->is_long_term               = fs->top_field->is_long_term;
            }
            else
            {
              p->mv[LIST_0][j][i][0] = fs->bottom_field->mv[LIST_0][jdiv][i][0];
              p->mv[LIST_0][j][i][1] = fs->bottom_field->mv[LIST_0][jdiv][i][1] ;
              p->mv[LIST_1][j][i][0] = fs->bottom_field->mv[LIST_1][jdiv][i][0];
              p->mv[LIST_1][j][i][1] = fs->bottom_field->mv[LIST_1][jdiv][i][1] ; 
              
              p->ref_idx[LIST_0][j][i]  = fs->bottom_field->ref_idx[LIST_0][jdiv][i];
              p->ref_idx[LIST_1][j][i]  = fs->bottom_field->ref_idx[LIST_1][jdiv][i];
              p->ref_pic_id[LIST_0][j][i] = fs->ref_id[LIST_0][jj + 4][i];
              p->ref_pic_id[LIST_1][j][i] = fs->ref_id[LIST_1][jj + 4][i];                     
              p->is_long_term             = fs->bottom_field->is_long_term;
            }
          }
        }
      }      
    }
  }


  p->is_long_term = fs->is_long_term;
  
  if (!active_sps->frame_mbs_only_flag || active_sps->direct_8x8_inference_flag)      
  {
    for (j=0 ; j<fs->size_y/4 ; j++)      
    {                
      jj = RSD(j);
      for (i=0 ; i<fs->size_x/4 ; i++)          
      {           
        ii = RSD(i);
        
        p->mv[LIST_0][j][i][0]=p->mv[LIST_0][jj][ii][0];
        p->mv[LIST_0][j][i][1]=p->mv[LIST_0][jj][ii][1];
        p->mv[LIST_1][j][i][0]=p->mv[LIST_1][jj][ii][0];
        p->mv[LIST_1][j][i][1]=p->mv[LIST_1][jj][ii][1];        
        
        p->ref_idx[LIST_0][j][i]=p->ref_idx[LIST_0][jj][ii];
        p->ref_idx[LIST_1][j][i]=p->ref_idx[LIST_1][jj][ii];
        p->ref_pic_id[LIST_0][j][i] = p->ref_pic_id[LIST_0][jj][ii];
        p->ref_pic_id[LIST_1][j][i] = p->ref_pic_id[LIST_1][jj][ii];
        
        if (img->direct_spatial_mv_pred_flag == 1)
        {
          p->moving_block[j][i]= 
            !((!p->is_long_term 
            && ((p->ref_idx[LIST_0][j][i] == 0) 
            &&  (abs(p->mv[LIST_0][j][i][0])>>1 == 0) 
            &&  (abs(p->mv[LIST_0][j][i][1])>>1 == 0))) 
            || ((p->ref_idx[LIST_0][j][i] == -1) 
            &&  (p->ref_idx[LIST_1][j][i] == 0) 
            &&  (abs(p->mv[LIST_1][j][i][0])>>1 == 0) 
            &&  (abs(p->mv[LIST_1][j][i][1])>>1 == 0)));
        }
      }
    }
  }
  else
  {
    for (j=0 ; j<fs->size_y/4 ; j++)      
    {                
      jj = RSD(j);
      for (i=0 ; i<fs->size_x/4 ; i++)          
      {           
        ii = RSD(i);
        //! Use inference flag to remap mvs/references
        p->mv[LIST_0][j][i][0]=fs->mv[LIST_0][j][i][0];
        p->mv[LIST_0][j][i][1]=fs->mv[LIST_0][j][i][1];
        p->mv[LIST_1][j][i][0]=fs->mv[LIST_1][j][i][0];
        p->mv[LIST_1][j][i][1]=fs->mv[LIST_1][j][i][1];        
        
        p->ref_idx[LIST_0][j][i]=fs->ref_idx[LIST_0][j][i];
        p->ref_idx[LIST_1][j][i]=fs->ref_idx[LIST_1][j][i];
        p->ref_pic_id[LIST_0][j][i] = fs->ref_id[LIST_0][j][i];
        p->ref_pic_id[LIST_1][j][i] = fs->ref_id[LIST_1][j][i];
        
        if (img->direct_spatial_mv_pred_flag == 1)
        {
          p->moving_block[j][i]= 
            !((!p->is_long_term 
            && ((p->ref_idx[LIST_0][j][i] == 0) 
            &&  (abs(p->mv[LIST_0][j][i][0])>>1 == 0) 
            &&  (abs(p->mv[LIST_0][j][i][1])>>1 == 0))) 
            || ((p->ref_idx[LIST_0][j][i] == -1) 
            &&  (p->ref_idx[LIST_1][j][i] == 0) 
            &&  (abs(p->mv[LIST_1][j][i][0])>>1 == 0) 
            &&  (abs(p->mv[LIST_1][j][i][1])>>1 == 0)));
        }
      }
    }      
  }
  
  
  if (img->direct_spatial_mv_pred_flag ==0)
  {
    for (j=0 ; j<fs->size_y/4 ; j++)      
    {                
      for (i=0 ; i<fs->size_x/4 ; i++)          
      {                
        
        if ((!img->MbaffFrameFlag &&!img->structure && fs->field_frame[j][i]) || (img->MbaffFrameFlag && fs->field_frame[j][i]))
        {
          p->mv[LIST_0][j][i][1] *= 2;        
          p->mv[LIST_1][j][i][1] *= 2;
        }
        else  if (img->structure && !fs->field_frame[j][i])
        {
          p->mv[LIST_0][j][i][1] /= 2;
          p->mv[LIST_1][j][i][1] /= 2;
        }
        
      }      
    }
    
    for (j=0; j<2 + (img->MbaffFrameFlag * 4);j+=2)
    {
      for (i=0; i<listXsize[j];i++)
      {
        int prescale, iTRb, iTRp;
        
        if (j==0)
        {
          iTRb = Clip3( -128, 127, dec_picture->poc - listX[LIST_0 + j][i]->poc );
        }
        else if (j == 2)
        {          
          iTRb = Clip3( -128, 127, dec_picture->top_poc - listX[LIST_0 + j][i]->poc );
        }
        else
        {
          iTRb = Clip3( -128, 127, dec_picture->bottom_poc - listX[LIST_0 + j][i]->poc );
        }
        
        iTRp = Clip3( -128, 127,  listX[LIST_1 + j][0]->poc - listX[LIST_0 + j][i]->poc);
        
        if (iTRp!=0)
        {
          prescale = ( 16384 + abs( iTRp / 2 ) ) / iTRp;
          img->mvscale[j][i] = Clip3( -1024, 1023, ( iTRb * prescale + 32 ) >> 6 ) ;
        }
        else
        {
          img->mvscale[j][i] = 9999;
        }
      }
    }
  }
}

