H.264 JM18 analysis—IDR frame coding(1st week)

来源:互联网 发布:广州多益网络老板徐波 编辑:程序博客网 时间:2024/04/29 10:25

视频序列的第一帧一定是IDR帧,采用帧内预测模式。

一、帧内预测

In an intra macroblock, there are three choices of intra prediction block size for the luma component, namely 16 × 16, 8 × 8 or 4 × 4. A single prediction block is generated for each chroma component. Each prediction block is generated using one of a number of possible prediction modes.

Intra prediction block sizeNotes16 × 16 (luma)A single 16 × 16 prediction block P is generated. Four possible prediction modes.8 × 8 (luma)An 8 × 8 prediction block P is generated for each 8 × 8 luma block. Nine possible prediction modes. ‘High’ Profiles only.4 × 4 (luma)A 4 × 4 prediction block P is generated for each 4 × 4 luma block. Nine possible prediction modes.ChromaOne prediction block P is generated for each chroma component. Four possible prediction modes. The same prediction mode is used for both chroma components.

 

二、片级(帧级)编码

编码一片时,需要写入片头信息,由以函数header_len += SliceHeader (currSlice);完成,片头信息格式参考标准文档 7.3.3 Slice header syntax.

片级编码的主体函数如下:

static void code_a_plane(VideoParameters *p_Vid, InputParameters *p_Inp)
{
  unsigned int NumberOfCodedMBs = 0;
  int SliceGroup = 0;
  DistMetric distortion;

  // The slice_group_change_cycle can be changed here.
  // FmoInit() is called before coding each picture, frame or field
  p_Vid->slice_group_change_cycle=1;
  FmoInit(p_Vid, p_Vid->active_pps, p_Vid->active_sps); //tj: fmo——Flexible Macroblock Order
  FmoStartPicture (p_Vid);           //! picture level initialization of FMO
 //tj: level_quant_params共定义了三个元素:int   OffsetComp;  int    ScaleComp;  int InvScaleComp;下面两个函数中,第一个初始化后两个参数,第二个函数初始化第一个参数。
  CalculateQuant4x4Param (p_Vid); //tj:参考《The H.264 Advanced Video Compression Standard》2ed 7.2.。
  CalculateOffset4x4Param(p_Vid); //tj: 参考《The H.264 Advanced Video Compression Standard》2ed (7.24)及下面的说明,是为了计算的方便。

  if(p_Inp->Transform8x8Mode)
  {
    CalculateQuant8x8Param (p_Vid);
    CalculateOffset8x8Param(p_Vid);
  }

  reset_pic_bin_count(p_Vid); //tj: 清零。
  p_Vid->bytes_in_picture = 0;

  while (NumberOfCodedMBs < p_Vid->PicSizeInMbs)       // loop over slices
  {
    // Encode one SLice Group
    while (!FmoSliceGroupCompletelyCoded (p_Vid, SliceGroup))
    {
      // Encode the current slice
      if (!p_Vid->mb_aff_frame_flag)
        NumberOfCodedMBs += encode_one_slice (p_Vid, SliceGroup, NumberOfCodedMBs); //tj: 对一个片组进行编码。
      else
        NumberOfCodedMBs += encode_one_slice_MBAFF (p_Vid, SliceGroup, NumberOfCodedMBs);

      FmoSetLastMacroblockInSlice (p_Vid, p_Vid->current_mb_nr);
      // Proceed to next slice
      p_Vid->current_slice_nr++;
      p_Vid->p_Stats->bit_slice = 0;
    }
    // Proceed to next SliceGroup
    SliceGroup++;
  }
  FmoEndPicture ();

  if ((p_Inp->SkipDeBlockNonRef == 0) || (p_Vid->nal_reference_idc != 0))
  {
    if(p_Inp->RDPictureDeblocking && !p_Vid->TurnDBOff)
    {
      find_distortion(p_Vid, &p_Vid->imgData);
      distortion.value[0] = p_Vid->p_Dist->metric[SSE].value[0];
      distortion.value[1] = p_Vid->p_Dist->metric[SSE].value[1];
      distortion.value[2] = p_Vid->p_Dist->metric[SSE].value[2];
    }
    else
      distortion.value[0] = distortion.value[1] = distortion.value[2] = 0;

    DeblockFrame (p_Vid, p_Vid->enc_picture->imgY, p_Vid->enc_picture->imgUV); //comment out to disable deblocking filter

    if(p_Inp->RDPictureDeblocking && !p_Vid->TurnDBOff)
    {
      find_distortion(p_Vid, &p_Vid->imgData);
      if(distortion.value[0]+distortion.value[1]+distortion.value[2] <
        p_Vid->p_Dist->metric[SSE].value[0]+
        p_Vid->p_Dist->metric[SSE].value[1]+
        p_Vid->p_Dist->metric[SSE].value[2])
      {
        p_Vid->EvaluateDBOff = 1;
      }
    }
  }

}

 

三、宏块(macroblock)级编码

主体函数:void encode_one_macroblock_high (Macroblock *currMB)

算法过程描述:

  • 保存编码状态(S T O R E   C O D I N G   S T A T E),执行函数:currSlice->store_coding_state (currMB, currSlice->p_RDO->cs_cm);
  • 设置色度预测模式(Set Chroma mode),执行函数:set_chroma_pred_mode(currMB, enc_mb, mb_available, chroma_pred_mode_range);
  • 计算色度预测值(precompute all new chroma intra prediction modes),执行函数:currSlice->intra_chroma_prediction(currMB, &mb_available[0], &mb_available[1], &mb_available[2]);

色度预测算法描述:一个色度宏块大小为8X8,预测模式有四种(0:vertical;1:horizontal;2:DC;3 :plane),在具体实现时,将8X8的宏块分成4个4X4的子块,计算各种预测模式下的预测值存入currSlice->mpr_16x16[uv + 1];(可将currSlice->mpr_16x16[uv + 1];看作一个四维数组currSlice->mpr_16x16[uv + 1][预测模式][色度的行][色度块的列];)

  • 比较各种预测模式下的失真度,选择最佳预测模式,执行函数:currSlice->intra_chroma_RD_decision(currMB, &enc_mb); 
  • 选择最佳的宏块(划分)模式(C H O O S E   B E S T   M A C R O B L O C K   M O D E),核心的编码工作几乎都在下面这个循环内完成。具体来说,对于一个16X16的宏块,可以有多种划分,如4个8X8的块,16个4X4的块等等,而每一种划分的编码性能不一样,因此需要选择一种最佳的模式。对于宏块级的编码而言,这个循环是最重要的了。执行主体:

 for (currMB->c_ipred_mode = chroma_pred_mode_range[0]; currMB->c_ipred_mode<=chroma_pred_mode_range[1]; currMB->c_ipred_mode++)
  {
    // bypass if c_ipred_mode is not allowed
    if ( (p_Vid->yuv_format != YUV400) &&
      (  ((!intra || !p_Inp->IntraDisableInterOnly) && p_Inp->ChromaIntraDisable == 1 && currMB->c_ipred_mode!=DC_PRED_8)
      || (currMB->c_ipred_mode == VERT_PRED_8 && !mb_available[0])
      || (currMB->c_ipred_mode == HOR_PRED_8  && !mb_available[1])
      || (currMB->c_ipred_mode == PLANE_8     && (!mb_available[1] || !mb_available[0] || !mb_available[2]))))
      continue;       

    //===== GET BEST MACROBLOCK MODE =====
    for (index=0; index < max_index; index++)
    {
      mode = mb_mode_table[index]; //tj: mb_mode_table[10]  = {0, 1, 2, 3, P8x8, I16MB, I4MB, I8MB, IPCM, SI4MB};index是连续的值,但mb_mode_table[index]的值却并不连续,与元素定义有关。
      if (enc_mb.valid[mode]) //tj: 比较所有合法的宏块类型下的失真度,比如对于I帧,宏块可以是I16MB、I4MB、IBLOCK和IPCM。valid[MAXMODE];,其中MAXMODE是15。
      {
        if (p_Vid->yuv_format != YUV400)
        {          
          currMB->i16mode = 0;
        }

        // Skip intra modes in inter slices if best mode is inter <P8x8 with cbp equal to 0   
        if (currSlice->P444_joined)
        {
          if (p_Inp->SkipIntraInInterSlices && !intra && mode >= I16MB
            && currMB->best_mode <=3 && currMB->best_cbp == 0 && currSlice->cmp_cbp[1] == 0 && currSlice->cmp_cbp[2] == 0 && (currMB->min_rdcost < weighted_cost(enc_mb.lambda_mdfp,5)))
            continue;
        }
        else
        {
          if (p_Inp->SkipIntraInInterSlices)
          {
            if (!intra && mode >= I4MB)
            {
              if (currMB->best_mode <=3 && currMB->best_cbp == 0 && (currMB->min_rdcost < weighted_cost(enc_mb.lambda_mdfp, 5)))
              {
                continue;
              }
              else if (currMB->best_mode == 0 && (currMB->min_rdcost < weighted_cost(enc_mb.lambda_mdfp,6)))
              {
                continue;
              }
            }
          }
        }

        compute_mode_RD_cost(currMB, &enc_mb, (short) mode, &inter_skip); //tj: 对各种合法的宏块(划分)类型计算代价函数。这个函数很关键,变换、量化、编码都在其中进行。
       
      }
    }// for (index=0; index<max_index; index++)
  }

  • 宏块率失真计算,执行函数:RDCost_for_macroblocks (currMB, enc_mb->lambda_mdfp, mode) ,I 帧16X16的宏块存在多种划分,如分成4X4的子块,需要计算各种划分下的失真度。具体算法待续。
原创粉丝点击