x264macroblockanalyse模块分析.docx

上传人:b****4 文档编号:12096128 上传时间:2023-04-17 格式:DOCX 页数:10 大小:18.38KB
下载 相关 举报
x264macroblockanalyse模块分析.docx_第1页
第1页 / 共10页
x264macroblockanalyse模块分析.docx_第2页
第2页 / 共10页
x264macroblockanalyse模块分析.docx_第3页
第3页 / 共10页
x264macroblockanalyse模块分析.docx_第4页
第4页 / 共10页
x264macroblockanalyse模块分析.docx_第5页
第5页 / 共10页
点击查看更多>>
下载资源
资源描述

x264macroblockanalyse模块分析.docx

《x264macroblockanalyse模块分析.docx》由会员分享,可在线阅读,更多相关《x264macroblockanalyse模块分析.docx(10页珍藏版)》请在冰豆网上搜索。

x264macroblockanalyse模块分析.docx

x264macroblockanalyse模块分析

【原创】x264_macroblock_analyse模块分析

本文对x264_macroblock_analyse()及其子函数的流程进行详尽的分析。

希望对大家有所帮助。

参考x264_050530版本。

1、voidx264_macroblock_analyse(x264_t*h)

首先初始化函数,然后进入一个选择语句

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

{

……..

}

elseif(h->sh.i_type==SLICE_TYPE_P)

{

……..

}

elseif(h->sh.i_type==SLICE_TYPE_B)

{

………

}

很明显,这是对不同类型的块采用不同的处理步骤,我们就进入SLICE_TYPE_P深入分析一下吧,因为P类型包含有I模式的检测,SLICE_TYPE_B只是SLICE_TYPE_P的简单延伸而已。

if(h->param.analyse.b_fast_pskip)

{

if(h->param.analyse.i_subpel_refine>=3)

analysis.b_try_pskip=1;

elseif(h->mb.i_mb_type_left==P_SKIP||

h->mb.i_mb_type_top==P_SKIP||

h->mb.i_mb_type_topleft==P_SKIP||

h->mb.i_mb_type_topright==P_SKIP)

b_skip=x264_macroblock_probe_pskip(h);

}

条件进入后首先判断skip模式,如果满足skip模式则判断结束,否则继续下面的判断。

x264_mb_analyse_inter_p16x16(h,&analysis);

if(flags&X264_ANALYSE_PSUB16x16)

{

if(h->param.analyse.b_mixed_references)

x264_mb_analyse_inter_p8x8_mixed_ref(h,&analysis);else

x264_mb_analyse_inter_p8x8(h,&analysis);

}

分析16×16和8×8模式。

模式代价值分别保存在和analysis.l0.me16x16.cost、analysis.l0.i_cost8x8中。

