Add field trial for screenshare bitrates when using temporal layers.

BUG=
R=pbos@webrtc.org, pthatcher@webrtc.org, stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/31209004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@7976 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/libjingle_tests.gyp b/talk/libjingle_tests.gyp
index b59a7ef..c8d78c2 100755
--- a/talk/libjingle_tests.gyp
+++ b/talk/libjingle_tests.gyp
@@ -110,6 +110,7 @@
         'media/devices/dummydevicemanager_unittest.cc',
         'media/devices/filevideocapturer_unittest.cc',
         'media/sctp/sctpdataengine_unittest.cc',
+        'media/webrtc/simulcast_unittest.cc',
         'media/webrtc/webrtcpassthroughrender_unittest.cc',
         'media/webrtc/webrtcvideocapturer_unittest.cc',
         'media/base/videoframe_unittest.h',
diff --git a/talk/media/webrtc/simulcast.cc b/talk/media/webrtc/simulcast.cc
index 289aaca..68a9d60 100755
--- a/talk/media/webrtc/simulcast.cc
+++ b/talk/media/webrtc/simulcast.cc
@@ -25,13 +25,15 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <stdio.h>
+
 #include "talk/media/base/mediachannel.h"  // For VideoOptions
 #include "talk/media/base/streamparams.h"
 #include "talk/media/webrtc/simulcast.h"
 #include "webrtc/base/common.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/common_types.h"  // For webrtc::VideoCodec
-
+#include "webrtc/system_wrappers/interface/field_trial.h"
 namespace cricket {
 
 struct SimulcastFormat {
@@ -71,9 +73,6 @@
     kDefaultConferenceNumberOfTemporalLayers[webrtc::kMaxSimulcastStreams] =
     {3, 3, 3, 3};
 
-static const int kScreencastWithTemporalLayerTargetVideoBitrate = 100;
-static const int kScreencastWithTemporalLayerMaxVideoBitrate = 1000;
-
 void GetSimulcastSsrcs(const StreamParams& sp, std::vector<uint32>* ssrcs) {
   const SsrcGroup* sim_group = sp.get_ssrc_group(kSimSsrcGroupSemantics);
   if (sim_group) {
@@ -414,10 +413,64 @@
   }
 }
 
+static const int kScreenshareMinBitrateKbps = 50;
+static const int kScreenshareMaxBitrateKbps = 6000;
+static const int kScreenshareDefaultTl0BitrateKbps = 100;
+static const int kScreenshareDefaultTl1BitrateKbps = 1000;
+
+static const char* kScreencastLayerFieldTrialName =
+    "WebRTC-ScreenshareLayerRates";
+
+ScreenshareLayerConfig::ScreenshareLayerConfig(int tl0_bitrate, int tl1_bitrate)
+    : tl0_bitrate_kbps(tl0_bitrate), tl1_bitrate_kbps(tl1_bitrate) {
+}
+
+ScreenshareLayerConfig ScreenshareLayerConfig::GetDefault() {
+  std::string group =
+      webrtc::field_trial::FindFullName(kScreencastLayerFieldTrialName);
+
+  ScreenshareLayerConfig config(kScreenshareDefaultTl0BitrateKbps,
+                                kScreenshareDefaultTl1BitrateKbps);
+  if (!group.empty() && !FromFieldTrialGroup(group, &config)) {
+    LOG(LS_WARNING) << "Unable to parse WebRTC-ScreenshareLayerRates"
+                       " field trial group: '" << group << "'.";
+  }
+  return config;
+}
+
+bool ScreenshareLayerConfig::FromFieldTrialGroup(
+    const std::string& group,
+    ScreenshareLayerConfig* config) {
+  // Parse field trial group name, containing bitrates for tl0 and tl1.
+  int tl0_bitrate;
+  int tl1_bitrate;
+  if (sscanf(group.c_str(), "%d-%d", &tl0_bitrate, &tl1_bitrate) != 2) {
+    return false;
+  }
+
+  // Sanity check.
+  if (tl0_bitrate < kScreenshareMinBitrateKbps ||
+      tl0_bitrate > kScreenshareMaxBitrateKbps ||
+      tl1_bitrate < kScreenshareMinBitrateKbps ||
+      tl1_bitrate > kScreenshareMaxBitrateKbps || tl0_bitrate > tl1_bitrate) {
+    return false;
+  }
+
+  config->tl0_bitrate_kbps = tl0_bitrate;
+  config->tl1_bitrate_kbps = tl1_bitrate;
+
+  return true;
+}
+
 void ConfigureConferenceModeScreencastCodec(webrtc::VideoCodec* codec) {
   codec->codecSpecific.VP8.numberOfTemporalLayers = 2;
-  codec->maxBitrate = kScreencastWithTemporalLayerMaxVideoBitrate;
-  codec->targetBitrate = kScreencastWithTemporalLayerTargetVideoBitrate;
+  ScreenshareLayerConfig config = ScreenshareLayerConfig::GetDefault();
+
+  // For screenshare in conference mode, tl0 and tl1 bitrates are piggybacked
+  // on the VideoCodec struct as target and max bitrates, respectively.
+  // See eg. webrtc::VP8EncoderImpl::SetRates().
+  codec->targetBitrate = config.tl0_bitrate_kbps;
+  codec->maxBitrate = config.tl1_bitrate_kbps;
 }
 
 }  // namespace cricket
diff --git a/talk/media/webrtc/simulcast.h b/talk/media/webrtc/simulcast.h
index be80973..4a7eeca 100755
--- a/talk/media/webrtc/simulcast.h
+++ b/talk/media/webrtc/simulcast.h
@@ -47,6 +47,23 @@
   SBM_COUNT
 };
 
