RTC RC: Support cdef level

Bug: b/283122279
Change-Id: I8f2e97b93503f468eba38210433b1f2f1e4bbe69
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 24e8a0d..4f0d087 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -2316,7 +2316,8 @@
                     cpi->sf.lpf_sf.cdef_pick_method, cpi->td.mb.rdmult,
                     cpi->sf.rt_sf.skip_cdef_sb, cpi->oxcf.tool_cfg.cdef_control,
                     use_screen_content_model,
-                    cpi->ppi->rtc_ref.non_reference_frame);
+                    cpi->ppi->rtc_ref.non_reference_frame,
+                    cpi->rc.rtc_external_ratectrl);
 
     // Apply the filter
     if ((skip_apply_postproc_filters & SKIP_APPLY_CDEF) == 0) {
diff --git a/av1/encoder/pickcdef.c b/av1/encoder/pickcdef.c
index 22a4557..83d1517 100644
--- a/av1/encoder/pickcdef.c
+++ b/av1/encoder/pickcdef.c
@@ -728,8 +728,8 @@
 #endif
 }
 
-static void pick_cdef_from_qp(AV1_COMMON *const cm, int skip_cdef,
-                              int is_screen_content) {
+void av1_pick_cdef_from_qp(AV1_COMMON *const cm, int skip_cdef,
+                           int is_screen_content) {
   const int bd = cm->seq_params->bit_depth;
   const int q =
       av1_ac_quant_QTX(cm->quant_params.base_qindex, 0, bd) >> (bd - 8);
@@ -807,6 +807,8 @@
   const int nvfb = (mi_params->mi_rows + MI_SIZE_64X64 - 1) / MI_SIZE_64X64;
   const int nhfb = (mi_params->mi_cols + MI_SIZE_64X64 - 1) / MI_SIZE_64X64;
   MB_MODE_INFO **mbmi = mi_params->mi_grid_base;
+  // mbmi is NULL when real-time rate control library is used.
+  if (!mbmi) return;
   for (int r = 0; r < nvfb; ++r) {
     for (int c = 0; c < nhfb; ++c) {
       MB_MODE_INFO *current_mbmi = mbmi[MI_SIZE_64X64 * c];
@@ -820,7 +822,8 @@
                      const YV12_BUFFER_CONFIG *ref, AV1_COMMON *cm,
                      MACROBLOCKD *xd, CDEF_PICK_METHOD pick_method, int rdmult,
                      int skip_cdef_feature, CDEF_CONTROL cdef_control,
-                     const int is_screen_content, int non_reference_frame) {
+                     const int is_screen_content, int non_reference_frame,
+                     int rtc_ext_rc) {
   assert(cdef_control != CDEF_NONE);
   if (cdef_control == CDEF_REFERENCE && non_reference_frame) {
     CdefInfo *const cdef_info = &cm->cdef_info;
@@ -831,8 +834,12 @@
     return;
   }
 
+  if (rtc_ext_rc) {
+    av1_pick_cdef_from_qp(cm, 0, 0);
+    return;
+  }
   if (pick_method == CDEF_PICK_FROM_Q) {
-    pick_cdef_from_qp(cm, skip_cdef_feature, is_screen_content);
+    av1_pick_cdef_from_qp(cm, skip_cdef_feature, is_screen_content);
     return;
   }
   const CommonModeInfoParams *const mi_params = &cm->mi_params;
diff --git a/av1/encoder/pickcdef.h b/av1/encoder/pickcdef.h
index 548a740..bdd8233 100644
--- a/av1/encoder/pickcdef.h
+++ b/av1/encoder/pickcdef.h
@@ -235,6 +235,7 @@
  * \param[in]      is_screen_content   Whether it is screen content type
  * \param[in]      non_reference_frame Indicates if current frame is
  * non-reference
+ * \param[in]      rtc_ext_rc   Indicate if external RC is used for testing
  *
  * \remark Nothing is returned. Instead, optimal CDEF parameters are stored
  * in the \c cdef_info structure of type \ref CdefInfo inside \c cm:
@@ -252,7 +253,22 @@
                      const YV12_BUFFER_CONFIG *ref, AV1_COMMON *cm,
                      MACROBLOCKD *xd, CDEF_PICK_METHOD pick_method, int rdmult,
                      int skip_cdef_feature, CDEF_CONTROL cdef_control,
-                     const int is_screen_content, int non_reference_frame);
+                     const int is_screen_content, int non_reference_frame,
+                     int rtc_ext_rc);
+
+/*!\brief AV1 CDEF level from QP
+ *
+ * \ingroup in_loop_cdef
+ *
+ * Calculates CDEF levels from frame QP. Only used for speed 7+ with RT mode.
+ *
+ * \param[in,out]  cm                 Pointer to top level common structure
+ * \param[in]      skip_cdef          Flag to skip CDEF filtering
+ * \param[in]      is_screen_content  Flag indicating screen content
+ *
+ */
+void av1_pick_cdef_from_qp(AV1_COMMON *const cm, int skip_cdef,
+                           int is_screen_content);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/av1/ratectrl_rtc.cc b/av1/ratectrl_rtc.cc
index e1470e6..a3ec6f6 100644
--- a/av1/ratectrl_rtc.cc
+++ b/av1/ratectrl_rtc.cc
@@ -19,6 +19,7 @@
 #include "aom_mem/aom_mem.h"
 #include "av1/encoder/encoder.h"
 #include "av1/encoder/encoder_utils.h"
+#include "av1/encoder/pickcdef.h"
 #include "av1/encoder/picklpf.h"
 #include "av1/encoder/ratectrl.h"
 #include "av1/encoder/rc_utils.h"
@@ -316,6 +317,16 @@
   return lpf_level;
 }
 
+AV1CdefInfo AV1RateControlRTC::GetCdefInfo() const {
+  av1_pick_cdef_from_qp(&cpi_->common, 0, 0);
+  AV1CdefInfo cdef_level;
+  cdef_level.cdef_strength_y = cpi_->common.cdef_info.cdef_strengths[0];
+  cdef_level.cdef_strength_uv = cpi_->common.cdef_info.cdef_uv_strengths[0];
+  cdef_level.damping = cpi_->common.cdef_info.cdef_damping;
+
+  return cdef_level;
+}
+
 signed char *AV1RateControlRTC::GetCyclicRefreshMap() const {
   return cpi_->cyclic_refresh->map;
 }
diff --git a/av1/ratectrl_rtc.h b/av1/ratectrl_rtc.h
index 6c223a7..e96e210 100644
--- a/av1/ratectrl_rtc.h
+++ b/av1/ratectrl_rtc.h
@@ -71,6 +71,12 @@
   int filter_level_v;
 };
 
