/* kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; remove-trailing-space on;
 * Copyright (C) 2008-2019 the xine project
 * Copyright (C) 2008 Christophe Thommeret <hftom@free.fr>
 *
 * This file is part of xine, a free video player.
 *
 * xine is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * xine is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
 *
 * alterh264_decode.c, a H264 video stream parser using VDPAU hardware decoder
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "alterh264_decode.h"
#include "group_vdpau.h"


#define MAX_DPB_SIZE 16
#define MIN_BUFFER_SIZE 10000
#define MAX_BUFFER_SIZE 3145728

#define NAL_UNSPECIFIED 0
#define NAL_SLICE_NO_IDR 1
#define NAL_SLICE_IDR 5
#define NAL_SEI 6
#define NAL_SEQUENCE 7
#define NAL_PICTURE 8
#define NAL_ACCES 9
#define NAL_END_SEQUENCE 10
#define NAL_END_STREAM 11
#define NAL_SEQUENCE_EXT 13

#define SLICE_TYPE_P 0
#define SLICE_TYPE_B 1
#define SLICE_TYPE_I 2
#define SLICE_TYPE_SP 3
#define SLICE_TYPE_SI 4

#define START_IDR_FLAG 1000

#define MAX_POC 2147483647

#define DPB_DRAW_CLEAR   1
#define DPB_DRAW_REFS   2
#define DPB_DRAW_CURRENT 3

//#define MAKE_DAT /*do NOT define this, unless you know what you do */
#ifdef MAKE_DAT
static int nframes;
static FILE *outfile;
#endif

static const uint8_t zigzag_4x4[16] = {
  0, 1, 4, 8,
  5, 2, 3, 6,
  9, 12, 13, 10,
  7, 11, 14, 15
};

static const uint8_t zigzag_8x8[64] = {
  0, 1, 8, 16, 9, 2, 3, 10,
  17, 24, 32, 25, 18, 11, 4, 5,
  12, 19, 26, 33, 40, 48, 41, 34,
  27, 20, 13, 6, 7, 14, 21, 28,
  35, 42, 49, 56, 57, 50, 43, 36,
  29, 22, 15, 23, 30, 37, 44, 51,
  58, 59, 52, 45, 38, 31, 39, 46,
  53, 60, 61, 54, 47, 55, 62, 63
};

static const uint8_t default_4x4_intra[16] = {
  6, 13, 13, 20,
  20, 20, 28, 28,
  28, 28, 32, 32,
  32, 37, 37, 42
};

static const uint8_t default_4x4_inter[16] = {
  10, 14, 14, 20,
  20, 20, 24, 24,
  24, 24, 27, 27,
  27, 30, 30, 34
};

static const uint8_t default_8x8_intra[64] = {
  6, 10, 10, 13, 11, 13, 16, 16,
  16, 16, 18, 18, 18, 18, 18, 23,
  23, 23, 23, 23, 23, 25, 25, 25,
  25, 25, 25, 25, 27, 27, 27, 27,
  27, 27, 27, 27, 29, 29, 29, 29,
  29, 29, 29, 31, 31, 31, 31, 31,
  31, 33, 33, 33, 33, 33, 36, 36,
  36, 36, 38, 38, 38, 40, 40, 42
};

static const uint8_t default_8x8_inter[64] = {
  9, 13, 13, 15, 13, 15, 17, 17,
  17, 17, 19, 19, 19, 19, 19, 21,
  21, 21, 21, 21, 21, 22, 22, 22,
  22, 22, 22, 22, 24, 24, 24, 24,
  24, 24, 24, 24, 25, 25, 25, 25,
  25, 25, 25, 27, 27, 27, 27, 27,
  27, 28, 28, 28, 28, 28, 30, 30,
  30, 30, 32, 32, 32, 33, 33, 35
};



/*-------- DPB -------------------------------------------*/
static void
dpb_print (sequence_t * sequence)
{
  int i;
  dpb_frame_t *frame;
  uint32_t sf;

  for (i = 0; i < MAX_DPB_SIZE; i++)
  {
    frame = sequence->dpb[i];
    if (!frame->used)
      break;
    vo_frame_t *vo = (vo_frame_t *) frame->videoSurface;
    vdpau_accel_t *accel;
    if (vo)
      accel = (vdpau_accel_t *) vo->accel_data;
    sf = (vo) ? accel->surface : (uint32_t)-1;
    fprintf (stderr,
	     "{ i:%d u:%d c:%d pn:%d-%d ir:%d-%d tpoc:%d bpoc:%d sf:%u }\n",
	     i, frame->used, frame->completed, frame->PicNum[0],
	     frame->PicNum[1], frame->is_reference[0], frame->is_reference[1],
	     frame->TopFieldOrderCnt, frame->BottomFieldOrderCnt, sf);
  }
}



static void
dpb_clear_all_pts (sequence_t * sequence)
{
  int i;

  for (i = 0; i < MAX_DPB_SIZE; i++)
  {
    if (!sequence->dpb[i]->used)
      break;
    sequence->dpb[i]->pts = 0;
  }
  sequence->cur_pic.pts = 0;
  sequence->cur_pic.drop_pts = 1;
}


static void
dpb_reset (sequence_t * sequence)
{
  int i;

  for (i = 0; i < MAX_DPB_SIZE; i++)
  {
    if (sequence->dpb[i]->videoSurface)
      sequence->dpb[i]->videoSurface->free (sequence->dpb[i]->videoSurface);
    memset (sequence->dpb[i], 0, sizeof (dpb_frame_t));
  }
  if (sequence->cur_pic.videoSurface && !sequence->cur_pic.is_reference[0]
      && !sequence->cur_pic.is_reference[1])
  {
    //fprintf(stderr, "freeing cur_pic\n");
    sequence->cur_pic.videoSurface->free (sequence->cur_pic.videoSurface);
  }
}



static void
dpb_remove (sequence_t * sequence, int index)
{
  lprintf ("|||||||||||||||||||||||||||||||||||||||| dbp_remove\n");
  int i;

  dpb_frame_t *frame = sequence->dpb[index];
  if (frame->videoSurface)
    frame->videoSurface->free (frame->videoSurface);
  memset (frame, 0, sizeof (dpb_frame_t));
  for (i = index; i < (MAX_DPB_SIZE - 1); i++)
  {
    sequence->dpb[i] = sequence->dpb[i + 1];
    if (!sequence->dpb[i]->used)
    {
      sequence->dpb[i + 1] = frame;
      break;
    }
  }
  if (i == (MAX_DPB_SIZE - 1))
    sequence->dpb[i] = frame;
}



static dpb_frame_t *
dpb_get_prev_ref (sequence_t * sequence)
{
  int i = MAX_DPB_SIZE - 1;

  while (i > -1)
  {
    if (sequence->dpb[i]->used)
      return sequence->dpb[i];
    --i;
  }

  return NULL;
}



static void
dpb_draw_frames (vdpau_h264_alter_decoder_t * this_gen, int32_t curpoc,
		 int draw_mode)
{
  sequence_t *seq = (sequence_t *) & this_gen->sequence;
  int i, index = 0;
  int32_t poc, tpoc;
  dpb_frame_t *frame;

  while (index > -1)
  {
    index = -1;
    poc = curpoc;
    for (i = 0; i < MAX_DPB_SIZE; i++)
    {
      frame = seq->dpb[i];
      if (!frame->used)
	break;
      tpoc =
	(frame->TopFieldOrderCnt >
	 frame->BottomFieldOrderCnt) ? frame->TopFieldOrderCnt : frame->
	BottomFieldOrderCnt;
      if (!frame->videoSurface->drawn && (tpoc <= poc))
      {
	poc = tpoc;
	index = i;
      }
    }
    if ((index > -1) && (poc <= curpoc))
    {
      //fprintf(stderr,"|||||||||||||||||||||||||||||||||||||||| dpb_draw_frame = %d\n", poc);
      frame = seq->dpb[index];
      frame->videoSurface->pts = frame->pts;
      //fprintf(stderr,"H264 PTS = %llu\n", frame->pts);
      frame->videoSurface->top_field_first = frame->top_field_first;
      frame->videoSurface->draw (frame->videoSurface, this_gen->stream);
      frame->videoSurface->drawn++;
      if ((draw_mode != DPB_DRAW_CLEAR) && !frame->is_reference[0]
	  && !frame->is_reference[1])
	dpb_remove (seq, index);
    }
    else
      index = -1;
  }

  if (draw_mode == DPB_DRAW_CURRENT)
  {
    //fprintf(stderr,"|||||||||||||||||||||||||||||||||||||||| dpb_draw_frame = %d\n", curpoc);
    frame = &seq->cur_pic;
    frame->videoSurface->pts = frame->pts;
    //fprintf(stderr,"H264 PTS = %llu\n", frame->pts);
    frame->videoSurface->top_field_first = frame->top_field_first;
    frame->videoSurface->draw (frame->videoSurface, this_gen->stream);
    frame->videoSurface->free (frame->videoSurface);
  }
  else if (draw_mode == DPB_DRAW_CLEAR)
    dpb_reset (seq);
}



static dpb_frame_t *
dpb_get_PicNum (sequence_t * sequence, int32_t pic_num, int *index)
{
  dpb_frame_t *frame;
  int i = 0;

  for (i = 0; i < MAX_DPB_SIZE; i++)
  {
    frame = sequence->dpb[i];
    if (!frame->used)
      break;
    if ((frame->PicNum[0] == pic_num) || (frame->PicNum[1] == pic_num))
    {
      *index = i;
      return frame;
    }
  }
  return 0;
}



static void
dpb_mmc1 (vdpau_h264_alter_decoder_t * this_gen, int32_t picnum)
{
  sequence_t *seq = (sequence_t *) & this_gen->sequence;
  int index;

  lprintf ("dpb_mmc1\n");

  dpb_frame_t *frame = dpb_get_PicNum (seq, picnum, &index);

  if (frame)
  {
    frame->is_reference[0] = frame->is_reference[1] = 0;
    if (frame->videoSurface->drawn)
      dpb_remove (seq, index);
    else
      dpb_draw_frames (this_gen,
		       (frame->TopFieldOrderCnt >
			frame->BottomFieldOrderCnt) ? frame->
		       TopFieldOrderCnt : frame->BottomFieldOrderCnt,
		       DPB_DRAW_REFS);
  }
}



static void
dbp_append (vdpau_h264_alter_decoder_t * this_gen, int second_field)
{
  sequence_t *sequence = (sequence_t *) & this_gen->sequence;
  int i, index = 0, refs = 0;
  int32_t fnw = MAX_POC;
  slice_param_t *sl = &sequence->slice_param;
  pic_param_t *pic = sequence->pic_param[sl->pic_parameter_set_id];
  seq_param_t *sp = sequence->seq_param[pic->seq_parameter_set_id];
  dpb_frame_t *tmp = 0, *cur_pic = &sequence->cur_pic;
  int max = sp->num_ref_frames ? sp->num_ref_frames : 1;
  max = (max > MAX_DPB_SIZE) ? MAX_DPB_SIZE : max;

#ifdef LOG
  vo_frame_t *vo = (vo_frame_t *) cur_pic->videoSurface;
  vdpau_accel_t *accel = (vdpau_accel_t *) vo->accel_data;
  lprintf
    ("|||||||||||||||||||||||||||||||||||||||| dbp_append surface = %d\n",
     accel->surface);
#endif

  if (second_field)
  {
    tmp = dpb_get_prev_ref (sequence);
    if (tmp)
    {
      memcpy (tmp, cur_pic, sizeof (dpb_frame_t));
      cur_pic->videoSurface = NULL;
    }
    else
      fprintf (stderr, "OOPS, no frame to store the second field ?!\n");
    return;
  }

  for (i = 0; i < MAX_DPB_SIZE; i++)
  {
    if (!sequence->dpb[i]->used)
      break;
    if (sequence->dpb[i]->FrameNumWrap < fnw)
    {
      fnw = sequence->dpb[i]->FrameNumWrap;
      index = i;
    }
    refs++;
  }

  if (refs >= max)
  {
    lprintf ("sliding window\n");
    tmp = sequence->dpb[index],
      tmp->is_reference[0] = tmp->is_reference[1] = 0;
    if (tmp->videoSurface->drawn)
      dpb_remove (sequence, index);
    else
      dpb_draw_frames (this_gen,
		       (tmp->TopFieldOrderCnt >
			tmp->BottomFieldOrderCnt) ? tmp->
		       TopFieldOrderCnt : tmp->BottomFieldOrderCnt,
		       DPB_DRAW_REFS);

    for (i = 0; i < MAX_DPB_SIZE; i++)
    {
      if (!sequence->dpb[i]->used)
	break;
    }
  }

  if (i < MAX_DPB_SIZE)
  {
    memcpy (sequence->dpb[i], cur_pic, sizeof (dpb_frame_t));
    if (!cur_pic->field_pic_flag)
      cur_pic->videoSurface = NULL;
  }
}

