no-frame-context-signaling + q-adapt-probs: Fix interaction
Slightly change the way we save and reload frame contexts during
frame setup. For "normal" frames everything is the same, but for
error-resilient and/or intra-only frames, we now:
* Reset the frame context using setup_past_independence()
(+ extra code if q-adapt-probs is enabled), as usual
* Store this frame context into a special slot in cm->frame_contexts
* Use that slot to fill in cm->pre_fc
The main difference from before is that (for error-resilient/intra-only
frames which are not key frames) we used to throw away the frame
context after setting it up, and would re-use whatever was set up
at the last keyframe.
This was fine when q_adapt_probs is disabled, but it caused an
inconsistency when combined with q_adapt_probs. See the attached
bug report for more details on that.
BUG=aomedia:1104
Change-Id: I9532b6b0e8ae29efbb4f059a0c67a73d7c7828ce
diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c
index ef5f2d4..0ddf6b6 100644
--- a/av1/common/entropymode.c
+++ b/av1/common/entropymode.c
@@ -3209,6 +3209,10 @@
if (cm->frame_type == KEY_FRAME) {
// Reset all frame contexts, as all reference frames will be lost.
for (i = 0; i < FRAME_CONTEXTS; ++i) cm->frame_contexts[i] = *cm->fc;
+ } else if (frame_is_intra_only(cm) || cm->error_resilient_mode) {
+ // Store the frame context into a special slot (not associated with any
+ // reference buffer), so that we can set up cm->pre_fc correctly later
+ cm->frame_contexts[FRAME_CONTEXT_DEFAULTS] = *cm->fc;
}
#else
if (cm->frame_type == KEY_FRAME || cm->error_resilient_mode ||
@@ -3216,15 +3220,8 @@
// 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
}
#endif // CONFIG_NO_FRAME_CONTEXT_SIGNALING
}
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 70ab2e2..66bce63 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -356,16 +356,24 @@
#if CONFIG_REFERENCE_BUFFER
set_use_reference_buffer(cm, 0);
#endif // CONFIG_REFERENCE_BUFFER
+#if CONFIG_NO_FRAME_CONTEXT_SIGNALING
+ cm->pre_fc = &cm->frame_contexts[FRAME_CONTEXT_DEFAULTS];
+#else
+ cm->pre_fc = &cm->frame_contexts[cm->frame_context_idx];
+#endif // CONFIG_NO_FRAME_CONTEXT_SIGNALING
} else {
#if CONFIG_NO_FRAME_CONTEXT_SIGNALING
- if (frame_is_intra_only(cm) || cm->error_resilient_mode ||
- cm->frame_refs[0].idx < 0) {
+ if (frame_is_intra_only(cm) || cm->error_resilient_mode) {
*cm->fc = cm->frame_contexts[FRAME_CONTEXT_DEFAULTS];
+ cm->pre_fc = &cm->frame_contexts[FRAME_CONTEXT_DEFAULTS];
} else {
+ assert(cm->frame_refs[0].idx >= 0);
*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
av1_zero(cpi->interp_filter_selected[0]);
}
@@ -375,18 +383,6 @@
cpi->rc.is_bipred_frame = 1;
}
#endif // !CONFIG_EXT_COMP_REFS
-#if CONFIG_NO_FRAME_CONTEXT_SIGNALING
- if (frame_is_intra_only(cm) || cm->error_resilient_mode ||
- cm->frame_refs[0].idx < 0) {
- // use default frame context values
- 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->pre_fc = &cm->frame_contexts[cm->frame_context_idx];
-#endif // CONFIG_NO_FRAME_CONTEXT_SIGNALING
cpi->vaq_refresh = 0;
}