Change command line flags for svc sample encoder.

Change-Id: I5b9ae6fee889ec6d143f447d1833febb41f11c24
diff --git a/examples/svc_encoder_rtc.c b/examples/svc_encoder_rtc.c
index 401049f..1bfca6d 100644
--- a/examples/svc_encoder_rtc.c
+++ b/examples/svc_encoder_rtc.c
@@ -21,19 +21,363 @@
 #include "aom/aomcx.h"
 #include "av1/common/enums.h"
 #include "av1/encoder/encoder.h"
+#include "common/args.h"
 #include "common/tools_common.h"
 #include "common/video_writer.h"
 #include "aom_ports/aom_timer.h"
 
+#define OPTION_BUFFER_SIZE 1024
+
+typedef struct {
+  const char *output_filename;
+  char options[OPTION_BUFFER_SIZE];
+  struct AvxInputContext input_ctx;
+  int speed;
+  int aq_mode;
+  int layering_mode;
+} AppInput;
+
+typedef enum {
+  QUANTIZER = 0,
+  BITRATE,
+  SCALE_FACTOR,
+  AUTO_ALT_REF,
+  ALL_OPTION_TYPES
+} LAYER_OPTION_TYPE;
+
+static const arg_def_t outputfile =
+    ARG_DEF("o", "output", 1, "Output filename");
+static const arg_def_t frames_arg =
+    ARG_DEF("f", "frames", 1, "number of frames to encode");
+static const arg_def_t threads_arg =
+    ARG_DEF("th", "threads", 1, "number of threads to use");
+static const arg_def_t width_arg = ARG_DEF("w", "width", 1, "source width");
+static const arg_def_t height_arg = ARG_DEF("h", "height", 1, "source height");
+static const arg_def_t timebase_arg =
+    ARG_DEF("t", "timebase", 1, "timebase (num/den)");
+static const arg_def_t bitrate_arg = ARG_DEF(
+    "b", "target-bitrate", 1, "encoding bitrate, in kilobits per second");
+static const arg_def_t spatial_layers_arg =
+    ARG_DEF("sl", "spatial-layers", 1, "number of spatial SVC layers");
+static const arg_def_t temporal_layers_arg =
+    ARG_DEF("tl", "temporal-layers", 1, "number of temporal SVC layers");
+static const arg_def_t layering_mode_arg =
+    ARG_DEF("lm", "layering-mode", 1, "temporal layering scheme.");
+static const arg_def_t kf_dist_arg =
+    ARG_DEF("k", "kf-dist", 1, "number of frames between keyframes");
+static const arg_def_t scale_factors_arg =
+    ARG_DEF("r", "scale-factors", 1, "scale factors (lowest to highest layer)");
+static const arg_def_t min_q_arg =
+    ARG_DEF(NULL, "min-q", 1, "Minimum quantizer");
+static const arg_def_t max_q_arg =
+    ARG_DEF(NULL, "max-q", 1, "Maximum quantizer");
+static const arg_def_t speed_arg =
+    ARG_DEF("sp", "speed", 1, "speed configuration");
+static const arg_def_t aqmode_arg =
+    ARG_DEF("aq", "aqmode", 1, "aq-mode off/on");
+static const arg_def_t bitrates_arg =
+    ARG_DEF("bl", "bitrates", 1, "bitrates[sl * num_tl + tl]");
+static const arg_def_t dropframe_thresh_arg =
+    ARG_DEF(NULL, "drop-frame", 1, "Temporal resampling threshold (buf %)");
+static const arg_def_t error_resilient_arg =
+    ARG_DEF(NULL, "error-resilient", 1, "Error resilient flag");
+
+#if CONFIG_AV1_HIGHBITDEPTH
+static const struct arg_enum_list bitdepth_enum[] = {
+  { "8", AOM_BITS_8 }, { "10", AOM_BITS_10 }, { "12", AOM_BITS_12 }, { NULL, 0 }
+};
+
+static const arg_def_t bitdepth_arg = ARG_DEF_ENUM(
+    "d", "bit-depth", 1, "Bit depth for codec 8, 10 or 12. ", bitdepth_enum);
+#endif  // CONFIG_AV1_HIGHBITDEPTH
+
+static const arg_def_t *svc_args[] = {
+  &frames_arg,          &outputfile,   &width_arg,
+  &height_arg,          &timebase_arg, &bitrate_arg,
+  &spatial_layers_arg,  &kf_dist_arg,  &scale_factors_arg,
+  &min_q_arg,           &max_q_arg,    &temporal_layers_arg,
+  &layering_mode_arg,   &threads_arg,  &aqmode_arg,
+#if CONFIG_AV1_HIGHBITDEPTH
+  &bitdepth_arg,
+#endif
+  &speed_arg,           &bitrates_arg, &dropframe_thresh_arg,
+  &error_resilient_arg, NULL
+};
+
 #define zero(Dest) memset(&(Dest), 0, sizeof(Dest));
 
 static const char *exec_name;
 