/*--------------------------------------------------------*/



static void
reset_slices (sequence_t * sequence)
{
  sequence->slices_count = 0;
  sequence->slice_mode = 0;
}



static void
reset_sequence (sequence_t * sequence)
{
  sequence->prevFrameNum = 0;
  sequence->prevFrameNumOffset = 0;
  sequence->prevMMC5 = 0;

  sequence->startup_frame = 0;
  sequence->reset = 0;
  sequence->chroma = 0;
  sequence->pic_pts = 0;
  sequence->bufpos = 0;
  sequence->bufseek = 0;
  sequence->start = -1;
  reset_slices (sequence);
  dpb_reset (sequence);
  memset (&sequence->cur_pic, 0, sizeof (dpb_frame_t));
  sequence->reset = VO_NEW_SEQUENCE_FLAG;
}



static void
set_ratio (sequence_t * seq, seq_param_t * sp)
{
  if (seq->mode_frame && seq->ratio)
    return;
  if (!seq->coded_height)
    seq->coded_height = 1;
  seq->ratio = (double) seq->coded_width / (double) seq->coded_height;
  if (sp->vui.aspect_ratio_info)
  {
    switch (sp->vui.aspect_ratio_idc)
    {
    case ASPECT_1_1:
      seq->ratio = 1 * seq->ratio;
      break;
    case ASPECT_12_11:
      seq->ratio *= 12.0 / 11.0;
      break;
    case ASPECT_10_11:
      seq->ratio *= 10.0 / 11.0;
      break;
    case ASPECT_16_11:
      seq->ratio *= 16.0 / 11.0;
      break;
    case ASPECT_40_33:
      seq->ratio *= 40.0 / 33.0;
      break;
    case ASPECT_24_11:
      seq->ratio *= 24.0 / 11.0;
      break;
    case ASPECT_20_11:
      seq->ratio *= 20.0 / 11.0;
      break;
    case ASPECT_32_11:
      seq->ratio *= 32.0 / 11.0;
      break;
    case ASPECT_80_33:
      seq->ratio *= 80.0 / 33.0;
      break;
    case ASPECT_18_11:
      seq->ratio *= 18.0 / 11.0;
      break;
    case ASPECT_15_11:
      seq->ratio *= 15.0 / 11.0;
      break;
    case ASPECT_64_33:
      seq->ratio *= 64.0 / 33.0;
      break;
    case ASPECT_160_99:
      seq->ratio *= 160.0 / 99.0;
      break;
    case ASPECT_4_3:
      seq->ratio *= 4.0 / 3.0;
      break;
    case ASPECT_3_2:
      seq->ratio *= 3.0 / 2.0;
      break;
    case ASPECT_2_1:
      seq->ratio *= 2.0 / 1.0;
      break;
    case ASPECT_EXTENDED_SAR:
      if (sp->vui.sar_height)
	seq->ratio *= (double) sp->vui.sar_width / sp->vui.sar_height;
      break;
    }
  }
}



static void
parse_scaling_list (bits_reader_t * br, uint8_t * scaling_list, int len,
		    int index)
{
  int last_scale = 8;
  int next_scale = 8;
  int32_t delta_scale;
  uint8_t use_default_scaling_matrix_flag = 0;
  int i;
  uint32_t u;

  const uint8_t *zigzag = (len == 64) ? zigzag_8x8 : zigzag_4x4;

  for (i = 0; i < len; i++)
  {
    if (next_scale != 0)
    {
      delta_scale = read_exp_se (br);
      next_scale = (last_scale + delta_scale + 256) % 256;
      if (i == 0 && next_scale == 0)
      {
	use_default_scaling_matrix_flag = 1;
	break;
      }
    }
    scaling_list[zigzag[i]] = last_scale =
      (next_scale == 0) ? last_scale : next_scale;
  }

  if (use_default_scaling_matrix_flag)
  {
    switch (index)
    {
    case 0:
    case 1:
    case 2:
      {
	for (u = 0; u < sizeof (default_4x4_intra); u++)
	  scaling_list[zigzag_4x4[u]] = default_4x4_intra[u];
	break;
      }
    case 3:
    case 4:
    case 5:
      {
	for (u = 0; u < sizeof (default_4x4_inter); u++)
	  scaling_list[zigzag_4x4[u]] = default_4x4_inter[u];
	break;
      }
    case 6:
      {
	for (u = 0; u < sizeof (default_8x8_intra); u++)
	  scaling_list[zigzag_8x8[u]] = default_8x8_intra[u];
	break;
      }
    case 7:
      {
	for (u = 0; u < sizeof (default_8x8_inter); u++)
	  scaling_list[zigzag_8x8[u]] = default_8x8_inter[u];
	break;
      }
    }
  }
}



static void
scaling_list_fallback_A (uint8_t * scaling_lists_4x4,
			 uint8_t * scaling_lists_8x8, int i)
{
  uint32_t j;
  switch (i)
  {
  case 0:
      for (j = 0; j < sizeof (default_4x4_intra); j++)
	scaling_lists_4x4[(i * 16) + zigzag_4x4[j]] = default_4x4_intra[j];
      break;
  case 3:
      for (j = 0; j < sizeof (default_4x4_inter); j++)
	scaling_lists_4x4[(i * 16) + zigzag_4x4[j]] = default_4x4_inter[j];
      break;
  case 1:
  case 2:
  case 4:
  case 5:
    memcpy (&scaling_lists_4x4[i * 16], &scaling_lists_4x4[(i - 1) * 16],
	    16);
    break;
  case 6:
      for (j = 0; j < sizeof (default_8x8_intra); j++)
	scaling_lists_8x8[(i - 6) * 64 + zigzag_8x8[j]] =
	  default_8x8_intra[j];
      break;
  case 7:
      for (j = 0; j < sizeof (default_8x8_inter); j++)
	scaling_lists_8x8[(i - 6) * 64 + zigzag_8x8[j]] =
	  default_8x8_inter[j];
      break;
  }
}



static void
scaling_list_fallback_B (seq_param_t * sp, pic_param_t * pic, int i)
{
  switch (i)
  {
  case 0:
  case 3:
    memcpy (pic->scaling_lists_4x4[i], sp->scaling_lists_4x4[i],
	    sizeof (pic->scaling_lists_4x4[i]));
    break;
  case 1:
  case 2:
  case 4:
  case 5:
    memcpy (pic->scaling_lists_4x4[i], pic->scaling_lists_4x4[i - 1],
	    sizeof (pic->scaling_lists_4x4[i]));
    break;
  case 6:
  case 7:
    memcpy (pic->scaling_lists_8x8[i - 6], sp->scaling_lists_8x8[i - 6],
	    sizeof (pic->scaling_lists_8x8[i - 6]));
    break;
  }
}



static void
vui_parameters (sequence_t * seq, vui_param_t * vui)
{
  bits_reader_t *br = &seq->br;
  int xine_color_matrix = 4; /* undefined, mpeg range */

  vui->aspect_ratio_info = read_bits (br, 1);
  lprintf ("aspect_ratio_info_present_flag = %d\n", vui->aspect_ratio_info);
  if (vui->aspect_ratio_info)
  {
    vui->aspect_ratio_idc = read_bits (br, 8);
    lprintf ("aspect_ratio_idc = %d\n", vui->aspect_ratio_idc);
    if (vui->aspect_ratio_idc == 255)
    {
      vui->sar_width = read_bits (br, 16);
      lprintf ("sar_width = %d\n", vui->sar_width);
      vui->sar_height = read_bits (br, 16);
      lprintf ("sar_height = %d\n", vui->sar_height);
    }
  }
  if (read_bits (br, 1))	/* overscan_info_present_flag */
    skip_bits (br, 1);		/* overscan_appropriate_falg */
  if (read_bits (br, 1))
  {				/* video_signal_type_present_flag */
    skip_bits (br, 3);		/*video_format */
    xine_color_matrix |= read_bits (br, 1);  /*video_full_range_flag */
    vui->colour_desc = read_bits (br, 1);
    lprintf ("colour_desc = %d\n", vui->colour_desc);
    if (vui->colour_desc)
    {
      skip_bits (br, 8);        /* colour_primaries */
      skip_bits (br, 8);	/* transfer_characteristics */
      xine_color_matrix = (xine_color_matrix & 1) | (read_bits (br, 8) << 1);  /* matrix_coefficients */
    }
  }
  VO_SET_FLAGS_CM (xine_color_matrix, seq->color_matrix);
  if (read_bits (br, 1))
  {				/* chroma_loc_info_present_flag */
    read_exp_ue (br);		/* chroma_sample_loc_type_top_field */
    read_exp_ue (br);		/* chroma_sample_loc_type_bottom_field */
  }
  vui->timing_info = read_bits (br, 1);
  lprintf ("timing_info = %d\n", vui->timing_info);
  if (vui->timing_info)
  {
    vui->num_units_in_tick = read_bits (br, 32);
    lprintf ("num_units_in_tick = %u\n", vui->num_units_in_tick);
    vui->time_scale = read_bits (br, 32);
    lprintf ("time_scale = %u\n", vui->time_scale);
    if (vui->time_scale > 0)
      seq->video_step =
	180000. * (double) vui->num_units_in_tick / (double) vui->time_scale;
  }
}



