Bug 1243607: make webrtc bitrate prefs take precedence over automatic bitrate selection r?pkerr draft
authorRandell Jesup <rjesup@jesup.org>
Wed, 27 Jan 2016 20:36:22 -0500
changeset 326434 10db5bdfd3be859b60c5e47796779da533a40c9a
parent 326333 60435dd84e92e8652eef2ac81c04459788ad852e
child 513615 fb2a1e4dc4fb305aa532e4f0329a40370546b51a
push id10155
push userrjesup@wgate.com
push dateThu, 28 Jan 2016 01:40:31 +0000
reviewerspkerr
bugs1243607
milestone47.0a1
Bug 1243607: make webrtc bitrate prefs take precedence over automatic bitrate selection r?pkerr
media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
media/webrtc/signaling/src/media-conduit/VideoConduit.h
modules/libpref/init/all.js
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -85,19 +85,19 @@ WebrtcVideoConduit::WebrtcVideoConduit()
   mSendingHeight(0),
   mReceivingWidth(640),
   mReceivingHeight(480),
   mSendingFramerate(DEFAULT_VIDEO_MAX_FRAMERATE),
   mLastFramerateTenths(DEFAULT_VIDEO_MAX_FRAMERATE*10),
   mNumReceivingStreams(1),
   mVideoLatencyTestEnable(false),
   mVideoLatencyAvg(0),
-  mMinBitrate(200),
-  mStartBitrate(300),
-  mMaxBitrate(2000),
+  mMinBitrate(0),
+  mStartBitrate(0),
+  mMaxBitrate(0),
   mCodecMode(webrtc::kRealtimeVideo)
 {}
 
 WebrtcVideoConduit::~WebrtcVideoConduit()
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
 
@@ -281,16 +281,25 @@ WebrtcVideoConduit::InitMain()
       (void) NS_WARN_IF(NS_FAILED(branch->GetIntPref("media.peerconnection.video.start_bitrate", &temp)));
       if (temp >= 0) {
         mStartBitrate = temp;
       }
       (void) NS_WARN_IF(NS_FAILED(branch->GetIntPref("media.peerconnection.video.max_bitrate", &temp)));
       if (temp >= 0) {
         mMaxBitrate = temp;
       }
+      if (mMinBitrate != 0 && mMinBitrate < webrtc::kViEMinCodecBitrate) {
+        mMinBitrate = webrtc::kViEMinCodecBitrate;
+      }
+      if (mStartBitrate < mMinBitrate) {
+        mStartBitrate = mMinBitrate;
+      }
+      if (mStartBitrate > mMaxBitrate) {
+        mStartBitrate = mMaxBitrate;
+      }
       bool use_loadmanager = false;
       (void) NS_WARN_IF(NS_FAILED(branch->GetBoolPref("media.navigator.load_adapt", &use_loadmanager)));
       if (use_loadmanager) {
         mLoadManager = LoadManagerBuild();
       }
     }
   }
 
@@ -956,73 +965,87 @@ WebrtcVideoConduit::ConfigureRecvMediaCo
   mPtrRTP->SetRembStatus(mChannel, false, true);
   DumpCodecDB();
   return kMediaConduitNoError;
 }
 
 struct ResolutionAndBitrateLimits {
   uint32_t resolution_in_mb;
   uint16_t min_bitrate;
+  uint16_t start_bitrate;
   uint16_t max_bitrate;
 };
 
 #define MB_OF(w,h) ((unsigned int)((((w)>>4))*((unsigned int)((h)>>4))))
 
 // For now, try to set the max rates well above the knee in the curve.
 // Chosen somewhat arbitrarily; it's hard to find good data oriented for
 // realtime interactive/talking-head recording.  These rates assume
 // 30fps.
 
 // XXX Populate this based on a pref (which we should consider sorting because
 // people won't assume they need to).
 static ResolutionAndBitrateLimits kResolutionAndBitrateLimits[] = {
-  {MB_OF(1920, 1200), 1500, 10000}, // >HD (3K, 4K, etc)
-  {MB_OF(1280, 720), 1200, 5000}, // HD ~1080-1200
-  {MB_OF(800, 480), 600, 2500}, // HD ~720
-  {std::max(MB_OF(400, 240), MB_OF(352, 288)), 200, 1300}, // VGA, WVGA
-  {MB_OF(176, 144), 100, 500}, // WQVGA, CIF
-  {0 , 40, 250} // QCIF and below
+  {MB_OF(1920, 1200), 1500, 2000, 10000}, // >HD (3K, 4K, etc)
+  {MB_OF(1280, 720), 1200, 1500, 5000}, // HD ~1080-1200
+  {MB_OF(800, 480), 600, 800, 2500}, // HD ~720
+  {std::max(MB_OF(400, 240), MB_OF(352, 288)), 200, 300, 1300}, // VGA, WVGA
+  {MB_OF(176, 144), 100, 150, 500}, // WQVGA, CIF
+  {0 , 40, 80, 250} // QCIF and below
 };
 