-void usage_exit(void) { exit(EXIT_FAILURE); }
+void usage_exit(void) {
+  fprintf(stderr, "Usage: %s <options> input_filename -o output_filename\n",
+          exec_name);
+  fprintf(stderr, "Options:\n");
+  arg_show_usage(stderr, svc_args);
+  exit(EXIT_FAILURE);
+}
 
-static int mode_to_num_temporal_layers[10] = { 1, 2, 3, 3, 2, 1, 1, 3, 3, 3 };
-static int mode_to_num_spatial_layers[10] = { 1, 1, 1, 1, 1, 2, 3, 3, 3, 3 };
-static int mode_to_num_layers[10] = { 1, 2, 3, 3, 2, 2, 3, 9, 9, 9 };
+static int file_is_y4m(const char detect[4]) {
+  if (memcmp(detect, "YUV4", 4) == 0) {
+    return 1;
+  }
+  return 0;
+}
+
+static int fourcc_is_ivf(const char detect[4]) {
+  if (memcmp(detect, "DKIF", 4) == 0) {
+    return 1;
+  }
+  return 0;
+}
+
+static const int option_max_values[ALL_OPTION_TYPES] = { 63, INT_MAX, INT_MAX,
+                                                         1 };
+
+static const int option_min_values[ALL_OPTION_TYPES] = { 0, 0, 1, 0 };
+
+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);
+
+  if (!input->file) fatal("Failed to open input file");
+
+  if (!fseeko(input->file, 0, SEEK_END)) {
+    /* Input file is seekable. Figure out how long it is, so we can get
+     * progress info.
+     */
+    input->length = ftello(input->file);
+    rewind(input->file);
+  }
+
+  /* Default to 1:1 pixel aspect ratio. */
+  input->pixel_aspect_ratio.numerator = 1;
+  input->pixel_aspect_ratio.denominator = 1;
+
+  /* For RAW input sources, these bytes will applied on the first frame
+   *  in read_frame().
+   */
+  input->detect.buf_read = fread(input->detect.buf, 1, 4, input->file);
+  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, csp,
+                       input->only_i420) >= 0) {
+      input->file_type = FILE_TYPE_Y4M;
+      input->width = input->y4m.pic_w;
+      input->height = input->y4m.pic_h;
+      input->pixel_aspect_ratio.numerator = input->y4m.par_n;
+      input->pixel_aspect_ratio.denominator = input->y4m.par_d;
+      input->framerate.numerator = input->y4m.fps_n;
+      input->framerate.denominator = input->y4m.fps_d;
+      input->fmt = input->y4m.aom_fmt;
+      input->bit_depth = input->y4m.bit_depth;
+    } else {
+      fatal("Unsupported Y4M stream.");
+    }
+  } else if (input->detect.buf_read == 4 && fourcc_is_ivf(input->detect.buf)) {
+    fatal("IVF is not supported as input.");
+  } else {
+    input->file_type = FILE_TYPE_RAW;
+  }
+}
+
+static aom_codec_err_t extract_option(LAYER_OPTION_TYPE type, char *input,
+                                      int *value0, int *value1) {
+  if (type == SCALE_FACTOR) {
+    *value0 = (int)strtol(input, &input, 10);
+    if (*input++ != '/') return AOM_CODEC_INVALID_PARAM;
+    *value1 = (int)strtol(input, &input, 10);
+
+    if (*value0 < option_min_values[SCALE_FACTOR] ||
+        *value1 < option_min_values[SCALE_FACTOR] ||
+        *value0 > option_max_values[SCALE_FACTOR] ||
+        *value1 > option_max_values[SCALE_FACTOR] ||
+        *value0 > *value1)  // num shouldn't be greater than den
+      return AOM_CODEC_INVALID_PARAM;
+  } else {
+    *value0 = atoi(input);
+    if (*value0 < option_min_values[type] || *value0 > option_max_values[type])
+      return AOM_CODEC_INVALID_PARAM;
+  }
+  return AOM_CODEC_OK;
+}
+
+static aom_codec_err_t parse_layer_options_from_string(
+    aom_svc_params_t *svc_params, LAYER_OPTION_TYPE type, const char *input,
+    int *option0, int *option1) {
+  aom_codec_err_t res = AOM_CODEC_OK;
+  char *input_string;
+  char *token;
+  const char *delim = ",";
+  int num_layers = svc_params->number_spatial_layers;
+  int i = 0;
+
+  if (type == BITRATE)
+    num_layers =
+        svc_params->number_spatial_layers * svc_params->number_temporal_layers;
+
+  if (input == NULL || option0 == NULL ||
+      (option1 == NULL && type == SCALE_FACTOR))
+    return AOM_CODEC_INVALID_PARAM;
+
+  input_string = malloc(strlen(input));
+  memcpy(input_string, input, strlen(input));
+  if (input_string == NULL) return AOM_CODEC_MEM_ERROR;
+  token = strtok(input_string, delim);  // NOLINT
+  for (i = 0; i < num_layers; ++i) {
+    if (token != NULL) {
+      res = extract_option(type, token, option0 + i, option1 + i);
+      if (res != AOM_CODEC_OK) break;
+      token = strtok(NULL, delim);  // NOLINT
+    } else {
+      break;
+    }
+  }
+  if (res == AOM_CODEC_OK && i != num_layers) {
+    res = AOM_CODEC_INVALID_PARAM;
+  }
+  free(input_string);
+  return res;
+}
+
+static void parse_command_line(int argc, const char **argv_,
+                               AppInput *app_input,
+                               aom_svc_params_t *svc_params,
+                               aom_codec_enc_cfg_t *enc_cfg) {
+  struct arg arg;
+  char **argv = NULL;
+  char **argi = NULL;
+  char **argj = NULL;
+  char string_options[1024] = { 0 };
+
+  // Default settings
+  svc_params->number_spatial_layers = 1;
+  svc_params->number_temporal_layers = 1;
+  app_input->layering_mode = 0;
+  enc_cfg->g_threads = 1;
+  enc_cfg->rc_end_usage = AOM_CBR;
+
+  // process command line options
+  argv = argv_dup(argc - 1, argv_ + 1);
+  for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
+    arg.argv_step = 1;
+
+    if (arg_match(&arg, &outputfile, argi)) {
+      app_input->output_filename = arg.val;
+    } else if (arg_match(&arg, &width_arg, argi)) {
+      enc_cfg->g_w = arg_parse_uint(&arg);
+    } else if (arg_match(&arg, &height_arg, argi)) {
+      enc_cfg->g_h = arg_parse_uint(&arg);
+    } else if (arg_match(&arg, &timebase_arg, argi)) {
+      enc_cfg->g_timebase = arg_parse_rational(&arg);
+    } else if (arg_match(&arg, &bitrate_arg, argi)) {
+      enc_cfg->rc_target_bitrate = arg_parse_uint(&arg);
+    } else if (arg_match(&arg, &spatial_layers_arg, argi)) {
+      svc_params->number_spatial_layers = arg_parse_uint(&arg);
+    } else if (arg_match(&arg, &temporal_layers_arg, argi)) {
+      svc_params->number_temporal_layers = arg_parse_uint(&arg);
+    } else if (arg_match(&arg, &speed_arg, argi)) {
+      app_input->speed = arg_parse_uint(&arg);
+      if (app_input->speed > 9) {
+        warn("Mapping speed %d to speed 9.\n", app_input->speed);
+      }
+    } else if (arg_match(&arg, &aqmode_arg, argi)) {
+      app_input->aq_mode = arg_parse_uint(&arg);
+    } else if (arg_match(&arg, &threads_arg, argi)) {
+      enc_cfg->g_threads = arg_parse_uint(&arg);
+    } else if (arg_match(&arg, &layering_mode_arg, argi)) {
+      app_input->layering_mode = arg_parse_int(&arg);
+    } else if (arg_match(&arg, &kf_dist_arg, argi)) {
+      enc_cfg->kf_min_dist = arg_parse_uint(&arg);
+      enc_cfg->kf_max_dist = enc_cfg->kf_min_dist;
+    } else if (arg_match(&arg, &scale_factors_arg, argi)) {
+      parse_layer_options_from_string(svc_params, SCALE_FACTOR, arg.val,
+                                      svc_params->scaling_factor_num,
+                                      svc_params->scaling_factor_den);
+    } else if (arg_match(&arg, &bitrates_arg, argi)) {
+      parse_layer_options_from_string(svc_params, BITRATE, arg.val,
+                                      svc_params->layer_target_bitrate, NULL);
+    } else if (arg_match(&arg, &min_q_arg, argi)) {
+      enc_cfg->rc_min_quantizer = arg_parse_uint(&arg);
+    } else if (arg_match(&arg, &max_q_arg, argi)) {
+      enc_cfg->rc_max_quantizer = arg_parse_uint(&arg);
+#if CONFIG_AV1_HIGHBITDEPTH
+    } else if (arg_match(&arg, &bitdepth_arg, argi)) {
+      enc_cfg->g_bit_depth = arg_parse_enum_or_int(&arg);
+      switch (enc_cfg->g_bit_depth) {
+        case AOM_BITS_8:
+          enc_cfg->g_input_bit_depth = 8;
+          enc_cfg->g_profile = 0;
+          break;
+        case AOM_BITS_10:
+          enc_cfg->g_input_bit_depth = 10;
+          enc_cfg->g_profile = 2;
+          break;
+        case AOM_BITS_12:
+          enc_cfg->g_input_bit_depth = 12;
+          enc_cfg->g_profile = 2;
+          break;
+        default:
+          die("Error: Invalid bit depth selected (%d)\n", enc_cfg->g_bit_depth);
+          break;
+      }
+#endif  // CONFIG_VP9_HIGHBITDEPTH
+    } else if (arg_match(&arg, &dropframe_thresh_arg, argi)) {
+      enc_cfg->rc_dropframe_thresh = arg_parse_uint(&arg);
+    } else if (arg_match(&arg, &error_resilient_arg, argi)) {
+      enc_cfg->g_error_resilient = arg_parse_uint(&arg);
+      if (enc_cfg->g_error_resilient != 0 && enc_cfg->g_error_resilient != 1)
+        die("Invalid value for error resilient (0, 1): %d.",
+            enc_cfg->g_error_resilient);
+    } else {
+      ++argj;
+    }
+  }
+
+  // There will be a space in front of the string options
+  if (strlen(string_options) > 0)
+    strncpy(app_input->options, string_options, OPTION_BUFFER_SIZE);
+
+  // Check for unrecognized options
+  for (argi = argv; *argi; ++argi)
+    if (argi[0][0] == '-' && strlen(argi[0]) > 1)
+      die("Error: Unrecognized option %s\n", *argi);
+
+  if (argv[0] == NULL) {
+    usage_exit();
+  }
+
+  app_input->input_ctx.filename = argv[0];
+  free(argv);
+
+  open_input_file(&app_input->input_ctx, 0);
+  if (app_input->input_ctx.file_type == FILE_TYPE_Y4M) {
+    enc_cfg->g_w = app_input->input_ctx.width;
+    enc_cfg->g_h = app_input->input_ctx.height;
+  }
+
+  if (enc_cfg->g_w < 16 || enc_cfg->g_w % 2 || enc_cfg->g_h < 16 ||
+      enc_cfg->g_h % 2)
+    die("Invalid resolution: %d x %d\n", enc_cfg->g_w, enc_cfg->g_h);
+
+  printf(
+      "Codec %s\n"
+      "layers: %d\n"
+      "width %d, height: %d\n"
+      "num: %d, den: %d, bitrate: %d\n"
+      "gop size: %d\n",
+      aom_codec_iface_name(aom_codec_av1_cx()),
+      svc_params->number_spatial_layers, enc_cfg->g_w, enc_cfg->g_h,
+      enc_cfg->g_timebase.num, enc_cfg->g_timebase.den,
+      enc_cfg->rc_target_bitrate, enc_cfg->kf_max_dist);
+}
+
+static unsigned int mode_to_num_temporal_layers[10] = { 1, 2, 3, 3, 2,
+                                                        1, 1, 3, 3, 3 };
+static unsigned int mode_to_num_spatial_layers[10] = { 1, 1, 1, 1, 1,
+                                                       2, 3, 3, 3, 3 };
 
 // For rate control encoding stats.
 struct RateControlMetrics {
@@ -88,73 +432,11 @@
   return !shortread;
 }
 
-static int file_is_y4m(const char detect[4]) {
-  if (memcmp(detect, "YUV4", 4) == 0) {
-    return 1;
-  }
-  return 0;
-}
-
-static int fourcc_is_ivf(const char detect[4]) {
-  if (memcmp(detect, "DKIF", 4) == 0) {
-    return 1;
-  }
-  return 0;
-}
-
 static void close_input_file(struct AvxInputContext *input) {
   fclose(input->file);
   if (input->file_type == FILE_TYPE_Y4M) y4m_input_close(&input->y4m);
 }
 
-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);
-
-  if (!input->file) fatal("Failed to open input file");
-
-  if (!fseeko(input->file, 0, SEEK_END)) {
-    /* Input file is seekable. Figure out how long it is, so we can get
-     * progress info.
-     */
-    input->length = ftello(input->file);
-    rewind(input->file);
-  }
-
-  /* Default to 1:1 pixel aspect ratio. */
-  input->pixel_aspect_ratio.numerator = 1;
-  input->pixel_aspect_ratio.denominator = 1;
-
-  /* For RAW input sources, these bytes will applied on the first frame
-   *  in read_frame().
-   */
-  input->detect.buf_read = fread(input->detect.buf, 1, 4, input->file);
-  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, csp,
-                       input->only_i420) >= 0) {
-      input->file_type = FILE_TYPE_Y4M;
-      input->width = input->y4m.pic_w;
-      input->height = input->y4m.pic_h;
-      input->pixel_aspect_ratio.numerator = input->y4m.par_n;
-      input->pixel_aspect_ratio.denominator = input->y4m.par_d;
-      input->framerate.numerator = input->y4m.fps_n;
-      input->framerate.denominator = input->y4m.fps_d;
-      input->fmt = input->y4m.aom_fmt;
-      input->bit_depth = input->y4m.bit_depth;
-    } else {
-      fatal("Unsupported Y4M stream.");
-    }
-  } else if (input->detect.buf_read == 4 && fourcc_is_ivf(input->detect.buf)) {
-    fatal("IVF is not supported as input.");
-  } else {
-    input->file_type = FILE_TYPE_RAW;
-  }
-}
-
 // Note: these rate control metrics assume only 1 key frame in the
 // sequence (i.e., first frame only). So for temporal pattern# 7
 // (which has key frame for every frame on base layer), the metrics
