From 317002fb37f0fec657c728b4c5c0479cb5367259 Mon Sep 17 00:00:00 2001
From: Imdad Sardharwalla <imdad.sardharwalla@argondesign.com>
Date: Tue, 5 Dec 2017 16:24:56 +0000
Subject: [PATCH] Monochrome control now in colorspace header

The monochrome bit has been removed from the end
of the sequence header.
Monochrome is now coded as a type of colorspace.

Encode in monochrome by using
  aomenc --color-space=monochrome ...

Change-Id: I9550de58eb3d67dae0eb651697cb63dc8b137931
---
 aom/aom_image.h           |  3 ++-
 aomdec.c                  | 17 +-------------
 aomenc.c                  | 27 +++++++++------------
 av1/av1_cx_iface.c        | 14 ++++++-----
 av1/av1_dx_iface.c        | 26 +++++++++++----------
 av1/common/onyxc_int.h    |  5 +---
 av1/decoder/decodeframe.c | 49 ++++++++++++++++++++++-----------------
 av1/decoder/decoder.h     |  3 ---
 av1/encoder/bitstream.c   | 21 +++++++++--------
 av1/encoder/encoder.c     |  4 ----
 av1/encoder/encoder.h     |  3 ---
 11 files changed, 76 insertions(+), 96 deletions(-)

diff --git a/aom/aom_image.h b/aom/aom_image.h
index 7767949608..0bf00cd346 100644
--- a/aom/aom_image.h
+++ b/aom/aom_image.h
@@ -78,7 +78,8 @@ typedef enum aom_color_space {
   AOM_CS_BT_2020_CL = 6,  /**< BT.2020 constant luminance */
   AOM_CS_SRGB = 7,        /**< sRGB */
   AOM_CS_ICTCP = 8,       /**< ICtCp, ITU-R BT.2100 */
-  AOM_CS_RESERVED = 9     /**< Values 9..31 are reserved */
+  AOM_CS_MONOCHROME = 9,  /**< Monochrome */
+  AOM_CS_RESERVED = 10    /**< Values 10..31 are reserved */
 } aom_color_space_t;      /**< alias for enum aom_color_space */
 
 /*!\brief List of supported transfer functions */
diff --git a/aomdec.c b/aomdec.c
index aa8ba94777..8aaffd6097 100644
--- a/aomdec.c
+++ b/aomdec.c
@@ -74,10 +74,6 @@ static const arg_def_t flipuvarg =
     ARG_DEF(NULL, "flipuv", 0, "Flip the chroma planes in the output");
 static const arg_def_t rawvideo =
     ARG_DEF(NULL, "rawvideo", 0, "Output raw YUV frames");
-#if CONFIG_MONO_VIDEO
-static const arg_def_t monochrome = ARG_DEF(
-    NULL, "monochrome", 0, "Force monochrome output (constant chroma planes)");
-#endif
 static const arg_def_t noblitarg =
     ARG_DEF(NULL, "noblit", 0, "Don't process the decoded frames");
 static const arg_def_t progressarg =