static void
seq_parameter_set_data (vdpau_h264_alter_decoder_t * this_gen)
{
  sequence_t *seq = (sequence_t *) & this_gen->sequence;
  seq_param_t *sp;
  int i;

  uint8_t profile_idc = read_bits (&seq->br, 8);
  lprintf ("profile_idc = %d\n", profile_idc);
  uint8_t constraint_set0_flag = read_bits (&seq->br, 1);
  lprintf ("constraint_set0_flag = %d\n", constraint_set0_flag);
  uint8_t constraint_set1_flag = read_bits (&seq->br, 1);
  lprintf ("constraint_set1_flag = %d\n", constraint_set1_flag);
  uint8_t constraint_set2_flag = read_bits (&seq->br, 1);
  lprintf ("constraint_set2_flag = %d\n", constraint_set2_flag);
  uint8_t constraint_set3_flag = read_bits (&seq->br, 1);
  lprintf ("constraint_set3_flag = %d\n", constraint_set3_flag);
  skip_bits (&seq->br, 4);
  uint8_t level_idc = read_bits (&seq->br, 8);
  lprintf ("level_idc = %d\n", level_idc);

  uint8_t seq_parameter_set_id = read_exp_ue (&seq->br);
  lprintf ("seq_parameter_set_id = %d\n", seq_parameter_set_id);
  if (seq_parameter_set_id > 31)
  {
    lprintf ("OOPS : seq_parameter_set_id > 31 !!\n");
    return;
  }

  if (!seq->seq_param[seq_parameter_set_id])
    seq->seq_param[seq_parameter_set_id] =
      (seq_param_t *) calloc (1, sizeof (seq_param_t));
  if (!seq->seq_param[seq_parameter_set_id])
  {
    lprintf ("OOPS : can't allocate SPS %d !!\n", seq_parameter_set_id);
    return;
  }

  sp = seq->seq_param[seq_parameter_set_id];
  sp->profile_idc = profile_idc;
  switch (profile_idc)
  {
  case 100:
    seq->profile = VDP_DECODER_PROFILE_H264_HIGH;
    break;
  case 77:
    seq->profile = VDP_DECODER_PROFILE_H264_MAIN;
    break;
  case 66:			/* nvidia's vdpau doesn't suppot baseline, force main */
  default:
    seq->profile = VDP_DECODER_PROFILE_H264_MAIN;
  }
  sp->constraint_set0_flag = constraint_set0_flag;
  sp->constraint_set1_flag = constraint_set1_flag;
  sp->constraint_set2_flag = constraint_set2_flag;
  sp->constraint_set3_flag = constraint_set3_flag;
  sp->level_idc = level_idc;

  memset (&sp->scaling_lists_4x4, 16, sizeof (sp->scaling_lists_4x4));
  memset (&sp->scaling_lists_8x8, 16, sizeof (sp->scaling_lists_8x8));

  sp->chroma_format_idc = 1;
  sp->separate_colour_plane_flag = 0;
  if (sp->profile_idc == 100 || sp->profile_idc == 110
      || sp->profile_idc == 122 || sp->profile_idc == 244
      || sp->profile_idc == 44 || sp->profile_idc == 83
      || sp->profile_idc == 86)
  {
    sp->chroma_format_idc = read_exp_ue (&seq->br);
    lprintf ("chroma_format_idc = %u\n", sp->chroma_format_idc);
    if (sp->chroma_format_idc == 3)
    {
      sp->separate_colour_plane_flag = read_bits (&seq->br, 1);
      lprintf ("separate_colour_plane_flag = %d\n",
	       sp->separate_colour_plane_flag);
    }
    sp->bit_depth_luma_minus8 = read_exp_ue (&seq->br);
    lprintf ("bit_depth_luma_minus8 = %u\n", sp->bit_depth_luma_minus8);
    sp->bit_depth_chroma_minus8 = read_exp_ue (&seq->br);
    lprintf ("bit_depth_chroma_minus8 = %u\n", sp->bit_depth_chroma_minus8);
    sp->qpprime_y_zero_transform_bypass_flag = read_bits (&seq->br, 1);
    lprintf ("qpprime_y_zero_transform_bypass_flag = %u\n",
	     sp->qpprime_y_zero_transform_bypass_flag);
    sp->seq_scaling_matrix_present_flag = read_bits (&seq->br, 1);
    lprintf ("seq_scaling_matrix_present_flag = %u\n",
	     sp->seq_scaling_matrix_present_flag);
    if (sp->seq_scaling_matrix_present_flag)
    {
      for (i = 0; i < 8; i++)
      {
	int scaling_flag = read_bits (&seq->br, 1);
	if (scaling_flag)
	{
	  if (i < 6)
	    parse_scaling_list (&seq->br, &sp->scaling_lists_4x4[i][0], 16,
				i);
	  else
	    parse_scaling_list (&seq->br, &sp->scaling_lists_8x8[i - 6][0],
				64, i);
	}
	else
	  scaling_list_fallback_A ((uint8_t *) sp->scaling_lists_4x4,
				   (uint8_t *) sp->scaling_lists_8x8, i);
      }
    }
  }
  sp->log2_max_frame_num_minus4 = read_exp_ue (&seq->br);
  lprintf ("log2_max_frame_num_minus4 = %u\n", sp->log2_max_frame_num_minus4);
  sp->pic_order_cnt_type = read_exp_ue (&seq->br);
  lprintf ("pic_order_cnt_type = %u\n", sp->pic_order_cnt_type);
  if (sp->pic_order_cnt_type == 0)
  {
    sp->log2_max_pic_order_cnt_lsb_minus4 = read_exp_ue (&seq->br);
    lprintf ("log2_max_pic_order_cnt_lsb_minus4 = %u\n",
	     sp->log2_max_pic_order_cnt_lsb_minus4);
  }
  else if (sp->pic_order_cnt_type == 1)
  {
    sp->delta_pic_order_always_zero_flag = read_bits (&seq->br, 1);
    lprintf ("delta_pic_order_always_zero_flag = %u\n",
	     sp->delta_pic_order_always_zero_flag);
    sp->offset_for_non_ref_pic = read_exp_se (&seq->br);
    lprintf ("offset_for_non_ref_pic = %d\n", sp->offset_for_non_ref_pic);
    sp->offset_for_top_to_bottom_field = read_exp_se (&seq->br);
    lprintf ("offset_for_top_to_bottom_field = %d\n",
	     sp->offset_for_top_to_bottom_field);
    sp->num_ref_frames_in_pic_order_cnt_cycle = read_exp_ue (&seq->br);
    lprintf ("num_ref_frames_in_pic_order_cnt_cycle = %u\n",
	     sp->num_ref_frames_in_pic_order_cnt_cycle);
    for (i = 0; i < sp->num_ref_frames_in_pic_order_cnt_cycle; i++)
    {
      sp->offset_for_ref_frame[i] = read_exp_se (&seq->br);
      lprintf ("offset_for_ref_frame[%d] = %d\n", i,
	       sp->offset_for_ref_frame[i]);
    }
  }
  sp->num_ref_frames = read_exp_ue (&seq->br);
  if (sp->num_ref_frames > 16)
    sp->num_ref_frames = 16;
  lprintf ("num_ref_frames = %u\n", sp->num_ref_frames);
  sp->gaps_in_frame_num_value_allowed_flag = read_bits (&seq->br, 1);
  lprintf ("gaps_in_frame_num_value_allowed_flag = %u\n",
	   sp->gaps_in_frame_num_value_allowed_flag);
  sp->pic_width_in_mbs_minus1 = read_exp_ue (&seq->br);
  lprintf ("pic_width_in_mbs_minus1 = %u\n", sp->pic_width_in_mbs_minus1);
  sp->pic_height_in_map_units_minus1 = read_exp_ue (&seq->br);
  lprintf ("pic_height_in_map_units_minus1 = %u\n",
	   sp->pic_height_in_map_units_minus1);
  sp->frame_mbs_only_flag = read_bits (&seq->br, 1);
  lprintf ("frame_mbs_only_flag = %u\n", sp->frame_mbs_only_flag);

  seq->coded_width = (sp->pic_width_in_mbs_minus1 + 1) * 16;
  seq->coded_height =
    (2 - sp->frame_mbs_only_flag) * (sp->pic_height_in_map_units_minus1 +
				     1) * 16;

  if (!sp->frame_mbs_only_flag)
  {
    sp->mb_adaptive_frame_field_flag = read_bits (&seq->br, 1);
    lprintf ("mb_adaptive_frame_field_flag = %u\n",
	     sp->mb_adaptive_frame_field_flag);
  }
  else
    sp->mb_adaptive_frame_field_flag = 0;
  sp->direct_8x8_inference_flag = read_bits (&seq->br, 1);
  lprintf ("direct_8x8_inference_flag = %u\n", sp->direct_8x8_inference_flag);
  sp->frame_cropping_flag = read_bits (&seq->br, 1);
  lprintf ("frame_cropping_flag = %u\n", sp->frame_cropping_flag);
  if (sp->frame_cropping_flag)
  {
    sp->frame_crop_left_offset = read_exp_ue (&seq->br);
    lprintf ("frame_crop_left_offset = %u\n", sp->frame_crop_left_offset);
    sp->frame_crop_right_offset = read_exp_ue (&seq->br);
    lprintf ("frame_crop_right_offset = %u\n", sp->frame_crop_right_offset);
    sp->frame_crop_top_offset = read_exp_ue (&seq->br);
    lprintf ("frame_crop_top_offset = %u\n", sp->frame_crop_top_offset);
    sp->frame_crop_bottom_offset = read_exp_ue (&seq->br);
    lprintf ("frame_crop_bottom_offset = %u\n", sp->frame_crop_bottom_offset);
    seq->coded_height -=
      (2 - sp->frame_mbs_only_flag) * 2 * sp->frame_crop_bottom_offset;
  }
  if (seq->coded_height == 1088)
    seq->coded_height = 1080;
  sp->vui_parameters_present_flag = read_bits (&seq->br, 1);
  lprintf ("vui_parameters_present_flag = %u\n",
	   sp->vui_parameters_present_flag);
  if (sp->vui_parameters_present_flag)
    vui_parameters (seq, &sp->vui);
  set_ratio (seq, sp);
}



