Don't send chroma data in monochrome mode

This is still a rather inefficient black+white encoder, since it carefully
computes some chroma data, but just doesn't write it. However, at least the
bitstream is now monochrome.

Change-Id: Ie8a89bf329e7b41441032fb0d9e9011385bc12ff
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h
index 024ad99..4199ed4 100644
--- a/av1/common/onyxc_int.h
+++ b/av1/common/onyxc_int.h
@@ -483,10 +483,6 @@
   unsigned int single_tile_decoding;
 #endif  // CONFIG_EXT_TILE
 
-#if CONFIG_MONO_VIDEO
-  int monochrome;
-#endif  // CONFIG_MONO_VIDEO
-
 #if CONFIG_DEPENDENT_HORZTILES
   int dependent_horz_tiles;
   int tile_group_start_row[MAX_TILE_ROWS][MAX_TILE_COLS];
@@ -1129,6 +1125,15 @@
 }
 #endif  // CONFIG_CFL
 
+static INLINE int av1_num_planes(const AV1_COMMON *cm) {
+#if CONFIG_MONO_VIDEO
+  return cm->seq_params.monochrome ? 1 : MAX_MB_PLANE;
+#else
+  (void)cm;
+  return MAX_MB_PLANE;
+#endif
+}
+
 static INLINE void av1_zero_above_context(AV1_COMMON *const cm,
                                           int mi_col_start, int mi_col_end) {
   const int width = mi_col_end - mi_col_start;
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 29049e2..7cc9c84 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -486,8 +486,7 @@
 #else
       const int current_qindex = xd->current_qindex;
 #endif  // CONFIG_EXT_DELTA_Q
-      int j;
-      for (j = 0; j < MAX_MB_PLANE; ++j) {
+      for (int j = 0; j < av1_num_planes(cm); ++j) {
         const int dc_delta_q =
             j == 0 ? cm->y_dc_delta_q
                    : (j == 1 ? cm->u_dc_delta_q : cm->v_dc_delta_q);
@@ -505,14 +504,13 @@
   if (mbmi->skip) av1_reset_skip_context(xd, mi_row, mi_col, bsize);
 
   if (!is_inter_block(mbmi)) {
-    int plane;
-
-    for (plane = 0; plane <= 1; ++plane) {
+    const int num_planes = av1_num_planes(cm);
+    for (int plane = 0; plane < AOMMIN(2, num_planes); ++plane) {
       if (mbmi->palette_mode_info.palette_size[plane])
         av1_decode_palette_tokens(xd, plane, r);
     }
 
-    for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
+    for (int plane = 0; plane < num_planes; ++plane) {
       const struct macroblockd_plane *const pd = &xd->plane[plane];
       const TX_SIZE tx_size = av1_get_tx_size(plane, xd);
       const int stepr = tx_size_high_unit[tx_size];
@@ -593,9 +591,7 @@
     // Reconstruction
     if (!mbmi->skip) {
       int eobtotal = 0;
-      int plane;
-
-      for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
+      for (int plane = 0; plane < av1_num_planes(cm); ++plane) {
         const struct macroblockd_plane *const pd = &xd->plane[plane];
         const BLOCK_SIZE plane_bsize =
             AOMMAX(BLOCK_4X4, get_plane_block_size(bsize, pd));
@@ -1008,7 +1004,7 @@
     }
   }
 #if CONFIG_LOOP_RESTORATION
-  for (int plane = 0; plane < MAX_MB_PLANE; ++plane) {
+  for (int plane = 0; plane < av1_num_planes(cm); ++plane) {
     int rcol0, rcol1, rrow0, rrow1, tile_tl_idx;
     if (av1_loop_restoration_corners_in_sb(cm, plane, mi_row, mi_col, bsize,
                                            &rcol0, &rcol1, &rrow0, &rrow1,
@@ -1131,7 +1127,8 @@
 #if CONFIG_INTRABC
   if (cm->allow_intrabc && NO_FILTER_FOR_IBC) return;
 #endif  // CONFIG_INTRABC
-  for (int p = 0; p < MAX_MB_PLANE; ++p) {
+  int all_none = 1, chroma_none = 1;
+  for (int p = 0; p < av1_num_planes(cm); ++p) {
     RestorationInfo *rsi = &cm->rst_info[p];
     if (aom_rb_read_bit(rb)) {
       rsi->frame_restoration_type =
@@ -1140,10 +1137,12 @@
       rsi->frame_restoration_type =
           aom_rb_read_bit(rb) ? RESTORE_SWITCHABLE : RESTORE_NONE;
     }
+    if (rsi->frame_restoration_type != RESTORE_NONE) {
+      all_none = 0;
+      chroma_none &= p == 0;
+    }
   }
-  if (cm->rst_info[0].frame_restoration_type != RESTORE_NONE ||
-      cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
-      cm->rst_info[2].frame_restoration_type != RESTORE_NONE) {
+  if (!all_none) {
     const int qsize = RESTORATION_TILESIZE_MAX >> 2;
     for (int p = 0; p < MAX_MB_PLANE; ++p)
       cm->rst_info[p].restoration_unit_size = qsize;
@@ -1159,16 +1158,18 @@
       cm->rst_info[p].restoration_unit_size = size;
   }
 
-  int s = AOMMIN(cm->subsampling_x, cm->subsampling_y);
-  if (s && (cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
-            cm->rst_info[2].frame_restoration_type != RESTORE_NONE)) {
-    cm->rst_info[1].restoration_unit_size =
-        cm->rst_info[0].restoration_unit_size >> (aom_rb_read_bit(rb) * s);
-  } else {
-    cm->rst_info[1].restoration_unit_size =
-        cm->rst_info[0].restoration_unit_size;
+  if (av1_num_planes(cm) > 1) {
+    int s = AOMMIN(cm->subsampling_x, cm->subsampling_y);
+    if (s && !chroma_none) {
+      cm->rst_info[1].restoration_unit_size =
+          cm->rst_info[0].restoration_unit_size >> (aom_rb_read_bit(rb) * s);
+    } else {
+      cm->rst_info[1].restoration_unit_size =
+          cm->rst_info[0].restoration_unit_size;
+    }
+    cm->rst_info[2].restoration_unit_size =
+        cm->rst_info[1].restoration_unit_size;
   }
-  cm->rst_info[2].restoration_unit_size = cm->rst_info[1].restoration_unit_size;
 }
 
 static void read_wiener_filter(int wiener_win, WienerInfo *wiener_info,
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 95d1af7..0e785d1 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -1212,7 +1212,12 @@
     }
   }
 
-  if (mbmi->uv_mode == UV_DC_PRED) {
+  const int uv_dc_pred =
+#if CONFIG_MONO_VIDEO
+      !cm->seq_params.monochrome &&
+#endif
+      mbmi->uv_mode == UV_DC_PRED;
+  if (uv_dc_pred) {
     const int n = pmi->palette_size[1];
     const int palette_uv_mode_ctx = (pmi->palette_size[0] > 0);
 #if CONFIG_NEW_MULTISYMBOL
@@ -2007,7 +2012,8 @@
 #endif  // CONFIG_DEPENDENT_HORZTILES
                  cm->mi_rows, cm->mi_cols);
 
-  for (plane = 0; plane <= 1; ++plane) {
+  const int num_planes = av1_num_planes(cm);
+  for (plane = 0; plane < AOMMIN(2, num_planes); ++plane) {
     const uint8_t palette_size_plane =
         mbmi->palette_mode_info.palette_size[plane];
     if (palette_size_plane > 0) {
@@ -2030,7 +2036,7 @@
 #if !CONFIG_LV_MAP
     assert(*tok < tok_end);
 #endif
-    for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
+    for (plane = 0; plane < num_planes; ++plane) {
       if (!is_chroma_reference(mi_row, mi_col, mbmi->sb_type,
                                xd->plane[plane].subsampling_x,
                                xd->plane[plane].subsampling_y)) {
@@ -2457,7 +2463,7 @@
     }
   }
 #if CONFIG_LOOP_RESTORATION
-  for (int plane = 0; plane < MAX_MB_PLANE; ++plane) {
+  for (int plane = 0; plane < av1_num_planes(cm); ++plane) {
     int rcol0, rcol1, rrow0, rrow1, tile_tl_idx;
     if (av1_loop_restoration_corners_in_sb(cm, plane, mi_row, mi_col, bsize,
                                            &rcol0, &rcol1, &rrow0, &rrow1,
@@ -2526,8 +2532,13 @@
 #if CONFIG_INTRABC
   if (cm->allow_intrabc && NO_FILTER_FOR_IBC) return;
 #endif  // CONFIG_INTRABC
-  for (int p = 0; p < MAX_MB_PLANE; ++p) {
+  int all_none = 1, chroma_none = 1;
+  for (int p = 0; p < av1_num_planes(cm); ++p) {
     RestorationInfo *rsi = &cm->rst_info[p];
+    if (rsi->frame_restoration_type != RESTORE_NONE) {
+      all_none = 0;
+      chroma_none &= p == 0;
+    }
     switch (rsi->frame_restoration_type) {
       case RESTORE_NONE:
         aom_wb_write_bit(wb, 0);
@@ -2548,9 +2559,7 @@
       default: assert(0);
     }
   }
-  if (cm->rst_info[0].frame_restoration_type != RESTORE_NONE ||
-      cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
-      cm->rst_info[2].frame_restoration_type != RESTORE_NONE) {
+  if (!all_none) {
     RestorationInfo *rsi = &cm->rst_info[0];
     const int qsize = RESTORATION_TILESIZE_MAX >> 2;
     const int hsize = RESTORATION_TILESIZE_MAX >> 1;
@@ -2559,23 +2568,25 @@
       aom_wb_write_bit(wb, rsi->restoration_unit_size != hsize);
     }
   }
-  int s = AOMMIN(cm->subsampling_x, cm->subsampling_y);
-  if (s && (cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
-            cm->rst_info[2].frame_restoration_type != RESTORE_NONE)) {
-    aom_wb_write_bit(wb,
-                     cm->rst_info[1].restoration_unit_size !=
-                         cm->rst_info[0].restoration_unit_size);
-    assert(cm->rst_info[1].restoration_unit_size ==
-               cm->rst_info[0].restoration_unit_size ||
-           cm->rst_info[1].restoration_unit_size ==
-               (cm->rst_info[0].restoration_unit_size >> s));
-    assert(cm->rst_info[2].restoration_unit_size ==
-           cm->rst_info[1].restoration_unit_size);
-  } else if (!s) {
-    assert(cm->rst_info[1].restoration_unit_size ==
-           cm->rst_info[0].restoration_unit_size);
-    assert(cm->rst_info[2].restoration_unit_size ==
-           cm->rst_info[1].restoration_unit_size);
+
+  if (av1_num_planes(cm) > 1) {
+    int s = AOMMIN(cm->subsampling_x, cm->subsampling_y);
+    if (s && !chroma_none) {
+      aom_wb_write_bit(wb,
+                       cm->rst_info[1].restoration_unit_size !=
+                           cm->rst_info[0].restoration_unit_size);
+      assert(cm->rst_info[1].restoration_unit_size ==
+                 cm->rst_info[0].restoration_unit_size ||
+             cm->rst_info[1].restoration_unit_size ==
+                 (cm->rst_info[0].restoration_unit_size >> s));
+      assert(cm->rst_info[2].restoration_unit_size ==
+             cm->rst_info[1].restoration_unit_size);
+    } else if (!s) {
+      assert(cm->rst_info[1].restoration_unit_size ==
+             cm->rst_info[0].restoration_unit_size);
+      assert(cm->rst_info[2].restoration_unit_size ==
+             cm->rst_info[1].restoration_unit_size);
+    }
   }
 }
 
@@ -3658,7 +3669,6 @@
   }
 
 #if CONFIG_MONO_VIDEO
-  seq_params->monochrome = cm->monochrome;
   aom_wb_write_bit(wb, seq_params->monochrome);
 #endif  // CONFIG_MONO_VIDEO
 }
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index c0d4563..74c293e 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -3608,7 +3608,8 @@
 
       cpi->tile_tok[tile_row][tile_col] = pre_tok + tile_tok;
       pre_tok = cpi->tile_tok[tile_row][tile_col];
-      tile_tok = allocated_tokens(*tile_info, cm->mib_size_log2 + MI_SIZE_LOG2);
+      tile_tok = allocated_tokens(*tile_info, cm->mib_size_log2 + MI_SIZE_LOG2,
+                                  av1_num_planes(cm));
 
 #if CONFIG_EXT_TILE
       tile_data->allow_update_cdf = !cm->large_scale_tile;
@@ -3674,7 +3675,8 @@
   cpi->tok_count[tile_row][tile_col] =
       (unsigned int)(tok - cpi->tile_tok[tile_row][tile_col]);
   assert(cpi->tok_count[tile_row][tile_col] <=
-         allocated_tokens(*tile_info, cm->mib_size_log2 + MI_SIZE_LOG2));
+         allocated_tokens(*tile_info, cm->mib_size_log2 + MI_SIZE_LOG2,
+                          av1_num_planes(cm)));
 }
 
 static void encode_tiles(AV1_COMP *cpi) {
@@ -4824,14 +4826,14 @@
   const int mi_height = mi_size_high[bsize];
   const int is_inter = is_inter_block(mbmi);
   const BLOCK_SIZE block_size = bsize;
+  const int num_planes = av1_num_planes(cm);
 
   if (!is_inter) {
 #if CONFIG_CFL
     xd->cfl->store_y = 1;
 #endif  // CONFIG_CFL
-    int plane;
     mbmi->skip = 1;
-    for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
+    for (int plane = 0; plane < num_planes; ++plane) {
       av1_encode_intra_block_plane((AV1_COMMON *)cm, x, block_size, plane, 1,
                                    mi_row, mi_col);
     }
@@ -4850,7 +4852,7 @@
     }
 
     if (bsize >= BLOCK_8X8) {
-      for (plane = 0; plane <= 1; ++plane) {
+      for (int plane = 0; plane < AOMMIN(2, num_planes); ++plane) {
         if (mbmi->palette_mode_info.palette_size[plane] > 0) {
           if (!dry_run)
             av1_tokenize_color_map(x, plane, 0, t, bsize, mbmi->tx_size,
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 649bfb0..e57d3d3 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -845,8 +845,8 @@
   aom_free(cpi->tile_tok[0][0]);
 
   {
-    unsigned int tokens =
-        get_token_alloc(cm->mb_rows, cm->mb_cols, MAX_SB_SIZE_LOG2);
+    unsigned int tokens = get_token_alloc(cm->mb_rows, cm->mb_cols,
+                                          MAX_SB_SIZE_LOG2, av1_num_planes(cm));
     CHECK_MEM_ERROR(cm, cpi->tile_tok[0][0],
                     aom_calloc(tokens, sizeof(*cpi->tile_tok[0][0])));
   }
@@ -5499,7 +5499,7 @@
 #endif  // CONFIG_EXT_TILE
 
 #if CONFIG_MONO_VIDEO
-  cm->monochrome = oxcf->monochrome;
+  cm->seq_params.monochrome = oxcf->monochrome;
 #endif  // CONFIG_MONO_VIDEO
 
 #if CONFIG_XIPHRC
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 2f72a28..b0ebd01 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -719,7 +719,7 @@
 }
 
 static INLINE unsigned int get_token_alloc(int mb_rows, int mb_cols,
-                                           int sb_size_log2) {
+                                           int sb_size_log2, int num_planes) {
   // Calculate the maximum number of max superblocks in the image.
   const int shift = sb_size_log2 - 4;
   const int sb_size = 1 << sb_size_log2;
@@ -727,10 +727,11 @@
   const int sb_rows = ALIGN_POWER_OF_TWO(mb_rows, shift) >> shift;
   const int sb_cols = ALIGN_POWER_OF_TWO(mb_cols, shift) >> shift;
 
-  // For transform coefficients, assume 3 planes with no subsampling. We assume
+  // For transform coefficients, assume planes with no subsampling. We assume
   // up to 1 token per pixel, and then allow a head room of 1 EOSB token per
   // 4x4 block per plane, plus EOSB_TOKEN per plane.
-  const int sb_coeff_toks = 3 * (sb_size_square + (sb_size_square / 16) + 1);
+  const int sb_coeff_toks =
+      num_planes * (sb_size_square + (sb_size_square / 16) + 1);
 
   // For palette coefficients, there can be at most one palette for each 8x8
   // block. If w, h are the width and height of the block, the palette has at
@@ -743,11 +744,12 @@
 
 // Get the allocated token size for a tile. It does the same calculation as in
 // the frame token allocation.
-static INLINE unsigned int allocated_tokens(TileInfo tile, int sb_size_log2) {
+static INLINE unsigned int allocated_tokens(TileInfo tile, int sb_size_log2,
+                                            int num_planes) {
   int tile_mb_rows = (tile.mi_row_end - tile.mi_row_start + 2) >> 2;
   int tile_mb_cols = (tile.mi_col_end - tile.mi_col_start + 2) >> 2;
 
-  return get_token_alloc(tile_mb_rows, tile_mb_cols, sb_size_log2);
+  return get_token_alloc(tile_mb_rows, tile_mb_cols, sb_size_log2, num_planes);
 }
 
 #if CONFIG_TEMPMV_SIGNALING
diff --git a/av1/encoder/tokenize.c b/av1/encoder/tokenize.c
index 4bc36c9..56c169b6 100644
--- a/av1/encoder/tokenize.c
+++ b/av1/encoder/tokenize.c
@@ -647,7 +647,6 @@
   TOKENEXTRA *t_backup = *t;
 #endif
   struct tokenize_b_args arg = { cpi, td, t, 0, allow_update_cdf };
-  int plane;
   if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
 
   if (mbmi->skip) {
@@ -663,7 +662,7 @@
     *t = t_backup;
 #endif
 
-  for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
+  for (int plane = 0; plane < av1_num_planes(cm); ++plane) {
     if (!is_chroma_reference(mi_row, mi_col, bsize,
                              xd->plane[plane].subsampling_x,
                              xd->plane[plane].subsampling_y)) {
@@ -735,10 +734,9 @@
     return;
   }
 
+  const int num_planes = av1_num_planes(&cpi->common);
   if (!dry_run) {
-    int plane;
-
-    for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
+    for (int plane = 0; plane < num_planes; ++plane) {
       if (!is_chroma_reference(mi_row, mi_col, bsize,
                                xd->plane[plane].subsampling_x,
                                xd->plane[plane].subsampling_y)) {
@@ -753,8 +751,7 @@
       (*t)++;
     }
   } else if (dry_run == DRY_RUN_NORMAL) {
-    int plane;
-    for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
+    for (int plane = 0; plane < num_planes; ++plane) {
       if (!is_chroma_reference(mi_row, mi_col, bsize,
                                xd->plane[plane].subsampling_x,
                                xd->plane[plane].subsampling_y))
@@ -763,8 +760,7 @@
                                              set_entropy_context_b, &arg);
     }
   } else if (dry_run == DRY_RUN_COSTCOEFFS) {
-    int plane;
-    for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
+    for (int plane = 0; plane < num_planes; ++plane) {
       if (!is_chroma_reference(mi_row, mi_col, bsize,
                                xd->plane[plane].subsampling_x,
                                xd->plane[plane].subsampling_y))