Commit da4d8b9c authored by Thomas Daede's avatar Thomas Daede

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
parent 1f990a64
......@@ -5527,14 +5527,22 @@ void av1_setup_past_independence(AV1_COMMON *cm) {
// 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
}
......@@ -62,6 +62,12 @@ extern "C" {
#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 @@ extern "C" {
#endif
#define FRAME_CONTEXTS (1 << FRAME_CONTEXTS_LOG2)
#endif // CONFIG_NO_FRAME_CONTEXT_SIGNALING
#define NUM_PING_PONG_BUFFERS 2
......@@ -347,7 +354,9 @@ typedef struct AV1Common {
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;
......
......@@ -4713,10 +4713,11 @@ static size_t read_uncompressed_header(AV1Decoder *pbi,
} 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 @@ static size_t read_uncompressed_header(AV1Decoder *pbi,
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 @@ void av1_decode_frame(AV1Decoder *pbi, const uint8_t *data,
#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 @@ void av1_decode_frame(AV1Decoder *pbi, const uint8_t *data,
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 @@ void av1_decode_frame(AV1Decoder *pbi, const uint8_t *data,
}
#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
}
......@@ -4399,9 +4399,9 @@ static void write_uncompressed_header(AV1_COMP *cpi,
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
......
......@@ -296,6 +296,10 @@ static void setup_frame(AV1_COMP *cpi) {
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 @@ static void setup_frame(AV1_COMP *cpi) {
#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 @@ static void setup_frame(AV1_COMP *cpi) {
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 @@ static void setup_frame(AV1_COMP *cpi) {
}
#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 @@ static void av1_enc_setup_mi(AV1_COMMON *cm) {
// 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 @@ static void encode_with_recode_loop(AV1_COMP *cpi, size_t *size,
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 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags,
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)) {
......
......@@ -70,6 +70,7 @@ typedef struct {
FRAME_CONTEXT fc;
} CODING_CONTEXT;
#if !CONFIG_NO_FRAME_CONTEXT_SIGNALING
typedef enum {
// regular inter frame
REGULAR_FRAME = 0,
......@@ -86,6 +87,7 @@ typedef enum {
EXT_ARF_FRAME = 5
#endif
} FRAME_CONTEXT_INDEX;
#endif
typedef enum {
NORMAL = 0,
......
......@@ -180,3 +180,4 @@ set(CONFIG_DIST_8X8 0 CACHE NUMBER "Internal flag.")
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.")
......@@ -339,6 +339,7 @@ EXPERIMENT_LIST="
mrc_tx
lpf_direct
uv_lvl
no_frame_context_signaling
"
CONFIG_LIST="
dependency_tracking
......
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