a->i_qp = h->mb.i_qp = i_qp;
a->i_lambda = i_qp0_cost_table[i_qp];
a->i_lambda2 = i_qp0_cost2_table[i_qp];
- a->b_mbrd = h->param.analyse.i_subpel_refine >= 6 && h->sh.i_type != SLICE_TYPE_B;
+ a->b_mbrd = h->param.analyse.i_subpel_refine >= 6 &&
+ ( h->sh.i_type != SLICE_TYPE_B || h->param.analyse.b_bframe_rdo );
h->mb.i_me_method = h->param.analyse.i_me_method;
h->mb.i_subpel_refine = h->param.analyse.i_subpel_refine;
int i, idx;
int i_max;
int predict_mode[9];
+ int i_satd_thresh;
- const int i_satd_thresh = a->i_best_satd * 5/4 + a->i_lambda * 10;
+ if( h->sh.i_type == SLICE_TYPE_B )
+ i_satd_thresh = a->i_best_satd * 9/8;
+ else
+ i_satd_thresh = a->i_best_satd * 5/4 + a->i_lambda * 10;
/*---------------- Try all mode and calculate their score ---------------*/
/* mb type cost */
a->i_cost8x8direct[i] += a->i_lambda * i_sub_mb_b_cost_table[D_DIRECT_8x8];
}
-
a->i_cost16x16direct += a->i_lambda * i_mb_b_cost_table[B_DIRECT];
+
+ if( a->b_mbrd )
+ {
+ if( a->i_cost16x16direct < a->i_best_satd )
+ a->i_best_satd = a->i_cost16x16direct;
+
+ h->mb.i_type = B_DIRECT;
+ a->i_cost16x16direct = x264_rd_cost_mb( h, a->i_lambda2 );
+ }
}
#define WEIGHTED_AVG( size, pix1, stride1, src2, stride2 ) \
a->i_cost16x16bi += a->i_lambda * i_mb_b_cost_table[B_BI_BI];
a->l0.me16x16.cost += a->i_lambda * i_mb_b_cost_table[B_L0_L0];
a->l1.me16x16.cost += a->i_lambda * i_mb_b_cost_table[B_L1_L1];
+
+ if( a->b_mbrd )
+ {
+ if( a->l0.me16x16.cost < a->i_best_satd )
+ a->i_best_satd = a->l0.me16x16.cost;
+ if( a->l1.me16x16.cost < a->i_best_satd )
+ a->i_best_satd = a->l1.me16x16.cost;
+ if( a->i_cost16x16bi < a->i_best_satd )
+ a->i_best_satd = a->i_cost16x16bi;
+
+ h->mb.i_partition = D_16x16;
+ /* L0 */
+ h->mb.i_type = B_L0_L0;
+ x264_macroblock_cache_mv( h, 0, 0, 4, 4, 0, a->l0.me16x16.mv[0], a->l0.me16x16.mv[1] );
+ a->l0.me16x16.cost = x264_rd_cost_mb( h, a->i_lambda2 );
+
+ /* L1 */
+ h->mb.i_type = B_L1_L1;
+ x264_macroblock_cache_mv( h, 0, 0, 4, 4, 1, a->l1.me16x16.mv[0], a->l1.me16x16.mv[1] );
+ a->l1.me16x16.cost = x264_rd_cost_mb( h, a->i_lambda2 );
+
+ /* BI */
+ h->mb.i_type = B_BI_BI;
+ a->i_cost16x16bi = x264_rd_cost_mb( h, a->i_lambda2 );
+ }
}
static inline void x264_mb_cache_mv_p8x8( x264_t *h, x264_mb_analysis_t *a, int i )
/* mb type cost */
a->i_cost8x8bi += a->i_lambda * i_mb_b_cost_table[B_8x8];
+
+ if( a->b_mbrd )
+ {
+ if( a->i_cost8x8bi < a->i_best_satd )
+ a->i_best_satd = a->i_cost8x8bi;
+
+ h->mb.i_type = B_8x8;
+ h->mb.i_partition = D_8x8;
+ a->i_cost8x8bi = x264_rd_cost_mb( h, a->i_lambda2 );
+ }
}
static void x264_mb_analyse_inter_b16x8( x264_t *h, x264_mb_analysis_t *a )
}
a->i_cost16x8bi += i_part_cost;
- if( i == 0 )
- x264_mb_cache_mv_b16x8( h, a, i, 0 );
+ x264_mb_cache_mv_b16x8( h, a, i, 0 );
}
/* mb type cost */
+ (a->i_mb_partition16x8[0]>>2) * 3
+ (a->i_mb_partition16x8[1]>>2);
a->i_cost16x8bi += a->i_lambda * i_mb_b16x8_cost_table[a->i_mb_type16x8];
+
+ if( a->b_mbrd )
+ {
+ if( a->i_cost16x8bi < a->i_best_satd )
+ a->i_best_satd = a->i_cost16x8bi;
+
+ h->mb.i_type = a->i_mb_type16x8;
+ h->mb.i_partition = D_16x8;
+ a->i_cost16x8bi = x264_rd_cost_mb( h, a->i_lambda2 );
+ }
}
static void x264_mb_analyse_inter_b8x16( x264_t *h, x264_mb_analysis_t *a )
{
}
a->i_cost8x16bi += i_part_cost;
- if( i == 0 )
- x264_mb_cache_mv_b8x16( h, a, i, 0 );
+ x264_mb_cache_mv_b8x16( h, a, i, 0 );
}
/* mb type cost */
+ (a->i_mb_partition8x16[0]>>2) * 3
+ (a->i_mb_partition8x16[1]>>2);
a->i_cost8x16bi += a->i_lambda * i_mb_b16x8_cost_table[a->i_mb_type8x16];
+
+ if( a->b_mbrd )
+ {
+ if( a->i_cost8x16bi < a->i_best_satd )
+ a->i_best_satd = a->i_cost8x16bi;
+
+ h->mb.i_type = a->i_mb_type8x16;
+ h->mb.i_partition = D_8x16;
+ a->i_cost8x16bi = x264_rd_cost_mb( h, a->i_lambda2 );
+ }
}
static inline void x264_mb_analyse_transform( x264_t *h )
{
if( *i_cost > 0 )
a->i_best_satd = (int64_t)a->i_best_satd * i_cost8 / *i_cost;
+ /* prevent a rare division by zero in x264_mb_analyse_intra */
+ if( a->i_best_satd == 0 )
+ a->i_best_satd = 1;
+
*i_cost = i_cost8;
}
else
}
else if( h->sh.i_type == SLICE_TYPE_B )
{
+ int i_bskip_cost = COST_MAX;
int b_skip = 0;
analysis.b_direct_available = x264_mb_predict_mv_direct16x16( h );
{
h->mb.i_type = B_SKIP;
x264_mb_mc( h );
-
- /* Conditioning the probe on neighboring block types
- * doesn't seem to help speed or quality. */
- b_skip = !h->mb.b_lossless && x264_macroblock_probe_bskip( h );
+ if( analysis.b_mbrd )
+ {
+ i_bskip_cost = h->pixf.ssd[PIXEL_16x16]( h->mb.pic.p_fenc[0], h->mb.pic.i_stride[0],
+ h->mb.pic.p_fdec[0], h->mb.pic.i_stride[0] )
+ + h->pixf.ssd[PIXEL_8x8]( h->mb.pic.p_fenc[1], h->mb.pic.i_stride[1],
+ h->mb.pic.p_fdec[1], h->mb.pic.i_stride[1] )
+ + h->pixf.ssd[PIXEL_8x8]( h->mb.pic.p_fenc[2], h->mb.pic.i_stride[2],
+ h->mb.pic.p_fdec[2], h->mb.pic.i_stride[2] );
+
+ if( i_bskip_cost == 0 )
+ {
+ h->mb.i_type = B_SKIP;
+ x264_analyse_update_cache( h, &analysis );
+ return;
+ }
+ }
+ else
+ {
+ /* Conditioning the probe on neighboring block types
+ * doesn't seem to help speed or quality. */
+ b_skip = !h->mb.b_lossless && x264_macroblock_probe_bskip( h );
+ }
}
if( !b_skip )
{
const unsigned int flags = h->param.analyse.inter;
+ int i_type;
int i_partition;
x264_mb_analyse_load_costs( h, &analysis );
x264_mb_analyse_inter_b16x16( h, &analysis );
- h->mb.i_type = B_L0_L0;
+ i_type = B_L0_L0;
i_partition = D_16x16;
i_cost = analysis.l0.me16x16.cost;
if( analysis.l1.me16x16.cost < i_cost )
{
- h->mb.i_type = B_L1_L1;
+ i_type = B_L1_L1;
i_cost = analysis.l1.me16x16.cost;
}
if( analysis.i_cost16x16bi < i_cost )
{
- h->mb.i_type = B_BI_BI;
+ i_type = B_BI_BI;
i_cost = analysis.i_cost16x16bi;
}
if( analysis.i_cost16x16direct < i_cost )
{
- h->mb.i_type = B_DIRECT;
+ i_type = B_DIRECT;
i_cost = analysis.i_cost16x16direct;
}
x264_mb_analyse_inter_b8x8( h, &analysis );
if( analysis.i_cost8x8bi < i_cost )
{
- h->mb.i_type = B_8x8;
+ i_type = B_8x8;
i_partition = D_8x8;
i_cost = analysis.i_cost8x8bi;
{
i_partition = D_16x8;
i_cost = analysis.i_cost16x8bi;
- h->mb.i_type = analysis.i_mb_type16x8;
+ i_type = analysis.i_mb_type16x8;
}
}
if( h->mb.i_sub_partition[0] == h->mb.i_sub_partition[2] ||
{
i_partition = D_8x16;
i_cost = analysis.i_cost8x16bi;
- h->mb.i_type = analysis.i_mb_type8x16;
+ i_type = analysis.i_mb_type8x16;
}
}
}
h->mb.i_partition = i_partition;
+ if( analysis.b_mbrd )
+ {
+ if( i_bskip_cost <= i_cost )
+ {
+ h->mb.i_type = B_SKIP;
+ x264_analyse_update_cache( h, &analysis );
+ return;
+ }
+ else
+ {
+ h->mb.i_type = i_type;
+ x264_mb_analyse_transform_rd( h, &analysis, &i_cost );
+ }
+ }
/* refine qpel */
- if( i_partition == D_16x16 )
+ else if( i_partition == D_16x16 )
{
analysis.l0.me16x16.cost -= analysis.i_lambda * i_mb_b_cost_table[B_L0_L0];
analysis.l1.me16x16.cost -= analysis.i_lambda * i_mb_b_cost_table[B_L1_L1];
- if( h->mb.i_type == B_L0_L0 )
+ if( i_type == B_L0_L0 )
{
x264_me_refine_qpel( h, &analysis.l0.me16x16 );
i_cost = analysis.l0.me16x16.cost
+ analysis.i_lambda * i_mb_b_cost_table[B_L0_L0];
}
- else if( h->mb.i_type == B_L1_L1 )
+ else if( i_type == B_L1_L1 )
{
x264_me_refine_qpel( h, &analysis.l1.me16x16 );
i_cost = analysis.l1.me16x16.cost
+ analysis.i_lambda * i_mb_b_cost_table[B_L1_L1];
}
- else if( h->mb.i_type == B_BI_BI )
+ else if( i_type == B_BI_BI )
{
x264_me_refine_qpel( h, &analysis.l0.me16x16 );
x264_me_refine_qpel( h, &analysis.l1.me16x16 );
if( analysis.i_sad_i16x16 < i_cost )
{
- h->mb.i_type = I_16x16;
+ i_type = I_16x16;
i_cost = analysis.i_sad_i16x16;
}
if( analysis.i_sad_i8x8 < i_cost )
{
- h->mb.i_type = I_8x8;
+ i_type = I_8x8;
i_cost = analysis.i_sad_i8x8;
}
if( analysis.i_sad_i4x4 < i_cost )
{
- h->mb.i_type = I_4x4;
+ i_type = I_4x4;
i_cost = analysis.i_sad_i4x4;
}
+
+ h->mb.i_type = i_type;
}
}
}
case B_SKIP:
- /* nothing has changed since x264_macroblock_probe_bskip */
- break;
case B_DIRECT:
x264_mb_load_mv_direct8x8( h, 0 );
x264_mb_load_mv_direct8x8( h, 1 );
" --merange <integer> Maximum motion vector search range [%d]\n"
" -m, --subme <integer> Subpixel motion estimation and partition\n"
" decision quality: 1=fast, 6=best. [%d]\n"
+ " --b-rdo RD based mode decision for B-frames. Requires subme 6.\n"
" --mixed-refs Decide references on a per partition basis\n"
" --no-chroma-me Ignore chroma in motion estimation\n"
" -8, --8x8dct Adaptive spatial transform size\n"
#define OPT_CHROMALOC 313
#define OPT_MIXED_REFS 314
#define OPT_CRF 315
+#define OPT_B_RDO 316
static struct option long_options[] =
{
{ "me", required_argument, NULL, OPT_ME },
{ "merange", required_argument, NULL, OPT_MERANGE },
{ "subme", required_argument, NULL, 'm' },
+ { "b-rdo", no_argument, NULL, OPT_B_RDO },
{ "mixed-refs", no_argument, NULL, OPT_MIXED_REFS },
{ "no-chroma-me", no_argument, NULL, OPT_NO_CHROMA_ME },
{ "8x8dct", no_argument, NULL, '8' },
case 'm':
param->analyse.i_subpel_refine = atoi(optarg);
break;
+ case OPT_B_RDO:
+ param->analyse.b_bframe_rdo = 1;
+ break;
case OPT_MIXED_REFS:
param->analyse.b_mixed_references = 1;
break;