uint32_t MediaEngineCameraVideoSource::GetBestFitnessDistance( const nsTArray<const MediaTrackConstraintSet*>& aConstraintSets) { size_t num = NumCapabilities(); CapabilitySet candidateSet; for (size_t i = 0; i < num; i++) { candidateSet.AppendElement(i); } bool first = true; for (const MediaTrackConstraintSet* cs : aConstraintSets) { for (size_t i = 0; i < candidateSet.Length(); ) { auto& candidate = candidateSet[i]; webrtc::CaptureCapability cap; GetCapability(candidate.mIndex, cap); uint32_t distance = GetFitnessDistance(cap, *cs, !first); if (distance == UINT32_MAX) { candidateSet.RemoveElementAt(i); } else { ++i; if (first) { candidate.mDistance = distance; } } } first = false; } if (!candidateSet.Length()) { return UINT32_MAX; } TrimLessFitCandidates(candidateSet); return candidateSet[0].mDistance; }
bool MediaEngineCameraVideoSource::ChooseCapability( const MediaTrackConstraints &aConstraints, const MediaEnginePrefs &aPrefs, const nsString& aDeviceId) { if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) { LOG(("ChooseCapability: prefs: %dx%d @%d-%dfps", aPrefs.GetWidth(), aPrefs.GetHeight(), aPrefs.mFPS, aPrefs.mMinFPS)); LogConstraints(aConstraints, false); if (aConstraints.mAdvanced.WasPassed()) { LOG(("Advanced array[%u]:", aConstraints.mAdvanced.Value().Length())); for (auto& advanced : aConstraints.mAdvanced.Value()) { LogConstraints(advanced, true); } } } size_t num = NumCapabilities(); CapabilitySet candidateSet; for (size_t i = 0; i < num; i++) { candidateSet.AppendElement(i); } // First, filter capabilities by required constraints (min, max, exact). for (size_t i = 0; i < candidateSet.Length();) { auto& candidate = candidateSet[i]; webrtc::CaptureCapability cap; GetCapability(candidate.mIndex, cap); candidate.mDistance = GetFitnessDistance(cap, aConstraints, false, aDeviceId); LogCapability("Capability", cap, candidate.mDistance); if (candidate.mDistance == UINT32_MAX) { candidateSet.RemoveElementAt(i); } else { ++i; } } // Filter further with all advanced constraints (that don't overconstrain). if (aConstraints.mAdvanced.WasPassed()) { for (const MediaTrackConstraintSet &cs : aConstraints.mAdvanced.Value()) { CapabilitySet rejects; for (size_t i = 0; i < candidateSet.Length();) { auto& candidate = candidateSet[i]; webrtc::CaptureCapability cap; GetCapability(candidate.mIndex, cap); if (GetFitnessDistance(cap, cs, true, aDeviceId) == UINT32_MAX) { rejects.AppendElement(candidate); candidateSet.RemoveElementAt(i); } else { ++i; } } if (!candidateSet.Length()) { candidateSet.AppendElements(Move(rejects)); } } } if (!candidateSet.Length()) { LOG(("failed to find capability match from %d choices",num)); return false; } // Remaining algorithm is up to the UA. TrimLessFitCandidates(candidateSet); // Any remaining multiples all have the same distance. A common case of this // occurs when no ideal is specified. Lean toward defaults. uint32_t sameDistance = candidateSet[0].mDistance; { MediaTrackConstraintSet prefs; prefs.mWidth.SetAsLong() = aPrefs.GetWidth(); prefs.mHeight.SetAsLong() = aPrefs.GetHeight(); prefs.mFrameRate.SetAsDouble() = aPrefs.mFPS; for (auto& candidate : candidateSet) { webrtc::CaptureCapability cap; GetCapability(candidate.mIndex, cap); candidate.mDistance = GetFitnessDistance(cap, prefs, false, aDeviceId); } TrimLessFitCandidates(candidateSet); } // Any remaining multiples all have the same distance, but may vary on // format. Some formats are more desirable for certain use like WebRTC. // E.g. I420 over RGB24 can remove a needless format conversion. bool found = false; for (auto& candidate : candidateSet) { webrtc::CaptureCapability cap; GetCapability(candidate.mIndex, cap); if (cap.rawType == webrtc::RawVideoType::kVideoI420 || cap.rawType == webrtc::RawVideoType::kVideoYUY2 || cap.rawType == webrtc::RawVideoType::kVideoYV12) { mCapability = cap; found = true; break; } } if (!found) { GetCapability(candidateSet[0].mIndex, mCapability); } LogCapability("Chosen capability", mCapability, sameDistance); return true; }