+struct AV1CdefInfo {
+  int cdef_strength_y;
+  int cdef_strength_uv;
+  int damping;
+};
+
 class AV1RateControlRTC {
  public:
   static std::unique_ptr<AV1RateControlRTC> Create(
@@ -82,6 +88,8 @@
   int GetQP() const;
   // GetLoopfilterLevel() needs to be called after ComputeQP()
   AV1LoopfilterLevel GetLoopfilterLevel() const;
+  // GetCdefInfo() needs to be called after ComputeQP()
+  AV1CdefInfo GetCdefInfo() const;
   signed char *GetCyclicRefreshMap() const;
   int *GetDeltaQ() const;
   void ComputeQP(const AV1FrameParamsRTC &frame_params);
diff --git a/test/ratectrl_rtc_test.cc b/test/ratectrl_rtc_test.cc
index 1357983..0d8d48f 100644
--- a/test/ratectrl_rtc_test.cc
+++ b/test/ratectrl_rtc_test.cc
@@ -150,6 +150,10 @@
     encoder->Control(AOME_GET_LOOPFILTER_LEVEL, &encoder_lpf_level);
     aom::AV1LoopfilterLevel loopfilter_level = rc_api_->GetLoopfilterLevel();
     ASSERT_EQ(loopfilter_level.filter_level[0], encoder_lpf_level);
+    aom::AV1CdefInfo cdef_level = rc_api_->GetCdefInfo();
+    int cdef_y_strengths[16];
+    encoder->Control(AV1E_GET_LUMA_CDEF_STRENGTH, cdef_y_strengths);
+    ASSERT_EQ(cdef_level.cdef_strength_y, cdef_y_strengths[0]);
   }
 
   void FramePktHook(const aom_codec_cx_pkt_t *pkt) override {