From e75084134b92ac3c865f25ad2540162f6198c8c5 Mon Sep 17 00:00:00 2001 From: Fergus Simpson Date: Tue, 14 Mar 2017 18:14:09 -0700 Subject: [PATCH] frame_superres: Add scale to uncompressed header A bit and a three bit literal have been added to the uncompressed frame header for use by the frame superres experiment. The bit is true if scaling is to be used, and is immediately followed by a three bit literal that encodes the scale to use. If the first bit is false, scaling is disabled and the scale factor numerator is set to the denominator (ie. 1:1 scaling). No literal follows if scaling is disabled. The denominator has been defined as a constant 16. The literal is biased by a defined constant of 8 - allowing fractions from 1/2 to 15/16 scaling in steps of 1/16 when scaling is used. Experimentation will be needed to discover which of these are useful. The bit and literal are immediately after the optional render_width and render_height, so that the superres parameters can be written and read just after the regular width and height, without interfering with the render_size parameters. This patch also adds an arbitrary write to make the scale 1:1, so as to not trigger any scaling until it's ready. Accompanying encode and decode helper functions are added. Change-Id: I8caa6247c73f5c7f84ef1fde1e80eb9b20bde0e3 --- av1/common/enums.h | 2 ++ av1/decoder/decodeframe.c | 37 ++++++++++++++++++++++++++++- av1/encoder/bitstream.c | 49 +++++++++++++++++++++++++++++++++++---- 3 files changed, 82 insertions(+), 6 deletions(-) diff --git a/av1/common/enums.h b/av1/common/enums.h index 52b0b9a98..00860f91c 100644 --- a/av1/common/enums.h +++ b/av1/common/enums.h @@ -504,6 +504,8 @@ typedef enum { } RestorationType; #if CONFIG_FRAME_SUPERRES #define SUPERRES_SCALE_DENOMINATOR 16 +#define SUPERRES_SCALE_BITS 3 +#define SUPERRES_SCALE_NUMERATOR_MIN 8 #endif // CONFIG_FRAME_SUPERRES #endif // CONFIG_LOOP_RESTORATION #ifdef __cplusplus diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c index fae9715af..5cec036d3 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c @@ -2798,6 +2798,38 @@ static void setup_render_size(AV1_COMMON *cm, struct aom_read_bit_buffer *rb) { av1_read_frame_size(rb, &cm->render_width, &cm->render_height); } +#if CONFIG_LOOP_RESTORATION && CONFIG_FRAME_SUPERRES +// TODO(afergs): make "struct aom_read_bit_buffer *const rb"? +static void setup_superres_size(AV1_COMMON *const cm, + struct aom_read_bit_buffer *rb, int *width, + int *height) { + // TODO(afergs): Test this behaviour + // Frame superres is probably in compatible with this render resolution + assert(cm->width == cm->render_width && cm->height == cm->render_height); + + cm->superres_width = cm->width; + cm->superres_height = cm->height; + if (aom_rb_read_bit(rb)) { + cm->superres_scale_numerator = + (uint8_t)aom_rb_read_literal(rb, SUPERRES_SCALE_BITS); + cm->superres_scale_numerator += SUPERRES_SCALE_NUMERATOR_MIN; + // Don't edit cm->width or cm->height directly, or the buffers won't get + // resized correctly + // TODO(afergs): Should the render resolution not be modified? It's the same + // by default (ie. when it isn't sent)... + // resize_context_buffers() will change cm->width to equal cm->render_width, + // then they'll be the same again + *width = cm->render_width = + cm->width * cm->superres_scale_numerator / SUPERRES_SCALE_DENOMINATOR; + *height = cm->render_height = + cm->height * cm->superres_scale_numerator / SUPERRES_SCALE_DENOMINATOR; + } else { + // 1:1 scaling - ie. no scaling, scale not provided + cm->superres_scale_numerator = SUPERRES_SCALE_DENOMINATOR; + } +} +#endif // CONFIG_LOOP_RESTORATION && CONFIG_FRAME_SUPERRES + static void resize_mv_buffer(AV1_COMMON *cm) { aom_free(cm->cur_frame->mvs); cm->cur_frame->mi_rows = cm->mi_rows; @@ -2843,8 +2875,11 @@ static void setup_frame_size(AV1_COMMON *cm, struct aom_read_bit_buffer *rb) { int width, height; BufferPool *const pool = cm->buffer_pool; av1_read_frame_size(rb, &width, &height); - resize_context_buffers(cm, width, height); setup_render_size(cm, rb); +#if CONFIG_LOOP_RESTORATION && CONFIG_FRAME_SUPERRES + setup_superres_size(cm, rb, &width, &height); +#endif // CONFIG_LOOP_RESTORATION && CONFIG_FRAME_SUPERRES + resize_context_buffers(cm, width, height); lock_buffer_pool(pool); if (aom_realloc_frame_buffer( diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c index a1641736b..adab30482 100644 --- a/av1/encoder/bitstream.c +++ b/av1/encoder/bitstream.c @@ -4168,12 +4168,48 @@ static void write_render_size(const AV1_COMMON *cm, } } +#if CONFIG_LOOP_RESTORATION && CONFIG_FRAME_SUPERRES +static void write_superres_scale(const AV1_COMMON *const cm, + struct aom_write_bit_buffer *wb) { + // This scaling and frame superres are probably incompatible + assert(cm->width == cm->render_width && cm->height == cm->render_height); + + // First bit is whether to to scale or not + if (cm->superres_scale_numerator == SUPERRES_SCALE_DENOMINATOR) { + aom_wb_write_bit(wb, 0); // no scaling + } else { + aom_wb_write_bit(wb, 1); // scaling, write scale factor + // TODO(afergs): write factor to the compressed header instead + aom_wb_write_literal( + wb, cm->superres_scale_numerator - SUPERRES_SCALE_NUMERATOR_MIN, + SUPERRES_SCALE_BITS); + } +} +#endif // CONFIG_LOOP_RESTORATION && CONFIG_FRAME_SUPERRES + static void write_frame_size(const AV1_COMMON *cm, struct aom_write_bit_buffer *wb) { - aom_wb_write_literal(wb, cm->width - 1, 16); - aom_wb_write_literal(wb, cm->height - 1, 16); +#if CONFIG_LOOP_RESTORATION && CONFIG_FRAME_SUPERRES + // If SUPERRES scaling is happening, write the full resolution instead of the + // downscaled resolution. The decoder will reduce this resolution itself. + if (cm->superres_scale_numerator != SUPERRES_SCALE_DENOMINATOR) { + aom_wb_write_literal(wb, cm->superres_width - 1, 16); + aom_wb_write_literal(wb, cm->superres_height - 1, 16); + } else { +#endif // CONFIG_LOOP_RESTORATION && CONFIG_FRAME_SUPERRES + aom_wb_write_literal(wb, cm->width - 1, 16); + aom_wb_write_literal(wb, cm->height - 1, 16); +#if CONFIG_LOOP_RESTORATION && CONFIG_FRAME_SUPERRES + } +#endif // CONFIG_LOOP_RESTORATION && CONFIG_FRAME_SUPERRES + // TODO(afergs): Also write something different to render_size? + // When superres scales, they'll be almost guaranteed to be + // different on the other side. write_render_size(cm, wb); +#if CONFIG_LOOP_RESTORATION && CONFIG_FRAME_SUPERRES + write_superres_scale(cm, wb); +#endif // CONFIG_LOOP_RESTORATION && CONFIG_FRAME_SUPERRES } static void write_frame_size_with_refs(AV1_COMP *cpi, @@ -4198,9 +4234,7 @@ static void write_frame_size_with_refs(AV1_COMP *cpi, } if (!found) { - aom_wb_write_literal(wb, cm->width - 1, 16); - aom_wb_write_literal(wb, cm->height - 1, 16); - write_render_size(cm, wb); + write_frame_size(cm, wb); } } @@ -4318,6 +4352,11 @@ static void write_uncompressed_header(AV1_COMP *cpi, } #endif +#if CONFIG_LOOP_RESTORATION && CONFIG_FRAME_SUPERRES + // TODO(afergs): Remove - this is just to stop superres from breaking + cm->superres_scale_numerator = SUPERRES_SCALE_DENOMINATOR; +#endif // CONFIG_LOOP_RESTORATION && CONFIG_FRAME_SUPERRES + if (cm->frame_type == KEY_FRAME) { write_sync_code(wb); write_bitdepth_colorspace_sampling(cm, wb); -- GitLab