Add new experiment: frame_context_signaling. This stores frame contexts alongside a reference frame, and always uses the frame in reference slot 0 (LAST_FRAME) as the source of the frame context. The encoder could then reorder reference frames as to control which frame context is used, however currently it does not. Low Latency AWCY result: PSNR | PSNR Cb | PSNR Cr | PSNR HVS | SSIM | MS SSIM | CIEDE 2000 -0.1438 | 0.4161 | N/A | 0.0386 | -0.0281 | 0.0453 | 0.2514 https://arewecompressedyet.com/?job=before-frame-context-signaling%402017-06-07T23%3A20%3A49.473Z&job=after-frame-context-signaling%402017-06-07T23%3A21%3A36.117Z Change-Id: I4f6f9b12cb403573efbf9e5c3077d62f5dedc467
diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c index 94b7f74..cb56c34 100644 --- a/av1/common/entropymode.c +++ b/av1/common/entropymode.c
@@ -5527,14 +5527,22 @@ // Reset all frame contexts. for (i = 0; i < FRAME_CONTEXTS; ++i) cm->frame_contexts[i] = *cm->fc; } else if (cm->reset_frame_context == RESET_FRAME_CONTEXT_CURRENT) { +#if CONFIG_NO_FRAME_CONTEXT_SIGNALING + // Reset the frame context of the first specified ref frame. + if (cm->frame_refs[0].idx >= 0) { + cm->frame_contexts[cm->frame_refs[0].idx] = *cm->fc; + } +#else // Reset only the frame context specified in the frame header. cm->frame_contexts[cm->frame_context_idx] = *cm->fc; +#endif // CONFIG_NO_FRAME_CONTEXT_SIGNALING } // prev_mip will only be allocated in encoder. if (frame_is_intra_only(cm) && cm->prev_mip && !cm->frame_parallel_decode) memset(cm->prev_mip, 0, cm->mi_stride * (cm->mi_rows + 1) * sizeof(*cm->prev_mip)); - +#if !CONFIG_NO_FRAME_CONTEXT_SIGNALING cm->frame_context_idx = 0; +#endif // !CONFIG_NO_FRAME_CONTEXT_SIGNALING }
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h index 48b1641..adef5a9 100644 --- a/av1/common/onyxc_int.h +++ b/av1/common/onyxc_int.h
@@ -62,6 +62,12 @@ #define DELTA_FRAME_ID_LENGTH_MINUS2 12 // Allows frame id deltas up to 2^14-1 #endif +#if CONFIG_NO_FRAME_CONTEXT_SIGNALING +#define FRAME_CONTEXTS (FRAME_BUFFERS + 1) +// Extra frame context which is always kept at default values +#define FRAME_CONTEXT_DEFAULTS (FRAME_CONTEXTS - 1) +#else + #if CONFIG_EXT_REFS #define FRAME_CONTEXTS_LOG2 3 #else @@ -69,6 +75,7 @@ #endif #define FRAME_CONTEXTS (1 << FRAME_CONTEXTS_LOG2) +#endif // CONFIG_NO_FRAME_CONTEXT_SIGNALING #define NUM_PING_PONG_BUFFERS 2 @@ -347,7 +354,9 @@ FRAME_CONTEXT *fc; /* this frame entropy */ FRAME_CONTEXT *frame_contexts; // FRAME_CONTEXTS FRAME_CONTEXT *pre_fc; // Context referenced in this frame +#if !CONFIG_NO_FRAME_CONTEXT_SIGNALING unsigned int frame_context_idx; /* Context to use/update */ +#endif FRAME_COUNTS counts; unsigned int current_video_frame;
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c index 4bd7558..91423a1 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c
@@ -4713,10 +4713,11 @@ } else { cm->refresh_frame_context = REFRESH_FRAME_CONTEXT_FORWARD; } - +#if !CONFIG_NO_FRAME_CONTEXT_SIGNALING // This flag will be overridden by the call to av1_setup_past_independence // below, forcing the use of context 0 for those frame types. cm->frame_context_idx = aom_rb_read_literal(rb, FRAME_CONTEXTS_LOG2); +#endif // Generate next_ref_frame_map. lock_buffer_pool(pool); @@ -4762,7 +4763,13 @@ cm->reset_frame_context == RESET_FRAME_CONTEXT_ALL) { for (i = 0; i < FRAME_CONTEXTS; ++i) cm->frame_contexts[i] = *cm->fc; } else if (cm->reset_frame_context == RESET_FRAME_CONTEXT_CURRENT) { +#if CONFIG_NO_FRAME_CONTEXT_SIGNALING + if (cm->frame_refs[0].idx <= 0) { + cm->frame_contexts[cm->frame_refs[0].idx] = *cm->fc; + } +#else cm->frame_contexts[cm->frame_context_idx] = *cm->fc; +#endif // CONFIG_NO_FRAME_CONTEXT_SIGNALING } #endif // CONFIG_Q_ADAPT_PROBS @@ -5337,9 +5344,19 @@ #endif // CONFIG_TEMPMV_SIGNALING av1_setup_block_planes(xd, cm->subsampling_x, cm->subsampling_y); - +#if CONFIG_NO_FRAME_CONTEXT_SIGNALING + if (cm->error_resilient_mode || frame_is_intra_only(cm)) { + // use the default frame context values + *cm->fc = cm->frame_contexts[FRAME_CONTEXT_DEFAULTS]; + cm->pre_fc = &cm->frame_contexts[FRAME_CONTEXT_DEFAULTS]; + } else { + *cm->fc = cm->frame_contexts[cm->frame_refs[0].idx]; + cm->pre_fc = &cm->frame_contexts[cm->frame_refs[0].idx]; + } +#else *cm->fc = cm->frame_contexts[cm->frame_context_idx]; cm->pre_fc = &cm->frame_contexts[cm->frame_context_idx]; +#endif // CONFIG_NO_FRAME_CONTEXT_SIGNALING if (!cm->fc->initialized) aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, "Uninitialized entropy context."); @@ -5364,7 +5381,11 @@ FrameWorkerData *const frame_worker_data = worker->data1; if (cm->refresh_frame_context == REFRESH_FRAME_CONTEXT_FORWARD) { context_updated = 1; +#if CONFIG_NO_FRAME_CONTEXT_SIGNALING + cm->frame_contexts[cm->new_fb_idx] = *cm->fc; +#else cm->frame_contexts[cm->frame_context_idx] = *cm->fc; +#endif // CONFIG_NO_FRAME_CONTEXT_SIGNALING } av1_frameworker_lock_stats(worker); pbi->cur_buf->row = -1; @@ -5464,7 +5485,13 @@ } #endif - // Non frame parallel update frame context here. +// Non frame parallel update frame context here. +#if CONFIG_NO_FRAME_CONTEXT_SIGNALING + // TODO(tdaede): Figure out of this condition is required. + if (!cm->error_resilient_mode && !context_updated) + cm->frame_contexts[cm->new_fb_idx] = *cm->fc; +#else if (!cm->error_resilient_mode && !context_updated) cm->frame_contexts[cm->frame_context_idx] = *cm->fc; +#endif }
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c index 70316be..9d76628 100644 --- a/av1/encoder/bitstream.c +++ b/av1/encoder/bitstream.c
@@ -4399,9 +4399,9 @@ aom_wb_write_bit( wb, cm->refresh_frame_context == REFRESH_FRAME_CONTEXT_FORWARD); } - +#if !CONFIG_NO_FRAME_CONTEXT_SIGNALING aom_wb_write_literal(wb, cm->frame_context_idx, FRAME_CONTEXTS_LOG2); - +#endif assert(cm->mib_size == mi_size_wide[cm->sb_size]); assert(cm->mib_size == 1 << cm->mib_size_log2); #if CONFIG_EXT_PARTITION
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index a4a060b..e07e006 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -296,6 +296,10 @@ if (frame_is_intra_only(cm) || cm->error_resilient_mode) { av1_setup_past_independence(cm); } else { +#if CONFIG_NO_FRAME_CONTEXT_SIGNALING +// Just use frame context from first signaled reference frame. +// This will always be LAST_FRAME for now. +#else #if CONFIG_EXT_REFS const GF_GROUP *gf_group = &cpi->twopass.gf_group; if (gf_group->rf_level[gf_group->index] == GF_ARF_LOW) @@ -315,6 +319,7 @@ #endif // CONFIG_EXT_REFS else cm->frame_context_idx = REGULAR_FRAME; +#endif // CONFIG_NO_FRAME_CONTEXT_SIGNALING } if (cm->frame_type == KEY_FRAME) { @@ -322,7 +327,16 @@ cpi->refresh_alt_ref_frame = 1; av1_zero(cpi->interp_filter_selected); } else { +#if CONFIG_NO_FRAME_CONTEXT_SIGNALING + if (frame_is_intra_only(cm) || cm->error_resilient_mode || + cm->frame_refs[0].idx < 0) { + *cm->fc = cm->frame_contexts[FRAME_CONTEXT_DEFAULTS]; + } else { + *cm->fc = cm->frame_contexts[cm->frame_refs[0].idx]; + } +#else *cm->fc = cm->frame_contexts[cm->frame_context_idx]; +#endif // CONFIG_NO_FRAME_CONTEXT_SIGNALING av1_zero(cpi->interp_filter_selected[0]); } #if CONFIG_EXT_REFS @@ -333,7 +347,16 @@ } #endif #endif +#if CONFIG_NO_FRAME_CONTEXT_SIGNALING + if (frame_is_intra_only(cm) || cm->error_resilient_mode) { + // use default frame context values + cm->pre_fc = &cm->frame_contexts[FRAME_CONTEXT_DEFAULTS]; + } else { + cm->pre_fc = &cm->frame_contexts[cm->frame_refs[0].idx]; + } +#else cm->pre_fc = &cm->frame_contexts[cm->frame_context_idx]; +#endif // CONFIG_NO_FRAME_CONTEXT_SIGNALING cpi->vaq_refresh = 0; @@ -350,7 +373,6 @@ // Clear left border column for (i = 1; i < cm->mi_rows + 1; ++i) memset(&cm->prev_mip[i * cm->mi_stride], 0, sizeof(*cm->prev_mip)); - cm->mi_grid_visible = cm->mi_grid_base + cm->mi_stride + 1; cm->prev_mi_grid_visible = cm->prev_mi_grid_base + cm->mi_stride + 1; @@ -4164,7 +4186,13 @@ cm->reset_frame_context == RESET_FRAME_CONTEXT_ALL) { for (i = 0; i < FRAME_CONTEXTS; ++i) cm->frame_contexts[i] = *cm->fc; } else if (cm->reset_frame_context == RESET_FRAME_CONTEXT_CURRENT) { +#if CONFIG_NO_FRAME_CONTEXT_SIGNALING + if (cm->frame_refs[0].idx >= 0) { + cm->frame_contexts[cm->frame_refs[0].idx] = *cm->fc; + } +#else cm->frame_contexts[cm->frame_context_idx] = *cm->fc; +#endif } } #endif // CONFIG_Q_ADAPT_PROBS @@ -5705,9 +5733,13 @@ Pass0Encode(cpi, size, dest, 0, frame_flags); } #endif - +#if CONFIG_NO_FRAME_CONTEXT_SIGNALING + // TODO(tdaede): Check if this condition is really needed. + if (!cm->error_resilient_mode) cm->frame_contexts[cm->new_fb_idx] = *cm->fc; +#else if (!cm->error_resilient_mode) cm->frame_contexts[cm->frame_context_idx] = *cm->fc; +#endif // CONFIG_NO_FRAME_CONTEXT_SIGNALING // No frame encoded, or frame was dropped, release scaled references. if ((*size == 0) && (frame_is_intra_only(cm) == 0)) {
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h index c3730f3..8ed8e0a 100644 --- a/av1/encoder/encoder.h +++ b/av1/encoder/encoder.h
@@ -70,6 +70,7 @@ FRAME_CONTEXT fc; } CODING_CONTEXT; +#if !CONFIG_NO_FRAME_CONTEXT_SIGNALING typedef enum { // regular inter frame REGULAR_FRAME = 0, @@ -86,6 +87,7 @@ EXT_ARF_FRAME = 5 #endif } FRAME_CONTEXT_INDEX; +#endif typedef enum { NORMAL = 0,
diff --git a/build/cmake/aom_config_defaults.cmake b/build/cmake/aom_config_defaults.cmake index b957270..482d679 100644 --- a/build/cmake/aom_config_defaults.cmake +++ b/build/cmake/aom_config_defaults.cmake
@@ -180,3 +180,4 @@ set(CONFIG_ALTREF2 0 CACHE NUMBER "Internal flag.") set(CONFIG_FLEX_REFS 0 CACHE NUMBER "Internal flag.") set(CONFIG_LPF_DIRECT 0 CACHE NUMBER "Internal flag.") +set(CONFIG_NO_FRAME_CONTEXT_SIGNALING 0 CACHE NUMBER "Internal flag.")
diff --git a/configure b/configure index bf796fb..157168f 100755 --- a/configure +++ b/configure
@@ -339,6 +339,7 @@ mrc_tx lpf_direct uv_lvl + no_frame_context_signaling " CONFIG_LIST=" dependency_tracking