Refactor CommonTileParams from AV1_COMMON

Also, refactor local variables/args for tiles when we can.

BUG=aomedia:2610

Change-Id: Ia07cdfb5e9351c8099199caca71f1028e83a85ed
diff --git a/av1/av1_dx_iface.c b/av1/av1_dx_iface.c
index 260a3d1..d36cb85 100644
--- a/av1/av1_dx_iface.c
+++ b/av1/av1_dx_iface.c
@@ -470,7 +470,7 @@
   // thread or loopfilter thread.
   frame_worker_data->pbi->max_threads = ctx->cfg.threads;
   frame_worker_data->pbi->inv_tile_order = ctx->invert_tile_order;
-  frame_worker_data->pbi->common.large_scale_tile = ctx->tile_mode;
+  frame_worker_data->pbi->common.tiles.large_scale = ctx->tile_mode;
   frame_worker_data->pbi->is_annexb = ctx->is_annexb;
   frame_worker_data->pbi->dec_tile_row = ctx->decode_tile_row;
   frame_worker_data->pbi->dec_tile_col = ctx->decode_tile_col;
@@ -524,7 +524,7 @@
   frame_worker_data->user_priv = user_priv;
   frame_worker_data->received_frame = 1;
 
-  frame_worker_data->pbi->common.large_scale_tile = ctx->tile_mode;
+  frame_worker_data->pbi->common.tiles.large_scale = ctx->tile_mode;
   frame_worker_data->pbi->dec_tile_row = ctx->decode_tile_row;
   frame_worker_data->pbi->dec_tile_col = ctx->decode_tile_col;
   frame_worker_data->pbi->ext_tile_debug = ctx->ext_tile_debug;
@@ -760,6 +760,7 @@
     FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
     AV1Decoder *const pbi = frame_worker_data->pbi;
     AV1_COMMON *const cm = &pbi->common;
