Add compatiblility with ARF_UPDATE keyframes.

Configure reference buffer update and tweak the encoder
to allow the keyframe to be arf + overlay, which will be added
in a future commit.

Change-Id: I87f32c15332d78f0626a955d940a99a29cc65ef8
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index c279f60..e4db615 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -2958,7 +2958,7 @@
 
   // Shown keyframes and switch-frames automatically refreshes all reference
   // frames.  For all other frame types, we need to write refresh_frame_flags.
-  if ((current_frame->frame_type == KEY_FRAME && cpi->no_show_fwd_kf) ||
+  if ((current_frame->frame_type == KEY_FRAME && !cm->show_frame) ||
       current_frame->frame_type == INTER_FRAME ||
       current_frame->frame_type == INTRA_ONLY_FRAME)
     aom_wb_write_literal(wb, current_frame->refresh_frame_flags, REF_FRAMES);
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index 6c4a3ce..0966093 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -46,7 +46,8 @@
 
 void av1_configure_buffer_updates(
     AV1_COMP *const cpi, RefreshFrameFlagsInfo *const refresh_frame_flags,
-    const FRAME_UPDATE_TYPE type, int force_refresh_all) {
+    const FRAME_UPDATE_TYPE type, const FRAME_TYPE frame_type,
+    int force_refresh_all) {
   // NOTE(weitinglin): Should we define another function to take care of
   // cpi->rc.is_$Source_Type to make this function as it is in the comment?
 
@@ -74,7 +75,13 @@
 
     case ARF_UPDATE:
       // NOTE: BWDREF does not get updated along with ALTREF_FRAME.
-      set_refresh_frame_flags(refresh_frame_flags, false, false, true);
+      if (frame_type == KEY_FRAME && !cpi->no_show_fwd_kf) {
+        // TODO(bohanli): consider moving this to force_refresh_all?
+        // This is Keyframe as arf
+        set_refresh_frame_flags(refresh_frame_flags, true, true, true);
+      } else {
+        set_refresh_frame_flags(refresh_frame_flags, false, false, true);
+      }
       break;
 
     case INTNL_OVERLAY_UPDATE:
@@ -572,7 +579,8 @@
 // Update reference frame stack info.
 void av1_update_ref_frame_map(AV1_COMP *cpi,
                               FRAME_UPDATE_TYPE frame_update_type,
-                              int show_existing_frame, int ref_map_index,
+                              FRAME_TYPE frame_type, int show_existing_frame,
+                              int ref_map_index,
                               RefBufferStack *ref_buffer_stack) {
   AV1_COMMON *const cm = &cpi->common;
   // TODO(jingning): Consider the S-frame same as key frame for the
@@ -612,7 +620,16 @@
       break;
     case ARF_UPDATE:
     case INTNL_ARF_UPDATE:
-      update_arf_stack(ref_map_index, ref_buffer_stack);
+      if (frame_type == KEY_FRAME && !cpi->no_show_fwd_kf) {
+        stack_reset(ref_buffer_stack->lst_stack,
+                    &ref_buffer_stack->lst_stack_size);
+        stack_reset(ref_buffer_stack->gld_stack,
+                    &ref_buffer_stack->gld_stack_size);
+        stack_reset(ref_buffer_stack->arf_stack,
+                    &ref_buffer_stack->arf_stack_size);
+      } else {
+        update_arf_stack(ref_map_index, ref_buffer_stack);
+      }
       stack_push(ref_buffer_stack->arf_stack, &ref_buffer_stack->arf_stack_size,
                  ref_map_index);
       break;
@@ -1024,10 +1041,13 @@
           find_unused_ref_frame(remapped_ref_idx, lst_stack, lst_stack_size);
     }
 
-    if (ref_map_index != INVALID_IDX)
+    if (ref_map_index != INVALID_IDX) {
       remapped_ref_idx[idx] = ref_map_index;
-    else
+    } else if (!gld_stack_size && arf_stack_size) {
+      remapped_ref_idx[idx] = ref_buffer_stack->arf_stack[0];
+    } else {
       remapped_ref_idx[idx] = ref_buffer_stack->gld_stack[0];
+    }
   }
 }
 
@@ -1161,9 +1181,9 @@
   // TODO(david.turner@argondesign.com): Change all the encode strategy to
   // modify frame_params instead of cm or cpi.
 
