Commit 1f990a64 authored by Rupert Swarbrick's avatar Rupert Swarbrick

tempv_signaling: Simplify test for whether prev_frame works for mvs

For some background, see this previous change in Gerrit[0]. What's
going on here is that we only want to use a previous frame for motion
vector prediction if the encoded sizes match. When scaling with
superres, this means the size before upscaling.

To check this correctly, we need to check prev_frame's width/height
and compare it with the current frame. Without superres, prev_frame's
width/height is stored in y_crop_width/y_crop_height so we can check
that way. With superres, those numbers are after the scaling, so can't
be compared with cm->width and cm->height.

The previous code worked around this by comparing with cm->last_width
and cm->last_height. That works because these are the width/height for
the last encoded and shown frame and that frame *is* prev_frame if
last_show_frame is true. Since this is the only case when we want to
use prev_frame, they are the numbers we need.

This patch simplifies the logic by storing the width/height in
RefCntBuffer before any scaling and then checking that they match.

The check for whether we can use motion vectors from a previous frame
is factored out into a pair of inline functions in the
header. frame_might_use_prev_frame_mvs() is true if it's possible that
this frame could use motion vectors from a previous frame. This
doesn't use knowledge of what prev_frame is: it just checks we're not
in error resilient mode and aren't a keyframe. When this is true, a
flag is signaled in the bitstream to say whether we actually want to
use motion vectors from the previous frame.

The second function, frame_can_use_prev_frame_mvs, is true if the
current frame / previous frame pair is suitable for sharing motion
vectors. This is a stricter test: the previous frame needs to be
have been shown and not to have been intra_only, and it needs to have
the same width/height as the current frame.

If the re-assignment of prev_frame (just before the calls to
frame_can_use_prev_frame_mvs()) were removed in some way, we could
probably combine the two functions and often save a bit per frame
header.

The other slight tidy-up in the patch is to move re-allocation of the
mvs buffer into onyxc_int.h: the code that did the allocation was
duplicated between the encoder and decoder.

[0] https://aomedia-review.googlesource.com/c/13806

BUG=aomedia:78

