mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-30 20:54:07 +00:00
Added early termination option for motion estimation.
Conflicts: src/search_inter.c
This commit is contained in:
parent
836a3b1daa
commit
e4f1a74512
10
src/cfg.c
10
src/cfg.c
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue