Commit 005d781f25 for aom

commit 005d781f25e620919f1e1c6418f856109c0f6028
Author: Jerome Jiang <jianj@google.com>
Date:   Wed Feb 11 15:44:18 2026 -0500

    RC: calc tpl stats for gop starting with leaf

    When using external rate control, in rare cases, the sequence ends
    with a GOP that has only 1 frame, which is also leaf frame. TPL stats
    needs to be calculated for those cases too.

    Change-Id: I777cb09eb972e3da78d64dd1046c589ac86defca

diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index 3b7973a767..f067e0219b 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -869,11 +869,18 @@ static int denoise_and_encode(AV1_COMP *const cpi, uint8_t *const dest,
     if (frame_params->frame_type != KEY_FRAME) {
       // In rare case, it's possible to have non ARF/GF update_type here.
       // We should set allow_tpl to zero in the situation
-      allow_tpl =
-          allow_tpl && (update_type == ARF_UPDATE || update_type == GF_UPDATE ||
-                        (cpi->use_ducky_encode &&
-                         cpi->ducky_encode_info.frame_info.gop_mode ==
-                             DUCKY_ENCODE_GOP_MODE_RCL));
+      bool frame_type_allow_tpl =
+          update_type == ARF_UPDATE || update_type == GF_UPDATE;
+      // When external rate control is used, sometimes the sequence ends with
+      // a GOP with only 1 frame which is a leaf frame. TPL stats needs to be
+      // calculated for it as well.
+      if (av1_use_tpl_for_extrc(&cpi->ext_ratectrl)) {
+        frame_type_allow_tpl |= update_type == LF_UPDATE;
+      }
+      allow_tpl = allow_tpl && (frame_type_allow_tpl ||
+                                (cpi->use_ducky_encode &&
+                                 cpi->ducky_encode_info.frame_info.gop_mode ==
+                                     DUCKY_ENCODE_GOP_MODE_RCL));
     }

     if (allow_tpl) {
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index 838064678d..d3699c90cf 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -1463,10 +1463,6 @@ static inline void init_mc_flow_dispenser(AV1_COMP *cpi, int frame_idx,
       gf_group->layer_depth[frame_idx] >= layer_depth_th;
 }

-static inline bool use_tpl_for_extrc(AOM_EXT_RATECTRL const *ext_rc) {
-  return ext_rc->ready && ext_rc->funcs.send_tpl_gop_stats != NULL;
-}
-
 static void tpl_store_before_propagation(AomTplBlockStats *tpl_block_stats,
                                          TplDepStats *src_stats, int mi_row,
                                          int mi_col) {
@@ -1555,7 +1551,7 @@ void av1_mc_flow_dispenser_row(AV1_COMP *cpi, TplTxfmStats *tpl_txfm_stats,
     tpl_model_store(tpl_frame->tpl_stats_ptr, mi_row, mi_col, tpl_frame->stride,
                     &tpl_stats, tpl_data->tpl_stats_block_mis_log2);

-    if (use_tpl_for_extrc(&cpi->ext_ratectrl)) {
+    if (av1_use_tpl_for_extrc(&cpi->ext_ratectrl)) {
       AomTplFrameStats *tpl_frame_stats_before_propagation =
           &cpi->extrc_tpl_gop_stats.frame_stats_list[tpl_data->frame_idx];
       AomTplBlockStats *block_stats =
@@ -2064,7 +2060,7 @@ int av1_tpl_setup_stats(AV1_COMP *cpi, int gop_eval,

   av1_init_tpl_stats(tpl_data);

-  if (use_tpl_for_extrc(&cpi->ext_ratectrl)) {
+  if (av1_use_tpl_for_extrc(&cpi->ext_ratectrl)) {
     init_tpl_stats_before_propagation(
         cpi->common.error, &cpi->extrc_tpl_gop_stats, tpl_data,
         tpl_gf_group_frames, cpi->common.width, cpi->common.height);
@@ -2135,7 +2131,7 @@ int av1_tpl_setup_stats(AV1_COMP *cpi, int gop_eval,
                              num_planes);
   }

-  if (use_tpl_for_extrc(&cpi->ext_ratectrl)) {
+  if (av1_use_tpl_for_extrc(&cpi->ext_ratectrl)) {
     // TPL stats has extra frames from next GOP. Trim those extra frames for
     // external RC.
     trim_tpl_stats(cpi->common.error, &cpi->extrc_tpl_gop_stats,
diff --git a/av1/encoder/tpl_model.h b/av1/encoder/tpl_model.h
index 8fba0cfd30..ba6fd9c3c4 100644
--- a/av1/encoder/tpl_model.h
+++ b/av1/encoder/tpl_model.h
@@ -35,6 +35,7 @@ struct TPL_INFO;

 #include "av1/common/mv.h"
 #include "av1/common/scale.h"
+#include "av1/encoder/av1_ext_ratectrl.h"
 #include "av1/encoder/block.h"
 #include "av1/encoder/lookahead.h"
 #include "av1/encoder/ratectrl.h"
@@ -415,6 +416,10 @@ typedef struct RD_COMMAND {
 void av1_read_rd_command(const char *filepath, RD_COMMAND *rd_command);
 #endif  // CONFIG_RD_COMMAND

+static inline bool av1_use_tpl_for_extrc(AOM_EXT_RATECTRL const *ext_rc) {
+  return ext_rc->ready && ext_rc->funcs.send_tpl_gop_stats != NULL;
+}
+
 /*!\brief Allocate buffers used by tpl model
  *
  * \param[in]    Top-level encode/decode structure