@@ -127,9 +123,6 @@ static const arg_def_t *all_args[] = { &help,
                                        &use_i420,
                                        &flipuvarg,
                                        &rawvideo,
-#if CONFIG_MONO_VIDEO
-                                       &monochrome,
-#endif
                                        &noblitarg,
                                        &progressarg,
                                        &limitarg,
@@ -540,9 +533,6 @@ static int main_loop(int argc, const char **argv_) {
   int use_y4m = 1;
   int opt_yv12 = 0;
   int opt_i420 = 0;
-#if CONFIG_MONO_VIDEO
-  int opt_rawvideo = 0;
-#endif
   aom_codec_dec_cfg_t cfg = { 0, 0, 0, CONFIG_LOWBITDEPTH, 0 };
 #if CONFIG_HIGHBITDEPTH
   unsigned int output_bit_depth = 0;
@@ -609,11 +599,6 @@ static int main_loop(int argc, const char **argv_) {
       opt_i420 = 1;
     } else if (arg_match(&arg, &rawvideo, argi)) {
       use_y4m = 0;
-#if CONFIG_MONO_VIDEO
-      opt_rawvideo = 1;
-    } else if (arg_match(&arg, &monochrome, argi)) {
-      cfg.monochrome = 1;
-#endif
     } else if (arg_match(&arg, &flipuvarg, argi)) {
       flipuv = 1;
     } else if (arg_match(&arg, &noblitarg, argi)) {
@@ -961,7 +946,7 @@ static int main_loop(int argc, const char **argv_) {
 #endif  // CONFIG_EXT_TILE
 
 #if CONFIG_MONO_VIDEO
-      int num_planes = (opt_rawvideo && cfg.monochrome) ? 1 : 3;
+      int num_planes = (!use_y4m && img->cs == AOM_CS_MONOCHROME) ? 1 : 3;
 #else
       int num_planes = 3;
 #endif
diff --git a/aomenc.c b/aomenc.c
index 44d8480881..54d6ba134f 100644
--- a/aomenc.c
+++ b/aomenc.c
@@ -269,10 +269,6 @@ static const arg_def_t large_scale_tile =
     ARG_DEF(NULL, "large-scale-tile", 1,
             "Large scale tile coding (0: off (default), 1: on)");
 #endif  // CONFIG_EXT_TILE
-#if CONFIG_MONO_VIDEO
-static const arg_def_t monochrome =
-    ARG_DEF(NULL, "monochrome", 0, "Monochrome video (no chroma planes)");
-#endif  // MONOCHROME
 
 static const arg_def_t *global_args[] = { &use_yv12,
                                           &use_i420,
@@ -297,9 +293,6 @@ static const arg_def_t *global_args[] = { &use_yv12,
 #if CONFIG_EXT_TILE
                                           &large_scale_tile,
 #endif  // CONFIG_EXT_TILE
-#if CONFIG_MONO_VIDEO
-                                          &monochrome,
-#endif  // CONFIG_MONO_VIDEO
                                           NULL };
 
 static const arg_def_t dropframe_thresh =
@@ -509,11 +502,17 @@ static const arg_def_t max_gf_interval = ARG_DEF(
     "max gf/arf frame interval (default 0, indicating in-built behavior)");
 
 static const struct arg_enum_list color_space_enum[] = {
-  { "unknown", AOM_CS_UNKNOWN },     { "bt601", AOM_CS_BT_601 },
-  { "bt709", AOM_CS_BT_709 },        { "smpte170", AOM_CS_SMPTE_170 },
-  { "smpte240", AOM_CS_SMPTE_240 },  { "bt2020ncl", AOM_CS_BT_2020_NCL },
-  { "bt2020cl", AOM_CS_BT_2020_CL }, { "sRGB", AOM_CS_SRGB },
-  { "ICtCp", AOM_CS_ICTCP },         { NULL, 0 }
+  { "unknown", AOM_CS_UNKNOWN },
+  { "bt601", AOM_CS_BT_601 },
+  { "bt709", AOM_CS_BT_709 },
+  { "smpte170", AOM_CS_SMPTE_170 },
+  { "smpte240", AOM_CS_SMPTE_240 },
+  { "bt2020ncl", AOM_CS_BT_2020_NCL },
+  { "bt2020cl", AOM_CS_BT_2020_CL },
+  { "sRGB", AOM_CS_SRGB },
+  { "ICtCp", AOM_CS_ICTCP },
+  { "monochrome", AOM_CS_MONOCHROME },
+  { NULL, 0 }
 };
 
 static const arg_def_t input_color_space =
@@ -1112,10 +1111,6 @@ static int parse_stream_params(struct AvxEncoderConfig *global,
     } else if (arg_match(&arg, &large_scale_tile, argi)) {
       config->cfg.large_scale_tile = arg_parse_uint(&arg);
 #endif  // CONFIG_EXT_TILE
-#if CONFIG_MONO_VIDEO
-    } else if (arg_match(&arg, &monochrome, argi)) {
-      config->cfg.monochrome = 1;
-#endif  // CONFIG_MONO_VIDEO
     } else if (arg_match(&arg, &dropframe_thresh, argi)) {
       config->cfg.rc_dropframe_thresh = arg_parse_uint(&arg);
     } else if (arg_match(&arg, &resize_mode, argi)) {
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 754cab9ba1..03086e60f5 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -312,9 +312,6 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx,
 #if CONFIG_EXT_TILE
   }
 #endif  // CONFIG_EXT_TILE
-#if CONFIG_MONO_VIDEO
-  RANGE_CHECK_HI(cfg, monochrome, 1);
-#endif  // CONFIG_MONO_VIDEO
 
 #if CONFIG_EXT_TILE
   if (cfg->large_scale_tile && extra_cfg->aq_mode)
@@ -383,12 +380,20 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx,
     ERROR("Codec bit-depth 8 not supported in profile > 1");
   }
 #if CONFIG_COLORSPACE_HEADERS
+#if CONFIG_MONO_VIDEO
+  RANGE_CHECK(extra_cfg, color_space, AOM_CS_UNKNOWN, AOM_CS_MONOCHROME);
+#else
   RANGE_CHECK(extra_cfg, color_space, AOM_CS_UNKNOWN, AOM_CS_ICTCP);
+#endif  // CONFIG_MONO_VIDEO
   RANGE_CHECK(extra_cfg, transfer_function, AOM_TF_UNKNOWN, AOM_TF_HLG);
   RANGE_CHECK(extra_cfg, chroma_sample_position, AOM_CSP_UNKNOWN,
               AOM_CSP_COLOCATED);
+#else
+#if CONFIG_MONO_VIDEO
+  RANGE_CHECK(extra_cfg, color_space, AOM_CS_UNKNOWN, AOM_CS_MONOCHROME);
 #else
   RANGE_CHECK(extra_cfg, color_space, AOM_CS_UNKNOWN, AOM_CS_SRGB);
+#endif
 #endif
   RANGE_CHECK(extra_cfg, color_range, 0, 1);
 
@@ -634,9 +639,6 @@ static aom_codec_err_t set_encoder_config(
 #if CONFIG_EXT_TILE
   }
 #endif  // CONFIG_EXT_TILE
-#if CONFIG_MONO_VIDEO
-  oxcf->monochrome = cfg->monochrome;
-#endif  // CONFIG_MONO_VIDEO
 
 #if CONFIG_MAX_TILE
   oxcf->tile_width_count = AOMMIN(cfg->tile_width_count, MAX_TILE_COLS);
diff --git a/av1/av1_dx_iface.c b/av1/av1_dx_iface.c
index 0d3914dd56..31caa3a24e 100644
--- a/av1/av1_dx_iface.c
+++ b/av1/av1_dx_iface.c
@@ -171,9 +171,21 @@ static int parse_bitdepth_colorspace_sampling(BITSTREAM_PROFILE profile,
   color_space = (aom_color_space_t)aom_rb_read_literal(rb, 5);
   rb->bit_offset += 5;  // Transfer function
 #else
-  color_space = (aom_color_space_t)aom_rb_read_literal(rb, 3);
+  color_space =
+      (aom_color_space_t)aom_rb_read_literal(rb, 3 + CONFIG_MONO_VIDEO);
 #endif
-  if (color_space != AOM_CS_SRGB) {
+  if (color_space == AOM_CS_SRGB) {
+    if (profile == PROFILE_1 || profile == PROFILE_3) {
+      rb->bit_offset += 1;  // unused
+    } else {
+      // RGB is only available in version 1.
+      return 0;
+    }
+#if CONFIG_MONO_VIDEO
+  } else if (color_space == AOM_CS_MONOCHROME) {
+    return 1;
+#endif  // CONFIG_MONO_VIDEO
+  } else {
     rb->bit_offset += 1;  // [16,235] (including xvycc) vs [0,255] range.
 
     if (profile == PROFILE_1 || profile == PROFILE_3) {
@@ -195,13 +207,6 @@ static int parse_bitdepth_colorspace_sampling(BITSTREAM_PROFILE profile,
 #else
     }
 #endif
-  } else {
-    if (profile == PROFILE_1 || profile == PROFILE_3) {
-      rb->bit_offset += 1;  // unused
-    } else {
-      // RGB is only available in version 1.
-      return 0;
-    }
   }
   return 1;
 }
@@ -514,9 +519,6 @@ static aom_codec_err_t init_decoder(aom_codec_alg_priv_t *ctx) {
     }
 #endif
     frame_worker_data->pbi->allow_lowbitdepth = ctx->cfg.allow_lowbitdepth;
-#if CONFIG_MONO_VIDEO
-    frame_worker_data->pbi->monochrome = ctx->cfg.monochrome;
-#endif
 
     // If decoding in serial mode, FrameWorker thread could create tile worker
     // thread or loopfilter thread.
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h
index 7d8fa3f69f..02aec6aa4f 100644
--- a/av1/common/onyxc_int.h
+++ b/av1/common/onyxc_int.h
@@ -217,9 +217,6 @@ typedef struct SequenceHeader {
   int frame_id_numbers_present_flag;
   int frame_id_length;
   int delta_frame_id_length;
-#if CONFIG_MONO_VIDEO
-  int monochrome;
-#endif  // CONFIG_MONO_VIDEO
 } SequenceHeader;
 #endif  // CONFIG_REFERENCE_BUFFER
 
@@ -1160,7 +1157,7 @@ static INLINE int max_intra_block_height(const MACROBLOCKD *xd,
 
 static INLINE int av1_num_planes(const AV1_COMMON *cm) {
 #if CONFIG_MONO_VIDEO
-  return cm->seq_params.monochrome ? 1 : MAX_MB_PLANE;
+  return cm->color_space == AOM_CS_MONOCHROME ? 1 : MAX_MB_PLANE;
 #else
   (void)cm;
   return MAX_MB_PLANE;
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index cbc9e6f2f3..39cd3c32b6 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -2370,9 +2370,33 @@ static void read_bitdepth_colorspace_sampling(AV1_COMMON *cm,
   cm->color_space = aom_rb_read_literal(rb, 5);
   cm->transfer_function = aom_rb_read_literal(rb, 5);
 #else
-  cm->color_space = aom_rb_read_literal(rb, 3);
+  cm->color_space = aom_rb_read_literal(rb, 3 + CONFIG_MONO_VIDEO);
 #endif
-  if (cm->color_space != AOM_CS_SRGB) {
+  if (cm->color_space == AOM_CS_SRGB) {
+    if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) {
+      // Note if colorspace is SRGB then 4:4:4 chroma sampling is assumed.
+      // 4:2:2 or 4:4:0 chroma sampling is not allowed.
+      cm->subsampling_y = cm->subsampling_x = 0;
+      if (aom_rb_read_bit(rb))
+        aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
+                           "Reserved bit set");
+    } else {
+      aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
+                         "4:4:4 color not supported in profile 0 or 2");
+    }
+#if CONFIG_MONO_VIDEO
+  } else if (cm->color_space == AOM_CS_MONOCHROME) {
+    cm->color_range = AOM_CR_FULL_RANGE;
+    cm->subsampling_y = cm->subsampling_x = 1;
+#if CONFIG_COLORSPACE_HEADERS
+    cm->chroma_sample_position = AOM_CSP_UNKNOWN;
+#endif
+#if CONFIG_EXT_QM
+    cm->separate_uv_delta_q = 0;
+#endif
+    return;
+#endif  // CONFIG_MONO_VIDEO
+  } else {
     // [16,235] (including xvycc) vs [0,255] range
     cm->color_range = aom_rb_read_bit(rb);
     if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) {
@@ -2392,18 +2416,6 @@ static void read_bitdepth_colorspace_sampling(AV1_COMMON *cm,
       cm->chroma_sample_position = aom_rb_read_literal(rb, 2);
     }
 #endif
-  } else {
-    if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) {
-      // Note if colorspace is SRGB then 4:4:4 chroma sampling is assumed.
-      // 4:2:2 or 4:4:0 chroma sampling is not allowed.
-      cm->subsampling_y = cm->subsampling_x = 0;
-      if (aom_rb_read_bit(rb))
-        aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
-                           "Reserved bit set");
-    } else {
-      aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
-                         "4:4:4 color not supported in profile 0 or 2");
-    }
   }
 #if CONFIG_EXT_QM
   cm->separate_uv_delta_q = aom_rb_read_bit(rb);
@@ -2435,10 +2447,6 @@ void read_sequence_header(SequenceHeader *seq_params,
     seq_params->frame_id_length =
         aom_rb_read_literal(rb, 3) + seq_params->delta_frame_id_length + 1;
   }
-
-#if CONFIG_MONO_VIDEO
-  seq_params->monochrome = aom_rb_read_bit(rb);
-#endif  // CONFIG_MONO_VIDEO
 }
 #endif  // CONFIG_REFERENCE_BUFFER || CONFIG_OBU
 
@@ -3575,9 +3583,8 @@ void av1_decode_tg_tiles_and_wrapup(AV1Decoder *pbi, const uint8_t *data,
 #endif
 
 #if CONFIG_MONO_VIDEO
-  // If the bit stream is monochrome, or the decoder is set to force a
-  // monochrome output, set the U and V buffers to a constant.
-  if (pbi->monochrome || cm->seq_params.monochrome) {
+  // If the bit stream is monochrome, set the U and V buffers to a constant.
+  if (av1_num_planes(cm) < 3) {
 #if CONFIG_HIGHBITDEPTH
     const int bytes_per_sample = cm->use_highbitdepth ? 2 : 1;
 #else
diff --git a/av1/decoder/decoder.h b/av1/decoder/decoder.h
index b5d97b7b38..28227a5ba2 100644
--- a/av1/decoder/decoder.h
+++ b/av1/decoder/decoder.h
@@ -81,9 +81,6 @@ typedef struct AV1Decoder {
   void *decrypt_state;
 
   int allow_lowbitdepth;
-#if CONFIG_MONO_VIDEO
-  int monochrome;
-#endif
   int max_threads;
   int inv_tile_order;
   int need_resync;   // wait for key/intra-only frame.
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index bfdf4bed3e..c1e99cf620 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -1069,7 +1069,7 @@ static void write_palette_mode_info(const AV1_COMMON *cm, const MACROBLOCKD *xd,
 
   const int uv_dc_pred =
 #if CONFIG_MONO_VIDEO
-      !cm->seq_params.monochrome &&
+      av1_num_planes(cm) > 1 &&
 #endif
       mbmi->uv_mode == UV_DC_PRED;
   if (uv_dc_pred) {
@@ -3543,9 +3543,16 @@ static void write_bitdepth_colorspace_sampling(
   aom_wb_write_literal(wb, cm->color_space, 5);
   aom_wb_write_literal(wb, cm->transfer_function, 5);
 #else
-  aom_wb_write_literal(wb, cm->color_space, 3);
+  aom_wb_write_literal(wb, cm->color_space, 3 + CONFIG_MONO_VIDEO);
 #endif
-  if (cm->color_space != AOM_CS_SRGB) {
+  if (cm->color_space == AOM_CS_SRGB) {
+    assert(cm->profile == PROFILE_1 || cm->profile == PROFILE_3);
+    aom_wb_write_bit(wb, 0);  // unused
+#if CONFIG_MONO_VIDEO
+  } else if (cm->color_space == AOM_CS_MONOCHROME) {
+    return;
+#endif  // CONFIG_MONO_VIDEO
+  } else {
     // 0: [16, 235] (i.e. xvYCC), 1: [0, 255]
     aom_wb_write_bit(wb, cm->color_range);
     if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) {
@@ -3561,10 +3568,8 @@ static void write_bitdepth_colorspace_sampling(
       aom_wb_write_literal(wb, cm->chroma_sample_position, 2);
     }
 #endif
-  } else {
-    assert(cm->profile == PROFILE_1 || cm->profile == PROFILE_3);
-    aom_wb_write_bit(wb, 0);  // unused
   }
+
 #if CONFIG_EXT_QM
   aom_wb_write_bit(wb, cm->separate_uv_delta_q);
 #endif
@@ -3611,10 +3616,6 @@ void write_sequence_header(AV1_COMP *cpi, struct aom_write_bit_buffer *wb) {
         wb, seq_params->frame_id_length - seq_params->delta_frame_id_length - 1,
         3);
   }
-
-#if CONFIG_MONO_VIDEO
-  aom_wb_write_bit(wb, seq_params->monochrome);
-#endif  // CONFIG_MONO_VIDEO
 }
 #endif  // CONFIG_REFERENCE_BUFFER || CONFIG_OBU
 
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index d8c9037966..14c85e977b 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -5560,10 +5560,6 @@ static void encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size,
 #endif  // CONFIG_REFERENCE_BUFFER
 #endif  // CONFIG_EXT_TILE
 
-#if CONFIG_MONO_VIDEO
-  cm->seq_params.monochrome = oxcf->monochrome;
-#endif  // CONFIG_MONO_VIDEO
-
 #if CONFIG_XIPHRC
   if (drop_this_frame) {
     av1_rc_postencode_update_drop_frame(cpi);
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index d1edaf991c..46371b4bb0 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -296,9 +296,6 @@ typedef struct AV1EncoderConfig {
   unsigned int large_scale_tile;
   unsigned int single_tile_decoding;
 #endif  // CONFIG_EXT_TILE
-#if CONFIG_MONO_VIDEO
-  int monochrome;
-#endif  // CONFIG_MONO_VIDEO
 
   unsigned int motion_vector_unit_test;
 } AV1EncoderConfig;
-- 
GitLab