Added rate-targeted temporal scalability

Added the ability to create rate-targeted, temporally
scalable, VP8 compatible bitstreams.

The application vp8_scalable_patterns.c demonstrates how
to use this capability. Users can create output bitstreams
containing upto 5 temporally separable streams encoded
as a single VP8 bitstream.
(previously abandoned as:
I92d1483e887adb274d07ce9e567e4d0314881b0a)

Change-Id: I156250a3fe930be57c069d508c41b6a7a4ea8d6a
diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c
index ca4e505..f833624 100644
--- a/vp8/vp8_cx_iface.c
+++ b/vp8/vp8_cx_iface.c
@@ -218,6 +218,25 @@
     }
 #endif
 
+    RANGE_CHECK(cfg, ts_number_layers, 1, 5);
+
+    if (cfg->ts_number_layers > 1)
+    {
+        int i;
+        RANGE_CHECK_HI(cfg, ts_periodicity, 16);
+
+        for (i=1; i<cfg->ts_number_layers; i++)
+            if (cfg->ts_target_bitrate[i] <= cfg->ts_target_bitrate[i-1])
+                ERROR("ts_target_bitrate entries are not strictly increasing");
+
+        RANGE_CHECK(cfg, ts_rate_decimator[cfg->ts_number_layers-1], 1, 1);
+        for (i=cfg->ts_number_layers-2; i>0; i--)
+            if (cfg->ts_rate_decimator[i-1] != 2*cfg->ts_rate_decimator[i])
+                ERROR("ts_rate_decimator factors are not powers of 2");
+
+        RANGE_CHECK_HI(cfg, ts_layer_id[i], cfg->ts_number_layers-1);
+    }
+
     return VPX_CODEC_OK;
 }
 
@@ -253,14 +272,15 @@
     oxcf->Width                 = cfg.g_w;
     oxcf->Height                = cfg.g_h;
     /* guess a frame rate if out of whack, use 30 */
-    oxcf->frame_rate             = (double)(cfg.g_timebase.den) / (double)(cfg.g_timebase.num);
+    oxcf->frame_rate = (double)(cfg.g_timebase.den) /
+                       (double)(cfg.g_timebase.num);
 
     if (oxcf->frame_rate > 180)
     {
         oxcf->frame_rate = 30;
     }
 
