From e8e0e7596a72d4e2f197f3240e9170afad8413a0 Mon Sep 17 00:00:00 2001 From: Miika Metsoila Date: Fri, 22 Dec 2017 12:10:41 +0200 Subject: [PATCH 1/2] Add a step-cutoff parameter for motion estimation search --- README.md | 3 +++ src/cfg.c | 5 +++++ src/cli.c | 4 ++++ src/kvazaar.h | 3 +++ src/search_inter.c | 20 ++++++++++++++------ 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e492b083..0c467b5d 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,9 @@ Compression tools: - full: Full Search - full8, full16, full32, full64 - dia: Diamond Search + --me-steps : How many search steps does the motion estimation + do before cutting off, -1 for no limits [-1] + Has effect only for 'hexbs' and 'dia' --subme : Set fractional pixel motion estimation level - 0: only integer motion estimation - 1: + 1/2-pixel horizontal and vertical diff --git a/src/cfg.c b/src/cfg.c index cee8c0f7..2739758a 100644 --- a/src/cfg.c +++ b/src/cfg.c @@ -130,6 +130,8 @@ int kvz_config_init(kvz_config *cfg) cfg->force_level = true; // don't care about level limits by-default cfg->high_tier = false; + cfg->me_max_steps = (uint32_t)-1; + return 1; } @@ -1153,6 +1155,9 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value) else if (OPT("high-tier")) { cfg->high_tier = true; } + else if (OPT("me-steps")) { + cfg->me_max_steps = (uint32_t)atoi(value); // fix + } else { return 0; } diff --git a/src/cli.c b/src/cli.c index 9040fd3d..0d3528b6 100644 --- a/src/cli.c +++ b/src/cli.c @@ -125,6 +125,7 @@ static const struct option long_options[] = { { "level", required_argument, NULL, 0 }, { "force-level", required_argument, NULL, 0 }, { "high-tier", no_argument, NULL, 0 }, + { "me-steps", required_argument, NULL, 0 }, {0, 0, 0, 0} }; @@ -431,6 +432,9 @@ void print_help(void) " - full: Full Search\n" " - full8, full16, full32, full64\n" " - dia: Diamond Search\n" + " --me-steps : How many search steps does the motion estimation\n" + " do before cutting off, -1 for no limits [-1]\n" + " Has effect only for 'hexbs' and 'dia'\n" " --subme : Set fractional pixel motion estimation level\n" " - 0: only integer motion estimation\n" " - 1: + 1/2-pixel horizontal and vertical\n" diff --git a/src/kvazaar.h b/src/kvazaar.h index f8275ba3..b7f5e445 100644 --- a/src/kvazaar.h +++ b/src/kvazaar.h @@ -361,6 +361,9 @@ typedef struct kvz_config uint8_t high_tier; /** \brief The maximum allowed bitrate for this level and tier. */ uint32_t max_bitrate; + + /** \brief Maximum steps that hexagonal and diagonal motion estimation can use. -1 to disable */ + uint32_t me_max_steps; } kvz_config; /** diff --git a/src/search_inter.c b/src/search_inter.c index 55975658..77dbb612 100644 --- a/src/search_inter.c +++ b/src/search_inter.c @@ -640,7 +640,7 @@ static void tz_search(inter_search_info_t *info, vector2d_t extra_mv) * the predicted motion vector is way off. In the future even more additional * points like 0,0 might be used, such as vectors from top or left. */ -static void hexagon_search(inter_search_info_t *info, vector2d_t extra_mv) +static void hexagon_search(inter_search_info_t *info, vector2d_t extra_mv, uint32_t max_steps) { // The start of the hexagonal pattern has been repeated at the end so that // the indices between 1-6 can be used as the start of a 3-point list of new @@ -689,9 +689,14 @@ static void hexagon_search(inter_search_info_t *info, vector2d_t extra_mv) } } + uint32_t steps_left = max_steps; + // Iteratively search the 3 new points around the best match, until the best // match is in the center. - while (best_index != 0) { + while (best_index != 0 && steps_left != 0) { + // decrement count if enabled + if (steps_left > 0 && max_steps != (uint32_t)-1) steps_left -= 1; + // Starting point of the 3 offsets to be searched. unsigned start; if (best_index == 1) { @@ -727,7 +732,7 @@ static void hexagon_search(inter_search_info_t *info, vector2d_t extra_mv) } -static void diamond_search(inter_search_info_t *info, vector2d_t extra_mv) +static void diamond_search(inter_search_info_t *info, vector2d_t extra_mv, uint32_t max_steps) { enum diapos { DIA_UP = 0, @@ -786,9 +791,12 @@ static void diamond_search(inter_search_info_t *info, vector2d_t extra_mv) // whether we found a better candidate this iteration uint8_t better_found; + uint32_t steps_left = max_steps; do { better_found = 0; + // decrement count if enabled + if (steps_left > 0 && max_steps != (uint32_t) -1) steps_left -= 1; // search the points of the diamond for (int i = 0; i < 4; ++i) { @@ -810,7 +818,7 @@ static void diamond_search(inter_search_info_t *info, vector2d_t extra_mv) // the xor operation flips the orientation from_dir = best_index ^ 0x3; } - } while (better_found); + } while (better_found && steps_left != 0); // and we're done } @@ -1250,11 +1258,11 @@ static void search_pu_inter_ref(inter_search_info_t *info, break; case KVZ_IME_DIA: - diamond_search(info, mv); + diamond_search(info, mv, info->state->encoder_control->cfg.me_max_steps); break; default: - hexagon_search(info, mv); + hexagon_search(info, mv, info->state->encoder_control->cfg.me_max_steps); break; } From 61213e3ad9f99a038a4dd17a31d162c5f79962be Mon Sep 17 00:00:00 2001 From: Miika Metsoila Date: Wed, 10 Jan 2018 15:16:52 +0200 Subject: [PATCH 2/2] Improve step parameter parsing and usage --- README.md | 2 +- src/cfg.c | 16 +++++++++++++++- src/cli.c | 2 +- src/search_inter.c | 33 +++++++++++++++++++++++---------- 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 0c467b5d..8f304bf9 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ Compression tools: - full8, full16, full32, full64 - dia: Diamond Search --me-steps : How many search steps does the motion estimation - do before cutting off, -1 for no limits [-1] + do before cutting off [-1] Has effect only for 'hexbs' and 'dia' --subme : Set fractional pixel motion estimation level - 0: only integer motion estimation diff --git a/src/cfg.c b/src/cfg.c index 2739758a..e01238ec 100644 --- a/src/cfg.c +++ b/src/cfg.c @@ -1156,7 +1156,21 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value) cfg->high_tier = true; } else if (OPT("me-steps")) { - cfg->me_max_steps = (uint32_t)atoi(value); // fix + char * tailptr = NULL; + + errno = 0; + long steps = strtol(value, &tailptr, 0); + + if (*tailptr != '\0') { + fprintf(stderr, "Invalid me-steps value: \"%s\"", value); + return 0; + } + if (steps < -1 || errno == ERANGE || steps > UINT32_MAX) { + fprintf(stderr, "me-steps value is out of bounds: \"%s\"", value); + return 0; + } + + cfg->me_max_steps = (uint32_t)steps; } else { return 0; diff --git a/src/cli.c b/src/cli.c index 0d3528b6..e742a3a0 100644 --- a/src/cli.c +++ b/src/cli.c @@ -433,7 +433,7 @@ void print_help(void) " - full8, full16, full32, full64\n" " - dia: Diamond Search\n" " --me-steps : How many search steps does the motion estimation\n" - " do before cutting off, -1 for no limits [-1]\n" + " do before cutting off [-1]\n" " Has effect only for 'hexbs' and 'dia'\n" " --subme : Set fractional pixel motion estimation level\n" " - 0: only integer motion estimation\n" diff --git a/src/search_inter.c b/src/search_inter.c index 77dbb612..4e1a7c31 100644 --- a/src/search_inter.c +++ b/src/search_inter.c @@ -630,6 +630,7 @@ static void tz_search(inter_search_info_t *info, vector2d_t extra_mv) * * \param info search info * \param extra_mv extra motion vector to check + * \param steps how many steps are done at maximum before exiting, does not affect the final step * * Motion vector is searched by first searching iteratively with the large * hexagon pattern until the best match is at the center of the hexagon. @@ -640,7 +641,7 @@ static void tz_search(inter_search_info_t *info, vector2d_t extra_mv) * the predicted motion vector is way off. In the future even more additional * points like 0,0 might be used, such as vectors from top or left. */ -static void hexagon_search(inter_search_info_t *info, vector2d_t extra_mv, uint32_t max_steps) +static void hexagon_search(inter_search_info_t *info, vector2d_t extra_mv, uint32_t steps) { // The start of the hexagonal pattern has been repeated at the end so that // the indices between 1-6 can be used as the start of a 3-point list of new @@ -689,13 +690,11 @@ static void hexagon_search(inter_search_info_t *info, vector2d_t extra_mv, uint3 } } - uint32_t steps_left = max_steps; - // Iteratively search the 3 new points around the best match, until the best // match is in the center. - while (best_index != 0 && steps_left != 0) { + while (best_index != 0 && steps != 0) { // decrement count if enabled - if (steps_left > 0 && max_steps != (uint32_t)-1) steps_left -= 1; + if (steps > 0) steps -= 1; // Starting point of the 3 offsets to be searched. unsigned start; @@ -731,8 +730,23 @@ static void hexagon_search(inter_search_info_t *info, vector2d_t extra_mv, uint3 } } - -static void diamond_search(inter_search_info_t *info, vector2d_t extra_mv, uint32_t max_steps) +/** +* \brief Do motion search using the diamond algorithm. +* +* \param info search info +* \param extra_mv extra motion vector to check +* \param steps how many steps are done at maximum before exiting +* +* Motion vector is searched by searching iteratively with a diamond-shaped +* pattern. We take care of not checking the direction we came from, but +* further checking for avoiding visits to already visited points is not done. +* +* If a non 0,0 predicted motion vector predictor is given as extra_mv, +* the 0,0 vector is also tried. This is hoped to help in the case where +* the predicted motion vector is way off. In the future even more additional +* points like 0,0 might be used, such as vectors from top or left. +**/ +static void diamond_search(inter_search_info_t *info, vector2d_t extra_mv, uint32_t steps) { enum diapos { DIA_UP = 0, @@ -791,12 +805,11 @@ static void diamond_search(inter_search_info_t *info, vector2d_t extra_mv, uint3 // whether we found a better candidate this iteration uint8_t better_found; - uint32_t steps_left = max_steps; do { better_found = 0; // decrement count if enabled - if (steps_left > 0 && max_steps != (uint32_t) -1) steps_left -= 1; + if (steps > 0) steps -= 1; // search the points of the diamond for (int i = 0; i < 4; ++i) { @@ -818,7 +831,7 @@ static void diamond_search(inter_search_info_t *info, vector2d_t extra_mv, uint3 // the xor operation flips the orientation from_dir = best_index ^ 0x3; } - } while (better_found && steps_left != 0); + } while (better_found && steps != 0); // and we're done }