Change-Id: If25227fa24222fc05c56529c2ac9ddf1e1c36a84
parent 2a52f291
...@@ -109,6 +109,10 @@ typedef struct { ...@@ -109,6 +109,10 @@ typedef struct {
MV_REF *mvs; MV_REF *mvs;
int mi_rows; int mi_rows;
int mi_cols; int mi_cols;
// Width and height give the size of the buffer (before any upscaling, unlike
// the sizes that can be derived from the buf structure)
int width;
int height;
#if CONFIG_GLOBAL_MOTION #if CONFIG_GLOBAL_MOTION
WarpedMotionParams global_motion[TOTAL_REFS_PER_FRAME]; WarpedMotionParams global_motion[TOTAL_REFS_PER_FRAME];
#endif // CONFIG_GLOBAL_MOTION #endif // CONFIG_GLOBAL_MOTION
...@@ -507,6 +511,35 @@ static INLINE void ref_cnt_fb(RefCntBuffer *bufs, int *idx, int new_idx) { ...@@ -507,6 +511,35 @@ static INLINE void ref_cnt_fb(RefCntBuffer *bufs, int *idx, int new_idx) {
bufs[new_idx].ref_count++; bufs[new_idx].ref_count++;
} }
#if CONFIG_TEMPMV_SIGNALING
// Returns 1 if this frame might use mvs from some previous frame. This
// function doesn't consider whether prev_frame is actually suitable (see
// frame_can_use_prev_frame_mvs for that)
static INLINE int frame_might_use_prev_frame_mvs(const AV1_COMMON *cm) {
return !cm->error_resilient_mode && !cm->intra_only;
}
// Returns 1 if this frame really can use MVs from some previous frame.
static INLINE int frame_can_use_prev_frame_mvs(const AV1_COMMON *cm) {
return (frame_might_use_prev_frame_mvs(cm) && cm->last_show_frame &&
cm->prev_frame && !cm->prev_frame->intra_only &&
cm->width == cm->prev_frame->width &&
cm->height == cm->prev_frame->height);
}
#endif
static INLINE void ensure_mv_buffer(RefCntBuffer *buf, AV1_COMMON *cm) {
if (buf->mvs == NULL || buf->mi_rows < cm->mi_rows ||
buf->mi_cols < cm->mi_cols) {
aom_free(buf->mvs);
buf->mi_rows = cm->mi_rows;
buf->mi_cols = cm->mi_cols;
CHECK_MEM_ERROR(
cm, buf->mvs,
(MV_REF *)aom_calloc(cm->mi_rows * cm->mi_cols, sizeof(*buf->mvs)));
}
}
#if CONFIG_VAR_REFS #if CONFIG_VAR_REFS
#define LAST_IS_VALID(cm) ((cm)->frame_refs[LAST_FRAME - 1].is_valid) #define LAST_IS_VALID(cm) ((cm)->frame_refs[LAST_FRAME - 1].is_valid)
#define LAST2_IS_VALID(cm) ((cm)->frame_refs[LAST2_FRAME - 1].is_valid) #define LAST2_IS_VALID(cm) ((cm)->frame_refs[LAST2_FRAME - 1].is_valid)
......
...@@ -3132,15 +3132,6 @@ static void setup_superres(AV1_COMMON *const cm, struct aom_read_bit_buffer *rb, ...@@ -3132,15 +3132,6 @@ static void setup_superres(AV1_COMMON *const cm, struct aom_read_bit_buffer *rb,
} }
#endif // CONFIG_FRAME_SUPERRES #endif // 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;
cm->cur_frame->mi_cols = cm->mi_cols;
CHECK_MEM_ERROR(cm, cm->cur_frame->mvs,
(MV_REF *)aom_calloc(cm->mi_rows * cm->mi_cols,
sizeof(*cm->cur_frame->mvs)));
}
static void resize_context_buffers(AV1_COMMON *cm, int width, int height) { static void resize_context_buffers(AV1_COMMON *cm, int width, int height) {
#if CONFIG_SIZE_LIMIT #if CONFIG_SIZE_LIMIT
if (width > DECODE_WIDTH_LIMIT || height > DECODE_HEIGHT_LIMIT) if (width > DECODE_WIDTH_LIMIT || height > DECODE_HEIGHT_LIMIT)
...@@ -3167,10 +3158,10 @@ static void resize_context_buffers(AV1_COMMON *cm, int width, int height) { ...@@ -3167,10 +3158,10 @@ static void resize_context_buffers(AV1_COMMON *cm, int width, int height) {
cm->width = width; cm->width = width;
cm->height = height; cm->height = height;
} }
if (cm->cur_frame->mvs == NULL || cm->mi_rows > cm->cur_frame->mi_rows ||
cm->mi_cols > cm->cur_frame->mi_cols) { ensure_mv_buffer(cm->cur_frame, cm);
resize_mv_buffer(cm); cm->cur_frame->width = cm->width;
} cm->cur_frame->height = cm->height;
} }
static void setup_frame_size(AV1_COMMON *cm, struct aom_read_bit_buffer *rb) { static void setup_frame_size(AV1_COMMON *cm, struct aom_read_bit_buffer *rb) {
...@@ -4572,9 +4563,6 @@ static size_t read_uncompressed_header(AV1Decoder *pbi, ...@@ -4572,9 +4563,6 @@ static size_t read_uncompressed_header(AV1Decoder *pbi,
#if CONFIG_PALETTE || CONFIG_INTRABC #if CONFIG_PALETTE || CONFIG_INTRABC
if (cm->intra_only) cm->allow_screen_content_tools = aom_rb_read_bit(rb); if (cm->intra_only) cm->allow_screen_content_tools = aom_rb_read_bit(rb);
#endif // CONFIG_PALETTE || CONFIG_INTRABC #endif // CONFIG_PALETTE || CONFIG_INTRABC
#if CONFIG_TEMPMV_SIGNALING
if (cm->intra_only || cm->error_resilient_mode) cm->use_prev_frame_mvs = 0;
#endif
if (cm->error_resilient_mode) { if (cm->error_resilient_mode) {
cm->reset_frame_context = RESET_FRAME_CONTEXT_ALL; cm->reset_frame_context = RESET_FRAME_CONTEXT_ALL;
} else { } else {
...@@ -4663,9 +4651,10 @@ static size_t read_uncompressed_header(AV1Decoder *pbi, ...@@ -4663,9 +4651,10 @@ static size_t read_uncompressed_header(AV1Decoder *pbi,
cm->allow_high_precision_mv = aom_rb_read_bit(rb); cm->allow_high_precision_mv = aom_rb_read_bit(rb);
cm->interp_filter = read_frame_interp_filter(rb); cm->interp_filter = read_frame_interp_filter(rb);
#if CONFIG_TEMPMV_SIGNALING #if CONFIG_TEMPMV_SIGNALING
if (!cm->error_resilient_mode) { if (frame_might_use_prev_frame_mvs(cm))
cm->use_prev_frame_mvs = aom_rb_read_bit(rb); cm->use_prev_frame_mvs = aom_rb_read_bit(rb);
} else
cm->use_prev_frame_mvs = 0;
#endif #endif
for (i = 0; i < INTER_REFS_PER_FRAME; ++i) { for (i = 0; i < INTER_REFS_PER_FRAME; ++i) {
RefBuffer *const ref_buf = &cm->frame_refs[i]; RefBuffer *const ref_buf = &cm->frame_refs[i];
...@@ -5333,16 +5322,7 @@ void av1_decode_frame(AV1Decoder *pbi, const uint8_t *data, ...@@ -5333,16 +5322,7 @@ void av1_decode_frame(AV1Decoder *pbi, const uint8_t *data,
#endif // CONFIG_EXT_REFS || CONFIG_TEMPMV_SIGNALING #endif // CONFIG_EXT_REFS || CONFIG_TEMPMV_SIGNALING
#if CONFIG_TEMPMV_SIGNALING #if CONFIG_TEMPMV_SIGNALING
if (cm->use_prev_frame_mvs) { if (cm->use_prev_frame_mvs) assert(frame_can_use_prev_frame_mvs(cm));
assert(!cm->error_resilient_mode && cm->prev_frame);
#if CONFIG_FRAME_SUPERRES
assert(cm->width == cm->last_width && cm->height == cm->last_height);
#else
assert(cm->width == last_fb_ref_buf->buf->y_crop_width &&
cm->height == last_fb_ref_buf->buf->y_crop_height);
#endif // CONFIG_FRAME_SUPERRES
assert(!cm->prev_frame->intra_only);
}
#else #else
cm->use_prev_frame_mvs = !cm->error_resilient_mode && cm->prev_frame && cm->use_prev_frame_mvs = !cm->error_resilient_mode && cm->prev_frame &&
#if CONFIG_FRAME_SUPERRES #if CONFIG_FRAME_SUPERRES
......
...@@ -4384,7 +4384,7 @@ static void write_uncompressed_header(AV1_COMP *cpi, ...@@ -4384,7 +4384,7 @@ static void write_uncompressed_header(AV1_COMP *cpi,
fix_interp_filter(cm, cpi->td.counts); fix_interp_filter(cm, cpi->td.counts);
write_frame_interp_filter(cm->interp_filter, wb); write_frame_interp_filter(cm->interp_filter, wb);
#if CONFIG_TEMPMV_SIGNALING #if CONFIG_TEMPMV_SIGNALING
if (!cm->error_resilient_mode) { if (frame_might_use_prev_frame_mvs(cm)) {
aom_wb_write_bit(wb, cm->use_prev_frame_mvs); aom_wb_write_bit(wb, cm->use_prev_frame_mvs);
} }
#endif #endif
......
...@@ -5282,19 +5282,7 @@ static void encode_frame_internal(AV1_COMP *cpi) { ...@@ -5282,19 +5282,7 @@ static void encode_frame_internal(AV1_COMP *cpi) {
#endif // CONFIG_EXT_REFS || CONFIG_TEMPMV_SIGNALING #endif // CONFIG_EXT_REFS || CONFIG_TEMPMV_SIGNALING
#if CONFIG_TEMPMV_SIGNALING #if CONFIG_TEMPMV_SIGNALING
if (cm->prev_frame) { cm->use_prev_frame_mvs &= frame_can_use_prev_frame_mvs(cm);
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->prev_frame->intra_only && cm->last_show_frame;
} else {
cm->use_prev_frame_mvs = 0;
}
#else #else
if (cm->prev_frame) { if (cm->prev_frame) {
cm->use_prev_frame_mvs = !cm->error_resilient_mode && cm->use_prev_frame_mvs = !cm->error_resilient_mode &&
......
...@@ -3468,15 +3468,9 @@ void av1_update_reference_frames(AV1_COMP *cpi) { ...@@ -3468,15 +3468,9 @@ void av1_update_reference_frames(AV1_COMP *cpi) {
static INLINE void alloc_frame_mvs(AV1_COMMON *const cm, int buffer_idx) { static INLINE void alloc_frame_mvs(AV1_COMMON *const cm, int buffer_idx) {
assert(buffer_idx != INVALID_IDX); assert(buffer_idx != INVALID_IDX);
RefCntBuffer *const new_fb_ptr = &cm->buffer_pool->frame_bufs[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 || ensure_mv_buffer(new_fb_ptr, cm);
new_fb_ptr->mi_cols < cm->mi_cols) { new_fb_ptr->width = cm->width;
aom_free(new_fb_ptr->mvs); new_fb_ptr->height = cm->height;
CHECK_MEM_ERROR(cm, new_fb_ptr->mvs,
(MV_REF *)aom_calloc(cm->mi_rows * cm->mi_cols,
sizeof(*new_fb_ptr->mvs)));
new_fb_ptr->mi_rows = cm->mi_rows;
new_fb_ptr->mi_cols = cm->mi_cols;
}
} }
void av1_scale_references(AV1_COMP *cpi) { void av1_scale_references(AV1_COMP *cpi) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment