From: Fiona Glaser Date: Mon, 5 Oct 2009 02:15:28 +0000 (-0700) Subject: Constrained intra prediction support X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7639d496ccc83f28166471d3a2a54292110f572c;p=libx264 Constrained intra prediction support Enable with --constrained-intra. Significantly reduces compression, but required for the base layer of SVC encodes and maybe some other use-cases. Commit sponsored by a media streaming company that wishes to remain anonymous. --- diff --git a/common/common.c b/common/common.c index 648c75a2..fe02d657 100644 --- a/common/common.c +++ b/common/common.c @@ -76,6 +76,8 @@ void x264_param_default( x264_param_t *param ) param->i_bframe_adaptive = X264_B_ADAPT_FAST; param->i_bframe_bias = 0; param->b_bframe_pyramid = 0; + param->b_interlaced = 0; + param->b_constrained_intra = 0; param->b_deblocking_filter = 1; param->i_deblocking_filter_alphac0 = 0; @@ -394,6 +396,8 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) p->i_cabac_init_idc = atoi(value); OPT("interlaced") p->b_interlaced = atobool(value); + OPT("constrained-intra") + p->b_constrained_intra = atobool(value); OPT("cqm") { if( strstr( value, "flat" ) ) @@ -890,6 +894,7 @@ char *x264_param2string( x264_param_t *p, int b_res ) s += sprintf( s, " nr=%d", p->analyse.i_noise_reduction ); s += sprintf( s, " decimate=%d", p->analyse.b_dct_decimate ); s += sprintf( s, " mbaff=%d", p->b_interlaced ); + s += sprintf( s, " constrained_intra=%d", p->b_constrained_intra ); s += sprintf( s, " bframes=%d", p->i_bframe ); if( p->i_bframe ) diff --git a/common/common.h b/common/common.h index 0498139b..a0afedab 100644 --- a/common/common.h +++ b/common/common.h @@ -461,6 +461,7 @@ struct x264_t unsigned int i_neighbour; unsigned int i_neighbour8[4]; /* neighbours of each 8x8 or 4x4 block that are available */ unsigned int i_neighbour4[16]; /* at the time the block is coded */ + unsigned int i_neighbour_intra; /* for constrained intra pred */ int i_mb_type_top; int i_mb_type_left; int i_mb_type_topleft; diff --git a/common/macroblock.c b/common/macroblock.c index 4ba66d1e..f27152f0 100644 --- a/common/macroblock.c +++ b/common/macroblock.c @@ -896,16 +896,20 @@ void x264_macroblock_cache_load( x264_t *h, int i_mb_x, int i_mb_y ) h->mb.i_b4_xy = i_mb_4x4; h->mb.i_mb_top_xy = i_top_xy; h->mb.i_neighbour = 0; + h->mb.i_neighbour_intra = 0; /* load cache */ if( i_top_xy >= h->sh.i_first_mb ) { h->mb.i_mb_type_top = - i_top_type= h->mb.type[i_top_xy]; + i_top_type = h->mb.type[i_top_xy]; h->mb.cache.i_cbp_top = h->mb.cbp[i_top_xy]; h->mb.i_neighbour |= MB_TOP; + if( !h->param.b_constrained_intra || IS_INTRA( i_top_type ) ) + h->mb.i_neighbour_intra |= MB_TOP; + /* load intra4x4 */ *(uint32_t*)&h->mb.cache.intra4x4_pred_mode[x264_scan8[0] - 8] = *(uint32_t*)&h->mb.intra4x4_pred_mode[i_top_xy][0]; @@ -921,10 +925,7 @@ void x264_macroblock_cache_load( x264_t *h, int i_mb_x, int i_mb_y ) h->mb.cache.i_cbp_top = -1; /* load intra4x4 */ - h->mb.cache.intra4x4_pred_mode[x264_scan8[0] - 8] = - h->mb.cache.intra4x4_pred_mode[x264_scan8[1] - 8] = - h->mb.cache.intra4x4_pred_mode[x264_scan8[4] - 8] = - h->mb.cache.intra4x4_pred_mode[x264_scan8[5] - 8] = -1; + *(uint32_t*)&h->mb.cache.intra4x4_pred_mode[x264_scan8[0] - 8] = 0xFFFFFFFFU; /* load non_zero_count */ h->mb.cache.non_zero_count[x264_scan8[0] - 8] = @@ -946,6 +947,9 @@ void x264_macroblock_cache_load( x264_t *h, int i_mb_x, int i_mb_y ) h->mb.i_neighbour |= MB_LEFT; + if( !h->param.b_constrained_intra || IS_INTRA( i_left_type ) ) + h->mb.i_neighbour_intra |= MB_LEFT; + /* load intra4x4 */ h->mb.cache.intra4x4_pred_mode[x264_scan8[0 ] - 1] = h->mb.intra4x4_pred_mode[i_left_xy][4]; h->mb.cache.intra4x4_pred_mode[x264_scan8[2 ] - 1] = h->mb.intra4x4_pred_mode[i_left_xy][5]; @@ -989,6 +993,8 @@ void x264_macroblock_cache_load( x264_t *h, int i_mb_x, int i_mb_y ) { h->mb.i_neighbour |= MB_TOPRIGHT; h->mb.i_mb_type_topright = h->mb.type[ i_top_xy + 1 ]; + if( !h->param.b_constrained_intra || IS_INTRA( h->mb.i_mb_type_topright ) ) + h->mb.i_neighbour_intra |= MB_TOPRIGHT; } else h->mb.i_mb_type_topright = -1; @@ -996,6 +1002,8 @@ void x264_macroblock_cache_load( x264_t *h, int i_mb_x, int i_mb_y ) { h->mb.i_neighbour |= MB_TOPLEFT; h->mb.i_mb_type_topleft = h->mb.type[ i_top_xy - 1 ]; + if( !h->param.b_constrained_intra || IS_INTRA( h->mb.i_mb_type_topleft ) ) + h->mb.i_neighbour_intra |= MB_TOPLEFT; } else h->mb.i_mb_type_topleft = -1; @@ -1183,17 +1191,17 @@ void x264_macroblock_cache_load( x264_t *h, int i_mb_x, int i_mb_y ) } h->mb.i_neighbour4[0] = - h->mb.i_neighbour8[0] = (h->mb.i_neighbour & (MB_TOP|MB_LEFT|MB_TOPLEFT)) - | ((h->mb.i_neighbour & MB_TOP) ? MB_TOPRIGHT : 0); + h->mb.i_neighbour8[0] = (h->mb.i_neighbour_intra & (MB_TOP|MB_LEFT|MB_TOPLEFT)) + | ((h->mb.i_neighbour_intra & MB_TOP) ? MB_TOPRIGHT : 0); h->mb.i_neighbour4[4] = - h->mb.i_neighbour4[1] = MB_LEFT | ((h->mb.i_neighbour & MB_TOP) ? (MB_TOP|MB_TOPLEFT|MB_TOPRIGHT) : 0); + h->mb.i_neighbour4[1] = MB_LEFT | ((h->mb.i_neighbour_intra & MB_TOP) ? (MB_TOP|MB_TOPLEFT|MB_TOPRIGHT) : 0); h->mb.i_neighbour4[2] = h->mb.i_neighbour4[8] = h->mb.i_neighbour4[10] = - h->mb.i_neighbour8[2] = MB_TOP|MB_TOPRIGHT | ((h->mb.i_neighbour & MB_LEFT) ? (MB_LEFT|MB_TOPLEFT) : 0); + h->mb.i_neighbour8[2] = MB_TOP|MB_TOPRIGHT | ((h->mb.i_neighbour_intra & MB_LEFT) ? (MB_LEFT|MB_TOPLEFT) : 0); h->mb.i_neighbour4[5] = - h->mb.i_neighbour8[1] = MB_LEFT | (h->mb.i_neighbour & MB_TOPRIGHT) - | ((h->mb.i_neighbour & MB_TOP) ? MB_TOP|MB_TOPLEFT : 0); + h->mb.i_neighbour8[1] = MB_LEFT | (h->mb.i_neighbour_intra & MB_TOPRIGHT) + | ((h->mb.i_neighbour_intra & MB_TOP) ? MB_TOP|MB_TOPLEFT : 0); } static void ALWAYS_INLINE x264_macroblock_store_pic( x264_t *h, int i ) @@ -1242,8 +1250,11 @@ void x264_macroblock_cache_save( x264_t *h ) h->mb.cache.intra4x4_pred_mode[x264_scan8[7] ], h->mb.cache.intra4x4_pred_mode[x264_scan8[13] ], 0); } - else + else if( !h->param.b_constrained_intra || IS_INTRA(i_mb_type) ) *(uint64_t*)intra4x4_pred_mode = I_PRED_4x4_DC * 0x0101010101010101ULL; + else + *(uint64_t*)intra4x4_pred_mode = (uint8_t)(-1) * 0x0101010101010101ULL; + if( i_mb_type == I_PCM ) { diff --git a/encoder/analyse.c b/encoder/analyse.c index 7ea86f4d..44e8d742 100644 --- a/encoder/analyse.c +++ b/encoder/analyse.c @@ -662,7 +662,7 @@ static void x264_mb_analyse_intra_chroma( x264_t *h, x264_mb_analysis_t *a ) p_srcc[0] = h->mb.pic.p_fenc[1]; p_srcc[1] = h->mb.pic.p_fenc[2]; - predict_8x8chroma_mode_available( h->mb.i_neighbour, predict_mode, &i_max ); + predict_8x8chroma_mode_available( h->mb.i_neighbour_intra, predict_mode, &i_max ); a->i_satd_i8x8chroma = COST_MAX; if( i_max == 4 && b_merged_satd ) { @@ -731,7 +731,7 @@ static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_satd_ /*---------------- Try all mode and calculate their score ---------------*/ /* 16x16 prediction selection */ - predict_16x16_mode_available( h->mb.i_neighbour, predict_mode, &i_max ); + predict_16x16_mode_available( h->mb.i_neighbour_intra, predict_mode, &i_max ); if( b_merged_satd && i_max == 4 ) { @@ -996,7 +996,7 @@ static void x264_intra_rd_refine( x264_t *h, x264_mb_analysis_t *a ) int old_pred_mode = a->i_predict16x16; i_thresh = a->i_satd_i16x16_dir[old_pred_mode] * 9/8; i_best = a->i_satd_i16x16; - predict_16x16_mode_available( h->mb.i_neighbour, predict_mode, &i_max ); + predict_16x16_mode_available( h->mb.i_neighbour_intra, predict_mode, &i_max ); for( i = 0; i < i_max; i++ ) { int i_mode = predict_mode[i]; @@ -1009,7 +1009,7 @@ static void x264_intra_rd_refine( x264_t *h, x264_mb_analysis_t *a ) } /* RD selection for chroma prediction */ - predict_8x8chroma_mode_available( h->mb.i_neighbour, predict_mode, &i_max ); + predict_8x8chroma_mode_available( h->mb.i_neighbour_intra, predict_mode, &i_max ); if( i_max > 1 ) { i_thresh = a->i_satd_i8x8chroma * 5/4; diff --git a/encoder/set.c b/encoder/set.c index 2f7e7855..49ca340e 100644 --- a/encoder/set.c +++ b/encoder/set.c @@ -384,7 +384,7 @@ void x264_pps_init( x264_pps_t *pps, int i_id, x264_param_t *param, x264_sps_t * pps->i_chroma_qp_index_offset = param->analyse.i_chroma_qp_offset; pps->b_deblocking_filter_control = 1; - pps->b_constrained_intra_pred = 0; + pps->b_constrained_intra_pred = param->b_constrained_intra; pps->b_redundant_pic_cnt = 0; pps->b_transform_8x8_mode = param->analyse.b_transform_8x8 ? 1 : 0; diff --git a/x264.c b/x264.c index 87eef2e4..ec4a3782 100644 --- a/x264.c +++ b/x264.c @@ -222,6 +222,7 @@ static void Help( x264_param_t *defaults, int longhelp ) H2( " --slice-max-size Limit the size of each slice in bytes\n"); H2( " --slice-max-mbs Limit the size of each slice in macroblocks\n"); H0( " --interlaced Enable pure-interlaced mode\n" ); + H2( " --constrained-intra Enable constrained intra prediction.\n" ); H0( "\n" ); H0( "Ratecontrol:\n" ); H0( "\n" ); @@ -428,6 +429,7 @@ static struct option long_options[] = { "filter", required_argument, NULL, 0 }, { "deblock", required_argument, NULL, 'f' }, { "interlaced", no_argument, NULL, 0 }, + { "constrained-intra", no_argument, NULL, 0 }, { "cabac", no_argument, NULL, 0 }, { "no-cabac", no_argument, NULL, 0 }, { "qp", required_argument, NULL, 'q' }, diff --git a/x264.h b/x264.h index ec9321c2..7bc2d36a 100644 --- a/x264.h +++ b/x264.h @@ -35,7 +35,7 @@ #include -#define X264_BUILD 76 +#define X264_BUILD 77 /* x264_t: * opaque handler for encoder */ @@ -206,6 +206,7 @@ typedef struct x264_param_t int i_cabac_init_idc; int b_interlaced; + int b_constrained_intra; int i_cqm_preset; char *psz_cqm_file; /* JM format */