-    oxcf->error_resilient_mode    = cfg.g_error_resilient;
+    oxcf->error_resilient_mode = cfg.g_error_resilient;
 
     switch (cfg.g_pass)
     {
@@ -277,13 +297,13 @@
 
     if (cfg.g_pass == VPX_RC_FIRST_PASS)
     {
-        oxcf->allow_lag              = 0;
-        oxcf->lag_in_frames           = 0;
+        oxcf->allow_lag     = 0;
+        oxcf->lag_in_frames = 0;
     }
     else
     {
-        oxcf->allow_lag              = (cfg.g_lag_in_frames) > 0;
-        oxcf->lag_in_frames           = cfg.g_lag_in_frames;
+        oxcf->allow_lag     = (cfg.g_lag_in_frames) > 0;
+        oxcf->lag_in_frames = cfg.g_lag_in_frames;
     }
 
     oxcf->allow_df               = (cfg.rc_dropframe_thresh > 0);
@@ -295,59 +315,71 @@
 
     if (cfg.rc_end_usage == VPX_VBR)
     {
-        oxcf->end_usage          = USAGE_LOCAL_FILE_PLAYBACK;
+        oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK;
     }
     else if (cfg.rc_end_usage == VPX_CBR)
     {
-        oxcf->end_usage          = USAGE_STREAM_FROM_SERVER;
+        oxcf->end_usage = USAGE_STREAM_FROM_SERVER;
     }
     else if (cfg.rc_end_usage == VPX_CQ)
     {
-        oxcf->end_usage          = USAGE_CONSTRAINED_QUALITY;
+        oxcf->end_usage = USAGE_CONSTRAINED_QUALITY;
     }
 
-    oxcf->target_bandwidth       = cfg.rc_target_bitrate;
+    oxcf->target_bandwidth         = cfg.rc_target_bitrate;
     oxcf->rc_max_intra_bitrate_pct = vp8_cfg.rc_max_intra_bitrate_pct;
 
-    oxcf->best_allowed_q          = cfg.rc_min_quantizer;
-    oxcf->worst_allowed_q         = cfg.rc_max_quantizer;
-    oxcf->cq_level                = vp8_cfg.cq_level;
+    oxcf->best_allowed_q           = cfg.rc_min_quantizer;
+    oxcf->worst_allowed_q          = cfg.rc_max_quantizer;
+    oxcf->cq_level                 = vp8_cfg.cq_level;
     oxcf->fixed_q = -1;
 
-    oxcf->under_shoot_pct         = cfg.rc_undershoot_pct;
-    oxcf->over_shoot_pct          = cfg.rc_overshoot_pct;
+    oxcf->under_shoot_pct          = cfg.rc_undershoot_pct;
+    oxcf->over_shoot_pct           = cfg.rc_overshoot_pct;
 
-    oxcf->maximum_buffer_size     = cfg.rc_buf_sz;
-    oxcf->starting_buffer_level   = cfg.rc_buf_initial_sz;
-    oxcf->optimal_buffer_level    = cfg.rc_buf_optimal_sz;
+    oxcf->maximum_buffer_size      = cfg.rc_buf_sz;
+    oxcf->starting_buffer_level    = cfg.rc_buf_initial_sz;
+    oxcf->optimal_buffer_level     = cfg.rc_buf_optimal_sz;
 
-    oxcf->two_pass_vbrbias        = cfg.rc_2pass_vbr_bias_pct;
+    oxcf->two_pass_vbrbias         = cfg.rc_2pass_vbr_bias_pct;
     oxcf->two_pass_vbrmin_section  = cfg.rc_2pass_vbr_minsection_pct;
     oxcf->two_pass_vbrmax_section  = cfg.rc_2pass_vbr_maxsection_pct;
 
-    oxcf->auto_key               = cfg.kf_mode == VPX_KF_AUTO
-                                   && cfg.kf_min_dist != cfg.kf_max_dist;
-    //oxcf->kf_min_dist         = cfg.kf_min_dis;
-    oxcf->key_freq               = cfg.kf_max_dist;
+    oxcf->auto_key                 = cfg.kf_mode == VPX_KF_AUTO
+                                       && cfg.kf_min_dist != cfg.kf_max_dist;
+    //oxcf->kf_min_dist            = cfg.kf_min_dis;
+    oxcf->key_freq                 = cfg.kf_max_dist;
+
+    oxcf->number_of_layers         = cfg.ts_number_layers;
+    oxcf->periodicity              = cfg.ts_periodicity;
+
+    if (oxcf->number_of_layers > 1)
+    {
+        memcpy (oxcf->target_bitrate, cfg.ts_target_bitrate,
+                          sizeof(cfg.ts_target_bitrate));
+        memcpy (oxcf->rate_decimator, cfg.ts_rate_decimator,
+                          sizeof(cfg.ts_rate_decimator));
+        memcpy (oxcf->layer_id, cfg.ts_layer_id, sizeof(cfg.ts_layer_id));
+    }
 
     //oxcf->delete_first_pass_file = cfg.g_delete_firstpassfile;
     //strcpy(oxcf->first_pass_file, cfg.g_firstpass_file);
 
-    oxcf->cpu_used               =  vp8_cfg.cpu_used;
-    oxcf->encode_breakout        =  vp8_cfg.static_thresh;
-    oxcf->play_alternate         =  vp8_cfg.enable_auto_alt_ref;
-    oxcf->noise_sensitivity      =  vp8_cfg.noise_sensitivity;
-    oxcf->Sharpness             =  vp8_cfg.Sharpness;
-    oxcf->token_partitions       =  vp8_cfg.token_partitions;
+    oxcf->cpu_used               = vp8_cfg.cpu_used;
+    oxcf->encode_breakout        = vp8_cfg.static_thresh;
+    oxcf->play_alternate         = vp8_cfg.enable_auto_alt_ref;
+    oxcf->noise_sensitivity      = vp8_cfg.noise_sensitivity;
+    oxcf->Sharpness              = vp8_cfg.Sharpness;
+    oxcf->token_partitions       = vp8_cfg.token_partitions;
 
-    oxcf->two_pass_stats_in        =  cfg.rc_twopass_stats_in;
-    oxcf->output_pkt_list         =  vp8_cfg.pkt_list;
+    oxcf->two_pass_stats_in      = cfg.rc_twopass_stats_in;
+    oxcf->output_pkt_list        = vp8_cfg.pkt_list;
 
-    oxcf->arnr_max_frames = vp8_cfg.arnr_max_frames;
-    oxcf->arnr_strength =  vp8_cfg.arnr_strength;
-    oxcf->arnr_type =      vp8_cfg.arnr_type;
+    oxcf->arnr_max_frames        = vp8_cfg.arnr_max_frames;
+    oxcf->arnr_strength          = vp8_cfg.arnr_strength;
+    oxcf->arnr_type              = vp8_cfg.arnr_type;
 
-    oxcf->tuning = vp8_cfg.tuning;
+    oxcf->tuning                 = vp8_cfg.tuning;
 
     /*
         printf("Current VP8 Settings: \n");
@@ -515,7 +547,7 @@
 
         cfg =  &ctx->priv->alg_priv->cfg;
 
-        /* Select the extra vp6 configuration table based on the current
+        /* Select the extra vp8 configuration table based on the current
          * usage value. If the current usage value isn't found, use the
          * values for usage case 0.
          */
@@ -1143,6 +1175,12 @@
         1,                  /* g_delete_first_pass_file */
         "vp8.fpf"           /* first pass filename */
 #endif
+
+        1,                  /* ts_number_layers */
+        {0},                /* ts_target_bitrate */
+        {0},                /* ts_rate_decimator */
+        0,                  /* ts_periodicity */
+        {0},                /* ts_layer_id */
     }},
     { -1, {NOT_IMPLEMENTED}}
 };