-  // Per-frame encode speed.  In theory this can vary, but things may have been
-  // written assuming speed-level will not change within a sequence, so this
-  // parameter should be used with caution.
+  // Per-frame encode speed.  In theory this can vary, but things may have
+  // been written assuming speed-level will not change within a sequence, so
+  // this parameter should be used with caution.
   frame_params.speed = oxcf->speed;
 
   // Work out some encoding parameters specific to the pass:
@@ -1199,7 +1219,8 @@
       !frame_params.show_existing_frame;
 
   av1_configure_buffer_updates(cpi, &frame_params.refresh_frame,
-                               frame_update_type, force_refresh_all);
+                               frame_update_type, frame_params.frame_type,
+                               force_refresh_all);
 
   if (!is_stat_generation_stage(cpi)) {
     const RefCntBuffer *ref_frames[INTER_REFS_PER_FRAME];
@@ -1217,9 +1238,18 @@
       ref_frames[i] = get_ref_frame_buf(cm, ref_frame_priority_order[i]);
       ref_frame_buf[i] = ref_frames[i] != NULL ? &ref_frames[i]->buf : NULL;
     }
+
     // Work out which reference frame slots may be used.
-    frame_params.ref_frame_flags = get_ref_frame_flags(
-        &cpi->sf, ref_frame_buf, ext_flags->ref_frame_flags);
+    if (av1_check_keyframe_overlay(gf_group->index, gf_group,
+                                   cpi->rc.frames_since_key)) {
+      // This is a KF overlay, it should refer to arf. However KF overlay
+      // has the same LAST and ALTREF references, so ALTREF will be disabled
+      // in function get_ref_frame_flags. Therefore setting it manually.
+      frame_params.ref_frame_flags = av1_ref_frame_flag_list[ALTREF_FRAME];
+    } else {
+      frame_params.ref_frame_flags = get_ref_frame_flags(
+          &cpi->sf, ref_frame_buf, ext_flags->ref_frame_flags);
+    }
 
     frame_params.primary_ref_frame =
         choose_primary_ref_frame(cpi, &frame_params);
@@ -1238,9 +1268,9 @@
 
   // The way frame_params->remapped_ref_idx is setup is a placeholder.
   // Currently, reference buffer assignment is done by update_ref_frame_map()
-  // which is called by high-level strategy AFTER encoding a frame.  It modifies
-  // cm->remapped_ref_idx.  If you want to use an alternative method to
-  // determine reference buffer assignment, just put your assignments into
+  // which is called by high-level strategy AFTER encoding a frame.  It
+  // modifies cm->remapped_ref_idx.  If you want to use an alternative method
+  // to determine reference buffer assignment, just put your assignments into
   // frame_params->remapped_ref_idx here and they will be used when encoding
   // this frame.  If frame_params->remapped_ref_idx is setup independently of
   // cm->remapped_ref_idx then update_ref_frame_map() will have no effect.
@@ -1277,8 +1307,9 @@
     if (!ext_flags->refresh_frame.update_pending) {
       int ref_map_index =
           av1_get_refresh_ref_frame_map(cm->current_frame.refresh_frame_flags);
-      av1_update_ref_frame_map(cpi, frame_update_type, cm->show_existing_frame,
-                               ref_map_index, &cpi->ref_buffer_stack);
+      av1_update_ref_frame_map(cpi, frame_update_type, frame_params.frame_type,
+                               cm->show_existing_frame, ref_map_index,
+                               &cpi->ref_buffer_stack);
     }
   }
 
@@ -1314,3 +1345,25 @@
 
   return AOM_CODEC_OK;
 }