static void
pic_parameter_set (vdpau_h264_alter_decoder_t * this_gen)
{
  sequence_t *seq = (sequence_t *) & this_gen->sequence;
  pic_param_t *pic;
  seq_param_t *sp;
  int i;

  uint8_t pic_parameter_set_id = read_exp_ue (&seq->br);
  lprintf ("pic_parameter_set_id = %u\n", pic_parameter_set_id);
  if (!seq->pic_param[pic_parameter_set_id])
    seq->pic_param[pic_parameter_set_id] =
      (pic_param_t *) calloc (1, sizeof (pic_param_t));
  if (!seq->pic_param[pic_parameter_set_id])
  {
    lprintf ("OOPS : can't allocate PPS %d !!\n", pic_parameter_set_id);
    return;
  }
  pic = seq->pic_param[pic_parameter_set_id];

  uint8_t seq_parameter_set_id = read_exp_ue (&seq->br);
  lprintf ("seq_parameter_set_id = %u\n", seq_parameter_set_id);
  if (seq_parameter_set_id > 31)
  {
    lprintf ("OOPS : referenced SPS (%d) does not exist !!\n",
	     seq_parameter_set_id);
    return;
  }
  if (!seq->seq_param[seq_parameter_set_id])
  {
    lprintf ("OOPS : referenced SPS (%d) does not exist !!\n",
	     seq_parameter_set_id);
    return;
  }

  pic->seq_parameter_set_id = seq_parameter_set_id;
  sp = seq->seq_param[pic->seq_parameter_set_id];
  pic->entropy_coding_mode_flag = read_bits (&seq->br, 1);
  lprintf ("entropy_coding_mode_flag = %u\n", pic->entropy_coding_mode_flag);
  pic->pic_order_present_flag = read_bits (&seq->br, 1);
  lprintf ("pic_order_present_flag = %u\n", pic->pic_order_present_flag);
  uint8_t num_slice_groups_minus1 = read_exp_ue (&seq->br);
  lprintf ("num_slice_groups_minus1 = %u\n", num_slice_groups_minus1);
  if (num_slice_groups_minus1 > 0)
  {
    uint8_t slice_group_map_type = read_exp_ue (&seq->br);
    lprintf ("slice_group_map_type = %u\n", slice_group_map_type);
    if (!slice_group_map_type)
    {
      for (i = 0; i < num_slice_groups_minus1; i++)
	read_exp_ue (&seq->br);
    }
    else if (slice_group_map_type == 2)
    {
      for (i = 0; i < num_slice_groups_minus1; i++)
      {
	read_exp_ue (&seq->br);
	read_exp_ue (&seq->br);
      }
    }
    else if (slice_group_map_type == 3 || slice_group_map_type == 4
	     || slice_group_map_type == 5)
    {
      read_bits (&seq->br, 1);
      read_exp_ue (&seq->br);
    }
    else if (slice_group_map_type == 6)
    {
      read_exp_ue (&seq->br);
    }
  }
  pic->num_ref_idx_l0_active_minus1 = read_exp_ue (&seq->br);
  lprintf ("num_ref_idx_l0_active_minus1 = %u\n",
	   pic->num_ref_idx_l0_active_minus1);
  pic->num_ref_idx_l1_active_minus1 = read_exp_ue (&seq->br);
  lprintf ("num_ref_idx_l1_active_minus1 = %u\n",
	   pic->num_ref_idx_l1_active_minus1);
  pic->weighted_pred_flag = read_bits (&seq->br, 1);
  lprintf ("weighted_pred_flag = %u\n", pic->weighted_pred_flag);
  pic->weighted_bipred_idc = read_bits (&seq->br, 2);
  lprintf ("weighted_bipred_idc = %u\n", pic->weighted_bipred_idc);
  pic->pic_init_qp_minus26 = read_exp_se (&seq->br);
  lprintf ("pic_init_qp_minus26 = %d\n", pic->pic_init_qp_minus26);
  pic->pic_init_qs_minus26 = read_exp_se (&seq->br);
  lprintf ("pic_init_qs_minus26 = %d\n", pic->pic_init_qs_minus26);
  pic->chroma_qp_index_offset = read_exp_se (&seq->br);
  lprintf ("chroma_qp_index_offset = %d\n", pic->chroma_qp_index_offset);
  pic->deblocking_filter_control_present_flag = read_bits (&seq->br, 1);
  lprintf ("deblocking_filter_control_present_flag = %u\n",
	   pic->deblocking_filter_control_present_flag);
  pic->constrained_intra_pred_flag = read_bits (&seq->br, 1);
  lprintf ("constrained_intra_pred_flag = %u\n",
	   pic->constrained_intra_pred_flag);
  pic->redundant_pic_cnt_present_flag = read_bits (&seq->br, 1);
  lprintf ("redundant_pic_cnt_present_flag = %u\n",
	   pic->redundant_pic_cnt_present_flag);

  uint32_t more = more_rbsp_data (&seq->br);
  lprintf ("more bits = %u (buflen = %d) (still = %zd)\n", more,
           seq->br.length, (ssize_t)(seq->br.start + seq->br.length - seq->br.buffer));
  if (more)
  {
    pic->transform_8x8_mode_flag = read_bits (&seq->br, 1);
    lprintf ("transform_8x8_mode_flag = %u\n", pic->transform_8x8_mode_flag);
    pic->pic_scaling_matrix_present_flag = read_bits (&seq->br, 1);
    lprintf ("pic_scaling_matrix_present_flag = %u\n",
	     pic->pic_scaling_matrix_present_flag);
    if (pic->pic_scaling_matrix_present_flag)
    {
      for (i = 0; i < 8; i++)
      {
	if (i < 6 || pic->transform_8x8_mode_flag)
	  pic->pic_scaling_list_present_flag[i] = read_bits (&seq->br, 1);
	else
	  pic->pic_scaling_list_present_flag[i] = 0;

	if (pic->pic_scaling_list_present_flag[i])
	{
	  if (i < 6)
	    parse_scaling_list (&seq->br, &pic->scaling_lists_4x4[i][0], 16,
				i);
	  else
	    parse_scaling_list (&seq->br, &pic->scaling_lists_8x8[i - 6][0],
				64, i);
	}
	else
	{
	  if (!sp->seq_scaling_matrix_present_flag)
	    scaling_list_fallback_A ((uint8_t *) pic->scaling_lists_4x4,
				     (uint8_t *) pic->scaling_lists_8x8, i);
	  else
	    scaling_list_fallback_B (sp, pic, i);
	}
      }
    }
    pic->second_chroma_qp_index_offset = read_exp_se (&seq->br);
    lprintf ("second_chroma_qp_index_offset = %d\n",
	     pic->second_chroma_qp_index_offset);
  }
  else
  {
    pic->transform_8x8_mode_flag = 0;
    pic->pic_scaling_matrix_present_flag = 0;
    pic->second_chroma_qp_index_offset = pic->chroma_qp_index_offset;
  }
}



static void
pred_weight_table (vdpau_h264_alter_decoder_t * this_gen, uint8_t slice_type,
		   uint8_t ChromaArrayType, uint8_t l0, uint8_t l1)
{
  sequence_t *seq = (sequence_t *) & this_gen->sequence;
  int i;

  read_exp_ue (&seq->br);
  if (ChromaArrayType)
    read_exp_ue (&seq->br);
  for (i = 0; i <= l0; i++)
  {
    if (read_bits (&seq->br, 1))
    {
      read_exp_se (&seq->br);
      read_exp_se (&seq->br);
    }
    if (ChromaArrayType && read_bits (&seq->br, 1))
    {
      read_exp_se (&seq->br);
      read_exp_se (&seq->br);
      read_exp_se (&seq->br);
      read_exp_se (&seq->br);
    }
  }
  if (slice_type == SLICE_TYPE_B)
  {
    for (i = 0; i <= l1; i++)
    {
      if (read_bits (&seq->br, 1))
      {
	read_exp_se (&seq->br);
	read_exp_se (&seq->br);
      }
      if (ChromaArrayType)
      {
	if (read_bits (&seq->br, 1))
	{
	  read_exp_se (&seq->br);
	  read_exp_se (&seq->br);
	  read_exp_se (&seq->br);
	  read_exp_se (&seq->br);
	}
      }
    }
  }
}



static void
ref_pic_list_reordering (vdpau_h264_alter_decoder_t * this_gen)
{
  sequence_t *seq = (sequence_t *) & this_gen->sequence;
  slice_param_t *sl = &seq->slice_param;

  if ((sl->slice_type != SLICE_TYPE_I) && (sl->slice_type != SLICE_TYPE_SI))
  {
    if (read_bits (&seq->br, 1))
    {
      uint32_t tmp/*, diff*/;
      do
      {
	tmp = read_exp_ue (&seq->br);
	if (tmp == 0 || tmp == 1)
	  /*diff =*/ read_exp_ue (&seq->br);
	else if (tmp == 2)
          /*diff =*/ read_exp_ue (&seq->br);
      }
      while (tmp != 3 && !seq->br.oflow);
    }
  }
  if (sl->slice_type == SLICE_TYPE_B)
  {
    if (read_bits (&seq->br, 1))
    {
      uint32_t tmp2/*, diff2*/;
      do
      {
	tmp2 = read_exp_ue (&seq->br);
	if (tmp2 == 0 || tmp2 == 1)
	  /*diff2 =*/ read_exp_ue (&seq->br);
	else if (tmp2 == 2)
	  /*diff2 =*/ read_exp_ue (&seq->br);
      }
      while (tmp2 != 3 && !seq->br.oflow);
    }
  }
}



static void
dec_ref_pic_marking (vdpau_h264_alter_decoder_t * this_gen, uint8_t idr)
{
  sequence_t *seq = (sequence_t *) & this_gen->sequence;
  int32_t pic_num;

  if (idr)
  {
#ifdef LOG
    uint8_t no_output_of_prior_pics_flag = read_bits (&seq->br, 1);
    lprintf ("no_output_of_prior_pics_flag = %u\n",
	     no_output_of_prior_pics_flag);
    uint8_t long_term_reference_flag = read_bits (&seq->br, 1);
    lprintf ("long_term_reference_flag = %u\n", long_term_reference_flag);
#else
    skip_bits (&seq->br, 2);
#endif
  }
  else
  {
    uint8_t adaptive_ref_pic_marking_mode_flag = read_bits (&seq->br, 1);
    lprintf ("adaptive_ref_pic_marking_mode_flag = %u\n",
	     adaptive_ref_pic_marking_mode_flag);
    if (!adaptive_ref_pic_marking_mode_flag)
    {
      if (seq->cur_pic.field_pic_flag
	  && (seq->cur_pic.completed == PICTURE_DONE)
	  && (seq->cur_pic.is_reference[0] || seq->cur_pic.is_reference[1]))
      {
	seq->cur_pic.is_reference[0] = seq->cur_pic.is_reference[1] =
	  SHORT_TERM_REF;
	lprintf ("short_ref marking\n");
      }
      // sliding window is always performed in dpb_append()
    }
    else
    {
      uint8_t memory_management_control_operation;
      do
      {
	memory_management_control_operation = read_exp_ue (&seq->br);
	lprintf ("memory_management_control_operation = %u\n",
		 memory_management_control_operation);
	if (memory_management_control_operation == 1
	    || memory_management_control_operation == 3)
	{
	  uint32_t difference_of_pic_nums_minus1 = read_exp_ue (&seq->br);
	  lprintf ("difference_of_pic_nums_minus1 = %u\n",
		   difference_of_pic_nums_minus1);
	  pic_num =
	    seq->cur_pic.PicNum[0] - (difference_of_pic_nums_minus1 + 1);
	  dpb_mmc1 (this_gen, pic_num);
	}
	if (memory_management_control_operation == 2)
	{
#ifdef LOG
	  uint32_t long_term_pic_num = read_exp_ue (&seq->br);
	  lprintf ("long_term_pic_num = %u\n", long_term_pic_num);
#else
          read_exp_ue (&seq->br);
#endif
	}
	if (memory_management_control_operation == 3
	    || memory_management_control_operation == 6)
	{
#ifdef LOG
	  uint32_t long_term_frame_idx = read_exp_ue (&seq->br);
	  lprintf ("long_term_frame_idx = %u\n", long_term_frame_idx);
#else
          read_exp_ue (&seq->br);
#endif
	}
	if (memory_management_control_operation == 4)
	{
#ifdef LOG
	  uint32_t max_long_term_frame_idx_plus1 = read_exp_ue (&seq->br);
	  lprintf ("max_long_term_frame_idx_plus1 = %u\n",
		   max_long_term_frame_idx_plus1);
#else
          read_exp_ue (&seq->br);
#endif
	}
      }
      while (memory_management_control_operation && !seq->br.oflow);
    }
  }
}



static void
slice_header (vdpau_h264_alter_decoder_t * this_gen, uint8_t nal_ref_idc,
	      uint8_t nal_unit_type)
{
  sequence_t *seq = (sequence_t *) & this_gen->sequence;
  slice_param_t *sl = &seq->slice_param;
  pic_param_t *pic;
  seq_param_t *sp;

  sl->nal_ref_idc = nal_ref_idc;
  sl->nal_unit_type = nal_unit_type;

  read_exp_ue (&seq->br);	/* first_mb_in_slice */
  sl->slice_type = read_exp_ue (&seq->br) % 5;
  lprintf ("slice_type = %u\n", sl->slice_type);
  sl->pic_parameter_set_id = read_exp_ue (&seq->br);
  lprintf ("pic_parameter_set_id = %u\n", sl->pic_parameter_set_id);
  if (!seq->pic_param[sl->pic_parameter_set_id])
  {
    lprintf ("OOPS : referenced PPS (%d) does not exist !!\n",
	     sl->pic_parameter_set_id);
    seq->cur_pic.missing_header = 1;
    return;
  }
  pic = seq->pic_param[sl->pic_parameter_set_id];
  if (!seq->seq_param[pic->seq_parameter_set_id])
  {
    lprintf ("OOPS : referenced SPS (%d) does not exist !!\n",
	     pic->seq_parameter_set_id);
    seq->cur_pic.missing_header = 1;
    return;
  }

  if (!seq->startup_frame && (sl->slice_type == SLICE_TYPE_I)
      && !seq->cur_pic.completed)
    seq->startup_frame = 1;

  lprintf ("seq_parameter_set_id = %u\n", pic->seq_parameter_set_id);
  sp = seq->seq_param[pic->seq_parameter_set_id];
  if (sp->separate_colour_plane_flag)
    read_bits (&seq->br, 2);	/* colour_plane_id */
  sl->frame_num = read_bits (&seq->br, sp->log2_max_frame_num_minus4 + 4);
  lprintf ("frame_num = %u\n", sl->frame_num);
  sl->MaxFrameNum = 1 << (sp->log2_max_frame_num_minus4 + 4);

  sl->field_pic_flag = sl->bottom_field_flag =
    sl->delta_pic_order_cnt_bottom = 0;
  sl->delta_pic_order_cnt[0] = sl->delta_pic_order_cnt[1] = 0;

  if (!sp->frame_mbs_only_flag)
  {
    sl->field_pic_flag = read_bits (&seq->br, 1);
    lprintf ("field_pic_flag = %u\n", sl->field_pic_flag);
    if (sl->field_pic_flag)
    {
      sl->bottom_field_flag = read_bits (&seq->br, 1);
      lprintf ("bottom_field_flag = %u\n", sl->bottom_field_flag);
    }
  }
  if (nal_unit_type == NAL_SLICE_IDR)
  {
    sl->idr_pic_id = read_exp_ue (&seq->br);
    lprintf ("idr_pic_id = %u\n", sl->idr_pic_id);
  }
  if (sp->pic_order_cnt_type == 0)
  {
    sl->pic_order_cnt_lsb =
      read_bits (&seq->br, sp->log2_max_pic_order_cnt_lsb_minus4 + 4);
    lprintf ("pic_order_cnt_lsb = %u\n", sl->pic_order_cnt_lsb);
    if (pic->pic_order_present_flag && !sl->field_pic_flag)
    {
      sl->delta_pic_order_cnt_bottom = read_exp_se (&seq->br);
      lprintf ("delta_pic_order_cnt_bottom = %d\n",
	       sl->delta_pic_order_cnt_bottom);
    }
  }
  if (sp->pic_order_cnt_type == 1 && !sp->delta_pic_order_always_zero_flag)
  {
    sl->delta_pic_order_cnt[0] = read_exp_se (&seq->br);
    lprintf ("delta_pic_order_cnt[0] = %d\n", sl->delta_pic_order_cnt[0]);
    if (pic->pic_order_present_flag && !sl->field_pic_flag)
    {
      sl->delta_pic_order_cnt[1] = read_exp_se (&seq->br);
      lprintf ("delta_pic_order_cnt[1] = %d\n", sl->delta_pic_order_cnt[1]);
    }
  }
  if (pic->redundant_pic_cnt_present_flag)
  {
    sl->redundant_pic_cnt = read_exp_ue (&seq->br);
    lprintf ("redundant_pic_cnt = %u\n", sl->redundant_pic_cnt);
  }
  if (sl->slice_type == SLICE_TYPE_B)
    skip_bits (&seq->br, 1);	/* direct_spatial_mv_pred_flag */

  sl->num_ref_idx_l0_active_minus1 = pic->num_ref_idx_l0_active_minus1;
  sl->num_ref_idx_l1_active_minus1 = pic->num_ref_idx_l1_active_minus1;

  if (sl->slice_type == SLICE_TYPE_P || sl->slice_type == SLICE_TYPE_SP
      || sl->slice_type == SLICE_TYPE_B)
  {
    if (read_bits (&seq->br, 1))
    {
      lprintf ("num_ref_idx_active_override_flag = 1\n");
      sl->num_ref_idx_l0_active_minus1 = read_exp_ue (&seq->br);
      if (sl->slice_type == SLICE_TYPE_B)
	sl->num_ref_idx_l1_active_minus1 = read_exp_ue (&seq->br);
      lprintf ("num_ref_idx_l0_active_minus1 = %u\n",
	       sl->num_ref_idx_l0_active_minus1);
      lprintf ("num_ref_idx_l1_active_minus1 = %u\n",
	       sl->num_ref_idx_l1_active_minus1);
    }
  }
}



static void
slice_header_post (vdpau_h264_alter_decoder_t * this_gen)
{
  sequence_t *seq = (sequence_t *) & this_gen->sequence;
  slice_param_t *sl = &seq->slice_param;

  if (!sl->nal_ref_idc)
    return;

  pic_param_t *pic = seq->pic_param[sl->pic_parameter_set_id];
  seq_param_t *sp = seq->seq_param[pic->seq_parameter_set_id];

  if ((pic->weighted_pred_flag
       && ((sl->slice_type == SLICE_TYPE_P)
	   || (sl->slice_type == SLICE_TYPE_SP)))
      || ((pic->weighted_bipred_idc == 1)
	  && (sl->slice_type == SLICE_TYPE_B)))
  {
    uint8_t chroma =
      (sp->separate_colour_plane_flag) ? 0 : sp->chroma_format_idc;
    pred_weight_table (this_gen, sl->slice_type, chroma,
		       sl->num_ref_idx_l0_active_minus1,
		       sl->num_ref_idx_l1_active_minus1);
  }

  dec_ref_pic_marking (this_gen, (sl->nal_unit_type == 5) ? 1 : 0);
}



static void
decode_poc (vdpau_h264_alter_decoder_t * this_gen)
{
  sequence_t *seq = (sequence_t *) & this_gen->sequence;
  slice_param_t *sl = &seq->slice_param;
  pic_param_t *pic = seq->pic_param[sl->pic_parameter_set_id];
  seq_param_t *sp = seq->seq_param[pic->seq_parameter_set_id];
  int parity = sl->bottom_field_flag ? 1 : 0;

  seq->cur_pic.used = 1;
  seq->cur_pic.FrameNum = sl->frame_num;
  seq->cur_pic.is_reference[parity] = sl->nal_ref_idc;
  seq->cur_pic.field_pic_flag = sl->field_pic_flag;

  if (sl->field_pic_flag)
  {
    if (!seq->cur_pic.completed)
      seq->cur_pic.top_field_first = !parity;
    seq->cur_pic.completed |=
      (parity ? PICTURE_BOTTOM_DONE : PICTURE_TOP_DONE);
  }
  else
  {
    seq->cur_pic.is_reference[!parity] = seq->cur_pic.is_reference[parity];
    seq->cur_pic.completed = PICTURE_DONE;
  }

  if (sp->pic_order_cnt_type == 0)
  {
    dpb_frame_t *prev_pic = dpb_get_prev_ref (seq);
    int32_t prevPicOrderCntMsb, prevPicOrderCntLsb;
    uint32_t MaxPicOrderCntLsb =
      1 << (sp->log2_max_pic_order_cnt_lsb_minus4 + 4);

    seq->cur_pic.pic_order_cnt_lsb = sl->pic_order_cnt_lsb;
    seq->cur_pic.top_field_first =
      (sl->delta_pic_order_cnt_bottom < 0) ? 0 : 1;

    if (!prev_pic)
    {
      seq->cur_pic.PicOrderCntMsb = seq->cur_pic.TopFieldOrderCnt =
	seq->cur_pic.BottomFieldOrderCnt = 0;
      return;
    }
    if (sl->nal_unit_type == NAL_SLICE_IDR)
      prevPicOrderCntMsb = prevPicOrderCntLsb = 0;
    else if (prev_pic->mmc5)
    {
      if (!sl->bottom_field_flag)
      {
	prevPicOrderCntMsb = 0;
	prevPicOrderCntLsb = prev_pic->TopFieldOrderCnt;
      }
      else
	prevPicOrderCntMsb = prevPicOrderCntLsb = 0;
    }
    else
    {
      prevPicOrderCntMsb = prev_pic->PicOrderCntMsb;
      prevPicOrderCntLsb = prev_pic->pic_order_cnt_lsb;
    }

    if ((sl->pic_order_cnt_lsb < prevPicOrderCntLsb)
	&& ((prevPicOrderCntLsb - sl->pic_order_cnt_lsb) >=
	    (int32_t)(MaxPicOrderCntLsb / 2)))
      seq->cur_pic.PicOrderCntMsb = prevPicOrderCntMsb + MaxPicOrderCntLsb;
    else if ((sl->pic_order_cnt_lsb > prevPicOrderCntLsb)
	     && ((sl->pic_order_cnt_lsb - prevPicOrderCntLsb) >
		 (int32_t)(MaxPicOrderCntLsb / 2)))
      seq->cur_pic.PicOrderCntMsb = prevPicOrderCntMsb - MaxPicOrderCntLsb;
    else
      seq->cur_pic.PicOrderCntMsb = prevPicOrderCntMsb;

    if (!sl->field_pic_flag)
    {
      seq->cur_pic.TopFieldOrderCnt =
	seq->cur_pic.PicOrderCntMsb + sl->pic_order_cnt_lsb;
      seq->cur_pic.BottomFieldOrderCnt =
	seq->cur_pic.TopFieldOrderCnt + sl->delta_pic_order_cnt_bottom;
    }
    else
    {
      if (sl->bottom_field_flag)
	seq->cur_pic.BottomFieldOrderCnt =
	  seq->cur_pic.PicOrderCntMsb + sl->pic_order_cnt_lsb;
      else
	seq->cur_pic.TopFieldOrderCnt =
	  seq->cur_pic.PicOrderCntMsb + sl->pic_order_cnt_lsb;
    }
  }
  else
  {
    int16_t FrameNumOffset, prevFrameNumOffset;
    uint16_t MaxFrameNum = 1 << (sp->log2_max_frame_num_minus4 + 4);

    if (sl->nal_unit_type == NAL_SLICE_IDR)
    {
      FrameNumOffset = 0;
    }
    else
    {
      if (seq->prevMMC5)
	prevFrameNumOffset = 0;
      else
	prevFrameNumOffset = seq->prevFrameNumOffset;

      if (seq->prevFrameNum > sl->frame_num)
	FrameNumOffset = prevFrameNumOffset + MaxFrameNum;
      else
	FrameNumOffset = prevFrameNumOffset;
    }

    if (sp->pic_order_cnt_type == 1)
    {
      int16_t absFrameNum = 0, picOrderCntCycleCnt =
	0, frameNumInPicOrderCntCycle = 0, expectedDeltaPerPicOrderCntCycle =
	0, expectedPicOrderCnt = 0;
      int i;
      if (sp->num_ref_frames_in_pic_order_cnt_cycle)
	absFrameNum = FrameNumOffset + sl->frame_num;
      if (!sl->nal_ref_idc && (absFrameNum > 0))
	--absFrameNum;

      for (i = 0; i < sp->num_ref_frames_in_pic_order_cnt_cycle; i++)
	expectedDeltaPerPicOrderCntCycle += sp->offset_for_ref_frame[i];

      if (absFrameNum > 0)
      {
	picOrderCntCycleCnt =
	  (absFrameNum - 1) / sp->num_ref_frames_in_pic_order_cnt_cycle;
	frameNumInPicOrderCntCycle =
	  (absFrameNum - 1) % sp->num_ref_frames_in_pic_order_cnt_cycle;
	expectedPicOrderCnt =
	  picOrderCntCycleCnt * expectedDeltaPerPicOrderCntCycle;
	for (i = 0; i < frameNumInPicOrderCntCycle; i++)
	  expectedPicOrderCnt += sp->offset_for_ref_frame[i];
      }
      if (!sl->nal_ref_idc)
	expectedPicOrderCnt += sp->offset_for_non_ref_pic;

      if (!sl->field_pic_flag)
      {
	seq->cur_pic.TopFieldOrderCnt =
	  expectedPicOrderCnt + sl->delta_pic_order_cnt[0];
	seq->cur_pic.BottomFieldOrderCnt =
	  seq->cur_pic.TopFieldOrderCnt + sp->offset_for_top_to_bottom_field +
	  sl->delta_pic_order_cnt[1];
      }
      else if (!sl->bottom_field_flag)
	seq->cur_pic.TopFieldOrderCnt =
	  expectedPicOrderCnt + sl->delta_pic_order_cnt[0];
      else
	seq->cur_pic.BottomFieldOrderCnt =
	  expectedPicOrderCnt + sp->offset_for_top_to_bottom_field +
	  sl->delta_pic_order_cnt[1];
    }
    else
    {
      int32_t tmpPicOrderCnt;
      if (sl->nal_unit_type == NAL_SLICE_IDR)
	tmpPicOrderCnt = 0;
      else if (!sl->nal_ref_idc)
	tmpPicOrderCnt = 2 * (FrameNumOffset + sl->frame_num) - 1;
      else
	tmpPicOrderCnt = 2 * (FrameNumOffset + sl->frame_num);

      if (!sl->field_pic_flag)
	seq->cur_pic.TopFieldOrderCnt = seq->cur_pic.BottomFieldOrderCnt =
	  tmpPicOrderCnt;
      else if (sl->bottom_field_flag)
	seq->cur_pic.BottomFieldOrderCnt = tmpPicOrderCnt;
      else
	seq->cur_pic.TopFieldOrderCnt = tmpPicOrderCnt;
    }
    seq->prevFrameNum = seq->cur_pic.FrameNum;
    seq->prevFrameNumOffset = FrameNumOffset;
  }

  if (seq->cur_pic.completed < PICTURE_DONE)
  {
    if (sl->bottom_field_flag)
      seq->cur_pic.TopFieldOrderCnt = seq->cur_pic.BottomFieldOrderCnt;
    else
      seq->cur_pic.BottomFieldOrderCnt = seq->cur_pic.TopFieldOrderCnt;
  }
}



