Introduce CONFIG_DDT_INTER experiment

This patch introduces an experiment under CONFIG_DDT_INTER flag, and
integrates it with CONFIG_IST.

Note that this is the same as CONFIG_MODE_DEP_INTER_TX in experimental
branch, but renamed as CONFIG_DDT_INTER because the transforms added
are not mode-dependent.

Change-Id: I5112c2b751e65a526c08adcc0823291d212fa20c
diff --git a/av1/common/av1_inv_txfm1d.c b/av1/common/av1_inv_txfm1d.c
index bd789a4..0e9c5a5 100644
--- a/av1/common/av1_inv_txfm1d.c
+++ b/av1/common/av1_inv_txfm1d.c
@@ -654,6 +654,47 @@
   bf1[31] = clamp_value(bf0[0] - bf0[31], stage_range[stage]);
 }
 
+#if CONFIG_DDT_INTER
+void av1_iklt4(const int32_t *input, int32_t *output, int8_t cos_bit,
+               const int8_t *stage_range) {
+  (void)cos_bit;
+  (void)stage_range;
+  for (int32_t i = 0; i < 4; i++) {
+    int32_t sum = 0;
+    for (int32_t j = 0; j < 4; j++) {
+      sum += input[j] * klt4_inter[j * 4 + i];
+    }
+    output[i] = ROUND_POWER_OF_TWO_SIGNED(sum, KLT_PREC_BITS);
+  }
+}
+
+void av1_iklt8(const int32_t *input, int32_t *output, int8_t cos_bit,
+               const int8_t *stage_range) {
+  (void)cos_bit;
+  (void)stage_range;
+  for (int32_t i = 0; i < 8; i++) {
+    int32_t sum = 0;
+    for (int32_t j = 0; j < 8; j++) {
+      sum += input[j] * klt8_inter[j * 8 + i];
+    }
+    output[i] = ROUND_POWER_OF_TWO_SIGNED(sum, KLT_PREC_BITS);
+  }
+}
+
+void av1_iklt16(const int32_t *input, int32_t *output, int8_t cos_bit,
+                const int8_t *stage_range) {
+  (void)cos_bit;
+  (void)stage_range;
+  for (int32_t i = 0; i < 16; i++) {
+    int32_t sum = 0;
+    for (int32_t j = 0; j < 16; j++) {
+      sum += input[j] * klt16_inter[j * 16 + i];
+    }
+    output[i] = ROUND_POWER_OF_TWO_SIGNED(sum, KLT_PREC_BITS);
+  }
+}
+#endif  // CONFIG_DDT_INTER
+
 void av1_iadst4(const int32_t *input, int32_t *output, int8_t cos_bit,
                 const int8_t *stage_range) {
   int bit = cos_bit;
diff --git a/av1/common/av1_inv_txfm1d.h b/av1/common/av1_inv_txfm1d.h
index 84bbfaf..31c6e09 100644
--- a/av1/common/av1_inv_txfm1d.h
+++ b/av1/common/av1_inv_txfm1d.h
@@ -15,6 +15,10 @@
 
 #include "av1/common/av1_txfm.h"
 
+#if CONFIG_DDT_INTER
+#include "av1/common/ddtx_bases.h"
+#endif  // CONFIG_DDT_INTER
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -59,6 +63,14 @@
 void av1_iidentity32_c(const int32_t *input, int32_t *output, int8_t cos_bit,
                        const int8_t *stage_range);
 
+#if CONFIG_DDT_INTER
+void av1_iklt4(const int32_t *input, int32_t *output, int8_t cos_bit,
+               const int8_t *stage_range);
+void av1_iklt8(const int32_t *input, int32_t *output, int8_t cos_bit,
+               const int8_t *stage_range);
+void av1_iklt16(const int32_t *input, int32_t *output, int8_t cos_bit,
+                const int8_t *stage_range);
+#endif  // CONFIG_DDT_INTER
 #ifdef __cplusplus
 }
 #endif
diff --git a/av1/common/av1_inv_txfm2d.c b/av1/common/av1_inv_txfm2d.c
index ff80d55..56a479c 100644
--- a/av1/common/av1_inv_txfm2d.c
+++ b/av1/common/av1_inv_txfm2d.c
@@ -125,6 +125,11 @@
 #if CONFIG_DST_32X32
     case TXFM_TYPE_ADST32: return av1_iadst32;
 #endif  // CONFIG_DST_32X32
+#if CONFIG_DDT_INTER
+    case TXFM_TYPE_DDT4: return av1_iklt4;
+    case TXFM_TYPE_DDT8: return av1_iklt8;
+    case TXFM_TYPE_DDT16: return av1_iklt16;
+#endif  // CONFIG_DDT_INTER
     case TXFM_TYPE_IDENTITY4: return av1_iidentity4_c;
     case TXFM_TYPE_IDENTITY8: return av1_iidentity8_c;
     case TXFM_TYPE_IDENTITY16: return av1_iidentity16_c;
diff --git a/av1/common/av1_txfm.c b/av1/common/av1_txfm.c
index 4c4a4c9..0fe1e7f 100644
--- a/av1/common/av1_txfm.c
+++ b/av1/common/av1_txfm.c
@@ -223,6 +223,25 @@
   }
 }
 
+#if CONFIG_DDT_INTER
+const TXFM_TYPE av1_txfm_type_ls[5][TX_TYPES_1D] = {
+  { TXFM_TYPE_DCT4, TXFM_TYPE_ADST4, TXFM_TYPE_ADST4, TXFM_TYPE_IDENTITY4,
+    TXFM_TYPE_DDT4 },
+  { TXFM_TYPE_DCT8, TXFM_TYPE_ADST8, TXFM_TYPE_ADST8, TXFM_TYPE_IDENTITY8,
+    TXFM_TYPE_DDT8 },
+  { TXFM_TYPE_DCT16, TXFM_TYPE_ADST16, TXFM_TYPE_ADST16, TXFM_TYPE_IDENTITY16,
+    TXFM_TYPE_DDT16 },
+#if CONFIG_DST_32X32
+  { TXFM_TYPE_DCT32, TXFM_TYPE_ADST32, TXFM_TYPE_ADST32, TXFM_TYPE_IDENTITY32,
+    TXFM_TYPE_ADST32 },
+#else
+  { TXFM_TYPE_DCT32, TXFM_TYPE_INVALID, TXFM_TYPE_INVALID, TXFM_TYPE_IDENTITY32,
+    TXFM_TYPE_INVALID },
+#endif
+  { TXFM_TYPE_DCT64, TXFM_TYPE_INVALID, TXFM_TYPE_INVALID, TXFM_TYPE_INVALID,
+    TXFM_TYPE_INVALID }
+};
+#else
 const TXFM_TYPE av1_txfm_type_ls[5][TX_TYPES_1D] = {
   { TXFM_TYPE_DCT4, TXFM_TYPE_ADST4, TXFM_TYPE_ADST4, TXFM_TYPE_IDENTITY4 },
   { TXFM_TYPE_DCT8, TXFM_TYPE_ADST8, TXFM_TYPE_ADST8, TXFM_TYPE_IDENTITY8 },
@@ -235,6 +254,7 @@
 #endif  // CONFIG_DST_32X32
   { TXFM_TYPE_DCT64, TXFM_TYPE_INVALID, TXFM_TYPE_INVALID, TXFM_TYPE_INVALID }
 };
+#endif  // CONFIG_DDT_INTER
 
 const int8_t av1_txfm_stage_num_list[TXFM_TYPES] = {
   4,   // TXFM_TYPE_DCT4
@@ -249,6 +269,11 @@
   1,   // TXFM_TYPE_IDENTITY8
   1,   // TXFM_TYPE_IDENTITY16
   1,   // TXFM_TYPE_IDENTITY32
+#if CONFIG_DDT_INTER
+  1,    // TXFM_TYPE_DDT4 (not used)
+  1,    // TXFM_TYPE_DDT8 (not used)
+  1,    // TXFM_TYPE_DDT16 (not used)
+#endif  // CONFIG_DDT_INTER
 #if CONFIG_DST_32X32
   1,  // TXFM_TYPE_ADST32
 #endif
diff --git a/av1/common/av1_txfm.h b/av1/common/av1_txfm.h
index ae6d8cf..5958434 100644
--- a/av1/common/av1_txfm.h
+++ b/av1/common/av1_txfm.h
@@ -45,6 +45,10 @@
 #define DST_32X32_PREC_BITS 7
 #endif  // CONFIG_DST_32X32
 
+#if CONFIG_DDT_INTER
+#define KLT_PREC_BITS 10
+#endif  // CONFIG_DDT_INTER
+
 #define MAX_TXFM_STAGE_NUM 12
 
 static const int cos_bit_min = 10;
@@ -136,6 +140,11 @@
   TXFM_TYPE_IDENTITY8,
   TXFM_TYPE_IDENTITY16,
   TXFM_TYPE_IDENTITY32,
+#if CONFIG_DDT_INTER
+  TXFM_TYPE_DDT4,
+  TXFM_TYPE_DDT8,
+  TXFM_TYPE_DDT16,  // DST type 7
+#endif              // CONFIG_DDT_INTER
 #if CONFIG_DST_32X32
   TXFM_TYPE_ADST32,
 #endif
@@ -143,6 +152,24 @@
   TXFM_TYPE_INVALID,
 } UENUM1BYTE(TXFM_TYPE);
 
+#if CONFIG_DDT_INTER
+static INLINE int idx_flip(const int txw, const int txh, const int idxr,
+                           const int idxc, const int ud_flip,
+                           const int lr_flip) {
+  if (ud_flip == 1 && lr_flip == 1) {
+    // return (txh - idxr - 1) * txw + txw - idxc - 1;
+    return (txh - idxr) * txw - idxc - 1;
+  } else if (ud_flip == 1 && lr_flip == 0) {
+    return (txh - idxr - 1) * txw + idxc;
+  } else if (ud_flip == 0 && lr_flip == 1) {
+    // return idxr * txw + txw - idxc - 1;
+    return (idxr + 1) * txw - idxc - 1;
+  } else {
+    return idxr * txw + idxc;
+  }
+}
+#endif  // CONFIG_DDT_INTER
+
 typedef struct TXFM_2D_FLIP_CFG {
   TX_SIZE tx_size;
   int ud_flip;  // flip upside down
@@ -172,22 +199,38 @@
     case H_DCT:
     case V_ADST:
     case H_ADST:
+#if CONFIG_DDT_INTER
+    case DDT_DDT:
+    case DDT_DCT:
+    case DCT_DDT:
+#endif  // CONFIG_DDT_INTER
       *ud_flip = 0;
       *lr_flip = 0;
       break;
     case FLIPADST_DCT:
     case FLIPADST_ADST:
     case V_FLIPADST:
+#if CONFIG_DDT_INTER
+    case FLIPDDT_DCT:
+    case FLIPDDT_DDT:
+#endif  // CONFIG_DDT_INTER
       *ud_flip = 1;
       *lr_flip = 0;
       break;
     case DCT_FLIPADST:
     case ADST_FLIPADST:
     case H_FLIPADST:
+#if CONFIG_DDT_INTER
+    case DCT_FLIPDDT:
+    case DDT_FLIPDDT:
+#endif  // CONFIG_DDT_INTER
       *ud_flip = 0;
       *lr_flip = 1;
       break;
     case FLIPADST_FLIPADST:
+#if CONFIG_DDT_INTER
+    case FLIPDDT_FLIPDDT:
+#endif  // CONFIG_DDT_INTER
       *ud_flip = 1;
       *lr_flip = 1;
       break;
diff --git a/av1/common/blockd.h b/av1/common/blockd.h
index ecab171..b5bf2a9 100644
--- a/av1/common/blockd.h
+++ b/av1/common/blockd.h
@@ -1271,6 +1271,35 @@
   1, 2, 5, 7, 12, 16,
 };
 
