LCOV - code coverage report
Current view: top level - dom/media/webrtc - MediaEngineCameraVideoSource.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 158 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 15 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       3             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "MediaEngineCameraVideoSource.h"
       6             : 
       7             : #include "mozilla/IntegerPrintfMacros.h"
       8             : #include "mozilla/SizePrintfMacros.h"
       9             : 
      10             : #include <limits>
      11             : 
      12             : namespace mozilla {
      13             : 
      14             : using namespace mozilla::gfx;
      15             : using namespace mozilla::dom;
      16             : 
      17             : extern LogModule* GetMediaManagerLog();
      18             : #define LOG(msg) MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Debug, msg)
      19             : #define LOGFRAME(msg) MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Verbose, msg)
      20             : 
      21             : // guts for appending data to the MSG track
      22           0 : bool MediaEngineCameraVideoSource::AppendToTrack(SourceMediaStream* aSource,
      23             :                                                  layers::Image* aImage,
      24             :                                                  TrackID aID,
      25             :                                                  StreamTime delta,
      26             :                                                  const PrincipalHandle& aPrincipalHandle)
      27             : {
      28           0 :   MOZ_ASSERT(aSource);
      29             : 
      30           0 :   VideoSegment segment;
      31           0 :   RefPtr<layers::Image> image = aImage;
      32           0 :   IntSize size(image ? mWidth : 0, image ? mHeight : 0);
      33           0 :   segment.AppendFrame(image.forget(), delta, size, aPrincipalHandle);
      34             : 
      35             :   // This is safe from any thread, and is safe if the track is Finished
      36             :   // or Destroyed.
      37             :   // This can fail if either a) we haven't added the track yet, or b)
      38             :   // we've removed or finished the track.
      39           0 :   return aSource->AppendToTrack(aID, &(segment));
      40             : }
      41             : 
      42             : // Sub-classes (B2G or desktop) should overload one of both of these two methods
      43             : // to provide capabilities
      44             : size_t
      45           0 : MediaEngineCameraVideoSource::NumCapabilities() const
      46             : {
      47           0 :   return mHardcodedCapabilities.Length();
      48             : }
      49             : 
      50             : void
      51           0 : MediaEngineCameraVideoSource::GetCapability(size_t aIndex,
      52             :                                             webrtc::CaptureCapability& aOut) const
      53             : {
      54           0 :   MOZ_ASSERT(aIndex < mHardcodedCapabilities.Length());
      55           0 :   aOut = mHardcodedCapabilities.SafeElementAt(aIndex, webrtc::CaptureCapability());
      56           0 : }
      57             : 
      58             : uint32_t
      59           0 : MediaEngineCameraVideoSource::GetFitnessDistance(
      60             :     const webrtc::CaptureCapability& aCandidate,
      61             :     const NormalizedConstraintSet &aConstraints,
      62             :     const nsString& aDeviceId) const
      63             : {
      64             :   // Treat width|height|frameRate == 0 on capability as "can do any".
      65             :   // This allows for orthogonal capabilities that are not in discrete steps.
      66             : 
      67             :   uint64_t distance =
      68           0 :     uint64_t(FitnessDistance(aDeviceId, aConstraints.mDeviceId)) +
      69           0 :     uint64_t(FitnessDistance(mFacingMode, aConstraints.mFacingMode)) +
      70           0 :     uint64_t(aCandidate.width? FitnessDistance(int32_t(aCandidate.width),
      71           0 :                                                aConstraints.mWidth) : 0) +
      72           0 :     uint64_t(aCandidate.height? FitnessDistance(int32_t(aCandidate.height),
      73           0 :                                                 aConstraints.mHeight) : 0) +
      74           0 :     uint64_t(aCandidate.maxFPS? FitnessDistance(double(aCandidate.maxFPS),
      75           0 :                                                 aConstraints.mFrameRate) : 0);
      76           0 :   return uint32_t(std::min(distance, uint64_t(UINT32_MAX)));
      77             : }
      78             : 
      79             : // Find best capability by removing inferiors. May leave >1 of equal distance
      80             : 
      81             : /* static */ void
      82           0 : MediaEngineCameraVideoSource::TrimLessFitCandidates(CapabilitySet& set) {
      83           0 :   uint32_t best = UINT32_MAX;
      84           0 :   for (auto& candidate : set) {
      85           0 :     if (best > candidate.mDistance) {
      86           0 :       best = candidate.mDistance;
      87             :     }
      88             :   }
      89           0 :   for (size_t i = 0; i < set.Length();) {
      90           0 :     if (set[i].mDistance > best) {
      91           0 :       set.RemoveElementAt(i);
      92             :     } else {
      93           0 :       ++i;
      94             :     }
      95             :   }
      96           0 :   MOZ_ASSERT(set.Length());
      97           0 : }
      98             : 
      99             : // GetBestFitnessDistance returns the best distance the capture device can offer
     100             : // as a whole, given an accumulated number of ConstraintSets.
     101             : // Ideal values are considered in the first ConstraintSet only.
     102             : // Plain values are treated as Ideal in the first ConstraintSet.
     103             : // Plain values are treated as Exact in subsequent ConstraintSets.
     104             : // Infinity = UINT32_MAX e.g. device cannot satisfy accumulated ConstraintSets.
     105             : // A finite result may be used to calculate this device's ranking as a choice.
     106             : 
     107             : uint32_t
     108           0 : MediaEngineCameraVideoSource::GetBestFitnessDistance(
     109             :     const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
     110             :     const nsString& aDeviceId) const
     111             : {
     112           0 :   size_t num = NumCapabilities();
     113             : 
     114           0 :   CapabilitySet candidateSet;
     115           0 :   for (size_t i = 0; i < num; i++) {
     116           0 :     candidateSet.AppendElement(i);
     117             :   }
     118             : 
     119           0 :   bool first = true;
     120           0 :   for (const NormalizedConstraintSet* ns : aConstraintSets) {
     121           0 :     for (size_t i = 0; i < candidateSet.Length();  ) {
     122           0 :       auto& candidate = candidateSet[i];
     123           0 :       webrtc::CaptureCapability cap;
     124           0 :       GetCapability(candidate.mIndex, cap);
     125           0 :       uint32_t distance = GetFitnessDistance(cap, *ns, aDeviceId);
     126           0 :       if (distance == UINT32_MAX) {
     127           0 :         candidateSet.RemoveElementAt(i);
     128             :       } else {
     129           0 :         ++i;
     130           0 :         if (first) {
     131           0 :           candidate.mDistance = distance;
     132             :         }
     133             :       }
     134             :     }
     135           0 :     first = false;
     136             :   }
     137           0 :   if (!candidateSet.Length()) {
     138           0 :     return UINT32_MAX;
     139             :   }
     140           0 :   TrimLessFitCandidates(candidateSet);
     141           0 :   return candidateSet[0].mDistance;
     142             : }
     143             : 
     144             : void
     145           0 : MediaEngineCameraVideoSource::LogConstraints(
     146             :     const NormalizedConstraintSet& aConstraints)
     147             : {
     148           0 :   auto& c = aConstraints;
     149           0 :   if (c.mWidth.mIdeal.isSome()) {
     150           0 :     LOG(("Constraints: width: { min: %d, max: %d, ideal: %d }",
     151             :          c.mWidth.mMin, c.mWidth.mMax,
     152             :          c.mWidth.mIdeal.valueOr(0)));
     153             :   } else {
     154           0 :     LOG(("Constraints: width: { min: %d, max: %d }",
     155             :          c.mWidth.mMin, c.mWidth.mMax));
     156             :   }
     157           0 :   if (c.mHeight.mIdeal.isSome()) {
     158           0 :     LOG(("             height: { min: %d, max: %d, ideal: %d }",
     159             :          c.mHeight.mMin, c.mHeight.mMax,
     160             :          c.mHeight.mIdeal.valueOr(0)));
     161             :   } else {
     162           0 :     LOG(("             height: { min: %d, max: %d }",
     163             :          c.mHeight.mMin, c.mHeight.mMax));
     164             :   }
     165           0 :   if (c.mFrameRate.mIdeal.isSome()) {
     166           0 :     LOG(("             frameRate: { min: %f, max: %f, ideal: %f }",
     167             :          c.mFrameRate.mMin, c.mFrameRate.mMax,
     168             :          c.mFrameRate.mIdeal.valueOr(0)));
     169             :   } else {
     170           0 :     LOG(("             frameRate: { min: %f, max: %f }",
     171             :          c.mFrameRate.mMin, c.mFrameRate.mMax));
     172             :   }
     173           0 : }
     174             : 
     175             : void
     176           0 : MediaEngineCameraVideoSource::LogCapability(const char* aHeader,
     177             :     const webrtc::CaptureCapability &aCapability, uint32_t aDistance)
     178             : {
     179             :   // RawVideoType and VideoCodecType media/webrtc/trunk/webrtc/common_types.h
     180             :   static const char* const types[] = {
     181             :     "I420",
     182             :     "YV12",
     183             :     "YUY2",
     184             :     "UYVY",
     185             :     "IYUV",
     186             :     "ARGB",
     187             :     "RGB24",
     188             :     "RGB565",
     189             :     "ARGB4444",
     190             :     "ARGB1555",
     191             :     "MJPEG",
     192             :     "NV12",
     193             :     "NV21",
     194             :     "BGRA",
     195             :     "Unknown type"
     196             :   };
     197             : 
     198             :   static const char* const codec[] = {
     199             :     "VP8",
     200             :     "VP9",
     201             :     "H264",
     202             :     "I420",
     203             :     "RED",
     204             :     "ULPFEC",
     205             :     "Generic codec",
     206             :     "Unknown codec"
     207             :   };
     208             : 
     209           0 :   LOG(("%s: %4u x %4u x %2u maxFps, %s, %s. Distance = %" PRIu32,
     210             :        aHeader, aCapability.width, aCapability.height, aCapability.maxFPS,
     211             :        types[std::min(std::max(uint32_t(0), uint32_t(aCapability.rawType)),
     212             :                       uint32_t(sizeof(types) / sizeof(*types) - 1))],
     213             :        codec[std::min(std::max(uint32_t(0), uint32_t(aCapability.codecType)),
     214             :                       uint32_t(sizeof(codec) / sizeof(*codec) - 1))],
     215             :        aDistance));
     216           0 : }
     217             : 
     218             : bool
     219           0 : MediaEngineCameraVideoSource::ChooseCapability(
     220             :     const NormalizedConstraints &aConstraints,
     221             :     const MediaEnginePrefs &aPrefs,
     222             :     const nsString& aDeviceId)
     223             : {
     224           0 :   if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) {
     225           0 :     LOG(("ChooseCapability: prefs: %dx%d @%d-%dfps",
     226             :          aPrefs.GetWidth(), aPrefs.GetHeight(),
     227             :          aPrefs.mFPS, aPrefs.mMinFPS));
     228           0 :     LogConstraints(aConstraints);
     229           0 :     if (aConstraints.mAdvanced.size()) {
     230           0 :       LOG(("Advanced array[%" PRIuSIZE "]:", aConstraints.mAdvanced.size()));
     231           0 :       for (auto& advanced : aConstraints.mAdvanced) {
     232           0 :         LogConstraints(advanced);
     233             :       }
     234             :     }
     235             :   }
     236             : 
     237           0 :   size_t num = NumCapabilities();
     238             : 
     239           0 :   CapabilitySet candidateSet;
     240           0 :   for (size_t i = 0; i < num; i++) {
     241           0 :     candidateSet.AppendElement(i);
     242             :   }
     243             : 
     244             :   // First, filter capabilities by required constraints (min, max, exact).
     245             : 
     246           0 :   for (size_t i = 0; i < candidateSet.Length();) {
     247           0 :     auto& candidate = candidateSet[i];
     248           0 :     webrtc::CaptureCapability cap;
     249           0 :     GetCapability(candidate.mIndex, cap);
     250           0 :     candidate.mDistance = GetFitnessDistance(cap, aConstraints, aDeviceId);
     251           0 :     LogCapability("Capability", cap, candidate.mDistance);
     252           0 :     if (candidate.mDistance == UINT32_MAX) {
     253           0 :       candidateSet.RemoveElementAt(i);
     254             :     } else {
     255           0 :       ++i;
     256             :     }
     257             :   }
     258             : 
     259           0 :   if (!candidateSet.Length()) {
     260           0 :     LOG(("failed to find capability match from %" PRIuSIZE " choices",num));
     261           0 :     return false;
     262             :   }
     263             : 
     264             :   // Filter further with all advanced constraints (that don't overconstrain).
     265             : 
     266           0 :   for (const auto &cs : aConstraints.mAdvanced) {
     267           0 :     CapabilitySet rejects;
     268           0 :     for (size_t i = 0; i < candidateSet.Length();) {
     269           0 :       auto& candidate = candidateSet[i];
     270           0 :       webrtc::CaptureCapability cap;
     271           0 :       GetCapability(candidate.mIndex, cap);
     272           0 :       if (GetFitnessDistance(cap, cs, aDeviceId) == UINT32_MAX) {
     273           0 :         rejects.AppendElement(candidate);
     274           0 :         candidateSet.RemoveElementAt(i);
     275             :       } else {
     276           0 :         ++i;
     277             :       }
     278             :     }
     279           0 :     if (!candidateSet.Length()) {
     280           0 :       candidateSet.AppendElements(Move(rejects));
     281             :     }
     282             :   }
     283           0 :   MOZ_ASSERT(candidateSet.Length(),
     284             :              "advanced constraints filtering step can't reduce candidates to zero");
     285             : 
     286             :   // Remaining algorithm is up to the UA.
     287             : 
     288           0 :   TrimLessFitCandidates(candidateSet);
     289             : 
     290             :   // Any remaining multiples all have the same distance. A common case of this
     291             :   // occurs when no ideal is specified. Lean toward defaults.
     292           0 :   uint32_t sameDistance = candidateSet[0].mDistance;
     293             :   {
     294           0 :     MediaTrackConstraintSet prefs;
     295           0 :     prefs.mWidth.SetAsLong() = aPrefs.GetWidth();
     296           0 :     prefs.mHeight.SetAsLong() = aPrefs.GetHeight();
     297           0 :     prefs.mFrameRate.SetAsDouble() = aPrefs.mFPS;
     298           0 :     NormalizedConstraintSet normPrefs(prefs, false);
     299             : 
     300           0 :     for (auto& candidate : candidateSet) {
     301           0 :       webrtc::CaptureCapability cap;
     302           0 :       GetCapability(candidate.mIndex, cap);
     303           0 :       candidate.mDistance = GetFitnessDistance(cap, normPrefs, aDeviceId);
     304             :     }
     305           0 :     TrimLessFitCandidates(candidateSet);
     306             :   }
     307             : 
     308             :   // Any remaining multiples all have the same distance, but may vary on
     309             :   // format. Some formats are more desirable for certain use like WebRTC.
     310             :   // E.g. I420 over RGB24 can remove a needless format conversion.
     311             : 
     312           0 :   bool found = false;
     313           0 :   for (auto& candidate : candidateSet) {
     314           0 :     webrtc::CaptureCapability cap;
     315           0 :     GetCapability(candidate.mIndex, cap);
     316           0 :     if (cap.rawType == webrtc::RawVideoType::kVideoI420 ||
     317           0 :         cap.rawType == webrtc::RawVideoType::kVideoYUY2 ||
     318           0 :         cap.rawType == webrtc::RawVideoType::kVideoYV12) {
     319           0 :       mCapability = cap;
     320           0 :       found = true;
     321           0 :       break;
     322             :     }
     323             :   }
     324           0 :   if (!found) {
     325           0 :     GetCapability(candidateSet[0].mIndex, mCapability);
     326             :   }
     327             : 
     328           0 :   LogCapability("Chosen capability", mCapability, sameDistance);
     329           0 :   return true;
     330             : }
     331             : 
     332             : void
     333           0 : MediaEngineCameraVideoSource::SetName(nsString aName)
     334             : {
     335           0 :   mDeviceName = aName;
     336           0 :   bool hasFacingMode = false;
     337           0 :   VideoFacingModeEnum facingMode = VideoFacingModeEnum::User;
     338             : 
     339             :   // Set facing mode based on device name.
     340             : #if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
     341             :   // Names are generated. Example: "Camera 0, Facing back, Orientation 90"
     342             :   //
     343             :   // See media/webrtc/trunk/webrtc/modules/video_capture/android/java/src/org/
     344             :   // webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java
     345             : 
     346             :   if (aName.Find(NS_LITERAL_STRING("Facing back")) != kNotFound) {
     347             :     hasFacingMode = true;
     348             :     facingMode = VideoFacingModeEnum::Environment;
     349             :   } else if (aName.Find(NS_LITERAL_STRING("Facing front")) != kNotFound) {
     350             :     hasFacingMode = true;
     351             :     facingMode = VideoFacingModeEnum::User;
     352             :   }
     353             : #endif // ANDROID
     354             : #ifdef XP_MACOSX
     355             :   // Kludge to test user-facing cameras on OSX.
     356             :   if (aName.Find(NS_LITERAL_STRING("Face")) != -1) {
     357             :     hasFacingMode = true;
     358             :     facingMode = VideoFacingModeEnum::User;
     359             :   }
     360             : #endif
     361             : #ifdef XP_WIN
     362             :   // The cameras' name of Surface book are "Microsoft Camera Front" and
     363             :   // "Microsoft Camera Rear" respectively.
     364             : 
     365             :   if (aName.Find(NS_LITERAL_STRING("Front")) != kNotFound) {
     366             :     hasFacingMode = true;
     367             :     facingMode = VideoFacingModeEnum::User;
     368             :   } else if (aName.Find(NS_LITERAL_STRING("Rear")) != kNotFound) {
     369             :     hasFacingMode = true;
     370             :     facingMode = VideoFacingModeEnum::Environment;
     371             :   }
     372             : #endif // WINDOWS
     373           0 :   if (hasFacingMode) {
     374           0 :     mFacingMode.Assign(NS_ConvertUTF8toUTF16(
     375           0 :         VideoFacingModeEnumValues::strings[uint32_t(facingMode)].value));
     376             :   } else {
     377           0 :     mFacingMode.Truncate();
     378             :   }
     379           0 : }
     380             : 
     381             : void
     382           0 : MediaEngineCameraVideoSource::GetName(nsAString& aName) const
     383             : {
     384           0 :   aName = mDeviceName;
     385           0 : }
     386             : 
     387             : void
     388           0 : MediaEngineCameraVideoSource::SetUUID(const char* aUUID)
     389             : {
     390           0 :   mUniqueId.Assign(aUUID);
     391           0 : }
     392             : 
     393             : void
     394           0 : MediaEngineCameraVideoSource::GetUUID(nsACString& aUUID) const
     395             : {
     396           0 :   aUUID = mUniqueId;
     397           0 : }
     398             : 
     399             : const nsCString&
     400           0 : MediaEngineCameraVideoSource::GetUUID() const
     401             : {
     402           0 :   return mUniqueId;
     403             : }
     404             : 
     405             : void
     406           0 : MediaEngineCameraVideoSource::SetDirectListeners(bool aHasDirectListeners)
     407             : {
     408           0 :   LOG((__FUNCTION__));
     409           0 :   mHasDirectListeners = aHasDirectListeners;
     410           0 : }
     411             : 
     412             : } // namespace mozilla

Generated by: LCOV version 1.13