frame_superres: Post encode/decode upscaling
This patch implements the post-encode and post-decode upscaling for the
frame superresolution experiment to work.
Upscaling happens after cdef and before loop restoration.
For now, this patch forces on random-superres.
The patch also cleans up some broken rate control hooks from VP9
days, to be brought back later when the resize and superres tools
are stable.
Change-Id: If0a8f69224dfaa0f4ae7703bd429ea2af953c7a6
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h
index ea265ec..be8a631 100644
--- a/av1/common/onyxc_int.h
+++ b/av1/common/onyxc_int.h
@@ -302,6 +302,8 @@
#if CONFIG_FRAME_SUPERRES
// The numerator of the superres scale; the denominator is fixed.
uint8_t superres_scale_numerator;
+ int superres_upscaled_width;
+ int superres_upscaled_height;
#endif // CONFIG_FRAME_SUPERRES
#if CONFIG_LOOP_RESTORATION
RestorationInfo rst_info[MAX_MB_PLANE];
diff --git a/av1/common/resize.c b/av1/common/resize.c
index f6fdec7..b5db615 100644
--- a/av1/common/resize.c
+++ b/av1/common/resize.c
@@ -816,11 +816,11 @@
#endif // CONFIG_HIGHBITDEPTH
#if CONFIG_HIGHBITDEPTH
-static void resize_and_extend_frame(const YV12_BUFFER_CONFIG *src,
- YV12_BUFFER_CONFIG *dst, int bd) {
+void av1_resize_and_extend_frame(const YV12_BUFFER_CONFIG *src,
+ YV12_BUFFER_CONFIG *dst, int bd) {
#else
-static void resize_and_extend_frame(const YV12_BUFFER_CONFIG *src,
- YV12_BUFFER_CONFIG *dst) {
+void av1_resize_and_extend_frame(const YV12_BUFFER_CONFIG *src,
+ YV12_BUFFER_CONFIG *dst) {
#endif // CONFIG_HIGHBITDEPTH
// TODO(dkovalev): replace YV12_BUFFER_CONFIG with aom_image_t
int i;
@@ -855,8 +855,8 @@
YV12_BUFFER_CONFIG *av1_scale_if_required_fast(AV1_COMMON *cm,
YV12_BUFFER_CONFIG *unscaled,
YV12_BUFFER_CONFIG *scaled) {
- if (cm->mi_cols * MI_SIZE != unscaled->y_width ||
- cm->mi_rows * MI_SIZE != unscaled->y_height) {
+ if (cm->width != unscaled->y_crop_width ||
+ cm->height != unscaled->y_crop_height) {
// For 2x2 scaling down.
aom_scale_frame(unscaled, scaled, unscaled->y_buffer, 9, 2, 1, 2, 1, 0);
aom_extend_frame_borders(scaled);
@@ -869,14 +869,107 @@
YV12_BUFFER_CONFIG *av1_scale_if_required(AV1_COMMON *cm,
YV12_BUFFER_CONFIG *unscaled,
YV12_BUFFER_CONFIG *scaled) {
- if (cm->width != unscaled->y_width || cm->height != unscaled->y_height) {
+ if (cm->width != unscaled->y_crop_width ||
+ cm->height != unscaled->y_crop_height) {
#if CONFIG_HIGHBITDEPTH
- resize_and_extend_frame(unscaled, scaled, (int)cm->bit_depth);
+ av1_resize_and_extend_frame(unscaled, scaled, (int)cm->bit_depth);
#else
- resize_and_extend_frame(unscaled, scaled);
+ av1_resize_and_extend_frame(unscaled, scaled);
#endif // CONFIG_HIGHBITDEPTH
return scaled;
} else {
return unscaled;
}
}
+
+#if CONFIG_FRAME_SUPERRES
+void av1_calculate_superres_size(const AV1_COMMON *cm, int *width,
+ int *height) {
+ *width = *width * cm->superres_scale_numerator / SUPERRES_SCALE_DENOMINATOR;
+ *height = *height * cm->superres_scale_numerator / SUPERRES_SCALE_DENOMINATOR;
+}
+
+// TODO(afergs): Look for in-place upscaling
+// TODO(afergs): aom_ vs av1_ functions? Which can I use?
+// Upscale decoded image.
+void av1_superres_upscale(AV1_COMMON *cm, BufferPool *const pool) {
+ if (av1_superres_unscaled(cm)) return;
+
+ YV12_BUFFER_CONFIG copy_buffer;
+ memset(©_buffer, 0, sizeof(copy_buffer));
+
+ YV12_BUFFER_CONFIG *const frame_to_show = get_frame_new_buffer(cm);
+
+ if (aom_alloc_frame_buffer(©_buffer, cm->width, cm->height,
+ cm->subsampling_x, cm->subsampling_y,
+#ifdef CONFIG_HIGHBITDEPTH
+ cm->use_highbitdepth,
+#endif // CONFIG_HIGHBITDEPTH
+ AOM_BORDER_IN_PIXELS, cm->byte_alignment))
+ aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
+ "Failed to allocate copy buffer for superres upscaling");
+
+ // Copy function assumes the frames are the same size, doesn't copy bit_depth.
+ aom_yv12_copy_frame(frame_to_show, ©_buffer);
+ copy_buffer.bit_depth = frame_to_show->bit_depth;
+ assert(copy_buffer.y_crop_width == cm->width);
+ assert(copy_buffer.y_crop_height == cm->height);
+
+ // Realloc the current frame buffer at a higher resolution in place.
+ if (pool != NULL) {
+ // Use callbacks if on the decoder.
+ aom_codec_frame_buffer_t *fb =
+ &pool->frame_bufs[cm->new_fb_idx].raw_frame_buffer;
+ aom_release_frame_buffer_cb_fn_t release_fb_cb = pool->release_fb_cb;
+ aom_get_frame_buffer_cb_fn_t cb = pool->get_fb_cb;
+ void *cb_priv = pool->cb_priv;
+
+ // Realloc with callback does not release the frame buffer - release first.
+ if (release_fb_cb(cb_priv, fb))
+ aom_internal_error(
+ &cm->error, AOM_CODEC_MEM_ERROR,
+ "Failed to free current frame buffer before superres upscaling");
+
+ if (aom_realloc_frame_buffer(
+ frame_to_show, cm->superres_upscaled_width,
+ cm->superres_upscaled_height, cm->subsampling_x, cm->subsampling_y,
+#ifdef CONFIG_HIGHBITDEPTH
+ cm->use_highbitdepth,
+#endif // CONFIG_HIGHBITDEPTH
+ AOM_BORDER_IN_PIXELS, cm->byte_alignment, fb, cb, cb_priv))
+ aom_internal_error(
+ &cm->error, AOM_CODEC_MEM_ERROR,
+ "Failed to allocate current frame buffer for superres upscaling");
+ } else {
+ // Don't use callbacks on the encoder.
+ if (aom_alloc_frame_buffer(frame_to_show, cm->superres_upscaled_width,
+ cm->superres_upscaled_height, cm->subsampling_x,
+ cm->subsampling_y,
+#ifdef CONFIG_HIGHBITDEPTH
+ cm->use_highbitdepth,
+#endif // CONFIG_HIGHBITDEPTH
+ AOM_BORDER_IN_PIXELS, cm->byte_alignment))
+ aom_internal_error(
+ &cm->error, AOM_CODEC_MEM_ERROR,
+ "Failed to reallocate current frame buffer for superres upscaling");
+ }
+ // TODO(afergs): verify frame_to_show is correct after realloc
+ // encoder:
+ // decoder:
+ frame_to_show->bit_depth = copy_buffer.bit_depth;
+ assert(frame_to_show->y_crop_width == cm->superres_upscaled_width);
+ assert(frame_to_show->y_crop_height == cm->superres_upscaled_height);
+
+ // Scale up and back into frame_to_show.
+ assert(frame_to_show->y_crop_width != cm->width);
+ assert(frame_to_show->y_crop_height != cm->height);
+#if CONFIG_HIGHBITDEPTH
+ av1_resize_and_extend_frame(©_buffer, frame_to_show, (int)cm->bit_depth);
+#else
+ av1_resize_and_extend_frame(©_buffer, frame_to_show);
+#endif // CONFIG_HIGHBITDEPTH
+
+ // Free the copy buffer
+ aom_free_frame_buffer(©_buffer);
+}
+#endif // CONFIG_FRAME_SUPERRES
diff --git a/av1/common/resize.h b/av1/common/resize.h
index 9bdba33..e67b7fe 100644
--- a/av1/common/resize.h
+++ b/av1/common/resize.h
@@ -63,6 +63,14 @@
int owidth, int bd);
#endif // CONFIG_HIGHBITDEPTH
+#if CONFIG_HIGHBITDEPTH
+void av1_resize_and_extend_frame(const YV12_BUFFER_CONFIG *src,
+ YV12_BUFFER_CONFIG *dst, int bd);
+#else
+void av1_resize_and_extend_frame(const YV12_BUFFER_CONFIG *src,
+ YV12_BUFFER_CONFIG *dst);
+#endif // CONFIG_HIGHBITDEPTH
+
YV12_BUFFER_CONFIG *av1_scale_if_required_fast(AV1_COMMON *cm,
YV12_BUFFER_CONFIG *unscaled,
YV12_BUFFER_CONFIG *scaled);
@@ -71,6 +79,21 @@
YV12_BUFFER_CONFIG *unscaled,
YV12_BUFFER_CONFIG *scaled);
+#if CONFIG_FRAME_SUPERRES
+// This is the size after superress scaling, which could be 1:1.
+// Superres scaling happens after regular downscaling.
+// TODO(afergs): Limit overall reduction to 1/2 of the original size
+void av1_calculate_superres_size(const AV1_COMMON *cm, int *width, int *height);
+
+void av1_superres_upscale(AV1_COMMON *cm, BufferPool *const pool);
+
+// Returns 1 if a superres upscaled frame is unscaled and 0 otherwise.
+static INLINE int av1_superres_unscaled(const AV1_COMMON *cm) {
+ return (cm->superres_scale_numerator == SUPERRES_SCALE_DENOMINATOR);
+}
+
+#endif // CONFIG_FRAME_SUPERRES
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index d7749dd..5e5db93 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -49,6 +49,9 @@
#include "av1/common/quant_common.h"
#include "av1/common/reconinter.h"
#include "av1/common/reconintra.h"
+#if CONFIG_FRAME_SUPERRES
+#include "av1/common/resize.h"
+#endif // CONFIG_FRAME_SUPERRES
#include "av1/common/seg_common.h"
#include "av1/common/thread_common.h"
#include "av1/common/tile_common.h"
@@ -2203,6 +2206,7 @@
partition,
#endif
bsize);
+
#if !(CONFIG_MOTION_VAR && CONFIG_NCOBMC)
#if CONFIG_SUPERTX
if (!supertx_enabled)
@@ -3020,31 +3024,30 @@
}
static void setup_render_size(AV1_COMMON *cm, struct aom_read_bit_buffer *rb) {
+#if CONFIG_FRAME_SUPERRES
+ cm->render_width = cm->superres_upscaled_width;
+ cm->render_height = cm->superres_upscaled_height;
+#else
cm->render_width = cm->width;
cm->render_height = cm->height;
+#endif // CONFIG_FRAME_SUPERRES
if (aom_rb_read_bit(rb))
av1_read_frame_size(rb, &cm->render_width, &cm->render_height);
}
#if 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): Save input resolution - it's the upscaled resolution
+static void setup_superres(AV1_COMMON *const cm, struct aom_read_bit_buffer *rb,
+ int *width, int *height) {
+ cm->superres_upscaled_width = *width;
+ cm->superres_upscaled_height = *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 = *width * cm->superres_scale_numerator / SUPERRES_SCALE_DENOMINATOR;
- *height =
- *width * cm->superres_scale_numerator / SUPERRES_SCALE_DENOMINATOR;
+ av1_calculate_superres_size(cm, width, height);
} else {
// 1:1 scaling - ie. no scaling, scale not provided
cm->superres_scale_numerator = SUPERRES_SCALE_DENOMINATOR;
@@ -3097,10 +3100,10 @@
int width, height;
BufferPool *const pool = cm->buffer_pool;
av1_read_frame_size(rb, &width, &height);
- setup_render_size(cm, rb);
#if CONFIG_FRAME_SUPERRES
- setup_superres_size(cm, rb, &width, &height);
+ setup_superres(cm, rb, &width, &height);
#endif // CONFIG_FRAME_SUPERRES
+ setup_render_size(cm, rb);
resize_context_buffers(cm, width, height);
lock_buffer_pool(pool);
@@ -3149,6 +3152,9 @@
height = buf->y_crop_height;
cm->render_width = buf->render_width;
cm->render_height = buf->render_height;
+#if CONFIG_FRAME_SUPERRES
+ setup_superres(cm, rb, &width, &height);
+#endif // CONFIG_FRAME_SUPERRES
found = 1;
break;
}
@@ -3156,10 +3162,10 @@
if (!found) {
av1_read_frame_size(rb, &width, &height);
- setup_render_size(cm, rb);
#if CONFIG_FRAME_SUPERRES
- setup_superres_size(cm, rb, &width, &height);
+ setup_superres(cm, rb, &width, &height);
#endif // CONFIG_FRAME_SUPERRES
+ setup_render_size(cm, rb);
}
if (width <= 0 || height <= 0)
@@ -5186,6 +5192,19 @@
}
#endif
+#if CONFIG_FRAME_SUPERRES
+void superres_post_decode(AV1Decoder *pbi) {
+ AV1_COMMON *const cm = &pbi->common;
+ BufferPool *const pool = cm->buffer_pool;
+
+ if (av1_superres_unscaled(cm)) return;
+
+ lock_buffer_pool(pool);
+ av1_superres_upscale(cm, pool);
+ unlock_buffer_pool(pool);
+}
+#endif // CONFIG_FRAME_SUPERRES
+
void av1_decode_frame(AV1Decoder *pbi, const uint8_t *data,
const uint8_t *data_end, const uint8_t **p_data_end) {
AV1_COMMON *const cm = &pbi->common;
@@ -5281,14 +5300,23 @@
#if CONFIG_TEMPMV_SIGNALING
if (cm->use_prev_frame_mvs) {
assert(!cm->error_resilient_mode && cm->prev_frame &&
- cm->width == last_fb_ref_buf->buf->y_width &&
- cm->height == last_fb_ref_buf->buf->y_height &&
+#if CONFIG_FRAME_SUPERRES
+ cm->width == cm->last_width && cm->height == cm->last_height &&
+#else
+ cm->width == last_fb_ref_buf->buf->y_crop_width &&
+ cm->height == last_fb_ref_buf->buf->y_crop_height &&
+#endif // CONFIG_FRAME_SUPERRES
!cm->prev_frame->intra_only);
}
#else
cm->use_prev_frame_mvs = !cm->error_resilient_mode && cm->prev_frame &&
+#if CONFIG_FRAME_SUPERRES
+ cm->width == cm->last_width &&
+ cm->height == cm->last_height &&
+#else
cm->width == cm->prev_frame->buf.y_crop_width &&
cm->height == cm->prev_frame->buf.y_crop_height &&
+#endif // CONFIG_FRAME_SUPERRES
!cm->last_intra_only && cm->last_show_frame &&
(cm->last_frame_type != KEY_FRAME);
#endif // CONFIG_TEMPMV_SIGNALING
@@ -5361,6 +5389,10 @@
}
#endif // CONFIG_CDEF
+#if CONFIG_FRAME_SUPERRES
+ superres_post_decode(pbi);
+#endif // CONFIG_FRAME_SUPERRES
+
#if CONFIG_LOOP_RESTORATION
if (cm->rst_info[0].frame_restoration_type != RESTORE_NONE ||
cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
diff --git a/av1/decoder/decoder.c b/av1/decoder/decoder.c
index eac280d..15a227c 100644
--- a/av1/decoder/decoder.c
+++ b/av1/decoder/decoder.c
@@ -444,7 +444,10 @@
// border.
if (pbi->dec_tile_row == -1 && pbi->dec_tile_col == -1)
#endif // CONFIG_EXT_TILE
- aom_extend_frame_inner_borders(cm->frame_to_show);
+ // TODO(debargha): Fix encoder side mv range, so that we can use the
+ // inner border extension. As of now use the larger extension.
+ // aom_extend_frame_inner_borders(cm->frame_to_show);
+ aom_extend_frame_borders(cm->frame_to_show);
aom_clear_system_state();
diff --git a/av1/encoder/aq_cyclicrefresh.c b/av1/encoder/aq_cyclicrefresh.c
index b2b4106..05aa28c 100644
--- a/av1/encoder/aq_cyclicrefresh.c
+++ b/av1/encoder/aq_cyclicrefresh.c
@@ -352,10 +352,7 @@
// For video conference clips, if the background has high motion in current
// frame because of the camera movement, set this frame as the golden frame.
// Use 70% and 5% as the thresholds for golden frame refreshing.
- // Also, force this frame as a golden update frame if this frame will change
- // the resolution (av1_resize_pending != 0).
- if (av1_resize_pending(cpi) ||
- (cnt1 * 10 > (70 * rows * cols) && cnt2 * 20 < cnt1)) {
+ if (cnt1 * 10 > (70 * rows * cols) && cnt2 * 20 < cnt1) {
av1_cyclic_refresh_set_golden_update(cpi);
rc->frames_till_gf_update_due = rc->baseline_gf_interval;
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index c44867b..fb8ab94 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -4172,8 +4172,7 @@
static void write_render_size(const AV1_COMMON *cm,
struct aom_write_bit_buffer *wb) {
- const int scaling_active =
- cm->width != cm->render_width || cm->height != cm->render_height;
+ const int scaling_active = !av1_resize_unscaled(cm);
aom_wb_write_bit(wb, scaling_active);
if (scaling_active) {
aom_wb_write_literal(wb, cm->render_width - 1, 16);
@@ -4189,7 +4188,6 @@
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);
@@ -4199,13 +4197,15 @@
static void write_frame_size(const AV1_COMMON *cm,
struct aom_write_bit_buffer *wb) {
+#if CONFIG_FRAME_SUPERRES
+ aom_wb_write_literal(wb, cm->superres_upscaled_width - 1, 16);
+ aom_wb_write_literal(wb, cm->superres_upscaled_height - 1, 16);
+ write_superres_scale(cm, wb);
+#else
aom_wb_write_literal(wb, cm->width - 1, 16);
aom_wb_write_literal(wb, cm->height - 1, 16);
-
- write_render_size(cm, wb);
-#if CONFIG_FRAME_SUPERRES
- write_superres_scale(cm, wb);
#endif // CONFIG_FRAME_SUPERRES
+ write_render_size(cm, wb);
}
static void write_frame_size_with_refs(AV1_COMP *cpi,
@@ -4218,20 +4218,26 @@
YV12_BUFFER_CONFIG *cfg = get_ref_frame_buffer(cpi, ref_frame);
if (cfg != NULL) {
+#if CONFIG_FRAME_SUPERRES
+ found = cm->superres_upscaled_width == cfg->y_crop_width &&
+ cm->superres_upscaled_height == cfg->y_crop_height;
+#else
found =
cm->width == cfg->y_crop_width && cm->height == cfg->y_crop_height;
+#endif
found &= cm->render_width == cfg->render_width &&
cm->render_height == cfg->render_height;
}
aom_wb_write_bit(wb, found);
if (found) {
+#if CONFIG_FRAME_SUPERRES
+ write_superres_scale(cm, wb);
+#endif // CONFIG_FRAME_SUPERRES
break;
}
}
- if (!found) {
- write_frame_size(cm, wb);
- }
+ if (!found) write_frame_size(cm, wb);
}
static void write_sync_code(struct aom_write_bit_buffer *wb) {
@@ -4370,11 +4376,6 @@
}
#endif
-#if CONFIG_FRAME_SUPERRES
- // TODO(afergs): Remove - this is just to stop superres from breaking
- cm->superres_scale_numerator = SUPERRES_SCALE_DENOMINATOR;
-#endif // CONFIG_FRAME_SUPERRES
-
if (cm->frame_type == KEY_FRAME) {
write_sync_code(wb);
write_bitdepth_colorspace_sampling(cm, wb);
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index 4e30d16..a0eed78 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -4860,17 +4860,31 @@
#if CONFIG_TEMPMV_SIGNALING
if (cm->prev_frame) {
cm->use_prev_frame_mvs &= !cm->error_resilient_mode &&
- cm->width == cm->prev_frame->buf.y_width &&
- cm->height == cm->prev_frame->buf.y_height &&
+#if CONFIG_FRAME_SUPERRES
+ cm->width == cm->last_width &&
+ cm->height == cm->last_height &&
+#else
+ cm->width == cm->prev_frame->buf.y_crop_width &&
+ cm->height == cm->prev_frame->buf.y_crop_height &&
+#endif // CONFIG_FRAME_SUPERRES
!cm->intra_only && !cm->prev_frame->intra_only;
} else {
cm->use_prev_frame_mvs = 0;
}
#else
- cm->use_prev_frame_mvs = !cm->error_resilient_mode && cm->prev_frame &&
- cm->width == cm->prev_frame->buf.y_crop_width &&
- cm->height == cm->prev_frame->buf.y_crop_height &&
- !cm->intra_only && cm->last_show_frame;
+ if (cm->prev_frame) {
+ cm->use_prev_frame_mvs = !cm->error_resilient_mode &&
+#if CONFIG_FRAME_SUPERRES
+ cm->width == cm->last_width &&
+ cm->height == cm->last_height &&
+#else
+ cm->width == cm->prev_frame->buf.y_crop_width &&
+ cm->height == cm->prev_frame->buf.y_crop_height &&
+#endif // CONFIG_FRAME_SUPERRES
+ !cm->intra_only && cm->last_show_frame;
+ } else {
+ cm->use_prev_frame_mvs = 0;
+ }
#endif // CONFIG_TEMPMV_SIGNALING
// Special case: set prev_mi to NULL when the previous mode info
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index f27928b..e9a27a9 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -2099,10 +2099,6 @@
cpi->resize_state = 0;
cpi->resize_avg_qp = 0;
cpi->resize_buffer_underflow = 0;
- cpi->resize_scale_num = 16;
- cpi->resize_scale_den = 16;
- cpi->resize_next_scale_num = 16;
- cpi->resize_next_scale_den = 16;
cpi->common.buffer_pool = pool;
@@ -2450,6 +2446,8 @@
av1_loop_filter_init(cm);
#if CONFIG_FRAME_SUPERRES
cm->superres_scale_numerator = SUPERRES_SCALE_DENOMINATOR;
+ cm->superres_upscaled_width = oxcf->scaled_frame_width;
+ cm->superres_upscaled_height = oxcf->scaled_frame_height;
#endif // CONFIG_FRAME_SUPERRES
#if CONFIG_LOOP_RESTORATION
av1_loop_restoration_precal();
@@ -3380,61 +3378,6 @@
#endif // DUMP_REF_FRAME_IMAGES
}
-static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) {
- MACROBLOCKD *xd = &cpi->td.mb.e_mbd;
- struct loopfilter *lf = &cm->lf;
- if (is_lossless_requested(&cpi->oxcf)) {
- lf->filter_level = 0;
- } else {
- struct aom_usec_timer timer;
-
- aom_clear_system_state();
-
- aom_usec_timer_start(&timer);
-
- av1_pick_filter_level(cpi->source, cpi, cpi->sf.lpf_pick);
-
- aom_usec_timer_mark(&timer);
- cpi->time_pick_lpf += aom_usec_timer_elapsed(&timer);
- }
-
- if (lf->filter_level > 0) {
-#if CONFIG_VAR_TX || CONFIG_EXT_PARTITION || CONFIG_CB4X4
- av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level, 0, 0);
-#else
- if (cpi->num_workers > 1)
- av1_loop_filter_frame_mt(cm->frame_to_show, cm, xd->plane,
- lf->filter_level, 0, 0, cpi->workers,
- cpi->num_workers, &cpi->lf_row_sync);
- else
- av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level, 0, 0);
-#endif
- }
-#if CONFIG_CDEF
- if (is_lossless_requested(&cpi->oxcf)) {
- cm->cdef_bits = 0;
- cm->cdef_strengths[0] = 0;
- cm->nb_cdef_strengths = 1;
- } else {
- // Find cm->dering_level, cm->clpf_strength_u and cm->clpf_strength_v
- av1_cdef_search(cm->frame_to_show, cpi->source, cm, xd,
- cpi->oxcf.speed > 0);
-
- // Apply the filter
- av1_cdef_frame(cm->frame_to_show, cm, xd);
- }
-#endif
-#if CONFIG_LOOP_RESTORATION
- av1_pick_filter_restoration(cpi->source, cpi, cpi->sf.lpf_pick);
- if (cm->rst_info[0].frame_restoration_type != RESTORE_NONE ||
- cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
- cm->rst_info[2].frame_restoration_type != RESTORE_NONE) {
- av1_loop_restoration_frame(cm->frame_to_show, cm, cm->rst_info, 7, 0, NULL);
- }
-#endif // CONFIG_LOOP_RESTORATION
- aom_extend_frame_inner_borders(cm->frame_to_show);
-}
-
static INLINE void alloc_frame_mvs(AV1_COMMON *const cm, int buffer_idx) {
RefCntBuffer *const new_fb_ptr = &cm->buffer_pool->frame_bufs[buffer_idx];
if (new_fb_ptr->mvs == NULL || new_fb_ptr->mi_rows < cm->mi_rows ||
@@ -3789,56 +3732,19 @@
}
#endif // CONFIG_LOOP_RESTORATION
-static void set_scaled_size(AV1_COMP *cpi) {
- AV1_COMMON *const cm = &cpi->common;
- AV1EncoderConfig *const oxcf = &cpi->oxcf;
-
- // TODO(afergs): Replace with call to av1_resize_pending? Could replace
- // scaled_size_set as well.
- // TODO(afergs): Realistically, if resize_pending is true, then the other
- // conditions must already be satisfied.
- // Try this first:
- // av1_resize_pending &&
- // (DYNAMIC && (1 Pass CBR || 2 Pass VBR)
- // STATIC && FIRST_FRAME)
- // Really, av1_resize_pending should just reflect the above.
- // TODO(afergs): Allow fixed resizing in AOM_CBR mode?
- // 2 Pass VBR: Resize if fixed resize and first frame, or dynamic resize and
- // a resize is pending.
- // 1 Pass CBR: Resize if dynamic resize and resize pending.
- if ((oxcf->pass == 2 && oxcf->rc_mode == AOM_VBR &&
- ((oxcf->resize_mode == RESIZE_FIXED && cm->current_video_frame == 0) ||
- (oxcf->resize_mode == RESIZE_DYNAMIC && av1_resize_pending(cpi)))) ||
- (oxcf->pass == 0 && oxcf->rc_mode == AOM_CBR &&
- oxcf->resize_mode == RESIZE_DYNAMIC && av1_resize_pending(cpi))) {
- // TODO(afergs): This feels hacky... Should it just set? Should
- // av1_set_next_scaled_size be a library function?
- av1_calculate_next_scaled_size(cpi, &oxcf->scaled_frame_width,
- &oxcf->scaled_frame_height);
- }
-}
-
static void set_frame_size(AV1_COMP *cpi, int width, int height) {
- int ref_frame;
AV1_COMMON *const cm = &cpi->common;
- AV1EncoderConfig *const oxcf = &cpi->oxcf;
MACROBLOCKD *const xd = &cpi->td.mb.e_mbd;
+ int ref_frame;
if (width != cm->width || height != cm->height) {
// There has been a change in the encoded frame size
av1_set_size_literal(cpi, width, height);
-
- // TODO(agrange) Scale cpi->max_mv_magnitude if frame-size has changed.
- // TODO(afergs): Make condition just (pass == 0) or (rc_mode == CBR) -
- // UNLESS CBR starts allowing FIXED resizing. Then the resize
- // mode will need to get checked too.
- if (oxcf->pass == 0 && oxcf->rc_mode == AOM_CBR &&
- oxcf->resize_mode == RESIZE_DYNAMIC)
- set_mv_search_params(cpi); // TODO(afergs): Needed? Caller calls after...
+ set_mv_search_params(cpi);
}
#if !CONFIG_XIPHRC
- if (oxcf->pass == 2) {
+ if (cpi->oxcf.pass == 2) {
av1_set_target_rate(cpi);
}
#endif
@@ -3857,6 +3763,7 @@
"Failed to allocate frame buffer");
#if CONFIG_LOOP_RESTORATION
+ // TODO(afergs): Use cm->superres_upscaled_(width|height)
set_restoration_tilesize(cm->width, cm->height, cm->rst_info);
for (int i = 0; i < MAX_MB_PLANE; ++i)
cm->rst_info[i].frame_restoration_type = RESTORE_NONE;
@@ -3915,16 +3822,124 @@
}
static void setup_frame_size(AV1_COMP *cpi) {
- set_scaled_size(cpi);
-#if CONFIG_FRAME_SUPERRES
int encode_width;
int encode_height;
- av1_calculate_superres_size(cpi, &encode_width, &encode_height);
- set_frame_size(cpi, encode_width, encode_height);
-#else
- set_frame_size(cpi, cpi->oxcf.scaled_frame_width,
- cpi->oxcf.scaled_frame_height);
+
+ av1_calculate_next_scaled_size(cpi, &encode_width, &encode_height);
+
+#if CONFIG_FRAME_SUPERRES
+ AV1_COMMON *cm = &cpi->common;
+ cm->superres_upscaled_width = encode_width;
+ cm->superres_upscaled_height = encode_height;
+ av1_calculate_next_superres_scale(cpi, encode_width, encode_width);
+ av1_calculate_superres_size(cm, &encode_width, &encode_height);
#endif // CONFIG_FRAME_SUPERRES
+
+ set_frame_size(cpi, encode_width, encode_height);
+}
+
+#if CONFIG_FRAME_SUPERRES
+static void superres_post_encode(AV1_COMP *cpi) {
+ AV1_COMMON *cm = &cpi->common;
+
+ if (av1_superres_unscaled(cm)) return;
+
+ assert(cpi->unscaled_source->y_crop_width != cm->superres_upscaled_width);
+ assert(cpi->unscaled_source->y_crop_height != cm->superres_upscaled_height);
+
+ av1_superres_upscale(cm, NULL);
+
+ // If regular resizing is occurring the source will need to be downscaled to
+ // match the upscaled superres resolution. Otherwise the original source is
+ // used.
+ if (av1_resize_unscaled(cm)) {
+ cpi->source = cpi->unscaled_source;
+ if (cpi->last_source != NULL) cpi->last_source = cpi->unscaled_last_source;
+ } else {
+ // Do downscale. cm->(width|height) has been updated by av1_superres_upscale
+ if (aom_realloc_frame_buffer(
+ &cpi->scaled_source, cm->superres_upscaled_width,
+ cm->superres_upscaled_height, cm->subsampling_x, cm->subsampling_y,
+#if CONFIG_HIGHBITDEPTH
+ cm->use_highbitdepth,
+#endif // CONFIG_HIGHBITDEPTH
+ AOM_BORDER_IN_PIXELS, cm->byte_alignment, NULL, NULL, NULL))
+ aom_internal_error(
+ &cm->error, AOM_CODEC_MEM_ERROR,
+ "Failed to reallocate scaled source buffer for superres");
+ assert(cpi->scaled_source.y_crop_width == cm->superres_upscaled_width);
+ assert(cpi->scaled_source.y_crop_height == cm->superres_upscaled_height);
+#if CONFIG_HIGHBITDEPTH
+ av1_resize_and_extend_frame(cpi->unscaled_source, &cpi->scaled_source,
+ (int)cm->bit_depth);
+#else
+ av1_resize_and_extend_frame(cpi->unscaled_source, &cpi->scaled_source);
+#endif // CONFIG_HIGHBITDEPTH
+ cpi->source = &cpi->scaled_source;
+ }
+}
+#endif // CONFIG_FRAME_SUPERRES
+
+static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) {
+ MACROBLOCKD *xd = &cpi->td.mb.e_mbd;
+ struct loopfilter *lf = &cm->lf;
+ if (is_lossless_requested(&cpi->oxcf)) {
+ lf->filter_level = 0;
+ } else {
+ struct aom_usec_timer timer;
+
+ aom_clear_system_state();
+
+ aom_usec_timer_start(&timer);
+
+ av1_pick_filter_level(cpi->source, cpi, cpi->sf.lpf_pick);
+
+ aom_usec_timer_mark(&timer);
+ cpi->time_pick_lpf += aom_usec_timer_elapsed(&timer);
+ }
+
+ if (lf->filter_level > 0) {
+#if CONFIG_VAR_TX || CONFIG_EXT_PARTITION || CONFIG_CB4X4
+ av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level, 0, 0);
+#else
+ if (cpi->num_workers > 1)
+ av1_loop_filter_frame_mt(cm->frame_to_show, cm, xd->plane,
+ lf->filter_level, 0, 0, cpi->workers,
+ cpi->num_workers, &cpi->lf_row_sync);
+ else
+ av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level, 0, 0);
+#endif
+ }
+#if CONFIG_CDEF
+ if (is_lossless_requested(&cpi->oxcf)) {
+ cm->cdef_bits = 0;
+ cm->cdef_strengths[0] = 0;
+ cm->nb_cdef_strengths = 1;
+ } else {
+ // Find cm->dering_level, cm->clpf_strength_u and cm->clpf_strength_v
+ av1_cdef_search(cm->frame_to_show, cpi->source, cm, xd,
+ cpi->oxcf.speed > 0);
+
+ // Apply the filter
+ av1_cdef_frame(cm->frame_to_show, cm, xd);
+ }
+#endif
+
+#if CONFIG_FRAME_SUPERRES
+ superres_post_encode(cpi);
+#endif // CONFIG_FRAME_SUPERRES
+
+#if CONFIG_LOOP_RESTORATION
+ av1_pick_filter_restoration(cpi->source, cpi, cpi->sf.lpf_pick);
+ if (cm->rst_info[0].frame_restoration_type != RESTORE_NONE ||
+ cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
+ cm->rst_info[2].frame_restoration_type != RESTORE_NONE) {
+ av1_loop_restoration_frame(cm->frame_to_show, cm, cm->rst_info, 7, 0, NULL);
+ }
+#endif // CONFIG_LOOP_RESTORATION
+ // TODO(debargha): Fix mv search range on encoder side
+ // aom_extend_frame_inner_borders(cm->frame_to_show);
+ aom_extend_frame_borders(cm->frame_to_show);
}
static void reset_use_upsampled_references(AV1_COMP *cpi) {
@@ -3950,30 +3965,24 @@
aom_clear_system_state();
-#if CONFIG_FRAME_SUPERRES
- // TODO(afergs): Figure out when is actually a good time to do superres
- cm->superres_scale_numerator = SUPERRES_SCALE_DENOMINATOR;
- // (uint8_t)(rand() % 9 + SUPERRES_SCALE_NUMERATOR_MIN);
- cpi->superres_pending = cpi->oxcf.superres_enabled && 0;
-#endif // CONFIG_FRAME_SUPERRES
-
setup_frame_size(cpi);
- av1_resize_step(cpi);
+ assert(cm->width == cpi->scaled_source.y_crop_width);
+ assert(cm->height == cpi->scaled_source.y_crop_height);
// For 1 pass CBR under dynamic resize mode: use faster scaling for source.
// Only for 2x2 scaling for now.
if (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == AOM_CBR &&
cpi->oxcf.resize_mode == RESIZE_DYNAMIC &&
- cpi->un_scaled_source->y_width == (cm->width << 1) &&
- cpi->un_scaled_source->y_height == (cm->height << 1)) {
- cpi->source = av1_scale_if_required_fast(cm, cpi->un_scaled_source,
+ cpi->unscaled_source->y_width == (cm->width << 1) &&
+ cpi->unscaled_source->y_height == (cm->height << 1)) {
+ cpi->source = av1_scale_if_required_fast(cm, cpi->unscaled_source,
&cpi->scaled_source);
if (cpi->unscaled_last_source != NULL)
cpi->last_source = av1_scale_if_required_fast(
cm, cpi->unscaled_last_source, &cpi->scaled_last_source);
} else {
cpi->source =
- av1_scale_if_required(cm, cpi->un_scaled_source, &cpi->scaled_source);
+ av1_scale_if_required(cm, cpi->unscaled_source, &cpi->scaled_source);
if (cpi->unscaled_last_source != NULL)
cpi->last_source = av1_scale_if_required(cm, cpi->unscaled_last_source,
&cpi->scaled_last_source);
@@ -4011,11 +4020,6 @@
// transform / motion compensation build reconstruction frame
av1_encode_frame(cpi);
-#if CONFIG_FRAME_SUPERRES
- // TODO(afergs): Upscale the frame to show
- cpi->superres_pending = 0;
-#endif // CONFIG_FRAME_SUPERRES
-
// Update some stats from cyclic refresh, and check if we should not update
// golden reference, for 1 pass CBR.
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cm->frame_type != KEY_FRAME &&
@@ -4052,11 +4056,7 @@
setup_frame_size(cpi);
-#if CONFIG_FRAME_SUPERRES
- if (loop_count == 0 || av1_resize_pending(cpi) || cpi->superres_pending) {
-#else
- if (loop_count == 0 || av1_resize_pending(cpi)) {
-#endif // CONFIG_FRAME_SUPERRES
+ if (loop_count == 0) {
set_size_dependent_vars(cpi, &q, &bottom_index, &top_index);
// cpi->sf.use_upsampled_references can be different from frame to frame.
@@ -4077,9 +4077,6 @@
undershoot_seen = 0;
#endif
- // Advance resize to next state now that updates are done
- av1_resize_step(cpi);
-
q_low = bottom_index;
q_high = top_index;
@@ -4094,8 +4091,7 @@
}
cpi->source =
- av1_scale_if_required(cm, cpi->un_scaled_source, &cpi->scaled_source);
-
+ av1_scale_if_required(cm, cpi->unscaled_source, &cpi->scaled_source);
if (cpi->unscaled_last_source != NULL)
cpi->last_source = av1_scale_if_required(cm, cpi->unscaled_last_source,
&cpi->scaled_last_source);
@@ -4217,8 +4213,6 @@
#if !CONFIG_XIPHRC
int retries = 0;
- // TODO(afergs): Replace removed recode when av1_resize_pending is true
-
// Frame size out of permitted range:
// Update correction factor & compute new Q to try...
// Frame is too large
@@ -5532,7 +5526,7 @@
if ((last_source = av1_lookahead_peek(cpi->lookahead, -1)) == NULL)
return -1;
}
-
+ if (cm->current_video_frame > 0) assert(last_source != NULL);
// Read in the source frame.
source = av1_lookahead_pop(cpi->lookahead, flush);
@@ -5544,11 +5538,9 @@
check_src_altref(cpi, source);
}
}
-
if (source) {
- cpi->un_scaled_source = cpi->source =
+ cpi->unscaled_source = cpi->source =
force_src_buffer ? force_src_buffer : &source->img;
-
cpi->unscaled_last_source = last_source != NULL ? &last_source->img : NULL;
*time_stamp = source->ts_start;
@@ -5619,7 +5611,6 @@
av1_rc_get_second_pass_params(cpi);
} else if (oxcf->pass == 1) {
setup_frame_size(cpi);
- av1_resize_step(cpi);
}
#endif
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index ee1257c..70de507 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -21,6 +21,7 @@
#include "av1/common/entropymode.h"
#include "av1/common/thread_common.h"
#include "av1/common/onyxc_int.h"
+#include "av1/common/resize.h"
#include "av1/encoder/aq_cyclicrefresh.h"
#if CONFIG_ANS
#include "aom_dsp/ans.h"
@@ -372,7 +373,7 @@
YV12_BUFFER_CONFIG *source;
YV12_BUFFER_CONFIG *last_source; // NULL for first frame and alt_ref frames
- YV12_BUFFER_CONFIG *un_scaled_source;
+ YV12_BUFFER_CONFIG *unscaled_source;
YV12_BUFFER_CONFIG scaled_source;
YV12_BUFFER_CONFIG *unscaled_last_source;
YV12_BUFFER_CONFIG scaled_last_source;
@@ -601,18 +602,10 @@
TileBufferEnc tile_buffers[MAX_TILE_ROWS][MAX_TILE_COLS];
int resize_state;
- int resize_scale_num;
- int resize_scale_den;
- int resize_next_scale_num;
- int resize_next_scale_den;
int resize_avg_qp;
int resize_buffer_underflow;
int resize_count;
-#if CONFIG_FRAME_SUPERRES
- int superres_pending;
-#endif // CONFIG_FRAME_SUPERRES
-
// VARIANCE_AQ segment map refresh
int vaq_refresh;
@@ -831,23 +824,22 @@
ubufs[new_uidx].ref_count++;
}
-// Returns 1 if a resize is pending and 0 otherwise.
-static INLINE int av1_resize_pending(const struct AV1_COMP *cpi) {
- return cpi->resize_scale_num != cpi->resize_next_scale_num ||
- cpi->resize_scale_den != cpi->resize_next_scale_den;
-}
-
// Returns 1 if a frame is unscaled and 0 otherwise.
-static INLINE int av1_resize_unscaled(const struct AV1_COMP *cpi) {
- return cpi->resize_scale_num == cpi->resize_scale_den;
+static INLINE int av1_resize_unscaled(const AV1_COMMON *cm) {
+#if CONFIG_FRAME_SUPERRES
+ return cm->superres_upscaled_width == cm->render_width &&
+ cm->superres_upscaled_height == cm->render_height;
+#else
+ return cm->width == cm->render_width && cm->height == cm->render_height;
+#endif // CONFIG_FRAME_SUPERRES
}
-// Moves resizing to the next state. This is just setting the numerator and
-// denominator to the next numerator and denominator, causing
-// av1_resize_pending to subsequently return false.
-static INLINE void av1_resize_step(struct AV1_COMP *cpi) {
- cpi->resize_scale_num = cpi->resize_next_scale_num;
- cpi->resize_scale_den = cpi->resize_next_scale_den;
+static INLINE int av1_frame_unscaled(const AV1_COMMON *cm) {
+#if CONFIG_FRAME_SUPERRES
+ return av1_superres_unscaled(cm) && av1_resize_unscaled(cm);
+#else
+ return av1_resize_unscaled(cm);
+#endif // CONFIG_FRAME_SUPERRES
}
#ifdef __cplusplus
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c
index 7a0abba..859c60b 100644
--- a/av1/encoder/firstpass.c
+++ b/av1/encoder/firstpass.c
@@ -1231,27 +1231,6 @@
}
}
-void av1_calculate_next_scaled_size(const AV1_COMP *cpi,
- int *scaled_frame_width,
- int *scaled_frame_height) {
- *scaled_frame_width =
- cpi->oxcf.width * cpi->resize_next_scale_num / cpi->resize_next_scale_den;
- *scaled_frame_height = cpi->oxcf.height * cpi->resize_next_scale_num /
- cpi->resize_next_scale_den;
-}
-
-#if CONFIG_FRAME_SUPERRES
-void av1_calculate_superres_size(const AV1_COMP *cpi, int *encoded_width,
- int *encoded_height) {
- *encoded_width = cpi->oxcf.scaled_frame_width *
- cpi->common.superres_scale_numerator /
- SUPERRES_SCALE_DENOMINATOR;
- *encoded_height = cpi->oxcf.scaled_frame_height *
- cpi->common.superres_scale_numerator /
- SUPERRES_SCALE_DENOMINATOR;
-}
-#endif // CONFIG_FRAME_SUPERRES
-
void av1_init_second_pass(AV1_COMP *cpi) {
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
TWO_PASS *const twopass = &cpi->twopass;
@@ -2291,12 +2270,6 @@
twopass->section_intra_rating = calculate_section_intra_ratio(
start_pos, twopass->stats_in_end, rc->baseline_gf_interval);
}
-
- if (oxcf->resize_mode == RESIZE_DYNAMIC) {
- // Default to starting GF groups at normal frame size.
- // TODO(afergs): Make a function for this
- cpi->resize_next_scale_num = cpi->resize_next_scale_den;
- }
}
// Threshold for use of the lagging second reference frame. High second ref
@@ -2638,12 +2611,6 @@
// The count of bits left is adjusted elsewhere based on real coded frame
// sizes.
twopass->modified_error_left -= kf_group_err;
-
- if (oxcf->resize_mode == RESIZE_DYNAMIC) {
- // Default to normal-sized frame on keyframes.
- // TODO(afergs): Make a function for this
- cpi->resize_next_scale_num = cpi->resize_next_scale_den;
- }
}
// Define the reference buffers that will be updated post encode.
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h
index 4310445..983b3b5 100644
--- a/av1/encoder/firstpass.h
+++ b/av1/encoder/firstpass.h
@@ -177,18 +177,6 @@
// Post encode update of the rate control parameters for 2-pass
void av1_twopass_postencode_update(struct AV1_COMP *cpi);
-void av1_calculate_next_scaled_size(const struct AV1_COMP *cpi,
- int *scaled_frame_width,
- int *scaled_frame_height);
-
-#if CONFIG_FRAME_SUPERRES
-// This is the size after superress scaling, which could be 1:1.
-// Superres scaling happens after regular downscaling.
-// TODO(afergs): Limit overall reduction to 1/2 of the original size
-void av1_calculate_superres_size(const struct AV1_COMP *cpi, int *encoded_width,
- int *encoded_height);
-#endif // CONFIG_FRAME_SUPERRES
-
#if CONFIG_EXT_REFS
static INLINE int get_number_of_extra_arfs(int interval, int arf_pending) {
if (arf_pending && MAX_EXT_ARFS > 0)
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 4552c67..ed6e9e6 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -94,8 +94,8 @@
static int kf_low = 400;
double av1_resize_rate_factor(const AV1_COMP *cpi) {
- return (double)(cpi->resize_scale_den * cpi->resize_scale_den) /
- (cpi->resize_scale_num * cpi->resize_scale_num);
+ return (double)(cpi->oxcf.width * cpi->oxcf.height) /
+ (cpi->common.width * cpi->common.height);
}
// Functions to compute the active minq lookup table entries based on a
@@ -1081,7 +1081,7 @@
}
// Modify active_best_quality for downscaled normal frames.
- if (!av1_resize_unscaled(cpi) && !frame_is_kf_gf_arf(cpi)) {
+ if (!av1_frame_unscaled(cm) && !frame_is_kf_gf_arf(cpi)) {
int qdelta = av1_compute_qdelta_by_rate(
rc, cm->frame_type, active_best_quality, 2.0, cm->bit_depth);
active_best_quality =
@@ -1164,7 +1164,7 @@
rc->this_frame_target = target;
// Modify frame size target when down-scaled.
- if (cpi->oxcf.resize_mode == RESIZE_DYNAMIC && !av1_resize_unscaled(cpi))
+ if (!av1_frame_unscaled(cm))
rc->this_frame_target =
(int)(rc->this_frame_target * av1_resize_rate_factor(cpi));
@@ -1663,3 +1663,59 @@
vbr_rate_correction(cpi, &target_rate);
av1_rc_set_frame_target(cpi, target_rate);
}
+
+static unsigned int lcg_rand16(unsigned int *state) {
+ *state = (unsigned int)(*state * 1103515245ULL + 12345);
+ return *state / 65536 % 32768;
+}
+
+void av1_calculate_next_scaled_size(AV1_COMP *cpi, int *width, int *height) {
+ AV1EncoderConfig *oxcf = &cpi->oxcf;
+
+ // TODO(afergs): Get width from frame instead?
+ *width = oxcf->width;
+ *height = oxcf->height;
+
+ if (oxcf->resize_mode == RESIZE_FIXED) {
+ *width = oxcf->scaled_frame_width;
+ *height = oxcf->scaled_frame_height;
+ return;
+ }
+ if (oxcf->resize_mode == RESIZE_DYNAMIC) {
+ // NOTE: RESIZE_DYNAMIC defaults to random now.
+ static unsigned int seed = 56789;
+ if (oxcf->pass == 2 || oxcf->pass == 0) {
+ int scale_num = lcg_rand16(&seed) % 4 + 13;
+ int scale_den = 16;
+ if (!(cpi->oxcf.width * scale_num / scale_den * 2 < oxcf->width ||
+ cpi->oxcf.height * scale_num / scale_den * 2 < oxcf->height)) {
+ *width = cpi->oxcf.width * scale_num / scale_den;
+ *height = cpi->oxcf.height * scale_num / scale_den;
+ }
+ }
+ }
+}
+
+#if CONFIG_FRAME_SUPERRES
+#define RANDOM_SUPERRES 1
+int av1_calculate_next_superres_scale(AV1_COMP *cpi, int width, int height) {
+ const AV1EncoderConfig *oxcf = &cpi->oxcf;
+ (void)width;
+ (void)height;
+ (void)oxcf;
+#if RANDOM_SUPERRES
+ if (cpi->common.frame_type != KEY_FRAME) {
+ if (oxcf->pass == 2 || oxcf->pass == 0) {
+ static unsigned int seed = 34567;
+ int new_num = lcg_rand16(&seed) % 9 + 8;
+ if (new_num * width / SUPERRES_SCALE_DENOMINATOR * 2 < oxcf->width ||
+ new_num * height / SUPERRES_SCALE_DENOMINATOR * 2 < oxcf->height)
+ new_num = SUPERRES_SCALE_DENOMINATOR;
+ cpi->common.superres_scale_numerator = new_num;
+ return new_num;
+ }
+ }
+#endif // RANDOM_SUPERRES
+ return 16;
+}
+#endif // CONFIG_FRAME_SUPERRES
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 61bb0c2..13b1555 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -256,6 +256,12 @@
int av1_resize_one_pass_cbr(struct AV1_COMP *cpi);
+void av1_calculate_next_scaled_size(struct AV1_COMP *cpi, int *width,
+ int *height);
+#if CONFIG_FRAME_SUPERRES
+int av1_calculate_next_superres_scale(struct AV1_COMP *cpi, int width,
+ int height);
+#endif // CONFIG_FRAME_SUPERRES
#ifdef __cplusplus
} // extern "C"
#endif