-static void
-SelectBandwidth(webrtc::VideoCodec& vie_codec,
-                unsigned short width,
-                unsigned short height,
-                mozilla::Atomic<int32_t, mozilla::Relaxed>& aLastFramerateTenths)
+void
+WebrtcVideoConduit::SelectBandwidth(webrtc::VideoCodec& vie_codec,
+                                    unsigned short width,
+                                    unsigned short height,
+                                    mozilla::Atomic<int32_t, mozilla::Relaxed>& aLastFramerateTenths)
 {
   // max bandwidth should be proportional (not linearly!) to resolution, and
   // proportional (perhaps linearly, or close) to current frame rate.
   unsigned int fs, mb_width, mb_height;
 
   mb_width = (width + 15) >> 4;
   mb_height = (height + 15) >> 4;
   fs = mb_width * mb_height;
 
   for (ResolutionAndBitrateLimits resAndLimits : kResolutionAndBitrateLimits) {
     if (fs > resAndLimits.resolution_in_mb) {
       vie_codec.minBitrate = resAndLimits.min_bitrate;
+      vie_codec.startBitrate = resAndLimits.start_bitrate;
       vie_codec.maxBitrate = resAndLimits.max_bitrate;
       break;
     }
   }
 
   // mLastFramerateTenths is an atomic, and scaled by *10
   double framerate = std::min((aLastFramerateTenths/10.),60.0);
   MOZ_ASSERT(framerate > 0);
   // Now linear reduction/increase based on fps (max 60fps i.e. doubling)
   if (framerate >= 10) {
     vie_codec.minBitrate = vie_codec.minBitrate * (framerate/30);
+    vie_codec.startBitrate = vie_codec.startBitrate * (framerate/30);
     vie_codec.maxBitrate = vie_codec.maxBitrate * (framerate/30);
   } else {
     // At low framerates, don't reduce bandwidth as much - cut slope to 1/2.
     // Mostly this would be ultra-low-light situations/mobile or screensharing.
     vie_codec.minBitrate = vie_codec.minBitrate * ((10-(framerate/2))/30);
+    vie_codec.startBitrate = vie_codec.startBitrate * ((10-(framerate/2))/30);
     vie_codec.maxBitrate = vie_codec.maxBitrate * ((10-(framerate/2))/30);
   }
 
+  if (mMinBitrate && mMinBitrate > vie_codec.minBitrate) {
+    vie_codec.minBitrate = mMinBitrate;
+  }
+  if (mStartBitrate && mStartBitrate > vie_codec.startBitrate) {
+    vie_codec.startBitrate = mStartBitrate;
+  }
+  if (mMaxBitrate && mMaxBitrate > vie_codec.maxBitrate) {
+    vie_codec.maxBitrate = mMaxBitrate;
+  }
+
   // If we try to set a minimum bitrate that is too low, ViE will reject it.
   vie_codec.minBitrate = std::max((unsigned int) webrtc::kViEMinCodecBitrate,
                                   vie_codec.minBitrate);
 }
 
 static void ConstrainPreservingAspectRatioExact(uint32_t max_fs,
                                                 unsigned short* width,
                                                 unsigned short* height)
@@ -1776,19 +1799,22 @@ WebrtcVideoConduit::CodecConfigToWebRTCC
   // width/height will be overridden on the first frame; they must be 'sane' for
   // SetSendCodec()
   if (codecInfo->mEncodingConstraints.maxFps > 0) {
     cinst.maxFramerate = codecInfo->mEncodingConstraints.maxFps;
   } else {
     cinst.maxFramerate = DEFAULT_VIDEO_MAX_FRAMERATE;
   }
 
