+ //early termination
+ if( fabsf( ref_mean[plane] - fenc_mean[plane] ) < 0.5f && fabsf( 1.f - guess_scale[plane] ) < epsilon )
+ {
+ SET_WEIGHT( weights[plane], 0, 1, 0, 0 );
+ continue;
+ }
+
+ if( plane )
+ {
+ weights[plane].i_denom = chroma_denom;
+ weights[plane].i_scale = x264_clip3( round( guess_scale[plane] * (1<<chroma_denom) ), 0, 255 );
+ if( weights[plane].i_scale > 127 )
+ {
+ weights[1].weightfn = weights[2].weightfn = NULL;
+ break;
+ }
+ }
+ else
+ x264_weight_get_h264( round( guess_scale[plane] * 128 ), 0, &weights[plane] );
+
+ found = 0;
+ mindenom = weights[plane].i_denom;
+ minscale = weights[plane].i_scale;
+ minoff = 0;
+
+ pixel *mcbuf;
+ if( !plane )
+ {
+ if( !fenc->b_intra_calculated )
+ {
+ x264_mb_analysis_t a;
+ x264_lowres_context_init( h, &a );
+ x264_slicetype_frame_cost( h, &a, &fenc, 0, 0, 0 );
+ }
+ mcbuf = x264_weight_cost_init_luma( h, fenc, ref, h->mb.p_weight_buf[0] );
+ origscore = minscore = x264_weight_cost_luma( h, fenc, mcbuf, NULL );
+ }
+ else
+ {
+ if( CHROMA444 )
+ {
+ mcbuf = x264_weight_cost_init_chroma444( h, fenc, ref, h->mb.p_weight_buf[0], plane );
+ origscore = minscore = x264_weight_cost_chroma444( h, fenc, mcbuf, NULL, plane );
+ }
+ else
+ {
+ pixel *dstu = h->mb.p_weight_buf[0];
+ pixel *dstv = h->mb.p_weight_buf[0]+fenc->i_stride[1]*fenc->i_lines[1];
+ if( !chroma_initted++ )
+ x264_weight_cost_init_chroma( h, fenc, ref, dstu, dstv );
+ mcbuf = plane == 1 ? dstu : dstv;
+ origscore = minscore = x264_weight_cost_chroma( h, fenc, mcbuf, NULL );
+ }
+ }
+
+ if( !minscore )
+ continue;
+
+ /* Picked somewhat arbitrarily */
+ static const uint8_t weight_check_distance[][2] =
+ {
+ {0,0},{0,0},{0,1},{0,1},
+ {0,1},{0,1},{0,1},{1,1},
+ {1,1},{2,1},{2,1},{4,2}
+ };
+ int scale_dist = b_lookahead ? 0 : weight_check_distance[h->param.analyse.i_subpel_refine][0];
+ int offset_dist = b_lookahead ? 0 : weight_check_distance[h->param.analyse.i_subpel_refine][1];
+
+ int start_scale = x264_clip3( minscale - scale_dist, 0, 127 );
+ int end_scale = x264_clip3( minscale + scale_dist, 0, 127 );
+ for( int i_scale = start_scale; i_scale <= end_scale; i_scale++ )
+ {
+ int cur_scale = i_scale;
+ int cur_offset = fenc_mean[plane] - ref_mean[plane] * cur_scale / (1 << mindenom) + 0.5f * b_lookahead;
+ if( cur_offset < - 128 || cur_offset > 127 )
+ {
+ /* Rescale considering the constraints on cur_offset. We do it in this order
+ * because scale has a much wider range than offset (because of denom), so
+ * it should almost never need to be clamped. */
+ cur_offset = x264_clip3( cur_offset, -128, 127 );
+ cur_scale = (1 << mindenom) * (fenc_mean[plane] - cur_offset) / ref_mean[plane] + 0.5f;
+ cur_scale = x264_clip3( cur_scale, 0, 127 );
+ }
+ int start_offset = x264_clip3( cur_offset - offset_dist, -128, 127 );
+ int end_offset = x264_clip3( cur_offset + offset_dist, -128, 127 );
+ for( int i_off = start_offset; i_off <= end_offset; i_off++ )
+ {
+ SET_WEIGHT( weights[plane], 1, cur_scale, mindenom, i_off );
+ unsigned int s;
+ if( plane )
+ {
+ if( CHROMA444 )
+ s = x264_weight_cost_chroma444( h, fenc, mcbuf, &weights[plane], plane );
+ else
+ s = x264_weight_cost_chroma( h, fenc, mcbuf, &weights[plane] );
+ }
+ else
+ s = x264_weight_cost_luma( h, fenc, mcbuf, &weights[plane] );
+ COPY4_IF_LT( minscore, s, minscale, cur_scale, minoff, i_off, found, 1 );
+
+ // Don't check any more offsets if the previous one had a lower cost than the current one
+ if( minoff == start_offset && i_off != start_offset )
+ break;
+ }
+ }
+ x264_emms();
+
+ /* Use a smaller denominator if possible */
+ if( !plane )
+ {
+ while( mindenom > 0 && !(minscale&1) )
+ {
+ mindenom--;
+ minscale >>= 1;
+ }
+ }
+
+ /* FIXME: More analysis can be done here on SAD vs. SATD termination. */
+ /* 0.2% termination derived experimentally to avoid weird weights in frames that are mostly intra. */
+ if( !found || (minscale == 1 << mindenom && minoff == 0) || (float)minscore / origscore > 0.998f )
+ {
+ SET_WEIGHT( weights[plane], 0, 1, 0, 0 );
+ continue;
+ }
+ else
+ SET_WEIGHT( weights[plane], 1, minscale, mindenom, minoff );
+
+ if( h->param.analyse.i_weighted_pred == X264_WEIGHTP_FAKE && weights[0].weightfn && !plane )
+ fenc->f_weighted_cost_delta[i_delta_index] = (float)minscore / origscore;