x264源码分析 -- x264_slicetype_mb_cost
来源:互联网 发布:游戏王软件 编辑:程序博客网 时间:2024/05/21 04:42
static int x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a,x264_frame_t **frames, int p0/*前向索引*/, int p1/*后向索引*/, int b/*当前索引*/, int dist_scale_factor, int do_search[2] ){ x264_frame_t *fref0 = frames[p0]; x264_frame_t *fref1 = frames[p1]; x264_frame_t *fenc = frames[b]; const int b_bidir = (b < p1); // 是否进行后向参考, 也就是当前帧是否是B帧 const int i_mb_x = h->mb.i_mb_x; // 预测宏块的X坐标 const int i_mb_y = h->mb.i_mb_y; // 预测宏块的Y坐标 const int i_mb_stride = h->sps->i_mb_width; // 以宏块为单位的宽度 const int i_mb_xy = i_mb_x + i_mb_y * i_mb_stride; // 二维坐标转换到一维坐标 const int i_stride = fenc->i_stride_lowres; // 待编码sub-pixel平面的跨度 const int i_pel_offset = 8 * ( i_mb_x + i_mb_y * i_stride ); const int i_bipred_weight = h->param.analyse.b_weighted_bipred ? 64 - (dist_scale_factor>>2) : 32; // 双向预测权重// [0][b-p0-1][i_mb_xy]: 前向预测宏块的索引 [1][p1-b-1][i_mb_xy]: 后向预测宏块的索引// fenc_mvs: 前后参考帧位置i_mb_xy的宏块mv int16_t (*fenc_mvs[2])[2] = { &frames[b]->lowres_mvs[0][b-p0-1][i_mb_xy], &frames[b]->lowres_mvs[1][p1-b-1][i_mb_xy] }; int (*fenc_costs[2]) = { &frames[b]->lowres_mv_costs[0][b-p0-1][i_mb_xy], &frames[b]->lowres_mv_costs[1][p1-b-1][i_mb_xy] }; ALIGNED_8( uint8_t pix1[9*FDEC_STRIDE] ); uint8_t *pix2 = pix1+8; x264_me_t m[2]; int i_bcost = COST_MAX; int l, i; int list_used = 0; h->mb.pic.p_fenc[0] = h->mb.pic.fenc_buf; h->mc.copy[PIXEL_8x8]( h->mb.pic.p_fenc[0], FENC_STRIDE, &fenc->lowres[0][i_pel_offset], i_stride, 8 ); // 拷贝1/2像素Origin平面(8x8) if( p0 == p1 ) // 前向索引=后向索引, 则进行I帧处理 goto lowres_intra_mb; // no need for h->mb.mv_min[]// 设置前向全像素预测范围 h->mb.mv_min_fpel[0] = -8*h->mb.i_mb_x - 4; h->mb.mv_max_fpel[0] = 8*( h->sps->i_mb_width - h->mb.i_mb_x - 1 ) + 4;// 设置前向半像素预测范围 h->mb.mv_min_spel[0] = 4*( h->mb.mv_min_fpel[0] - 8 ); h->mb.mv_max_spel[0] = 4*( h->mb.mv_max_fpel[0] + 8 ); if( h->mb.i_mb_x >= h->sps->i_mb_width - 2 ) // 如果当前宏块是倒数1,2列, 设置后向预测范围. 为什么倒数1,2行的时候不这么做? { h->mb.mv_min_fpel[1] = -8*h->mb.i_mb_y - 4; h->mb.mv_max_fpel[1] = 8*( h->sps->i_mb_height - h->mb.i_mb_y - 1 ) + 4; h->mb.mv_min_spel[1] = 4*( h->mb.mv_min_fpel[1] - 8 ); h->mb.mv_max_spel[1] = 4*( h->mb.mv_max_fpel[1] + 8 ); }// 装载1/2像素各个平面(原, 水平, 垂直, 对角线)#define LOAD_HPELS_LUMA(dst, src) \ { \ (dst)[0] = &(src)[0][i_pel_offset]; \ (dst)[1] = &(src)[1][i_pel_offset]; \ (dst)[2] = &(src)[2][i_pel_offset]; \ (dst)[3] = &(src)[3][i_pel_offset]; \ }// mv不能超过搜索范围#define CLIP_MV( mv ) \ { \ mv[0] = x264_clip3( mv[0], h->mb.mv_min_spel[0], h->mb.mv_max_spel[0] ); \ mv[1] = x264_clip3( mv[1], h->mb.mv_min_spel[1], h->mb.mv_max_spel[1] ); \ }// NOTES>> 用亮度块代替整个宏块的复杂度// src1/2: 分别以mv前/后向偏移得到的8x8块// pix1: src1和src2的中值块// h->pixf.mbcmp[PIXEL_8x8]: 计算8x8块的SATD值#define TRY_BIDIR( mv0, mv1, penalty ) \ { \ int stride1 = 16, stride2 = 16; \ uint8_t *src1, *src2; \ int i_cost; \ src1 = h->mc.get_ref( pix1, &stride1, m[0].p_fref, m[0].i_stride[0], \ (mv0)[0], (mv0)[1], 8, 8 ); /*前向预测出8x8宏块src1*/ \ src2 = h->mc.get_ref( pix2, &stride2, m[1].p_fref, m[1].i_stride[0], \ (mv1)[0], (mv1)[1], 8, 8 ); /*后向预测出8x8宏块src2*/ \ h->mc.avg[PIXEL_8x8]( pix1, 16, src1, stride1, src2, stride2, i_bipred_weight ); /*根据src1和src2中值计算出pix1*/ \ i_cost = penalty + h->pixf.mbcmp[PIXEL_8x8]( \ m[0].p_fenc[0], FENC_STRIDE, pix1, 16 ); /*计算原像素和pix1的残差cost*/\ COPY2_IF_LT( i_bcost, i_cost, list_used, 3 ); \ } m[0].i_pixel = PIXEL_8x8; m[0].p_cost_mv = a->p_cost_mv; m[0].i_stride[0] = i_stride; m[0].p_fenc[0] = h->mb.pic.p_fenc[0]; LOAD_HPELS_LUMA( m[0].p_fref, fref0->lowres ); // 装载{前向参考帧}的半像素平面 if( b_bidir ) // 如果是B帧 { int16_t *mvr = fref1->lowres_mvs[0][p1-p0-1][i_mb_xy]; // 后向参考帧 的 前向参考帧 对应i_mb_xy的宏块 int dmv[2][2]; h->mc.memcpy_aligned( &m[1], &m[0], sizeof(x264_me_t) ); LOAD_HPELS_LUMA( m[1].p_fref, fref1->lowres ); // 装载{后向参考帧}的半像素平面// 根据dist_scale_factor计算出一组双向MV dmv[0][0] = ( mvr[0] * dist_scale_factor + 128 ) >> 8; dmv[0][1] = ( mvr[1] * dist_scale_factor + 128 ) >> 8; dmv[1][0] = dmv[0][0] - mvr[0]; dmv[1][1] = dmv[0][1] - mvr[1]; CLIP_MV( dmv[0] ); CLIP_MV( dmv[1] ); TRY_BIDIR( dmv[0], dmv[1], 0 ); // 根据这组MV计算双向预测cost if( dmv[0][0] | dmv[0][1] | dmv[1][0] | dmv[1][1] ) // 如果mv都不为0, 以 前后向参考帧的第一个8x8宏块预测 { int i_cost; h->mc.avg[PIXEL_8x8]( pix1, 16, m[0].p_fref[0], m[0].i_stride[0], m[1].p_fref[0], m[1].i_stride[0], i_bipred_weight ); i_cost = h->pixf.mbcmp[PIXEL_8x8]( m[0].p_fenc[0], FENC_STRIDE, pix1, 16 ); COPY2_IF_LT( i_bcost, i_cost, list_used, 3 ); } } for( l = 0; l < 1 + b_bidir; l++ ) { if( do_search[l] ) { int i_mvc = 0; int16_t (*fenc_mv)[2] = fenc_mvs[l]; // 每个参考帧中每个宏块的MV ALIGNED_4( int16_t mvc[4][2] ); /* Reverse-order MV prediction. */ *(uint32_t*)mvc[0] = 0; *(uint32_t*)mvc[1] = 0; *(uint32_t*)mvc[2] = 0;#define MVC(mv) { *(uint32_t*)mvc[i_mvc] = *(uint32_t*)mv; i_mvc++; } if( i_mb_x < h->sps->i_mb_width - 1 ) MVC(fenc_mv[1]); if( i_mb_y < h->sps->i_mb_height - 1 ) { MVC(fenc_mv[i_mb_stride]); if( i_mb_x > 0 ) MVC(fenc_mv[i_mb_stride-1]); if( i_mb_x < h->sps->i_mb_width - 1 ) MVC(fenc_mv[i_mb_stride+1]); }#undef MVC x264_median_mv( m[l].mvp, mvc[0], mvc[1], mvc[2] ); // 中值预测MV x264_me_search( h, &m[l], mvc, i_mvc ); // ** 这里只计算最小SATD_cost **, 应该是为了rate_control m[l].cost -= 2; // remove mvcost from skip mbs if( *(uint32_t*)m[l].mv ) m[l].cost += 5; *(uint32_t*)fenc_mvs[l] = *(uint32_t*)m[l].mv; // 更新预测后得到的MV *fenc_costs[l] = m[l].cost; } else // 不用预测了 { *(uint32_t*)m[l].mv = *(uint32_t*)fenc_mvs[l]; // 直接使用参考帧的MV m[l].cost = *fenc_costs[l]; // 直接使用参考帧的MV_cost } COPY2_IF_LT( i_bcost, m[l].cost, list_used, l+1 ); } if( b_bidir && ( *(uint32_t*)m[0].mv || *(uint32_t*)m[1].mv ) ) TRY_BIDIR( m[0].mv, m[1].mv, 5 ); /* Store to width-2 bitfield. */ frames[b]->lowres_inter_types[b-p0][p1-b][i_mb_xy>>2] &= ~(3<<((i_mb_xy&3)*2)); frames[b]->lowres_inter_types[b-p0][p1-b][i_mb_xy>>2] |= list_used<<((i_mb_xy&3)*2);lowres_intra_mb: /* forbid intra-mbs in B-frames, because it's rare and not worth checking */ /* FIXME: Should we still forbid them now that we cache intra scores? */ if( !b_bidir || h->param.rc.b_mb_tree ) // 帧内计算SATD { int i_icost, b_intra; if( !fenc->b_intra_calculated ) { ALIGNED_ARRAY_16( uint8_t, edge,[33] ); uint8_t *pix = &pix1[8+FDEC_STRIDE - 1]; uint8_t *src = &fenc->lowres[0][i_pel_offset - 1]; const int intra_penalty = 5; int satds[4]; memcpy( pix-FDEC_STRIDE, src-i_stride, 17 ); for( i=0; i<8; i++ ) pix[i*FDEC_STRIDE] = src[i*i_stride]; pix++; if( h->pixf.intra_mbcmp_x3_8x8c ) { h->pixf.intra_mbcmp_x3_8x8c( h->mb.pic.p_fenc[0], pix, satds ); h->predict_8x8c[I_PRED_CHROMA_P]( pix ); satds[I_PRED_CHROMA_P] = h->pixf.mbcmp[PIXEL_8x8]( pix, FDEC_STRIDE, h->mb.pic.p_fenc[0], FENC_STRIDE ); } else { for( i=0; i<4; i++ ) { h->predict_8x8c[i]( pix ); satds[i] = h->pixf.mbcmp[PIXEL_8x8]( pix, FDEC_STRIDE, h->mb.pic.p_fenc[0], FENC_STRIDE ); } } i_icost = X264_MIN4( satds[0], satds[1], satds[2], satds[3] ); h->predict_8x8_filter( pix, edge, ALL_NEIGHBORS, ALL_NEIGHBORS ); for( i=3; i<9; i++ ) { int satd; h->predict_8x8[i]( pix, edge ); satd = h->pixf.mbcmp[PIXEL_8x8]( pix, FDEC_STRIDE, h->mb.pic.p_fenc[0], FENC_STRIDE ); i_icost = X264_MIN( i_icost, satd ); } i_icost += intra_penalty; fenc->i_intra_cost[i_mb_xy] = i_icost; } else i_icost = fenc->i_intra_cost[i_mb_xy]; if( !b_bidir ) { b_intra = i_icost < i_bcost; if( b_intra ) i_bcost = i_icost; if( (i_mb_x > 0 && i_mb_x < h->sps->i_mb_width - 1 && i_mb_y > 0 && i_mb_y < h->sps->i_mb_height - 1) || h->sps->i_mb_width <= 2 || h->sps->i_mb_height <= 2 ) { fenc->i_intra_mbs[b-p0] += b_intra; fenc->i_cost_est[0][0] += i_icost; if( h->param.rc.i_aq_mode ) fenc->i_cost_est_aq[0][0] += (i_icost * fenc->i_inv_qscale_factor[i_mb_xy] + 128) >> 8; } } } fenc->lowres_costs[b-p0][p1-b][i_mb_xy] = i_bcost; // i_mb_xy位置的宏块, 前向参考p0, 后向参考p1时的cost值 return i_bcost;}#undef TRY_BIDIR
0 0
- x264源码分析 -- x264_slicetype_mb_cost
- x264 - x264_slicetype_mb_cost
- x264源码分析
- x264源码分析
- x264 源码分析 (1)
- x264 源码分析 (2)
- x264 源码分析 (3)
- x264 源码分析 (4)
- x264 源码分析 (5)
- x264 源码分析 (6)
- X264源码分析
- x264源码分析 -- get_ref
- x264源码分析 -- x264_slicetype_path
- x264源码分析 -- frame_init_lowres_core
- x264命令行工具(x264.exe)源码整体分析
- x264源码分析三:x264_slices_write和x264_slice_write函数分析
- X264分析
- x264分析
- 在asp中调用sql server的存储过程方法
- Word 打不开 解决方法
- 第十二周上机项目二
- Oracle游标使用参考语句
- SDUT -refresh的停车场(栈和队列)
- x264源码分析 -- x264_slicetype_mb_cost
- FBReader Amdroid源码
- 一些 Oracle Sql 语句的使用
- Android:Layout_weight的深刻理解
- 一个简单的easyui动态初始化datagrid的列名的实例
- POI读取Excel浅谈
- Poi 读写Excel 合并ExcelSheet Struts2实现
- Android笔记一.深入理解Intent和IntentFilters(一)
- Linux 下FTP搭建