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,