Added early termination option for motion estimation.

Conflicts:
	src/search_inter.c
This commit is contained in:
Eemeli Kallio 2016-06-06 15:47:31 +03:00
parent 836a3b1daa
commit e4f1a74512
4 changed files with 90 additions and 0 deletions

View file

@ -108,6 +108,8 @@ int kvz_config_init(kvz_config *cfg)
cfg->mv_constraint = KVZ_MV_CONSTRAIN_NONE; cfg->mv_constraint = KVZ_MV_CONSTRAIN_NONE;
cfg->me_early_termination = 0;
return 1; return 1;
} }
@ -290,6 +292,8 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value)
static const char * const cu_split_termination_names[] = { "zero", "off", NULL }; static const char * const cu_split_termination_names[] = { "zero", "off", NULL };
static const char * const me_early_termination_names[] = { "off", "on", "sensitive", NULL };
static const char * const preset_values[11][32] = { static const char * const preset_values[11][32] = {
{ {
"ultrafast", "ultrafast",
@ -838,6 +842,12 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value)
cfg->cu_split_termination = mode; cfg->cu_split_termination = mode;
return result; return result;
} }
else if OPT("me-early-termination"){
int8_t mode = 0;
int result = parse_enum(value, me_early_termination_names, &mode);
cfg->me_early_termination = mode;
return result;
}
else else
return 0; return 0;
#undef OPT #undef OPT

View file

@ -106,6 +106,7 @@ static const struct option long_options[] = {
{ "mv-constraint", required_argument, NULL, 0 }, { "mv-constraint", required_argument, NULL, 0 },
{ "hash", required_argument, NULL, 0 }, { "hash", required_argument, NULL, 0 },
{"cu-split-termination",required_argument, NULL, 0 }, {"cu-split-termination",required_argument, NULL, 0 },
{ "me-early-termination",required_argument, NULL, 0 },
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
@ -379,6 +380,10 @@ void print_help(void)
" \"zero\": Terminate when splitting gives little\n" " \"zero\": Terminate when splitting gives little\n"
" improvement.\n" " improvement.\n"
" \"off\": Don't terminate splitting early\n" " \"off\": Don't terminate splitting early\n"
" --me-early-termitanion : Specify the me early termination behaviour\n"
" \"off\": Early termination is off\n"
" \"on\": Early termination is on\n"
" \"sensitive\": Sensitive early termination is on\n"
"\n" "\n"
" Video Usability Information:\n" " Video Usability Information:\n"
" --sar <width:height> : Specify Sample Aspect Ratio\n" " --sar <width:height> : Specify Sample Aspect Ratio\n"

View file

@ -138,6 +138,13 @@ enum kvz_cu_split_termination
KVZ_CU_SPLIT_TERMINATION_OFF = 1 KVZ_CU_SPLIT_TERMINATION_OFF = 1
}; };
enum kvz_me_early_termination
{
KVZ_ME_EARLY_TERMINATION_OFF = 0,
KVZ_ME_EARLY_TERMINATION_ON = 1,
KVZ_ME_EARLY_TERMINATION_SENSITIVE = 2
};
/** /**
* \brief GoP picture configuration. * \brief GoP picture configuration.
*/ */
@ -247,6 +254,8 @@ typedef struct kvz_config
enum kvz_cu_split_termination cu_split_termination; /*!< \brief Mode of cu split termination. */ enum kvz_cu_split_termination cu_split_termination; /*!< \brief Mode of cu split termination. */
enum kvz_me_early_termination me_early_termination;
} kvz_config; } kvz_config;
/** /**

View file

@ -257,6 +257,61 @@ static int calc_mvd_cost(const encoder_state_t * const state, int x, int y, int
} }
static bool early_terminate(int16_t num_cand, inter_merge_cand_t *merge_cand, vector2d_t *mv_in_out, vector2d_t *mv, const encoder_state_t *const state,
const vector2d_t *orig, unsigned width, unsigned height, int wpp_limit, const kvz_picture *pic, const kvz_picture *ref,
int16_t mv_cand[2][2], int32_t ref_idx, unsigned *best_cost, uint32_t *bitcost_out, uint32_t *best_bitcost,
int(*calc_mvd)(const encoder_state_t * const, int, int, int, int16_t[2][2], inter_merge_cand_t[MRG_MAX_NUM_CANDS],
int16_t, int32_t, uint32_t *))
{
static const vector2d_t small_hexbs[5] = {
{ 0, 0 },
{ 0, -1 }, { -1, 0 }, { 1, 0 }, { 0, 1 },
};
double multiplier = 1;
// If early termination is set to fast set multiplier to 0.9
if (state->encoder_control->cfg->me_early_termination == KVZ_ME_EARLY_TERMINATION_SENSITIVE){
multiplier = 0.95;
}
const vector2d_t *offset;
for (int k = 0; k < 2; ++k){
unsigned best_index = 0;
for (int i = 1; i < 5; ++i) {
offset = &small_hexbs[i];
if (!intmv_within_tile(state, orig, mv->x + offset->x, mv->y + offset->y, width, height, wpp_limit)) {
continue;
}
unsigned cost = kvz_image_calc_sad(pic, ref, orig->x, orig->y,
(state->tile->lcu_offset_x * LCU_WIDTH) + orig->x + mv->x + offset->x,
(state->tile->lcu_offset_y * LCU_WIDTH) + orig->y + mv->y + offset->y,
width, height, -1);
unsigned bitcost;
cost += calc_mvd(state, mv->x + offset->x, mv->y + offset->y, 2, mv_cand, merge_cand, num_cand, ref_idx, &bitcost);
if (cost < multiplier * *best_cost ) {
*best_cost = cost;
best_index = i;
*best_bitcost = bitcost;
}
}
// Adjust the movement vector
mv->x += small_hexbs[best_index].x;
mv->y += small_hexbs[best_index].y;
// if best match is at center we stop the search
if (best_index == 0){
// Return final movement vector in quarter-pixel precision.
mv_in_out->x = mv->x << 2;
mv_in_out->y = mv->y << 2;
*bitcost_out = *best_bitcost;
return true;
}
}
return false;
}
unsigned kvz_tz_pattern_search(const encoder_state_t * const state, const kvz_picture *pic, const kvz_picture *ref, unsigned pattern_type, unsigned kvz_tz_pattern_search(const encoder_state_t * const state, const kvz_picture *pic, const kvz_picture *ref, unsigned pattern_type,
const vector2d_t *orig, const int iDist, vector2d_t *mv, unsigned best_cost, int *best_dist, const vector2d_t *orig, const int iDist, vector2d_t *mv, unsigned best_cost, int *best_dist,
int16_t mv_cand[2][2], inter_merge_cand_t merge_cand[MRG_MAX_NUM_CANDS], int16_t num_cand, int32_t ref_idx, uint32_t *best_bitcost, int16_t mv_cand[2][2], inter_merge_cand_t merge_cand[MRG_MAX_NUM_CANDS], int16_t num_cand, int32_t ref_idx, uint32_t *best_bitcost,
@ -536,6 +591,11 @@ static unsigned tz_search(const encoder_state_t * const state,
best_cost = select_starting_point(num_cand, merge_cand, mv_in_out, &mv, state, orig, width, height, wpp_limit, best_cost = select_starting_point(num_cand, merge_cand, mv_in_out, &mv, state, orig, width, height, wpp_limit,
pic, ref, mv_cand, ref_idx, best_cost, &best_index, &best_bitcost, calc_mvd); pic, ref, mv_cand, ref_idx, best_cost, &best_index, &best_bitcost, calc_mvd);
// Check if we should stop search
if (state->encoder_control->cfg->me_early_termination){
if (early_terminate(num_cand, merge_cand, mv_in_out, &mv, state, orig, width, height, wpp_limit,
pic, ref, mv_cand, ref_idx, &best_cost, bitcost_out, &best_bitcost, calc_mvd)) return best_cost;
}
//step 2, grid search //step 2, grid search
for (iDist = 1; iDist <= iSearchRange; iDist *= 2) for (iDist = 1; iDist <= iSearchRange; iDist *= 2)
{ {
@ -685,6 +745,12 @@ static unsigned hexagon_search(const encoder_state_t * const state,
best_cost = select_starting_point(num_cand, merge_cand, mv_in_out, &mv, state, orig, width, height, wpp_limit, best_cost = select_starting_point(num_cand, merge_cand, mv_in_out, &mv, state, orig, width, height, wpp_limit,
pic, ref, mv_cand, ref_idx, best_cost, &best_index, &best_bitcost, calc_mvd); pic, ref, mv_cand, ref_idx, best_cost, &best_index, &best_bitcost, calc_mvd);
// Check if we should stop search
if (state->encoder_control->cfg->me_early_termination){
if (early_terminate(num_cand, merge_cand, mv_in_out, &mv, state, orig, width, height, wpp_limit,
pic, ref, mv_cand, ref_idx, &best_cost, bitcost_out, &best_bitcost, calc_mvd)) return best_cost;
}
// Search the initial 7 points of the hexagon. // Search the initial 7 points of the hexagon.
best_index = 0; best_index = 0;
for (i = 0; i < 7; ++i) { for (i = 0; i < 7; ++i) {