From 57c36e189af3450a27f8146dd256502b6a4d28a0 Mon Sep 17 00:00:00 2001 From: Pavel Frolov Date: Tue, 12 Sep 2017 15:00:40 +0300 Subject: [PATCH] Init cm->prev_frame before decoding gm params This fixes global motion read/write mismatch. Minimal test case would be 3 encoded frames with: 1) frame0: KEY frame 2) frame1: INTER frame with refresh_frame_flags not 0x00 and not 0xFF, say 0x01 (refresh first slot) 3) frame2: INTER frame with all reference indices equal to 3 (i.e. no reference to frame1) When decoding frame2 decoder will use cm->prev_frame=frame1 for gm params decoding, then switch to cm->prev_frame=frame0 for the rest of the frame. This makes frame2 dependent on frame1 which is not used as reference. And also it is different from what encoder does. BUG=aomedia:750 Change-Id: I42ba19c03d909286af12ba3149910693a12249e8 --- av1/decoder/decodeframe.c | 79 +++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c index 0ad255be9..fec406fb3 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c @@ -5076,6 +5076,45 @@ static size_t read_uncompressed_header(AV1Decoder *pbi, cm->reduced_tx_set_used = aom_rb_read_bit(rb); #endif // CONFIG_EXT_TX +#if CONFIG_EXT_REFS || CONFIG_TEMPMV_SIGNALING + // NOTE(zoeliu): As cm->prev_frame can take neither a frame of + // show_exisiting_frame=1, nor can it take a frame not used as + // a reference, it is probable that by the time it is being + // referred to, the frame buffer it originally points to may + // already get expired and have been reassigned to the current + // newly coded frame. Hence, we need to check whether this is + // the case, and if yes, we have 2 choices: + // (1) Simply disable the use of previous frame mvs; or + // (2) Have cm->prev_frame point to one reference frame buffer, + // e.g. LAST_FRAME. + if (!dec_is_ref_frame_buf(pbi, cm->prev_frame)) { + // Reassign the LAST_FRAME buffer to cm->prev_frame. + cm->prev_frame = + cm->frame_refs[LAST_FRAME - LAST_FRAME].idx != INVALID_IDX + ? &cm->buffer_pool + ->frame_bufs[cm->frame_refs[LAST_FRAME - LAST_FRAME].idx] + : NULL; + } +#endif // CONFIG_EXT_REFS || CONFIG_TEMPMV_SIGNALING + +#if CONFIG_TEMPMV_SIGNALING + if (cm->use_prev_frame_mvs && !frame_can_use_prev_frame_mvs(cm)) { + aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, + "Frame wrongly requests previous frame MVs"); + } +#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 + #if CONFIG_GLOBAL_MOTION if (!frame_is_intra_only(cm)) read_global_motion(cm, rb); #endif @@ -5383,9 +5422,6 @@ void av1_decode_frame(AV1Decoder *pbi, const uint8_t *data, uint8_t clear_data[MAX_AV1_HEADER_SIZE]; size_t first_partition_size; YV12_BUFFER_CONFIG *new_fb; -#if CONFIG_EXT_REFS || CONFIG_TEMPMV_SIGNALING - RefBuffer *last_fb_ref_buf = &cm->frame_refs[LAST_FRAME - LAST_FRAME]; -#endif // CONFIG_EXT_REFS || CONFIG_TEMPMV_SIGNALING #if CONFIG_ADAPT_SCAN av1_deliver_eob_threshold(cm, xd); @@ -5447,43 +5483,6 @@ void av1_decode_frame(AV1Decoder *pbi, const uint8_t *data, cm->setup_mi(cm); -#if CONFIG_EXT_REFS || CONFIG_TEMPMV_SIGNALING - // NOTE(zoeliu): As cm->prev_frame can take neither a frame of - // show_exisiting_frame=1, nor can it take a frame not used as - // a reference, it is probable that by the time it is being - // referred to, the frame buffer it originally points to may - // already get expired and have been reassigned to the current - // newly coded frame. Hence, we need to check whether this is - // the case, and if yes, we have 2 choices: - // (1) Simply disable the use of previous frame mvs; or - // (2) Have cm->prev_frame point to one reference frame buffer, - // e.g. LAST_FRAME. - if (!dec_is_ref_frame_buf(pbi, cm->prev_frame)) { - // Reassign the LAST_FRAME buffer to cm->prev_frame. - cm->prev_frame = last_fb_ref_buf->idx != INVALID_IDX - ? &cm->buffer_pool->frame_bufs[last_fb_ref_buf->idx] - : NULL; - } -#endif // CONFIG_EXT_REFS || CONFIG_TEMPMV_SIGNALING - -#if CONFIG_TEMPMV_SIGNALING - if (cm->use_prev_frame_mvs && !frame_can_use_prev_frame_mvs(cm)) { - aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, - "Frame wrongly requests previous frame MVs"); - } -#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 - #if CONFIG_MFMV av1_setup_frame_buf_refs(cm); av1_setup_motion_field(cm); -- GitLab