static void
decode_picnum (vdpau_h264_alter_decoder_t * this_gen)
{
  sequence_t *seq = (sequence_t *) & this_gen->sequence;
  slice_param_t *sl = &seq->slice_param;
  dpb_frame_t *frame;
  int i = 0;

  int parity = sl->bottom_field_flag ? 1 : 0;

  if (!seq->cur_pic.field_pic_flag)
    seq->cur_pic.PicNum[0] = seq->cur_pic.FrameNum;
  else
    seq->cur_pic.PicNum[parity] = 2 * seq->cur_pic.FrameNum + 1;

  while (i < MAX_DPB_SIZE)
  {
    frame = seq->dpb[i];
    if (!frame->used)
      break;
    if (frame->FrameNum > seq->cur_pic.FrameNum)
      frame->FrameNumWrap = frame->FrameNum - sl->MaxFrameNum;
    else
      frame->FrameNumWrap = frame->FrameNum;

    if (!sl->field_pic_flag)
    {
      frame->PicNum[0] = frame->PicNum[1] = frame->FrameNumWrap;
    }
    else
    {
      frame->PicNum[0] = 2 * frame->FrameNumWrap + (parity ? 0 : 1);
      frame->PicNum[1] = 2 * frame->FrameNumWrap + (parity ? 1 : 0);
    }
    ++i;
  }
}



static int
check_ref_list (vdpau_h264_alter_decoder_t * this_gen)
{
  int i, j, bad_frame = 0;
  dpb_frame_t *frame;
  sequence_t *seq = (sequence_t *) & this_gen->sequence;
  slice_param_t *sl = &seq->slice_param;
  pic_param_t *pic = seq->pic_param[sl->pic_parameter_set_id];
  seq_param_t *sp = seq->seq_param[pic->seq_parameter_set_id];
  int prefs = 0;
  int brefs = 0;
  int poc, curpoc;

  //int fps = (double)sp->vui.time_scale / (double)sp->vui.num_units_in_tick / ( 2 - sl->field_pic_flag );
  int fps = (1 + sl->field_pic_flag) * 2 * sp->num_ref_frames;

  if (seq->startup_frame >= fps)
    return 0;

  curpoc =
    (seq->cur_pic.TopFieldOrderCnt >
     seq->cur_pic.BottomFieldOrderCnt) ? seq->cur_pic.TopFieldOrderCnt : seq->
    cur_pic.BottomFieldOrderCnt;

  for (i = 15; i > -1; i--)
  {
    frame = seq->dpb[i];
    if (!frame->used)
      continue;
    poc =
      (frame->TopFieldOrderCnt >
       frame->BottomFieldOrderCnt) ? frame->TopFieldOrderCnt : frame->
      BottomFieldOrderCnt;
    if (seq->cur_pic.field_pic_flag)
    {
      if (!frame->videoSurface->bad_frame)
      {
	for (j = 0; j < 2; j++)
	{
	  if (frame->is_reference[j])
	  {
	    if (poc <= curpoc)
	      ++prefs;
	    else
	      ++brefs;
	  }
	}
      }
    }
    else
    {
      if (!frame->videoSurface->bad_frame)
      {
	if (poc <= curpoc)
	  ++prefs;
	else
	  ++brefs;
      }
    }
  }

  if (sl->slice_type != SLICE_TYPE_I)
  {
    if (prefs < (sl->num_ref_idx_l0_active_minus1 + 1))
      bad_frame = 1;
    if (sl->slice_type == SLICE_TYPE_B)
    {
      if (brefs < (sl->num_ref_idx_l1_active_minus1 + 1))
	bad_frame = 1;
    }
  }

  if (bad_frame)
    fprintf (stderr,
	     "******** Missing refframes, dropping. nrf=%d lo=%d prefs=%d l1=%d brefs=%d type=%d (%d fps)\n",
	     sp->num_ref_frames, sl->num_ref_idx_l0_active_minus1 + 1, prefs,
	     sl->num_ref_idx_l1_active_minus1 + 1, brefs, sl->slice_type,
	     fps);
  //else
  //fprintf(stderr,"******** GOOD ! nrf=%d lo=%d prefs=%d l1=%d brefs=%d type=%d (%d fps)\n", sp->num_ref_frames, sl->num_ref_idx_l0_active_minus1 + 1, prefs, sl->num_ref_idx_l1_active_minus1 + 1, brefs, sl->slice_type, fps );

  if (seq->cur_pic.is_reference[0] || seq->cur_pic.is_reference[1])
    ++seq->startup_frame;

  return bad_frame;
}



static void
decode_render (vdpau_h264_alter_decoder_t * vd, int bad_frame)
{
  int i, j;
  VdpPictureInfoH264 info;
  seq_param_t *sp;
  pic_param_t *pic;
  slice_param_t *sl;
  sequence_t *seq = (sequence_t *) & vd->sequence;
  vo_frame_t *img;

  if (!seq->cur_pic.field_pic_flag || (seq->cur_pic.completed < PICTURE_DONE))
  {
    img =
      vd->stream->video_out->get_frame (vd->stream->video_out,
					seq->coded_width, seq->coded_height,
					seq->ratio, XINE_IMGFMT_VDPAU,
					VO_BOTH_FIELDS | seq->chroma | seq->
					reset | seq->color_matrix);
    seq->reset = 0;
    img->drawn = 0;
  }
  else
    img = seq->cur_pic.videoSurface;

  if (!img)
  {				/* should not happen */
    fprintf (stderr,
	     "vdpau_h264_alter : !!!!!!!!!!!!!!!!!!!!!! No vo_frame_t !!!!!!!!!!!!!!!!!!!!!!!\n");
    return;
  }

  vdpau_accel_t *accel = (vdpau_accel_t *) img->accel_data;
  if (!seq->accel_vdpau)
    seq->accel_vdpau = accel;

  if (seq->vdp_runtime_nr != *(seq->accel_vdpau->current_vdp_runtime_nr))
    vd->decoder = VDP_INVALID_HANDLE;

  sl = &vd->sequence.slice_param;
  pic = vd->sequence.pic_param[sl->pic_parameter_set_id];
  sp = vd->sequence.seq_param[pic->seq_parameter_set_id];

  VdpStatus st;
  if (vd->decoder == VDP_INVALID_HANDLE || vd->decoder_profile != seq->profile
      || vd->decoder_width != seq->coded_width
      || vd->decoder_height != seq->coded_height)
  {
    if (accel->lock)
      accel->lock (accel->vo_frame);
    if (vd->decoder != VDP_INVALID_HANDLE)
    {
      accel->vdp_decoder_destroy (vd->decoder);
      vd->decoder = VDP_INVALID_HANDLE;
    }
    st =
      accel->vdp_decoder_create (accel->vdp_device, seq->profile,
				 seq->coded_width, seq->coded_height,
				 sp->num_ref_frames, &vd->decoder);
    if (accel->unlock)
      accel->unlock (accel->vo_frame);
    if (st != VDP_STATUS_OK)
      fprintf (stderr, "vdpau_h264_alter : failed to create decoder !! %s\n",
	       accel->vdp_get_error_string (st));
    else
    {
      vd->decoder_profile = seq->profile;
      vd->decoder_width = seq->coded_width;
      vd->decoder_height = seq->coded_height;
      seq->vdp_runtime_nr = seq->accel_vdpau->vdp_runtime_nr;
    }
  }

  info.slice_count = seq->slices_count;
  info.field_order_cnt[0] = seq->cur_pic.TopFieldOrderCnt;
  info.field_order_cnt[1] = seq->cur_pic.BottomFieldOrderCnt;
  info.is_reference = sl->nal_ref_idc ? VDP_TRUE : VDP_FALSE;
  info.frame_num = sl->frame_num;
  info.field_pic_flag = sl->field_pic_flag;
  info.bottom_field_flag = sl->bottom_field_flag;
  info.num_ref_frames = sp->num_ref_frames;
  info.mb_adaptive_frame_field_flag = sp->mb_adaptive_frame_field_flag
    && !sl->field_pic_flag;
  info.constrained_intra_pred_flag = pic->constrained_intra_pred_flag;
  info.weighted_pred_flag = pic->weighted_pred_flag;
  info.weighted_bipred_idc = pic->weighted_bipred_idc;
  info.frame_mbs_only_flag = sp->frame_mbs_only_flag;
  info.transform_8x8_mode_flag = pic->transform_8x8_mode_flag;
  info.chroma_qp_index_offset = pic->chroma_qp_index_offset;
  info.second_chroma_qp_index_offset = pic->second_chroma_qp_index_offset;
  info.pic_init_qp_minus26 = pic->pic_init_qp_minus26;
  info.num_ref_idx_l0_active_minus1 = pic->num_ref_idx_l0_active_minus1;
  info.num_ref_idx_l1_active_minus1 = pic->num_ref_idx_l1_active_minus1;
  info.log2_max_frame_num_minus4 = sp->log2_max_frame_num_minus4;
  info.pic_order_cnt_type = sp->pic_order_cnt_type;
  info.log2_max_pic_order_cnt_lsb_minus4 =
    sp->log2_max_pic_order_cnt_lsb_minus4;
  info.delta_pic_order_always_zero_flag =
    sp->delta_pic_order_always_zero_flag;
  info.direct_8x8_inference_flag = sp->direct_8x8_inference_flag;
  info.entropy_coding_mode_flag = pic->entropy_coding_mode_flag;
  info.pic_order_present_flag = pic->pic_order_present_flag;
  info.deblocking_filter_control_present_flag =
    pic->deblocking_filter_control_present_flag;
  info.redundant_pic_cnt_present_flag = pic->redundant_pic_cnt_present_flag;

  if (!pic->pic_scaling_matrix_present_flag)
  {
    xine_fast_memcpy (info.scaling_lists_4x4, sp->scaling_lists_4x4,
		      sizeof (info.scaling_lists_4x4));
    xine_fast_memcpy (info.scaling_lists_8x8, sp->scaling_lists_8x8,
		      sizeof (info.scaling_lists_8x8));
  }
  else
  {
    xine_fast_memcpy (info.scaling_lists_4x4, pic->scaling_lists_4x4,
		      sizeof (info.scaling_lists_4x4));
    xine_fast_memcpy (info.scaling_lists_8x8, pic->scaling_lists_8x8,
		      sizeof (info.scaling_lists_8x8));
  }

  j = 0;
  for (i = (MAX_DPB_SIZE - 1); i > -1; i--)
  {
    if (!seq->dpb[i]->used)
      continue;
    vdpau_accel_t *accel =
      (vdpau_accel_t *) seq->dpb[i]->videoSurface->accel_data;
    info.referenceFrames[j].surface = accel->surface;
    info.referenceFrames[j].is_long_term = 0;
    info.referenceFrames[j].frame_idx = seq->dpb[i]->FrameNum;
    info.referenceFrames[j].top_is_reference =
      seq->dpb[i]->is_reference[0] ? VDP_TRUE : VDP_FALSE;
    info.referenceFrames[j].bottom_is_reference =
      seq->dpb[i]->is_reference[1] ? VDP_TRUE : VDP_FALSE;
    info.referenceFrames[j].field_order_cnt[0] =
      seq->dpb[i]->TopFieldOrderCnt;
    info.referenceFrames[j].field_order_cnt[1] =
      seq->dpb[i]->BottomFieldOrderCnt;
    ++j;
  }
  for (; j < MAX_DPB_SIZE; j++)
  {
    info.referenceFrames[j].surface = VDP_INVALID_HANDLE;
    info.referenceFrames[j].is_long_term = 0;
    info.referenceFrames[j].frame_idx = 0;
    info.referenceFrames[j].top_is_reference = 0;
    info.referenceFrames[j].bottom_is_reference = 0;
    info.referenceFrames[j].field_order_cnt[0] = 0;
    info.referenceFrames[j].field_order_cnt[1] = 0;
  }

  uint8_t sc[3] = { 0, 0, 1 };
  VdpBitstreamBuffer vbits[seq->slices_count * 2];
  for (i = 0; i < seq->slices_count; i++)
  {
    vbits[i * 2].struct_version = VDP_BITSTREAM_BUFFER_VERSION;
    vbits[i * 2].bitstream = sc;
    vbits[i * 2].bitstream_bytes = 3;
    vbits[(i * 2) + 1].struct_version = VDP_BITSTREAM_BUFFER_VERSION;
    vbits[(i * 2) + 1].bitstream = seq->buf + seq->slices[i].buf_offset;
    vbits[(i * 2) + 1].bitstream_bytes = seq->slices[i].len;
  }
  if (accel->lock)
    accel->lock (accel->vo_frame);
  st =
    accel->vdp_decoder_render (vd->decoder, accel->surface,
			       CAST_VdpPictureInfo_PTR &info,
			       seq->slices_count * 2, vbits);
  if (accel->unlock)
    accel->unlock (accel->vo_frame);
  if (st != VDP_STATUS_OK)
    lprintf ("**********************DECODING failed! - surface = %d - %s\n",
	     accel->surface, accel->vdp_get_error_string (st));
  else
    lprintf ("**********************DECODING success! - surface = %d\n",
	     accel->surface);

  if ((seq->ratio != seq->reported_ratio)
      || (seq->coded_width != seq->reported_coded_width)
      || (seq->coded_height != seq->reported_coded_height)
      || (seq->video_step != seq->reported_video_step))
  {
    seq->reported_ratio = seq->ratio;
    seq->reported_coded_width = seq->coded_width;
    seq->reported_coded_height = seq->coded_height;
    seq->reported_video_step = seq->video_step;
    _x_stream_info_set (vd->stream, XINE_STREAM_INFO_VIDEO_WIDTH,
			seq->coded_width);
    _x_stream_info_set (vd->stream, XINE_STREAM_INFO_VIDEO_HEIGHT,
			seq->coded_height);
    _x_stream_info_set (vd->stream, XINE_STREAM_INFO_VIDEO_RATIO,
			((double) 10000 * seq->ratio));
    _x_stream_info_set (vd->stream, XINE_STREAM_INFO_FRAME_DURATION,
			seq->video_step);
    _x_meta_info_set_utf8 (vd->stream, XINE_META_INFO_VIDEOCODEC,
			   "H264/AVC (vdpau_alter)");
    xine_event_t event;
    xine_format_change_data_t data;
    event.type = XINE_EVENT_FRAME_FORMAT_CHANGE;
    event.stream = vd->stream;
    event.data = &data;
    event.data_length = sizeof (data);
    data.width = seq->coded_width;
    data.height = seq->coded_height;
    data.aspect = seq->ratio;
    xine_event_send (vd->stream, &event);
  }

  if (seq->cur_pic.completed == PICTURE_DONE)
  {
    seq->cur_pic.pts = seq->pic_pts;
    seq->pic_pts = 0;
  }
  if (seq->cur_pic.drop_pts)
    seq->cur_pic.pts = 0;
  if (sp->frame_mbs_only_flag)
    img->progressive_frame = -1;
  img->bad_frame = bad_frame;
  img->duration = seq->video_step;
  seq->cur_pic.videoSurface = img;
}



