text: /* Any workload management goes in this file */
  
  #include "viddec_fw_debug.h"
  #include "vc1.h"
  #include "vc1parse.h"
  #include "viddec_fw_workload.h"
  #include <auto_eas/gen4_mfd.h>
  #include "viddec_pm_utils_bstream.h"
  
  /* this function returns workload frame types corresponding to VC1 PTYPES (frame types)
   * VC1 frame types: can be found in vc1parse_common_defs.h
   * workload frame types are in viddec_workload.h
  */
  static inline uint32_t vc1_populate_frame_type(uint32_t vc1_frame_type)
  {
      uint32_t viddec_frame_type;
  
        switch(vc1_frame_type)
        {
          case VC1_I_FRAME: 
              viddec_frame_type = VIDDEC_FRAME_TYPE_I; 
              break;
          case VC1_P_FRAME: 
              viddec_frame_type = VIDDEC_FRAME_TYPE_P; 
              break;
          case VC1_B_FRAME: 
              viddec_frame_type = VIDDEC_FRAME_TYPE_B; 
              break;
          case VC1_BI_FRAME:  
              viddec_frame_type = VIDDEC_FRAME_TYPE_BI; 
              break;
          case VC1_SKIPPED_FRAME :  
              viddec_frame_type =  VIDDEC_FRAME_TYPE_SKIP; 
              break;
          default: 
              viddec_frame_type = VIDDEC_FRAME_TYPE_INVALID; 
              break;
        } // switch on vc1 frame type
  
     return(viddec_frame_type);
  } // vc1_populate_frame_type
  
  static void translate_parser_info_to_frame_attributes(void *parent, vc1_viddec_parser_t *parser)
  {
      viddec_workload_t        *wl = viddec_pm_get_header( parent );
      viddec_frame_attributes_t *attrs = &wl->attrs;
      vc1_Info        *info = &parser->info;
      unsigned i;
  
      /* typical sequence layer and entry_point data */
      attrs->cont_size.height       = info->metadata.height * 2 + 2;
      attrs->cont_size.width        = info->metadata.width  * 2 + 2;
      
      /* frame type */
      /* we can have two fileds with different types for field interlace coding mode */
      if (info->picLayerHeader.FCM == VC1_FCM_FIELD_INTERLACE) {
        attrs->frame_type = vc1_populate_frame_type(info->picLayerHeader.PTypeField1);
        attrs->bottom_field_type = vc1_populate_frame_type(info->picLayerHeader.PTypeField2);
      } else {
        attrs->frame_type = vc1_populate_frame_type(info->picLayerHeader.PTYPE);
        attrs->bottom_field_type = VIDDEC_FRAME_TYPE_INVALID; //unknown
      }
  
      /* frame counter */
      attrs->vc1.tfcntr = info->picLayerHeader.TFCNTR;
  
      /* TFF, repeat frame, field */
      attrs->vc1.tff = info->picLayerHeader.TFF;
      attrs->vc1.rptfrm = info->picLayerHeader.RPTFRM;
      attrs->vc1.rff = info->picLayerHeader.RFF;
  
      /* PAN Scan */
      attrs->vc1.ps_present = info->picLayerHeader.PS_PRESENT;
      attrs->vc1.num_of_pan_scan_windows = info->picLayerHeader.number_of_pan_scan_window;
      for (i=0;i<attrs->vc1.num_of_pan_scan_windows;i++) {
        attrs->vc1.pan_scan_window[i].hoffset =  info->picLayerHeader.PAN_SCAN_WINDOW[i].hoffset;
        attrs->vc1.pan_scan_window[i].voffset =  info->picLayerHeader.PAN_SCAN_WINDOW[i].voffset;
        attrs->vc1.pan_scan_window[i].width =  info->picLayerHeader.PAN_SCAN_WINDOW[i].width;
        attrs->vc1.pan_scan_window[i].height =  info->picLayerHeader.PAN_SCAN_WINDOW[i].height;
      } //end for i
  
      return;
  } // translate_parser_info_to_frame_attributes
  
  void vc1_intcomp(vc1_viddec_parser_t *parser, vc1_Info *pInfo, VC1D_SPR_REGS *spr) 
  {
      vc1_metadata_t *md = &pInfo->metadata;
      vc1_PictureLayerHeader *pic = &pInfo->picLayerHeader;
      uint32_t intcomp1 = 1;
      uint32_t intcomp2 = 0;
  
      // Get the intensity compensation from the bitstream
      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, LUMA_SCALE_1, intcomp1, pic->LUMSCALE);
      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, LUMA_SHIFT_1, intcomp1, pic->LUMSHIFT);
  
      if(md->INTCOMPFIELD == VC1_INTCOMP_BOTH_FIELD) 
      {
          intcomp2 = 1;
          BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, LUMA_SCALE_1, intcomp2, md->LUMSCALE2);
          BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, LUMA_SHIFT_1, intcomp2, md->LUMSHIFT2);
      }
  
      switch(md->INTCOMPFIELD)
      {
          case VC1_INTCOMP_TOP_FIELD:
              if(pic->CurrField == 0) // First field decoded
              {
                  if(pic->TFF)
                  {
                      //parser->intcomp_bot[0] = intcomp1 << 13;
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_2, spr->intcomp_fwd_top, intcomp1);
                  }
                  else
                  {
                      parser->intcomp_top[0] = intcomp1;
                      parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].intcomp_top = intcomp1;
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_1, spr->intcomp_fwd_top, intcomp1);
                  }
              }
              else // Second field
              {
                  if(pic->TFF)
                  {
                      parser->intcomp_top[0] = intcomp1;
                      parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].intcomp_top = intcomp1;
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_1, spr->intcomp_bwd_top, intcomp1);
                  }
                  else
                  {
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_2, spr->intcomp_fwd_top, intcomp1);
                  }
              }
              break;
          case VC1_INTCOMP_BOTTOM_FIELD:
              if(pic->CurrField == 0) // First field decoded
              {
                  if(pic->TFF)
                  {
                      parser->intcomp_bot[0] = intcomp1;
                      parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].intcomp_bot = intcomp1;
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_1, spr->intcomp_fwd_bot, intcomp1);
                  }
                  else
                  {
                      parser->intcomp_bot[0] = intcomp1 << 13;
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_2, spr->intcomp_fwd_bot, intcomp1);
                  }
              }
              else // Second field
              {
                  if(pic->TFF)
                  {
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_2, spr->intcomp_fwd_bot, intcomp1);
                  }
                  else
                  {
                      parser->intcomp_bot[0] = intcomp1;
                      parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].intcomp_bot = intcomp1;
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_1, spr->intcomp_bwd_bot, intcomp1);
                  }
              }
              break;
          case VC1_INTCOMP_BOTH_FIELD:
              if(pic->CurrField == 0) // First field decoded
              {
                  if(pic->TFF)
                  {
                      parser->intcomp_bot[0] = intcomp2;
                      parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].intcomp_bot = intcomp2;
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_2, spr->intcomp_fwd_top, intcomp1);
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_1, spr->intcomp_fwd_bot, intcomp2);
                  }
                  else
                  {
                      parser->intcomp_top[0] = intcomp2;
                      parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].intcomp_top = intcomp2;
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_2, spr->intcomp_fwd_bot, intcomp1);
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_1, spr->intcomp_fwd_top, intcomp2);
                  }
              }
              else // Second field
              {
                  if(pic->TFF)
                  {
                      parser->intcomp_top[0] = intcomp1;
                      parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].intcomp_top = intcomp1;
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_1, spr->intcomp_bwd_top, intcomp1);
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_2, spr->intcomp_fwd_bot, intcomp2);
                  }
                  else
                  {
                      parser->intcomp_bot[0] = intcomp1;
                      parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].intcomp_bot = intcomp1;
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_1, spr->intcomp_bwd_bot, intcomp1);
                      BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_2, spr->intcomp_fwd_top, intcomp2);
                  }
              }
              break;
          default:
              break;
      } // switch on INTCOMPFIELD
  
      return;
  } // vc1_intcomp
  
  static void handle_intensity_compensation(vc1_viddec_parser_t *parser, vc1_Info *pInfo, VC1D_SPR_REGS *spr)
  {
      vc1_PictureLayerHeader *pic = &pInfo->picLayerHeader;
      uint8_t intcomp_present = false;
  
      if((pic->MVMODE == VC1_MVMODE_INTENSCOMP) || (pic->INTCOMP))
      {
          intcomp_present = true;
          if(pic->FCM == VC1_FCM_FIELD_INTERLACE)  
          {
              vc1_intcomp(parser, pInfo, spr);
          } 
          else 
          {
              BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_1, spr->intcomp_fwd_top, 1);
              BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, LUMA_SCALE_1, spr->intcomp_fwd_top, pic->LUMSCALE);
              BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, LUMA_SHIFT_1, spr->intcomp_fwd_top, pic->LUMSHIFT);
  
              if(parser->ref_frame[VC1_REF_FRAME_T_MINUS_1].fcm == VC1_FCM_FIELD_INTERLACE)
              {
                 BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, INT_COMP_2, spr->intcomp_fwd_bot, 1);
                 BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, LUMA_SCALE_2, spr->intcomp_fwd_bot, pic->LUMSCALE);
                 BF_WRITE(VC1_0_SEQPIC_INTENSITY_COMPENSATION, LUMA_SHIFT_2, spr->intcomp_fwd_bot, pic->LUMSHIFT);
              }
  
              parser->intcomp_top[0] = spr->intcomp_fwd_top;
              parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].intcomp_top = spr->intcomp_fwd_top;
              parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].intcomp_bot = spr->intcomp_fwd_top;
          }
      }
  
      // Propagate the previous picture's intensity compensation
      if(pic->FCM == VC1_FCM_FIELD_INTERLACE)
      {
          if( (pic->CurrField) || 
              ((pic->CurrField == 0) && (parser->ref_frame[VC1_REF_FRAME_T_MINUS_1].fcm == VC1_FCM_FIELD_INTERLACE)))
          { 
              spr->intcomp_fwd_top |= parser->intcomp_top[1];
              spr->intcomp_fwd_bot |= parser->intcomp_bot[1];
          }
      }
      if(pic->FCM == VC1_FCM_FRAME_INTERLACE)
      {
          if( (pic->CurrField) || 
              ((pic->CurrField == 0) && (parser->ref_frame[VC1_REF_FRAME_T_MINUS_1].fcm == VC1_FCM_FIELD_INTERLACE)))
          {
              spr->intcomp_fwd_bot |= parser->intcomp_bot[1];
          }
      }
  
      switch(pic->PTYPE)
      {
          case VC1_B_FRAME:
              spr->intcomp_fwd_top = parser->intcomp_last[0];
              spr->intcomp_fwd_bot = parser->intcomp_last[1];
              spr->intcomp_bwd_top = parser->intcomp_last[2];
              spr->intcomp_bwd_bot = parser->intcomp_last[3];
              break;
          case VC1_P_FRAME:
              // If first field, store the intcomp values to propagate.
              // If second field has valid intcomp values, store them
              // to propagate.
              if(pic->CurrField == 0) // first field
              {
                  parser->intcomp_last[0] = spr->intcomp_fwd_top;
                  parser->intcomp_last[1] = spr->intcomp_fwd_bot;
                  parser->intcomp_last[2] = spr->intcomp_bwd_top;
                  parser->intcomp_last[3] = spr->intcomp_bwd_bot;
              }
              else // Second field
              {
                      parser->intcomp_last[0] |= spr->intcomp_fwd_top;
                      parser->intcomp_last[1] |= spr->intcomp_fwd_bot;
                      parser->intcomp_last[2] |= spr->intcomp_bwd_top;
                      parser->intcomp_last[3] |= spr->intcomp_bwd_bot;
              }
              break;
          case VC1_I_FRAME:
          case VC1_BI_FRAME:
              break;
          default:
              break;
      }
  
      return; 
  } // handle_intensity_compensation
  
  /**
   * This function populates the registers for range reduction (main profile) 
   * This function assumes pInfo->metadata.RANGERED is ON at the sequence layer (J.1.17)
   * A frame is marked as range reduced by the RANGEREDFRM flag at the picture layer,  
   * and the output of the decoded range reduced frame needs to be scaled up (8.1.1.4).
   * Previous reference frame needs be upscaled or downscaled based on the RR status of
   * current and previous frame (8.3.4.11)
   */
  static inline void vc1_fill_RR_hw_struct(vc1_viddec_parser_t *parser, vc1_Info *pInfo, VC1D_SPR_REGS *spr)
  {
      vc1_PictureLayerHeader *pic = &pInfo->picLayerHeader;
      int is_previous_ref_rr=0;
     
      /* range reduction applies to luma and chroma component 
      which are the same register bit as RANGE_MAPY_FLAG, RANGE_MAPUV_FLAG */
      BF_WRITE(VC1_0_SEQPIC_RANGE_MAP, RANGE_MAP_Y_FLAG, spr->range_map, pic->RANGEREDFRM);
      BF_WRITE(VC1_0_SEQPIC_RANGE_MAP, RANGE_MAP_UV_FLAG, spr->range_map, pic->RANGEREDFRM); 
      
      /* Get the range reduced status of the previous frame */
      switch (pic->PTYPE) 
      {
          case VC1_P_FRAME:
          {
              is_previous_ref_rr = parser->ref_frame[VC1_REF_FRAME_T_MINUS_1].rr_frm;
              break;
          }
          case VC1_B_FRAME:
          {
              is_previous_ref_rr = parser->ref_frame[VC1_REF_FRAME_T_MINUS_2].rr_frm;
              break;
          }
          default:
          {
              break;
          }
      }
  
      /* if current frame is RR and previous frame is not 
          donwscale the reference pixel ( RANGE_REF_RED_TYPE =1 in register) */
      if(pic->RANGEREDFRM) 
      {
          if(!is_previous_ref_rr) 
          {
              BF_WRITE(VC1_0_SEQPIC_RECON_CONTROL, RANGE_REF_RED_EN, spr->recon_control, 1);
              BF_WRITE(VC1_0_SEQPIC_RECON_CONTROL, RANGE_REF_RED_TYPE, spr->recon_control, 1);
          }
      } 
      else 
      {  
          /* if current frame is not RR but previous was RR,  scale up the reference frame ( RANGE_REF_RED_TYPE = 0) */
          if(is_previous_ref_rr) 
          {
              BF_WRITE(VC1_0_SEQPIC_RECON_CONTROL, RANGE_REF_RED_EN, spr->recon_control, 1);
              BF_WRITE(VC1_0_SEQPIC_RECON_CONTROL, RANGE_REF_RED_TYPE, spr->recon_control, 0);
          }
      } // end for RR upscale
  
  } // vc1_fill_RR_hw_struct
  
  /**
   * fill workload items that will load registers for HW decoder
   */
  static void vc1_fill_hw_struct(vc1_viddec_parser_t *parser, vc1_Info* pInfo, VC1D_SPR_REGS *spr)
  {
      vc1_metadata_t *md = &pInfo->metadata;
      vc1_PictureLayerHeader *pic = &pInfo->picLayerHeader;
      int field = pic->CurrField;
      int ptype;
  
      ptype = pic->PTYPE;
  
      LOG_CRIT("ptype = %d, field = %d, topfield = %d, slice = %d", ptype, pic->CurrField, pic->BottomField, pic->SLICE_ADDR);
  
      /* Common to both fields */
      BF_WRITE(VC1_0_SEQPIC_STREAM_FORMAT_1, PROFILE, spr->stream_format1, md->PROFILE);
  
      BF_WRITE(VC1_0_SEQPIC_CODED_SIZE, WIDTH, spr->coded_size, md->width);
      BF_WRITE(VC1_0_SEQPIC_CODED_SIZE, HEIGHT, spr->coded_size, md->height);
  
      BF_WRITE(VC1_0_SEQPIC_STREAM_FORMAT_2, INTERLACE, spr->stream_format2, md->INTERLACE);
  
      BF_WRITE(VC1_0_SEQPIC_ENTRY_POINT_1, LOOPFILTER,    spr->entrypoint1, md->LOOPFILTER);
      BF_WRITE(VC1_0_SEQPIC_ENTRY_POINT_1, FASTUVMC,      spr->entrypoint1, md->FASTUVMC);
      BF_WRITE(VC1_0_SEQPIC_ENTRY_POINT_1, EXTENDED_MV,   spr->entrypoint1, md->EXTENDED_MV);
      BF_WRITE(VC1_0_SEQPIC_ENTRY_POINT_1, DQUANT,        spr->entrypoint1, md->DQUANT);
      BF_WRITE(VC1_0_SEQPIC_ENTRY_POINT_1, VS_TRANSFORM,  spr->entrypoint1, md->VSTRANSFORM);
      BF_WRITE(VC1_0_SEQPIC_ENTRY_POINT_1, OVERLAP,       spr->entrypoint1, md->OVERLAP);
      BF_WRITE(VC1_0_SEQPIC_ENTRY_POINT_1, QUANTIZER,     spr->entrypoint1, md->QUANTIZER);
      BF_WRITE(VC1_0_SEQPIC_ENTRY_POINT_1, EXTENDED_DMV,  spr->entrypoint1, md->EXTENDED_DMV);
  
      /* if range reduction is indicated at seq. layer, populate range reduction registers for the frame*/
      if(md->RANGERED)
      {
          vc1_fill_RR_hw_struct(parser, pInfo, spr );
      } 
      else 
      { //range mapping
          BF_WRITE( VC1_0_SEQPIC_RANGE_MAP, RANGE_MAP_Y_FLAG, spr->range_map, md->RANGE_MAPY_FLAG);
          BF_WRITE( VC1_0_SEQPIC_RANGE_MAP, RANGE_MAP_Y, spr->range_map, md->RANGE_MAPY);
          BF_WRITE( VC1_0_SEQPIC_RANGE_MAP, RANGE_MAP_UV_FLAG, spr->range_map, md->RANGE_MAPUV_FLAG);
          BF_WRITE( VC1_0_SEQPIC_RANGE_MAP, RANGE_MAP_UV, spr->range_map, md->RANGE_MAPUV);
      }
  
      BF_WRITE(VC1_0_SEQPIC_FRAME_TYPE, FCM, spr->frame_type, pic->FCM);
      BF_WRITE(VC1_0_SEQPIC_FRAME_TYPE, PTYPE, spr->frame_type, pic->PTYPE);
  
      BF_WRITE( VC1_0_SEQPIC_RECON_CONTROL, RNDCTRL, spr->recon_control, md->RNDCTRL);
      BF_WRITE( VC1_0_SEQPIC_RECON_CONTROL, UVSAMP, spr->recon_control, pic->UVSAMP);
      BF_WRITE( VC1_0_SEQPIC_RECON_CONTROL, PQUANT, spr->recon_control, pic->PQUANT);
      BF_WRITE( VC1_0_SEQPIC_RECON_CONTROL, HALFQP, spr->recon_control, pic->HALFQP);
      BF_WRITE( VC1_0_SEQPIC_RECON_CONTROL, UNIFORM_QNT, spr->recon_control, pic->UniformQuant);
      BF_WRITE( VC1_0_SEQPIC_RECON_CONTROL, POSTPROC, spr->recon_control, pic->POSTPROC);
      BF_WRITE( VC1_0_SEQPIC_RECON_CONTROL, CONDOVER, spr->recon_control, pic->CONDOVER);
      BF_WRITE( VC1_0_SEQPIC_RECON_CONTROL, PQINDEX_LE8, spr->recon_control, (pic->PQINDEX <= 8));
  
      BF_WRITE( VC1_0_SEQPIC_MOTION_VECTOR_CONTROL, MVRANGE,   spr->mv_control, pic->MVRANGE);
      if ( pic->MVMODE == VC1_MVMODE_INTENSCOMP)
          BF_WRITE( VC1_0_SEQPIC_MOTION_VECTOR_CONTROL, MVMODE,    spr->mv_control, pic->MVMODE2);
      else
          BF_WRITE( VC1_0_SEQPIC_MOTION_VECTOR_CONTROL, MVMODE,    spr->mv_control, pic->MVMODE);
      BF_WRITE( VC1_0_SEQPIC_MOTION_VECTOR_CONTROL, MVTAB,  spr->mv_control,  pic->MVTAB);
      BF_WRITE( VC1_0_SEQPIC_MOTION_VECTOR_CONTROL, DMVRANGE,  spr->mv_control, pic->DMVRANGE);
      BF_WRITE( VC1_0_SEQPIC_MOTION_VECTOR_CONTROL, MV4SWITCH, spr->mv_control, pic->MV4SWITCH);
      BF_WRITE( VC1_0_SEQPIC_MOTION_VECTOR_CONTROL, MBMODETAB, spr->mv_control, pic->MBMODETAB);
      BF_WRITE( VC1_0_SEQPIC_MOTION_VECTOR_CONTROL, NUMREF,    spr->mv_control,
          pic->NUMREF || ((pic->PTYPE == VC1_B_FRAME) && ( pic->FCM == VC1_FCM_FIELD_INTERLACE )  ));
      BF_WRITE( VC1_0_SEQPIC_MOTION_VECTOR_CONTROL, REFFIELD,  spr->mv_control, pic->REFFIELD);
  
      handle_intensity_compensation(parser, pInfo, spr);
  
      BF_WRITE(VC1_0_SEQPIC_REFERENCE_B_FRACTION, BFRACTION_DEN, spr->ref_bfraction, pic->BFRACTION_DEN);
      BF_WRITE(VC1_0_SEQPIC_REFERENCE_B_FRACTION, BFRACTION_NUM, spr->ref_bfraction, pic->BFRACTION_NUM);
      BF_WRITE(VC1_0_SEQPIC_REFERENCE_B_FRACTION, REFDIST, spr->ref_bfraction, md->REFDIST);
  
      // BLOCK CONTROL REGISTER Offset 0x2C
      BF_WRITE( VC1_0_SEQPIC_BLOCK_CONTROL, CBPTAB, spr->blk_control, pic->CBPTAB);
      BF_WRITE(VC1_0_SEQPIC_BLOCK_CONTROL, TTMFB, spr->blk_control, pic->TTMBF);
      BF_WRITE(VC1_0_SEQPIC_BLOCK_CONTROL, TTFRM, spr->blk_control, pic->TTFRM);
      BF_WRITE(VC1_0_SEQPIC_BLOCK_CONTROL, MV2BPTAB, spr->blk_control, pic->MV2BPTAB);
      BF_WRITE(VC1_0_SEQPIC_BLOCK_CONTROL, MV4BPTAB, spr->blk_control, pic->MV4BPTAB);
      if((field == 1) && (pic->SLICE_ADDR)) 
      {
          int mby = md->height * 2 + 2;
          mby = (mby + 15 ) / 16;
          pic->SLICE_ADDR -= (mby/2);
      }
      BF_WRITE(VC1_0_SEQPIC_BLOCK_CONTROL, INITIAL_MV_Y, spr->blk_control, pic->SLICE_ADDR);
      BF_WRITE(VC1_0_SEQPIC_BLOCK_CONTROL, BP_RAW_ID2, spr->blk_control, md->bp_raw[0]);
      BF_WRITE(VC1_0_SEQPIC_BLOCK_CONTROL, BP_RAW_ID1, spr->blk_control, md->bp_raw[1]);
      BF_WRITE(VC1_0_SEQPIC_BLOCK_CONTROL, BP_RAW_ID0, spr->blk_control, md->bp_raw[2]);
  
      BF_WRITE( VC1_0_SEQPIC_TRANSFORM_DATA, TRANSACFRM,  spr->trans_data, pic->TRANSACFRM);
      BF_WRITE( VC1_0_SEQPIC_TRANSFORM_DATA, TRANSACFRM2, spr->trans_data, pic->TRANSACFRM2);
      BF_WRITE( VC1_0_SEQPIC_TRANSFORM_DATA, TRANSDCTAB,  spr->trans_data, pic->TRANSDCTAB);
  
      // When DQUANT is 1 or 2, we have the VOPDQUANT structure in the bitstream that
      // controls the value calculated for ALTPQUANT
      // ALTPQUANT must be in the range of 1 and 31 for it to be valid 
      // DQUANTFRM is present only when DQUANT is 1 and ALTPQUANT setting should be dependent on DQUANT instead
      if(md->DQUANT)
      {
          if(pic->PQDIFF == 7)
              BF_WRITE( VC1_0_SEQPIC_VOP_DEQUANT, PQUANT_ALT, spr->vop_dquant, pic->ABSPQ);
          else if (pic->DQUANTFRM == 1)
              BF_WRITE( VC1_0_SEQPIC_VOP_DEQUANT, PQUANT_ALT, spr->vop_dquant, pic->PQUANT + pic->PQDIFF + 1);
      }
      BF_WRITE( VC1_0_SEQPIC_VOP_DEQUANT, DQUANTFRM, spr->vop_dquant, pic->DQUANTFRM);
      BF_WRITE( VC1_0_SEQPIC_VOP_DEQUANT, DQPROFILE, spr->vop_dquant, pic->DQPROFILE);
      BF_WRITE( VC1_0_SEQPIC_VOP_DEQUANT, DQES,      spr->vop_dquant, pic->DQSBEDGE);
      BF_WRITE( VC1_0_SEQPIC_VOP_DEQUANT, DQBILEVEL, spr->vop_dquant, pic->DQBILEVEL);
  
      BF_WRITE(VC1_0_SEQPIC_CURR_FRAME_ID,FCM, spr->ref_frm_id[VC1_FRAME_CURRENT_REF], pic->FCM );
  
      if ( ptype == VC1_B_FRAME) {
           // Forward reference is past reference and is the second temporally closest reference - hence minus_2
           BF_WRITE(VC1_0_SEQPIC_FWD_REF_FRAME_ID, FCM, parser->spr.ref_frm_id[VC1_FRAME_PAST], parser->ref_frame[VC1_REF_FRAME_T_MINUS_2].fcm );
           // Backward reference is future reference frame and is temporally the closest - hence minus_1
           BF_WRITE(VC1_0_SEQPIC_BWD_REF_FRAME_ID, FCM, parser->spr.ref_frm_id[VC1_FRAME_FUTURE], parser->ref_frame[VC1_REF_FRAME_T_MINUS_1].fcm );
      } else {
           // Only Forward reference is valid and is the temporally closest reference - hence minus_1, backward is set same as forward
           BF_WRITE(VC1_0_SEQPIC_FWD_REF_FRAME_ID, FCM, parser->spr.ref_frm_id[VC1_FRAME_PAST], parser->ref_frame[VC1_REF_FRAME_T_MINUS_1].fcm );
           BF_WRITE(VC1_0_SEQPIC_BWD_REF_FRAME_ID, FCM, parser->spr.ref_frm_id[VC1_FRAME_FUTURE], parser->ref_frame[VC1_REF_FRAME_T_MINUS_1].fcm );
      }
  
      BF_WRITE( VC1_0_SEQPIC_FIELD_REF_FRAME_ID, TOP_FIELD,    spr->fieldref_ctrl_id, pic->BottomField);
      BF_WRITE( VC1_0_SEQPIC_FIELD_REF_FRAME_ID, SECOND_FIELD, spr->fieldref_ctrl_id, pic->CurrField);
      if(parser->info.picLayerHeader.PTYPE == VC1_I_FRAME)
      {
          BF_WRITE(VC1_0_SEQPIC_FIELD_REF_FRAME_ID, ANCHOR, spr->fieldref_ctrl_id, 1);
      }
      else
      {
          BF_WRITE(VC1_0_SEQPIC_FIELD_REF_FRAME_ID, ANCHOR, spr->fieldref_ctrl_id, parser->ref_frame[VC1_REF_FRAME_T_MINUS_1].anchor[pic->CurrField]);
      }
  
      if( pic->FCM == VC1_FCM_FIELD_INTERLACE ) {
          BF_WRITE(VC1_0_SEQPIC_IMAGE_STRUCTURE, IMG_STRUC, spr->imgstruct, (pic->BottomField) ? 2 : 1);
      }
  
      return;
  } // vc1_fill_hw_struct
  
  int32_t vc1_parse_emit_current_frame(void *parent, vc1_viddec_parser_t *parser)
  {
     viddec_workload_item_t wi;
     const uint32_t *pl;
     int i;
     int nitems;
  
      if( parser->info.picLayerHeader.PTYPE == VC1_SKIPPED_FRAME ) {
          translate_parser_info_to_frame_attributes( parent, parser );
          return 0;
      }
  
     translate_parser_info_to_frame_attributes( parent, parser );
     memset(&parser->spr, 0, sizeof(VC1D_SPR_REGS));
     vc1_fill_hw_struct( parser, &parser->info, &parser->spr );
  
     /* STUFF BSP Data Memory it into a variety of workload items */
  
     pl = (const uint32_t *) &parser->spr;
  
     // How many payloads must be generated
     nitems = (sizeof(parser->spr) + 7) / 8; /* In QWORDs rounded up */
  
  
     // Dump DMEM to an array of workitems
     for( i = 0; (i < nitems) && ( (parser->info.picLayerHeader.SLICE_ADDR == 0) || parser->info.picture_info_has_changed ); i++ )
     {
        wi.vwi_type           = VIDDEC_WORKLOAD_DECODER_SPECIFIC;
        wi.data.data_offset   = (unsigned int)pl - (unsigned int)&parser->spr; // offset within struct
        wi.data.data_payload[0] = pl[0];
        wi.data.data_payload[1] = pl[1];
        pl += 2;
  
        viddec_pm_append_workitem( parent, &wi );
     }
     
     {
        uint32_t bit, byte;
        uint8_t is_emul;
        viddec_pm_get_au_pos(parent, &bit, &byte, &is_emul);
        // Send current bit offset and current slice
        wi.vwi_type          = VIDDEC_WORKLOAD_VC1_BITOFFSET;
        // If slice data starts in the middle of the emulation prevention sequence - 
        // Eg: 00 00 03 01 - slice data starts at the second byte of 0s, we still feed the data 
        // to the decoder starting at the first byte of 0s so that the decoder can detect the 
        // emulation prevention. But the actual data starts are offset 8 in this bit sequence.
        wi.vwi_payload[0]    = bit + (is_emul*8);
        wi.vwi_payload[1]    = parser->info.picLayerHeader.SLICE_ADDR;
        wi.vwi_payload[2]    = 0xdeaddead;
        viddec_pm_append_workitem( parent, &wi );
     }
  
     viddec_pm_append_pixeldata( parent );
  
     return(0);
  }
  
  /* sends VIDDEC_WORKLOAD_VC1_PAST_FRAME item */
  static inline void vc1_send_past_ref_items(void *parent)
  {
     viddec_workload_item_t wi;
     wi.vwi_type = VIDDEC_WORKLOAD_VC1_PAST_FRAME;
     wi.ref_frame.reference_id = 0;
     wi.ref_frame.luma_phys_addr = 0;
     wi.ref_frame.chroma_phys_addr = 0;
     viddec_pm_append_workitem( parent, &wi );
     return;
  }
  
  /* send future frame item */
  static inline void vc1_send_future_ref_items(void *parent)
  {
     viddec_workload_item_t wi;
     wi.vwi_type = VIDDEC_WORKLOAD_VC1_FUTURE_FRAME;
     wi.ref_frame.reference_id = 0;
     wi.ref_frame.luma_phys_addr = 0;
     wi.ref_frame.chroma_phys_addr = 0;
     viddec_pm_append_workitem( parent, &wi );
     return;
  }
  
  /* send reorder frame item to host
   * future frame gets push to past   */
  static inline void send_reorder_ref_items(void *parent)
  {
     viddec_workload_item_t wi;
     wi.vwi_type = VIDDEC_WORKLOAD_REFERENCE_FRAME_REORDER;
     wi.ref_reorder.ref_table_offset = 0;
     wi.ref_reorder.ref_reorder_00010203 = 0x01010203; //put reference frame index 1 as reference index 0
     wi.ref_reorder.ref_reorder_04050607 = 0x04050607; // index 4,5,6,7 stay the same
     viddec_pm_append_workitem( parent, &wi );
     return;
  } // send_reorder_ref_items
  
  /** update workload with more workload items for ref and update values to store...
   */
  void vc1_start_new_frame(void *parent, vc1_viddec_parser_t *parser)
  {
     vc1_metadata_t *md = &(parser->info.metadata);
     viddec_workload_t *wl = viddec_pm_get_header(parent);
     int frame_type = parser->info.picLayerHeader.PTYPE;
     int frame_id = 1; // new reference frame is assigned index 1
  
     /* init */
     memset(&parser->spr, 0, sizeof(parser->spr));
     wl->is_reference_frame = 0;
  
     /* set flag - extra ouput frame needed for range adjustment (range mapping or range reduction */
     if (parser->info.metadata.RANGE_MAPY_FLAG || 
          parser->info.metadata.RANGE_MAPUV_FLAG || 
          parser->info.picLayerHeader.RANGEREDFRM)
     {
        wl->is_reference_frame |= WORKLOAD_FLAGS_RA_FRAME;
     }
     
     LOG_CRIT("vc1_start_new_frame: frame_type=%d \n",frame_type);
  
     parser->is_reference_picture = ((VC1_B_FRAME != frame_type) && (VC1_BI_FRAME != frame_type));
  
     /* reference / anchor frames processing 
      * we need to send reorder before reference frames */ 
     if (parser->is_reference_picture)
     {
        /* one frame has been sent */
        if (parser->ref_frame[VC1_REF_FRAME_T_MINUS_1].id != -1) 
        {
           /* there is a frame in the reference buffer, move it to the past */
           send_reorder_ref_items(parent); 
        }
     }
  
     /* send workitems for reference frames */
     switch( frame_type ) 
     {
        case VC1_B_FRAME:
        {
            vc1_send_past_ref_items(parent);
            vc1_send_future_ref_items(parent);
            break;
        }
        case VC1_SKIPPED_FRAME:
        {
           wl->is_reference_frame |= WORKLOAD_SKIPPED_FRAME;
             vc1_send_past_ref_items(parent);
            break;
        }
        case VC1_P_FRAME:
        {
            vc1_send_past_ref_items( parent);
           break;
        }
      default:
          break;
     }
  
      /* reference / anchor frames from previous code 
       * we may need it for frame reduction */ 
      if (parser->is_reference_picture)
      {
          wl->is_reference_frame |= WORKLOAD_REFERENCE_FRAME | (frame_id & WORKLOAD_REFERENCE_FRAME_BMASK);
  
          parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].id      = frame_id;
          parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].fcm     = parser->info.picLayerHeader.FCM;
          parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].anchor[0]  = (parser->info.picLayerHeader.PTYPE == VC1_I_FRAME);
          if(parser->info.picLayerHeader.FCM == VC1_FCM_FIELD_INTERLACE)
          {
              parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].anchor[1] = (parser->info.picLayerHeader.PTypeField2 == VC1_I_FRAME);
          }
          else
          {
              parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].anchor[1] = parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].anchor[0];
          }
  
          parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].type = parser->info.picLayerHeader.PTYPE;
          parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].rr_en = md->RANGERED;
          parser->ref_frame[VC1_REF_FRAME_T_MINUS_0].rr_frm = parser->info.picLayerHeader.RANGEREDFRM;
  
          LOG_CRIT("anchor[0] = %d, anchor[1] = %d",
              parser->ref_frame[VC1_REF_FRAME_T_MINUS_1].anchor[0],
              parser->ref_frame[VC1_REF_FRAME_T_MINUS_1].anchor[1] );
      }
  
      return;
  } // vc1_start_new_frame
  
  void vc1_end_frame(vc1_viddec_parser_t *parser)
  {
      /* update status of reference frames */
      if(parser->is_reference_picture)
      {
          parser->ref_frame[VC1_REF_FRAME_T_MINUS_2] = parser->ref_frame[VC1_REF_FRAME_T_MINUS_1];
          parser->ref_frame[VC1_REF_FRAME_T_MINUS_1] = parser->ref_frame[VC1_REF_FRAME_T_MINUS_0];
      }
  
      return;
  } // vc1_end_frame
  
  