Commit b57fee02 authored by Zoe Liu's avatar Zoe Liu

[NORMATIVE] Add decoder support for frame_refs_signaling

One bit is added to the frame header, to signal whether the references
for inter frames will be short-signaled.

When the bit is set, only 6 bits are used at the frame header level to
signal the choices of LAST_FRAME and GOLDEN_FRAME out of the eight
buffered references. All the other 5 references will be specified
using the frame offset info. Hence, compared to the baseline, the use
of frame_refs_signaling provides 2 scenarios:

(1) Reference short-signaling:
    3*7 - (1+3*2) = 14 bits are saved in the frame header;
(2) Reference regular-signaling:
    1 bit is added to the frame header.

BUG=aomedia:1392

Change-Id: I2d4ff0e367a4df107235c1e7066dd28cb2c60431
parent 0c294fab
......@@ -491,7 +491,10 @@ typedef struct macroblockd_plane {
((x) + (i) * (1 << (tx_size_wide_log2[0] + tx_size_high_log2[0])))
typedef struct RefBuffer {
int idx;
int idx; // frame buf idx
#if CONFIG_FRAME_REFS_SIGNALING
int map_idx; // frame map idx
#endif // CONFIG_FRAME_REFS_SIGNALING
YV12_BUFFER_CONFIG *buf;
struct scale_factors sf;
} RefBuffer;
......
......@@ -9,6 +9,8 @@
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#include <stdlib.h>
#include "av1/common/mvref_common.h"
#include "av1/common/warped_motion.h"
......@@ -2159,3 +2161,192 @@ void av1_setup_skip_mode_allowed(AV1_COMMON *cm) {
}
}
#endif // CONFIG_EXT_SKIP
#if CONFIG_FRAME_REFS_SIGNALING
typedef struct {
int map_idx; // frame map index
int buf_idx; // frame buffer index
int offset; // frame offset
} REF_FRAME_INFO;
static int compare_ref_frame_info(const void *arg_a, const void *arg_b) {
const REF_FRAME_INFO *info_a = (REF_FRAME_INFO *)arg_a;
const REF_FRAME_INFO *info_b = (REF_FRAME_INFO *)arg_b;
if (info_a->offset < info_b->offset)
return -1;
else if (info_a->offset > info_b->offset)
return 1;
return (info_a->map_idx < info_b->map_idx)
? -1
: ((info_a->map_idx > info_b->map_idx) ? 1 : 0);
}
static void set_ref_frame_info(AV1_COMMON *const cm, int frame_idx,
REF_FRAME_INFO *ref_info) {
assert(frame_idx >= 0 && frame_idx <= INTER_REFS_PER_FRAME);
const int buf_idx = ref_info->buf_idx;
cm->frame_refs[frame_idx].idx = buf_idx;
cm->frame_refs[frame_idx].buf = &cm->buffer_pool->frame_bufs[buf_idx].buf;
cm->frame_refs[frame_idx].map_idx = ref_info->map_idx;
}
void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx,
int gld_map_idx) {
BufferPool *const pool = cm->buffer_pool;
RefCntBuffer *const frame_bufs = pool->frame_bufs;
int lst_frame_offset = -1;
int gld_frame_offset = -1;
const int cur_frame_offset = (int)cm->cur_frame->cur_frame_offset;
REF_FRAME_INFO ref_frame_info[REF_FRAMES];
int ref_flag_list[INTER_REFS_PER_FRAME] = { 0, 0, 0, 0, 0, 0, 0 };
for (int i = 0; i < REF_FRAMES; ++i) {
const int map_idx = i;
ref_frame_info[i].map_idx = map_idx;
ref_frame_info[i].offset = -1;
const int buf_idx = cm->ref_frame_map[map_idx];
ref_frame_info[i].buf_idx = buf_idx;
if (buf_idx < 0 || buf_idx >= FRAME_BUFFERS) continue;
// TODO(zoeliu@google.com): To verify the checking on ref_count.
if (frame_bufs[buf_idx].ref_count <= 0) continue;
const int offset = (int)frame_bufs[buf_idx].cur_frame_offset;
ref_frame_info[i].offset = offset;
if (map_idx == lst_map_idx) lst_frame_offset = offset;
if (map_idx == gld_map_idx) gld_frame_offset = offset;
}
// Confirm both LAST_FRAME and GOLDEN_FRAME are valid forward reference
// frames.
if (lst_frame_offset < 0 || lst_frame_offset >= cur_frame_offset) {
aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
"Inter frame requests a look-ahead frame as LAST");
}
if (gld_frame_offset < 0 || gld_frame_offset >= cur_frame_offset) {
aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
"Inter frame requests a look-ahead frame as GOLDEN");
}
// Sort ref frames based on their frame_offset values.
qsort(ref_frame_info, REF_FRAMES, sizeof(REF_FRAME_INFO),
compare_ref_frame_info);
// Identify forward and backward reference frames.
// Forward reference: offset < cur_frame_offset
// Backward reference: offset >= cur_frame_offset
int fwd_start_idx = 0, fwd_end_idx = REF_FRAMES - 1;
for (int i = 0; i < REF_FRAMES; i++) {
if (ref_frame_info[i].offset == -1) {
fwd_start_idx++;
continue;
}
if (ref_frame_info[i].offset >= cur_frame_offset) {
fwd_end_idx = i - 1;
break;
}
}
int bwd_start_idx = fwd_end_idx + 1;
int bwd_end_idx = REF_FRAMES - 1;
// === Backward Reference Frames ===
// == ALTREF_FRAME ==
if (bwd_start_idx <= bwd_end_idx) {
set_ref_frame_info(cm, ALTREF_FRAME - LAST_FRAME,
&ref_frame_info[bwd_end_idx]);
ref_flag_list[ALTREF_FRAME - LAST_FRAME] = 1;
bwd_end_idx--;
}
// == BWDREF_FRAME ==
if (bwd_start_idx <= bwd_end_idx) {
set_ref_frame_info(cm, BWDREF_FRAME - LAST_FRAME,
&ref_frame_info[bwd_start_idx]);
ref_flag_list[BWDREF_FRAME - LAST_FRAME] = 1;
bwd_start_idx++;
}
// == ALTREF2_FRAME ==
if (bwd_start_idx <= bwd_end_idx) {
set_ref_frame_info(cm, ALTREF2_FRAME - LAST_FRAME,
&ref_frame_info[bwd_start_idx]);
ref_flag_list[ALTREF2_FRAME - LAST_FRAME] = 1;
}
// === Forward Reference Frames ===
for (int i = fwd_start_idx; i <= fwd_end_idx; ++i) {
// == LAST_FRAME ==
if (ref_frame_info[i].map_idx == lst_map_idx) {
set_ref_frame_info(cm, LAST_FRAME - LAST_FRAME, &ref_frame_info[i]);
ref_flag_list[LAST_FRAME - LAST_FRAME] = 1;
}
// == GOLDEN_FRAME ==
if (ref_frame_info[i].map_idx == gld_map_idx) {
set_ref_frame_info(cm, GOLDEN_FRAME - LAST_FRAME, &ref_frame_info[i]);
ref_flag_list[GOLDEN_FRAME - LAST_FRAME] = 1;
}
}
assert(ref_flag_list[LAST_FRAME - LAST_FRAME] == 1 &&
ref_flag_list[GOLDEN_FRAME - LAST_FRAME] == 1);
// == LAST2_FRAME ==
// == LAST3_FRAME ==
// == BWDREF_FRAME ==
// == ALTREF2_FRAME ==
// == ALTREF_FRAME ==
// Set up the reference frames in the anti-chronological order.
static const MV_REFERENCE_FRAME ref_frame_list[INTER_REFS_PER_FRAME - 2] = {
LAST2_FRAME, LAST3_FRAME, BWDREF_FRAME, ALTREF2_FRAME, ALTREF_FRAME
};
int ref_idx;
for (ref_idx = 0; ref_idx < (INTER_REFS_PER_FRAME - 2); ref_idx++) {
const MV_REFERENCE_FRAME ref_frame = ref_frame_list[ref_idx];
if (ref_flag_list[ref_frame - LAST_FRAME] == 1) continue;
while (fwd_start_idx <= fwd_end_idx &&
(ref_frame_info[fwd_end_idx].map_idx == lst_map_idx ||
ref_frame_info[fwd_end_idx].map_idx == gld_map_idx)) {
fwd_end_idx--;
}
if (fwd_start_idx > fwd_end_idx) break;
set_ref_frame_info(cm, ref_frame - LAST_FRAME,
&ref_frame_info[fwd_end_idx]);
ref_flag_list[ref_frame - LAST_FRAME] = 1;
fwd_end_idx--;
}
// Assign all the remaining frame(s), if any, to the earliest reference frame.
for (; ref_idx < (INTER_REFS_PER_FRAME - 2); ref_idx++) {
const MV_REFERENCE_FRAME ref_frame = ref_frame_list[ref_idx];
set_ref_frame_info(cm, ref_frame - LAST_FRAME,
&ref_frame_info[fwd_start_idx]);
ref_flag_list[ref_frame - LAST_FRAME] = 1;
}
for (int i = 0; i < INTER_REFS_PER_FRAME; i++) {
assert(ref_flag_list[i] == 1);
}
}
#endif // CONFIG_FRAME_REFS_SIGNALING
......@@ -442,6 +442,10 @@ void av1_setup_skip_mode_allowed(AV1_COMMON *cm);
void av1_setup_motion_field(AV1_COMMON *cm);
#endif // CONFIG_MFMV
#if CONFIG_FRAME_REFS_SIGNALING
void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx, int gld_map_idx);
#endif // CONFIG_FRAME_REFS_SIGNALING
static INLINE void av1_collect_neighbors_ref_counts(MACROBLOCKD *const xd) {
av1_zero(xd->neighbors_ref_counts);
......
......@@ -614,6 +614,10 @@ typedef struct AV1Common {
DqType dq_type;
#endif // CONFIG_NEW_QUANT
#if CONFIG_FRAME_REFS_SIGNALING
int frame_refs_short_signaling;
#endif // CONFIG_FRAME_REFS_SIGNALING
#if CONFIG_SCALABILITY
int temporal_layer_id;
int enhancement_layer_id;
......
......@@ -2881,6 +2881,10 @@ static int read_uncompressed_header(AV1Decoder *pbi,
cm->allow_intrabc = 0;
#endif // CONFIG_INTRABC
#if CONFIG_FRAME_REFS_SIGNALING
cm->frame_refs_short_signaling = 0;
#endif // CONFIG_FRAME_REFS_SIGNALING
if (cm->frame_type == KEY_FRAME) {
cm->current_video_frame = 0;
#if !CONFIG_OBU
......@@ -2995,9 +2999,17 @@ static int read_uncompressed_header(AV1Decoder *pbi,
cm->is_reference_frame = 0;
}
for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
const int ref = aom_rb_read_literal(rb, REF_FRAMES_LOG2);
const int idx = cm->ref_frame_map[ref];
#if CONFIG_FRAME_REFS_SIGNALING
cm->frame_refs_short_signaling = aom_rb_read_bit(rb);
if (cm->frame_refs_short_signaling) {
// == LAST_FRAME ==
const int lst_ref = aom_rb_read_literal(rb, REF_FRAMES_LOG2);
const int lst_idx = cm->ref_frame_map[lst_ref];
// == GOLDEN_FRAME ==
const int gld_ref = aom_rb_read_literal(rb, REF_FRAMES_LOG2);
const int gld_idx = cm->ref_frame_map[gld_ref];
// Most of the time, streams start with a keyframe. In that case,
// ref_frame_map will have been filled in at that point and will not
......@@ -3005,18 +3017,51 @@ static int read_uncompressed_header(AV1Decoder *pbi,
// with an intra-only frame, so long as they don't then signal a
// reference to a slot that hasn't been set yet. That's what we are
// checking here.
if (idx == -1)
if (lst_idx == -1)
aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
"Inter frame requests nonexistent reference");
if (gld_idx == -1)
aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
"Inter frame requests nonexistent reference");
av1_set_frame_refs(cm, lst_ref, gld_ref);
}
#endif // CONFIG_FRAME_REFS_SIGNALING
for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
int ref = 0;
#if CONFIG_FRAME_REFS_SIGNALING
if (!cm->frame_refs_short_signaling) {
#endif // CONFIG_FRAME_REFS_SIGNALING
ref = aom_rb_read_literal(rb, REF_FRAMES_LOG2);
const int idx = cm->ref_frame_map[ref];
// Most of the time, streams start with a keyframe. In that case,
// ref_frame_map will have been filled in at that point and will not
// contain any -1's. However, streams are explicitly allowed to start
// with an intra-only frame, so long as they don't then signal a
// reference to a slot that hasn't been set yet. That's what we are
// checking here.
if (idx == -1)
aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
"Inter frame requests nonexistent reference");
RefBuffer *const ref_frame = &cm->frame_refs[i];
ref_frame->idx = idx;
ref_frame->buf = &frame_bufs[idx].buf;
#if CONFIG_FRAME_REFS_SIGNALING
ref_frame->map_idx = ref;
} else {
ref = cm->frame_refs[i].map_idx;
}
#endif // CONFIG_FRAME_REFS_SIGNALING
RefBuffer *const ref_frame = &cm->frame_refs[i];
ref_frame->idx = idx;
ref_frame->buf = &frame_bufs[idx].buf;
#if CONFIG_OBU
// NOTE: For the scenario of (cm->frame_type != S_FRAME),
// ref_frame_sign_bias will be reset based on frame offsets.
cm->ref_frame_sign_bias[LAST_FRAME + i] = 0;
#endif // CONFIG_OBU
#if CONFIG_REFERENCE_BUFFER
if (cm->seq_params.frame_id_numbers_present_flag) {
int frame_id_length = cm->seq_params.frame_id_length;
......@@ -3026,8 +3071,8 @@ static int read_uncompressed_header(AV1Decoder *pbi,
((cm->current_frame_id - (delta_frame_id_minus1 + 1) +
(1 << frame_id_length)) %
(1 << frame_id_length));
/* Compare values derived from delta_frame_id_minus1 and
* refresh_frame_flags. Also, check valid for referencing */
// Compare values derived from delta_frame_id_minus1 and
// refresh_frame_flags. Also, check valid for referencing
if (ref_frame_id != cm->ref_frame_id[ref] ||
cm->valid_for_referencing[ref] == 0)
aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
......
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