+// Config for use with screen cast when temporal layers are enabled.
+struct ScreenshareLayerConfig {
+ public:
+  ScreenshareLayerConfig(int tl0_bitrate, int tl1_bitrate);
+
+  // Bitrates, for temporal layers 0 and 1.
+  int tl0_bitrate_kbps;
+  int tl1_bitrate_kbps;
+
+  static ScreenshareLayerConfig GetDefault();
+
+  // Parse bitrate from group name on format "(tl0_bitrate)-(tl1_bitrate)",
+  // eg. "100-1000" for the default rates.
+  static bool FromFieldTrialGroup(const std::string& group,
+                                  ScreenshareLayerConfig* config);
+};
+
 // TODO(pthatcher): Write unit tests just for these functions,
 // independent of WebrtcVideoEngine.
 
diff --git a/talk/media/webrtc/simulcast_unittest.cc b/talk/media/webrtc/simulcast_unittest.cc
new file mode 100644
index 0000000..e6b97f7
--- /dev/null
+++ b/talk/media/webrtc/simulcast_unittest.cc
@@ -0,0 +1,73 @@
+/*
+ * libjingle
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+
+#include "talk/media/webrtc/simulcast.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cricket {
+
+class ScreenshareLayerConfigTest : public testing::Test,
+                                   protected ScreenshareLayerConfig {
+ public:
+  ScreenshareLayerConfigTest() : ScreenshareLayerConfig(0, 0) {}
+
+  void ExpectParsingFails(const std::string& group) {
+    ScreenshareLayerConfig config(100, 1000);
+    EXPECT_FALSE(FromFieldTrialGroup(group, &config));
+  }
+};
+
+TEST_F(ScreenshareLayerConfigTest, UsesDefaultBitrateConfigForDefaultGroup) {
+  ExpectParsingFails("");
+}
+
+TEST_F(ScreenshareLayerConfigTest, UsesDefaultConfigForInvalidBitrates) {
+  ExpectParsingFails("-");
+  ExpectParsingFails("1-");
+  ExpectParsingFails("-1");
+  ExpectParsingFails("-12");
+  ExpectParsingFails("12-");
+  ExpectParsingFails("booh!");
+  ExpectParsingFails("1-b");
+  ExpectParsingFails("a-2");
+  ExpectParsingFails("49-1000");
+  ExpectParsingFails("50-6001");
+  ExpectParsingFails("100-99");
+  ExpectParsingFails("1002003004005006-99");
+  ExpectParsingFails("99-1002003004005006");
+}
+
+TEST_F(ScreenshareLayerConfigTest, ParsesValidBitrateConfig) {
+  ScreenshareLayerConfig config(100, 1000);
+  EXPECT_TRUE(ScreenshareLayerConfig::FromFieldTrialGroup("101-1001", &config));
+  EXPECT_EQ(101, config.tl0_bitrate_kbps);
+  EXPECT_EQ(1001, config.tl1_bitrate_kbps);
+}
+
+}  // namespace cricket
diff --git a/talk/media/webrtc/webrtcvideoengine2.cc b/talk/media/webrtc/webrtcvideoengine2.cc
index 0b72fdf..09dd4e1 100644
--- a/talk/media/webrtc/webrtcvideoengine2.cc
+++ b/talk/media/webrtc/webrtcvideoengine2.cc
@@ -131,8 +131,6 @@
 
 static const int kDefaultRtcpReceiverReportSsrc = 1;
 
-static const int kConferenceModeTemporalLayerBitrateBps = 100000;
-
 // External video encoders are given payloads 120-127. This also means that we
 // only support up to 8 external payload types.
 static const int kExternalVideoPayloadTypeBase = 120;
@@ -1657,9 +1655,17 @@
   // Conference mode screencast uses 2 temporal layers split at 100kbit.
   if (parameters_.options.conference_mode.GetWithDefaultIfUnset(false) &&
       dimensions.is_screencast && encoder_config.streams.size() == 1) {
+    ScreenshareLayerConfig config = ScreenshareLayerConfig::GetDefault();
+
+    // For screenshare in conference mode, tl0 and tl1 bitrates are piggybacked
+    // on the VideoCodec struct as target and max bitrates, respectively.
+    // See eg. webrtc::VP8EncoderImpl::SetRates().
+    encoder_config.streams[0].target_bitrate_bps =
+        config.tl0_bitrate_kbps * 1000;
+    encoder_config.streams[0].max_bitrate_bps = config.tl1_bitrate_kbps * 1000;
     encoder_config.streams[0].temporal_layer_thresholds_bps.clear();
     encoder_config.streams[0].temporal_layer_thresholds_bps.push_back(
-        kConferenceModeTemporalLayerBitrateBps);
+        config.tl0_bitrate_kbps * 1000);
   }
   return encoder_config;
 }
diff --git a/webrtc/modules/video_coding/BUILD.gn b/webrtc/modules/video_coding/BUILD.gn
index 7a7b0f0..eebd085 100644
--- a/webrtc/modules/video_coding/BUILD.gn
+++ b/webrtc/modules/video_coding/BUILD.gn
@@ -85,8 +85,8 @@
 
 source_set("video_coding_utility") {
   sources = [
-    "utility/include/frame_dropper.h",
     "utility/frame_dropper.cc",
+    "utility/include/frame_dropper.h",
     "utility/quality_scaler.cc",
     "utility/quality_scaler.h",
   ]