+#if CONFIG_DDT_INTER
+// Whether or not the primary transform is a ddtx
+static INLINE int has_ddtx(TX_TYPE tx_type) {
+  return tx_type >= DDT_DDT && tx_type <= DDT_FLIPDDT;
+}
+
+static INLINE TX_TYPE ddtx_to_trigtx(TX_TYPE tx_type) {
+  switch (tx_type) {
+    case DDT_DDT: return ADST_ADST;
+    case DDT_DCT: return ADST_DCT;
+    case DCT_DDT: return DCT_ADST;
+    case FLIPDDT_FLIPDDT: return FLIPADST_FLIPADST;
+    case FLIPDDT_DCT: return FLIPADST_DCT;
+    case DCT_FLIPDDT: return DCT_FLIPADST;
+    case FLIPDDT_DDT: return FLIPADST_ADST;
+    case DDT_FLIPDDT: return ADST_FLIPADST;
+    default: assert(0); return 0;
+  }
+}
+
+static const int av1_ext_tx_used[EXT_TX_SET_TYPES][TX_TYPES] = {
+  { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+};
+#else
 static const int av1_ext_tx_used[EXT_TX_SET_TYPES][TX_TYPES] = {
   { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
   { 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
@@ -1279,6 +1308,7 @@
   { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
   { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
 };
+#endif  // CONFIG_DDT_INTER
 
 static const uint16_t av1_reduced_intra_tx_used_flag[INTRA_MODES] = {
   0x080F,  // DC_PRED:       0000 1000 0000 1111
@@ -1307,7 +1337,11 @@
 
 static const TxSetType av1_ext_tx_set_lookup[2][2] = {
   { EXT_TX_SET_DTT4_IDTX_1DDCT, EXT_TX_SET_DTT4_IDTX },
+#if CONFIG_DDT_INTER
+  { EXT_TX_SET_ALL24, EXT_TX_SET_DTT9_IDTX_1DDCT },
+#else
   { EXT_TX_SET_ALL16, EXT_TX_SET_DTT9_IDTX_1DDCT },
+#endif  // CONFIG_DDT_INTER
 };
 
 #if CONFIG_DST_32X32
@@ -1548,24 +1582,44 @@
  *
  */
 static INLINE void disable_secondary_tx_type(TX_TYPE *tx_type) {
+#if CONFIG_DDT_INTER
+  // Mask both secondary tx and ddtx flag
+  *tx_type &= (*tx_type & 0x40) ? 0x1f : 0x0f;
+#else
   *tx_type &= 0x0f;
+#endif  // CONFIG_DDT_INTER
 }
 /*
  * This function masks primary transform type used by the transform block
  */
 static INLINE void disable_primary_tx_type(TX_TYPE *tx_type) {
+#if CONFIG_DDT_INTER
+  *tx_type &= 0x30;  // Set the 6th bit to zero and apply masking
+#else
   *tx_type &= 0xf0;
+#endif
 }
 /*
- * This function returns primary transform type used by the transform block
+ * This function returns primary transform type used by the transform block.
+ * If data-driven transform is enabled (CONFIG_DDT_INTER), bit 6 of
+ * tx_type stores is_ddtx. If it is 1, then take 5 bits (ddtx can be from 16 to
+ * 23). Otherwise, take 4 bits (primary tx ranges from 0 to 16).
  */
 static INLINE TX_TYPE get_primary_tx_type(TX_TYPE tx_type) {
+#if CONFIG_DDT_INTER
+  return (tx_type & 0x40) ? (tx_type & 0x1f) : (tx_type & 0x0f);
+#else
   return tx_type & 0x0f;
+#endif  // CONFIG_DDT_INTER
 }
 /*
  * This function returns secondary transform type used by the transform block
  */
 static INLINE TX_TYPE get_secondary_tx_type(TX_TYPE tx_type) {
+#if CONFIG_DDT_INTER
+  if (tx_type & 0x40) return 0;
+  tx_type &= 0x3f;  // Set the 6th bit to zero
+#endif              // CONFIG_DDT_INTER
   return (tx_type >> 4);
 }
 /*
@@ -1647,6 +1701,12 @@
       // Secondary transforms are disabled for chroma
       disable_secondary_tx_type(&tx_type);
 #endif  // CONFIG_IST
+#if CONFIG_DDT_INTER
+      // In DDT_INTER, transform pruning is not applied to ddtx, which causes
+      // a mismatch if uv_tx_type has ddtx in it. In this case, we replace ddtx
+      // by adst as a workaround.
+      if (has_ddtx(tx_type)) tx_type = ddtx_to_trigtx(tx_type);
+#endif  // CONFIG_DDT_INTER
     } else {
       // In intra mode, uv planes don't share the same prediction mode as y
       // plane, so the tx_type should not be shared
diff --git a/av1/common/common_data.h b/av1/common/common_data.h
index abe5cbd..79be189 100644
--- a/av1/common/common_data.h
+++ b/av1/common/common_data.h
@@ -157,12 +157,20 @@
   DCT_1D,      ADST_1D, DCT_1D,      ADST_1D,
   FLIPADST_1D, DCT_1D,  FLIPADST_1D, ADST_1D, FLIPADST_1D, IDTX_1D,
   DCT_1D,      IDTX_1D, ADST_1D,     IDTX_1D, FLIPADST_1D, IDTX_1D,
+#if CONFIG_DDT_INTER
+  DDT1_1D,    DDT1_1D, DCT_1D,      DDT1_1D, DDT1_1D,   DCT_1D,
+  DDT1_1D,    DDT1_1D,
+#endif  // CONFIG_DDT_INTER
 };
 
 static const TX_TYPE_1D htx_tab[TX_TYPES] = {
   DCT_1D,  DCT_1D,      ADST_1D,     ADST_1D,
   DCT_1D,  FLIPADST_1D, FLIPADST_1D, FLIPADST_1D, ADST_1D, IDTX_1D,
   IDTX_1D, DCT_1D,      IDTX_1D,     ADST_1D,     IDTX_1D, FLIPADST_1D,
+#if CONFIG_DDT_INTER
+  DDT1_1D, DCT_1D,      DDT1_1D,    DDT1_1D,    DCT_1D,  DDT1_1D,
+  DDT1_1D, DDT1_1D,
+#endif  // CONFIG_DDT_INTER
 };
 
 #define TXSIZE_CAT_INVALID (-1)
diff --git a/av1/common/ddtx_bases.h b/av1/common/ddtx_bases.h
new file mode 100644
index 0000000..8423f05
--- /dev/null
+++ b/av1/common/ddtx_bases.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2021, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 3-Clause Clear License
+ * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
+ * License was not distributed with this source code in the LICENSE file, you
+ * can obtain it at aomedia.org/license/software-license/bsd-3-c-c/.  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
+ * aomedia.org/license/patent-license/.
+ */
+
+#ifndef DDT_BASES_H_
+#define DDT_BASES_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Inter KLTs
+// Quantized with 2^10 and scale factor 1.4142135623730951
+static const int32_t klt4_inter[16] = {
+  -25, 17,   668,  1284, -60,  370,  1238, -651,
+  505, 1317, -293, 145,  1356, -474, 176,  -59,
+};
+
+// Quantized with 2^10 and scale factor 2
+static const int32_t klt8_inter[64] = {
+  33,   35,   28,    89,   402,   1017, 1404, 1009, 0,    -34,  -10,
+  415,  1185, 1090,  -330, -1148, 0,    1,    365,  1211, 968,  -680,
+  -549, 947,  -63,   -466, -1272, -935, 652,  158,  -719, 717,  911,
+  1374, 590,  -619,  89,   414,   -639, 399,  1342, 295,  -945, 276,
+  338,  -724, 709,   -443, 1030,  -859, -116, 707,  -894, 807,  -587,
+  295,  705,  -1124, 1091, -845,  587,  -370, 204,  -85,
+};
+
+// Quantized with 2^10 and scale factor 2.8284271247461903
+static const int32_t klt16_inter[256] = {
+  325,   377,   419,  468,   526,  597,   684,   785,   860,   910,   951,
+  968,   947,   878,  765,   607,  348,   430,   500,   576,   656,   731,
+  794,   815,   713,  441,   32,   -462,  -912,  -1174, -1159, -879,  627,
+  744,   781,   778,  711,   557,  293,   -87,   -521,  -926,  -1138, -963,
+  -356,  433,   929,  888,   634,  743,   725,   625,   417,   84,    -389,
+  -887,  -1030, -581, 296,   1047, 999,   83,    -866,  -1031, 547,   605,
+  487,   245,   -88,  -475,  -829, -864,  -237,  803,   1170,  204,   -1103,
+  -1018, 352,   1127, 825,   836,  515,   -13,   -620,  -1048, -878,  41,
+  985,   797,   -430, -942,  146,  969,   63,    -921,  739,   660,   180,
+  -436,  -919,  -797, 167,   1068, 458,   -946,  -655,  853,   538,   -950,
+  -441,  942,   945,  643,   -293, -1091, -910,  308,   1161,  272,   -957,
+  -265,  865,   -49,  -786,  474,  575,   -741,  977,   297,   -853,  -1024,
+  160,   1054,  135,  -967,  73,   888,   -522,  -560,  884,   -164,  -831,
+  776,   1055,  -136, -1213, -270, 1092,  292,   -1005, 64,    828,   -660,
+  -217,  833,   -586, -213,  861,  -655,  951,   -596,  -952,  721,   666,
+  -934,  -115,  933,  -714,  -208, 876,   -794,  117,   592,   -927,  573,
+  858,   -899,  -368, 1040,  -391, -668,  960,   -363,  -451,  914,   -768,
+  176,   496,   -929, 966,   -521, 672,   -948,  171,   719,   -927,  341,
+  441,   -903,  848,  -399,  -200, 720,   -1025, 1055,  -858,  412,   531,
+  -912,  601,   97,   -681,  760,  -391,  -170,  673,   -1016, 1145,  -1099,
+  942,   -721,  478,  -204,  549,  -1012, 892,   -345,  -384,  947,   -1202,
+  1186,  -1021, 792,  -583,  397,  -248,  139,   -69,   20,    452,   -1009,
+  1334,  -1426, 1286, -1010, 681,  -398,  198,   -73,   -5,    48,    -64,
+  60,    -49,   24,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // DDT_BASES_H
diff --git a/av1/common/entropy.c b/av1/common/entropy.c
index 2553155..8bc639f 100644
--- a/av1/common/entropy.c
+++ b/av1/common/entropy.c
@@ -269,6 +269,19 @@
   for (int i = 0; i < FRAME_LF_COUNT; i++) {
     RESET_CDF_COUNTER(fc->delta_lf_multi_cdf[i], DELTA_LF_PROBS + 1);
   }
+#if CONFIG_DDT_INTER
+  RESET_CDF_COUNTER(fc->use_ddtx_inter_cdf, 2);
+  RESET_CDF_COUNTER_STRIDE(fc->ddtx_type_inter_cdf, 8, CDF_SIZE(DDT_TYPES));
+  RESET_CDF_COUNTER_STRIDE(fc->intra_ext_tx_cdf[1], INTRA_TX_SET1,
+                           CDF_SIZE(TX_TYPES_TRIG));
+  RESET_CDF_COUNTER_STRIDE(fc->intra_ext_tx_cdf[2], INTRA_TX_SET2,
+                           CDF_SIZE(TX_TYPES_TRIG));
+  RESET_CDF_COUNTER_STRIDE(fc->inter_ext_tx_cdf[1], 16,
+                           CDF_SIZE(TX_TYPES_TRIG));
+  RESET_CDF_COUNTER_STRIDE(fc->inter_ext_tx_cdf[2], 12,
+                           CDF_SIZE(TX_TYPES_TRIG));
+  RESET_CDF_COUNTER_STRIDE(fc->inter_ext_tx_cdf[3], 2, CDF_SIZE(TX_TYPES_TRIG));
+#else
   RESET_CDF_COUNTER_STRIDE(fc->intra_ext_tx_cdf[1], INTRA_TX_SET1,
                            CDF_SIZE(TX_TYPES));
   RESET_CDF_COUNTER_STRIDE(fc->intra_ext_tx_cdf[2], INTRA_TX_SET2,
@@ -276,6 +289,7 @@
   RESET_CDF_COUNTER_STRIDE(fc->inter_ext_tx_cdf[1], 16, CDF_SIZE(TX_TYPES));
   RESET_CDF_COUNTER_STRIDE(fc->inter_ext_tx_cdf[2], 12, CDF_SIZE(TX_TYPES));
   RESET_CDF_COUNTER_STRIDE(fc->inter_ext_tx_cdf[3], 2, CDF_SIZE(TX_TYPES));
+#endif  // CONFIG_DDT_INTER
   RESET_CDF_COUNTER(fc->cfl_sign_cdf, CFL_JOINT_SIGNS);
   RESET_CDF_COUNTER(fc->cfl_alpha_cdf, CFL_ALPHABET_SIZE);
 #if CONFIG_IST
diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c
index 3c17d18..f99767b 100644
--- a/av1/common/entropymode.c
+++ b/av1/common/entropymode.c
@@ -300,8 +300,13 @@
       }
     };
 
+#if CONFIG_DDT_INTER
+static const aom_cdf_prob default_intra_ext_tx_cdf
+    [EXT_TX_SETS_INTRA][EXT_TX_SIZES][INTRA_MODES][CDF_SIZE(TX_TYPES_TRIG)] = {
+#else
 static const aom_cdf_prob default_intra_ext_tx_cdf
     [EXT_TX_SETS_INTRA][EXT_TX_SIZES][INTRA_MODES][CDF_SIZE(TX_TYPES)] = {
+#endif  // CONFIG_DDT_INTER
       {
           {
               { 0 },
@@ -617,9 +622,15 @@
 #endif  // CONFIG_FORWARDSKIP
     };
 
+#if CONFIG_DDT_INTER
+static const aom_cdf_prob
+    default_inter_ext_tx_cdf[EXT_TX_SETS_INTER][EXT_TX_SIZES][CDF_SIZE(
+        TX_TYPES_TRIG)] = {
+#else
 static const aom_cdf_prob
     default_inter_ext_tx_cdf[EXT_TX_SETS_INTER][EXT_TX_SIZES][CDF_SIZE(
         TX_TYPES)] = {
+#endif  // CONFIG_DDT_INTER
       {
           { 0 },
           { 0 },
@@ -654,6 +665,24 @@
       },
     };
 
+#if CONFIG_DDT_INTER
+static const aom_cdf_prob
+    default_ddtx_type_inter_cdf[EXT_TX_SIZES][CDF_SIZE(DDT_TYPES)] = {
+      { AOM_CDF8(4096, 8192, 12288, 16384, 20480, 24576, 28672) },
+      { AOM_CDF8(4096, 8192, 12288, 16384, 20480, 24576, 28672) },
+      { AOM_CDF8(4096, 8192, 12288, 16384, 20480, 24576, 28672) },
+      { AOM_CDF8(4096, 8192, 12288, 16384, 20480, 24576, 28672) },
+    };
+
+static const aom_cdf_prob default_use_ddtx_inter_cdf[EXT_TX_SIZES]
+                                                    [CDF_SIZE(2)] = {
+                                                      { AOM_CDF2(16384) },
+                                                      { AOM_CDF2(16384) },
+                                                      { AOM_CDF2(16384) },
+                                                      { AOM_CDF2(16384) },
+                                                    };
+#endif  // CONFIG_DDT_INTER
+
 static const aom_cdf_prob default_cfl_sign_cdf[CDF_SIZE(CFL_JOINT_SIGNS)] = {
   AOM_CDF8(1418, 2123, 13340, 18405, 26972, 28343, 32294)
 };
@@ -1876,6 +1905,10 @@
   av1_copy(fc->partition_cdf, default_partition_cdf);
   av1_copy(fc->intra_ext_tx_cdf, default_intra_ext_tx_cdf);
   av1_copy(fc->inter_ext_tx_cdf, default_inter_ext_tx_cdf);
+#if CONFIG_DDT_INTER
+  av1_copy(fc->ddtx_type_inter_cdf, default_ddtx_type_inter_cdf);
+  av1_copy(fc->use_ddtx_inter_cdf, default_use_ddtx_inter_cdf);
+#endif  // CONFIG_DDT_INTER
   av1_copy(fc->skip_mode_cdfs, default_skip_mode_cdfs);
   av1_copy(fc->skip_txfm_cdfs, default_skip_txfm_cdfs);
 #if CONFIG_CONTEXT_DERIVATION
diff --git a/av1/common/entropymode.h b/av1/common/entropymode.h
index 51a4768..2955367 100644
--- a/av1/common/entropymode.h
+++ b/av1/common/entropymode.h
@@ -254,10 +254,19 @@
   aom_cdf_prob delta_q_cdf[CDF_SIZE(DELTA_Q_PROBS + 1)];
   aom_cdf_prob delta_lf_multi_cdf[FRAME_LF_COUNT][CDF_SIZE(DELTA_LF_PROBS + 1)];
   aom_cdf_prob delta_lf_cdf[CDF_SIZE(DELTA_LF_PROBS + 1)];
+#if CONFIG_DDT_INTER
+  aom_cdf_prob ddtx_type_inter_cdf[EXT_TX_SIZES][CDF_SIZE(DDT_TYPES)];
+  aom_cdf_prob use_ddtx_inter_cdf[EXT_TX_SIZES][CDF_SIZE(2)];
+  aom_cdf_prob intra_ext_tx_cdf[EXT_TX_SETS_INTRA][EXT_TX_SIZES][INTRA_MODES]
+                               [CDF_SIZE(TX_TYPES_TRIG)];
+  aom_cdf_prob inter_ext_tx_cdf[EXT_TX_SETS_INTER][EXT_TX_SIZES]
+                               [CDF_SIZE(TX_TYPES_TRIG)];
+#else
   aom_cdf_prob intra_ext_tx_cdf[EXT_TX_SETS_INTRA][EXT_TX_SIZES][INTRA_MODES]
                                [CDF_SIZE(TX_TYPES)];
   aom_cdf_prob inter_ext_tx_cdf[EXT_TX_SETS_INTER][EXT_TX_SIZES]
                                [CDF_SIZE(TX_TYPES)];
+#endif  // CONFIG_DDT_INTER
   aom_cdf_prob cfl_sign_cdf[CDF_SIZE(CFL_JOINT_SIGNS)];
   aom_cdf_prob cfl_alpha_cdf[CFL_ALPHA_CONTEXTS][CDF_SIZE(CFL_ALPHABET_SIZE)];
 #if CONFIG_IST
@@ -286,7 +295,11 @@
 };
 #endif  // CONFIG_FORWARDSKIP
 
+#if CONFIG_DDT_INTER
+static const int av1_ext_tx_ind[EXT_TX_SET_TYPES][TX_TYPES_TRIG] = {
+#else
 static const int av1_ext_tx_ind[EXT_TX_SET_TYPES][TX_TYPES] = {
+#endif  // CONFIG_DDT_INTER
   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
   { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
   { 1, 3, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
@@ -295,7 +308,11 @@
   { 7, 8, 9, 12, 10, 11, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6 },
 };
 
+#if CONFIG_DDT_INTER
+static const int av1_ext_tx_inv[EXT_TX_SET_TYPES][TX_TYPES_TRIG] = {
+#else
 static const int av1_ext_tx_inv[EXT_TX_SET_TYPES][TX_TYPES] = {
+#endif  // CONFIG_DDT_INTER
   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
   { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
   { 9, 0, 3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
diff --git a/av1/common/enums.h b/av1/common/enums.h
index f84ea5a..f2b097c 100644
--- a/av1/common/enums.h
+++ b/av1/common/enums.h
@@ -362,6 +362,9 @@
   ADST_1D,
   FLIPADST_1D,
   IDTX_1D,
+#if CONFIG_DDT_INTER
+  DDT1_1D,
+#endif  // CONFIG_DDT_INTER
   TX_TYPES_1D,
 } UENUM1BYTE(TX_TYPE_1D);
 
@@ -382,8 +385,22 @@
   H_ADST,             // Identity in vertical, ADST in horizontal
   V_FLIPADST,         // FLIPADST in vertical, identity in horizontal
   H_FLIPADST,         // Identity in vertical, FLIPADST in horizontal
+#if CONFIG_DDT_INTER
+  DDT_DDT,          // DDT in both horizontal and vertical
+  DDT_DCT,          // DDT in vertical, DCT in horizontal
+  DCT_DDT,          // DCT in vertical, DDT in horizontal
+  FLIPDDT_FLIPDDT,  // flipped DDT in both horizontal and vertical
+  FLIPDDT_DCT,      // flipped DDT in vertical, DCT in horizontal
+  DCT_FLIPDDT,      // DCT in vertical, flipped DDT in horizontal
+  FLIPDDT_DDT,      // flipped DDT in vertical, DDT in horizontal
+  DDT_FLIPDDT,      // DDT in vertical, flipped DDT in horizontal
+#endif              // CONFIG_DDT_INTER
   TX_TYPES,
-  DCT_ADST_TX_MASK = 0x000F,  // Either DCT or ADST in each direction
+#if CONFIG_DDT_INTER
+  TX_TYPES_TRIG = DDT_DDT,               // Trignometric transforms (16)
+  DDT_TYPES = TX_TYPES - TX_TYPES_TRIG,  // data-driven transforms (8)
+#endif                                   // CONFIG_DDT_INTER
+  DCT_ADST_TX_MASK = 0x000F,             // Either DCT or ADST in each direction
 } UENUM1BYTE(TX_TYPE);
 
 enum {
@@ -409,8 +426,14 @@
   EXT_TX_SET_DTT4_IDTX_1DDCT,
   // Discrete Trig transforms w/ flip (9) + Identity (1) + 1D Hor/Ver DCT (2)
   EXT_TX_SET_DTT9_IDTX_1DDCT,
+#if CONFIG_DDT_INTER
+  // Discrete Trig transforms w/ flip (9) + Identity (1) + 1D Hor/Ver (6)
+  //  + DCT w/ 2 DDTs (4) + 2 DDTs (4)
+  EXT_TX_SET_ALL24,
+#else
   // Discrete Trig transforms w/ flip (9) + Identity (1) + 1D Hor/Ver (6)
   EXT_TX_SET_ALL16,
+#endif  // CONFIG_DDT_INTER
   EXT_TX_SET_TYPES
 } UENUM1BYTE(TxSetType);
 
diff --git a/av1/common/idct.c b/av1/common/idct.c
index 659bb0b..7f97bf6 100644
--- a/av1/common/idct.c
+++ b/av1/common/idct.c
@@ -354,7 +354,9 @@
   av1_inv_stxfm(dqcoeff, &txfm_param);
 #endif
 
-#if CONFIG_DST_32X32
+#if CONFIG_DDT_INTER
+  av1_highbd_inv_txfm_add_c(dqcoeff, dst, stride, &txfm_param);
+#elif CONFIG_DST_32X32
   if ((tx_size_wide[tx_size] == 16 || tx_size_high[tx_size] == 16 ||
        tx_size_wide[tx_size] == 32 || tx_size_high[tx_size] == 32) &&
       allowed_tx_mask)
@@ -369,7 +371,7 @@
     av1_highbd_inv_txfm_add(dqcoeff, dst, stride, &txfm_param);
 #else
   av1_highbd_inv_txfm_add(dqcoeff, dst, stride, &txfm_param);
-#endif  // CONFIG_DST7_16X16 && CONFIG_DST_32X32
+#endif  // CONFIG_DDT_INTER
 }
 
 // Inverse secondary transform
diff --git a/av1/common/quant_common.c b/av1/common/quant_common.c
index 8a961c2..3f1c6d5 100644
--- a/av1/common/quant_common.c
+++ b/av1/common/quant_common.c
@@ -244,13 +244,18 @@
 
 // Returns true if the tx_type corresponds to non-identity transform in both
 // horizontal and vertical directions.
-#if CONFIG_IST
 static INLINE bool is_2d_transform(TX_TYPE tx_type) {
+#if CONFIG_DDT_INTER && CONFIG_IST
+  return (get_primary_tx_type(tx_type) < IDTX ||
+          get_primary_tx_type(tx_type) >= DDT_DDT);
+#elif CONFIG_DDT_INTER
+  return (tx_type < IDTX || tx_type >= DDT_DDT);
+#elif CONFIG_IST
   return (get_primary_tx_type(tx_type) < IDTX);
-}
 #else
-static INLINE bool is_2d_transform(TX_TYPE tx_type) { return (tx_type < IDTX); }
+  return tx_type < IDTX;
 #endif
+}
 
 const qm_val_t *av1_get_iqmatrix(const CommonQuantParams *quant_params,
                                  const MACROBLOCKD *xd, int plane,
diff --git a/av1/common/scan.c b/av1/common/scan.c
index 476ec48..40c80ee 100644
--- a/av1/common/scan.c
+++ b/av1/common/scan.c
@@ -1693,6 +1693,16 @@
       { mcol_scan_4x4, av1_mcol_iscan_4x4 },
       { mrow_scan_4x4, av1_mrow_iscan_4x4 },
       { mcol_scan_4x4, av1_mcol_iscan_4x4 },
+#if CONFIG_DDT_INTER
+      { default_scan_4x4, av1_default_iscan_4x4 },
+      { default_scan_4x4, av1_default_iscan_4x4 },
+      { default_scan_4x4, av1_default_iscan_4x4 },
+      { default_scan_4x4, av1_default_iscan_4x4 },
+      { default_scan_4x4, av1_default_iscan_4x4 },
+      { default_scan_4x4, av1_default_iscan_4x4 },
+      { default_scan_4x4, av1_default_iscan_4x4 },
+      { default_scan_4x4, av1_default_iscan_4x4 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_8X8
@@ -1712,6 +1722,16 @@
       { mcol_scan_8x8, av1_mcol_iscan_8x8 },
       { mrow_scan_8x8, av1_mrow_iscan_8x8 },
       { mcol_scan_8x8, av1_mcol_iscan_8x8 },
+#if CONFIG_DDT_INTER
+      { default_scan_8x8, av1_default_iscan_8x8 },
+      { default_scan_8x8, av1_default_iscan_8x8 },
+      { default_scan_8x8, av1_default_iscan_8x8 },
+      { default_scan_8x8, av1_default_iscan_8x8 },
+      { default_scan_8x8, av1_default_iscan_8x8 },
+      { default_scan_8x8, av1_default_iscan_8x8 },
+      { default_scan_8x8, av1_default_iscan_8x8 },
+      { default_scan_8x8, av1_default_iscan_8x8 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_16X16
@@ -1731,6 +1751,16 @@
       { mcol_scan_16x16, av1_mcol_iscan_16x16 },
       { mrow_scan_16x16, av1_mrow_iscan_16x16 },
       { mcol_scan_16x16, av1_mcol_iscan_16x16 },
+#if CONFIG_DDT_INTER
+      { default_scan_16x16, av1_default_iscan_16x16 },
+      { default_scan_16x16, av1_default_iscan_16x16 },
+      { default_scan_16x16, av1_default_iscan_16x16 },
+      { default_scan_16x16, av1_default_iscan_16x16 },
+      { default_scan_16x16, av1_default_iscan_16x16 },
+      { default_scan_16x16, av1_default_iscan_16x16 },
+      { default_scan_16x16, av1_default_iscan_16x16 },
+      { default_scan_16x16, av1_default_iscan_16x16 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_32X32
@@ -1750,6 +1780,16 @@
       { mcol_scan_32x32, av1_mcol_iscan_32x32 },
       { mrow_scan_32x32, av1_mrow_iscan_32x32 },
       { mcol_scan_32x32, av1_mcol_iscan_32x32 },
+#if CONFIG_DDT_INTER
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_64X64
@@ -1771,6 +1811,16 @@
       { mcol_scan_32x32, av1_mcol_iscan_32x32 },
       { mrow_scan_32x32, av1_mrow_iscan_32x32 },
       { mcol_scan_32x32, av1_mcol_iscan_32x32 },
+#if CONFIG_DDT_INTER
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_4X8
@@ -1790,6 +1840,16 @@
       { mcol_scan_4x8, av1_mcol_iscan_4x8 },
       { mrow_scan_4x8, av1_mrow_iscan_4x8 },
       { mcol_scan_4x8, av1_mcol_iscan_4x8 },
+#if CONFIG_DDT_INTER
+      { default_scan_4x8, av1_default_iscan_4x8 },
+      { default_scan_4x8, av1_default_iscan_4x8 },
+      { default_scan_4x8, av1_default_iscan_4x8 },
+      { default_scan_4x8, av1_default_iscan_4x8 },
+      { default_scan_4x8, av1_default_iscan_4x8 },
+      { default_scan_4x8, av1_default_iscan_4x8 },
+      { default_scan_4x8, av1_default_iscan_4x8 },
+      { default_scan_4x8, av1_default_iscan_4x8 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_8X4
@@ -1809,6 +1869,16 @@
       { mcol_scan_8x4, av1_mcol_iscan_8x4 },
       { mrow_scan_8x4, av1_mrow_iscan_8x4 },
       { mcol_scan_8x4, av1_mcol_iscan_8x4 },
+#if CONFIG_DDT_INTER
+      { default_scan_8x4, av1_default_iscan_8x4 },
+      { default_scan_8x4, av1_default_iscan_8x4 },
+      { default_scan_8x4, av1_default_iscan_8x4 },
+      { default_scan_8x4, av1_default_iscan_8x4 },
+      { default_scan_8x4, av1_default_iscan_8x4 },
+      { default_scan_8x4, av1_default_iscan_8x4 },
+      { default_scan_8x4, av1_default_iscan_8x4 },
+      { default_scan_8x4, av1_default_iscan_8x4 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_8X16
@@ -1828,6 +1898,16 @@
       { mcol_scan_8x16, av1_mcol_iscan_8x16 },
       { mrow_scan_8x16, av1_mrow_iscan_8x16 },
       { mcol_scan_8x16, av1_mcol_iscan_8x16 },
+#if CONFIG_DDT_INTER
+      { default_scan_8x16, av1_default_iscan_8x16 },
+      { default_scan_8x16, av1_default_iscan_8x16 },
+      { default_scan_8x16, av1_default_iscan_8x16 },
+      { default_scan_8x16, av1_default_iscan_8x16 },
+      { default_scan_8x16, av1_default_iscan_8x16 },
+      { default_scan_8x16, av1_default_iscan_8x16 },
+      { default_scan_8x16, av1_default_iscan_8x16 },
+      { default_scan_8x16, av1_default_iscan_8x16 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_16X8
@@ -1847,6 +1927,16 @@
       { mcol_scan_16x8, av1_mcol_iscan_16x8 },
       { mrow_scan_16x8, av1_mrow_iscan_16x8 },
       { mcol_scan_16x8, av1_mcol_iscan_16x8 },
+#if CONFIG_DDT_INTER
+      { default_scan_16x8, av1_default_iscan_16x8 },
+      { default_scan_16x8, av1_default_iscan_16x8 },
+      { default_scan_16x8, av1_default_iscan_16x8 },
+      { default_scan_16x8, av1_default_iscan_16x8 },
+      { default_scan_16x8, av1_default_iscan_16x8 },
+      { default_scan_16x8, av1_default_iscan_16x8 },
+      { default_scan_16x8, av1_default_iscan_16x8 },
+      { default_scan_16x8, av1_default_iscan_16x8 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_16X32
@@ -1866,6 +1956,16 @@
       { mcol_scan_16x32, av1_mcol_iscan_16x32 },
       { mrow_scan_16x32, av1_mrow_iscan_16x32 },
       { mcol_scan_16x32, av1_mcol_iscan_16x32 },
+#if CONFIG_DDT_INTER
+      { default_scan_16x32, av1_default_iscan_16x32 },
+      { default_scan_16x32, av1_default_iscan_16x32 },
+      { default_scan_16x32, av1_default_iscan_16x32 },
+      { default_scan_16x32, av1_default_iscan_16x32 },
+      { default_scan_16x32, av1_default_iscan_16x32 },
+      { default_scan_16x32, av1_default_iscan_16x32 },
+      { default_scan_16x32, av1_default_iscan_16x32 },
+      { default_scan_16x32, av1_default_iscan_16x32 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_32X16
@@ -1885,6 +1985,16 @@
       { mcol_scan_32x16, av1_mcol_iscan_32x16 },
       { mrow_scan_32x16, av1_mrow_iscan_32x16 },
       { mcol_scan_32x16, av1_mcol_iscan_32x16 },
+#if CONFIG_DDT_INTER
+      { default_scan_32x16, av1_default_iscan_32x16 },
+      { default_scan_32x16, av1_default_iscan_32x16 },
+      { default_scan_32x16, av1_default_iscan_32x16 },
+      { default_scan_32x16, av1_default_iscan_32x16 },
+      { default_scan_32x16, av1_default_iscan_32x16 },
+      { default_scan_32x16, av1_default_iscan_32x16 },
+      { default_scan_32x16, av1_default_iscan_32x16 },
+      { default_scan_32x16, av1_default_iscan_32x16 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_32X64
@@ -1906,6 +2016,16 @@
       { mcol_scan_32x32, av1_mcol_iscan_32x32 },
       { mrow_scan_32x32, av1_mrow_iscan_32x32 },
       { mcol_scan_32x32, av1_mcol_iscan_32x32 },
+#if CONFIG_DDT_INTER
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_64X32
@@ -1927,6 +2047,16 @@
       { mcol_scan_32x32, av1_mcol_iscan_32x32 },
       { mrow_scan_32x32, av1_mrow_iscan_32x32 },
       { mcol_scan_32x32, av1_mcol_iscan_32x32 },
+#if CONFIG_DDT_INTER
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+      { default_scan_32x32, av1_default_iscan_32x32 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_4X16
@@ -1946,6 +2076,16 @@
       { mcol_scan_4x16, av1_mcol_iscan_4x16 },
       { mrow_scan_4x16, av1_mrow_iscan_4x16 },
       { mcol_scan_4x16, av1_mcol_iscan_4x16 },
+#if CONFIG_DDT_INTER
+      { default_scan_4x16, av1_default_iscan_4x16 },
+      { default_scan_4x16, av1_default_iscan_4x16 },
+      { default_scan_4x16, av1_default_iscan_4x16 },
+      { default_scan_4x16, av1_default_iscan_4x16 },
+      { default_scan_4x16, av1_default_iscan_4x16 },
+      { default_scan_4x16, av1_default_iscan_4x16 },
+      { default_scan_4x16, av1_default_iscan_4x16 },
+      { default_scan_4x16, av1_default_iscan_4x16 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_16X4
@@ -1965,6 +2105,16 @@
       { mcol_scan_16x4, av1_mcol_iscan_16x4 },
       { mrow_scan_16x4, av1_mrow_iscan_16x4 },
       { mcol_scan_16x4, av1_mcol_iscan_16x4 },
+#if CONFIG_DDT_INTER
+      { default_scan_16x4, av1_default_iscan_16x4 },
+      { default_scan_16x4, av1_default_iscan_16x4 },
+      { default_scan_16x4, av1_default_iscan_16x4 },
+      { default_scan_16x4, av1_default_iscan_16x4 },
+      { default_scan_16x4, av1_default_iscan_16x4 },
+      { default_scan_16x4, av1_default_iscan_16x4 },
+      { default_scan_16x4, av1_default_iscan_16x4 },
+      { default_scan_16x4, av1_default_iscan_16x4 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_8X32
@@ -1984,6 +2134,16 @@
       { mcol_scan_8x32, av1_mcol_iscan_8x32 },
       { mrow_scan_8x32, av1_mrow_iscan_8x32 },
       { mcol_scan_8x32, av1_mcol_iscan_8x32 },
+#if CONFIG_DDT_INTER
+      { default_scan_8x32, av1_default_iscan_8x32 },
+      { default_scan_8x32, av1_default_iscan_8x32 },
+      { default_scan_8x32, av1_default_iscan_8x32 },
+      { default_scan_8x32, av1_default_iscan_8x32 },
+      { default_scan_8x32, av1_default_iscan_8x32 },
+      { default_scan_8x32, av1_default_iscan_8x32 },
+      { default_scan_8x32, av1_default_iscan_8x32 },
+      { default_scan_8x32, av1_default_iscan_8x32 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_32X8
@@ -2003,6 +2163,16 @@
       { mcol_scan_32x8, av1_mcol_iscan_32x8 },
       { mrow_scan_32x8, av1_mrow_iscan_32x8 },
       { mcol_scan_32x8, av1_mcol_iscan_32x8 },
+#if CONFIG_DDT_INTER
+      { default_scan_32x8, av1_default_iscan_32x8 },
+      { default_scan_32x8, av1_default_iscan_32x8 },
+      { default_scan_32x8, av1_default_iscan_32x8 },
+      { default_scan_32x8, av1_default_iscan_32x8 },
+      { default_scan_32x8, av1_default_iscan_32x8 },
+      { default_scan_32x8, av1_default_iscan_32x8 },
+      { default_scan_32x8, av1_default_iscan_32x8 },
+      { default_scan_32x8, av1_default_iscan_32x8 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_16X64
@@ -2024,6 +2194,16 @@
       { mcol_scan_16x32, av1_mcol_iscan_16x32 },
       { mrow_scan_16x32, av1_mrow_iscan_16x32 },
       { mcol_scan_16x32, av1_mcol_iscan_16x32 },
+#if CONFIG_DDT_INTER
+      { default_scan_16x32, av1_default_iscan_16x32 },
+      { default_scan_16x32, av1_default_iscan_16x32 },
+      { default_scan_16x32, av1_default_iscan_16x32 },
+      { default_scan_16x32, av1_default_iscan_16x32 },
+      { default_scan_16x32, av1_default_iscan_16x32 },
+      { default_scan_16x32, av1_default_iscan_16x32 },
+      { default_scan_16x32, av1_default_iscan_16x32 },
+      { default_scan_16x32, av1_default_iscan_16x32 },
+#endif  // CONFIG_DDT_INTER
   },
   {
       // TX_64X16
@@ -2045,5 +2225,15 @@
       { mcol_scan_32x16, av1_mcol_iscan_32x16 },
       { mrow_scan_32x16, av1_mrow_iscan_32x16 },
       { mcol_scan_32x16, av1_mcol_iscan_32x16 },
+#if CONFIG_DDT_INTER
+      { default_scan_32x16, av1_default_iscan_32x16 },
+      { default_scan_32x16, av1_default_iscan_32x16 },
+      { default_scan_32x16, av1_default_iscan_32x16 },
+      { default_scan_32x16, av1_default_iscan_32x16 },
+      { default_scan_32x16, av1_default_iscan_32x16 },
+      { default_scan_32x16, av1_default_iscan_32x16 },
+      { default_scan_32x16, av1_default_iscan_32x16 },
+      { default_scan_32x16, av1_default_iscan_32x16 },
+#endif  // CONFIG_DDT_INTER
   },
 };
diff --git a/av1/common/txb_common.h b/av1/common/txb_common.h
index 31db5d9..f60c992 100644
--- a/av1/common/txb_common.h
+++ b/av1/common/txb_common.h
@@ -42,6 +42,16 @@
   TX_CLASS_HORIZ,  // H_ADST
   TX_CLASS_VERT,   // V_FLIPADST
   TX_CLASS_HORIZ,  // H_FLIPADST
+#if CONFIG_DDT_INTER
+  TX_CLASS_2D,  // DDT_DDT
+  TX_CLASS_2D,  // DDT_DCT
+  TX_CLASS_2D,  // DCT_DDT
+  TX_CLASS_2D,  // FLIPDDT_FLIPDDT
+  TX_CLASS_2D,  // FLIPDDT_DCT
+  TX_CLASS_2D,  // DCT_FLIPDDT
+  TX_CLASS_2D,  // FLIPDDT_DDT
+  TX_CLASS_2D,  // DDT_FLIPDDT`
+#endif          // CONFIG_DDT_INTER
 };
 
 static INLINE int get_txb_bwl(TX_SIZE tx_size) {
diff --git a/av1/common/x86/highbd_inv_txfm_sse4.c b/av1/common/x86/highbd_inv_txfm_sse4.c
index dc6dbaa..ec4c493 100644
--- a/av1/common/x86/highbd_inv_txfm_sse4.c
+++ b/av1/common/x86/highbd_inv_txfm_sse4.c
@@ -5100,6 +5100,9 @@
   int bd = txfm_param->bd;
   const TX_TYPE tx_type = txfm_param->tx_type;
   const int32_t *src = cast_to_int32(input);
+#if CONFIG_DDT_INTER
+  av1_inv_txfm2d_add_8x8_c(src, CONVERT_TO_SHORTPTR(dest), stride, tx_type, bd);
+#else
   switch (tx_type) {
     case IDTX:
     case H_DCT:
@@ -5117,6 +5120,7 @@
                                     tx_type, bd);
       break;
   }
+#endif  // CONFIG_DDT_INTER
 }
 void av1_highbd_inv_txfm_add_4x4_sse4_1(const tran_low_t *input, uint8_t *dest,
                                         int stride,
@@ -5132,8 +5136,12 @@
     av1_highbd_iwht4x4_add(input, dest, stride, eob, bd);
     return;
   }
+#if CONFIG_DDT_INTER
+  av1_inv_txfm2d_add_4x4_c(src, CONVERT_TO_SHORTPTR(dest), stride, tx_type, bd);
+#else
   av1_inv_txfm2d_add_4x4_sse4_1(src, CONVERT_TO_SHORTPTR(dest), stride, tx_type,
                                 bd);
+#endif  // CONFIG_DDT_INTER
 }
 static void iidentity32_sse4_1(__m128i *in, __m128i *out, int bit, int do_cols,
                                int bd, int out_shift) {
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c
index fcddc28..4e74c41 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -820,9 +820,30 @@
     const TX_SIZE square_tx_size = txsize_sqr_map[tx_size];
     FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
     if (inter_block) {
-      *tx_type = av1_ext_tx_inv[tx_set_type][aom_read_symbol(
-          r, ec_ctx->inter_ext_tx_cdf[eset][square_tx_size],
-          av1_num_ext_tx_set[tx_set_type], ACCT_STR)];
+#if CONFIG_DDT_INTER
+      if (tx_set_type == EXT_TX_SET_ALL24) {
+        if (aom_read_symbol(r, ec_ctx->use_ddtx_inter_cdf[square_tx_size], 2,
+                            ACCT_STR)) {
+          *tx_type =
+              DDT_DDT +
+              aom_read_symbol(r, ec_ctx->ddtx_type_inter_cdf[square_tx_size],
+                              DDT_TYPES, ACCT_STR);
+#if CONFIG_IST
+          *tx_type |= (1 << 6);
+#endif  // CONFIG_IST
+        } else {
+          *tx_type = av1_ext_tx_inv[tx_set_type][aom_read_symbol(
+              r, ec_ctx->inter_ext_tx_cdf[eset][square_tx_size],
+              av1_num_ext_tx_set[tx_set_type], ACCT_STR)];
+        }
+      } else {
+#endif  // CONFIG_DDT_INTER
+        *tx_type = av1_ext_tx_inv[tx_set_type][aom_read_symbol(
+            r, ec_ctx->inter_ext_tx_cdf[eset][square_tx_size],
+            av1_num_ext_tx_set[tx_set_type], ACCT_STR)];
+#if CONFIG_DDT_INTER
+      }
+#endif
     } else {
 #if CONFIG_FORWARDSKIP
       if (mbmi->fsc_mode[xd->tree_type == CHROMA_PART]) {
diff --git a/av1/encoder/av1_fwd_txfm1d.c b/av1/encoder/av1_fwd_txfm1d.c
index a5fb5e1..75613fe 100644
--- a/av1/encoder/av1_fwd_txfm1d.c
+++ b/av1/encoder/av1_fwd_txfm1d.c
@@ -674,6 +674,47 @@
   av1_range_check_buf(stage, input, bf1, size, stage_range[stage]);
 }
 
+#if CONFIG_DDT_INTER
+void av1_fklt4(const int32_t *input, int32_t *output, int8_t cos_bit,
+               const int8_t *stage_range) {
+  (void)cos_bit;
+  (void)stage_range;
+  for (int32_t i = 0; i < 4; i++) {
+    int32_t sum = 0;
+    for (int32_t j = 0; j < 4; j++) {
+      sum += input[j] * klt4_inter[i * 4 + j];
+    }
+    output[i] = ROUND_POWER_OF_TWO_SIGNED(sum, KLT_PREC_BITS);
+  }
+}
+
+void av1_fklt8(const int32_t *input, int32_t *output, int8_t cos_bit,
+               const int8_t *stage_range) {
+  (void)cos_bit;
+  (void)stage_range;
+  for (int32_t i = 0; i < 8; i++) {
+    int32_t sum = 0;
+    for (int32_t j = 0; j < 8; j++) {
+      sum += input[j] * klt8_inter[i * 8 + j];
+    }
+    output[i] = ROUND_POWER_OF_TWO_SIGNED(sum, KLT_PREC_BITS);
+  }
+}
+
+void av1_fklt16(const int32_t *input, int32_t *output, int8_t cos_bit,
+                const int8_t *stage_range) {
+  (void)cos_bit;
+  (void)stage_range;
+  for (int32_t i = 0; i < 16; i++) {
+    int32_t sum = 0;
+    for (int32_t j = 0; j < 16; j++) {
+      sum += input[j] * klt16_inter[i * 16 + j];
+    }
+    output[i] = ROUND_POWER_OF_TWO_SIGNED(sum, KLT_PREC_BITS);
+  }
+}
+#endif  // CONFIG_DDT_INTER
+
 void av1_fadst4(const int32_t *input, int32_t *output, int8_t cos_bit,
                 const int8_t *stage_range) {
   int bit = cos_bit;
diff --git a/av1/encoder/av1_fwd_txfm1d.h b/av1/encoder/av1_fwd_txfm1d.h
index d41f81c..9f96341 100644
--- a/av1/encoder/av1_fwd_txfm1d.h
+++ b/av1/encoder/av1_fwd_txfm1d.h
@@ -15,6 +15,10 @@
 
 #include "av1/common/av1_txfm.h"
 
+#if CONFIG_DDT_INTER
+#include "av1/common/ddtx_bases.h"
+#endif  // CONFIG_DDT_INTER
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -47,6 +51,14 @@
                        const int8_t *stage_range);
 void av1_fidentity32_c(const int32_t *input, int32_t *output, int8_t cos_bit,
                        const int8_t *stage_range);
+#if CONFIG_DDT_INTER
+void av1_fklt4(const int32_t *input, int32_t *output, int8_t cos_bit,
+               const int8_t *stage_range);
+void av1_fklt8(const int32_t *input, int32_t *output, int8_t cos_bit,
+               const int8_t *stage_range);
+void av1_fklt16(const int32_t *input, int32_t *output, int8_t cos_bit,
+                const int8_t *stage_range);
+#endif  // CONFIG_DDT_INTER
 #ifdef __cplusplus
 }
 #endif
diff --git a/av1/encoder/av1_fwd_txfm2d.c b/av1/encoder/av1_fwd_txfm2d.c
index 8d55e59..0989a1e 100644
--- a/av1/encoder/av1_fwd_txfm2d.c
+++ b/av1/encoder/av1_fwd_txfm2d.c
@@ -34,6 +34,11 @@
 #if CONFIG_DST_32X32
     case TXFM_TYPE_ADST32: return av1_fadst32;
 #endif  // CONFIG_DST_32X32
+#if CONFIG_DDT_INTER
+    case TXFM_TYPE_DDT4: return av1_fklt4;
+    case TXFM_TYPE_DDT8: return av1_fklt8;
+    case TXFM_TYPE_DDT16: return av1_fklt16;
+#endif  // CONFIG_DDT_INTER
     case TXFM_TYPE_IDENTITY4: return av1_fidentity4_c;
     case TXFM_TYPE_IDENTITY8: return av1_fidentity8_c;
     case TXFM_TYPE_IDENTITY16: return av1_fidentity16_c;
@@ -388,20 +393,14 @@
 #endif
 
 static const int8_t *fwd_txfm_range_mult2_list[TXFM_TYPES] = {
-  fdct4_range_mult2,
-  fdct8_range_mult2,
-  fdct16_range_mult2,
-  fdct32_range_mult2,
-  fdct64_range_mult2,
-  fadst4_range_mult2,
-  fadst8_range_mult2,
-  fadst16_range_mult2,
-  fidtx4_range_mult2,
-  fidtx8_range_mult2,
-  fidtx16_range_mult2,
-  fidtx32_range_mult2
+  fdct4_range_mult2,   fdct8_range_mult2,   fdct16_range_mult2,
+  fdct32_range_mult2,  fdct64_range_mult2,  fadst4_range_mult2,
+  fadst8_range_mult2,  fadst16_range_mult2, fidtx4_range_mult2,
+  fidtx8_range_mult2,  fidtx16_range_mult2, fidtx32_range_mult2,
+#if CONFIG_DDT_INTER
+  fadst4_range_mult2,  fadst8_range_mult2,  fadst16_range_mult2,
+#endif  // CONFIG_DDT_INTER
 #if CONFIG_DST_32X32
-  ,
   fadst32_range_mult2,
 #endif
 };
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 1f8170d..da8c9a2 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -1089,9 +1089,33 @@
     assert(av1_ext_tx_used[tx_set_type][tx_type]);
 #endif
     if (is_inter) {
-      aom_write_symbol(w, av1_ext_tx_ind[tx_set_type][tx_type],
-                       ec_ctx->inter_ext_tx_cdf[eset][square_tx_size],
-                       av1_num_ext_tx_set[tx_set_type]);
+#if CONFIG_DDT_INTER
+      if (tx_set_type == EXT_TX_SET_ALL24) {
+#if CONFIG_IST
+        TX_TYPE ptx_type = get_primary_tx_type(tx_type);
+#else
+        TX_TYPE ptx_type = tx_type;
+#endif
+        int is_ddtx = has_ddtx(ptx_type);
+        aom_write_symbol(w, is_ddtx, ec_ctx->use_ddtx_inter_cdf[square_tx_size],
+                         2);
+        if (is_ddtx) {
+          aom_write_symbol(w, ptx_type - DDT_DDT,
+                           ec_ctx->ddtx_type_inter_cdf[square_tx_size],
+                           DDT_TYPES);
+        } else {
+          aom_write_symbol(w, av1_ext_tx_ind[tx_set_type][ptx_type],
+                           ec_ctx->inter_ext_tx_cdf[eset][square_tx_size],
+                           av1_num_ext_tx_set[tx_set_type]);
+        }
+      } else {
+#endif  // CONFIG_DDT_INTER
+        aom_write_symbol(w, av1_ext_tx_ind[tx_set_type][tx_type],
+                         ec_ctx->inter_ext_tx_cdf[eset][square_tx_size],
+                         av1_num_ext_tx_set[tx_set_type]);
+#if CONFIG_DDT_INTER
+      }
+#endif  // CONFIG_DDT_INTER
     } else {
 #if CONFIG_FORWARDSKIP
       if (mbmi->fsc_mode[xd->tree_type == CHROMA_PART]) {
diff --git a/av1/encoder/block.h b/av1/encoder/block.h
index 918d4c7..6e97fee 100644
--- a/av1/encoder/block.h
+++ b/av1/encoder/block.h
@@ -828,11 +828,23 @@
   //! txfm_partition_cost
   int txfm_partition_cost[TXFM_PARTITION_CONTEXTS][2];
 #endif  // CONFIG_NEW_TX_PARTITION
+#if CONFIG_DDT_INTER
+  //! use_ddtx_inter_costs
+  int use_ddtx_inter_costs[EXT_TX_SIZES][2];
+  //! ddtx_type_inter_costs
+  int ddtx_type_inter_costs[EXT_TX_SIZES][DDT_TYPES];
+  //! inter_tx_type_costs
+  int inter_tx_type_costs[EXT_TX_SETS_INTER][EXT_TX_SIZES][TX_TYPES_TRIG];
+  //! intra_tx_type_costs
+  int intra_tx_type_costs[EXT_TX_SETS_INTRA][EXT_TX_SIZES][INTRA_MODES]
+                         [TX_TYPES_TRIG];
+#else
   //! inter_tx_type_costs
   int inter_tx_type_costs[EXT_TX_SETS_INTER][EXT_TX_SIZES][TX_TYPES];
   //! intra_tx_type_costs
   int intra_tx_type_costs[EXT_TX_SETS_INTRA][EXT_TX_SIZES][INTRA_MODES]
                          [TX_TYPES];
+#endif  // CONFIG_DDT_INTER
   /**@}*/
 
   /*****************************************************************************
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index aef4637..3072f2f 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -1286,9 +1286,17 @@
   unsigned int delta_lf_multi[FRAME_LF_COUNT][DELTA_LF_PROBS][2];
   unsigned int delta_lf[DELTA_LF_PROBS][2];
 
+#if CONFIG_DDT_INTER
+  unsigned int use_ddtx_inter[EXT_TX_SIZES][2];
+  unsigned int ddtx_type_inter[EXT_TX_SIZES][DDT_TYPES];
+  unsigned int inter_ext_tx[EXT_TX_SETS_INTER][EXT_TX_SIZES][TX_TYPES_TRIG];
+  unsigned int intra_ext_tx[EXT_TX_SETS_INTRA][EXT_TX_SIZES][INTRA_MODES]
+                           [TX_TYPES_TRIG];
+#else
   unsigned int inter_ext_tx[EXT_TX_SETS_INTER][EXT_TX_SIZES][TX_TYPES];
   unsigned int intra_ext_tx[EXT_TX_SETS_INTRA][EXT_TX_SIZES][INTRA_MODES]
                            [TX_TYPES];
+#endif  // CONFIG_DDT_INTER
   unsigned int filter_intra_mode[FILTER_INTRA_MODES];
   unsigned int filter_intra[BLOCK_SIZES_ALL][2];
   unsigned int switchable_restore[RESTORE_SWITCHABLE_TYPES];
diff --git a/av1/encoder/encodetxb.c b/av1/encoder/encodetxb.c
index e21d998..85eebe2 100644
--- a/av1/encoder/encodetxb.c
+++ b/av1/encoder/encodetxb.c
@@ -849,9 +849,34 @@
     const int ext_tx_set =
         get_ext_tx_set(tx_size, is_inter, reduced_tx_set_used);
     if (is_inter) {
+#if CONFIG_DDT_INTER
+      const TxSetType tx_set_type =
+          av1_get_ext_tx_set_type(tx_size, is_inter, reduced_tx_set_used);
+      if (tx_set_type == EXT_TX_SET_ALL24) {
+#if CONFIG_IST
+        TX_TYPE ptx_type = get_primary_tx_type(tx_type);
+#else
+        TX_TYPE ptx_type = tx_type;
+#endif  // CONFIG_IST
+        int is_ddtx = has_ddtx(ptx_type);
+        int use_ddtx_cost =
+            x->mode_costs.use_ddtx_inter_costs[square_tx_size][is_ddtx];
+        int tx_type_cost =
+            is_ddtx
+                ? x->mode_costs
+                      .ddtx_type_inter_costs[square_tx_size][ptx_type - DDT_DDT]
+                : x->mode_costs.inter_tx_type_costs[ext_tx_set][square_tx_size]
+                                                   [ptx_type];
+        return use_ddtx_cost + tx_type_cost;
+      } else {
+        return x->mode_costs
+            .inter_tx_type_costs[ext_tx_set][square_tx_size][tx_type];
+      }
+#else
       if (ext_tx_set > 0)
         return x->mode_costs
             .inter_tx_type_costs[ext_tx_set][square_tx_size][tx_type];
+#endif  // CONFIG_DDT_INTER
     } else {
       if (ext_tx_set > 0) {
         PREDICTION_MODE intra_dir;
@@ -2084,13 +2109,56 @@
           av1_get_ext_tx_set_type(tx_size, is_inter, reduced_tx_set_used);
       if (is_inter) {
         if (allow_update_cdf) {
-          update_cdf(fc->inter_ext_tx_cdf[eset][txsize_sqr_map[tx_size]],
-                     av1_ext_tx_ind[tx_set_type][tx_type],
-                     av1_num_ext_tx_set[tx_set_type]);
+#if CONFIG_DDT_INTER
+          if (tx_set_type == EXT_TX_SET_ALL24) {
+#if CONFIG_IST
+            TX_TYPE ptx_type = get_primary_tx_type(tx_type);
+#else
+            TX_TYPE ptx_type = tx_type;
+#endif  // CONFIG_IST
+            int is_ddtx = has_ddtx(ptx_type);
+            update_cdf(fc->use_ddtx_inter_cdf[txsize_sqr_map[tx_size]], is_ddtx,
+                       2);
+            if (is_ddtx) {
+              update_cdf(fc->ddtx_type_inter_cdf[txsize_sqr_map[tx_size]],
+                         ptx_type - DDT_DDT, DDT_TYPES);
+            } else {
+              update_cdf(fc->inter_ext_tx_cdf[eset][txsize_sqr_map[tx_size]],
+                         av1_ext_tx_ind[tx_set_type][ptx_type],
+                         av1_num_ext_tx_set[tx_set_type]);
+            }
+          } else {
+#endif  // CONFIG_DDT_INTER
+            update_cdf(fc->inter_ext_tx_cdf[eset][txsize_sqr_map[tx_size]],
+                       av1_ext_tx_ind[tx_set_type][tx_type],
+                       av1_num_ext_tx_set[tx_set_type]);
+#if CONFIG_DDT_INTER
+          }
+#endif
         }
 #if CONFIG_ENTROPY_STATS
-        ++counts->inter_ext_tx[eset][txsize_sqr_map[tx_size]]
-                              [av1_ext_tx_ind[tx_set_type][tx_type]];
+#if CONFIG_DDT_INTER
+        if (tx_set_type == EXT_TX_SET_ALL24) {
+#if CONFIG_IST
+          TX_TYPE ptx_type = get_primary_tx_type(tx_type);
+#else
+          TX_TYPE ptx_type = tx_type;
+#endif  // CONFIG_IST
+          int is_ddtx = has_ddtx(ptx_type);
+          ++counts->use_ddtx_inter[txsize_sqr_map[tx_size]][is_ddtx];
+          if (is_ddtx)
+            ++counts->ddtx_type_inter[txsize_sqr_map[tx_size]]
+                                     [ptx_type - DDT_DDT];
+          else
+            ++counts->inter_ext_tx[eset][txsize_sqr_map[tx_size]]
+                                  [av1_ext_tx_ind[tx_set_type][ptx_type]];
+        } else {
+#endif
+          ++counts->inter_ext_tx[eset][txsize_sqr_map[tx_size]]
+                                [av1_ext_tx_ind[tx_set_type][tx_type]];
+#if CONFIG_DDT_INTER
+        }
+#endif
 #endif  // CONFIG_ENTROPY_STATS
       } else {
 #if CONFIG_FORWARDSKIP
diff --git a/av1/encoder/hybrid_fwd_txfm.c b/av1/encoder/hybrid_fwd_txfm.c
index 09248f4..5ef2ff8 100644
--- a/av1/encoder/hybrid_fwd_txfm.c
+++ b/av1/encoder/hybrid_fwd_txfm.c
@@ -91,21 +91,35 @@
     av1_highbd_fwht4x4(src_diff, coeff, diff_stride);
     return;
   }
+#if CONFIG_DDT_INTER
+  av1_fwd_txfm2d_4x4_c(src_diff, dst_coeff, diff_stride, tx_type, bd);
+#else
   av1_fwd_txfm2d_4x4(src_diff, dst_coeff, diff_stride, tx_type, bd);
+#endif  // CCONFIG_DDT_INTER
 }
 
 static void highbd_fwd_txfm_4x8(const int16_t *src_diff, tran_low_t *coeff,
                                 int diff_stride, TxfmParam *txfm_param) {
   int32_t *dst_coeff = (int32_t *)coeff;
+#if CONFIG_DDT_INTER
+  av1_fwd_txfm2d_4x8_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
+                       txfm_param->bd);
+#else
   av1_fwd_txfm2d_4x8(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
                      txfm_param->bd);
+#endif  // CONFIG_DDT_INTER
 }
 
 static void highbd_fwd_txfm_8x4(const int16_t *src_diff, tran_low_t *coeff,
                                 int diff_stride, TxfmParam *txfm_param) {
   int32_t *dst_coeff = (int32_t *)coeff;
+#if CONFIG_DDT_INTER
+  av1_fwd_txfm2d_8x4_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
+                       txfm_param->bd);
+#else
   av1_fwd_txfm2d_8x4(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
                      txfm_param->bd);
+#endif  // CONFIG_DDT_INTER
 }
 
 static void highbd_fwd_txfm_8x16(const int16_t *src_diff, tran_low_t *coeff,
@@ -113,7 +127,9 @@
   int32_t *dst_coeff = (int32_t *)coeff;
   const TX_TYPE tx_type = txfm_param->tx_type;
   const int bd = txfm_param->bd;
-#if CONFIG_DST7_16X16
+#if CONFIG_DDT_INTER
+  av1_fwd_txfm2d_8x16_c(src_diff, dst_coeff, diff_stride, tx_type, bd);
+#elif CONFIG_DST7_16X16
   uint16_t allowed_tx_mask = 0xF1FE;
   allowed_tx_mask &= (1 << tx_type);
   if (allowed_tx_mask)
@@ -122,7 +138,7 @@
     av1_fwd_txfm2d_8x16(src_diff, dst_coeff, diff_stride, tx_type, bd);
 #else
   av1_fwd_txfm2d_8x16(src_diff, dst_coeff, diff_stride, tx_type, bd);
-#endif  // CONFIG_DST7_16X16
+#endif  // CONFIG_DDT_INTER
 }
 
 static void highbd_fwd_txfm_16x8(const int16_t *src_diff, tran_low_t *coeff,
@@ -130,7 +146,9 @@
   int32_t *dst_coeff = (int32_t *)coeff;
   const TX_TYPE tx_type = txfm_param->tx_type;
   const int bd = txfm_param->bd;
-#if CONFIG_DST7_16X16
+#if CONFIG_DDT_INTER
+  av1_fwd_txfm2d_16x8_c(src_diff, dst_coeff, diff_stride, tx_type, bd);
+#elif CONFIG_DST7_16X16
   uint16_t allowed_tx_mask = 0xF1FE;
   allowed_tx_mask &= (1 << tx_type);
   if (allowed_tx_mask)
@@ -139,13 +157,16 @@
     av1_fwd_txfm2d_16x8(src_diff, dst_coeff, diff_stride, tx_type, bd);
 #else
   av1_fwd_txfm2d_16x8(src_diff, dst_coeff, diff_stride, tx_type, bd);
-#endif  // CONFIG_DST7_16X16
+#endif  // CONFIG_DDT_INTER
 }
 
 static void highbd_fwd_txfm_16x32(const int16_t *src_diff, tran_low_t *coeff,
                                   int diff_stride, TxfmParam *txfm_param) {
   int32_t *dst_coeff = (int32_t *)coeff;
-#if CONFIG_DST_32X32
+#if CONFIG_DDT_INTER
+  av1_fwd_txfm2d_16x32_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
+                         txfm_param->bd);
+#elif CONFIG_DST_32X32
   const TX_TYPE tx_type = txfm_param->tx_type;
   uint16_t allowed_tx_mask = 0xF1FE;
   allowed_tx_mask &= (1 << tx_type);
@@ -159,13 +180,16 @@
   assert(txfm_param->tx_type == DCT_DCT || txfm_param->tx_type == IDTX);
   av1_fwd_txfm2d_16x32(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
                        txfm_param->bd);
-#endif  // CONFIG_DST_32X32
+#endif  // CONFIG_DDT_INTER
 }
 
 static void highbd_fwd_txfm_32x16(const int16_t *src_diff, tran_low_t *coeff,
                                   int diff_stride, TxfmParam *txfm_param) {
   int32_t *dst_coeff = (int32_t *)coeff;
-#if CONFIG_DST_32X32
+#if CONFIG_DDT_INTER
+  av1_fwd_txfm2d_32x16_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
+                         txfm_param->bd);
+#elif CONFIG_DST_32X32
   const TX_TYPE tx_type = txfm_param->tx_type;
   uint16_t allowed_tx_mask = 0xF1FE;
   allowed_tx_mask &= (1 << tx_type);
@@ -179,13 +203,16 @@
   assert(txfm_param->tx_type == DCT_DCT || txfm_param->tx_type == IDTX);
   av1_fwd_txfm2d_32x16(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
                        txfm_param->bd);
-#endif  // CONFIG_DST_32X32
+#endif  // CONFIG_DDT_INTER
 }
 
 static void highbd_fwd_txfm_16x4(const int16_t *src_diff, tran_low_t *coeff,
                                  int diff_stride, TxfmParam *txfm_param) {
   int32_t *dst_coeff = (int32_t *)coeff;
-#if CONFIG_DST7_16X16
+#if CONFIG_DDT_INTER
+  av1_fwd_txfm2d_16x4_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
+                        txfm_param->bd);
+#elif CONFIG_DST7_16X16
   const TX_TYPE tx_type = txfm_param->tx_type;
   uint16_t allowed_tx_mask = 0xF1FE;
   allowed_tx_mask &= (1 << tx_type);
@@ -198,13 +225,16 @@
 #else
   av1_fwd_txfm2d_16x4(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
                       txfm_param->bd);
-#endif  // CONFIG_DST7_16X16
+#endif  // CONFIG_DDT_INTER
 }
 
 static void highbd_fwd_txfm_4x16(const int16_t *src_diff, tran_low_t *coeff,
                                  int diff_stride, TxfmParam *txfm_param) {
   int32_t *dst_coeff = (int32_t *)coeff;
-#if CONFIG_DST7_16X16
+#if CONFIG_DDT_INTER
+  av1_fwd_txfm2d_4x16_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
+                        txfm_param->bd);
+#elif CONFIG_DST7_16X16
   const TX_TYPE tx_type = txfm_param->tx_type;
   uint16_t allowed_tx_mask = 0xF1FE;
   allowed_tx_mask &= (1 << tx_type);
@@ -217,13 +247,16 @@
 #else
   av1_fwd_txfm2d_4x16(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
                       txfm_param->bd);
-#endif  // CONFIG_DST7_16X16
+#endif  // CONFIG_DDT_INTER
 }
 
 static void highbd_fwd_txfm_32x8(const int16_t *src_diff, tran_low_t *coeff,
                                  int diff_stride, TxfmParam *txfm_param) {
   int32_t *dst_coeff = (int32_t *)coeff;
-#if CONFIG_DST_32X32
+#if CONFIG_DDT_INTER
+  av1_fwd_txfm2d_32x8_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
+                        txfm_param->bd);
+#elif CONFIG_DST_32X32
   const TX_TYPE tx_type = txfm_param->tx_type;
   uint16_t allowed_tx_mask = 0xF1FE;
   allowed_tx_mask &= (1 << tx_type);
@@ -236,13 +269,16 @@
 #else
   av1_fwd_txfm2d_32x8(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
                       txfm_param->bd);
-#endif  // CONFIG_DST_32X32
+#endif  // CONFIG_DDT_INTER
 }
 
 static void highbd_fwd_txfm_8x32(const int16_t *src_diff, tran_low_t *coeff,
                                  int diff_stride, TxfmParam *txfm_param) {
   int32_t *dst_coeff = (int32_t *)coeff;
-#if CONFIG_DST_32X32
+#if CONFIG_DDT_INTER
+  av1_fwd_txfm2d_8x32_c(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
+                        txfm_param->bd);
+#elif CONFIG_DST_32X32
   const TX_TYPE tx_type = txfm_param->tx_type;
   uint16_t allowed_tx_mask = 0xF1FE;
   allowed_tx_mask &= (1 << tx_type);
@@ -255,7 +291,7 @@
 #else
   av1_fwd_txfm2d_8x32(src_diff, dst_coeff, diff_stride, txfm_param->tx_type,
                       txfm_param->bd);
-#endif  // CONFIG_DST_32X32
+#endif  // CONFIG_DDT_INTER
 }
 
 static void highbd_fwd_txfm_8x8(const int16_t *src_diff, tran_low_t *coeff,
@@ -263,7 +299,11 @@
   int32_t *dst_coeff = (int32_t *)coeff;
   const TX_TYPE tx_type = txfm_param->tx_type;
   const int bd = txfm_param->bd;
+#if CONFIG_DDT_INTER
+  av1_fwd_txfm2d_8x8_c(src_diff, dst_coeff, diff_stride, tx_type, bd);
+#else
   av1_fwd_txfm2d_8x8(src_diff, dst_coeff, diff_stride, tx_type, bd);
+#endif  // CONFIG_DDT_INTER
 }
 
 static void highbd_fwd_txfm_16x16(const int16_t *src_diff, tran_low_t *coeff,
@@ -271,7 +311,9 @@
   int32_t *dst_coeff = (int32_t *)coeff;
   const TX_TYPE tx_type = txfm_param->tx_type;
   const int bd = txfm_param->bd;
-#if CONFIG_DST7_16X16
+#if CONFIG_DDT_INTER
+  av1_fwd_txfm2d_16x16_c(src_diff, dst_coeff, diff_stride, tx_type, bd);
+#elif CONFIG_DST7_16X16
   uint16_t allowed_tx_mask = 0xF1FE;
   allowed_tx_mask &= (1 << tx_type);
   if (allowed_tx_mask)
@@ -280,7 +322,7 @@
     av1_fwd_txfm2d_16x16(src_diff, dst_coeff, diff_stride, tx_type, bd);
 #else
   av1_fwd_txfm2d_16x16(src_diff, dst_coeff, diff_stride, tx_type, bd);
-#endif  // CONFIG_DST7_16X16
+#endif  // CONFIG_DDT_INTER
 }
 
 static void highbd_fwd_txfm_32x32(const int16_t *src_diff, tran_low_t *coeff,
@@ -323,7 +365,11 @@
   assert(txfm_param->tx_type == DCT_DCT);
   int32_t *dst_coeff = (int32_t *)coeff;
   const int bd = txfm_param->bd;
+#if CONFIG_DDT_INTER
+  av1_fwd_txfm2d_16x64_c(src_diff, dst_coeff, diff_stride, DCT_DCT, bd);
+#else
   av1_fwd_txfm2d_16x64(src_diff, dst_coeff, diff_stride, DCT_DCT, bd);
+#endif  // CONFIG_DDT_INTER
 }
 
 static void highbd_fwd_txfm_64x16(const int16_t *src_diff, tran_low_t *coeff,
@@ -331,7 +377,11 @@
   assert(txfm_param->tx_type == DCT_DCT);
   int32_t *dst_coeff = (int32_t *)coeff;
   const int bd = txfm_param->bd;
+#if CONFIG_DDT_INTER
+  av1_fwd_txfm2d_64x16_c(src_diff, dst_coeff, diff_stride, DCT_DCT, bd);
+#else
   av1_fwd_txfm2d_64x16(src_diff, dst_coeff, diff_stride, DCT_DCT, bd);
+#endif  // CONFIG_DDT_INTER
 }
 
 static void highbd_fwd_txfm_64x64(const int16_t *src_diff, tran_low_t *coeff,
@@ -344,6 +394,9 @@
 
 void av1_fwd_txfm(const int16_t *src_diff, tran_low_t *coeff, int diff_stride,
                   TxfmParam *txfm_param) {
+#if CONFIG_DDT_INTER
+  av1_lowbd_fwd_txfm_c(src_diff, coeff, diff_stride, txfm_param);
+#else
   if (txfm_param->bd == 8) {
 #if CONFIG_DST7_16X16 || CONFIG_DST_32X32
     const TX_TYPE tx_type = txfm_param->tx_type;
@@ -372,6 +425,7 @@
   } else {
     av1_highbd_fwd_txfm(src_diff, coeff, diff_stride, txfm_param);
   }
+#endif  // CONFIG_DDT_INTER
 }
 
 void av1_lowbd_fwd_txfm_c(const int16_t *src_diff, tran_low_t *coeff,
diff --git a/av1/encoder/rd.c b/av1/encoder/rd.c
index bda46a8..73684e0 100644
--- a/av1/encoder/rd.c
+++ b/av1/encoder/rd.c
@@ -84,7 +84,11 @@
   {
       // Inter
       EXT_TX_SET_DCTONLY,
+#if CONFIG_DDT_INTER
+      EXT_TX_SET_ALL24,
+#else
       EXT_TX_SET_ALL16,
+#endif  // CONFIG_DDT_INTER
       EXT_TX_SET_DTT9_IDTX_1DDCT,
       EXT_TX_SET_DCT_IDTX,
   },
@@ -280,6 +284,16 @@
       }
     }
   }
+#if CONFIG_DDT_INTER
+  for (i = TX_4X4; i < EXT_TX_SIZES; ++i) {
+    av1_cost_tokens_from_cdf(mode_costs->ddtx_type_inter_costs[i],
+                             fc->ddtx_type_inter_cdf[i], NULL);
+  }
+  for (int s = 0; s < EXT_TX_SIZES; ++s) {
+    av1_cost_tokens_from_cdf(mode_costs->use_ddtx_inter_costs[s],
+                             fc->use_ddtx_inter_cdf[s], NULL);
+  }
+#endif  // CONFIG_DDT_INTER
 #if !CONFIG_AIMC
   for (i = 0; i < PARTITION_STRUCTURE_NUM; ++i) {
     for (j = 0; j < DIRECTIONAL_MODES; ++j) {
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index 8b74a2d..9489963 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -70,7 +70,11 @@
 #endif
   txfm_param.tx_size = tx_size;
   txfm_param.lossless = 0;
+#if CONFIG_DDT_INTER
+  txfm_param.tx_set_type = EXT_TX_SET_ALL24;
+#else
   txfm_param.tx_set_type = EXT_TX_SET_ALL16;
+#endif  // CONFIG_DDT_INTER
 
   txfm_param.bd = bit_depth;
   av1_fwd_txfm(src_diff, coeff, bw, &txfm_param);
diff --git a/av1/encoder/tx_search.c b/av1/encoder/tx_search.c
index af438a9..3216e4a 100644
--- a/av1/encoder/tx_search.c
+++ b/av1/encoder/tx_search.c
@@ -1408,7 +1408,11 @@
   // to ensure we can try ones even outside of ext_tx_set of current block
   // this function should only be called for size < 16
   assert(txsize_sqr_up_map[tx_size] <= TX_16X16);
+#if CONFIG_DDT_INTER
+  txfm_param.tx_set_type = EXT_TX_SET_ALL24;
+#else
   txfm_param.tx_set_type = EXT_TX_SET_ALL16;
+#endif  // CONFIG_DDT_INTER
 
   int rate_cost = 0;
   int64_t dist = 0, sse = 0;
@@ -1482,7 +1486,12 @@
   // combine rd_h and rd_v to prune tx candidates
   int i_v, i_h;
   int64_t rds[16];
+#if CONFIG_DDT_INTER
+  // Pruning is not applied to DDT for now.
+  int num_cand = 0, last = TX_TYPES_TRIG - 1;
+#else
   int num_cand = 0, last = TX_TYPES - 1;
+#endif  // CONFIG_DDT_INTER
 
   for (int i = 0; i < 16; i++) {
     i_v = sel_pattern_v[i];
@@ -1522,10 +1531,19 @@
   const AV1_COMMON *cm = &cpi->common;
   int tx_type;
 
+#if CONFIG_DDT_INTER
+  // Pruning is not applied to DDT for now.
+  int64_t rds[TX_TYPES_TRIG];
+#else
   int64_t rds[TX_TYPES];
+#endif  // CONFIG_DDT_INTER
 
   int num_cand = 0;
+#if CONFIG_DDT_INTER
+  int last = TX_TYPES_TRIG - 1;
+#else
   int last = TX_TYPES - 1;
+#endif  // CONFIG_DDT_INTER
 
   TxfmParam txfm_param;
   QUANT_PARAM quant_param;
@@ -1537,7 +1555,11 @@
   av1_setup_quant(tx_size, 1, AV1_XFORM_QUANT_B, cpi->oxcf.q_cfg.quant_b_adapt,
                   &quant_param);
 
+#if CONFIG_DDT_INTER
+  for (int idx = 0; idx < TX_TYPES_TRIG; idx++) {
+#else
   for (int idx = 0; idx < TX_TYPES; idx++) {
+#endif  // CONFIG_DDT_INTER
     tx_type = idx;
     int rate_cost = 0;
     int64_t dist = 0, sse = 0;
@@ -1681,7 +1703,11 @@
     { 4, 1 }, { 6, 3 }, { 9, 6 }, { 9, 6 }, { 12, 9 }
   };
   int pruning_aggressiveness = 0;
+#if CONFIG_DDT_INTER
+  if (tx_set_type == EXT_TX_SET_ALL24)
+#else
   if (tx_set_type == EXT_TX_SET_ALL16)
+#endif  // CONFIG_DDT_INTER
     pruning_aggressiveness =
         prune_aggr_table[prune_2d_txfm_mode - TX_TYPE_PRUNE_1][0];
   else if (tx_set_type == EXT_TX_SET_DTT9_IDTX_1DDCT)
@@ -1765,7 +1791,11 @@
     FLIPADST_DCT, FLIPADST_ADST, FLIPADST_FLIPADST, V_FLIPADST,
     H_DCT,        H_ADST,        H_FLIPADST,        IDTX
   };
+#if CONFIG_DDT_INTER
+  if (tx_set_type != EXT_TX_SET_ALL24 &&
+#else
   if (tx_set_type != EXT_TX_SET_ALL16 &&
+#endif  // CONFIG_DDT_INTER
       tx_set_type != EXT_TX_SET_DTT9_IDTX_1DDCT)
     return;
 #if CONFIG_NN_V2
@@ -1828,7 +1858,11 @@
   float sum_score = 0.0;
   // Calculate sum of allowed tx type score and Populate allow bit mask based
   // on score_thresh and allowed_tx_mask
+#if CONFIG_DDT_INTER
+  for (int tx_idx = 0; tx_idx < TX_TYPES_TRIG; tx_idx++) {
+#else
   for (int tx_idx = 0; tx_idx < TX_TYPES; tx_idx++) {
+#endif  // CONFIG_DDT_INTER
     int allow_tx_type = *allowed_tx_mask & (1 << tx_type_table_2D[tx_idx]);
     if (scores_2D[tx_idx] > max_score && allow_tx_type) {
       max_score = scores_2D[tx_idx];
@@ -1848,7 +1882,11 @@
     sum_score += scores_2D[max_score_i];
   }
   // Sort tx type probability of all types
+#if CONFIG_DDT_INTER
+  sort_probability(scores_2D, tx_type_table_2D, TX_TYPES_TRIG);
+#else
   sort_probability(scores_2D, tx_type_table_2D, TX_TYPES);
+#endif  // CONFIG_DDT_INTER
 
   // Enable more pruning based on tx type probability and number of allowed tx
   // types
@@ -1858,7 +1896,11 @@
     int tx_idx, tx_count = 0;
     const float inv_sum_score = 100 / sum_score;
     // Get allowed tx types based on sorted probability score and tx count
+#if CONFIG_DDT_INTER
+    for (tx_idx = 0; tx_idx < TX_TYPES_TRIG; tx_idx++) {
+#else
     for (tx_idx = 0; tx_idx < TX_TYPES; tx_idx++) {
+#endif  // CONFIG_DDT_INTER
       // Skip the tx type which has more than 30% of cumulative
       // probability and allowed tx type count is more than 2
       if (score_ratio > 30.0 && tx_count >= 2) break;
@@ -1874,7 +1916,11 @@
       }
     }
     // Set remaining tx types as pruned
+#if CONFIG_DDT_INTER
+    for (; tx_idx < TX_TYPES_TRIG; tx_idx++)
+#else
     for (; tx_idx < TX_TYPES; tx_idx++)
+#endif  // CONFIG_DDT_INTER
       allow_bitmask &= ~(1 << tx_type_table_2D[tx_idx]);
   }
   memcpy(txk_map, tx_type_table_2D, sizeof(tx_type_table_2D));
@@ -2045,7 +2091,11 @@
       uint16_t prune = 0;
       int max_prob = -1;
       int max_idx = 0;
+#if CONFIG_DDT_INTER
+      for (i = 0; i < TX_TYPES_TRIG; i++) {
+#else
       for (i = 0; i < TX_TYPES; i++) {
+#endif  // CONFIG_DDT_INTER
         if (tx_type_probs[i] > max_prob && (allowed_tx_mask & (1 << i))) {
           max_prob = tx_type_probs[i];
           max_idx = i;
@@ -2055,7 +2105,11 @@
       if ((prune >> max_idx) & 0x01) prune &= ~(1 << max_idx);
       allowed_tx_mask &= (~prune);
     }
+#if CONFIG_DDT_INTER
+    for (i = 0; i < TX_TYPES_TRIG; i++) {
+#else
     for (i = 0; i < TX_TYPES; i++) {
+#endif  // CONFIG_DDT_INTER
       if (allowed_tx_mask & (1 << i)) num_allowed++;
     }
     assert(num_allowed > 0);
@@ -2356,9 +2410,16 @@
   // txk_allowed = TX_TYPES: >1 tx types are allowed
   // txk_allowed < TX_TYPES: only that specific tx type is allowed.
   TX_TYPE txk_allowed = TX_TYPES;
+#if CONFIG_DDT_INTER
+  int txk_map[TX_TYPES] = { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11,
+                            12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };
+  const TxSetType tx_set_type = av1_get_ext_tx_set_type(
+      tx_size, is_inter, cm->features.reduced_tx_set_used);
+#else
   int txk_map[TX_TYPES] = {
     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
   };
+#endif  // CONFIG_DDT_INTER
   const int dequant_shift = xd->bd - 5;
 
   const int qstep =
@@ -2495,7 +2556,13 @@
     const int max_stx = xd->enable_ist ? 4 : 1;
     for (int stx = 0; stx < max_stx; ++stx) {
       TX_TYPE tx_type = (TX_TYPE)txk_map[idx];
+#if CONFIG_DDT_INTER
+      int is_ddtx = has_ddtx(tx_type);
+      if (!is_ddtx && !(allowed_tx_mask & (1 << tx_type))) continue;
+      if (is_ddtx && !av1_ext_tx_used[tx_set_type][tx_type]) continue;
+#else
       if (!(allowed_tx_mask & (1 << tx_type))) continue;
+#endif  // CONFIG_DDT_INTER
       const PREDICTION_MODE intra_mode =
           (plane == AOM_PLANE_Y) ? mbmi->mode : get_uv_mode(mbmi->uv_mode);
       const int filter = mbmi->filter_intra_mode_info.use_filter_intra;
@@ -2510,11 +2577,20 @@
            xd->lossless[mbmi->segment_id]);
       if (skip_stx && stx) continue;
       tx_type += (stx << 4);
+#if CONFIG_DDT_INTER
+      tx_type += (is_ddtx << 6);
+#endif  // CONFIG_DDT_INTER
       txfm_param.tx_type = get_primary_tx_type(tx_type);
       txfm_param.sec_tx_type = stx;
 #else
     const TX_TYPE tx_type = (TX_TYPE)txk_map[idx];
+#if CONFIG_DDT_INTER
+    int is_ddtx = has_ddtx(tx_type);
+    if (!is_ddtx && !(allowed_tx_mask & (1 << tx_type))) continue;
+    if (is_ddtx && !av1_ext_tx_used[tx_set_type][tx_type]) continue;
+#else
     if (!(allowed_tx_mask & (1 << tx_type))) continue;
+#endif  // CONFIG_DDT_INTER
     txfm_param.tx_type = tx_type;
 #endif
       if (av1_use_qmatrix(&cm->quant_params, xd, mbmi->segment_id)) {
diff --git a/av1/encoder/x86/av1_fwd_txfm2d_sse4.c b/av1/encoder/x86/av1_fwd_txfm2d_sse4.c
index 8032fb7..57cb7a3 100644
--- a/av1/encoder/x86/av1_fwd_txfm2d_sse4.c
+++ b/av1/encoder/x86/av1_fwd_txfm2d_sse4.c
@@ -355,6 +355,10 @@
 void av1_lowbd_fwd_txfm_sse4_1(const int16_t *src_diff, tran_low_t *coeff,
                                int diff_stride, TxfmParam *txfm_param) {
   FwdTxfm2dFunc fwd_txfm2d_func = fwd_txfm2d_func_ls[txfm_param->tx_size];
+#if CONFIG_DDT_INTER
+  (void)fwd_txfm2d_func;  // this is added to silence a warning
+  av1_lowbd_fwd_txfm_c(src_diff, coeff, diff_stride, txfm_param);
+#else
   if ((fwd_txfm2d_func == NULL) ||
       (txfm_param->lossless && txfm_param->tx_size == TX_4X4)) {
     av1_lowbd_fwd_txfm_c(src_diff, coeff, diff_stride, txfm_param);
@@ -362,4 +366,5 @@
     fwd_txfm2d_func(src_diff, coeff, diff_stride, txfm_param->tx_type,
                     txfm_param->bd);
   }
+#endif  // CONFIG_DDT_INTER
 }
diff --git a/build/cmake/aom_config_defaults.cmake b/build/cmake/aom_config_defaults.cmake
index 78fb105..46c4535 100644
--- a/build/cmake/aom_config_defaults.cmake
+++ b/build/cmake/aom_config_defaults.cmake
@@ -206,6 +206,8 @@
 # Primary Transforms
 set_aom_config_var(CONFIG_DST7_16X16 0 NUMBER "AV2 DST7 16x16 experiment flag.")
 set_aom_config_var(CONFIG_DST_32X32 0 NUMBER "AV2 DST7 32x32 experiment flag.")
+set_aom_config_var(CONFIG_DDT_INTER 0 NUMBER
+                   "AV2 data-driven inter transform experiment flag.")
 #
 # Variables in this section control optional features of the build system.
 #
diff --git a/test/av1_fwd_txfm2d_test.cc b/test/av1_fwd_txfm2d_test.cc
index 63f6c99..9e1cf60 100644
--- a/test/av1_fwd_txfm2d_test.cc
+++ b/test/av1_fwd_txfm2d_test.cc
@@ -271,7 +271,11 @@
         }
         param.tx_type = (TX_TYPE)tx_type;
         param.tx_size = (TX_SIZE)tx_size;
+#if CONFIG_DDT_INTER
+        param.tx_set_type = EXT_TX_SET_ALL24;
+#else
         param.tx_set_type = EXT_TX_SET_ALL16;
+#endif  // CONFIG_DDT_INTER
         param.bd = bd;
         ref_func(input, ref_output, input_stride, (TX_TYPE)tx_type, bd);
         target_func(input, output, input_stride, &param);
@@ -321,7 +325,11 @@
 
         param.tx_type = (TX_TYPE)tx_type;
         param.tx_size = (TX_SIZE)tx_size;
+#if CONFIG_DDT_INTER
+        param.tx_set_type = EXT_TX_SET_ALL24;
+#else
         param.tx_set_type = EXT_TX_SET_ALL16;
+#endif  // CONFIG_DDT_INTER
         param.bd = bd;
 
         aom_usec_timer ref_timer, test_timer;
@@ -475,7 +483,11 @@
           }
           param.tx_type = (TX_TYPE)tx_type;
           param.tx_size = (TX_SIZE)tx_size;
+#if CONFIG_DDT_INTER
+          param.tx_set_type = EXT_TX_SET_ALL24;
+#else
           param.tx_set_type = EXT_TX_SET_ALL16;
+#endif  // CONFIG_DDT_INTER
           param.bd = bd;
 
           ref_func(input, ref_output, input_stride, (TX_TYPE)tx_type, bd);
@@ -529,7 +541,11 @@
 
         param.tx_type = (TX_TYPE)tx_type;
         param.tx_size = (TX_SIZE)tx_size;
+#if CONFIG_DDT_INTER
+        param.tx_set_type = EXT_TX_SET_ALL24;
+#else
         param.tx_set_type = EXT_TX_SET_ALL16;
+#endif  // CONFIG_DDT_INTER
         param.bd = bd;
 
         aom_usec_timer ref_timer, test_timer;
diff --git a/test/av1_highbd_iht_test.cc b/test/av1_highbd_iht_test.cc
index 2630655..ef275db 100644
--- a/test/av1_highbd_iht_test.cc
+++ b/test/av1_highbd_iht_test.cc
@@ -237,7 +237,11 @@
   txfm_param.tx_size = tx_size_;
   txfm_param.lossless = 0;
   txfm_param.bd = bit_depth_;
+#if CONFIG_DDT_INTER
+  txfm_param.tx_set_type = EXT_TX_SET_ALL24;
+#else
   txfm_param.tx_set_type = EXT_TX_SET_ALL16;
+#endif  // CONFIG_DDT_INTER
 
   for (int cnt = 0; cnt < randTimes; ++cnt) {
     for (int r = 0; r < BLK_WIDTH; ++r) {
diff --git a/test/av1_txfm_test.h b/test/av1_txfm_test.h
index c9c6bce..ca0a613 100644
--- a/test/av1_txfm_test.h
+++ b/test/av1_txfm_test.h
@@ -92,7 +92,11 @@
   } else if (tx_size_sqr_up == TX_32X32) {
     tx_set_type = EXT_TX_SET_DCT_IDTX;
   } else {
+#if CONFIG_DDT_INTER
+    tx_set_type = EXT_TX_SET_ALL24;
+#else
     tx_set_type = EXT_TX_SET_ALL16;
+#endif  // CONFIG_DDT_INTER
   }
   return av1_ext_tx_used[tx_set_type][tx_type] != 0;
 }
diff --git a/tools/aom_entropy_optimizer.c b/tools/aom_entropy_optimizer.c
index c190df1..ce10657 100644
--- a/tools/aom_entropy_optimizer.c
+++ b/tools/aom_entropy_optimizer.c
@@ -356,11 +356,31 @@
       "static const aom_cdf_prob default_partition_cdf[PARTITION_CONTEXTS]"
       "[CDF_SIZE(EXT_PARTITION_TYPES)]");
 
+#if CONFIG_DDT_INTER
+  cts_each_dim[0] = EXT_TX_SIZES;
+  cts_each_dim[1] = 2;
+  optimize_cdf_table(
+      &fc.use_ddtx_inter[0][0], probsfile, 2, cts_each_dim,
+      "static const aom_cdf_prob default_use_ddtx_inter[EXT_TX_SIZES]"
+      "[CDF_SIZE(2)]");
+
+  cts_each_dim[0] = EXT_TX_SIZES;
+  cts_each_dim[1] = DDT_TYPES;
+  optimize_cdf_table(&fc.ddtx_type_inter[0][0], probsfile, 2, cts_each_dim,
+                     "static const aom_cdf_prob\n"
+                     "default_ddtx_type_inter[EXT_TX_SIZES]"
+                     "[CDF_SIZE(DDT_TYPES)]");
+#endif  // CONFIG_DDT_INTER
+
   /* tx type */
   cts_each_dim[0] = EXT_TX_SETS_INTRA;
   cts_each_dim[1] = EXT_TX_SIZES;
   cts_each_dim[2] = INTRA_MODES;
+#if CONFIG_DDT_INTER
+  cts_each_dim[3] = TX_TYPES_TRIG;
+#else
   cts_each_dim[3] = TX_TYPES;
+#endif  // CONFIG_DDT_INTER
 #if CONFIG_FORWARDSKIP
   int intra_ext_tx_types_each_ctx[EXT_TX_SETS_INTRA] = { 0, INTRA_TX_SET1,
                                                          INTRA_TX_SET2 };
@@ -380,7 +400,11 @@
 
   cts_each_dim[0] = EXT_TX_SETS_INTER;
   cts_each_dim[1] = EXT_TX_SIZES;
+#if CONFIG_DDT_INTER
+  cts_each_dim[2] = TX_TYPES_TRIG;
+#else
   cts_each_dim[2] = TX_TYPES;
+#endif  // CONFIG_DDT_INTER
   int inter_ext_tx_types_each_ctx[EXT_TX_SETS_INTER] = { 0, 16, 12, 2 };
   optimize_cdf_table_var_modes_3d(
       &fc.inter_ext_tx[0][0][0], probsfile, 3, cts_each_dim,