+
+// Determine whether a frame is a keyframe arf. Will return 0 for fwd kf arf.
+// Note it depends on frame_since_key and gf_group, therefore should be called
+// after the gf group is defined, or otherwise a keyframe arf may still return
+// 0.
+int av1_check_keyframe_arf(int gf_index, GF_GROUP *gf_group,
+                           int frame_since_key) {
+  if (gf_index >= gf_group->size) return 0;
+  return gf_group->update_type[gf_index] == ARF_UPDATE &&
+         gf_group->update_type[gf_index + 1] == OVERLAY_UPDATE &&
+         frame_since_key == 0;
+}
+
+// Determine whether a frame is a keyframe overlay (will also return 0 for fwd
+// kf overlays).
+int av1_check_keyframe_overlay(int gf_index, GF_GROUP *gf_group,
+                               int frame_since_key) {
+  if (gf_index < 1) return 0;
+  return gf_group->update_type[gf_index - 1] == ARF_UPDATE &&
+         gf_group->update_type[gf_index] == OVERLAY_UPDATE &&
+         frame_since_key == 0;
+}
diff --git a/av1/encoder/encode_strategy.h b/av1/encoder/encode_strategy.h
index 9d5c3ce..4bafb0a 100644
--- a/av1/encoder/encode_strategy.h
+++ b/av1/encoder/encode_strategy.h
@@ -63,7 +63,8 @@
 // refresh_*_frame flags to be set, because we refresh all buffers in this case.
 void av1_configure_buffer_updates(
     AV1_COMP *const cpi, RefreshFrameFlagsInfo *const refresh_frame_flags,
-    const FRAME_UPDATE_TYPE type, int force_refresh_all);
+    const FRAME_UPDATE_TYPE type, const FRAME_TYPE frame_type,
+    int force_refresh_all);
 
 int av1_get_refresh_frame_flags(const AV1_COMP *const cpi,
                                 const EncodeFrameParams *const frame_params,
@@ -74,7 +75,8 @@
 
 void av1_update_ref_frame_map(AV1_COMP *cpi,
                               FRAME_UPDATE_TYPE frame_update_type,
-                              int show_existing_frame, int ref_map_index,
+                              FRAME_TYPE frame_type, int show_existing_frame,
+                              int ref_map_index,
                               RefBufferStack *ref_buffer_stack);
 
 void av1_get_ref_frames(AV1_COMP *const cpi, RefBufferStack *ref_buffer_stack);
@@ -82,6 +84,11 @@
 int is_forced_keyframe_pending(struct lookahead_ctx *lookahead,
                                const int up_to_index,
                                const COMPRESSOR_STAGE compressor_stage);
+
+int av1_check_keyframe_arf(int gf_index, GF_GROUP *gf_group,
+                           int frame_since_key);
+int av1_check_keyframe_overlay(int gf_index, GF_GROUP *gf_group,
+                               int frame_since_key);
 /*!\endcond */
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index c5bebc6..b829e55 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -2813,7 +2813,12 @@
           realloc_and_scale_source(cpi, cm->cur_frame->buf.y_crop_width,
                                    cm->cur_frame->buf.y_crop_height);
     }
-    ++current_frame->frame_number;
+
+    // current_frame->frame_number is incremented already for
+    // keyframe overlays.
+    if (!av1_check_keyframe_overlay(cpi->gf_group.index, &cpi->gf_group,
+                                    cpi->rc.frames_since_key))
+      ++current_frame->frame_number;
 
     return AOM_CODEC_OK;
   }
@@ -3058,10 +3063,14 @@
   // A droppable frame might not be shown but it always
   // takes a space in the gf group. Therefore, even when
   // it is not shown, we still need update the count down.
-
   if (cm->show_frame) {
-    // Don't increment frame counters if this was an altref buffer
-    // update not a real frame
+    // Don't increment frame counters if this is a key frame overlay
+    if (!av1_check_keyframe_overlay(cpi->gf_group.index, &cpi->gf_group,
+                                    cpi->rc.frames_since_key))
+      ++current_frame->frame_number;
+  } else if (av1_check_keyframe_arf(cpi->gf_group.index, &cpi->gf_group,
+                                    cpi->rc.frames_since_key)) {
+    // TODO(bohanli) Hack here: increment kf overlay before it is encoded
     ++current_frame->frame_number;
   }
 
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index 70c4450..c118a44 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -2783,7 +2783,12 @@
   av1_zero(this_frame);
   // call above fn
   if (is_stat_consumption_stage(cpi)) {
-    process_first_pass_stats(cpi, &this_frame);
+    // Do not read if it is overlay for kf arf, since kf already
+    // advanced the first pass stats pointer
+    if (!av1_check_keyframe_overlay(gf_group->index, gf_group,
+                                    rc->frames_since_key)) {
+      process_first_pass_stats(cpi, &this_frame);
+    }
   } else {
     rc->active_worst_quality = oxcf->rc_cfg.cq_level;
   }
