aomenc: respect chroma-sample-position for Y4M

BUG=aomedia:2096

Change-Id: I838eb98b6183563fcdf69db9d9b3c95874d5748d
diff --git a/apps/aomenc.c b/apps/aomenc.c
index a9c6f78..06fb480 100644
--- a/apps/aomenc.c
+++ b/apps/aomenc.c
@@ -845,14 +845,17 @@
   if (!rat->den) die("Error: %s has zero denominator\n", msg);
 }
 
-static void parse_global_config(struct AvxEncoderConfig *global, int *argc,
+/* Parses global config arguments into the AvxEncoderConfig. Note that
+ * argv is modified and overwrites all parsed arguments.
+ */
+static void parse_global_config(struct AvxEncoderConfig *global, int argc,
                                 char ***argv) {
   char **argi, **argj;
   struct arg arg;
   const int num_encoder = get_aom_encoder_count();
   char **argv_local = (char **)*argv;
 #if CONFIG_FILEOPTIONS
-  int argc_local = *argc;
+  int argc_local = argc;
 #endif
   if (num_encoder < 1) die("Error: no valid encoder available\n");
 
@@ -861,6 +864,7 @@
   global->codec = get_aom_encoder_by_index(num_encoder - 1);
   global->passes = 0;
   global->color_type = I420;
+  global->csp = AOM_CSP_UNKNOWN;
 
 #if CONFIG_FILEOPTIONS
   const char *cfg = NULL;
@@ -900,6 +904,10 @@
 
       if (global->pass < 1 || global->pass > 2)
         die("Error: Invalid pass selected (%d)\n", global->pass);
+    } else if (arg_match(&arg, &input_chroma_sample_position, argi)) {
+      global->csp = arg_parse_enum(&arg);
+      /* Flag is used by later code as well, preserve it. */
+      argj++;
     } else if (arg_match(&arg, &usage, argi))
       global->usage = arg_parse_uint(&arg);
     else if (arg_match(&arg, &good_dl, argi))
@@ -963,7 +971,8 @@
   }
 }
 
-static void open_input_file(struct AvxInputContext *input) {
+static void open_input_file(struct AvxInputContext *input,
+                            aom_chroma_sample_position_t csp) {
   /* Parse certain options from the input file, if possible */
   input->file = strcmp(input->filename, "-") ? fopen(input->filename, "rb")
                                              : set_binary_mode(stdin);
@@ -989,7 +998,7 @@
   input->detect.position = 0;
 
   if (input->detect.buf_read == 4 && file_is_y4m(input->detect.buf)) {
-    if (y4m_input_open(&input->y4m, input->file, input->detect.buf, 4,
+    if (y4m_input_open(&input->y4m, input->file, input->detect.buf, 4, csp,
                        input->only_i420) >= 0) {
       input->file_type = FILE_TYPE_Y4M;
       input->width = input->y4m.pic_w;
@@ -1914,7 +1923,7 @@
    * codec.
    */
   argv = argv_dup(argc - 1, argv_ + 1);
-  parse_global_config(&global, &argc, &argv);
+  parse_global_config(&global, argc, &argv);
 
 #if CONFIG_FILEOPTIONS
   if (argc < 2) usage_exit();
@@ -1970,7 +1979,7 @@
     int64_t average_rate = -1;
     int64_t lagged_count = 0;
 
-    open_input_file(&input);
+    open_input_file(&input, global.csp);
 
     /* If the input file doesn't specify its w/h (raw files), try to get
      * the data from the first stream's configuration.
diff --git a/apps/aomenc.h b/apps/aomenc.h
index 7c23df0..5e59c1a 100644
--- a/apps/aomenc.h
+++ b/apps/aomenc.h
@@ -53,6 +53,7 @@
   int disable_warnings;
   int disable_warning_prompt;
   int experimental_bitstream;
+  aom_chroma_sample_position_t csp;
 };
 
 #ifdef __cplusplus
diff --git a/common/y4minput.c b/common/y4minput.c
index eca8b1b..20b2310 100644
--- a/common/y4minput.c
+++ b/common/y4minput.c
@@ -109,7 +109,8 @@
   if (!got_par) _y4m->par_n = _y4m->par_d = 0;
   /*Chroma-type is not specified in older files, e.g., those generated by
      mplayer.*/
-  if (!got_chroma) strcpy(_y4m->chroma_type, "420");
+  if (!got_chroma)
+    snprintf(_y4m->chroma_type, sizeof(_y4m->chroma_type), "420");
   return 0;
 }
 
@@ -778,7 +779,7 @@
 }
 
 int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip,
-                   int only_420) {
+                   aom_chroma_sample_position_t csp, int only_420) {
   char buffer[80] = { 0 };
   int ret;
   int i;
@@ -831,6 +832,10 @@
     _y4m->dst_buf_read_sz =
         _y4m->pic_w * _y4m->pic_h +
         2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2);
+    if (csp == AOM_CSP_VERTICAL) {
+      fprintf(stderr, "Unsupported conversion from 420jpeg to 420mpeg2\n");
+      return -1;
+    }
     /* Natively supported: no conversion required. */
     _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
     _y4m->convert = y4m_convert_null;
@@ -877,7 +882,11 @@
     /*Chroma filter required: read into the aux buf first.*/
     _y4m->aux_buf_sz = _y4m->aux_buf_read_sz =
         2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2);
-    _y4m->convert = y4m_convert_42xmpeg2_42xjpeg;
+    _y4m->convert = y4m_convert_null;
+    if (csp != AOM_CSP_VERTICAL) {
+      _y4m->convert = y4m_convert_42xmpeg2_42xjpeg;
+      snprintf(_y4m->chroma_type, sizeof(_y4m->chroma_type), "420");
+    }
   } else if (strcmp(_y4m->chroma_type, "420paldv") == 0) {
     _y4m->src_c_dec_h = _y4m->dst_c_dec_h = _y4m->src_c_dec_v =
         _y4m->dst_c_dec_v = 2;
diff --git a/common/y4minput.h b/common/y4minput.h
index 01b9ce9..f6c5a3d 100644
--- a/common/y4minput.h
+++ b/common/y4minput.h
@@ -57,8 +57,14 @@
   unsigned int bit_depth;
 };
 
+/**
+ * Open the input file, treating it as Y4M. y4m_input is filled in after
+ * reading it. Note that chroma-sample-position should only be set for 420
+ * input, and the input chroma is shifted if necessary. The code does not
+ * support the conversion from co-located to vertical.
+ */
 int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip,
-                   int only_420);
+                   aom_chroma_sample_position_t csp, int only_420);
 void y4m_input_close(y4m_input *_y4m);
 int y4m_input_fetch_frame(y4m_input *_y4m, FILE *_fin, aom_image_t *img);
 
diff --git a/test/y4m_video_source.h b/test/y4m_video_source.h
index 3dea901..42dee69 100644
--- a/test/y4m_video_source.h
+++ b/test/y4m_video_source.h
@@ -41,7 +41,8 @@
 
   virtual void ReadSourceToStart() {
     ASSERT_TRUE(input_file_ != NULL);
-    ASSERT_FALSE(y4m_input_open(&y4m_, input_file_, NULL, 0, 0));
+    ASSERT_FALSE(
+        y4m_input_open(&y4m_, input_file_, NULL, 0, AOM_CSP_UNKNOWN, 0));
     framerate_numerator_ = y4m_.fps_n;
     framerate_denominator_ = y4m_.fps_d;
     frame_ = 0;