Bug 1430856 - Default to two default capabilities when a camera can handle anything. r=jib a=lizzard
authorAndreas Pehrson <pehrsons@mozilla.com>
Wed, 21 Feb 2018 22:39:40 +0100
changeset 454960 2cc8275facbf5084a1be37b6bd9e503de133a141
parent 454959 b398276a70a23ffa0e2d7e4b8396bdb665ed9542
child 454961 75f5893a686fae9133324782ee4061647537e587
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjib, lizzard
bugs1430856
milestone59.0
Bug 1430856 - Default to two default capabilities when a camera can handle anything. r=jib a=lizzard If a camera returns no capabilities we interpret it as it being able to handle any capability we throw at it. However, we also end up trying to start it with the default capability of 0x0@0. This often works, but we can crash when rescaling it to the chosen target capability 0x0@0. With this patch we inject up to two default capabilities, one at 640x480@30 and one at 1280x720@30. With constraints present we'll try to adjust these defaults so they fit within the constraints while at the same time preserve the aspect ratio given by prefs. MozReview-Commit-ID: 3mr7Li5TTbV
dom/media/webrtc/MediaEngineCameraVideoSource.cpp
dom/media/webrtc/MediaEngineCameraVideoSource.h
--- a/dom/media/webrtc/MediaEngineCameraVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineCameraVideoSource.cpp
@@ -268,16 +268,65 @@ MediaEngineCameraVideoSource::ChooseCapa
   }
 
   nsTArray<CapabilityCandidate> candidateSet;
   size_t num = NumCapabilities();
   for (size_t i = 0; i < num; i++) {
     candidateSet.AppendElement(CapabilityCandidate(GetCapability(i)));
   }
 
+  if (!mHardcodedCapabilities.IsEmpty() &&
+      GetMediaSource() == MediaSourceEnum::Camera) {
+    // We have a hardcoded capability, which means this camera didn't report
+    // discrete capabilities. It might still allow a ranged capability, so we
+    // add a couple of default candidates based on prefs and constraints.
+    // The chosen candidate will be propagated to StartCapture() which will fail
+    // for an invalid candidate.
+    MOZ_DIAGNOSTIC_ASSERT(mHardcodedCapabilities.Length() == 1);
+    MOZ_DIAGNOSTIC_ASSERT(candidateSet.Length() == 1);
+    candidateSet.Clear();
+
+    FlattenedConstraints c(aConstraints);
+    // Reuse the code across both the low-definition (`false`) pref and
+    // the high-definition (`true`) pref.
+    // If there are constraints we try to satisfy them but we default to prefs.
+    // Note that since constraints are from content and can literally be
+    // anything we put (rather generous) caps on them.
+    for (bool isHd : {false, true}) {
+      webrtc::CaptureCapability cap;
+      int32_t prefWidth = aPrefs.GetWidth(isHd);
+      int32_t prefHeight = aPrefs.GetHeight(isHd);
+
+      cap.width = c.mWidth.Get(prefWidth);
+      cap.width = std::max(0, std::min(cap.width, 7680));
+
+      cap.height = c.mHeight.Get(prefHeight);
+      cap.height = std::max(0, std::min(cap.height, 4320));
+
+      cap.maxFPS = c.mFrameRate.Get(aPrefs.mFPS);
+      cap.maxFPS = std::max(0, std::min(cap.maxFPS, 480));
+
+      if (cap.width != prefWidth) {
+        // Width was affected by constraints.
+        // We'll adjust the height too so the aspect ratio is retained.
+        cap.height = cap.width * prefHeight / prefWidth;
+      } else if (cap.height != prefHeight) {
+        // Height was affected by constraints but not width.
+        // We'll adjust the width too so the aspect ratio is retained.
+        cap.width = cap.height * prefWidth / prefHeight;
+      }
+
+      if (candidateSet.Contains(cap, CapabilityComparator())) {
+        continue;
+      }
+      LogCapability("Hardcoded capability", cap, 0);
+      candidateSet.AppendElement(CapabilityCandidate(Move(cap)));
+    }
+  }
+
   // First, filter capabilities by required constraints (min, max, exact).
 
   for (size_t i = 0; i < candidateSet.Length();) {
     auto& candidate = candidateSet[i];
     candidate.mDistance =
       GetDistance(candidate.mCapability, aConstraints, aDeviceId, aCalculate);
     LogCapability("Capability", candidate.mCapability, candidate.mDistance);
     if (candidate.mDistance == UINT32_MAX) {
--- a/dom/media/webrtc/MediaEngineCameraVideoSource.h
+++ b/dom/media/webrtc/MediaEngineCameraVideoSource.h
@@ -91,16 +91,25 @@ protected:
                                  uint32_t aDistance = 0)
     : mCapability(Forward<webrtc::CaptureCapability>(aCapability))
     , mDistance(aDistance) {}
 
     const webrtc::CaptureCapability mCapability;
     uint32_t mDistance;
   };
 
+  class CapabilityComparator {
+  public:
+    bool Equals(const CapabilityCandidate& aCandidate,
+                const webrtc::CaptureCapability& aCapability) const
+    {
+      return aCandidate.mCapability == aCapability;
+    }
+  };
+
   ~MediaEngineCameraVideoSource() {}
 
   // guts for appending data to the MSG track
   virtual bool AppendToTrack(SourceMediaStream* aSource,
                              layers::Image* aImage,
                              TrackID aID,
                              StreamTime delta,
                              const PrincipalHandle& aPrincipalHandle);