static void
decode_picture (vdpau_h264_alter_decoder_t * decoder)
{
  if (decoder->sequence.cur_pic.missing_header
      || !decoder->sequence.startup_frame)
  {
    memset (&decoder->sequence.cur_pic, 0, sizeof (dpb_frame_t));
    lprintf ("MISSING_HEADER or !startup_frame\n\n");
    return;
  }

  slice_param_t *sl = &decoder->sequence.slice_param;
  dpb_frame_t *cur_pic = &decoder->sequence.cur_pic;

  if (cur_pic->completed && cur_pic->field_pic_flag)
  {
    int wrong_field = 0;
    if ((sl->frame_num != cur_pic->FrameNum)
	|| (sl->bottom_field_flag
	    && (cur_pic->completed == PICTURE_BOTTOM_DONE))
	|| (!sl->bottom_field_flag
	    && (cur_pic->completed == PICTURE_TOP_DONE))
	|| !sl->field_pic_flag)
    {
      wrong_field = 1;
    }
    if (wrong_field)
    {
      fprintf (stderr, "vdpau_h264_alter : Wrong field, skipping.\n");
      memset (cur_pic, 0, sizeof (dpb_frame_t));
      dpb_reset (&decoder->sequence);
      cur_pic->missing_header = 1;
      decoder->sequence.startup_frame = 0;
      return;
    }
  }

  /* picture decoding */
  decode_poc (decoder);
  lprintf ("TopFieldOrderCnt = %d - BottomFieldOrderCnt = %d\n",
	   cur_pic->TopFieldOrderCnt, cur_pic->BottomFieldOrderCnt);
  if (sl->nal_unit_type == 5)
  {
    dpb_draw_frames (decoder, MAX_POC, DPB_DRAW_CLEAR);
    decoder->sequence.startup_frame = START_IDR_FLAG;
  }
  decode_picnum (decoder);
  ref_pic_list_reordering (decoder);
  lprintf ("............................. slices_count = %d\n",
	   decoder->sequence.slices_count);

  decode_render (decoder, check_ref_list (decoder));

  /* dec_ref_pic_marking */
  slice_header_post (decoder);

  if (!cur_pic->is_reference[0] && !cur_pic->is_reference[1])
  {
    if (cur_pic->completed == PICTURE_DONE)
    {
      dpb_draw_frames (decoder,
		       (cur_pic->TopFieldOrderCnt >
			cur_pic->BottomFieldOrderCnt) ? cur_pic->
		       TopFieldOrderCnt : cur_pic->BottomFieldOrderCnt,
		       DPB_DRAW_CURRENT);
    }
  }
  else
  {
    if (decoder->sequence.
	seq_param[decoder->sequence.pic_param[sl->pic_parameter_set_id]->
		  seq_parameter_set_id]->pic_order_cnt_type == 2)
      dpb_draw_frames (decoder,
		       (cur_pic->TopFieldOrderCnt >
			cur_pic->BottomFieldOrderCnt) ? cur_pic->
		       TopFieldOrderCnt : cur_pic->BottomFieldOrderCnt,
		       DPB_DRAW_REFS);

    if (!sl->field_pic_flag || cur_pic->completed < PICTURE_DONE)
      dbp_append (decoder, 0);
    else
      dbp_append (decoder, 1);
  }

  if (cur_pic->completed == PICTURE_DONE)
    memset (cur_pic, 0, sizeof (dpb_frame_t));


  lprintf
    ("\n___________________________________________________________________________________________\n\n");
}



static int
parse_startcodes (vdpau_h264_alter_decoder_t * this_gen, uint8_t * buf,
		  uint32_t len)
{
  sequence_t *sequence = (sequence_t *) & this_gen->sequence;
  bits_reader_set (&sequence->br, buf, len);
  int ret = 0;

  skip_bits (&sequence->br, 1);	/* forbidden_zero_bit */
  uint8_t nal_ref_idc = read_bits (&sequence->br, 2);
  uint8_t nal_unit_type = read_bits (&sequence->br, 5);
  lprintf ("NAL size = %d, nal_ref_idc = %d, nal_unit_type = %d\n", len,
	   nal_ref_idc, nal_unit_type);

  switch (nal_unit_type)
  {
  case NAL_END_SEQUENCE:
    break;
  case NAL_SEQUENCE:
    seq_parameter_set_data (this_gen);
    break;
  case NAL_PICTURE:
    pic_parameter_set (this_gen);
    break;
  case NAL_SLICE_IDR:
    slice_header (this_gen, nal_ref_idc, nal_unit_type);
    sequence->slices[sequence->slices_count].buf_offset = buf - sequence->buf;
    sequence->slices[sequence->slices_count].len = len;
    ++sequence->slices_count;
    sequence->slice_mode = NAL_SLICE_IDR;
    break;
  case NAL_SLICE_NO_IDR:
    slice_header (this_gen, nal_ref_idc, nal_unit_type);
    sequence->slices[sequence->slices_count].buf_offset = buf - sequence->buf;
    sequence->slices[sequence->slices_count].len = len;
    ++sequence->slices_count;
    sequence->slice_mode = NAL_SLICE_NO_IDR;
    break;
  }

  return ret;
}



static void
parse_codec_private (vdpau_h264_alter_decoder_t * this_gen, const uint8_t * buf,
		     uint32_t len)
{
  sequence_t *sequence = (sequence_t *) & this_gen->sequence;
  bits_reader_set (&sequence->br, buf, len);
  const uint8_t *buffer = buf;
  int i;

  lprintf ("parse_codec_private\n");

  sequence->mode_frame = 1;

  // reserved 
  skip_bits (&sequence->br, 8);
  skip_bits (&sequence->br, 8);	/* profile_idc */
  skip_bits (&sequence->br, 8);
  skip_bits (&sequence->br, 8);	/* level_idc */
  skip_bits (&sequence->br, 6);

  sequence->frame_header_size = read_bits (&sequence->br, 2) + 1;
  //sequence->frame_header_size = 3;
  skip_bits (&sequence->br, 3);
  uint8_t count = read_bits (&sequence->br, 5);
  buffer += 6;
  for (i = 0; i < count; i++)
  {
    bits_reader_set (&sequence->br, buffer, len - (buffer - buf));
    uint16_t sps_size = read_bits (&sequence->br, 16);
    skip_bits (&sequence->br, 8);
    seq_parameter_set_data (this_gen);
    buffer += sps_size + 2;
  }
  count = buffer[0];
  ++buffer;
  for (i = 0; i < count; i++)
  {
    bits_reader_set (&sequence->br, buffer, len - (buffer - buf));
    uint16_t pps_size = read_bits (&sequence->br, 16);
    skip_bits (&sequence->br, 8);
    pic_parameter_set (this_gen);
    buffer += pps_size + 2;
  }
}



static void
flush_buffer (sequence_t * seq)
{
  if (((int)seq->bufpos - seq->bufseek) >= seq->bufseek)
  {
    seq->bufsize = (seq->bufpos - seq->bufseek) + MIN_BUFFER_SIZE;
    lprintf ("buffer too short, have to allocate a new one.\n");
    uint8_t *tmp = (uint8_t *) malloc (seq->bufsize);
    xine_fast_memcpy (tmp, seq->buf + seq->bufseek,
		      seq->bufpos - seq->bufseek);
    free (seq->buf);
    seq->buf = tmp;
  }
  else
    xine_fast_memcpy (seq->buf, seq->buf + seq->bufseek,
		      seq->bufpos - seq->bufseek);

  seq->bufpos -= seq->bufseek;
  seq->start = -1;
  seq->bufseek = 0;
  reset_slices (seq);
}



/*
 * This function receives a buffer of data from the demuxer layer and
 * figures out how to handle it based on its header flags.
 */