diff --git a/av1/encoder/temporal_filter.c b/av1/encoder/temporal_filter.c
index f7abc4d..b57c1e0 100644
--- a/av1/encoder/temporal_filter.c
+++ b/av1/encoder/temporal_filter.c
@@ -1015,7 +1015,8 @@
   }
   num_frames = AOMMIN(num_frames + adjust_num, lookahead_depth + 1);
 
-  if (filter_frame_lookahead_idx == -1) {  // Key frame.
+  if (filter_frame_lookahead_idx == -1 ||
+      filter_frame_lookahead_idx == 0) {  // Key frame.
     num_before = 0;
     num_after = AOMMIN(num_frames - 1, max_after);
   } else if (filter_frame_lookahead_idx < -1) {  // Key frame in one-pass mode.
@@ -1141,7 +1142,7 @@
   }
 
   // Do filtering.
-  const int is_key_frame = (filter_frame_lookahead_idx < 0);
+  const int is_key_frame = (filter_frame_lookahead_idx <= 0);
   // Setup scaling factors. Scaling on each of the arnr frames is not
   // supported.
   // ARF is produced at the native frame size and resized when coded.
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index 9bc1d1b..6a828a8 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -970,7 +970,10 @@
         frame_update_type == INTNL_OVERLAY_UPDATE ||
         frame_update_type == OVERLAY_UPDATE;
     frame_params.frame_type =
-        frame_update_type == KF_UPDATE ? KEY_FRAME : INTER_FRAME;
+        (frame_update_type == KF_UPDATE ||
+         av1_check_keyframe_arf(gf_index, gf_group, cpi->rc.frames_since_key))
+            ? KEY_FRAME
+            : INTER_FRAME;
 
     if (frame_update_type == LF_UPDATE)
       *pframe_qindex = gf_group->q_val[gf_index];
@@ -1007,7 +1010,7 @@
         cpi, &frame_params, frame_update_type, &ref_buffer_stack);
 
     int refresh_frame_map_index = av1_get_refresh_ref_frame_map(refresh_mask);
-    av1_update_ref_frame_map(cpi, frame_update_type,
+    av1_update_ref_frame_map(cpi, frame_update_type, frame_params.frame_type,
                              frame_params.show_existing_frame,
                              refresh_frame_map_index, &ref_buffer_stack);
 
@@ -1067,7 +1070,7 @@
     int refresh_mask = av1_get_refresh_frame_flags(
         cpi, &frame_params, frame_update_type, &ref_buffer_stack);
     int refresh_frame_map_index = av1_get_refresh_ref_frame_map(refresh_mask);
-    av1_update_ref_frame_map(cpi, frame_update_type,
+    av1_update_ref_frame_map(cpi, frame_update_type, frame_params.frame_type,
                              frame_params.show_existing_frame,
                              refresh_frame_map_index, &ref_buffer_stack);
 
@@ -1116,7 +1119,8 @@
   cm->current_frame.frame_type = frame_params->frame_type;
   for (int gf_index = gf_group->index; gf_index < gf_group->size; ++gf_index) {
     av1_configure_buffer_updates(cpi, &this_frame_params.refresh_frame,
-                                 gf_group->update_type[gf_index], 0);
+                                 gf_group->update_type[gf_index],
+                                 cm->current_frame.frame_type, 0);
 
     memcpy(&cpi->refresh_frame, &this_frame_params.refresh_frame,
            sizeof(cpi->refresh_frame));
@@ -1174,15 +1178,18 @@
   }
 
   av1_configure_buffer_updates(cpi, &this_frame_params.refresh_frame,
-                               gf_group->update_type[gf_group->index], 0);
+                               gf_group->update_type[gf_group->index],
+                               frame_params->frame_type, 0);
   cm->current_frame.frame_type = frame_params->frame_type;
   cm->show_frame = frame_params->show_frame;
 
   if (cpi->common.tiles.large_scale) return 0;
   if (gf_group->max_layer_depth_allowed == 0) return 1;
+  assert(gf_group->arf_index >= 0);
 
   double beta[2] = { 0.0 };
-  for (int frame_idx = 1; frame_idx <= AOMMIN(tpl_gf_group_frames - 1, 2);
+  for (int frame_idx = gf_group->arf_index;
+       frame_idx <= AOMMIN(tpl_gf_group_frames - 1, gf_group->arf_index + 1);
        ++frame_idx) {
     TplDepFrame *tpl_frame = &tpl_data->tpl_frame[frame_idx];
     TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr;