JM ldecod分析:获取slice

JM ldecod分析:解码slice

承接上节 JM ldecod分析
read_new_slice()从h264数据流中获取一个slice。
slice结构参见关键数据结构
(后边提到的数据结构均在该链接中)

  1. read_next_nalu()

NALU_t结构是nalu的描述头,用来保存nalu的头信息和nalu body的buf指针。

read_new_slice

从bitstream中读取到slice之后,slice分为slice_header和slice_data两部分。读取slice_header 的部分字段的时候,需要首先获取pps 和sps。所以读取slice_header时,代码分成两部分。slice_header字段使用的是哥伦布编码进行编码的。
slice_data字段主要使用熵编码,CAVLC和CABAC。

/*!
 ************************************************************************
 * \brief
 *    Reads new slice from bit_stream_dec
 ************************************************************************
 */
int read_new_slice(Slice *currSlice)
{
  VideoParameters *p_Vid = currSlice->p_Vid;
  InputParameters *p_Inp = currSlice->p_Inp;

  NALU_t *nalu = p_Vid->nalu; 
  int current_header = 0;
  int BitsUsedByHeader;
  Bitstream *currStream = NULL;

  static NALU_t *pending_nalu = NULL;

  int slice_id_a, slice_id_b, slice_id_c;

  for (;;)
  {
#if (MVC_EXTENSION_ENABLE)
    currSlice->svc_extension_flag = -1;
#endif
    if (!pending_nalu)
    {
      读取一个nalu(ebsp已经被转化为rbsp)
      if (0 == read_next_nalu(p_Vid, nalu))
        return EOS;
    }
    else
    {
      nalu = pending_nalu;
      pending_nalu = NULL;
    }

#if (MVC_EXTENSION_ENABLE)
    if(p_Inp->DecodeAllLayers == 1 && (nalu->nal_unit_type == NALU_TYPE_PREFIX || nalu->nal_unit_type == NALU_TYPE_SLC_EXT))
    {
      currStream = currSlice->partArr[0].bitstream;
      currStream->ei_flag = 0;
      currStream->frame_bitoffset = currStream->read_len = 0;
      fast_memcpy (currStream->streamBuffer, &nalu->buf[1], nalu->len-1);
      currStream->code_len = currStream->bitstream_length = RBSPtoSODB(currStream->streamBuffer, nalu->len-1);

      currSlice->svc_extension_flag = read_u_1 ("svc_extension_flag"        , currStream, &p_Dec->UsedBits);

      if(currSlice->svc_extension_flag)
      {
        nal_unit_header_svc_extension();
      }
      else
      {
        nal_unit_header_mvc_extension(&currSlice->NaluHeaderMVCExt, currStream);
        currSlice->NaluHeaderMVCExt.iPrefixNALU = (nalu->nal_unit_type == NALU_TYPE_PREFIX);
      }

      if(nalu->nal_unit_type == NALU_TYPE_SLC_EXT)
      {        
        if(currSlice->svc_extension_flag)
        {
          //to be implemented for Annex G;
        }
        else 
        {
          nalu->nal_unit_type = NALU_TYPE_SLICE; //currSlice->NaluHeaderMVCExt.non_idr_flag==0? NALU_TYPE_IDR: NALU_TYPE_SLICE; 
        }
      }
    }
#endif
根据nalu类型进行处理
process_nalu:
    switch (nalu->nal_unit_type)
    {
    case NALU_TYPE_SLICE:
    case NALU_TYPE_IDR:

      if (p_Vid->recovery_point || nalu->nal_unit_type == NALU_TYPE_IDR)
      {
        if (p_Vid->recovery_point_found == 0)
        {
          if (nalu->nal_unit_type != NALU_TYPE_IDR)
          {
            printf("Warning: Decoding does not start with an IDR picture.\n");
            p_Vid->non_conforming_stream = 1;
          }
          else
            p_Vid->non_conforming_stream = 0;
        }
        p_Vid->recovery_point_found = 1;
      }

      if (p_Vid->recovery_point_found == 0)
        break;

      currSlice->idr_flag = (nalu->nal_unit_type == NALU_TYPE_IDR);
      currSlice->nal_reference_idc = nalu->nal_reference_idc;
      currSlice->dp_mode = PAR_DP_1;
      currSlice->max_part_nr = 1;
#if (MVC_EXTENSION_ENABLE)
      if (currSlice->svc_extension_flag != 0)
      {
        currStream = currSlice->partArr[0].bitstream;
        currStream->ei_flag = 0;
        currStream->frame_bitoffset = currStream->read_len = 0;
        fast_memcpy (currStream->streamBuffer, &nalu->buf[1], nalu->len-1);
        currStream->code_len = currStream->bitstream_length = RBSPtoSODB(currStream->streamBuffer, nalu->len-1);
      }
#else   
      currStream = currSlice->partArr[0].bitstream;
      currStream->ei_flag = 0;
      currStream->frame_bitoffset = currStream->read_len = 0;
      保存解码原数据
      memcpy (currStream->streamBuffer, &nalu->buf[1], nalu->len-1);
      将最后的填充0 bit删掉,获得code_len 编码后数据长度
      currStream->code_len = currStream->bitstream_length = RBSPtoSODB(currStream->streamBuffer, nalu->len-1);
#endif

#if (MVC_EXTENSION_ENABLE)
      if(currSlice->svc_extension_flag == 0)
      {  //MVC
        //if(is_MVC_profile(p_Vid->active_sps->profile_idc))
        //{
          currSlice->view_id = currSlice->NaluHeaderMVCExt.view_id;
          currSlice->inter_view_flag = currSlice->NaluHeaderMVCExt.inter_view_flag;
          currSlice->anchor_pic_flag = currSlice->NaluHeaderMVCExt.anchor_pic_flag;
        //}
      }
      else if(currSlice->svc_extension_flag == -1) //SVC and the normal AVC;
      {
        if(p_Vid->active_subset_sps == NULL)
        {
          currSlice->view_id = GetBaseViewId(p_Vid, &p_Vid->active_subset_sps);
          if(currSlice->NaluHeaderMVCExt.iPrefixNALU >0)
          {
            assert(currSlice->view_id == currSlice->NaluHeaderMVCExt.view_id);
            currSlice->inter_view_flag = currSlice->NaluHeaderMVCExt.inter_view_flag;
            currSlice->anchor_pic_flag = currSlice->NaluHeaderMVCExt.anchor_pic_flag;
          }
          else
          {
            currSlice->inter_view_flag = 1;
            currSlice->anchor_pic_flag = currSlice->idr_flag;
          }
        }
        else
        {
          assert(p_Vid->active_subset_sps->num_views_minus1 >=0);
          // prefix NALU available
          if(currSlice->NaluHeaderMVCExt.iPrefixNALU >0)
          {
            currSlice->view_id = currSlice->NaluHeaderMVCExt.view_id;
            currSlice->inter_view_flag = currSlice->NaluHeaderMVCExt.inter_view_flag;
            currSlice->anchor_pic_flag = currSlice->NaluHeaderMVCExt.anchor_pic_flag;
          }
          else
          { //no prefix NALU;
            currSlice->view_id = p_Vid->active_subset_sps->view_id[0];
            currSlice->inter_view_flag = 1;
            currSlice->anchor_pic_flag = currSlice->idr_flag;
          }
        }
      }
     currSlice->layer_id = currSlice->view_id = GetVOIdx( p_Vid, currSlice->view_id );
#endif

      // Some syntax of the Slice Header depends on the parameter set, which depends on
      // the parameter set ID of the SLice header.  Hence, read the pic_parameter_set_id
      // of the slice header first, then setup the active parameter sets, and then read
      // the rest of the slice header
      BitsUsedByHeader = FirstPartOfSliceHeader(currSlice);
      UseParameterSet (currSlice);
      currSlice->active_sps = p_Vid->active_sps;
      currSlice->active_pps = p_Vid->active_pps;
      currSlice->Transform8x8Mode = p_Vid->active_pps->transform_8x8_mode_flag;
      currSlice->chroma444_not_separate = (p_Vid->active_sps->chroma_format_idc==YUV444)&&((p_Vid->separate_colour_plane_flag == 0));

      BitsUsedByHeader += RestOfSliceHeader (currSlice);
#if (MVC_EXTENSION_ENABLE)
      if(currSlice->view_id >=0)
      {
        currSlice->p_Dpb = p_Vid->p_Dpb_layer[currSlice->view_id];
      }
#endif

      assign_quant_params (currSlice);        

      // if primary slice is replaced with redundant slice, set the correct image type
      if(currSlice->redundant_pic_cnt && p_Vid->Is_primary_correct==0 && p_Vid->Is_redundant_correct)
      {
        p_Vid->dec_picture->slice_type = p_Vid->type;
      }

      if(is_new_picture(p_Vid->dec_picture, currSlice, p_Vid->old_slice))
      {
        if(p_Vid->iSliceNumOfCurrPic==0)
          init_picture(p_Vid, currSlice, p_Inp);

        current_header = SOP;
        //check zero_byte if it is also the first NAL unit in the access unit
        CheckZeroByteVCL(p_Vid, nalu);
      }
      else
        current_header = SOS;

      setup_slice_methods(currSlice);

      // From here on, p_Vid->active_sps, p_Vid->active_pps and the slice header are valid
      if (currSlice->mb_aff_frame_flag)
        currSlice->current_mb_nr = currSlice->start_mb_nr << 1;
      else
        currSlice->current_mb_nr = currSlice->start_mb_nr;

      if (p_Vid->active_pps->entropy_coding_mode_flag)
      {
        int ByteStartPosition = currStream->frame_bitoffset/8;
        if (currStream->frame_bitoffset%8 != 0)
        {
          ++ByteStartPosition;
        }
        arideco_start_decoding (&currSlice->partArr[0].de_cabac, currStream->streamBuffer, ByteStartPosition, &currStream->read_len);
      }
      // printf ("read_new_slice: returning %s\n", current_header == SOP?"SOP":"SOS");
      //FreeNALU(nalu);
      p_Vid->recovery_point = 0;
      return current_header;
      break;
    case NALU_TYPE_DPA:
      if (p_Vid->recovery_point_found == 0)
        break;

      // read DP_A
      currSlice->dpB_NotPresent =1; 
      currSlice->dpC_NotPresent =1; 

      currSlice->idr_flag          = FALSE;
      currSlice->nal_reference_idc = nalu->nal_reference_idc;
      currSlice->dp_mode     = PAR_DP_3;
      currSlice->max_part_nr = 3;
      currSlice->ei_flag     = 0;
#if MVC_EXTENSION_ENABLE
      currSlice->p_Dpb = p_Vid->p_Dpb_layer[0];
#endif
      currStream             = currSlice->partArr[0].bitstream;
      currStream->ei_flag    = 0;
      currStream->frame_bitoffset = currStream->read_len = 0;
      memcpy (currStream->streamBuffer, &nalu->buf[1], nalu->len-1);
      currStream->code_len = currStream->bitstream_length = RBSPtoSODB(currStream->streamBuffer, nalu->len-1);
#if MVC_EXTENSION_ENABLE
      currSlice->view_id = GetBaseViewId(p_Vid, &p_Vid->active_subset_sps);
      currSlice->inter_view_flag = 1;
      currSlice->layer_id = currSlice->view_id = GetVOIdx( p_Vid, currSlice->view_id );
      currSlice->anchor_pic_flag = currSlice->idr_flag;
#endif

      BitsUsedByHeader = FirstPartOfSliceHeader(currSlice);
      UseParameterSet (currSlice);
      currSlice->active_sps = p_Vid->active_sps;
      currSlice->active_pps = p_Vid->active_pps;
      currSlice->Transform8x8Mode = p_Vid->active_pps->transform_8x8_mode_flag;
      currSlice->chroma444_not_separate = (p_Vid->active_sps->chroma_format_idc==YUV444)&&((p_Vid->separate_colour_plane_flag == 0));

      BitsUsedByHeader += RestOfSliceHeader (currSlice);
#if MVC_EXTENSION_ENABLE
      currSlice->p_Dpb = p_Vid->p_Dpb_layer[currSlice->view_id];
#endif

      assign_quant_params (currSlice);        


      if(is_new_picture(p_Vid->dec_picture, currSlice, p_Vid->old_slice))
      {
        if(p_Vid->iSliceNumOfCurrPic==0)
          init_picture(p_Vid, currSlice, p_Inp);

        current_header = SOP;
        //check zero_byte if it is also the first NAL unit in the access unit
        CheckZeroByteVCL(p_Vid, nalu);
      }
      else
        current_header = SOS;

      setup_slice_methods(currSlice);

      // From here on, p_Vid->active_sps, p_Vid->active_pps and the slice header are valid
      if (currSlice->mb_aff_frame_flag)
        currSlice->current_mb_nr = currSlice->start_mb_nr << 1;
      else
        currSlice->current_mb_nr = currSlice->start_mb_nr;

      // Now I need to read the slice ID, which depends on the value of
      // redundant_pic_cnt_present_flag

      slice_id_a  = read_ue_v("NALU: DP_A slice_id", currStream, &p_Dec->UsedBits);

      if (p_Vid->active_pps->entropy_coding_mode_flag)
        error ("received data partition with CABAC, this is not allowed", 500);

      // continue with reading next DP
      if (0 == read_next_nalu(p_Vid, nalu))
        return current_header;

      if ( NALU_TYPE_DPB == nalu->nal_unit_type)
      {
        // we got a DPB
        currStream             = currSlice->partArr[1].bitstream;
        currStream->ei_flag    = 0;
        currStream->frame_bitoffset = currStream->read_len = 0;

        memcpy (currStream->streamBuffer, &nalu->buf[1], nalu->len-1);
        currStream->code_len = currStream->bitstream_length = RBSPtoSODB(currStream->streamBuffer, nalu->len-1);

        slice_id_b  = read_ue_v("NALU: DP_B slice_id", currStream, &p_Dec->UsedBits);

        currSlice->dpB_NotPresent = 0; 

        if ((slice_id_b != slice_id_a) || (nalu->lost_packets))
        {
          printf ("Waning: got a data partition B which does not match DP_A (DP loss!)\n");
          currSlice->dpB_NotPresent =1; 
          currSlice->dpC_NotPresent =1; 
        }
        else
        {
          if (p_Vid->active_pps->redundant_pic_cnt_present_flag)
            read_ue_v("NALU: DP_B redundant_pic_cnt", currStream, &p_Dec->UsedBits);

          // we're finished with DP_B, so let's continue with next DP
          if (0 == read_next_nalu(p_Vid, nalu))
            return current_header;
        }
      }
      else
      {
        currSlice->dpB_NotPresent =1; 
      }

      // check if we got DP_C
      if ( NALU_TYPE_DPC == nalu->nal_unit_type)
      {
        currStream             = currSlice->partArr[2].bitstream;
        currStream->ei_flag    = 0;
        currStream->frame_bitoffset = currStream->read_len = 0;

        memcpy (currStream->streamBuffer, &nalu->buf[1], nalu->len-1);
        currStream->code_len = currStream->bitstream_length = RBSPtoSODB(currStream->streamBuffer, nalu->len-1);

        currSlice->dpC_NotPresent = 0;

        slice_id_c  = read_ue_v("NALU: DP_C slice_id", currStream, &p_Dec->UsedBits);
        if ((slice_id_c != slice_id_a)|| (nalu->lost_packets))
        {
          printf ("Warning: got a data partition C which does not match DP_A(DP loss!)\n");
          //currSlice->dpB_NotPresent =1;
          currSlice->dpC_NotPresent =1;
        }

        if (p_Vid->active_pps->redundant_pic_cnt_present_flag)
          read_ue_v("NALU:SLICE_C redudand_pic_cnt", currStream, &p_Dec->UsedBits);
      }
      else
      {
        currSlice->dpC_NotPresent =1;
        pending_nalu = nalu;
      }

      // check if we read anything else than the expected partitions
      if ((nalu->nal_unit_type != NALU_TYPE_DPB) && (nalu->nal_unit_type != NALU_TYPE_DPC) && (!currSlice->dpC_NotPresent))
      {
        // we have a NALI that we can't process here, so restart processing
        goto process_nalu;
        // yes, "goto" should not be used, but it's really the best way here before we restructure the decoding loop
        // (which should be taken care of anyway)
      }

      //FreeNALU(nalu);
      return current_header;
      break;
    case NALU_TYPE_DPB:
      if (p_Inp->silent == FALSE)
      {
        printf ("found data partition B without matching DP A, discarding\n");
      }
      break;
    case NALU_TYPE_DPC:
      if (p_Inp->silent == FALSE)
      {
        printf ("found data partition C without matching DP A, discarding\n");
      }
      break;
    case NALU_TYPE_SEI:
      //printf ("read_new_slice: Found NALU_TYPE_SEI, len %d\n", nalu->len);
      InterpretSEIMessage(nalu->buf,nalu->len,p_Vid, currSlice);
      break;
    case NALU_TYPE_PPS:
      //printf ("Found NALU_TYPE_PPS\n");
      ProcessPPS(p_Vid, nalu);
      break;
    case NALU_TYPE_SPS:
      //printf ("Found NALU_TYPE_SPS\n");
      ProcessSPS(p_Vid, nalu);
      break;
    case NALU_TYPE_AUD:
      //printf ("Found NALU_TYPE_AUD\n");
      //        printf ("read_new_slice: Found 'Access Unit Delimiter' NAL unit, len %d, ignored\n", nalu->len);
      break;
    case NALU_TYPE_EOSEQ:
      //        printf ("read_new_slice: Found 'End of Sequence' NAL unit, len %d, ignored\n", nalu->len);
      break;
    case NALU_TYPE_EOSTREAM:
      //        printf ("read_new_slice: Found 'End of Stream' NAL unit, len %d, ignored\n", nalu->len);
      break;
    case NALU_TYPE_FILL:
      if (p_Inp->silent == FALSE)
      {
        //printf ("read_new_slice: Found NALU_TYPE_FILL, len %d\n", (int) nalu->len);
        //printf ("Skipping these filling bits, proceeding w/ next NALU\n");
      }
      break;
#if (MVC_EXTENSION_ENABLE)
    case NALU_TYPE_VDRD:
      //printf ("Found NALU_TYPE_VDRD\n");
      //        printf ("read_new_slice: Found 'View and Dependency Representation Delimiter' NAL unit, len %d, ignored\n", nalu->len);
      break;
    case NALU_TYPE_PREFIX:
      //printf ("Found NALU_TYPE_PREFIX\n");
      if(currSlice->svc_extension_flag==1)
        prefix_nal_unit_svc();
      break;
    case NALU_TYPE_SUB_SPS:
      //printf ("Found NALU_TYPE_SUB_SPS\n");
      if (p_Inp->DecodeAllLayers== 1)
      {
        ProcessSubsetSPS(p_Vid, nalu);
      }
      else
      {
        if (p_Inp->silent == FALSE)
          printf ("Found Subsequence SPS NALU. Ignoring.\n");
      }
      break;
    case NALU_TYPE_SLC_EXT:
      //printf ("Found NALU_TYPE_SLC_EXT\n");
      if (p_Inp->DecodeAllLayers == 0 &&  (p_Inp->silent == FALSE))
        printf ("Found SVC extension NALU (%d). Ignoring.\n", (int) nalu->nal_unit_type);
      break;
#endif
    default:
      {
        if (p_Inp->silent == FALSE)
          printf ("Found NALU type %d, len %d undefined, ignore NALU, moving on\n", (int) nalu->nal_unit_type, (int) nalu->len);
      }
      break;
    }
  }
}

read_new_slice() 中首先分割bit流通过read_next_nalu()获取到下一个Nalu,根据Nalu的类型进行处理:

参见 JM ldecod分析: 分帧处理

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值