static void
vdpau_h264_alter_decode_data (video_decoder_t * this_gen, buf_element_t * buf)
{
  vdpau_h264_alter_decoder_t *this = (vdpau_h264_alter_decoder_t *) this_gen;
  sequence_t *seq = (sequence_t *) & this->sequence;

#ifdef MAKE_DAT
  fwrite (buf->content, 1, buf->size, outfile);
#endif

  if (buf->decoder_flags & BUF_FLAG_FRAMERATE)
  {
    lprintf ("BUF_FLAG_FRAMERATE\n");
    seq->video_step = buf->decoder_info[0];
  }

  if (buf->decoder_flags & BUF_FLAG_ASPECT)
  {
    lprintf ("BUF_FLAG_ASPECT\n");
    seq->ratio =
      (double) buf->decoder_info[1] / (double) buf->decoder_info[2];
  }

  if (buf->decoder_flags & BUF_FLAG_STDHEADER)
  {
    lprintf ("BUF_FLAG_STDHEADER\n");
    seq->flag_header = 1;
    xine_bmiheader *bih = (xine_bmiheader *) buf->content;
    seq->coded_width = bih->biWidth;
    seq->coded_height = bih->biHeight;
    uint8_t *codec_private = buf->content + sizeof (xine_bmiheader);
    uint32_t codec_private_len = bih->biSize - sizeof (xine_bmiheader);
    if (codec_private_len > 0)
      parse_codec_private (this, codec_private, codec_private_len);
    return;
  }

  if (buf->decoder_flags & BUF_FLAG_SPECIAL)
  {
    if (buf->decoder_info[1] == BUF_SPECIAL_DECODER_CONFIG)
    {
      lprintf ("BUF_SPECIAL_DECODER_CONFIG\n");
      seq->flag_header = 1;
      const uint8_t *codec_private = buf->decoder_info_ptr[2];
      uint32_t codec_private_len = buf->decoder_info[2];
      if (codec_private_len > 0)
	parse_codec_private (this, codec_private, codec_private_len);
    }
    return;
  }

  if (!buf->size)
    return;

  int size = seq->bufpos + buf->size;
  if ((int)seq->bufsize < size)
  {
    if (seq->bufsize > MAX_BUFFER_SIZE)
    {
      fprintf (stderr,
	       "vdpau_h264_alter : sorry, can't accumulate so much data, broken stream?\n");
      reset_sequence (seq);
      return;
    }
    seq->bufsize = size + MIN_BUFFER_SIZE;
    seq->buf = (uint8_t *) realloc (seq->buf, seq->bufsize);
    lprintf ("realloc new size = %d\n", seq->bufsize);
  }
  xine_fast_memcpy (seq->buf + seq->bufpos, buf->content, buf->size);
  seq->bufpos += buf->size;

  if (buf->decoder_flags & BUF_FLAG_FRAME_START)
    seq->pic_pts = buf->pts;

  int frame_end = buf->decoder_flags & BUF_FLAG_FRAME_END;

  if (seq->mode_frame)
  {
    if (!seq->pic_pts)
      seq->pic_pts = buf->pts;
    if (frame_end)
    {
      if (buf->pts)
	seq->pic_pts = buf->pts;
      lprintf ("frame_end && seq->mode_frame\n");
      uint32_t fhs;
      uint8_t tb;
      uint32_t j = 0;
      while (j < seq->bufpos)
      {
	uint32_t s = 0;
	for (fhs = 0; fhs < seq->frame_header_size; fhs++)
	  s |= seq->buf[j + fhs] << (8 * (seq->frame_header_size - 1 - fhs));
	tb = *(seq->buf + j + seq->frame_header_size) & 0x1F;
	if (seq->slice_mode && (tb != seq->slice_mode))
	{
	  decode_picture (this);
	  reset_slices (seq);
	}
	parse_startcodes (this, seq->buf + j + seq->frame_header_size, s);
	j += seq->frame_header_size + s;
      }
      if (seq->slice_mode)
      {
	decode_picture (this);
	reset_slices (seq);
      }
      seq->bufpos = 0;
    }
    return;
  }

  while (seq->bufseek <= (int)seq->bufpos - 4)
  {
    uint8_t *buffer = seq->buf + seq->bufseek;
    if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 1)
    {
      if (seq->start < 0)
      {
	seq->start = seq->bufseek;
	uint8_t tb = buffer[3] & 0x1F;
	if (((tb == NAL_SLICE_NO_IDR) || (tb == NAL_SLICE_IDR))
	    && !seq->pic_pts)
	  seq->pic_pts = buf->pts;
	if (seq->slice_mode && (tb != seq->slice_mode))
	{
	  decode_picture (this);
	  flush_buffer (seq);
	}
	if ((tb & 0x1F) == NAL_END_SEQUENCE)
	{
	  dpb_print (seq);
	  dpb_draw_frames (this, MAX_POC, DPB_DRAW_CLEAR);
	  lprintf ("NAL_END_SEQUENCE\n");
	  dpb_print (seq);
	}
      }
      else
      {
	parse_startcodes (this, seq->buf + seq->start + 3,
			  seq->bufseek - seq->start - 3);
	seq->start = -1;
	--seq->bufseek;
      }
    }
    ++seq->bufseek;
  }

  if (frame_end && seq->flag_header && (seq->start > -1)
      && (seq->bufseek > seq->start))
  {
    lprintf ("frame_end && seq->start\n");
    seq->bufseek = seq->bufpos;
    parse_startcodes (this, seq->buf + seq->start + 3,
		      seq->bufseek - seq->start - 3);
    if (seq->slice_mode)
      decode_picture (this);
    flush_buffer (seq);
  }
}


/*
 * This function is called when xine needs to flush the system.
 */
static void
vdpau_h264_alter_flush (video_decoder_t * this_gen)
{
  vdpau_h264_alter_decoder_t *this = (vdpau_h264_alter_decoder_t *) this_gen;

  lprintf ("vdpau_h264_alter_flush\n");
  dpb_draw_frames (this, MAX_POC, DPB_DRAW_REFS);
}


/*
 * This function resets the video decoder.
 */
static void
vdpau_h264_alter_reset (video_decoder_t * this_gen)
{
  vdpau_h264_alter_decoder_t *this = (vdpau_h264_alter_decoder_t *) this_gen;

  lprintf ("vdpau_h264_alter_reset\n");
  reset_sequence (&this->sequence);
}


/*
 * The decoder should forget any stored pts values here.
 */
static void
vdpau_h264_alter_discontinuity (video_decoder_t * this_gen)
{
  vdpau_h264_alter_decoder_t *this = (vdpau_h264_alter_decoder_t *) this_gen;
  lprintf ("vdpau_h264_alter_discontinuity\n");

  dpb_clear_all_pts (&this->sequence);
  this->sequence.reset = VO_NEW_SEQUENCE_FLAG;
}


/*
 * This function frees the video decoder instance allocated to the decoder.
 */
static void
vdpau_h264_alter_dispose (video_decoder_t * this_gen)
{

  vdpau_h264_alter_decoder_t *this = (vdpau_h264_alter_decoder_t *) this_gen;

  lprintf ("vdpau_h264_alter_dispose\n");

  if ((this->decoder != VDP_INVALID_HANDLE) && this->sequence.accel_vdpau)
  {
    if (this->sequence.accel_vdpau->lock)
      this->sequence.accel_vdpau->lock (this->sequence.accel_vdpau->vo_frame);
    this->sequence.accel_vdpau->vdp_decoder_destroy (this->decoder);
    this->decoder = VDP_INVALID_HANDLE;
    if (this->sequence.accel_vdpau->unlock)
      this->sequence.accel_vdpau->unlock (this->sequence.accel_vdpau->vo_frame);
  }
  reset_sequence (&this->sequence);

  int i;
  for (i = 0; i < MAX_DPB_SIZE; i++)
    free (this->sequence.dpb[i]);
  for (i = 0; i < 32; i++)
    if (this->sequence.seq_param[i])
      free (this->sequence.seq_param[i]);
  for (i = 0; i < 255; i++)
    if (this->sequence.pic_param[i])
      free (this->sequence.pic_param[i]);

  this->stream->video_out->close (this->stream->video_out, this->stream);

  free (this->sequence.buf);
  free (this_gen);
}


/*
 * This function allocates, initializes, and returns a private video
 * decoder structure.
 */
static video_decoder_t *
open_plugin (video_decoder_class_t * class_gen, xine_stream_t * stream)
{

  vdpau_h264_alter_decoder_t *this;

  (void)class_gen;

  /* the videoout must be vdpau-capable to support this decoder */
  if (!
      (stream->video_out->
       get_capabilities (stream->video_out) & VO_CAP_VDPAU_H264))
    return NULL;

  /* now check if vdpau has free decoder resource */
  vo_frame_t *img =
    stream->video_out->get_frame (stream->video_out, 1920, 1080, 1, XINE_IMGFMT_VDPAU,
                                  VO_BOTH_FIELDS | VO_GET_FRAME_MAY_FAIL);
  if (!img) {
    return NULL;
  }
  vdpau_accel_t *accel = (vdpau_accel_t *) img->accel_data;
  int runtime_nr = accel->vdp_runtime_nr;
  img->free (img);
  VdpDecoder decoder;
  VdpStatus st;
  if (accel->lock)
    accel->lock (accel->vo_frame);
  st =accel->vdp_decoder_create (accel->vdp_device,
			       VDP_DECODER_PROFILE_H264_MAIN, 1920, 1080, 16,
			       &decoder);
  if (accel->unlock)
    accel->unlock (accel->vo_frame);
  if (st != VDP_STATUS_OK)
  {
    fprintf (stderr, "can't create vdpau decoder!\n");
    return NULL;
  }

  if (accel->lock)
    accel->lock (accel->vo_frame);
  accel->vdp_decoder_destroy (decoder);
  if (accel->unlock)
    accel->unlock (accel->vo_frame);

  this =
    (vdpau_h264_alter_decoder_t *) calloc (1,
					   sizeof
					   (vdpau_h264_alter_decoder_t));

  this->video_decoder.decode_data = vdpau_h264_alter_decode_data;
  this->video_decoder.flush = vdpau_h264_alter_flush;
  this->video_decoder.reset = vdpau_h264_alter_reset;
  this->video_decoder.discontinuity = vdpau_h264_alter_discontinuity;
  this->video_decoder.dispose = vdpau_h264_alter_dispose;

  this->stream = stream;

  int i;
  for (i = 0; i < 16; i++)
    this->sequence.dpb[i] = (dpb_frame_t *) calloc (1, sizeof (dpb_frame_t));
  this->sequence.bufsize = MIN_BUFFER_SIZE;
  this->sequence.buf = (uint8_t *) malloc (this->sequence.bufsize);
  this->sequence.vdp_runtime_nr = runtime_nr;
  this->sequence.reset = VO_NEW_SEQUENCE_FLAG;
  this->sequence.reset = VO_NEW_SEQUENCE_FLAG;
  this->sequence.ratio = 0.0;
  this->sequence.video_step = 3600;
  this->sequence.coded_width = 1280;
  this->sequence.coded_height = 720;
  this->sequence.reported_ratio = 0.0;
  this->sequence.reported_video_step = 0;
  this->sequence.reported_coded_width = 0;
  this->sequence.reported_coded_height = 0;
  this->sequence.frame_header_size = 4;
  this->sequence.flag_header = 0;
  this->sequence.mode_frame = 0;
  reset_sequence (&this->sequence);

  this->decoder = VDP_INVALID_HANDLE;
  this->sequence.accel_vdpau = NULL;

  (stream->video_out->open) (stream->video_out, stream);

#ifdef MAKE_DAT
  outfile = fopen ("/tmp/h264.dat", "w");
  nframes = 0;
#endif

  return &this->video_decoder;
}


/*
 * This function allocates a private video decoder class and initializes
 * the class's member functions.
 */
void *
h264_alter_init_plugin (xine_t * xine, const void *data)
{
  (void)xine;
  (void)data;

  static const video_decoder_class_t decode_video_vdpau_h264_alter_class = {
    .open_plugin = open_plugin,
    .identifier  = "vdpau_h264_alter",
    .description =
      N_
      ("vdpau_h264_alter: H264 decoder plugin using VDPAU hardware decoding.\n"
       "Must be used along with video_out_vdpau."),
    .dispose = NULL,
  };

  return (void *)&decode_video_vdpau_h264_alter_class;
}

