Add encoder support for multi-layer GF 16

Currently the use of the new multi-layer GF group of 16 is guarded by
the macro USE_GF16_MULTI_LAYER, which is turned off. Hence this CL
does not change any of the encoder behavior.

Change-Id: I588cd34e19388337a2ecb0a0cb3f796a37647e24
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index f6864cc..ad8d8f4 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -3649,10 +3649,31 @@
 #endif  // CONFIG_LOOPFILTERING_ACROSS_TILES
 }
 
-static int get_refresh_mask(AV1_COMP *cpi) {
+#if CONFIG_EXT_REFS
+#if USE_GF16_MULTI_LAYER
+static int get_refresh_mask_gf16(AV1_COMP *cpi) {
   int refresh_mask = 0;
 
+  if (cpi->refresh_last_frame || cpi->refresh_golden_frame ||
+      cpi->refresh_bwd_ref_frame || cpi->refresh_alt2_ref_frame ||
+      cpi->refresh_alt_ref_frame) {
+    assert(cpi->refresh_fb_idx >= 0 && cpi->refresh_fb_idx < REF_FRAMES);
+    refresh_mask |= (1 << cpi->refresh_fb_idx);
+  }
+
+  return refresh_mask;
+}
+#endif  // USE_GF16_MULTI_LAYER
+#endif  // CONFIG_EXT_REFS
+
+static int get_refresh_mask(AV1_COMP *cpi) {
 #if CONFIG_EXT_REFS
+#if USE_GF16_MULTI_LAYER
+  if (cpi->rc.baseline_gf_interval == 16) return get_refresh_mask_gf16(cpi);
+#endif  // USE_GF16_MULTI_LAYER
+
+  int refresh_mask = 0;
+
   // NOTE(zoeliu): When LAST_FRAME is to get refreshed, the decoder will be
   // notified to get LAST3_FRAME refreshed and then the virtual indexes for all
   // the 3 LAST reference frames will be updated accordingly, i.e.:
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 512a461..1176dcb 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -989,6 +989,7 @@
   cpi->bwd_fb_idx = LAST_REF_FRAMES + 1;
   cpi->alt2_fb_idx = LAST_REF_FRAMES + 2;
   cpi->alt_fb_idx = LAST_REF_FRAMES + 3;
+  cpi->ext_fb_idx = LAST_REF_FRAMES + 4;
   for (fb_idx = 0; fb_idx < MAX_EXT_ARFS + 1; ++fb_idx)
     cpi->arf_map[fb_idx] = LAST_REF_FRAMES + 2 + fb_idx;
 #else   // !CONFIG_EXT_REFS
@@ -3101,7 +3102,53 @@
 #endif
 
 #if CONFIG_EXT_REFS && !CONFIG_XIPHRC
+#if USE_GF16_MULTI_LAYER
+static void check_show_existing_frame_gf16(AV1_COMP *cpi) {
+  const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
+  AV1_COMMON *const cm = &cpi->common;
+  const FRAME_UPDATE_TYPE next_frame_update_type =
+      gf_group->update_type[gf_group->index];
+
+  if (cm->show_existing_frame == 1) {
+    cm->show_existing_frame = 0;
+  } else if (cpi->rc.is_last_bipred_frame) {
+    cpi->rc.is_last_bipred_frame = 0;
+    cm->show_existing_frame = 1;
+    cpi->existing_fb_idx_to_show = cpi->bwd_fb_idx;
+  } else if (next_frame_update_type == OVERLAY_UPDATE ||
+             next_frame_update_type == INTNL_OVERLAY_UPDATE) {
+    // Check the temporal filtering status for the next OVERLAY frame
+    const int num_arfs_in_gf = cpi->num_extra_arfs + 1;
+    int which_arf = 0, arf_idx;
+    // Identify the index to the next overlay frame.
+    for (arf_idx = 0; arf_idx < num_arfs_in_gf; arf_idx++) {
+      if (gf_group->index == cpi->arf_pos_for_ovrly[arf_idx]) {
+        which_arf = arf_idx;
+        break;
+      }
+    }
+    assert(arf_idx < num_arfs_in_gf);
+    if (cpi->is_arf_filter_off[which_arf]) {
+      cm->show_existing_frame = 1;
+      cpi->rc.is_src_frame_alt_ref = 1;
+      cpi->existing_fb_idx_to_show = (next_frame_update_type == OVERLAY_UPDATE)
+                                         ? cpi->alt_fb_idx
+                                         : cpi->bwd_fb_idx;
+      cpi->is_arf_filter_off[which_arf] = 0;
+    }
+  }
+  cpi->rc.is_src_frame_ext_arf = 0;
+}
+#endif  // USE_GF16_MULTI_LAYER
+
 static void check_show_existing_frame(AV1_COMP *cpi) {
+#if USE_GF16_MULTI_LAYER
+  if (cpi->rc.baseline_gf_interval == 16) {
+    check_show_existing_frame_gf16(cpi);
+    return;
+  }
+#endif  // USE_GF16_MULTI_LAYER
+
   const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
   AV1_COMMON *const cm = &cpi->common;
   const FRAME_UPDATE_TYPE next_frame_update_type =
@@ -3111,9 +3158,9 @@
   if (cm->show_existing_frame == 1) {
     cm->show_existing_frame = 0;
   } else if (cpi->rc.is_last_bipred_frame) {
-    // NOTE(zoeliu): If the current frame is a last bi-predictive frame, it is
-    //               needed next to show the BWDREF_FRAME, which is pointed by
-    //               the last_fb_idxes[0] after reference frame buffer update
+    // NOTE: If the current frame is a last bi-predictive frame, it is
+    //       needed next to show the BWDREF_FRAME, which is pointed by
+    //       the last_fb_idxes[0] after reference frame buffer update
     cpi->rc.is_last_bipred_frame = 0;
     cm->show_existing_frame = 1;
     cpi->existing_fb_idx_to_show = cpi->lst_fb_idxes[0];
@@ -3351,14 +3398,69 @@
 }
 #endif  // CONFIG_VAR_REFS
 
-static void update_reference_frames(AV1_COMP *cpi) {
+#if CONFIG_EXT_REFS
+#if USE_GF16_MULTI_LAYER
+static void update_reference_frames_gf16(AV1_COMP *cpi) {
   AV1_COMMON *const cm = &cpi->common;
   BufferPool *const pool = cm->buffer_pool;
 
+  if (cm->frame_type == KEY_FRAME) {
+    for (int ref_frame = 0; ref_frame < LAST_REF_FRAMES; ++ref_frame) {
+      ref_cnt_fb(pool->frame_bufs,
+                 &cm->ref_frame_map[cpi->lst_fb_idxes[ref_frame]],
+                 cm->new_fb_idx);
+    }
+    ref_cnt_fb(pool->frame_bufs, &cm->ref_frame_map[cpi->gld_fb_idx],
+               cm->new_fb_idx);
+    ref_cnt_fb(pool->frame_bufs, &cm->ref_frame_map[cpi->bwd_fb_idx],
+               cm->new_fb_idx);
+    ref_cnt_fb(pool->frame_bufs, &cm->ref_frame_map[cpi->alt2_fb_idx],
+               cm->new_fb_idx);
+    ref_cnt_fb(pool->frame_bufs, &cm->ref_frame_map[cpi->alt_fb_idx],
+               cm->new_fb_idx);
+  } else {
+    if (cpi->refresh_last_frame || cpi->refresh_golden_frame ||
+        cpi->refresh_bwd_ref_frame || cpi->refresh_alt2_ref_frame ||
+        cpi->refresh_alt_ref_frame) {
+      assert(cpi->refresh_fb_idx >= 0 && cpi->refresh_fb_idx < REF_FRAMES);
+      ref_cnt_fb(pool->frame_bufs, &cm->ref_frame_map[cpi->refresh_fb_idx],
+                 cm->new_fb_idx);
+    }
+
+    // TODO(zoeliu): To handle cpi->interp_filter_selected[].
+
+    // For GF of 16, an additional ref frame index mapping needs to be handled
+    // if this is the last frame to encode in the current GF group.
+    const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
+    if (gf_group->update_type[gf_group->index + 1] == OVERLAY_UPDATE)
+      av1_ref_frame_map_idx_updates(cpi, gf_group->index + 1);
+  }
+
+#if DUMP_REF_FRAME_IMAGES == 1
+  // Dump out all reference frame images.
+  dump_ref_frame_images(cpi);
+#endif  // DUMP_REF_FRAME_IMAGES
+}
+#endif  // USE_GF16_MULTI_LAYER
+#endif  // CONFIG_EXT_REFS
+
+static void update_reference_frames(AV1_COMP *cpi) {
+  AV1_COMMON *const cm = &cpi->common;
+
   // NOTE: Save the new show frame buffer index for --test-code=warn, i.e.,
   //       for the purpose to verify no mismatch between encoder and decoder.
   if (cm->show_frame) cpi->last_show_frame_buf_idx = cm->new_fb_idx;
 
+#if CONFIG_EXT_REFS
+#if USE_GF16_MULTI_LAYER
+  if (cpi->rc.baseline_gf_interval == 16) {
+    update_reference_frames_gf16(cpi);
+    return;
+  }
+#endif  // USE_GF16_MULTI_LAYER
+#endif  // CONFIG_EXT_REFS
+
+  BufferPool *const pool = cm->buffer_pool;
   // At this point the new frame has been encoded.
   // If any buffer copy / swapping is signaled it should be done here.
   if (cm->frame_type == KEY_FRAME) {
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 8792b22..b26c241 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -414,6 +414,10 @@
   int alt2_fb_idx;  // ALTREF2_FRAME
 #endif              // CONFIG_EXT_REFS
   int alt_fb_idx;
+#if CONFIG_EXT_REFS
+  int ext_fb_idx;      // extra ref frame buffer index
+  int refresh_fb_idx;  // ref frame buffer index to refresh
+#endif                 // CONFIG_EXT_REFS
 
   int last_show_frame_buf_idx;  // last show frame buffer index
 
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c
index daa626b..dc90480 100644
--- a/av1/encoder/firstpass.c
+++ b/av1/encoder/firstpass.c
@@ -1700,8 +1700,8 @@
       LAST_FRAME,     // cpi->lst_fb_idxes[LAST_FRAME - LAST_FRAME]
       LAST2_FRAME,    // cpi->lst_fb_idxes[LAST2_FRAME - LAST_FRAME]
       LAST3_FRAME,    // cpi->lst_fb_idxes[LAST3_FRAME - LAST_FRAME]
-      BWDREF_FRAME,   // cpi->bwd_fb_idx (BWDREF_FRAME)
       GOLDEN_FRAME,   // cpi->gld_fb_idx (GOLDEN_FRAME)
+      BWDREF_FRAME,   // cpi->bwd_fb_idx (BWDREF_FRAME)
       ALTREF2_FRAME,  // cpi->alt2_fb_idx (ALTREF2_FRAME)
       ALTREF_FRAME,   // cpi->alt_fb_idx (ALTREF_FRAME)
       REF_FRAMES,     // cpi->ext_fb_idx (extra ref frame)
@@ -2116,6 +2116,7 @@
   }
 };
 
+// === GF Group of 16 ===
 static void define_gf_group_structure_16(AV1_COMP *cpi) {
   RATE_CONTROL *const rc = &cpi->rc;
   TWO_PASS *const twopass = &cpi->twopass;
@@ -2138,13 +2139,26 @@
     // Treat KEY_FRAME differently
     if (frame_index == 0 && key_frame) {
       gf_group->update_type[frame_index] = KF_UPDATE;
+
       gf_group->rf_level[frame_index] = KF_STD;
+      gf_group->arf_src_offset[frame_index] = 0;
+      gf_group->brf_src_offset[frame_index] = 0;
+      gf_group->bidir_pred_enabled[frame_index] = 0;
+      for (int ref_idx = 0; ref_idx < REF_FRAMES; ++ref_idx)
+        gf_group->ref_fb_idx_map[frame_index][ref_idx] = ref_idx;
+      gf_group->refresh_idx[frame_index] =
+          cpi->lst_fb_idxes[LAST_FRAME - LAST_FRAME];
+      gf_group->refresh_flag[frame_index] =
+          cpi->lst_fb_idxes[LAST_FRAME - LAST_FRAME];
+
       continue;
     }
 
+    // == update_type ==
     gf_group->update_type[frame_index] =
         gf16_multi_layer_params[frame_index][param_idx++];
 
+    // == rf_level ==
     // Derive rf_level from update_type
     switch (gf_group->update_type[frame_index]) {
       case LF_UPDATE: gf_group->rf_level[frame_index] = INTER_NORMAL; break;
@@ -2166,20 +2180,71 @@
       default: gf_group->rf_level[frame_index] = INTER_NORMAL; break;
     }
 
+    // == arf_src_offset ==
     gf_group->arf_src_offset[frame_index] =
         gf16_multi_layer_params[frame_index][param_idx++];
+
+    // == brf_src_offset ==
     gf_group->brf_src_offset[frame_index] =
         gf16_multi_layer_params[frame_index][param_idx++];
 
+    // == bidir_pred_enabled ==
+    // Derive bidir_pred_enabled from bidir_src_offset
+    gf_group->bidir_pred_enabled[frame_index] =
+        gf_group->brf_src_offset[frame_index] ? 1 : 0;
+
+    // == ref_fb_idx_map ==
     for (int ref_idx = 0; ref_idx < REF_FRAMES; ++ref_idx)
       gf_group->ref_fb_idx_map[frame_index][ref_idx] =
           gf16_multi_layer_params[frame_index][param_idx++];
 
+    // == refresh_idx ==
     gf_group->refresh_idx[frame_index] =
         gf16_multi_layer_params[frame_index][param_idx++];
+
+    // == refresh_flag ==
     gf_group->refresh_flag[frame_index] =
         gf16_multi_layer_params[frame_index][param_idx];
   }
+
+  // Mark the ARF_UPDATE / INTNL_ARF_UPDATE and OVERLAY_UPDATE /
+  // INTNL_OVERLAY_UPDATE for rate allocation
+  // NOTE: Indexes are designed in the display order backward:
+  //       ALT[3] .. ALT[2] .. ALT[1] .. ALT[0],
+  //       but their coding order is as follows:
+  // ALT0-ALT2-ALT3 .. OVERLAY3 .. OVERLAY2-ALT1 .. OVERLAY1 .. OVERLAY0
+
+  const int num_arfs_in_gf = cpi->num_extra_arfs + 1;
+  const int sub_arf_interval = rc->baseline_gf_interval / num_arfs_in_gf;
+
+  // == arf_pos_for_ovrly ==: Position for OVERLAY
+  for (int arf_idx = 0; arf_idx < num_arfs_in_gf; arf_idx++) {
+    const int prior_num_arfs =
+        (arf_idx <= 1) ? num_arfs_in_gf : (num_arfs_in_gf - 1);
+    cpi->arf_pos_for_ovrly[arf_idx] =
+        sub_arf_interval * (num_arfs_in_gf - arf_idx) + prior_num_arfs;
+  }
+
+  // == arf_pos_in_gf ==: Position for ALTREF
+  cpi->arf_pos_in_gf[0] = 1;
+  cpi->arf_pos_in_gf[1] = cpi->arf_pos_for_ovrly[2] + 1;
+  cpi->arf_pos_in_gf[2] = 2;
+  cpi->arf_pos_in_gf[3] = 3;
+
+  // == arf_update_idx ==
+  // == arf_ref_idx ==
+  // NOTE: Due to the hierarchical nature of GF16, these two parameters only
+  //       relect the index to the nearest future overlay.
+  int start_frame_index = 0;
+  for (int arf_idx = (num_arfs_in_gf - 1); arf_idx >= 0; --arf_idx) {
+    const int end_frame_index = cpi->arf_pos_for_ovrly[arf_idx];
+    for (int frame_index = start_frame_index; frame_index <= end_frame_index;
+         ++frame_index) {
+      gf_group->arf_update_idx[frame_index] = arf_idx;
+      gf_group->arf_ref_idx[frame_index] = arf_idx;
+    }
+    start_frame_index = end_frame_index + 1;
+  }
 }
 #endif  // USE_GF16_MULTI_LAYER
 #endif  // CONFIG_EXT_REFS
@@ -2191,31 +2256,6 @@
 #if USE_GF16_MULTI_LAYER
   if (rc->baseline_gf_interval == 16) {
     define_gf_group_structure_16(cpi);
-
-    // Mark the ARF_UPDATE / INTNL_ARF_UPDATE and OVERLAY_UPDATE /
-    // INTNL_OVERLAY_UPDATE for rate allocation
-    // NOTE: Indexes are designed in the display order backward:
-    //       ALT[3] .. ALT[2] .. ALT[1] .. ALT[0],
-    //       but their coding order is as follows:
-    // ALT0-ALT2-ALT3 .. OVERLAY3 .. OVERLAY2-ALT1 .. OVERLAY1 .. OVERLAY0
-
-    const int num_arfs_in_gf = cpi->num_extra_arfs + 1;
-    const int sub_arf_interval = rc->baseline_gf_interval / num_arfs_in_gf;
-
-    // arf_pos_for_ovrly[]: Position for OVERLAY
-    for (int arf_idx = 0; arf_idx < num_arfs_in_gf; arf_idx++) {
-      const int prior_num_arfs =
-          (arf_idx <= 1) ? num_arfs_in_gf : (num_arfs_in_gf - 1);
-      cpi->arf_pos_for_ovrly[arf_idx] =
-          sub_arf_interval * (num_arfs_in_gf - arf_idx) + prior_num_arfs;
-    }
-
-    // arf_pos_in_gf[]:     Position for ALTREF
-    cpi->arf_pos_in_gf[0] = 1;
-    cpi->arf_pos_in_gf[1] = cpi->arf_pos_for_ovrly[2] + 1;
-    cpi->arf_pos_in_gf[2] = 2;
-    cpi->arf_pos_in_gf[3] = 3;
-
     return;
   }
 #endif  // USE_GF16_MULTI_LAYER
@@ -2223,7 +2263,6 @@
 
   TWO_PASS *const twopass = &cpi->twopass;
   GF_GROUP *const gf_group = &twopass->gf_group;
-
   int i;
   int frame_index = 0;
   const int key_frame = cpi->common.frame_type == KEY_FRAME;
@@ -3385,6 +3424,153 @@
   twopass->modified_error_left -= kf_group_err;
 }
 
+#if USE_GF16_MULTI_LAYER
+// === GF Group of 16 ===
+void av1_ref_frame_map_idx_updates(AV1_COMP *cpi, int gf_frame_index) {
+  TWO_PASS *const twopass = &cpi->twopass;
+  GF_GROUP *const gf_group = &twopass->gf_group;
+
+  int ref_fb_idx_prev[REF_FRAMES];
+  int ref_fb_idx_curr[REF_FRAMES];
+
+  ref_fb_idx_prev[LAST_FRAME - LAST_FRAME] =
+      cpi->lst_fb_idxes[LAST_FRAME - LAST_FRAME];
+  ref_fb_idx_prev[LAST2_FRAME - LAST_FRAME] =
+      cpi->lst_fb_idxes[LAST2_FRAME - LAST_FRAME];
+  ref_fb_idx_prev[LAST3_FRAME - LAST_FRAME] =
+      cpi->lst_fb_idxes[LAST3_FRAME - LAST_FRAME];
+  ref_fb_idx_prev[GOLDEN_FRAME - LAST_FRAME] = cpi->gld_fb_idx;
+  ref_fb_idx_prev[BWDREF_FRAME - LAST_FRAME] = cpi->bwd_fb_idx;
+  ref_fb_idx_prev[ALTREF2_FRAME - LAST_FRAME] = cpi->alt2_fb_idx;
+  ref_fb_idx_prev[ALTREF_FRAME - LAST_FRAME] = cpi->alt_fb_idx;
+  ref_fb_idx_prev[REF_FRAMES - LAST_FRAME] = cpi->ext_fb_idx;
+
+  // Update map index for each reference frame
+  for (int ref_idx = 0; ref_idx < REF_FRAMES; ++ref_idx) {
+    int ref_frame = gf_group->ref_fb_idx_map[gf_frame_index][ref_idx];
+    ref_fb_idx_curr[ref_idx] = ref_fb_idx_prev[ref_frame - LAST_FRAME];
+  }
+
+  cpi->lst_fb_idxes[LAST_FRAME - LAST_FRAME] =
+      ref_fb_idx_curr[LAST_FRAME - LAST_FRAME];
+  cpi->lst_fb_idxes[LAST2_FRAME - LAST_FRAME] =
+      ref_fb_idx_curr[LAST2_FRAME - LAST_FRAME];
+  cpi->lst_fb_idxes[LAST3_FRAME - LAST_FRAME] =
+      ref_fb_idx_curr[LAST3_FRAME - LAST_FRAME];
+  cpi->gld_fb_idx = ref_fb_idx_curr[GOLDEN_FRAME - LAST_FRAME];
+  cpi->bwd_fb_idx = ref_fb_idx_curr[BWDREF_FRAME - LAST_FRAME];
+  cpi->alt2_fb_idx = ref_fb_idx_curr[ALTREF2_FRAME - LAST_FRAME];
+  cpi->alt_fb_idx = ref_fb_idx_curr[ALTREF_FRAME - LAST_FRAME];
+  cpi->ext_fb_idx = ref_fb_idx_curr[REF_FRAMES - LAST_FRAME];
+}
+
+// Define the reference buffers that will be updated post encode.
+static void configure_buffer_updates_16(AV1_COMP *cpi) {
+  TWO_PASS *const twopass = &cpi->twopass;
+  GF_GROUP *const gf_group = &twopass->gf_group;
+
+  if (gf_group->update_type[gf_group->index] == KF_UPDATE) {
+    cpi->refresh_fb_idx = 0;
+
+    cpi->refresh_last_frame = 1;
+    cpi->refresh_golden_frame = 1;
+    cpi->refresh_bwd_ref_frame = 1;
+    cpi->refresh_alt2_ref_frame = 1;
+    cpi->refresh_alt_ref_frame = 1;
+
+    return;
+  }
+
+  // Update reference frame map indexes
+  av1_ref_frame_map_idx_updates(cpi, gf_group->index);
+
+  // Update refresh index
+  switch (gf_group->refresh_idx[gf_group->index]) {
+    case LAST_FRAME:
+      cpi->refresh_fb_idx = cpi->lst_fb_idxes[LAST_FRAME - LAST_FRAME];
+      break;
+
+    case LAST2_FRAME:
+      cpi->refresh_fb_idx = cpi->lst_fb_idxes[LAST2_FRAME - LAST_FRAME];
+      break;
+
+    case LAST3_FRAME:
+      cpi->refresh_fb_idx = cpi->lst_fb_idxes[LAST3_FRAME - LAST_FRAME];
+      break;
+
+    case GOLDEN_FRAME: cpi->refresh_fb_idx = cpi->gld_fb_idx; break;
+
+    case BWDREF_FRAME: cpi->refresh_fb_idx = cpi->bwd_fb_idx; break;
+
+    case ALTREF2_FRAME: cpi->refresh_fb_idx = cpi->alt2_fb_idx; break;
+
+    case ALTREF_FRAME: cpi->refresh_fb_idx = cpi->alt_fb_idx; break;
+
+    case REF_FRAMES: cpi->refresh_fb_idx = cpi->ext_fb_idx; break;
+
+    default: assert(0); break;
+  }
+
+  // Update refresh flags
+  switch (gf_group->refresh_flag[gf_group->index]) {
+    case LAST_FRAME:
+      cpi->refresh_last_frame = 1;
+      cpi->refresh_golden_frame = 0;
+      cpi->refresh_bwd_ref_frame = 0;
+      cpi->refresh_alt2_ref_frame = 0;
+      cpi->refresh_alt_ref_frame = 0;
+      break;
+
+    case GOLDEN_FRAME:
+      cpi->refresh_last_frame = 0;
+      cpi->refresh_golden_frame = 1;
+      cpi->refresh_bwd_ref_frame = 0;
+      cpi->refresh_alt2_ref_frame = 0;
+      cpi->refresh_alt_ref_frame = 0;
+      break;
+
+    case BWDREF_FRAME:
+      cpi->refresh_last_frame = 0;
+      cpi->refresh_golden_frame = 0;
+      cpi->refresh_bwd_ref_frame = 1;
+      cpi->refresh_alt2_ref_frame = 0;
+      cpi->refresh_alt_ref_frame = 0;
+      break;
+
+    case ALTREF2_FRAME:
+      cpi->refresh_last_frame = 0;
+      cpi->refresh_golden_frame = 0;
+      cpi->refresh_bwd_ref_frame = 0;
+      cpi->refresh_alt2_ref_frame = 1;
+      cpi->refresh_alt_ref_frame = 0;
+      break;
+
+    case ALTREF_FRAME:
+      cpi->refresh_last_frame = 0;
+      cpi->refresh_golden_frame = 0;
+      cpi->refresh_bwd_ref_frame = 0;
+      cpi->refresh_alt2_ref_frame = 0;
+      cpi->refresh_alt_ref_frame = 1;
+      break;
+
+    default: assert(0); break;
+  }
+
+  switch (gf_group->update_type[gf_group->index]) {
+    case BRF_UPDATE: cpi->rc.is_bwd_ref_frame = 1; break;
+
+    case LAST_BIPRED_UPDATE: cpi->rc.is_last_bipred_frame = 1; break;
+
+    case BIPRED_UPDATE: cpi->rc.is_bipred_frame = 1; break;
+
+    case INTNL_OVERLAY_UPDATE: cpi->rc.is_src_frame_ext_arf = 1;
+    case OVERLAY_UPDATE: cpi->rc.is_src_frame_alt_ref = 1; break;
+
+    default: break;
+  }
+}
+#endif  // USE_GF16_MULTI_LAYER
+
 // Define the reference buffers that will be updated post encode.
 static void configure_buffer_updates(AV1_COMP *cpi) {
   TWO_PASS *const twopass = &cpi->twopass;
@@ -3398,6 +3584,14 @@
   cpi->rc.is_last_bipred_frame = 0;
   cpi->rc.is_bipred_frame = 0;
   cpi->rc.is_src_frame_ext_arf = 0;
+
+#if USE_GF16_MULTI_LAYER
+  RATE_CONTROL *const rc = &cpi->rc;
+  if (rc->baseline_gf_interval == 16) {
+    configure_buffer_updates_16(cpi);
+    return;
+  }
+#endif  // USE_GF16_MULTI_LAYER
 #endif  // CONFIG_EXT_REFS
 
   switch (twopass->gf_group.update_type[twopass->gf_group.index]) {
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h
index 7c948a5..9ac542b 100644
--- a/av1/encoder/firstpass.h
+++ b/av1/encoder/firstpass.h
@@ -199,6 +199,10 @@
 void av1_twopass_postencode_update(struct AV1_COMP *cpi);
 
 #if CONFIG_EXT_REFS
+#if USE_GF16_MULTI_LAYER
+void av1_ref_frame_map_idx_updates(struct AV1_COMP *cpi, int gf_frame_index);
+#endif  // USE_GF16_MULTI_LAYER
+
 static INLINE int get_number_of_extra_arfs(int interval, int arf_pending) {
   if (arf_pending && MAX_EXT_ARFS > 0)
     return interval >= MIN_EXT_ARF_INTERVAL * (MAX_EXT_ARFS + 1)
diff --git a/av1/encoder/temporal_filter.c b/av1/encoder/temporal_filter.c
index f9304ae..5c1fa32 100644
--- a/av1/encoder/temporal_filter.c
+++ b/av1/encoder/temporal_filter.c
@@ -652,14 +652,29 @@
     strength = 0;
     frames_to_blur = 1;
   }
-#endif  // CONFIG_EXT_REFS
 
-#if CONFIG_EXT_REFS
-  if (strength == 0 && frames_to_blur == 1) {
-    cpi->is_arf_filter_off[gf_group->arf_update_idx[gf_group->index]] = 1;
-  } else {
-    cpi->is_arf_filter_off[gf_group->arf_update_idx[gf_group->index]] = 0;
+  int which_arf = gf_group->arf_update_idx[gf_group->index];
+
+#if USE_GF16_MULTI_LAYER
+  if (cpi->rc.baseline_gf_interval == 16) {
+    // Identify the index to the current ARF.
+    const int num_arfs_in_gf = cpi->num_extra_arfs + 1;
+    int arf_idx;
+    for (arf_idx = 0; arf_idx < num_arfs_in_gf; arf_idx++) {
+      if (gf_group->index == cpi->arf_pos_in_gf[arf_idx]) {
+        which_arf = arf_idx;
+        break;
+      }
+    }
+    assert(arf_idx < num_arfs_in_gf);
   }
+#endif  // USE_GF16_MULTI_LAYER
+
+  // Set the temporal filtering status for the corresponding OVERLAY frame
+  if (strength == 0 && frames_to_blur == 1)
+    cpi->is_arf_filter_off[which_arf] = 1;
+  else
+    cpi->is_arf_filter_off[which_arf] = 0;
 #endif  // CONFIG_EXT_REFS
 
   frames_to_blur_backward = (frames_to_blur / 2);