summaryrefslogtreecommitdiff
path: root/media/libaom/src/av1/encoder/gop_structure.c
diff options
context:
space:
mode:
Diffstat (limited to 'media/libaom/src/av1/encoder/gop_structure.c')
-rw-r--r--media/libaom/src/av1/encoder/gop_structure.c311
1 files changed, 311 insertions, 0 deletions
diff --git a/media/libaom/src/av1/encoder/gop_structure.c b/media/libaom/src/av1/encoder/gop_structure.c
new file mode 100644
index 0000000000..1ed71a0f99
--- /dev/null
+++ b/media/libaom/src/av1/encoder/gop_structure.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2019, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#include <stdint.h>
+
+#include "config/aom_config.h"
+#include "config/aom_scale_rtcd.h"
+
+#include "aom/aom_codec.h"
+#include "aom/aom_encoder.h"
+
+#include "aom_ports/system_state.h"
+
+#include "av1/common/av1_common_int.h"
+
+#include "av1/encoder/encoder.h"
+#include "av1/encoder/firstpass.h"
+#include "av1/encoder/gop_structure.h"
+
+// Set parameters for frames between 'start' and 'end' (excluding both).
+static void set_multi_layer_params(const TWO_PASS *twopass,
+ GF_GROUP *const gf_group, RATE_CONTROL *rc,
+ FRAME_INFO *frame_info, int start, int end,
+ int *cur_frame_idx, int *frame_ind,
+ int arf_ind, int layer_depth) {
+ const int num_frames_to_process = end - start - 1;
+ assert(num_frames_to_process >= 0);
+ if (num_frames_to_process == 0) return;
+
+ // Either we are at the last level of the pyramid, or we don't have enough
+ // frames between 'l' and 'r' to create one more level.
+ if (layer_depth > gf_group->max_layer_depth_allowed ||
+ num_frames_to_process < 3) {
+ // Leaf nodes.
+ while (++start < end) {
+ gf_group->update_type[*frame_ind] = LF_UPDATE;
+ gf_group->arf_src_offset[*frame_ind] = 0;
+ ++*cur_frame_idx;
+ gf_group->cur_frame_idx[*frame_ind] = *cur_frame_idx;
+ gf_group->frame_disp_idx[*frame_ind] = start;
+ gf_group->layer_depth[*frame_ind] = MAX_ARF_LAYERS;
+ gf_group->arf_boost[*frame_ind] = av1_calc_arf_boost(
+ twopass, rc, frame_info, start, end - start, 0, NULL, NULL);
+ gf_group->max_layer_depth =
+ AOMMAX(gf_group->max_layer_depth, layer_depth);
+ ++(*frame_ind);
+ }
+ } else {
+ const int m = (start + end) / 2;
+
+ // Internal ARF.
+ gf_group->update_type[*frame_ind] = INTNL_ARF_UPDATE;
+ gf_group->arf_src_offset[*frame_ind] = m - start - 1;
+ gf_group->cur_frame_idx[*frame_ind] = *cur_frame_idx;
+ gf_group->frame_disp_idx[*frame_ind] = m;
+ gf_group->layer_depth[*frame_ind] = layer_depth;
+
+ // Get the boost factor for intermediate ARF frames.
+ gf_group->arf_boost[*frame_ind] = av1_calc_arf_boost(
+ twopass, rc, frame_info, m, end - m, m - start, NULL, NULL);
+ ++(*frame_ind);
+
+ // Frames displayed before this internal ARF.
+ set_multi_layer_params(twopass, gf_group, rc, frame_info, start, m,
+ cur_frame_idx, frame_ind, 1, layer_depth + 1);
+
+ // Overlay for internal ARF.
+ gf_group->update_type[*frame_ind] = INTNL_OVERLAY_UPDATE;
+ gf_group->arf_src_offset[*frame_ind] = 0;
+ gf_group->cur_frame_idx[*frame_ind] = *cur_frame_idx;
+ gf_group->frame_disp_idx[*frame_ind] = m;
+ gf_group->arf_boost[*frame_ind] = 0;
+ gf_group->layer_depth[*frame_ind] = layer_depth;
+ ++(*frame_ind);
+
+ // Frames displayed after this internal ARF.
+ set_multi_layer_params(twopass, gf_group, rc, frame_info, m, end,
+ cur_frame_idx, frame_ind, arf_ind, layer_depth + 1);
+ }
+}
+
+static int construct_multi_layer_gf_structure(
+ AV1_COMP *cpi, TWO_PASS *twopass, GF_GROUP *const gf_group,
+ RATE_CONTROL *rc, FRAME_INFO *const frame_info, int gf_interval,
+ FRAME_UPDATE_TYPE first_frame_update_type) {
+ int frame_index = 0;
+
+ // Keyframe / Overlay frame / Golden frame.
+ assert(gf_interval >= 1);
+ assert(first_frame_update_type == KF_UPDATE ||
+ first_frame_update_type == OVERLAY_UPDATE ||
+ first_frame_update_type == GF_UPDATE);
+
+ gf_group->update_type[frame_index] = first_frame_update_type;
+ gf_group->arf_src_offset[frame_index] = 0;
+ gf_group->cur_frame_idx[frame_index] = 0;
+ gf_group->layer_depth[frame_index] =
+ first_frame_update_type == OVERLAY_UPDATE ? MAX_ARF_LAYERS + 1 : 0;
+ gf_group->max_layer_depth = 0;
+ ++frame_index;
+
+ // ALTREF.
+ const int use_altref = gf_group->max_layer_depth_allowed > 0;
+ if (use_altref) {
+ gf_group->update_type[frame_index] = ARF_UPDATE;
+ gf_group->arf_src_offset[frame_index] = gf_interval - 1;
+ gf_group->cur_frame_idx[frame_index] = 0;
+ gf_group->frame_disp_idx[frame_index] = gf_interval;
+ gf_group->layer_depth[frame_index] = 1;
+ gf_group->arf_boost[frame_index] = cpi->rc.gfu_boost;
+ gf_group->max_layer_depth = 1;
+ ++frame_index;
+ }
+
+ int cur_frame_index = 0;
+ // Rest of the frames.
+ set_multi_layer_params(twopass, gf_group, rc, frame_info, 0, gf_interval,
+ &cur_frame_index, &frame_index, 0, use_altref + 1);
+
+ // The end frame will be Overlay frame for an ARF GOP; otherwise set it to
+ // be GF, for consistency, which will be updated in the next GOP.
+ gf_group->update_type[frame_index] = use_altref ? OVERLAY_UPDATE : GF_UPDATE;
+ gf_group->arf_src_offset[frame_index] = 0;
+ return frame_index;
+}
+
+#define CHECK_GF_PARAMETER 0
+#if CHECK_GF_PARAMETER
+void check_frame_params(GF_GROUP *const gf_group, int gf_interval) {
+ static const char *update_type_strings[FRAME_UPDATE_TYPES] = {
+ "KF_UPDATE", "LF_UPDATE", "GF_UPDATE",
+ "ARF_UPDATE", "OVERLAY_UPDATE", "INTNL_OVERLAY_UPDATE",
+ "INTNL_ARF_UPDATE"
+ };
+ FILE *fid = fopen("GF_PARAMS.txt", "a");
+
+ fprintf(fid, "\ngf_interval = {%d}\n", gf_interval);
+ for (int i = 0; i < gf_group->size; ++i) {
+ fprintf(fid, "#%2d : %s %d %d %d %d\n", i,
+ update_type_strings[gf_group->update_type[i]],
+ gf_group->arf_src_offset[i], gf_group->arf_pos_in_gf[i],
+ gf_group->arf_update_idx[i], gf_group->pyramid_level[i]);
+ }
+
+ fprintf(fid, "number of nodes in each level: \n");
+ for (int i = 0; i < gf_group->pyramid_height; ++i) {
+ fprintf(fid, "lvl %d: %d ", i, gf_group->pyramid_lvl_nodes[i]);
+ }
+ fprintf(fid, "\n");
+ fclose(fid);
+}
+#endif // CHECK_GF_PARAMETER
+
+#define REF_IDX(ref) ((ref)-LAST_FRAME)
+
+static INLINE void reset_ref_frame_idx(int *ref_idx, int reset_value) {
+ for (int i = 0; i < REF_FRAMES; ++i) ref_idx[i] = reset_value;
+}
+
+static INLINE void set_ref_frame_disp_idx(GF_GROUP *const gf_group) {
+ for (int i = 0; i < gf_group->size; ++i) {
+ for (int ref = 0; ref < INTER_REFS_PER_FRAME + 1; ++ref) {
+ int ref_gop_idx = gf_group->ref_frame_gop_idx[i][ref];
+ if (ref_gop_idx == -1) {
+ gf_group->ref_frame_disp_idx[i][ref] = -1;
+ } else {
+ gf_group->ref_frame_disp_idx[i][ref] =
+ gf_group->frame_disp_idx[ref_gop_idx];
+ }
+ }
+ }
+}
+
+static void set_gop_ref_frame_map(GF_GROUP *const gf_group) {
+ // Initialize the reference slots as all -1.
+ for (int frame_idx = 0; frame_idx < gf_group->size; ++frame_idx)
+ reset_ref_frame_idx(gf_group->ref_frame_gop_idx[frame_idx], -1);
+
+ // Set the map for frames in the current gop
+ for (int frame_idx = 0; frame_idx < gf_group->size; ++frame_idx) {
+ const FRAME_UPDATE_TYPE update_type = gf_group->update_type[frame_idx];
+ // TODO(yuec): need to figure out how to determine
+ // (1) whether a KEY_FRAME has show_frame on
+ // (2) whether a frame with INTNL_OVERLAY_UPDATE type has
+ // show_existing_frame on
+ const int show_frame =
+ update_type != ARF_UPDATE && update_type != INTNL_ARF_UPDATE;
+ const int show_existing_frame =
+ update_type == OVERLAY_UPDATE || update_type == INTNL_OVERLAY_UPDATE;
+
+ int this_ref_map[INTER_REFS_PER_FRAME + 1];
+ memcpy(this_ref_map, gf_group->ref_frame_gop_idx[frame_idx],
+ sizeof(this_ref_map));
+ int *next_ref_map = &gf_group->ref_frame_gop_idx[frame_idx + 1][0];
+
+ switch (update_type) {
+ case KF_UPDATE:
+ if (show_frame) {
+ reset_ref_frame_idx(this_ref_map, frame_idx);
+ } else {
+ this_ref_map[REF_IDX(LAST3_FRAME)] = frame_idx;
+ this_ref_map[REF_IDX(EXTREF_FRAME)] = frame_idx;
+ this_ref_map[REF_IDX(ALTREF2_FRAME)] = frame_idx;
+ this_ref_map[REF_IDX(GOLDEN_FRAME)] = frame_idx;
+ this_ref_map[REF_IDX(ALTREF_FRAME)] = frame_idx;
+ }
+ break;
+ case LF_UPDATE: this_ref_map[REF_IDX(LAST3_FRAME)] = frame_idx; break;
+ case GF_UPDATE:
+ this_ref_map[REF_IDX(LAST3_FRAME)] = frame_idx;
+ this_ref_map[REF_IDX(GOLDEN_FRAME)] = frame_idx;
+ break;
+ case OVERLAY_UPDATE:
+ this_ref_map[REF_IDX(ALTREF_FRAME)] = frame_idx;
+ break;
+ case ARF_UPDATE: this_ref_map[REF_IDX(ALTREF_FRAME)] = frame_idx; break;
+ case INTNL_OVERLAY_UPDATE:
+ if (!show_existing_frame)
+ this_ref_map[REF_IDX(LAST3_FRAME)] = frame_idx;
+ break;
+ case INTNL_ARF_UPDATE:
+ this_ref_map[REF_IDX(EXTREF_FRAME)] = frame_idx;
+ break;
+ default: assert(0); break;
+ }
+
+ memcpy(next_ref_map, this_ref_map, sizeof(this_ref_map));
+
+ switch (update_type) {
+ case LF_UPDATE:
+ case GF_UPDATE:
+ next_ref_map[REF_IDX(LAST3_FRAME)] = this_ref_map[REF_IDX(LAST2_FRAME)];
+ next_ref_map[REF_IDX(LAST2_FRAME)] = this_ref_map[REF_IDX(LAST_FRAME)];
+ next_ref_map[REF_IDX(LAST_FRAME)] = this_ref_map[REF_IDX(LAST3_FRAME)];
+ break;
+ case INTNL_OVERLAY_UPDATE:
+ if (!show_existing_frame) {
+ next_ref_map[REF_IDX(LAST3_FRAME)] =
+ this_ref_map[REF_IDX(LAST2_FRAME)];
+ next_ref_map[REF_IDX(LAST2_FRAME)] =
+ this_ref_map[REF_IDX(LAST_FRAME)];
+ next_ref_map[REF_IDX(LAST_FRAME)] =
+ this_ref_map[REF_IDX(LAST3_FRAME)];
+ } else {
+ next_ref_map[REF_IDX(LAST_FRAME)] =
+ this_ref_map[REF_IDX(BWDREF_FRAME)];
+ next_ref_map[REF_IDX(LAST2_FRAME)] =
+ this_ref_map[REF_IDX(LAST_FRAME)];
+ next_ref_map[REF_IDX(LAST3_FRAME)] =
+ this_ref_map[REF_IDX(LAST2_FRAME)];
+ next_ref_map[REF_IDX(BWDREF_FRAME)] =
+ this_ref_map[REF_IDX(ALTREF2_FRAME)];
+ next_ref_map[REF_IDX(ALTREF2_FRAME)] =
+ this_ref_map[REF_IDX(EXTREF_FRAME)];
+ next_ref_map[REF_IDX(EXTREF_FRAME)] =
+ this_ref_map[REF_IDX(LAST3_FRAME)];
+ }
+ break;
+ case INTNL_ARF_UPDATE:
+ if (!show_existing_frame) {
+ next_ref_map[REF_IDX(BWDREF_FRAME)] =
+ this_ref_map[REF_IDX(EXTREF_FRAME)];
+ next_ref_map[REF_IDX(ALTREF2_FRAME)] =
+ this_ref_map[REF_IDX(BWDREF_FRAME)];
+ next_ref_map[REF_IDX(EXTREF_FRAME)] =
+ this_ref_map[REF_IDX(ALTREF2_FRAME)];
+ }
+ break;
+ case OVERLAY_UPDATE:
+ next_ref_map[REF_IDX(ALTREF_FRAME)] =
+ this_ref_map[REF_IDX(GOLDEN_FRAME)];
+ next_ref_map[REF_IDX(GOLDEN_FRAME)] =
+ this_ref_map[REF_IDX(ALTREF_FRAME)];
+ break;
+ default: break;
+ }
+ }
+
+ // Set the map in display order index by converting from gop indices in the
+ // above map
+ set_ref_frame_disp_idx(gf_group);
+}
+
+void av1_gop_setup_structure(AV1_COMP *cpi,
+ const EncodeFrameParams *const frame_params) {
+ RATE_CONTROL *const rc = &cpi->rc;
+ GF_GROUP *const gf_group = &cpi->gf_group;
+ TWO_PASS *const twopass = &cpi->twopass;
+ FRAME_INFO *const frame_info = &cpi->frame_info;
+ const int key_frame = (frame_params->frame_type == KEY_FRAME);
+ const FRAME_UPDATE_TYPE first_frame_update_type =
+ key_frame ? KF_UPDATE
+ : rc->source_alt_ref_active ? OVERLAY_UPDATE : GF_UPDATE;
+ gf_group->size = construct_multi_layer_gf_structure(
+ cpi, twopass, gf_group, rc, frame_info, rc->baseline_gf_interval,
+ first_frame_update_type);
+
+ set_gop_ref_frame_map(gf_group);
+
+#if CHECK_GF_PARAMETER
+ check_frame_params(gf_group, rc->baseline_gf_interval);
+#endif
+}