ESR: add syntax for 2d superres scaling factor
The new syntax supports 4 possible scaling factors, which will be
applied to both horizontal and vertical directions. The index is
first parsed, and the decoder will retrieve the scaling factor from
a lookup table. Currently the place holder is {8/10, 8/12, 8/14,
8/16}.
Also the data structures are generalized in order to support more
flexible factors instead of sticking with a fixed numerator(8).
Change-Id: I3174795d3be00102411b416cd35252e2f6fcfac0
diff --git a/av1/common/av1_common_int.h b/av1/common/av1_common_int.h
index 11006e2..e5689ea 100644
--- a/av1/common/av1_common_int.h
+++ b/av1/common/av1_common_int.h
@@ -786,11 +786,24 @@
int superres_upscaled_height; /*!< Super-resolved frame height */
/**@}*/
+#if CONFIG_EXT_SUPERRES
+ /**
+ * \name Super-resolution scaling factor information.
+ * The index, numerator, and denominator of the superres scale used by this
+ * frame.
+ */
+ /**@{*/
+ uint8_t superres_scale_index; /*!< Superres scaling index */
+ uint8_t superres_scale_numerator; /*!< Superres scaling numerator */
+ uint8_t superres_scale_denominator; /*!< Superres scaling denominator */
+ /**@}*/
+#else // CONFIG_EXT_SUPERRES
/*!
* The denominator of the superres scale used by this frame.
* Note: The numerator is fixed to be SCALE_NUMERATOR.
*/
uint8_t superres_scale_denominator;
+#endif // CONFIG_EXT_SUPERRES
/*!
* If true, buffer removal times are present.
diff --git a/av1/common/enums.h b/av1/common/enums.h
index dd9a790..25824c5 100644
--- a/av1/common/enums.h
+++ b/av1/common/enums.h
@@ -678,8 +678,13 @@
SCALABILITY_SS = 14
} UENUM1BYTE(SCALABILITY_STRUCTURES);
+#if CONFIG_EXT_SUPERRES
+#define SUPERRES_SCALE_BITS 2
+#define SUPERRES_SCALES (1 << SUPERRES_SCALE_BITS)
+#else // CONFIG_EXT_SUPERRES
#define SUPERRES_SCALE_BITS 3
#define SUPERRES_SCALE_DENOMINATOR_MIN (SCALE_NUMERATOR + 1)
+#endif // CONFIG_EXT_SUPERRES
// In large_scale_tile coding, external references are used.
#define MAX_EXTERNAL_REFERENCES 128
diff --git a/av1/common/resize.c b/av1/common/resize.c
index 95d3368..ffe2346 100644
--- a/av1/common/resize.c
+++ b/av1/common/resize.c
@@ -1348,6 +1348,38 @@
}
}
+#if CONFIG_EXT_SUPERRES
+// Calculates the scaled dimension given the original dimension and the scale
+// denominator.
+static void calculate_scaled_size_helper(int *dim, int denom, int num) {
+ if (denom != num) {
+ // We need to ensure the constraint in "Appendix A" of the spec:
+ // * FrameWidth is greater than or equal to 16
+ // * FrameHeight is greater than or equal to 16
+ // For this, we clamp the downscaled dimension to at least 16. One
+ // exception: if original dimension itself was < 16, then we keep the
+ // downscaled dimension to be same as the original, to ensure that resizing
+ // is valid.
+ const int min_dim = AOMMIN(16, *dim);
+ // Use this version if we need *dim to be even
+ // *width = (*width * SCALE_NUMERATOR + denom) / (2 * denom);
+ // *width <<= 1;
+ *dim = (*dim * num + denom / 2) / (denom);
+ *dim = AOMMAX(*dim, min_dim);
+ }
+}
+
+void av1_calculate_scaled_size(int *width, int *height, int resize_denom) {
+ calculate_scaled_size_helper(width, resize_denom, SCALE_NUMERATOR);
+ calculate_scaled_size_helper(height, resize_denom, SCALE_NUMERATOR);
+}
+
+void av1_calculate_scaled_superres_size(int *width, int *height,
+ int superres_denom, int superres_num) {
+ calculate_scaled_size_helper(width, superres_denom, superres_num);
+ calculate_scaled_size_helper(height, superres_denom, superres_num);
+}
+#else // CONFIG_EXT_SUPERRES
// Calculates the scaled dimension given the original dimension and the scale
// denominator.
static void calculate_scaled_size_helper(int *dim, int denom) {
@@ -1378,6 +1410,7 @@
(void)height;
calculate_scaled_size_helper(width, superres_denom);
}
+#endif // CONFIG_EXT_SUPERRES
void av1_calculate_unscaled_superres_size(int *width, int *height, int denom) {
if (denom != SCALE_NUMERATOR) {
diff --git a/av1/common/resize.h b/av1/common/resize.h
index b08de80..db188a8 100644
--- a/av1/common/resize.h
+++ b/av1/common/resize.h
@@ -20,6 +20,17 @@
extern "C" {
#endif
+typedef struct {
+ uint8_t scale_num;
+ uint8_t scale_denom;
+} ScaleFactor;
+
+#if CONFIG_EXT_SUPERRES
+static const ScaleFactor superres_scales[SUPERRES_SCALES] = {
+ { 8, 10 }, { 8, 12 }, { 8, 14 }, { 8, 16 }
+};
+#endif // CONFIG_EXT_SUPERRES
+
void av1_resize_plane(const uint8_t *const input, int height, int width,
int in_stride, uint8_t *output, int height2, int width2,
int out_stride);
@@ -83,11 +94,17 @@
// Calculates the scaled dimensions from the given original dimensions and the
// resize scale denominator.
void av1_calculate_scaled_size(int *width, int *height, int resize_denom);
-
+#if CONFIG_EXT_SUPERRES
+// Similar to above, but calculates scaled dimensions after superres from the
+// given original dimensions and superres scale denominator.
+void av1_calculate_scaled_superres_size(int *width, int *height,
+ int superres_denom, int superres_num);
+#else // CONFIG_EXT_SUPERRES
// Similar to above, but calculates scaled dimensions after superres from the
// given original dimensions and superres scale denominator.
void av1_calculate_scaled_superres_size(int *width, int *height,
int superres_denom);
+#endif // CONFIG_EXT_SUPERRES
// Inverse of av1_calculate_scaled_superres_size() above: calculates the
// original dimensions from the given scaled dimensions and the scale
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 9cd6888..d21180f 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -59,6 +59,9 @@
#include "av1/common/tile_common.h"
#include "av1/common/warped_motion.h"
#include "av1/common/obmc.h"
+#if CONFIG_EXT_SUPERRES
+#include "av1/common/resize.h"
+#endif // CONFIG_EXT_SUPERRES
#include "av1/decoder/decodeframe.h"
#include "av1/decoder/decodemv.h"
#include "av1/decoder/decoder.h"
@@ -2013,6 +2016,17 @@
if (!seq_params->enable_superres) return;
if (aom_rb_read_bit(rb)) {
+#if CONFIG_EXT_SUPERRES
+ cm->superres_scale_index =
+ (uint8_t)aom_rb_read_literal(rb, SUPERRES_SCALE_BITS);
+ cm->superres_scale_denominator =
+ superres_scales[cm->superres_scale_index].scale_denom;
+ cm->superres_scale_numerator =
+ superres_scales[cm->superres_scale_index].scale_num;
+ av1_calculate_scaled_superres_size(width, height,
+ cm->superres_scale_denominator,
+ cm->superres_scale_numerator);
+#else // CONFIG_EXT_SUPERRES
cm->superres_scale_denominator =
(uint8_t)aom_rb_read_literal(rb, SUPERRES_SCALE_BITS);
cm->superres_scale_denominator += SUPERRES_SCALE_DENOMINATOR_MIN;
@@ -2020,9 +2034,13 @@
// resized correctly
av1_calculate_scaled_superres_size(width, height,
cm->superres_scale_denominator);
+#endif // CONFIG_EXT_SUPERRES
} else {
// 1:1 scaling - ie. no scaling, scale not provided
cm->superres_scale_denominator = SCALE_NUMERATOR;
+#if CONFIG_EXT_SUPERRES
+ cm->superres_scale_numerator = SCALE_NUMERATOR;
+#endif // CONFIG_EXT_SUPERRES
}
}
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index f484e58..88a8dc4 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -2430,21 +2430,42 @@
struct aom_write_bit_buffer *wb) {
const SequenceHeader *const seq_params = &cm->seq_params;
if (!seq_params->enable_superres) {
+#if CONFIG_EXT_SUPERRES
+ assert(cm->superres_scale_denominator == cm->superres_scale_numerator);
+#else // CONFIG_EXT_SUPERRES
assert(cm->superres_scale_denominator == SCALE_NUMERATOR);
+#endif // CONFIG_EXT_SUPERRES
return;
}
// First bit is whether to to scale or not
+#if CONFIG_EXT_SUPERRES
+ if (cm->superres_scale_denominator == cm->superres_scale_numerator) {
+#else // CONFIG_EXT_SUPERRES
if (cm->superres_scale_denominator == SCALE_NUMERATOR) {
+#endif // CONFIG_EXT_SUPERRES
aom_wb_write_bit(wb, 0); // no scaling
} else {
aom_wb_write_bit(wb, 1); // scaling, write scale factor
+#if CONFIG_EXT_SUPERRES
+ assert(cm->superres_scale_denominator > cm->superres_scale_numerator);
+ // Current across-scale prediction can handle downsampling factor <= 2
+ assert(cm->superres_scale_denominator <= 2 * cm->superres_scale_numerator);
+ assert(cm->superres_scale_index >= 0);
+ assert(cm->superres_scale_index < SUPERRES_SCALES);
+ assert(cm->superres_scale_denominator ==
+ superres_scale_denominators[cm->superres_scale_index]);
+ assert(cm->superres_scale_numerator ==
+ superres_scale_numerators[cm->superres_scale_index]);
+ aom_wb_write_literal(wb, cm->superres_scale_index, SUPERRES_SCALE_BITS);
+#else // CONFIG_EXT_SUPERRES
assert(cm->superres_scale_denominator >= SUPERRES_SCALE_DENOMINATOR_MIN);
assert(cm->superres_scale_denominator <
SUPERRES_SCALE_DENOMINATOR_MIN + (1 << SUPERRES_SCALE_BITS));
aom_wb_write_literal(
wb, cm->superres_scale_denominator - SUPERRES_SCALE_DENOMINATOR_MIN,
SUPERRES_SCALE_BITS);
+#endif // CONFIG_EXT_SUPERRES
}
}
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 9ce60bb..5beaa83 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -54,6 +54,9 @@
int resize_width;
int resize_height;
uint8_t superres_denom;
+#if CONFIG_EXT_SUPERRES
+ uint8_t superres_num;
+#endif // CONFIG_EXT_SUPERRES
} size_params_type;
enum {
diff --git a/av1/encoder/superres_scale.c b/av1/encoder/superres_scale.c
index 1ab260d..6c1eca7 100644
--- a/av1/encoder/superres_scale.c
+++ b/av1/encoder/superres_scale.c
@@ -77,6 +77,7 @@
// Choose an arbitrary random number
static unsigned int seed = 56789;
const ResizeCfg *resize_cfg = &cpi->oxcf.resize_cfg;
+
if (is_stat_generation_stage(cpi)) return SCALE_NUMERATOR;
uint8_t new_denom = SCALE_NUMERATOR;
@@ -184,15 +185,29 @@
return denom;
}
+#if CONFIG_EXT_SUPERRES
+// TODO(yuec): redesign the algorithm to return a valid option that is in the
+// new lookup table.
+static ScaleFactor calculate_next_superres_scale(AV1_COMP *cpi) {
+#else // CONFIG_EXT_SUPERRES
static uint8_t calculate_next_superres_scale(AV1_COMP *cpi) {
+#endif // CONFIG_EXT_SUPERRES
// Choose an arbitrary random number
static unsigned int seed = 34567;
const AV1EncoderConfig *oxcf = &cpi->oxcf;
const SuperResCfg *const superres_cfg = &oxcf->superres_cfg;
const FrameDimensionCfg *const frm_dim_cfg = &oxcf->frm_dim_cfg;
const RateControlCfg *const rc_cfg = &oxcf->rc_cfg;
+#if CONFIG_EXT_SUPERRES
+ ScaleFactor factor = { SCALE_NUMERATOR, SCALE_NUMERATOR };
+#endif // CONFIG_EXT_SUPERRES
- if (is_stat_generation_stage(cpi)) return SCALE_NUMERATOR;
+ if (is_stat_generation_stage(cpi))
+#if CONFIG_EXT_SUPERRES
+ return factor;
+#else // CONFIG_EXT_SUPERRES
+ return SCALE_NUMERATOR;
+#endif // CONFIG_EXT_SUPERRES
uint8_t new_denom = SCALE_NUMERATOR;
// Make sure that superres mode of the frame is consistent with the
@@ -269,9 +284,27 @@
}
default: assert(0);
}
+#if CONFIG_EXT_SUPERRES
+ factor.scale_denom = new_denom;
+ return factor;
+#else // CONFIG_EXT_SUPERRES
return new_denom;
+#endif // CONFIG_EXT_SUPERRES
}
+#if CONFIG_EXT_SUPERRES
+static int dimension_is_ok(int orig_dim, int resized_dim, int denom, int nom) {
+ return (resized_dim * nom >= orig_dim * denom / 2);
+}
+
+static int dimensions_are_ok(int owidth, int oheight, size_params_type *rsz) {
+ const uint8_t denom = rsz->superres_denom;
+ const uint8_t nom = rsz->superres_num;
+
+ return dimension_is_ok(owidth, rsz->resize_width, denom, nom) &&
+ dimension_is_ok(oheight, rsz->resize_height, denom, nom);
+}
+#else // CONFIG_EXT_SUPERRES
static int dimension_is_ok(int orig_dim, int resized_dim, int denom) {
return (resized_dim * SCALE_NUMERATOR >= orig_dim * denom / 2);
}
@@ -281,6 +314,7 @@
(void)oheight;
return dimension_is_ok(owidth, rsz->resize_width, rsz->superres_denom);
}
+#endif // CONFIG_EXT_SUPERRES
static int validate_size_scales(RESIZE_MODE resize_mode,
aom_superres_mode superres_mode, int owidth,
@@ -323,7 +357,12 @@
superres_mode == AOM_SUPERRES_RANDOM) {
// Alter both resize and superres scales as needed to enforce conformity.
do {
+#if CONFIG_EXT_SUPERRES
+ if (resize_denom * rsz->superres_num >
+ rsz->superres_denom * SCALE_NUMERATOR)
+#else // CONFIG_EXT_SUPERRES
if (resize_denom > rsz->superres_denom)
+#endif // CONFIG_EXT_SUPERRES
--resize_denom;
else
--rsz->superres_denom;
@@ -333,7 +372,11 @@
resize_denom);
} while (!dimensions_are_ok(owidth, oheight, rsz) &&
(resize_denom > SCALE_NUMERATOR ||
+#if CONFIG_EXT_SUPERRES
+ rsz->superres_denom > rsz->superres_num));
+#else // CONFIG_EXT_SUPERRES
rsz->superres_denom > SCALE_NUMERATOR));
+#endif // CONFIG_EXT_SUPERRES
} else { // We are allowed to alter neither resize scale nor superres
// scale.
return 0;
@@ -346,8 +389,14 @@
const AV1EncoderConfig *oxcf = &cpi->oxcf;
ResizePendingParams *resize_pending_params = &cpi->resize_pending_params;
const FrameDimensionCfg *const frm_dim_cfg = &oxcf->frm_dim_cfg;
+#if CONFIG_EXT_SUPERRES
+ size_params_type rsz = { frm_dim_cfg->width, frm_dim_cfg->height,
+ SCALE_NUMERATOR, SCALE_NUMERATOR };
+ ScaleFactor factor;
+#else // CONFIG_EXT_SUPERRES
size_params_type rsz = { frm_dim_cfg->width, frm_dim_cfg->height,
SCALE_NUMERATOR };
+#endif // CONFIG_EXT_SUPERRES
int resize_denom = SCALE_NUMERATOR;
if (has_no_stats_stage(cpi) && cpi->use_svc &&
cpi->svc.spatial_layer_id < cpi->svc.number_spatial_layers - 1) {
@@ -368,7 +417,13 @@
av1_calculate_scaled_size(&rsz.resize_width, &rsz.resize_height,
resize_denom);
}
+#if CONFIG_EXT_SUPERRES
+ factor = calculate_next_superres_scale(cpi);
+ rsz.superres_denom = factor.scale_denom;
+ rsz.superres_num = factor.scale_num;
+#else // CONFIG_EXT_SUPERRES
rsz.superres_denom = calculate_next_superres_scale(cpi);
+#endif // CONFIG_EXT_SUPERRES
if (!validate_size_scales(oxcf->resize_cfg.resize_mode, cpi->superres_mode,
frm_dim_cfg->width, frm_dim_cfg->height, &rsz))
assert(0 && "Invalid scale parameters");
@@ -384,8 +439,14 @@
cm->superres_upscaled_width = encode_width;
cm->superres_upscaled_height = encode_height;
cm->superres_scale_denominator = rsz->superres_denom;
+#if CONFIG_EXT_SUPERRES
+ cm->superres_scale_numerator = rsz->superres_num;
+ av1_calculate_scaled_superres_size(&encode_width, &encode_height,
+ rsz->superres_denom, rsz->superres_num);
+#else
av1_calculate_scaled_superres_size(&encode_width, &encode_height,
rsz->superres_denom);
+#endif
av1_set_frame_size(cpi, encode_width, encode_height);
}
@@ -393,7 +454,19 @@
AV1_COMMON *cm = &cpi->common;
// Reset superres params from previous frame.
cm->superres_scale_denominator = SCALE_NUMERATOR;
+#if CONFIG_EXT_SUPERRES
+ cm->superres_scale_numerator = SCALE_NUMERATOR;
+#endif // CONFIG_EXT_SUPERRES
const size_params_type rsz = calculate_next_size_params(cpi);
+#if CONFIG_EXT_SUPERRES
+ // TODO(yuec): get the index from the decision made above once the new
+ // algorithm for selecting the scaling factor is completed.
+ cm->superres_scale_index = 0;
+ cm->superres_scale_denominator =
+ superres_scales[cm->superres_scale_index].scale_denom;
+ cm->superres_scale_numerator =
+ superres_scales[cm->superres_scale_index].scale_num;
+#endif // CONFIG_EXT_SUPERRES
setup_frame_size_from_params(cpi, &rsz);
assert(av1_is_min_tile_width_satisfied(cm));
diff --git a/av1/encoder/superres_scale.h b/av1/encoder/superres_scale.h
index 450a4ed..2a348a2 100644
--- a/av1/encoder/superres_scale.h
+++ b/av1/encoder/superres_scale.h
@@ -13,6 +13,7 @@
#define AOM_AV1_ENCODER_SUPERRES_SCALE_H_
#include "av1/encoder/encoder.h"
+#include "av1/common/resize.h"
#ifdef __cplusplus
extern "C" {