分享

X264源程序分析(x264_slice_write)

 X264 2011-09-19

X264源程序分析(x264_slice_write)  

这些只是暂时的看法,可能有许多“自以为是”的看法。以后回头看看,发现误解之处再更改:) 

static inline void x264_slice_write( x264_t *h, int i_nal_type, int i_nal_ref_idc )

{  

    …… 

    for( mb_xy = 0, i_skip = 0; mb_xy < h->sps->i_mb_width * h->sps->i_mb_height; mb_xy++ )

    {//h->sps->i_mb_width=22; h->sps->i_mb_height=18。两者相乘,确定了一帧内宏块的个数。 

          const int i_mb_y = mb_xy / h->sps->i_mb_width;

          const int i_mb_x = mb_xy % h->sps->i_mb_width;

          //x,y是宏块在slice中的x,y坐标的定位 

            int mb_spos = bs_pos(&h->out.bs);

           /*是把当前宏块的up宏块和left宏块的intra4x4_pred_modenon_zero_count加载进来,放到一个数组里面, 这个数组用来直接得到当前宏块的左侧和上面宏块的相关值.要想得到当前块的预测值,要先知道上面,左面的预测值,它的目的是替代getneighbour函数。*/

           x264_macroblock_cache_load( h, i_mb_x, i_mb_y );

     ————————————————————————————————————————— 

    ·intra4x4_pred_mode[] :一个宏块中,每个4×4的预测模式 

    ·non_zero_count[]:和cbp有关系,说明一个4*4块是否需要进行变换,另外cavlc中也要用到 

    ·static const int x264_scan8[16+2*4] 编码是,每个宏块会用到相邻宏块的信息,这个数据结构,能把一个宏块编码时要用到的信息都包含在内,可以加速编码时的内存访问 

       static const int x264_scan8[16+2*4] =
      {
          
/* Luma */
           4+1*8, 5+1*8, 4+2*8, 5+2*8,
           6+1*8, 7+1*8, 6+2*8, 7+2*8,
           4+3*8, 5+3*8, 4+4*8, 5+4*8, 
           6+3*8, 7+3*8, 6+4*8, 7+4*8,

           /* Cb */
           1+1*8, 2+1*8, 
           1+2*8, 2+2*8,

 
         /* Cr */
           1+4*8, 2+4*8,
           1+5*8, 2+5*8,
       };
       /*
          0 1 2 3 4 5 6 7
          0
          1 B B L L L L
          2 B B L L L L
          3 L L L L
          4 R R L L L L
          5 R R
       */

X264源程序分析(x264_slice_write) - DayDream - 狂奔的蜗牛
 

     ————————————————————————————————————————— 

          /* Slice I: choose I_4x4 or I_16x16 mode

          * Slice P: choose between using P mode or intra (4x4 or 16x16) */

         TIMER_START( i_mtime_analyse );

         x264_macroblock_analyse( h );//通过一系列的SAD算出最优方案。

         TIMER_STOP( i_mtime_analyse );

TIMER_START( i_mtime_analyse );

         x264_macroblock_analyse( h );//通过一系列的SAD算出最优方案。

         TIMER_STOP( i_mtime_analyse );

    —————————————————————————————————————————

         void x264_macroblock_analyse( x264_t *h )

         {   /*--------------------------- Do the analysis ---------------------------*/

               if( h->sh.i_type == SLICE_TYPE_I )

             {

                    /*帧内预测分析(亮度)Try all mode and calculate their score

                      Include 16x16 prediction selection &  4x4 prediction selection */

                      x264_mb_analyse_intra( h, &analysis, COST_MAX );

                     ——————————————————————————

                    static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *res, int i_cost_inter )

                   {     ……

                          predict_16x16_mode_available( h->mb.i_neighbour, predict_mode, &i_max );

                         //根据是否存在topleft值,确定使用什么预测模式(16*16亮度预测模式)

                         predict_4x4_mode_available( h->mb.i_neighbour, idx, predict_mode, &i_max )

                         //根据是否存在topleft值,确定使用什么预测模式(4*4亮度预测模式)

        }

                   ——————————————————————————

                          if( analysis.i_sad_i4x4 < analysis.i_sad_i16x16 )h->mb.i_type = I_4x4;

                        else h->mb.i_type = I_16x16;

                 }

                 else if( h->sh.i_type == SLICE_TYPE_P )

                 {   ……

                          /* Fast P_SKIP detection *///判断是不是SKIP

                          if( ( (i_neighbour&MB_LEFT) && h->mb.type[h->mb.i_mb_xy - 1] == P_SKIP ) ||

                              ( (i_neighbour&MB_TOP) && h->mb.type[h->mb.i_mb_xy - h->mb.i_mb_stride] == P_SKIP ) ||

                             ( ((i_neighbour&(MB_TOP|MB_LEFT)) == (MB_TOP|MB_LEFT) ) && h->mb.type[h->mb.i_mb_xy - h-                              >mb.i_mb_stride-1 ] == P_SKIP ) ||

                            ( (i_neighbour&MB_TOPRIGHT) && h->mb.type[h->mb.i_mb_xy - h->mb.i_mb_stride+1 ] == P_SKIP ) )

                           {b_skip = x264_macroblock_probe_pskip( h ); }

                           if( b_skip )

                         {

                               h->mb.i_type = P_SKIP;

                              h->mb.i_partition = D_16x16;

                          }

                         else//Direct

                        {    ……

                             x264_mb_analyse_load_costs( h, &analysis );

                            //帧间预测 /* Select best inter mode */ /*16*1616*88*168*88*44*84*4*/……

                            /* refine qpel *//*帧间模式选择后,对该模式进行亚象素精细搜索。以进一步减少误差。注意,在前面每个模式的检测时,也要进行亚象素搜索(包括半象素和1/4象素)我怎么觉得好像只有16*16的帧间模式检测中用到了亚像素的搜索呢(主要是这两个函数:x264_mb_predict_mv_ref16x16( h, 0, i_ref, mvc, &i_mvc ); x264_me_search_ref( h, &m, mvc, i_mvc, p_fullpel_thresh );)?*/

                            //帧内预测(亮度

                            x264_mb_analyse_intra( h, &analysis, i_cost );

                           if( h->mb.b_chroma_me && ( analysis.i_sad_i16x16 < i_cost|| ( analysis.i_sad_i4x4 < i_cost )))

                           {    //满足条件后进行色度的帧内预测

                                 x264_mb_analyse_intra_chroma( h, &analysis );

                                analysis.i_sad_i16x16 += analysis.i_sad_i8x8;

                                analysis.i_sad_i4x4 += analysis.i_sad_i8x8;

                            }/*亮度代价分别存在analysis.i_sad_i16x16/i8x8/i4x4中,色度代价存在analysis.i_sad_i8x8chroma中。*/

                         else if( h->sh.i_type == SLICE_TYPE_B )     ……                  

                         /*-------------------- Update MB from the analysis ----------------------*/

                         /*根据上述所判断的结果,进行详细的帧内或帧间预测*/ }

    —————————————————————————————————————————

         /* encode this macrobock -> be carefull it can change the mb type to P_SKIP if needed */

         TIMER_START( i_mtime_encode );

         x264_macroblock_encode( h );

         TIMER_STOP( i_mtime_encode );

/* encode this macrobock -> be carefull it can change the mb type to P_SKIP if needed */

         TIMER_START( i_mtime_encode );

         x264_macroblock_encode( h );

         TIMER_STOP( i_mtime_encode );

—————————————————————————————————————————

void x264_macroblock_encode( x264_t *h )

{

    ……

    /*SKIP片的处理*/

   if( h->mb.i_type == P_SKIP )

   {……}

   if( h->mb.i_type == B_SKIP )

   {……}

    /* quantification scale */

    if( h->mb.i_type == I_16x16 )

   {……

          /* do the right prediction */

         h->predict_16x16[i_mode]( h->mb.pic.p_fdec[0], h->mb.pic.i_stride[0] );

        /*我们看到h->predict_16x16[i_mode]( h->mb.pic.p_fdec[0], h->mb.pic.i_fdec[0] )只调用了一次,这是因为在x264_macroblock_analyse(  )中我们已经确定了采用4种方式中的哪种最合适。*/

         /* encode the 16x16 macroblock */

         x264_mb_encode_i16x16( h, i_qscale );

         /*在这个函数中可以看到量化、zig-扫描、反量化等函数了。包含:

sub16x16_dctquant_4x4scan_zigzag_4x4x264_mb_dequant_4x4dct4x4dc        scan_zigzag_4x4fullidct4x4dcx264_mb_dequant_4x4_dcadd16x16_idct等函数*/

        /* fix the pred mode value */

   ……}

   else if( h->mb.i_type == I_4x4 )

  {

        for( i = 0; i < 16; i++ )

       {……

              x264_mb_encode_i4x4( h, i, i_qscale );

   ……}

   }

   else /* Inter MB */

  {……

       /* Motion compensation */

       x264_mb_mc( h );

       for( i8x8 = 0; i8x8 < 4; i8x8++ )

      {……

          /* encode one 4x4 block */

         ……

         /* decimate this 8x8 block */

    ……

         if( i_decimate_8x8 < 4 ){……}

         if( i_decimate_mb < 6 ){……}

         else

        {

              h->dctf.add16x16_idct( h->mb.pic.p_fdec[0], h->mb.pic.i_stride[0], dct4x4 );

         }//这部分的dedcimate,小徐老师提过。我对它没什么概念,以后再看看。(这一部分是这样的:残差X进行变换和量化后,检查宏块能量,如果太低的话(i_decimate_8x8 < 4及后面的i_decimate_mb < 6 ),可以将其值置为0。它们直接进行熵编码,不需要反量化和反变换了。而其他宏块除了要进行熵编码外,还需要反量化和反变换。)

    }

    /*以上都是亮度分析,下面开始色度分析了*/

    /* encode chroma */

  ……

    /* encode the 8x8 blocks */

    x264_mb_encode_8x8( h, !IS_INTRA( h->mb.i_type ), i_qscale );//对色度块进行编码了.

   /* 这个函数的for循环里面有个2,即对2个色度系数进行编码。*/

    /*下面的代码是计算cbp系数看需要对残差(包括ac,dc)中的哪个系数进行传输。*/

    /* Calculate the Luma/Chroma patern and non_zero_count */

  ……

    /* Calculate the chroma patern *///色度的cbp3种方式.

  ……

    /* store cbp */

  ……

}

—————————————————————————————————————————

       TIMER_START( i_mtime_write );

        /*熵编码部分*/

        TIMER_STOP( i_mtime_write );

/*熵编码部分*///只分析cavlc方式

        TIMER_START( i_mtime_write );

        if( IS_SKIP( h->mb.i_type ) )

        {……

                i_skip++;}

        else

        {……

            else//只分析cavlc编码

            {

                if( h->sh.i_type != SLICE_TYPE_I )

                {

                    bs_write_ue( &h->out.bs, i_skip );  /* skip run */

                    i_skip = 0;

                }

                x264_macroblock_write_cavlc( h, &h->out.bs );

—————————————————————————————————————————

void x264_macroblock_write_cavlc( x264_t *h, bs_t *s )

{……

      /*根据帧类型,确定i_mb_i_offset*/

   ……

      /*cavlc编码*/

      //剩下的代码中,用到了许多bs.h中的函数: bs_write_uebs_writebs_write1bs_write_te//bs_write_se

   ……

       else if( i_mb_type == P_8x8 )

       {……

          x264_sub_mb_mv_write_cavlc( h, s, 0 );

        }

    ……

        /* Coded block patern */

   ……

       /* write residual *///DCAC的亮度、色度残差。这里就要用到x264_macroblock_encode最后一部分求cpb的值了。

       //同时,这部分还要用到函数:block_residual_write_cavlccavlc.c文件中)

}

—————————————————————————————————————————

            }

        }

        TIMER_STOP( i_mtime_write );

        //剩下的就是一些后续工作了。

   ……

       x264_macroblock_cache_save( h );//保存,为下次预测作参考

   ……

}

到此,x264_slice_write函数就简要地分析完毕了。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多