-  cinst.minBitrate = mMinBitrate;
-  cinst.startBitrate = mStartBitrate;
-  cinst.maxBitrate = mMaxBitrate;
+  // Defaults if rates aren't forced by pref.  Typically defaults are
+  // overridden on the first video frame.
+  cinst.minBitrate = mMinBitrate ? mMinBitrate : 200;
+  cinst.startBitrate = mStartBitrate ? mStartBitrate : 300;
+  cinst.targetBitrate = cinst.startBitrate;
+  cinst.maxBitrate = mMaxBitrate ? mMaxBitrate : 2000;
 
   if (cinst.codecType == webrtc::kVideoCodecH264)
   {
 #ifdef MOZ_WEBRTC_OMX
     cinst.resolution_divisor = 16;
 #endif
     // cinst.codecSpecific.H264.profile = ?
     cinst.codecSpecific.H264.profile_byte = codecInfo->mProfile;
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.h
@@ -134,16 +134,27 @@ public:
    * Register Transport for this Conduit. RTP and RTCP frames from the VideoEngine
    * shall be passed to the registered transport for transporting externally.
    */
   virtual MediaConduitErrorCode SetTransmitterTransport(RefPtr<TransportInterface> aTransport) override;
 
   virtual MediaConduitErrorCode SetReceiverTransport(RefPtr<TransportInterface> aTransport) override;
 
   /**
+   * Function to set the encoding bitrate limits based on incoming frame size and rate
+   * @param vie_codec: codec config structure to modify
+   * @param width, height: dimensions of the frame
+   * @param aLastFramerateTenths: holds the current input framerate
+   */
+  void SelectBandwidth(webrtc::VideoCodec& vie_codec,
+                       unsigned short width,
+                       unsigned short height,
+                       mozilla::Atomic<int32_t, mozilla::Relaxed>& aLastFramerateTenths);
+
+  /**
    * Function to select and change the encoding resolution based on incoming frame size
    * and current available bandwidth.
    * @param width, height: dimensions of the frame
    * @param frame: optional frame to submit for encoding after reconfig
    */
   bool SelectSendResolution(unsigned short width,
                             unsigned short height,
                             webrtc::I420VideoFrame *frame);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -379,40 +379,37 @@ pref("media.peerconnection.video.enabled
 pref("media.navigator.video.max_fs", 1200); // 640x480 == 1200mb
 pref("media.navigator.video.max_fr", 30);
 pref("media.navigator.video.h264.level", 12); // 0x42E00C - level 1.2
 pref("media.navigator.video.h264.max_br", 700); // 8x10
 pref("media.navigator.video.h264.max_mbps", 11880); // CIF@30fps
 pref("media.peerconnection.video.h264_enabled", false);
 pref("media.peerconnection.video.vp9_enabled", false);
 pref("media.getusermedia.aec", 4);
-// Gonk typically captures at QVGA, and so min resolution is QQVGA or
-// 160x120; 100Kbps is plenty for that.
-pref("media.peerconnection.video.min_bitrate", 100);
-pref("media.peerconnection.video.start_bitrate", 220);
-pref("media.peerconnection.video.max_bitrate", 1000);
 #else
 pref("media.navigator.video.default_width",0);  // adaptive default
 pref("media.navigator.video.default_height",0); // adaptive default
 pref("media.peerconnection.enabled", true);
 pref("media.peerconnection.video.enabled", true);
 pref("media.navigator.video.max_fs", 12288); // Enough for 2048x1536
 pref("media.navigator.video.max_fr", 60);
 pref("media.navigator.video.h264.level", 31); // 0x42E01f - level 3.1
 pref("media.navigator.video.h264.max_br", 0);
 pref("media.navigator.video.h264.max_mbps", 0);
 pref("media.peerconnection.video.h264_enabled", false);
 pref("media.getusermedia.aec", 1);
 pref("media.getusermedia.browser.enabled", true);
+#endif
+// Gonk typically captures at QVGA, and so min resolution is QQVGA or
+// 160x120; 100Kbps is plenty for that.
 // Desktop is typically VGA capture or more; and qm_select will not drop resolution
 // below 1/2 in each dimension (or so), so QVGA (320x200) is the lowest here usually.
-pref("media.peerconnection.video.min_bitrate", 200);
-pref("media.peerconnection.video.start_bitrate", 300);
-pref("media.peerconnection.video.max_bitrate", 2000);
-#endif
+pref("media.peerconnection.video.min_bitrate", 0);
+pref("media.peerconnection.video.start_bitrate", 0);
+pref("media.peerconnection.video.max_bitrate", 0);
 pref("media.navigator.audio.fake_frequency", 1000);
 pref("media.navigator.permission.disabled", false);
 pref("media.peerconnection.simulcast", true);
 pref("media.peerconnection.default_iceservers", "[]");
 pref("media.peerconnection.ice.loopback", false); // Set only for testing in offline environments.
 pref("media.peerconnection.ice.tcp", false);
 pref("media.peerconnection.ice.tcp_so_sock_count", 0); // Disable SO gathering
 pref("media.peerconnection.ice.link_local", false); // Set only for testing IPV6 in networks that don't assign IPV6 addresses