if((flags&X264_ANALYSE_PSUB16x16)&&analysis.l0.i_cost8x8

{

…….

}

如果8×8代价值小于16×16,则进行子宏块分割的判断。

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

{

x264_mb_analyse_inter_p4x4(h,&analysis,i);

if(analysis.l0.i_cost4x4[i]

{

………

}

依次对4个子宏块(8×8)进行处理,x264_mb_analyse_inter_p4x4()函数实际上是得到4个4×4块的代价和analysis.l0.i_cost4x4[i]。

如果4×4模式优于8×8模式,才进行8×8块的细分割。

细分割代码分析略。

if((flags&X264_ANALYSE_PSUB16x16)&&analysis.l0.i_cost8x8

{

x264_mb_analyse_inter_p16x8(h,&analysis);

……..

x264_mb_analyse_inter_p8x16(h,&analysis);

……...

}

紧接着检测16×8和8×16模式

x264_me_refine_qpel(h,&analysis.l0.me16x16);

……..

帧间模式选择后,对该模式进行亚象素精细搜索。

以进一步减少误差。

值得注意的是,在前面每个模式的检测时,也要进行亚象素搜索,见x264_me_search_ref()函数的最后几行。

这里的亚象素搜索是在前面基础上再进行精细搜索的。

二者亚象素搜索(包括半象素和1/4象素)的次数由subpel_iterations[i][4]确定,而i由编译参数subme确定,看运行帮助:

-m,--submeSubpixelmotionestimationquality:

1=fast,5=best

实际上subme就是决定模式选择前后亚象素估计的点数。

Subme越大,压缩效率越好,计算量越大。

x264_mb_analyse_intra(h,&analysis,i_cost);

if(h->mb.b_chroma_me&&!

analysis.b_mbrd&&

(analysis.i_sad_i16x16

||analysis.i_sad_i8x8

||analysis.i_sad_i4x4

{

x264_mb_analyse_intra_chroma(h,&analysis);

analysis.i_sad_i16x16+=analysis.i_sad_i8x8chroma;

analysis.i_sad_i8x8+=analysis.i_sad_i8x8chroma;

analysis.i_sad_i4x4+=analysis.i_sad_i8x8chroma;

}

分析宏块的帧内编码,包括亮度和色度。

亮度的16×16、8×8、4×4代价分别存在analysis.i_sad_i16x16、analysis.i_sad_i8x8、analysis.i_sad_i4x4中,色度代价存在analysis.i_sad_i8x8chroma中。

i_intra_type=I_16x16;

i_intra_cost=analysis.i_sad_i16x16;

if(analysis.i_sad_i8x8

{

i_intra_type=I_8x8;

i_intra_cost=analysis.i_sad_i8x8;

}

if(analysis.i_sad_i4x4

{

i_intra_type=I_4x4;

i_intra_cost=analysis.i_sad_i4x4;

}

if(i_intra_cost

{

i_type=i_intra_type;

i_cost=i_intra_cost;

}

比较得到最佳的帧内预测模式。

if(i_intra_cost

{

i_type=i_intra_type;

i_cost=i_intra_cost;

}

帧内代价与帧间代价比较,得到最佳的预测模式。

整个P类型就分析完了,然后看看条件跳出以后执行什么

if(!

analysis.b_mbrd)

x264_mb_analyse_transform(h);

判断变换的时候是采用8×8变换还是4×4变换。

这样,怎么函数就分析完了^_^,下面看看调用的重要子函数。

欢迎浏览我的blog:

 

2、staticinlineintx264_macroblock_probe_pskip(x264_t*h)

该函数直接调用了x264_macroblock_probe_skip(h,0);看看里边有什么东东。

if(!

b_bidir)

{

x264_mb_predict_mv_pskip(h,mvp);

mvp[0]=x264_clip3(mvp[0],h->mb.mv_min[0],h->mb.mv_max[0]);

mvp[1]=x264_clip3(mvp[1],h->mb.mv_min[1],h->mb.mv_max[1]);

h->mc.mc_luma(h->mb.pic.p_fref[0][0],h->mb.pic.i_stride[0],

h->mb.pic.p_fdec[0],FDEC_STRIDE,

mvp[0],mvp[1],16,16);

}

先得到预测矢量MVp,然后对MVp进行饱和处理,再进行相应的运动补偿。

h->dctf.sub16x16_dct(dct4x4,h->mb.pic.p_fenc[0],FENC_STRIDE,

h->mb.pic.p_fdec[0],FDEC_STRIDE);

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

{

/*encodeone4x4block*/

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

{

constintidx=i8x8*4+i4x4;

quant_4x4(h,dct4x4[idx],(int(*)[4][4])def_quant4_mf,i_qp,0);

scan_zigzag_4x4full(dctscan,dct4x4[idx]);

i_decimate_mb+=x264_mb_decimate_score(dctscan,16);

if(i_decimate_mb>=6)

{

/*notasP_SKIP*/

return0;

}

}

}

进行dct变换(注意是4×4变换,不是8×8!

),然后对每个8×8块中的4×4对进行量化,zigzag扫描,得到8×8块的i_decimate_mb值。

如果量化后系数中只有零星的非零系数,且都是1或-1,i_decimate_mb就比较小。

if(i_decimate_mb<6),可以将系数全变为0。

注意,其他模式下的残差编码也用到了该处理过程。

程序后面是对色度进行处理,与亮度类似,不进行讨论。

3、staticvoidx264_mb_analyse_inter_p16x16(x264_t*h,x264_mb_analysis_t*a)

直接看核心吧。

for(i_ref=0;i_refi_ref0;i_ref++)

{

循环搜索搜索每个参考帧

x264_mb_predict_mv_16x16(h,0,i_ref,m.mvp);

得到MVp,

x264_mb_predict_mv_ref16x16(h,0,i_ref,mvc,&i_mvc);

得到邻块的MV、前一帧对应位置的MV,可用来预测搜索起点,加速运动估计。

x264_me_search_ref(h,&m,mvc,i_mvc,p_halfpel_thresh);

运动估计函数。

下面将详细讨论

再接着就是一个多参考帧的中止判断,略。

4、voidx264_me_search_ref(x264_t*h,x264_me_t*m,int(*mvc)[2],inti_mvc,int*p_halfpel_thresh)

bmx=pmx=x264_clip3((m->mvp[0]+2)>>2,mv_x_min,mv_x_max);

bmy=pmy=x264_clip3((m->mvp[1]+2)>>2,mv_y_min,mv_y_max);

bcost=COST_MAX;

COST_MV(pmx,pmy);

bcost-=p_cost_mvx[bmx<<2]+p_cost_mvy[bmy<<2];

for(i=0;i

{

constintmx=x264_clip3((mvc[i][0]+2)>>2,mv_x_min,mv_x_max);

constintmy=x264_clip3((mvc[i][1]+2)>>2,mv_y_min,mv_y_max);

if(mx!

=bmx||my!

=bmy)

COST_MV(mx,my);

}

COST_MV(0,0);

先检测MVp点,再检测其他预测矢量,最后检测原点(0,0)。

注意mvp[0

]保留的是1/4精度,所以除以4就变成了整象素精度。

然后就是具体的搜索算法。

代码不贴,直接解释吧。

^_^

case菱形搜索:

用小菱形模板反复搜索。

菱形算法还有大模板搜索,这里没用到。

case六边形:

先用六边形模板反复搜索,粗匹配。

然后用小菱形模板搜索一次,得到最终的整象素运动矢量

caseUMHexagonS:

看我主页中的注释,呵呵,是基于JM9.5的。

case连续消除法(SEA)全搜索法的快速运算。

这里不介绍了。

if(h->mb.i_subpel_refine>=2)

{

inthpel=subpel_iterations[h->mb.i_subpel_refine][2];

intqpel=subpel_iterations[h->mb.i_subpel_refine][3];

refine_subpel(h,m,hpel,qpel,p_halfpel_thresh,0);

}

亚象素搜索,在x264_macroblock_analyse()函数我已经介绍过了

5、voidx264_me_refine_qpel(x264_t*h,x264_me_t*m)

该函数一开始得到半象素、1/4象素搜索的次数(菱形小模板),分别为hpel、qhpel,然后调用refine_subpel(),去看看!

if(hpel_iters)

{

intmx=x264_clip3(m->mvp[0],h->mb.mv_min_spel[0],h->mb.mv_max_spel[0]);

intmy=x264_clip3(m->mvp[1],h->mb.mv_min_spel[1],h->mb.mv_max_spel[1]);

if(mx!

=bmx||my!

=bmy)

COST_MV_SAD(mx,my,-1);

}

检测MVp的小数精度。

for(i=hpel_iters;i>0;i--)

{

odir=bdir;

omx=bmx;

omy=bmy;

COST_MV_SAD(omx,omy-2,0);

COST_MV_SAD(omx,omy+2,1);

COST_MV_SAD(omx-2,omy,2);

COST_MV_SAD(omx+2,omy,3);

if(bmx==omx&&bmy==omy)

break;

}

对半象素精度进行hpel_iters次小菱形搜索。

后面有1/4象素精度的qpel_iters次小模板搜索,略。

6、staticuint8_t*get_ref(uint8_t*src[4],inti_src_stride,uint8_t*dst,int*i_dst_stride,intmvx,intmvy,inti_width,inti_height)

该函数得到亚象素搜索时参考块的指针。

src1、src2分别指向半象素精度块。

1/4搜索时需要临时插值,就是pixel_avg()函数的只能功能。

值得注意的是变量correction的作用,当作是1/4插值时的偏移量吧。

N个人问过我,其实结合1/4象素插值,仔细推导一下就出来了。

7、staticvoidx264_mb_analyse_intra(x264_t*h,x264_mb_analysis_t*a,inti_cost_inter)

依次检测Intra_16x16、Intra4x4、Intra8x8的最佳模式。

值得注意,if(subme<=1)

h->pixf.mbcmp是求sad值

else

h->pixf.mbcmp是求satd值

另外,对与Intra4x4、Intra8x8,此时就要进行真正的变换量化、反变换反量化、重建,因为要为后续的块做参考。

而且,就算其系数值很小,也不能改变cbp,切记切记。

具体分析略。

8、staticinlinevoidx264_mb_analyse_transform(x264_t*h)

就是对残差进行4x4、8x8的satd变换,比较绝对和值,值较小对应的尺寸用于变换的尺寸。

欢迎浏览我的blog:

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 其它

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1