@@ -614,31 +896,24 @@
   }
 }
 
-int main(int argc, char **argv) {
+int main(int argc, const char **argv) {
+  AppInput app_input;
   AvxVideoWriter *outfile[AOM_MAX_LAYERS] = { NULL };
   aom_codec_enc_cfg_t cfg;
   int frame_cnt = 0;
   aom_image_t raw;
-  aom_codec_err_t res;
-  unsigned int width;
-  unsigned int height;
-  uint32_t error_resilient = 0;
-  int speed;
   int frame_avail;
   int got_data = 0;
   int flags = 0;
   unsigned i;
   int pts = 0;             // PTS starts at 0.
   int frame_duration = 1;  // 1 timebase tick per frame.
-  int layering_mode = 0;
   aom_svc_layer_id_t layer_id;
   aom_svc_params_t svc_params;
   aom_svc_ref_frame_config_t ref_frame_config;
-  struct AvxInputContext input_ctx;
+
   struct RateControlMetrics rc;
   int64_t cx_time = 0;
-  const int min_args_base = 13;
-  const int min_args = min_args_base;
   double sum_bitrate = 0.0;
   double sum_bitrate2 = 0.0;
   double framerate = 30.0;
@@ -646,7 +921,7 @@
   int set_err_resil_frame = 0;
   zero(rc.layer_target_bitrate);
   memset(&layer_id, 0, sizeof(aom_svc_layer_id_t));
-  memset(&input_ctx, 0, sizeof(input_ctx));
+  memset(&app_input, 0, sizeof(AppInput));
   memset(&svc_params, 0, sizeof(svc_params));
 
   // Flag to test dynamic scaling of source frames for single
@@ -654,77 +929,59 @@
   const int test_dynamic_scaling_single_layer = 0;
 
   /* Setup default input stream settings */
-  input_ctx.framerate.numerator = 30;
-  input_ctx.framerate.denominator = 1;
-  input_ctx.only_i420 = 1;
-  input_ctx.bit_depth = 0;
-  unsigned int ts_number_layers = 1;
-  unsigned int ss_number_layers = 1;
+  app_input.input_ctx.framerate.numerator = 30;
+  app_input.input_ctx.framerate.denominator = 1;
+  app_input.input_ctx.only_i420 = 1;
+  app_input.input_ctx.bit_depth = 0;
   exec_name = argv[0];
-  // Check usage and arguments.
-  if (argc < min_args) {
-    die("Usage: %s <infile> <outfile> <codec_type(av1)> <width> <height> "
-        "<rate_num> <rate_den> <speed> <frame_drop_threshold> "
-        "<error_resilient> <threads> <mode> "
-        "<Rate_0> ... <Rate_nlayers-1>\n",
-        argv[0]);
+
+  // start with default encoder configuration
+  aom_codec_err_t res =
+      aom_codec_enc_config_default(aom_codec_av1_cx(), &cfg, 0);
+  if (res) {
+    die("Failed to get config: %s\n", aom_codec_err_to_string(res));
   }
 
-  aom_codec_iface_t *encoder = get_aom_encoder_by_short_name(argv[3]);
+  // Real time parameters.
+  cfg.g_usage = AOM_USAGE_REALTIME;
 
-  width = (unsigned int)strtoul(argv[4], NULL, 0);
-  height = (unsigned int)strtoul(argv[5], NULL, 0);
-  if (width < 16 || width % 2 || height < 16 || height % 2) {
-    die("Invalid resolution: %d x %d", width, height);
+  cfg.rc_end_usage = AOM_CBR;
+  cfg.rc_min_quantizer = 2;
+  cfg.rc_max_quantizer = 52;
+  cfg.rc_undershoot_pct = 50;
+  cfg.rc_overshoot_pct = 50;
+  cfg.rc_buf_initial_sz = 600;
+  cfg.rc_buf_optimal_sz = 600;
+  cfg.rc_buf_sz = 1000;
+  cfg.rc_resize_mode = 0;  // Set to RESIZE_DYNAMIC for dynamic resize.
+  cfg.g_lag_in_frames = 0;
+  cfg.kf_mode = AOM_KF_AUTO;
+
+  parse_command_line(argc, argv, &app_input, &svc_params, &cfg);
+
+  unsigned int ts_number_layers = svc_params.number_temporal_layers;
+  unsigned int ss_number_layers = svc_params.number_spatial_layers;
+
+  unsigned int width = cfg.g_w;
+  unsigned int height = cfg.g_h;
+
+  if (ts_number_layers !=
+          mode_to_num_temporal_layers[app_input.layering_mode] ||
+      ss_number_layers != mode_to_num_spatial_layers[app_input.layering_mode]) {
+    die("Number of layers doesn't match layering mode.");
   }
 
-  layering_mode = (int)strtol(argv[12], NULL, 0);
-  if (layering_mode < 0 || layering_mode > 13) {
-    die("Invalid layering mode (0..12) %s", argv[12]);
-  }
-
-  if (argc != min_args + mode_to_num_layers[layering_mode]) {
-    die("Invalid number of arguments");
-  }
-
-  ts_number_layers = mode_to_num_temporal_layers[layering_mode];
-  ss_number_layers = mode_to_num_spatial_layers[layering_mode];
-
-  input_ctx.filename = argv[1];
-  open_input_file(&input_ctx, 0);
-
   // Y4M reader has its own allocation.
-  if (input_ctx.file_type != FILE_TYPE_Y4M) {
+  if (app_input.input_ctx.file_type != FILE_TYPE_Y4M) {
     if (!aom_img_alloc(&raw, AOM_IMG_FMT_I420, width, height, 32)) {
       die("Failed to allocate image", width, height);
     }
   }
 
-  // Populate encoder configuration.
-  res = aom_codec_enc_config_default(encoder, &cfg, 0);
-  if (res) {
-    printf("Failed to get config: %s\n", aom_codec_err_to_string(res));
-    return EXIT_FAILURE;
-  }
+  aom_codec_iface_t *encoder = get_aom_encoder_by_short_name("av1");
 
-  // Update the default configuration with our settings.
-  cfg.g_w = width;
-  cfg.g_h = height;
-
-  // Timebase format e.g. 30fps: numerator=1, demoninator = 30.
-  cfg.g_timebase.num = (int)strtol(argv[6], NULL, 0);
-  cfg.g_timebase.den = (int)strtol(argv[7], NULL, 0);
-
-  speed = (int)strtol(argv[8], NULL, 0);
-  if (speed < 0 || speed > 8) {
-    die("Invalid speed setting: must be positive");
-  }
-
-  for (i = min_args_base;
-       (int)i < min_args_base + mode_to_num_layers[layering_mode]; ++i) {
-    rc.layer_target_bitrate[i - 13] = (int)strtol(argv[i], NULL, 0);
-    svc_params.layer_target_bitrate[i - 13] = rc.layer_target_bitrate[i - 13];
-  }
+  memcpy(&rc.layer_target_bitrate[0], &svc_params.layer_target_bitrate[0],
+         sizeof(svc_params.layer_target_bitrate));
 
   cfg.rc_target_bitrate =
       svc_params.layer_target_bitrate[ss_number_layers * ts_number_layers - 1];
@@ -739,44 +996,16 @@
     svc_params.framerate_factor[2] = 1;
   }
 
-  // Real time parameters.
-  cfg.g_usage = AOM_USAGE_REALTIME;
-
-  cfg.rc_dropframe_thresh = (unsigned int)strtoul(argv[9], NULL, 0);
-  cfg.rc_end_usage = AOM_CBR;
-  cfg.rc_min_quantizer = 2;
-  cfg.rc_max_quantizer = 52;
-  cfg.rc_undershoot_pct = 50;
-  cfg.rc_overshoot_pct = 50;
-  cfg.rc_buf_initial_sz = 600;
-  cfg.rc_buf_optimal_sz = 600;
-  cfg.rc_buf_sz = 1000;
-  cfg.rc_resize_mode = 0;  // Set to RESIZE_DYNAMIC for dynamic resize.
-
-  // Use 1 thread as default.
-  cfg.g_threads = (unsigned int)strtoul(argv[11], NULL, 0);
-
-  error_resilient = (uint32_t)strtoul(argv[10], NULL, 0);
-  if (error_resilient != 0 && error_resilient != 1) {
-    die("Invalid value for error resilient (0, 1): %d.", error_resilient);
-  }
-  // Enable error resilient mode.
-  cfg.g_error_resilient = error_resilient;
-  cfg.g_lag_in_frames = 0;
-  cfg.kf_mode = AOM_KF_AUTO;
-
-  // Disable automatic keyframe placement.
-  cfg.kf_min_dist = cfg.kf_max_dist = 3000;
-
   framerate = cfg.g_timebase.den / cfg.g_timebase.num;
   set_rate_control_metrics(&rc, framerate, ss_number_layers, ts_number_layers);
 
-  if (input_ctx.file_type == FILE_TYPE_Y4M) {
-    if (input_ctx.width != cfg.g_w || input_ctx.height != cfg.g_h) {
+  if (app_input.input_ctx.file_type == FILE_TYPE_Y4M) {
+    if (app_input.input_ctx.width != cfg.g_w ||
+        app_input.input_ctx.height != cfg.g_h) {
       die("Incorrect width or height: %d x %d", cfg.g_w, cfg.g_h);
     }
-    if (input_ctx.framerate.numerator != cfg.g_timebase.den ||
-        input_ctx.framerate.denominator != cfg.g_timebase.num) {
+    if (app_input.input_ctx.framerate.numerator != cfg.g_timebase.den ||
+        app_input.input_ctx.framerate.denominator != cfg.g_timebase.num) {
       die("Incorrect framerate: numerator %d denominator %d",
           cfg.g_timebase.num, cfg.g_timebase.den);
     }
@@ -794,7 +1023,8 @@
       info.time_base.numerator = cfg.g_timebase.num;
       info.time_base.denominator = cfg.g_timebase.den;
 
-      snprintf(file_name, sizeof(file_name), "%s_%d.av1", argv[2], i);
+      snprintf(file_name, sizeof(file_name), "%s_%d.av1",
+               app_input.output_filename, i);
       outfile[i] = aom_video_writer_open(file_name, kContainerIVF, &info);
       if (!outfile[i]) die("Failed to open %s for writing", file_name);
       assert(outfile[i] != NULL);
@@ -806,8 +1036,8 @@
   if (aom_codec_enc_init(&codec, encoder, &cfg, 0))
     die("Failed to initialize encoder");
 
-  aom_codec_control(&codec, AOME_SET_CPUUSED, speed);
-  aom_codec_control(&codec, AV1E_SET_AQ_MODE, 3);
+  aom_codec_control(&codec, AOME_SET_CPUUSED, app_input.speed);
+  aom_codec_control(&codec, AV1E_SET_AQ_MODE, app_input.aq_mode);
   aom_codec_control(&codec, AV1E_SET_GF_CBR_BOOST_PCT, 0);
   aom_codec_control(&codec, AV1E_SET_ENABLE_CDEF, 1);
   aom_codec_control(&codec, AV1E_SET_ENABLE_ORDER_HINT, 0);
@@ -851,7 +1081,7 @@
   frame_avail = 1;
   while (frame_avail || got_data) {
     struct aom_usec_timer timer;
-    frame_avail = read_frame(&input_ctx, &raw);
+    frame_avail = read_frame(&(app_input.input_ctx), &raw);
     int is_key_frame = (frame_cnt % cfg.kf_max_dist) == 0;
     // Loop over spatial layers.
     for (unsigned int slx = 0; slx < ss_number_layers; slx++) {
@@ -861,9 +1091,9 @@
 
       // Set the reference/update flags, layer_id, and reference_map
       // buffer index.
-      set_layer_pattern(layering_mode, frame_cnt, &layer_id, &ref_frame_config,
-                        &use_svc_control, slx, is_key_frame,
-                        (layering_mode == 9));
+      set_layer_pattern(app_input.layering_mode, frame_cnt, &layer_id,
+                        &ref_frame_config, &use_svc_control, slx, is_key_frame,
+                        (app_input.layering_mode == 9));
       aom_codec_control(&codec, AV1E_SET_SVC_LAYER_ID, &layer_id);
       if (use_svc_control)
         aom_codec_control(&codec, AV1E_SET_SVC_REF_FRAME_CONFIG,
@@ -964,7 +1194,7 @@
     ++frame_cnt;
     pts += frame_duration;
   }
-  close_input_file(&input_ctx);
+  close_input_file(&(app_input.input_ctx));
   printout_rate_control_summary(&rc, frame_cnt, ss_number_layers,
                                 ts_number_layers);
   printf("\n");
@@ -978,7 +1208,7 @@
   for (i = 0; i < ss_number_layers * ts_number_layers; ++i)
     aom_video_writer_close(outfile[i]);
 
-  if (input_ctx.file_type != FILE_TYPE_Y4M) {
+  if (app_input.input_ctx.file_type != FILE_TYPE_Y4M) {
     aom_img_free(&raw);
   }
   return EXIT_SUCCESS;