+    CommonTileParams *const tiles = &cm->tiles;
     // Wait for the frame from worker thread.
     if (winterface->sync(worker)) {
       // Check if worker has received any frames.
@@ -778,7 +779,7 @@
         yuvconfig2image(&ctx->img, sd, frame_worker_data->user_priv);
         move_decoder_metadata_to_img(pbi, &ctx->img);
 
-        if (!pbi->ext_tile_debug && cm->large_scale_tile) {
+        if (!pbi->ext_tile_debug && tiles->large_scale) {
           *index += 1;  // Advance the iterator to point to the next image
           aom_img_remove_metadata(&ctx->img);
           yuvconfig2image(&ctx->img, &pbi->tile_list_outbuf, NULL);
@@ -788,11 +789,11 @@
         }
 
         const int num_planes = av1_num_planes(cm);
-        if (pbi->ext_tile_debug && cm->single_tile_decoding &&
+        if (pbi->ext_tile_debug && tiles->single_tile_decoding &&
             pbi->dec_tile_row >= 0) {
           int tile_width, tile_height;
           av1_get_uniform_tile_size(cm, &tile_width, &tile_height);
-          const int tile_row = AOMMIN(pbi->dec_tile_row, cm->tile_rows - 1);
+          const int tile_row = AOMMIN(pbi->dec_tile_row, tiles->rows - 1);
           const int mi_row = tile_row * tile_height;
           const int ssy = ctx->img.y_chroma_shift;
           int plane;
@@ -806,11 +807,11 @@
           ctx->img.d_h = AOMMIN(tile_height, cm->mi_rows - mi_row) * MI_SIZE;
         }
 
-        if (pbi->ext_tile_debug && cm->single_tile_decoding &&
+        if (pbi->ext_tile_debug && tiles->single_tile_decoding &&
             pbi->dec_tile_col >= 0) {
           int tile_width, tile_height;
           av1_get_uniform_tile_size(cm, &tile_width, &tile_height);
-          const int tile_col = AOMMIN(pbi->dec_tile_col, cm->tile_cols - 1);
+          const int tile_col = AOMMIN(pbi->dec_tile_col, tiles->cols - 1);
           const int mi_col = tile_col * tile_width;
           const int ssx = ctx->img.x_chroma_shift;
           const int is_hbd = (ctx->img.fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 1 : 0;
diff --git a/av1/common/alloccommon.c b/av1/common/alloccommon.c
index b31b37c..e4a3cfb 100644
--- a/av1/common/alloccommon.c
+++ b/av1/common/alloccommon.c
@@ -73,7 +73,7 @@
   // able to quickly answer the question "Where is the <n>'th stripe for tile
   // row <m>?" To make that efficient, we generate the rst_last_stripe array.
   int num_stripes = 0;
-  for (int i = 0; i < cm->tile_rows; ++i) {
+  for (int i = 0; i < cm->tiles.rows; ++i) {
     TileInfo tile_info;
     av1_tile_set_row(&tile_info, cm, i);
     const int mi_h = tile_info.mi_row_end - tile_info.mi_row_start;
diff --git a/av1/common/av1_common_int.h b/av1/common/av1_common_int.h
index ac98b34..7362fdf 100644
--- a/av1/common/av1_common_int.h
+++ b/av1/common/av1_common_int.h
@@ -336,6 +336,29 @@
   int error_resilient_mode;
 } FeatureFlags;
 
+// Struct containing params related to tiles.
+typedef struct CommonTileParams {
+  int cols;
+  int rows;
+  int max_width_sb;
+  int max_height_sb;
+  int min_log2_cols;
+  int max_log2_cols;
+  int max_log2_rows;
+  int min_log2_rows;
+  int min_log2;
+  int uniform_spacing;
+  int log2_cols;                        // only valid for uniform tiles
+  int log2_rows;                        // only valid for uniform tiles
+  int col_start_sb[MAX_TILE_COLS + 1];  // valid for 0 <= i <= tile_cols
+  int row_start_sb[MAX_TILE_ROWS + 1];  // valid for 0 <= i <= tile_rows
+  int width;                            // Width in MI units
+  int height;                           // Height in MI units
+  int min_inner_width;                  // min width of non-rightmost tile
+  unsigned int large_scale;
+  unsigned int single_tile_decoding;
+} CommonTileParams;
+
 typedef struct AV1Common {
   // Information about the current frame that is being coded.
   CurrentFrame current_frame;
@@ -540,25 +563,8 @@
   FRAME_CONTEXT *default_frame_context;
   int primary_ref_frame;
 
-  int tile_cols, tile_rows;
-
-  int max_tile_width_sb;
-  int min_log2_tile_cols;
-  int max_log2_tile_cols;
-  int max_log2_tile_rows;
-  int min_log2_tile_rows;
-  int min_log2_tiles;
-  int max_tile_height_sb;
-  int uniform_tile_spacing_flag;
-  int log2_tile_cols;                        // only valid for uniform tiles
-  int log2_tile_rows;                        // only valid for uniform tiles
-  int tile_col_start_sb[MAX_TILE_COLS + 1];  // valid for 0 <= i <= tile_cols
-  int tile_row_start_sb[MAX_TILE_ROWS + 1];  // valid for 0 <= i <= tile_rows
-  int tile_width, tile_height;               // In MI units
-  int min_inner_tile_width;                  // min width of non-rightmost tile
-
-  unsigned int large_scale_tile;
-  unsigned int single_tile_decoding;
+  // Parameters related to tiling.
+  CommonTileParams tiles;
 
   int byte_alignment;
 
diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c
index 874e2f0..3c480ac 100644
--- a/av1/common/entropymode.c
+++ b/av1/common/entropymode.c
@@ -1071,7 +1071,7 @@
   *cm->default_frame_context = *cm->fc;
   // TODO(jack.haughton@argondesign.com): don't think this should be necessary,
   // but could do with fuller testing
-  if (cm->large_scale_tile) {
+  if (cm->tiles.large_scale) {
     for (int i = LAST_FRAME; i <= ALTREF_FRAME; ++i) {
       RefCntBuffer *const buf = get_ref_frame_buf(cm, i);
       if (buf != NULL) buf->frame_context = *cm->fc;
diff --git a/av1/common/resize.c b/av1/common/resize.c
index 2f2efd8..ab9a2a0 100644
--- a/av1/common/resize.c
+++ b/av1/common/resize.c
@@ -1235,7 +1235,7 @@
   int32_t x0_qn = get_upscale_convolve_x0(downscaled_plane_width,
                                           upscaled_plane_width, x_step_qn);
 
-  for (int j = 0; j < cm->tile_cols; j++) {
+  for (int j = 0; j < cm->tiles.cols; j++) {
     av1_tile_set_col(&tile_col, cm, j);
     // Determine the limits of this tile column in both the source
     // and destination images.
@@ -1248,7 +1248,7 @@
 
     const int upscaled_x0 = (downscaled_x0 * superres_denom) / SCALE_NUMERATOR;
     int upscaled_x1;
-    if (j == cm->tile_cols - 1) {
+    if (j == cm->tiles.cols - 1) {
       // Note that we can't just use AOMMIN here - due to rounding,
       // (downscaled_x1 * superres_denom) / SCALE_NUMERATOR may be less than
       // upscaled_plane_width.
@@ -1262,7 +1262,7 @@
     const int dst_width = upscaled_x1 - upscaled_x0;
 
     const int pad_left = (j == 0);
-    const int pad_right = (j == cm->tile_cols - 1);
+    const int pad_right = (j == cm->tiles.cols - 1);
 
 #if CONFIG_AV1_HIGHBITDEPTH
     if (cm->seq_params.use_highbitdepth)
diff --git a/av1/common/tile_common.c b/av1/common/tile_common.c
index 2e4349b..4c044e6 100644
--- a/av1/common/tile_common.c
+++ b/av1/common/tile_common.c
@@ -28,102 +28,110 @@
 }
 
 void av1_get_tile_limits(AV1_COMMON *const cm) {
-  int mi_cols = ALIGN_POWER_OF_TWO(cm->mi_cols, cm->seq_params.mib_size_log2);
-  int mi_rows = ALIGN_POWER_OF_TWO(cm->mi_rows, cm->seq_params.mib_size_log2);
-  int sb_cols = mi_cols >> cm->seq_params.mib_size_log2;
-  int sb_rows = mi_rows >> cm->seq_params.mib_size_log2;
+  const SequenceHeader *const seq_params = &cm->seq_params;
+  CommonTileParams *const tiles = &cm->tiles;
+  const int mi_cols =
+      ALIGN_POWER_OF_TWO(cm->mi_cols, seq_params->mib_size_log2);
+  const int mi_rows =
+      ALIGN_POWER_OF_TWO(cm->mi_rows, seq_params->mib_size_log2);
+  const int sb_cols = mi_cols >> seq_params->mib_size_log2;
+  const int sb_rows = mi_rows >> seq_params->mib_size_log2;
 
-  int sb_size_log2 = cm->seq_params.mib_size_log2 + MI_SIZE_LOG2;
-  cm->max_tile_width_sb = MAX_TILE_WIDTH >> sb_size_log2;
-  int max_tile_area_sb = MAX_TILE_AREA >> (2 * sb_size_log2);
+  const int sb_size_log2 = seq_params->mib_size_log2 + MI_SIZE_LOG2;
+  tiles->max_width_sb = MAX_TILE_WIDTH >> sb_size_log2;
+  const int max_tile_area_sb = MAX_TILE_AREA >> (2 * sb_size_log2);
 
-  cm->min_log2_tile_cols = tile_log2(cm->max_tile_width_sb, sb_cols);
-  cm->max_log2_tile_cols = tile_log2(1, AOMMIN(sb_cols, MAX_TILE_COLS));
-  cm->max_log2_tile_rows = tile_log2(1, AOMMIN(sb_rows, MAX_TILE_ROWS));
-  cm->min_log2_tiles = tile_log2(max_tile_area_sb, sb_cols * sb_rows);
-  cm->min_log2_tiles = AOMMAX(cm->min_log2_tiles, cm->min_log2_tile_cols);
+  tiles->min_log2_cols = tile_log2(tiles->max_width_sb, sb_cols);
+  tiles->max_log2_cols = tile_log2(1, AOMMIN(sb_cols, MAX_TILE_COLS));
+  tiles->max_log2_rows = tile_log2(1, AOMMIN(sb_rows, MAX_TILE_ROWS));
+  tiles->min_log2 = tile_log2(max_tile_area_sb, sb_cols * sb_rows);
+  tiles->min_log2 = AOMMAX(tiles->min_log2, tiles->min_log2_cols);
 }
 
-void av1_calculate_tile_cols(AV1_COMMON *const cm) {
-  int mi_cols = ALIGN_POWER_OF_TWO(cm->mi_cols, cm->seq_params.mib_size_log2);
-  int mi_rows = ALIGN_POWER_OF_TWO(cm->mi_rows, cm->seq_params.mib_size_log2);
-  int sb_cols = mi_cols >> cm->seq_params.mib_size_log2;
-  int sb_rows = mi_rows >> cm->seq_params.mib_size_log2;
+void av1_calculate_tile_cols(const SequenceHeader *const seq_params,
+                             int cm_mi_rows, int cm_mi_cols,
+                             CommonTileParams *const tiles) {
+  int mi_cols = ALIGN_POWER_OF_TWO(cm_mi_cols, seq_params->mib_size_log2);
+  int mi_rows = ALIGN_POWER_OF_TWO(cm_mi_rows, seq_params->mib_size_log2);
+  int sb_cols = mi_cols >> seq_params->mib_size_log2;
+  int sb_rows = mi_rows >> seq_params->mib_size_log2;
   int i;
 
   // This will be overridden if there is at least two columns of tiles
   // (otherwise there is no inner tile width)
-  cm->min_inner_tile_width = -1;
+  tiles->min_inner_width = -1;
 
-  if (cm->uniform_tile_spacing_flag) {
+  if (tiles->uniform_spacing) {
     int start_sb;
-    int size_sb = ALIGN_POWER_OF_TWO(sb_cols, cm->log2_tile_cols);
-    size_sb >>= cm->log2_tile_cols;
+    int size_sb = ALIGN_POWER_OF_TWO(sb_cols, tiles->log2_cols);
+    size_sb >>= tiles->log2_cols;
     assert(size_sb > 0);
     for (i = 0, start_sb = 0; start_sb < sb_cols; i++) {
-      cm->tile_col_start_sb[i] = start_sb;
+      tiles->col_start_sb[i] = start_sb;
       start_sb += size_sb;
     }
-    cm->tile_cols = i;
-    cm->tile_col_start_sb[i] = sb_cols;
-    cm->min_log2_tile_rows = AOMMAX(cm->min_log2_tiles - cm->log2_tile_cols, 0);
-    cm->max_tile_height_sb = sb_rows >> cm->min_log2_tile_rows;
+    tiles->cols = i;
+    tiles->col_start_sb[i] = sb_cols;
+    tiles->min_log2_rows = AOMMAX(tiles->min_log2 - tiles->log2_cols, 0);
+    tiles->max_height_sb = sb_rows >> tiles->min_log2_rows;
 
-    cm->tile_width = size_sb << cm->seq_params.mib_size_log2;
-    cm->tile_width = AOMMIN(cm->tile_width, cm->mi_cols);
-    if (cm->tile_cols > 1) {
-      cm->min_inner_tile_width = cm->tile_width;
+    tiles->width = size_sb << seq_params->mib_size_log2;
+    tiles->width = AOMMIN(tiles->width, cm_mi_cols);
+    if (tiles->cols > 1) {
+      tiles->min_inner_width = tiles->width;
     }
   } else {
     int max_tile_area_sb = (sb_rows * sb_cols);
     int widest_tile_sb = 1;
     int narrowest_inner_tile_sb = 65536;
-    cm->log2_tile_cols = tile_log2(1, cm->tile_cols);
-    for (i = 0; i < cm->tile_cols; i++) {
-      int size_sb = cm->tile_col_start_sb[i + 1] - cm->tile_col_start_sb[i];
+    tiles->log2_cols = tile_log2(1, tiles->cols);
+    for (i = 0; i < tiles->cols; i++) {
+      int size_sb = tiles->col_start_sb[i + 1] - tiles->col_start_sb[i];
       widest_tile_sb = AOMMAX(widest_tile_sb, size_sb);
       // ignore the rightmost tile in frame for determining the narrowest
-      if (i < cm->tile_cols - 1)
+      if (i < tiles->cols - 1)
         narrowest_inner_tile_sb = AOMMIN(narrowest_inner_tile_sb, size_sb);
     }
-    if (cm->min_log2_tiles) {
-      max_tile_area_sb >>= (cm->min_log2_tiles + 1);
+    if (tiles->min_log2) {
+      max_tile_area_sb >>= (tiles->min_log2 + 1);
     }
-    cm->max_tile_height_sb = AOMMAX(max_tile_area_sb / widest_tile_sb, 1);
-    if (cm->tile_cols > 1) {
-      cm->min_inner_tile_width = narrowest_inner_tile_sb
-                                 << cm->seq_params.mib_size_log2;
+    tiles->max_height_sb = AOMMAX(max_tile_area_sb / widest_tile_sb, 1);
+    if (tiles->cols > 1) {
+      tiles->min_inner_width = narrowest_inner_tile_sb
+                               << seq_params->mib_size_log2;
     }
   }
 }
 
-void av1_calculate_tile_rows(AV1_COMMON *const cm) {
-  int mi_rows = ALIGN_POWER_OF_TWO(cm->mi_rows, cm->seq_params.mib_size_log2);
-  int sb_rows = mi_rows >> cm->seq_params.mib_size_log2;
+void av1_calculate_tile_rows(const SequenceHeader *const seq_params,
+                             int cm_mi_rows, CommonTileParams *const tiles) {
+  int mi_rows = ALIGN_POWER_OF_TWO(cm_mi_rows, seq_params->mib_size_log2);
+  int sb_rows = mi_rows >> seq_params->mib_size_log2;
   int start_sb, size_sb, i;
 
-  if (cm->uniform_tile_spacing_flag) {
-    size_sb = ALIGN_POWER_OF_TWO(sb_rows, cm->log2_tile_rows);
-    size_sb >>= cm->log2_tile_rows;
+  if (tiles->uniform_spacing) {
+    size_sb = ALIGN_POWER_OF_TWO(sb_rows, tiles->log2_rows);
+    size_sb >>= tiles->log2_rows;
     assert(size_sb > 0);
     for (i = 0, start_sb = 0; start_sb < sb_rows; i++) {
-      cm->tile_row_start_sb[i] = start_sb;
+      tiles->row_start_sb[i] = start_sb;
       start_sb += size_sb;
     }
-    cm->tile_rows = i;
-    cm->tile_row_start_sb[i] = sb_rows;
+    tiles->rows = i;
+    tiles->row_start_sb[i] = sb_rows;
 
-    cm->tile_height = size_sb << cm->seq_params.mib_size_log2;
-    cm->tile_height = AOMMIN(cm->tile_height, cm->mi_rows);
+    tiles->height = size_sb << seq_params->mib_size_log2;
+    tiles->height = AOMMIN(tiles->height, cm_mi_rows);
   } else {
-    cm->log2_tile_rows = tile_log2(1, cm->tile_rows);
+    tiles->log2_rows = tile_log2(1, tiles->rows);
   }
 }
 
 void av1_tile_set_row(TileInfo *tile, const AV1_COMMON *cm, int row) {
-  assert(row < cm->tile_rows);
-  int mi_row_start = cm->tile_row_start_sb[row] << cm->seq_params.mib_size_log2;
-  int mi_row_end = cm->tile_row_start_sb[row + 1]
+  assert(row < cm->tiles.rows);
+  int mi_row_start = cm->tiles.row_start_sb[row]
+                     << cm->seq_params.mib_size_log2;
+  int mi_row_end = cm->tiles.row_start_sb[row + 1]
                    << cm->seq_params.mib_size_log2;
   tile->tile_row = row;
   tile->mi_row_start = mi_row_start;
@@ -132,9 +140,10 @@
 }
 
 void av1_tile_set_col(TileInfo *tile, const AV1_COMMON *cm, int col) {
-  assert(col < cm->tile_cols);
-  int mi_col_start = cm->tile_col_start_sb[col] << cm->seq_params.mib_size_log2;
-  int mi_col_end = cm->tile_col_start_sb[col + 1]
+  assert(col < cm->tiles.cols);
+  int mi_col_start = cm->tiles.col_start_sb[col]
+                     << cm->seq_params.mib_size_log2;
+  int mi_col_end = cm->tiles.col_start_sb[col + 1]
                    << cm->seq_params.mib_size_log2;
   tile->tile_col = col;
   tile->mi_col_start = mi_col_start;
@@ -198,21 +207,22 @@
 }
 
 void av1_get_uniform_tile_size(const AV1_COMMON *cm, int *w, int *h) {
-  if (cm->uniform_tile_spacing_flag) {
-    *w = cm->tile_width;
-    *h = cm->tile_height;
+  const CommonTileParams *const tiles = &cm->tiles;
+  if (tiles->uniform_spacing) {
+    *w = tiles->width;
+    *h = tiles->height;
   } else {
-    for (int i = 0; i < cm->tile_cols; ++i) {
+    for (int i = 0; i < tiles->cols; ++i) {
       const int tile_width_sb =
-          cm->tile_col_start_sb[i + 1] - cm->tile_col_start_sb[i];
+          tiles->col_start_sb[i + 1] - tiles->col_start_sb[i];
       const int tile_w = tile_width_sb * cm->seq_params.mib_size;
       assert(i == 0 || tile_w == *w);  // ensure all tiles have same dimension
       *w = tile_w;
     }
 
-    for (int i = 0; i < cm->tile_rows; ++i) {
+    for (int i = 0; i < tiles->rows; ++i) {
       const int tile_height_sb =
-          cm->tile_row_start_sb[i + 1] - cm->tile_row_start_sb[i];
+          tiles->row_start_sb[i + 1] - tiles->row_start_sb[i];
       const int tile_h = tile_height_sb * cm->seq_params.mib_size;
       assert(i == 0 || tile_h == *h);  // ensure all tiles have same dimension
       *h = tile_h;
@@ -222,8 +232,8 @@
 
 int av1_is_min_tile_width_satisfied(const AV1_COMMON *cm) {
   // Disable check if there is a single tile col in the frame
-  if (cm->tile_cols == 1) return 1;
+  if (cm->tiles.cols == 1) return 1;
 
-  return ((cm->min_inner_tile_width << MI_SIZE_LOG2) >=
+  return ((cm->tiles.min_inner_width << MI_SIZE_LOG2) >=
           (64 << av1_superres_scaled(cm)));
 }
diff --git a/av1/common/tile_common.h b/av1/common/tile_common.h
index 0f3d1aa..4469e9e 100644
--- a/av1/common/tile_common.h
+++ b/av1/common/tile_common.h
@@ -19,6 +19,8 @@
 #include "config/aom_config.h"
 
 struct AV1Common;
+struct SequenceHeader;
+struct CommonTileParams;
 
 #define DEFAULT_MAX_NUM_TG 1
 
@@ -56,8 +58,11 @@
 
 void av1_get_uniform_tile_size(const struct AV1Common *cm, int *w, int *h);
 void av1_get_tile_limits(struct AV1Common *const cm);
-void av1_calculate_tile_cols(struct AV1Common *const cm);
-void av1_calculate_tile_rows(struct AV1Common *const cm);
+void av1_calculate_tile_cols(const struct SequenceHeader *seq_params,
+                             int cm_mi_rows, int cm_mi_cols,
+                             struct CommonTileParams *tiles);
+void av1_calculate_tile_rows(const struct SequenceHeader *seq_params,
+                             int cm_mi_rows, struct CommonTileParams *tiles);
 
 // Checks if the minimum tile_width requirement is satisfied
 int av1_is_min_tile_width_satisfied(const struct AV1Common *cm);
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index a37fc99..dca1a13 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -2335,66 +2335,68 @@
 
 static AOM_INLINE void read_tile_info_max_tile(
     AV1_COMMON *const cm, struct aom_read_bit_buffer *const rb) {
-  int width_mi = ALIGN_POWER_OF_TWO(cm->mi_cols, cm->seq_params.mib_size_log2);
-  int height_mi = ALIGN_POWER_OF_TWO(cm->mi_rows, cm->seq_params.mib_size_log2);
-  int width_sb = width_mi >> cm->seq_params.mib_size_log2;
-  int height_sb = height_mi >> cm->seq_params.mib_size_log2;
+  const SequenceHeader *const seq_params = &cm->seq_params;
+  CommonTileParams *const tiles = &cm->tiles;
+  int width_mi = ALIGN_POWER_OF_TWO(cm->mi_cols, seq_params->mib_size_log2);
+  int height_mi = ALIGN_POWER_OF_TWO(cm->mi_rows, seq_params->mib_size_log2);
+  int width_sb = width_mi >> seq_params->mib_size_log2;
+  int height_sb = height_mi >> seq_params->mib_size_log2;
 
   av1_get_tile_limits(cm);
-  cm->uniform_tile_spacing_flag = aom_rb_read_bit(rb);
+  tiles->uniform_spacing = aom_rb_read_bit(rb);
 
   // Read tile columns
-  if (cm->uniform_tile_spacing_flag) {
-    cm->log2_tile_cols = cm->min_log2_tile_cols;
-    while (cm->log2_tile_cols < cm->max_log2_tile_cols) {
+  if (tiles->uniform_spacing) {
+    tiles->log2_cols = tiles->min_log2_cols;
+    while (tiles->log2_cols < tiles->max_log2_cols) {
       if (!aom_rb_read_bit(rb)) {
         break;
       }
-      cm->log2_tile_cols++;
+      tiles->log2_cols++;
     }
   } else {
     int i;
     int start_sb;
     for (i = 0, start_sb = 0; width_sb > 0 && i < MAX_TILE_COLS; i++) {
       const int size_sb =
-          1 + rb_read_uniform(rb, AOMMIN(width_sb, cm->max_tile_width_sb));
-      cm->tile_col_start_sb[i] = start_sb;
+          1 + rb_read_uniform(rb, AOMMIN(width_sb, tiles->max_width_sb));
+      tiles->col_start_sb[i] = start_sb;
       start_sb += size_sb;
       width_sb -= size_sb;
     }
-    cm->tile_cols = i;
-    cm->tile_col_start_sb[i] = start_sb + width_sb;
+    tiles->cols = i;
+    tiles->col_start_sb[i] = start_sb + width_sb;
   }
-  av1_calculate_tile_cols(cm);
+  av1_calculate_tile_cols(seq_params, cm->mi_rows, cm->mi_cols, tiles);
 
   // Read tile rows
-  if (cm->uniform_tile_spacing_flag) {
-    cm->log2_tile_rows = cm->min_log2_tile_rows;
-    while (cm->log2_tile_rows < cm->max_log2_tile_rows) {
+  if (tiles->uniform_spacing) {
+    tiles->log2_rows = tiles->min_log2_rows;
+    while (tiles->log2_rows < tiles->max_log2_rows) {
       if (!aom_rb_read_bit(rb)) {
         break;
       }
-      cm->log2_tile_rows++;
+      tiles->log2_rows++;
     }
   } else {
     int i;
     int start_sb;
     for (i = 0, start_sb = 0; height_sb > 0 && i < MAX_TILE_ROWS; i++) {
       const int size_sb =
-          1 + rb_read_uniform(rb, AOMMIN(height_sb, cm->max_tile_height_sb));
-      cm->tile_row_start_sb[i] = start_sb;
+          1 + rb_read_uniform(rb, AOMMIN(height_sb, tiles->max_height_sb));
+      tiles->row_start_sb[i] = start_sb;
       start_sb += size_sb;
       height_sb -= size_sb;
     }
-    cm->tile_rows = i;
-    cm->tile_row_start_sb[i] = start_sb + height_sb;
+    tiles->rows = i;
+    tiles->row_start_sb[i] = start_sb + height_sb;
   }
-  av1_calculate_tile_rows(cm);
+  av1_calculate_tile_rows(seq_params, cm->mi_rows, tiles);
 }
 
 void av1_set_single_tile_decoding_mode(AV1_COMMON *const cm) {
-  cm->single_tile_decoding = 0;
-  if (cm->large_scale_tile) {
+  cm->tiles.single_tile_decoding = 0;
+  if (cm->tiles.large_scale) {
     struct loopfilter *lf = &cm->lf;
     RestorationInfo *const rst_info = cm->rst_info;
     const CdefInfo *const cdef_info = &cm->cdef_info;
@@ -2410,7 +2412,7 @@
         rst_info[2].frame_restoration_type == RESTORE_NONE;
     assert(IMPLIES(cm->features.coded_lossless, no_loopfilter && no_cdef));
     assert(IMPLIES(cm->features.all_lossless, no_restoration));
-    cm->single_tile_decoding = no_loopfilter && no_cdef && no_restoration;
+    cm->tiles.single_tile_decoding = no_loopfilter && no_cdef && no_restoration;
   }
 }
 
@@ -2421,11 +2423,11 @@
   read_tile_info_max_tile(cm, rb);
 
   pbi->context_update_tile_id = 0;
-  if (cm->tile_rows * cm->tile_cols > 1) {
+  if (cm->tiles.rows * cm->tiles.cols > 1) {
     // tile to use for cdf update
     pbi->context_update_tile_id =
-        aom_rb_read_literal(rb, cm->log2_tile_rows + cm->log2_tile_cols);
-    if (pbi->context_update_tile_id >= cm->tile_rows * cm->tile_cols) {
+        aom_rb_read_literal(rb, cm->tiles.log2_rows + cm->tiles.log2_cols);
+    if (pbi->context_update_tile_id >= cm->tiles.rows * cm->tiles.cols) {
       aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
                          "Invalid context_update_tile_id");
     }
@@ -2444,7 +2446,7 @@
   if (mod > 0) aom_rb_read_literal(rb, CHAR_BIT - mod);
   assert(rb->bit_offset % CHAR_BIT == 0);
 
-  if (cm->tile_cols * cm->tile_rows > 1) {
+  if (cm->tiles.cols * cm->tiles.rows > 1) {
     // Read the number of bytes used to store tile size
     pbi->tile_col_size_bytes = aom_rb_read_literal(rb, 2) + 1;
     pbi->tile_size_bytes = aom_rb_read_literal(rb, 2) + 1;
@@ -2512,13 +2514,13 @@
 }
 
 // Returns the end of the last tile buffer
-// (tile_buffers[cm->tile_rows - 1][cm->tile_cols - 1]).
+// (tile_buffers[cm->tiles.rows - 1][cm->tiles.cols - 1]).
 static const uint8_t *get_ls_tile_buffers(
     AV1Decoder *pbi, const uint8_t *data, const uint8_t *data_end,
     TileBufferDec (*const tile_buffers)[MAX_TILE_COLS]) {
   AV1_COMMON *const cm = &pbi->common;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  const int tile_cols = cm->tiles.cols;
+  const int tile_rows = cm->tiles.rows;
   const int have_tiles = tile_cols * tile_rows > 1;
   const uint8_t *raw_data_end;  // The end of the last tile buffer
 
@@ -2645,8 +2647,8 @@
     TileBufferDec (*const tile_buffers)[MAX_TILE_COLS], int start_tile,
     int end_tile) {
   AV1_COMMON *const cm = &pbi->common;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  const int tile_cols = cm->tiles.cols;
+  const int tile_rows = cm->tiles.rows;
   int tc = 0;
 
   for (int r = 0; r < tile_rows; ++r) {
@@ -2838,7 +2840,7 @@
   AV1_COMMON *const cm = &pbi->common;
   const int num_planes = av1_num_planes(cm);
   TileDataDec *const tile_data =
-      pbi->tile_data + tile_info.tile_row * cm->tile_cols + tile_info.tile_col;
+      pbi->tile_data + tile_info.tile_row * cm->tiles.cols + tile_info.tile_col;
   const int sb_cols_in_tile = av1_get_sb_cols_in_tile(cm, tile_info);
   const int sb_row_in_tile =
       (mi_row - tile_info.mi_row_start) >> cm->seq_params.mib_size_log2;
@@ -2948,8 +2950,9 @@
                                    int end_tile) {
   AV1_COMMON *const cm = &pbi->common;
   ThreadData *const td = &pbi->td;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  CommonTileParams *const tiles = &cm->tiles;
+  const int tile_cols = tiles->cols;
+  const int tile_rows = tiles->rows;
   const int n_tiles = tile_cols * tile_rows;
   TileBufferDec(*const tile_buffers)[MAX_TILE_COLS] = pbi->tile_buffers;
   const int dec_tile_row = AOMMIN(pbi->dec_tile_row, tile_rows);
@@ -2966,7 +2969,7 @@
   uint8_t allow_update_cdf;
   const uint8_t *raw_data_end = NULL;
 
-  if (cm->large_scale_tile) {
+  if (tiles->large_scale) {
     tile_rows_start = single_row ? dec_tile_row : 0;
     tile_rows_end = single_row ? dec_tile_row + 1 : tile_rows;
     tile_cols_start = single_col ? dec_tile_col : 0;
@@ -2987,9 +2990,9 @@
   // No tiles to decode.
   if (tile_rows_end <= tile_rows_start || tile_cols_end <= tile_cols_start ||
       // First tile is larger than end_tile.
-      tile_rows_start * cm->tile_cols + tile_cols_start > end_tile ||
+      tile_rows_start * tiles->cols + tile_cols_start > end_tile ||
       // Last tile is smaller than start_tile.
-      (tile_rows_end - 1) * cm->tile_cols + tile_cols_end - 1 < start_tile)
+      (tile_rows_end - 1) * tiles->cols + tile_cols_end - 1 < start_tile)
     return data;
 
   allow_update_cdf = allow_update_cdf && !cm->features.disable_cdf_update;
@@ -2998,9 +3001,9 @@
   assert(tile_cols <= MAX_TILE_COLS);
 
 #if EXT_TILE_DEBUG
-  if (cm->large_scale_tile && !pbi->ext_tile_debug)
+  if (tiles->large_scale && !pbi->ext_tile_debug)
     raw_data_end = get_ls_single_tile_buffer(pbi, data, tile_buffers);
-  else if (cm->large_scale_tile && pbi->ext_tile_debug)
+  else if (tiles->large_scale && pbi->ext_tile_debug)
     raw_data_end = get_ls_tile_buffers(pbi, data, data_end, tile_buffers);
   else
 #endif  // EXT_TILE_DEBUG
@@ -3032,11 +3035,11 @@
 
     for (tile_col = tile_cols_start; tile_col < tile_cols_end; ++tile_col) {
       const int col = inv_col_order ? tile_cols - 1 - tile_col : tile_col;
-      TileDataDec *const tile_data = pbi->tile_data + row * cm->tile_cols + col;
+      TileDataDec *const tile_data = pbi->tile_data + row * tiles->cols + col;
       const TileBufferDec *const tile_bs_buf = &tile_buffers[row][col];
 
-      if (row * cm->tile_cols + col < start_tile ||
-          row * cm->tile_cols + col > end_tile)
+      if (row * tiles->cols + col < start_tile ||
+          row * tiles->cols + col > end_tile)
         continue;
 
       td->bit_reader = &tile_data->bit_reader;
@@ -3070,7 +3073,7 @@
     }
   }
 
-  if (cm->large_scale_tile) {
+  if (tiles->large_scale) {
     if (n_tiles == 1) {
       // Find the end of the single tile buffer
       return aom_reader_find_end(&pbi->tile_data->bit_reader);
@@ -3157,12 +3160,12 @@
   }
   thread_data->error_info.setjmp = 1;
 
-  allow_update_cdf = cm->large_scale_tile ? 0 : 1;
+  allow_update_cdf = cm->tiles.large_scale ? 0 : 1;
   allow_update_cdf = allow_update_cdf && !cm->features.disable_cdf_update;
 
   set_decode_func_pointers(td, 0x3);
 
-  assert(cm->tile_cols > 0);
+  assert(cm->tiles.cols > 0);
   while (!td->xd.corrupted) {
     TileJobsDec *cur_job_info = get_dec_job_info(&pbi->tile_mt_info);
 
@@ -3252,11 +3255,11 @@
        ++tile_row_idx) {
     for (tile_col_idx = tile_cols_start; tile_col_idx < tile_cols_end;
          ++tile_col_idx) {
-      if (tile_row_idx * cm->tile_cols + tile_col_idx < start_tile ||
-          tile_row_idx * cm->tile_cols + tile_col_idx > end_tile)
+      if (tile_row_idx * cm->tiles.cols + tile_col_idx < start_tile ||
+          tile_row_idx * cm->tiles.cols + tile_col_idx > end_tile)
         continue;
 
-      tile_data = pbi->tile_data + tile_row_idx * cm->tile_cols + tile_col_idx;
+      tile_data = pbi->tile_data + tile_row_idx * cm->tiles.cols + tile_col_idx;
       dec_row_mt_sync = &tile_data->dec_row_mt_sync;
 
       num_threads_working = dec_row_mt_sync->num_threads_working;
@@ -3289,7 +3292,7 @@
   // No job found to process
   if (tile_row == -1 || tile_col == -1) return 0;
 
-  tile_data = pbi->tile_data + tile_row * cm->tile_cols + tile_col;
+  tile_data = pbi->tile_data + tile_row * cm->tiles.cols + tile_col;
   tile_info = tile_data->tile_info;
   dec_row_mt_sync = &tile_data->dec_row_mt_sync;
 
@@ -3402,12 +3405,12 @@
   }
   thread_data->error_info.setjmp = 1;
 
-  allow_update_cdf = cm->large_scale_tile ? 0 : 1;
+  allow_update_cdf = cm->tiles.large_scale ? 0 : 1;
   allow_update_cdf = allow_update_cdf && !cm->features.disable_cdf_update;
 
   set_decode_func_pointers(td, 0x1);
 
-  assert(cm->tile_cols > 0);
+  assert(cm->tiles.cols > 0);
   while (!td->xd.corrupted) {
     TileJobsDec *cur_job_info = get_dec_job_info(&pbi->tile_mt_info);
 
@@ -3475,7 +3478,7 @@
     int mi_row = next_job_info.mi_row;
 
     TileDataDec *tile_data =
-        pbi->tile_data + tile_row * cm->tile_cols + tile_col;
+        pbi->tile_data + tile_row * cm->tiles.cols + tile_col;
     AV1DecRowMTSync *dec_row_mt_sync = &tile_data->dec_row_mt_sync;
     TileInfo tile_info = tile_data->tile_info;
 
@@ -3515,11 +3518,11 @@
 
   for (int row = tile_rows_start; row < tile_rows_end; row++) {
     for (int col = tile_cols_start; col < tile_cols_end; col++) {
-      if (row * cm->tile_cols + col < start_tile ||
-          row * cm->tile_cols + col > end_tile)
+      if (row * cm->tiles.cols + col < start_tile ||
+          row * cm->tiles.cols + col > end_tile)
         continue;
       tile_job_queue->tile_buffer = &pbi->tile_buffers[row][col];
-      tile_job_queue->tile_data = pbi->tile_data + row * cm->tile_cols + col;
+      tile_job_queue->tile_data = pbi->tile_data + row * cm->tiles.cols + col;
       tile_job_queue++;
       tile_mt_info->jobs_enqueued++;
     }
@@ -3725,8 +3728,9 @@
                                       const uint8_t *data_end, int start_tile,
                                       int end_tile) {
   AV1_COMMON *const cm = &pbi->common;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  CommonTileParams *const tiles = &cm->tiles;
+  const int tile_cols = tiles->cols;
+  const int tile_rows = tiles->rows;
   const int n_tiles = tile_cols * tile_rows;
   TileBufferDec(*const tile_buffers)[MAX_TILE_COLS] = pbi->tile_buffers;
   const int dec_tile_row = AOMMIN(pbi->dec_tile_row, tile_rows);
@@ -3741,7 +3745,7 @@
   int num_workers;
   const uint8_t *raw_data_end = NULL;
 
-  if (cm->large_scale_tile) {
+  if (tiles->large_scale) {
     tile_rows_start = single_row ? dec_tile_row : 0;
     tile_rows_end = single_row ? dec_tile_row + 1 : tile_rows;
     tile_cols_start = single_col ? dec_tile_col : 0;
@@ -3774,8 +3778,8 @@
 
   // get tile size in tile group
 #if EXT_TILE_DEBUG
-  if (cm->large_scale_tile) assert(pbi->ext_tile_debug == 1);
-  if (cm->large_scale_tile)
+  if (tiles->large_scale) assert(pbi->ext_tile_debug == 1);
+  if (tiles->large_scale)
     raw_data_end = get_ls_tile_buffers(pbi, data, data_end, tile_buffers);
   else
 #endif  // EXT_TILE_DEBUG
@@ -3787,7 +3791,7 @@
 
   for (int row = 0; row < tile_rows; row++) {
     for (int col = 0; col < tile_cols; col++) {
-      TileDataDec *tile_data = pbi->tile_data + row * cm->tile_cols + col;
+      TileDataDec *tile_data = pbi->tile_data + row * tiles->cols + col;
       av1_tile_init(&tile_data->tile_info, cm, row, col);
     }
   }
@@ -3803,7 +3807,7 @@
     aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
                        "Failed to decode tile data");
 
-  if (cm->large_scale_tile) {
+  if (tiles->large_scale) {
     if (n_tiles == 1) {
       // Find the end of the single tile buffer
       return aom_reader_find_end(&pbi->tile_data->bit_reader);
@@ -3850,12 +3854,12 @@
 
   for (int tile_row = tile_rows_start; tile_row < tile_rows_end; ++tile_row) {
     for (int tile_col = tile_cols_start; tile_col < tile_cols_end; ++tile_col) {
-      if (tile_row * cm->tile_cols + tile_col < start_tile ||
-          tile_row * cm->tile_cols + tile_col > end_tile)
+      if (tile_row * cm->tiles.cols + tile_col < start_tile ||
+          tile_row * cm->tiles.cols + tile_col > end_tile)
         continue;
 
       TileDataDec *const tile_data =
-          pbi->tile_data + tile_row * cm->tile_cols + tile_col;
+          pbi->tile_data + tile_row * cm->tiles.cols + tile_col;
       TileInfo tile_info = tile_data->tile_info;
 
       tile_data->dec_row_mt_sync.mi_rows_parse_done = 0;
@@ -3900,8 +3904,9 @@
                                           const uint8_t *data_end,
                                           int start_tile, int end_tile) {
   AV1_COMMON *const cm = &pbi->common;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  CommonTileParams *const tiles = &cm->tiles;
+  const int tile_cols = tiles->cols;
+  const int tile_rows = tiles->rows;
   const int n_tiles = tile_cols * tile_rows;
   TileBufferDec(*const tile_buffers)[MAX_TILE_COLS] = pbi->tile_buffers;
   const int dec_tile_row = AOMMIN(pbi->dec_tile_row, tile_rows);
@@ -3918,7 +3923,7 @@
   const uint8_t *raw_data_end = NULL;
   int max_sb_rows = 0;
 
-  if (cm->large_scale_tile) {
+  if (tiles->large_scale) {
     tile_rows_start = single_row ? dec_tile_row : 0;
     tile_rows_end = single_row ? dec_tile_row + 1 : tile_rows;
     tile_cols_start = single_col ? dec_tile_col : 0;
@@ -3953,8 +3958,8 @@
 
   // get tile size in tile group
 #if EXT_TILE_DEBUG
-  if (cm->large_scale_tile) assert(pbi->ext_tile_debug == 1);
-  if (cm->large_scale_tile)
+  if (tiles->large_scale) assert(pbi->ext_tile_debug == 1);
+  if (tiles->large_scale)
     raw_data_end = get_ls_tile_buffers(pbi, data, data_end, tile_buffers);
   else
 #endif  // EXT_TILE_DEBUG
@@ -3970,7 +3975,7 @@
 
   for (int row = 0; row < tile_rows; row++) {
     for (int col = 0; col < tile_cols; col++) {
-      TileDataDec *tile_data = pbi->tile_data + row * cm->tile_cols + col;
+      TileDataDec *tile_data = pbi->tile_data + row * tiles->cols + col;
       av1_tile_init(&tile_data->tile_info, cm, row, col);
 
       max_sb_rows = AOMMAX(max_sb_rows,
@@ -4005,7 +4010,7 @@
     aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
                        "Failed to decode tile data");
 
-  if (cm->large_scale_tile) {
+  if (tiles->large_scale) {
     if (n_tiles == 1) {
       // Find the end of the single tile buffer
       return aom_reader_find_end(&pbi->tile_data->bit_reader);
@@ -5152,9 +5157,9 @@
 
   if (cm->num_allocated_above_context_planes < av1_num_planes(cm) ||
       cm->num_allocated_above_context_mi_col < cm->mi_cols ||
-      cm->num_allocated_above_contexts < cm->tile_rows) {
+      cm->num_allocated_above_contexts < cm->tiles.rows) {
     av1_free_above_context_buffers(cm, cm->num_allocated_above_contexts);
-    if (av1_alloc_above_context_buffers(cm, cm->tile_rows))
+    if (av1_alloc_above_context_buffers(cm, cm->tiles.rows))
       aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
                          "Failed to allocate context buffers");
   }
@@ -5244,7 +5249,7 @@
   read_film_grain(cm, rb);
 
 #if EXT_TILE_DEBUG
-  if (pbi->ext_tile_debug && cm->large_scale_tile) {
+  if (pbi->ext_tile_debug && cm->tiles.large_scale) {
     read_ext_tile_info(pbi, rb);
     av1_set_single_tile_decoding_mode(cm);
   }
@@ -5311,9 +5316,9 @@
 
   if (trailing_bits_present) av1_check_trailing_bits(pbi, rb);
 
-  // If cm->single_tile_decoding = 0, the independent decoding of a single tile
-  // or a section of a frame is not allowed.
-  if (!cm->single_tile_decoding &&
+  // If cm->tiles.single_tile_decoding = 0, the independent decoding of a single
+  // tile or a section of a frame is not allowed.
+  if (!cm->tiles.single_tile_decoding &&
       (pbi->dec_tile_row >= 0 || pbi->dec_tile_col >= 0)) {
     pbi->dec_tile_row = -1;
     pbi->dec_tile_col = -1;
@@ -5384,6 +5389,7 @@
                                     const uint8_t **p_data_end, int start_tile,
                                     int end_tile, int initialize_flag) {
   AV1_COMMON *const cm = &pbi->common;
+  CommonTileParams *const tiles = &cm->tiles;
   MACROBLOCKD *const xd = &pbi->mb;
   const int tile_count_tg = end_tile - start_tile + 1;
 
@@ -5393,12 +5399,12 @@
   av1_loop_filter_frame_init(cm, 0, num_planes);
 #endif
 
-  if (pbi->max_threads > 1 && !(cm->large_scale_tile && !pbi->ext_tile_debug) &&
+  if (pbi->max_threads > 1 && !(tiles->large_scale && !pbi->ext_tile_debug) &&
       pbi->row_mt)
     *p_data_end =
         decode_tiles_row_mt(pbi, data, data_end, start_tile, end_tile);
   else if (pbi->max_threads > 1 && tile_count_tg > 1 &&
-           !(cm->large_scale_tile && !pbi->ext_tile_debug))
+           !(tiles->large_scale && !pbi->ext_tile_debug))
     *p_data_end = decode_tiles_mt(pbi, data, data_end, start_tile, end_tile);
   else
     *p_data_end = decode_tiles(pbi, data, data_end, start_tile, end_tile);
@@ -5408,11 +5414,11 @@
     set_planes_to_neutral_grey(&cm->seq_params, xd->cur_buf, 1);
   }
 
-  if (end_tile != cm->tile_rows * cm->tile_cols - 1) {
+  if (end_tile != tiles->rows * tiles->cols - 1) {
     return;
   }
 
-  if (!cm->features.allow_intrabc && !cm->single_tile_decoding) {
+  if (!cm->features.allow_intrabc && !tiles->single_tile_decoding) {
     if (cm->lf.filter_level[0] || cm->lf.filter_level[1]) {
       if (pbi->num_workers > 1) {
         av1_loop_filter_frame_mt(
@@ -5503,7 +5509,7 @@
 #endif
 
   // Non frame parallel update frame context here.
-  if (!cm->large_scale_tile) {
+  if (!tiles->large_scale) {
     cm->cur_frame->frame_context = *cm->fc;
   }
 }
diff --git a/av1/decoder/obu.c b/av1/decoder/obu.c
index 9bbd40c..0b6fb5d 100644
--- a/av1/decoder/obu.c
+++ b/av1/decoder/obu.c
@@ -278,11 +278,12 @@
                                       int *start_tile, int *end_tile,
                                       int tile_start_implicit) {
   AV1_COMMON *const cm = &pbi->common;
+  CommonTileParams *const tiles = &cm->tiles;
   uint32_t saved_bit_offset = rb->bit_offset;
   int tile_start_and_end_present_flag = 0;
-  const int num_tiles = pbi->common.tile_rows * pbi->common.tile_cols;
+  const int num_tiles = tiles->rows * tiles->cols;
 
-  if (!pbi->common.large_scale_tile && num_tiles > 1) {
+  if (!tiles->large_scale && num_tiles > 1) {
     tile_start_and_end_present_flag = aom_rb_read_bit(rb);
     if (tile_start_implicit && tile_start_and_end_present_flag) {
       aom_internal_error(
@@ -291,12 +292,12 @@
       return -1;
     }
   }
-  if (pbi->common.large_scale_tile || num_tiles == 1 ||
+  if (tiles->large_scale || num_tiles == 1 ||
       !tile_start_and_end_present_flag) {
     *start_tile = 0;
     *end_tile = num_tiles - 1;
   } else {
-    int tile_bits = cm->log2_tile_rows + cm->log2_tile_cols;
+    int tile_bits = tiles->log2_rows + tiles->log2_cols;
     *start_tile = aom_rb_read_literal(rb, tile_bits);
     *end_tile = aom_rb_read_literal(rb, tile_bits);
   }
@@ -346,7 +347,7 @@
 
   tg_payload_size = (uint32_t)(*p_data_end - data);
 
-  *is_last_tg = end_tile == cm->tile_rows * cm->tile_cols - 1;
+  *is_last_tg = end_tile == cm->tiles.rows * cm->tiles.cols - 1;
   return header_size + tg_payload_size;
 }
 
@@ -474,7 +475,7 @@
                                               int *frame_decoding_finished) {
   AV1_COMMON *const cm = &pbi->common;
   uint32_t tile_list_payload_size = 0;
-  const int num_tiles = cm->tile_cols * cm->tile_rows;
+  const int num_tiles = cm->tiles.cols * cm->tiles.rows;
   const int start_tile = 0;
   const int end_tile = num_tiles - 1;
   int i = 0;
@@ -516,8 +517,8 @@
     pbi->dec_tile_row = aom_rb_read_literal(rb, 8);
     pbi->dec_tile_col = aom_rb_read_literal(rb, 8);
     if (pbi->dec_tile_row < 0 || pbi->dec_tile_col < 0 ||
-        pbi->dec_tile_row >= cm->tile_rows ||
-        pbi->dec_tile_col >= cm->tile_cols) {
+        pbi->dec_tile_row >= cm->tiles.rows ||
+        pbi->dec_tile_col >= cm->tiles.cols) {
       cm->error.error_code = AOM_CODEC_CORRUPT_FRAME;
       return 0;
     }
@@ -860,8 +861,8 @@
     return -1;
   }
 
-  // Reset pbi->camera_frame_header_ready to 0 if cm->large_scale_tile = 0.
-  if (!cm->large_scale_tile) pbi->camera_frame_header_ready = 0;
+  // Reset pbi->camera_frame_header_ready to 0 if cm->tiles.large_scale = 0.
+  if (!cm->tiles.large_scale) pbi->camera_frame_header_ready = 0;
 
   // decode frame as a series of OBUs
   while (!frame_decoding_finished && cm->error.error_code == AOM_CODEC_OK) {
@@ -947,11 +948,11 @@
         }
         // Only decode first frame header received
         if (!pbi->seen_frame_header ||
-            (cm->large_scale_tile && !pbi->camera_frame_header_ready)) {
+            (cm->tiles.large_scale && !pbi->camera_frame_header_ready)) {
           frame_header_size = read_frame_header_obu(
               pbi, &rb, data, p_data_end, obu_header.type != OBU_FRAME);
           pbi->seen_frame_header = 1;
-          if (!pbi->ext_tile_debug && cm->large_scale_tile)
+          if (!pbi->ext_tile_debug && cm->tiles.large_scale)
             pbi->camera_frame_header_ready = 1;
         } else {
           // TODO(wtc): Verify that the frame_header_obu is identical to the
@@ -1029,7 +1030,7 @@
           return -1;
         }
 
-        cm->large_scale_tile = 1;
+        cm->tiles.large_scale = 1;
         av1_set_single_tile_decoding_mode(cm);
         decoded_payload_size =
             read_and_decode_one_tile_list(pbi, &rb, data, data + payload_size,
diff --git a/av1/encoder/av1_multi_thread.c b/av1/encoder/av1_multi_thread.c
index 1260c7a..d170b0c 100644
--- a/av1/encoder/av1_multi_thread.c
+++ b/av1/encoder/av1_multi_thread.c
@@ -19,8 +19,8 @@
   struct AV1Common *cm = &cpi->common;
   MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
   int tile_row, tile_col;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  const int tile_cols = cm->tiles.cols;
+  const int tile_rows = cm->tiles.rows;
 
   multi_thread_ctxt->allocated_tile_cols = tile_cols;
   multi_thread_ctxt->allocated_tile_rows = tile_rows;
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 841f9b4..7c35623 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -2125,43 +2125,43 @@
   int width_sb = width_mi >> cm->seq_params.mib_size_log2;
   int height_sb = height_mi >> cm->seq_params.mib_size_log2;
   int size_sb, i;
+  const CommonTileParams *const tiles = &cm->tiles;
 
-  aom_wb_write_bit(wb, cm->uniform_tile_spacing_flag);
+  aom_wb_write_bit(wb, tiles->uniform_spacing);
 
-  if (cm->uniform_tile_spacing_flag) {
+  if (tiles->uniform_spacing) {
     // Uniform spaced tiles with power-of-two number of rows and columns
     // tile columns
-    int ones = cm->log2_tile_cols - cm->min_log2_tile_cols;
+    int ones = tiles->log2_cols - tiles->min_log2_cols;
     while (ones--) {
       aom_wb_write_bit(wb, 1);
     }
-    if (cm->log2_tile_cols < cm->max_log2_tile_cols) {
+    if (tiles->log2_cols < tiles->max_log2_cols) {
       aom_wb_write_bit(wb, 0);
     }
 
     // rows
-    ones = cm->log2_tile_rows - cm->min_log2_tile_rows;
+    ones = tiles->log2_rows - tiles->min_log2_rows;
     while (ones--) {
       aom_wb_write_bit(wb, 1);
     }
-    if (cm->log2_tile_rows < cm->max_log2_tile_rows) {
+    if (tiles->log2_rows < tiles->max_log2_rows) {
       aom_wb_write_bit(wb, 0);
     }
   } else {
     // Explicit tiles with configurable tile widths and heights
     // columns
-    for (i = 0; i < cm->tile_cols; i++) {
-      size_sb = cm->tile_col_start_sb[i + 1] - cm->tile_col_start_sb[i];
-      wb_write_uniform(wb, AOMMIN(width_sb, cm->max_tile_width_sb),
-                       size_sb - 1);
+    for (i = 0; i < tiles->cols; i++) {
+      size_sb = tiles->col_start_sb[i + 1] - tiles->col_start_sb[i];
+      wb_write_uniform(wb, AOMMIN(width_sb, tiles->max_width_sb), size_sb - 1);
       width_sb -= size_sb;
     }
     assert(width_sb == 0);
 
     // rows
-    for (i = 0; i < cm->tile_rows; i++) {
-      size_sb = cm->tile_row_start_sb[i + 1] - cm->tile_row_start_sb[i];
-      wb_write_uniform(wb, AOMMIN(height_sb, cm->max_tile_height_sb),
+    for (i = 0; i < tiles->rows; i++) {
+      size_sb = tiles->row_start_sb[i + 1] - tiles->row_start_sb[i];
+      wb_write_uniform(wb, AOMMIN(height_sb, tiles->max_height_sb),
                        size_sb - 1);
       height_sb -= size_sb;
     }
@@ -2175,9 +2175,9 @@
   write_tile_info_max_tile(cm, wb);
 
   *saved_wb = *wb;
-  if (cm->tile_rows * cm->tile_cols > 1) {
+  if (cm->tiles.rows * cm->tiles.cols > 1) {
     // tile id used for cdf update
-    aom_wb_write_literal(wb, 0, cm->log2_tile_cols + cm->log2_tile_rows);
+    aom_wb_write_literal(wb, 0, cm->tiles.log2_cols + cm->tiles.log2_rows);
     // Number of bytes in tile size - 1
     aom_wb_write_literal(wb, 3, 2);
   }
@@ -2192,7 +2192,7 @@
   assert(aom_wb_is_byte_aligned(wb));
 
   *saved_wb = *wb;
-  if (cm->tile_rows * cm->tile_cols > 1) {
+  if (cm->tiles.rows * cm->tiles.cols > 1) {
     // Note that the last item in the uncompressed header is the data
     // describing tile configuration.
     // Number of bytes in tile column size - 1
@@ -3053,7 +3053,7 @@
 
   const int might_bwd_adapt = !(seq_params->reduced_still_picture_hdr) &&
                               !(features->disable_cdf_update);
-  if (cm->large_scale_tile)
+  if (cm->tiles.large_scale)
     assert(cm->refresh_frame_context == REFRESH_FRAME_CONTEXT_DISABLED);
 
   if (might_bwd_adapt) {
@@ -3123,7 +3123,7 @@
       (cm->show_frame || cm->showable_frame))
     write_film_grain_params(cpi, wb);
 
-  if (cm->large_scale_tile) write_ext_tile_info(cm, saved_wb, wb);
+  if (cm->tiles.large_scale) write_ext_tile_info(cm, saved_wb, wb);
 }
 
 static int choose_size_bytes(uint32_t size, int spare_msbs) {
@@ -3157,7 +3157,7 @@
   }
 }
 
-static int remux_tiles(const AV1_COMMON *const cm, uint8_t *dst,
+static int remux_tiles(const CommonTileParams *const tiles, uint8_t *dst,
                        const uint32_t data_size, const uint32_t max_tile_size,
                        const uint32_t max_tile_col_size,
                        int *const tile_size_bytes,
@@ -3166,7 +3166,7 @@
   int tsb;
   int tcsb;
 
-  if (cm->large_scale_tile) {
+  if (tiles->large_scale) {
     // The top bit in the tile size field indicates tile copy mode, so we
     // have 1 less bit to code the tile size
     tsb = choose_size_bytes(max_tile_size, 1);
@@ -3187,25 +3187,25 @@
   uint32_t wpos = 0;
   uint32_t rpos = 0;
 
-  if (cm->large_scale_tile) {
+  if (tiles->large_scale) {
     int tile_row;
     int tile_col;
 
-    for (tile_col = 0; tile_col < cm->tile_cols; tile_col++) {
+    for (tile_col = 0; tile_col < tiles->cols; tile_col++) {
       // All but the last column has a column header
-      if (tile_col < cm->tile_cols - 1) {
+      if (tile_col < tiles->cols - 1) {
         uint32_t tile_col_size = mem_get_le32(dst + rpos);
         rpos += 4;
 
         // Adjust the tile column size by the number of bytes removed
         // from the tile size fields.
-        tile_col_size -= (4 - tsb) * cm->tile_rows;
+        tile_col_size -= (4 - tsb) * tiles->rows;
 
         mem_put_varsize(dst + wpos, tcsb, tile_col_size);
         wpos += tcsb;
       }
 
-      for (tile_row = 0; tile_row < cm->tile_rows; tile_row++) {
+      for (tile_row = 0; tile_row < tiles->rows; tile_row++) {
         // All, including the last row has a header
         uint32_t tile_header = mem_get_le32(dst + rpos);
         rpos += 4;
@@ -3233,7 +3233,7 @@
 
     return wpos;
   }
-  const int n_tiles = cm->tile_cols * cm->tile_rows;
+  const int n_tiles = tiles->cols * tiles->rows;
   int n;
 
   for (n = 0; n < n_tiles; n++) {
@@ -3437,21 +3437,22 @@
                                        const FrameHeaderInfo *fh_info,
                                        int *const largest_tile_id) {
   AV1_COMMON *const cm = &cpi->common;
+  const CommonTileParams *const tiles = &cm->tiles;
   aom_writer mode_bc;
   int tile_row, tile_col;
   // Store the location and size of each tile's data in the bitstream:
   TileBufferEnc tile_buffers[MAX_TILE_ROWS][MAX_TILE_COLS];
   uint32_t total_size = 0;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  const int tile_cols = tiles->cols;
+  const int tile_rows = tiles->rows;
   unsigned int tile_size = 0;
   unsigned int max_tile_size = 0;
   unsigned int max_tile_col_size = 0;
-  const int n_log2_tiles = cm->log2_tile_rows + cm->log2_tile_cols;
+  const int n_log2_tiles = tiles->log2_rows + tiles->log2_cols;
   // Fixed size tile groups for the moment
   const int num_tg_hdrs = cpi->num_tg;
   const int tg_size =
-      (cm->large_scale_tile)
+      (tiles->large_scale)
           ? 1
           : (tile_rows * tile_cols + num_tg_hdrs - 1) / num_tg_hdrs;
   int tile_count = 0;
@@ -3463,7 +3464,7 @@
 
   *largest_tile_id = 0;
 
-  if (cm->large_scale_tile) {
+  if (tiles->large_scale) {
     // For large_scale_tile case, we always have only one tile group, so it can
     // be written as an OBU_FRAME.
     const OBU_TYPE obu_type = OBU_FRAME;
@@ -3512,7 +3513,7 @@
         // even for the last one, unless no tiling is used at all.
         total_size += data_offset;
         cpi->td.mb.e_mbd.tile_ctx = &this_tile->tctx;
-        mode_bc.allow_update_cdf = !cm->large_scale_tile;
+        mode_bc.allow_update_cdf = !tiles->large_scale;
         mode_bc.allow_update_cdf =
             mode_bc.allow_update_cdf && !cm->features.disable_cdf_update;
         aom_start_encode(&mode_bc, buf->data + data_offset);
@@ -3531,7 +3532,7 @@
           // tile header: size of this tile, or copy offset
           uint32_t tile_header = tile_size - AV1_MIN_TILE_SIZE_BYTES;
           const int tile_copy_mode =
-              ((AOMMAX(cm->tile_width, cm->tile_height) << MI_SIZE_LOG2) <= 256)
+              ((AOMMAX(tiles->width, tiles->height) << MI_SIZE_LOG2) <= 256)
                   ? 1
                   : 0;
 
@@ -3568,7 +3569,7 @@
     }
 
     if (have_tiles) {
-      total_size = remux_tiles(cm, data, total_size - frame_header_size,
+      total_size = remux_tiles(tiles, data, total_size - frame_header_size,
                                max_tile_size, max_tile_col_size,
                                &tile_size_bytes, &tile_col_size_bytes);
       total_size += frame_header_size;
@@ -3726,7 +3727,7 @@
     // cdf update. The encoder currently sets it to the largest tile
     // (but is up to the encoder)
     aom_wb_overwrite_literal(saved_wb, *largest_tile_id,
-                             cm->log2_tile_cols + cm->log2_tile_rows);
+                             tiles->log2_cols + tiles->log2_rows);
     // If more than one tile group. tile_size_bytes takes the default value 4
     // and does not need to be set. For a single tile group it is set in the
     // section below.
@@ -3736,7 +3737,7 @@
       const uint32_t tile_data_size = total_size - tile_data_offset;
 
       total_size =
-          remux_tiles(cm, tile_data_start, tile_data_size, max_tile_size,
+          remux_tiles(tiles, tile_data_start, tile_data_size, max_tile_size,
                       max_tile_col_size, &tile_size_bytes, &unused);
       total_size += tile_data_offset;
       assert(tile_size_bytes >= 1 && tile_size_bytes <= 4);
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index f722991..5b0b014 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -252,7 +252,7 @@
   // Note(yunqing): In other cases, primary_ref_frame is chosen based on
   // cpi->gf_group.layer_depth[cpi->gf_group.index], which also controls
   // frame bit allocation.
-  if (cm->large_scale_tile) return (LAST_FRAME - LAST_FRAME);
+  if (cm->tiles.large_scale) return (LAST_FRAME - LAST_FRAME);
 
   // Find the most recent reference frame with the same reference type as the
   // current frame
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index 275644d..301dcfe 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -4728,7 +4728,7 @@
 
   // TODO(angiebird): Let inter_mode_rd_model_estimation support multi-tile.
   if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1 &&
-      cm->tile_cols == 1 && cm->tile_rows == 1) {
+      cm->tiles.cols == 1 && cm->tiles.rows == 1) {
     av1_inter_mode_data_fit(tile_data, x->rdmult);
   }
 }
@@ -4904,8 +4904,8 @@
 
 void av1_alloc_tile_data(AV1_COMP *cpi) {
   AV1_COMMON *const cm = &cpi->common;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  const int tile_cols = cm->tiles.cols;
+  const int tile_rows = cm->tiles.rows;
 
   if (cpi->tile_data != NULL) aom_free(cpi->tile_data);
   CHECK_MEM_ERROR(
@@ -4917,8 +4917,8 @@
 void av1_init_tile_data(AV1_COMP *cpi) {
   AV1_COMMON *const cm = &cpi->common;
   const int num_planes = av1_num_planes(cm);
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  const int tile_cols = cm->tiles.cols;
+  const int tile_rows = cm->tiles.rows;
   int tile_col, tile_row;
   TOKENEXTRA *pre_tok = cpi->tile_tok[0][0];
   TOKENLIST *tplist = cpi->tplist[0][0];
@@ -4939,7 +4939,7 @@
       cpi->tplist[tile_row][tile_col] = tplist + tplist_count;
       tplist = cpi->tplist[tile_row][tile_col];
       tplist_count = av1_get_sb_rows_in_tile(cm, tile_data->tile_info);
-      tile_data->allow_update_cdf = !cm->large_scale_tile;
+      tile_data->allow_update_cdf = !cm->tiles.large_scale;
       tile_data->allow_update_cdf =
           tile_data->allow_update_cdf && !cm->features.disable_cdf_update;
       tile_data->tctx = *cm->fc;
@@ -4951,7 +4951,7 @@
                        int tile_col, int mi_row) {
   AV1_COMMON *const cm = &cpi->common;
   const int num_planes = av1_num_planes(cm);
-  const int tile_cols = cm->tile_cols;
+  const int tile_cols = cm->tiles.cols;
   TileDataEnc *this_tile = &cpi->tile_data[tile_row * tile_cols + tile_col];
   const TileInfo *const tile_info = &this_tile->tile_info;
   TOKENEXTRA *tok = NULL;
@@ -4987,7 +4987,7 @@
                      int tile_col) {
   AV1_COMMON *const cm = &cpi->common;
   TileDataEnc *const this_tile =
-      &cpi->tile_data[tile_row * cm->tile_cols + tile_col];
+      &cpi->tile_data[tile_row * cm->tiles.cols + tile_col];
   const TileInfo *const tile_info = &this_tile->tile_info;
   int mi_row;
 
@@ -5009,8 +5009,8 @@
 
 static AOM_INLINE void encode_tiles(AV1_COMP *cpi) {
   AV1_COMMON *const cm = &cpi->common;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  const int tile_cols = cm->tiles.cols;
+  const int tile_rows = cm->tiles.rows;
   int tile_col, tile_row;
 
   if (cpi->tile_data == NULL || cpi->allocated_tiles < tile_cols * tile_rows)
@@ -5021,7 +5021,7 @@
   for (tile_row = 0; tile_row < tile_rows; ++tile_row) {
     for (tile_col = 0; tile_col < tile_cols; ++tile_col) {
       TileDataEnc *const this_tile =
-          &cpi->tile_data[tile_row * cm->tile_cols + tile_col];
+          &cpi->tile_data[tile_row * cm->tiles.cols + tile_col];
       cpi->td.intrabc_used = 0;
       cpi->td.deltaq_used = 0;
       cpi->td.mb.e_mbd.tile_ctx = &this_tile->tctx;
@@ -5812,7 +5812,7 @@
     cpi->row_mt_sync_write_ptr = av1_row_mt_sync_write;
     av1_encode_tiles_row_mt(cpi);
   } else {
-    if (AOMMIN(cpi->oxcf.max_threads, cm->tile_cols * cm->tile_rows) > 1)
+    if (AOMMIN(cpi->oxcf.max_threads, cm->tiles.cols * cm->tiles.rows) > 1)
       av1_encode_tiles_mt(cpi);
     else
       encode_tiles(cpi);
@@ -5997,7 +5997,7 @@
       current_frame->reference_mode = REFERENCE_MODE_SELECT;
 
     cm->interp_filter = SWITCHABLE;
-    if (cm->large_scale_tile) cm->interp_filter = EIGHTTAP_REGULAR;
+    if (cm->tiles.large_scale) cm->interp_filter = EIGHTTAP_REGULAR;
 
     cm->switchable_motion_mode = 1;
 
@@ -6026,7 +6026,7 @@
     if (skip_mode_info->skip_mode_flag && rdc->skip_mode_used_flag == 0)
       skip_mode_info->skip_mode_flag = 0;
 
-    if (!cm->large_scale_tile) {
+    if (!cm->tiles.large_scale) {
       if (cm->tx_mode == TX_MODE_SELECT && cpi->td.mb.txb_split_count == 0)
         cm->tx_mode = TX_MODE_LARGEST;
     }
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 5acc8e8..5dc3427 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -1147,49 +1147,51 @@
 
 static void set_tile_info(AV1_COMP *cpi) {
   AV1_COMMON *const cm = &cpi->common;
+  const SequenceHeader *const seq_params = &cm->seq_params;
+  CommonTileParams *const tiles = &cm->tiles;
   int i, start_sb;
 
   av1_get_tile_limits(cm);
 
   // configure tile columns
   if (cpi->oxcf.tile_width_count == 0 || cpi->oxcf.tile_height_count == 0) {
-    cm->uniform_tile_spacing_flag = 1;
-    cm->log2_tile_cols = AOMMAX(cpi->oxcf.tile_columns, cm->min_log2_tile_cols);
-    cm->log2_tile_cols = AOMMIN(cm->log2_tile_cols, cm->max_log2_tile_cols);
+    tiles->uniform_spacing = 1;
+    tiles->log2_cols = AOMMAX(cpi->oxcf.tile_columns, tiles->min_log2_cols);
+    tiles->log2_cols = AOMMIN(tiles->log2_cols, tiles->max_log2_cols);
   } else {
-    int mi_cols = ALIGN_POWER_OF_TWO(cm->mi_cols, cm->seq_params.mib_size_log2);
-    int sb_cols = mi_cols >> cm->seq_params.mib_size_log2;
+    int mi_cols = ALIGN_POWER_OF_TWO(cm->mi_cols, seq_params->mib_size_log2);
+    int sb_cols = mi_cols >> seq_params->mib_size_log2;
     int size_sb, j = 0;
-    cm->uniform_tile_spacing_flag = 0;
+    tiles->uniform_spacing = 0;
     for (i = 0, start_sb = 0; start_sb < sb_cols && i < MAX_TILE_COLS; i++) {
-      cm->tile_col_start_sb[i] = start_sb;
+      tiles->col_start_sb[i] = start_sb;
       size_sb = cpi->oxcf.tile_widths[j++];
       if (j >= cpi->oxcf.tile_width_count) j = 0;
-      start_sb += AOMMIN(size_sb, cm->max_tile_width_sb);
+      start_sb += AOMMIN(size_sb, tiles->max_width_sb);
     }
-    cm->tile_cols = i;
-    cm->tile_col_start_sb[i] = sb_cols;
+    tiles->cols = i;
+    tiles->col_start_sb[i] = sb_cols;
   }
-  av1_calculate_tile_cols(cm);
+  av1_calculate_tile_cols(seq_params, cm->mi_rows, cm->mi_cols, tiles);
 
   // configure tile rows
-  if (cm->uniform_tile_spacing_flag) {
-    cm->log2_tile_rows = AOMMAX(cpi->oxcf.tile_rows, cm->min_log2_tile_rows);
-    cm->log2_tile_rows = AOMMIN(cm->log2_tile_rows, cm->max_log2_tile_rows);
+  if (tiles->uniform_spacing) {
+    tiles->log2_rows = AOMMAX(cpi->oxcf.tile_rows, tiles->min_log2_rows);
+    tiles->log2_rows = AOMMIN(tiles->log2_rows, tiles->max_log2_rows);
   } else {
-    int mi_rows = ALIGN_POWER_OF_TWO(cm->mi_rows, cm->seq_params.mib_size_log2);
-    int sb_rows = mi_rows >> cm->seq_params.mib_size_log2;
+    int mi_rows = ALIGN_POWER_OF_TWO(cm->mi_rows, seq_params->mib_size_log2);
+    int sb_rows = mi_rows >> seq_params->mib_size_log2;
     int size_sb, j = 0;
     for (i = 0, start_sb = 0; start_sb < sb_rows && i < MAX_TILE_ROWS; i++) {
-      cm->tile_row_start_sb[i] = start_sb;
+      tiles->row_start_sb[i] = start_sb;
       size_sb = cpi->oxcf.tile_heights[j++];
       if (j >= cpi->oxcf.tile_height_count) j = 0;
-      start_sb += AOMMIN(size_sb, cm->max_tile_height_sb);
+      start_sb += AOMMIN(size_sb, tiles->max_height_sb);
     }
-    cm->tile_rows = i;
-    cm->tile_row_start_sb[i] = sb_rows;
+    tiles->rows = i;
+    tiles->row_start_sb[i] = sb_rows;
   }
-  av1_calculate_tile_rows(cm);
+  av1_calculate_tile_rows(seq_params, cm->mi_rows, tiles);
 }
 
 static void update_frame_size(AV1_COMP *cpi) {
@@ -4330,9 +4332,9 @@
   // Allocate above context buffers
   if (cm->num_allocated_above_context_planes < av1_num_planes(cm) ||
       cm->num_allocated_above_context_mi_col < cm->mi_cols ||
-      cm->num_allocated_above_contexts < cm->tile_rows) {
+      cm->num_allocated_above_contexts < cm->tiles.rows) {
     av1_free_above_context_buffers(cm, cm->num_allocated_above_contexts);
-    if (av1_alloc_above_context_buffers(cm, cm->tile_rows))
+    if (av1_alloc_above_context_buffers(cm, cm->tiles.rows))
       aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
                          "Failed to allocate context buffers");
   }
@@ -4788,12 +4790,12 @@
                  cm->features.coded_lossless && cm->features.all_lossless));
 
   const int use_loopfilter =
-      !cm->features.coded_lossless && !cm->large_scale_tile;
+      !cm->features.coded_lossless && !cm->tiles.large_scale;
   const int use_cdef = cm->seq_params.enable_cdef &&
-                       !cm->features.coded_lossless && !cm->large_scale_tile;
+                       !cm->features.coded_lossless && !cm->tiles.large_scale;
   const int use_restoration = cm->seq_params.enable_restoration &&
                               !cm->features.all_lossless &&
-                              !cm->large_scale_tile;
+                              !cm->tiles.large_scale;
 
   struct loopfilter *lf = &cm->lf;
 
@@ -4888,9 +4890,9 @@
   }
 
   // Initialise all tiles' contexts from the global frame context
-  for (int tile_col = 0; tile_col < cm->tile_cols; tile_col++) {
-    for (int tile_row = 0; tile_row < cm->tile_rows; tile_row++) {
-      const int tile_idx = tile_row * cm->tile_cols + tile_col;
+  for (int tile_col = 0; tile_col < cm->tiles.cols; tile_col++) {
+    for (int tile_row = 0; tile_row < cm->tiles.rows; tile_row++) {
+      const int tile_idx = tile_row * cm->tiles.cols + tile_col;
       cpi->tile_data[tile_idx].tctx = *cm->fc;
     }
   }
@@ -6191,14 +6193,14 @@
   // frame type has been decided outside of this function call
   cm->cur_frame->frame_type = current_frame->frame_type;
 
-  cm->large_scale_tile = cpi->oxcf.large_scale_tile;
-  cm->single_tile_decoding = cpi->oxcf.single_tile_decoding;
+  cm->tiles.large_scale = cpi->oxcf.large_scale_tile;
+  cm->tiles.single_tile_decoding = cpi->oxcf.single_tile_decoding;
 
   features->allow_ref_frame_mvs &= frame_might_allow_ref_frame_mvs(cm);
   // features->allow_ref_frame_mvs needs to be written into the frame header
-  // while cm->large_scale_tile is 1, therefore, "cm->large_scale_tile=1" case
+  // while cm->tiles.large_scale is 1, therefore, "cm->tiles.large_scale=1" case
   // is separated from frame_might_allow_ref_frame_mvs().
-  features->allow_ref_frame_mvs &= !cm->large_scale_tile;
+  features->allow_ref_frame_mvs &= !cm->tiles.large_scale;
 
   features->allow_warped_motion =
       cpi->oxcf.allow_warped_motion && frame_might_allow_warped_motion(cm);
@@ -6430,13 +6432,13 @@
     *cm->fc = cpi->tile_data[largest_tile_id].tctx;
     av1_reset_cdf_symbol_counters(cm->fc);
   }
-  if (!cm->large_scale_tile) {
+  if (!cm->tiles.large_scale) {
     cm->cur_frame->frame_context = *cm->fc;
   }
 
   if (cpi->oxcf.ext_tile_debug) {
     // (yunqing) This test ensures the correctness of large scale tile coding.
-    if (cm->large_scale_tile && is_stat_consumption_stage(cpi)) {
+    if (cm->tiles.large_scale && is_stat_consumption_stage(cpi)) {
       char fn[20] = "./fc";
       fn[4] = current_frame->frame_number / 100 + '0';
       fn[5] = (current_frame->frame_number % 100) / 10 + '0';
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 36ac9dd..b6eba2a 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -1385,7 +1385,7 @@
                                  int mi_row, TOKENEXTRA **tok, int sb_size_log2,
                                  int num_planes) {
   AV1_COMMON *const cm = &cpi->common;
-  const int tile_cols = cm->tile_cols;
+  const int tile_cols = cm->tiles.cols;
   TileDataEnc *this_tile = &cpi->tile_data[tile_row * tile_cols + tile_col];
   const TileInfo *const tile_info = &this_tile->tile_info;
 
diff --git a/av1/encoder/ethread.c b/av1/encoder/ethread.c
index e5841c3..0ba8d63 100644
--- a/av1/encoder/ethread.c
+++ b/av1/encoder/ethread.c
@@ -50,9 +50,9 @@
   const int mib_size = cm->seq_params.mib_size;
   const int frame_lf_count =
       av1_num_planes(cm) > 1 ? FRAME_LF_COUNT : FRAME_LF_COUNT - 2;
-  for (int row = 0; row < cm->tile_rows; row++) {
-    for (int col = 0; col < cm->tile_cols; col++) {
-      TileDataEnc *tile_data = &cpi->tile_data[row * cm->tile_cols + col];
+  for (int row = 0; row < cm->tiles.rows; row++) {
+    for (int col = 0; col < cm->tiles.cols; col++) {
+      TileDataEnc *tile_data = &cpi->tile_data[row * cm->tiles.cols + col];
       const TileInfo *const tile_info = &tile_data->tile_info;
       for (int mi_row = tile_info->mi_row_start; mi_row < tile_info->mi_row_end;
            mi_row += mib_size) {
@@ -240,8 +240,8 @@
                                                     int *current_mi_row,
                                                     int *end_of_frame) {
   AV1_COMMON *const cm = &cpi->common;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  const int tile_cols = cm->tiles.cols;
+  const int tile_rows = cm->tiles.rows;
 
   int tile_id = -1;  // Stores the tile ID with minimum proc done
   int max_mis_to_encode = 0;
@@ -364,8 +364,8 @@
   EncWorkerData *const thread_data = (EncWorkerData *)arg1;
   AV1_COMP *const cpi = thread_data->cpi;
   const AV1_COMMON *const cm = &cpi->common;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  const int tile_cols = cm->tiles.cols;
+  const int tile_rows = cm->tiles.rows;
   int t;
 
   (void)unused;
@@ -376,7 +376,7 @@
     int tile_col = t % tile_cols;
 
     TileDataEnc *const this_tile =
-        &cpi->tile_data[tile_row * cm->tile_cols + tile_col];
+        &cpi->tile_data[tile_row * cm->tiles.cols + tile_col];
     thread_data->td->mb.e_mbd.tile_ctx = &this_tile->tctx;
     thread_data->td->mb.tile_pb_ctx = &this_tile->tctx;
     av1_encode_tile(cpi, thread_data->td, tile_row, tile_col);
@@ -610,8 +610,8 @@
 
 void av1_encode_tiles_mt(AV1_COMP *cpi) {
   AV1_COMMON *const cm = &cpi->common;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  const int tile_cols = cm->tiles.cols;
+  const int tile_rows = cm->tiles.rows;
   int num_workers = AOMMIN(cpi->oxcf.max_threads, tile_cols * tile_rows);
 
   if (cpi->tile_data == NULL || cpi->allocated_tiles < tile_cols * tile_rows)
@@ -644,8 +644,8 @@
 
 void av1_encode_tiles_row_mt(AV1_COMP *cpi) {
   AV1_COMMON *const cm = &cpi->common;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  const int tile_cols = cm->tiles.cols;
+  const int tile_rows = cm->tiles.rows;
   MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
   int num_workers = 0;
   int total_num_threads_row_mt = 0;
@@ -660,7 +660,7 @@
 
   for (int row = 0; row < tile_rows; row++) {
     for (int col = 0; col < tile_cols; col++) {
-      TileDataEnc *tile_data = &cpi->tile_data[row * cm->tile_cols + col];
+      TileDataEnc *tile_data = &cpi->tile_data[row * cm->tiles.cols + col];
       int num_sb_rows_in_tile =
           av1_get_sb_rows_in_tile(cm, tile_data->tile_info);
       int num_sb_cols_in_tile =
diff --git a/av1/encoder/level.c b/av1/encoder/level.c
index 6a6ceb2..1d570a3 100644
--- a/av1/encoder/level.c
+++ b/av1/encoder/level.c
@@ -909,8 +909,8 @@
                            int *min_cropped_tile_height,
                            int *tile_width_valid) {
   const AV1_COMMON *const cm = &cpi->common;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  const int tile_cols = cm->tiles.cols;
+  const int tile_rows = cm->tiles.rows;
   const int superres_scale_denominator = cm->superres_scale_denominator;
 
   *max_tile_size = 0;
@@ -922,7 +922,7 @@
   for (int tile_row = 0; tile_row < tile_rows; ++tile_row) {
     for (int tile_col = 0; tile_col < tile_cols; ++tile_col) {
       const TileInfo *const tile_info =
-          &cpi->tile_data[tile_row * cm->tile_cols + tile_col].tile_info;
+          &cpi->tile_data[tile_row * cm->tiles.cols + tile_col].tile_info;
       const int tile_width =
           (tile_info->mi_col_end - tile_info->mi_col_start) * MI_SIZE;
       const int tile_height =
@@ -1048,8 +1048,8 @@
   const int upscaled_width = cm->superres_upscaled_width;
   const int width = cm->width;
   const int height = cm->height;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  const int tile_cols = cm->tiles.cols;
+  const int tile_rows = cm->tiles.rows;
   const int tiles = tile_cols * tile_rows;
   const int luma_pic_size = upscaled_width * height;
   const int frame_header_count = cpi->frame_header_count;
diff --git a/av1/encoder/mv_prec.c b/av1/encoder/mv_prec.c
index 601d958..384554d 100644
--- a/av1/encoder/mv_prec.c
+++ b/av1/encoder/mv_prec.c
@@ -346,8 +346,8 @@
 void av1_collect_mv_stats(AV1_COMP *cpi, int current_q) {
   MV_STATS *mv_stats = &cpi->mv_stats;
   const AV1_COMMON *cm = &cpi->common;
-  const int tile_cols = cm->tile_cols;
-  const int tile_rows = cm->tile_rows;
+  const int tile_cols = cm->tiles.cols;
+  const int tile_rows = cm->tiles.rows;
 
   for (int tile_row = 0; tile_row < tile_rows; tile_row++) {
     TileInfo tile_info;
diff --git a/av1/encoder/segmentation.c b/av1/encoder/segmentation.c
index 43a2803..d2b0ab0 100644
--- a/av1/encoder/segmentation.c
+++ b/av1/encoder/segmentation.c
@@ -183,10 +183,10 @@
   // First of all generate stats regarding how well the last segment map
   // predicts this one
   if (!scale_up) {
-    for (tile_row = 0; tile_row < cm->tile_rows; tile_row++) {
+    for (tile_row = 0; tile_row < cm->tiles.rows; tile_row++) {
       TileInfo tile_info;
       av1_tile_set_row(&tile_info, cm, tile_row);
-      for (tile_col = 0; tile_col < cm->tile_cols; tile_col++) {
+      for (tile_col = 0; tile_col < cm->tiles.cols; tile_col++) {
         MB_MODE_INFO **mi_ptr;
         av1_tile_set_col(&tile_info, cm, tile_col);
         mi_ptr = cm->mi_grid_base + tile_info.mi_row_start * cm->mi_stride +
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index 15e80b7..fe7649e 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -1033,7 +1033,7 @@
   cm->current_frame.frame_type = frame_params->frame_type;
   cm->show_frame = frame_params->show_frame;
 
-  if (cpi->common.large_scale_tile) return 0;
+  if (cpi->common.tiles.large_scale) return 0;
   if (gf_group->max_layer_depth_allowed == 0) return 1;
 
   double beta[2] = { 0.0 };