web123456

x264 Loop Filtering Principles Series: x264_frame_deblock_row Function

void x264_frame_deblock_row( x264_t *h, int mb_y ) { int b_interlaced = SLICE_MBAFF; int a = h->sh.i_alpha_c0_offset - QP_BD_OFFSET; int b = h->sh.i_beta_offset - QP_BD_OFFSET; int qp_thresh = 15 - X264_MIN( a, b ) - X264_MAX( 0, h->pps->i_chroma_qp_index_offset ); int stridey = h->fdec->i_stride[0]; int strideuv = h->fdec->i_stride[1]; int chroma_format = CHROMA_FORMAT; int chroma444 = CHROMA444; int chroma_height = 16 >> CHROMA_V_SHIFT; intptr_t uvdiff = chroma444 ? h->fdec->plane[2] - h->fdec->plane[1] : 1; for( int mb_x = 0; mb_x < h->mb.i_mb_width; mb_x += (~b_interlaced | mb_y)&1, mb_y ^= b_interlaced ) { x264_prefetch_fenc( h, h->fdec, mb_x, mb_y ); macroblock_cache_load_neighbours_deblock( h, mb_x, mb_y ); int mb_xy = h->mb.i_mb_xy; int transform_8x8 = h->mb.mb_transform_size[mb_xy]; int intra_cur = IS_INTRA( h->mb.type[mb_xy] ); uint8_t (*bs)[8][4] = h->deblock_strength[mb_y&1][h->param.b_sliced_threads?mb_xy:mb_x]; pixel *pixy = h->fdec->plane[0] + 16*mb_y*stridey + 16*mb_x; pixel *pixuv = CHROMA_FORMAT ? h->fdec->plane[1] + chroma_height*mb_y*strideuv + 16*mb_x : NULL; if( mb_y & MB_INTERLACED ) { pixy -= 15*stridey; if( CHROMA_FORMAT ) pixuv -= (chroma_height-1)*strideuv; } int stride2y = stridey << MB_INTERLACED; int stride2uv = strideuv << MB_INTERLACED; int qp = h->mb.qp[mb_xy]; int qpc = h->chroma_qp_table[qp]; int first_edge_only = (h->mb.partition[mb_xy] == D_16x16 && !h->mb.cbp[mb_xy] && !intra_cur) || qp <= qp_thresh; #define FILTER( intra, dir, edge, qp, chroma_qp )\ do\ {\ if( !(edge & 1) || !transform_8x8 )\ {\ deblock_edge##intra( h, pixy + 4*edge*(dir?stride2y:1),\ stride2y, bs[dir][edge], qp, a, b, 0,\ h->loopf.deblock_luma##intra[dir] );\ if( chroma_format == CHROMA_444 )\ {\ deblock_edge##intra( h, pixuv + 4*edge*(dir?stride2uv:1),\ stride2uv, bs[dir][edge], chroma_qp, a, b, 0,\ h->loopf.deblock_luma##intra[dir] );\ deblock_edge##intra( h, pixuv + uvdiff + 4*edge*(dir?stride2uv:1),\ stride2uv, bs[dir][edge], chroma_qp, a, b, 0,\ h->loopf.deblock_luma##intra[dir] );\ }\ else if( chroma_format == CHROMA_420 && !(edge & 1) )\ {\ deblock_edge##intra( h, pixuv + edge*(dir?2*stride2uv:4),\ stride2uv, bs[dir][edge], chroma_qp, a, b, 1,\ h->loopf.deblock_chroma##intra[dir] );\ }\ }\ if( chroma_format == CHROMA_422 && (dir || !(edge & 1)) )\ {\ deblock_edge##intra( h, pixuv + edge*(dir?4*stride2uv:4),\ stride2uv, bs[dir][edge], chroma_qp, a, b, 1,\ h->loopf.deblock_chroma##intra[dir] );\ }\ } while( 0 ) if( h->mb.i_neighbour & MB_LEFT ) { if( b_interlaced && h->mb.field[h->mb.i_mb_left_xy[0]] != MB_INTERLACED ) { int luma_qp[2]; int chroma_qp[2]; int left_qp[2]; x264_deblock_inter_t luma_deblock = h->loopf.deblock_luma_mbaff; x264_deblock_inter_t chroma_deblock = h->loopf.deblock_chroma_mbaff; x264_deblock_intra_t luma_intra_deblock = h->loopf.deblock_luma_intra_mbaff; x264_deblock_intra_t chroma_intra_deblock = h->loopf.deblock_chroma_intra_mbaff; int c = chroma444 ? 0 : 1; left_qp[0] = h->mb.qp[h->mb.i_mb_left_xy[0]]; luma_qp[0] = (qp + left_qp[0] + 1) >> 1; chroma_qp[0] = (qpc + h->chroma_qp_table[left_qp[0]] + 1) >> 1; if( intra_cur || IS_INTRA( h->mb.type[h->mb.i_mb_left_xy[0]] ) ) { deblock_edge_intra( h, pixy, 2*stridey, bs[0][0], luma_qp[0], a, b, 0, luma_intra_deblock ); if( chroma_format ) { deblock_edge_intra( h, pixuv, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_intra_deblock ); if( chroma444 ) deblock_edge_intra( h, pixuv + uvdiff, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_intra_deblock ); } } else { deblock_edge( h, pixy, 2*stridey, bs[0][0], luma_qp[0], a, b, 0, luma_deblock ); if( chroma_format ) { deblock_edge( h, pixuv, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_deblock ); if( chroma444 ) deblock_edge( h, pixuv + uvdiff, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_deblock ); } } int offy = MB_INTERLACED ? 4 : 0; int offuv = MB_INTERLACED ? 4-CHROMA_V_SHIFT : 0; left_qp[1] = h->mb.qp[h->mb.i_mb_left_xy[1]]; luma_qp[1] = (qp + left_qp[1] + 1) >> 1; chroma_qp[1] = (qpc + h->chroma_qp_table[left_qp[1]] + 1) >> 1; if( intra_cur || IS_INTRA( h->mb.type[h->mb.i_mb_left_xy[1]] ) ) { deblock_edge_intra( h, pixy + (stridey<<offy), 2*stridey, bs[0][4], luma_qp[1], a, b, 0, luma_intra_deblock ); if( chroma_format ) { deblock_edge_intra( h, pixuv + (strideuv<<offuv), 2*strideuv, bs[0][4], chroma_qp[1], a, b, c, chroma_intra_deblock ); if( chroma444 ) deblock_edge_intra( h, pixuv + uvdiff + (strideuv<<offuv), 2*strideuv, bs[0][4], chroma_qp[1], a, b, c, chroma_intra_deblock ); } } else { deblock_edge( h, pixy + (stridey<<offy), 2*stridey, bs[0][4], luma_qp[1], a, b, 0, luma_deblock ); if( chroma_format ) { deblock_edge( h, pixuv + (strideuv<<offuv), 2*strideuv, bs[0][4], chroma_qp[1], a, b, c, chroma_deblock ); if( chroma444 ) deblock_edge( h, pixuv + uvdiff + (strideuv<<offuv), 2*strideuv, bs[0][4], chroma_qp[1], a, b, c, chroma_deblock ); } } } else { int qpl = h->mb.qp[h->mb.i_mb_xy-1]; int qp_left = (qp + qpl + 1) >> 1; int qpc_left = (qpc + h->chroma_qp_table[qpl] + 1) >> 1; int intra_left = IS_INTRA( h->mb.type[h->mb.i_mb_xy-1] ); int intra_deblock = intra_cur || intra_left; /* Any MB that was coded, or that analysis decided to skip, has quality commensurate with its QP. * But if deblocking affects neighboring MBs that were force-skipped, blur might accumulate there. * So reset their effective QP to max, to indicate that lack of guarantee. */ if( h->fdec->mb_info && M32( bs[0][0] ) ) { #define RESET_EFFECTIVE_QP(xy) h->fdec->effective_qp[xy] |= 0xff * !!(h->fdec->mb_info[xy] & X264_MBINFO_CONSTANT); RESET_EFFECTIVE_QP(mb_xy); RESET_EFFECTIVE_QP(h->mb.i_mb_left_xy[0]); } if( intra_deblock ) FILTER( _intra, 0, 0, qp_left, qpc_left ); else FILTER( , 0, 0, qp_left, qpc_left ); } } if( !first_edge_only ) { FILTER( , 0, 1, qp, qpc ); FILTER( , 0, 2, qp, qpc ); FILTER( , 0, 3, qp, qpc ); } if( h->mb.i_neighbour & MB_TOP ) { if( b_interlaced && !(mb_y&1) && !MB_INTERLACED && h->mb.field[h->mb.i_mb_top_xy] ) { int mbn_xy = mb_xy - 2 * h->mb.i_mb_stride; for( int j = 0; j < 2; j++, mbn_xy += h->mb.i_mb_stride ) { int qpt = h->mb.qp[mbn_xy]; int qp_top = (qp + qpt + 1) >> 1; int qpc_top = (qpc + h->chroma_qp_table[qpt] + 1) >> 1; int intra_top = IS_INTRA( h->mb.type[mbn_xy] ); if( intra_cur || intra_top ) M32( bs[1][4*j] ) = 0x03030303; // deblock the first horizontal edge of the even rows, then the first horizontal edge of the odd rows deblock_edge( h, pixy + j*stridey, 2* stridey, bs[1][4*j], qp_top, a, b, 0, h->loopf.deblock_luma[1] ); if( chroma444 ) { deblock_edge( h, pixuv + j*strideuv, 2*strideuv, bs[1][4*j], qpc_top, a, b, 0, h->loopf.deblock_luma[1] ); deblock_edge( h, pixuv + uvdiff + j*strideuv, 2*strideuv, bs[1][4*j], qpc_top, a, b, 0, h->loopf.deblock_luma[1] ); } else if( chroma_format ) deblock_edge( h, pixuv + j*strideuv, 2*strideuv, bs[1][4*j], qpc_top, a, b, 1, h->loopf.deblock_chroma[1] ); } } else { int qpt = h->mb.qp[h->mb.i_mb_top_xy]; int qp_top = (qp + qpt + 1) >> 1; int qpc_top = (qpc + h->chroma_qp_table[qpt] + 1) >> 1; int intra_top = IS_INTRA( h->mb.type[h->mb.i_mb_top_xy] ); int intra_deblock = intra_cur || intra_top; /* This edge has been modified, reset effective qp to max. */ if( h->fdec->mb_info && M32( bs[1][0] ) ) { RESET_EFFECTIVE_QP(mb_xy); RESET_EFFECTIVE_QP(h->mb.i_mb_top_xy); } if( (!b_interlaced || (!MB_INTERLACED && !h->mb.field[h->mb.i_mb_top_xy])) && intra_deblock ) { FILTER( _intra, 1, 0, qp_top, qpc_top ); } else { if( intra_deblock ) M32( bs[1][0] ) = 0x03030303; FILTER( , 1, 0, qp_top, qpc_top ); } } } if( !first_edge_only ) { FILTER( , 1, 1, qp, qpc ); FILTER( , 1, 2, qp, qpc ); FILTER( , 1, 3, qp, qpc ); } #undef FILTER } }