tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 596b5c2cfe64d63c2ac5e62b0ddf2ec94ce8acb8
parent e6ebd3a140fedea61fe28872da89a91a1c9c3490
Author: az <azebrowski@mozilla.com>
Date:   Mon,  1 Dec 2025 17:07:05 +0000

Bug 1993541 - Part 3: Add MediaCapabilitiesValidation.{h,cpp} to validate MediaCapabilities API types per spec. r=pehrsons,media-playback-reviewers,padenot

Differential Revision: https://phabricator.services.mozilla.com/D263717

Diffstat:
Mdom/media/mediacapabilities/MediaCapabilities.cpp | 2+-
Adom/media/mediacapabilities/MediaCapabilitiesValidation.cpp | 495+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adom/media/mediacapabilities/MediaCapabilitiesValidation.h | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdom/media/mediacapabilities/moz.build | 1+
4 files changed, 558 insertions(+), 1 deletion(-)

diff --git a/dom/media/mediacapabilities/MediaCapabilities.cpp b/dom/media/mediacapabilities/MediaCapabilities.cpp @@ -36,7 +36,7 @@ #include "mozilla/layers/KnowsCompositor.h" #include "nsContentUtils.h" -static mozilla::LazyLogModule sMediaCapabilitiesLog("MediaCapabilities"); +mozilla::LazyLogModule sMediaCapabilitiesLog("MediaCapabilities"); #define LOG(msg, ...) \ DDMOZ_LOG(sMediaCapabilitiesLog, LogLevel::Debug, msg, ##__VA_ARGS__) diff --git a/dom/media/mediacapabilities/MediaCapabilitiesValidation.cpp b/dom/media/mediacapabilities/MediaCapabilitiesValidation.cpp @@ -0,0 +1,495 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#include "MediaCapabilitiesValidation.h" + +#include <algorithm> +#include <array> +#include <cmath> +#include <utility> + +#include "MediaMIMETypes.h" +#include "mozilla/Assertions.h" +#include "mozilla/ErrorResult.h" +#include "mozilla/Logging.h" +#include "mozilla/Result.h" +#include "mozilla/Variant.h" +#include "mozilla/dom/MediaCapabilitiesBinding.h" +#include "mozilla/dom/Promise.h" +#include "nsReadableUtils.h" + +extern mozilla::LazyLogModule sMediaCapabilitiesLog; +#define LOG(args) MOZ_LOG(sMediaCapabilitiesLog, LogLevel::Debug, args) + +namespace mozilla::mediacaps { +using dom::AudioConfiguration; +using dom::MediaConfiguration; +using dom::MediaDecodingConfiguration; +using dom::MediaDecodingType; +using dom::MediaEncodingConfiguration; +using dom::MediaEncodingType; +using dom::MSG_INVALID_MEDIA_AUDIO_CONFIGURATION; +using dom::MSG_INVALID_MEDIA_VIDEO_CONFIGURATION; +using dom::MSG_MISSING_REQUIRED_DICTIONARY_MEMBER; +using dom::Promise; +using dom::VideoConfiguration; + +static nsAutoCString GetMIMEDebugString(const MediaConfiguration& aConfig); +static bool IsContainerType(const MediaExtendedMIMEType& aMime); +static bool IsSingleCodecType(const MediaExtendedMIMEType& aMime); + +// If encodingOrDecodingType is webrtc (MediaEncodingType) or webrtc +// (MediaDecodingType) and mimeType is not one that is used with RTP +// (as defined in the specifications of the corresponding RTP payload formats +// [IANA-MEDIA-TYPES] [RFC6838]), return unsupported. +// +// Unsupported: iLBC, iSAC (Chrome, Safari) +// https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Formats/WebRTC_codecs +static const std::array kSingleWebRTCCodecTypes = { + // "audio/ilbc"_ns, "audio/isac"_ns, + "audio/g711-alaw"_ns, "audio/g711-mlaw"_ns, "audio/g722"_ns, + "audio/opus"_ns, "audio/pcma"_ns, "audio/pcmu"_ns, + "video/av1"_ns, "video/h264"_ns, "video/vp8"_ns, + "video/vp9"_ns, +}; + +static const std::array kContainerTypes = {"video/mkv"_ns, "video/mp4"_ns, + "video/webm"_ns, "audio/ogg"_ns, + "audio/mp4"_ns, "audio/webm"_ns}; + +// https://w3c.github.io/media-capabilities/#check-mime-type-support +ValidationResult CheckMIMETypeSupport(const MediaExtendedMIMEType& aMime, + const AVType& aAVType, + const MediaType& aMediaType) { + // Step 1: If encodingOrDecodingType is webrtc (MediaEncodingType) or + // webrtc (MediaDecodingType) and mimeType is not one that is used with + // RTP (as defined in the specifications of the corresponding RTP payload + // formats [IANA-MEDIA-TYPES] [RFC6838]), return unsupported. + // TODO bug 1825286 + + // Step 2: If colorGamut is present and is not valid for mimeType, return + // unsupported. + // TODO bug 1825286 + return Ok(); +} + +// Checks MIME type validity as per: +// https://w3c.github.io/media-capabilities/#check-mime-type-validity +// NOTE: Open issue, https://github.com/w3c/media-capabilities/issues/238 +// "Do WebRTC encoding/decoding types have the single-codec restrictions?" +static ValidationResult CheckMIMETypeValidity( + const MediaExtendedMIMEType& aMime, const AVType& aAVType, + const MediaType& aMediaType) { + // Step 1: If the type of mimeType per [RFC9110] is neither + // media nor application, return false. + const MediaMIMEType& mimetype = aMime.Type(); + if (!mimetype.HasAudioMajorType() && !mimetype.HasVideoMajorType() && + !mimetype.HasApplicationMajorType()) { + ValidationResult err = + Err(aAVType == AVType::AUDIO ? ValidationError::InvalidAudioType + : ValidationError::InvalidVideoType); + LOG( + ("[Invalid MIME Validity #1, %s] Rejecting - not media, not " + "application %s", + EnumValueToString(err.unwrapErr()), aMime.OriginalString().get())); + return err; + } + + // The following two steps don't appear to be explicitly defined in the spec + // but are required for some WPT passes and seem like they'd make the most + // sense to have here. The tests in question can be found here: + // https://searchfox.org/firefox-main/rev/cd639e07f74b203d72b0f4a2bea757ae9e10401a/testing/web-platform/tests/media-capabilities/decodingInfo.any.js#140-161 + + // Step 1a?: Test that decodingInfo rejects if the audio configuration + // contentType is of type video + if (aAVType == AVType::AUDIO && !aMime.Type().HasAudioMajorType()) { + ValidationResult err = Err(ValidationError::InvalidAudioType); + LOG(("[Invalid MIME Validity #1a?, %s] Rejecting '%s'", + EnumValueToString(err.unwrapErr()), aMime.OriginalString().get())); + return err; + } + + // Step 1b?: Test that decodingInfo rejects if the video configuration + // contentType is of type audio + if (aAVType == AVType::VIDEO && !aMime.Type().HasVideoMajorType()) { + ValidationResult err = Err(ValidationError::InvalidVideoType); + LOG(("[Invalid MIME Validity #1b?, %s] Rejecting '%s'", + EnumValueToString(err.unwrapErr()), aMime.OriginalString().get())); + return err; + } + + // Step 2: If the combined type and subtype members of mimeType allow a + // single media codec and the parameters member of mimeType is not + // empty, return false. + // + // (NOTE: WEBRTC EXCEPTION, SEE ISSUE) + // https://github.com/w3c/media-capabilities/issues/238 + // TODO bug 1825286 (WebRTC) + const size_t numParams = aMime.GetParameterCount(); + if (IsSingleCodecType(aMime) && numParams != 0) { + ValidationResult err = Err(ValidationError::SingleCodecHasParams); + LOG(("[Invalid MIME Validity #2, %s] Rejecting '%s'", + EnumValueToString(err.unwrapErr()), aMime.OriginalString().get())); + return err; + } + + // Step 3: If the combined type and subtype members of mimeType allow + // multiple media codecs, run the following steps: + if (IsContainerType(aMime)) { + // Step 3.1: If the parameters member of mimeType does not contain a single + // key named "codecs", return false. + if ((numParams != 1) || !aMime.HaveCodecs()) { + ValidationResult err = Err(ValidationError::ContainerMissingCodecsParam); + LOG(("[Invalid MIME Validity #3.1, %s] Rejecting '%s'", + EnumValueToString(err.unwrapErr()), aMime.OriginalString().get())); + return err; + } + + // Step 3.2: If the value of mimeType.parameters["codecs"] does not + // describe a single media codec, return false. + const auto& codecs = aMime.Codecs(); + if (!aMime.HaveCodecs() || codecs.IsEmpty() || + codecs.AsString().FindChar(',') != kNotFound) { + ValidationResult err = Err(ValidationError::ContainerCodecsNotSingle); + LOG(("[Invalid MIME #3.2, %s] Rejecting '%s'", + EnumValueToString(err.unwrapErr()), aMime.OriginalString().get())); + return err; + } + } + + // Step 4: Return true + return Ok(); +} + +// https://w3c.github.io/media-capabilities/#audioconfiguration +ValidationResult IsValidAudioConfiguration(const AudioConfiguration& aConfig, + const MediaType& aType) { + // Step 1: Let mimeType be the result of running parse a MIME type with + // configuration’s contentType. + const Maybe<MediaExtendedMIMEType> mime = + MakeMediaExtendedMIMEType(aConfig.mContentType); + + // Step 2: If mimeType is failure, return false. + if (!mime) { + ValidationResult err = Err(ValidationError::InvalidAudioType); + LOG(("[Invalid AudioConfiguration #2, %s] Rejecting '%s'\n", + EnumValueToString(err.unwrapErr()), + NS_ConvertUTF16toUTF8(aConfig.mContentType).get())); + return err; + } + + // Return the result of running check MIME type validity with mimeType and + // audio. The channels member represents the audio channels used by the audio + // track. channels is only applicable to the decoding types media-source, + // file, and webrtc and the encoding type webrtc. + return CheckMIMETypeValidity(mime.ref(), AVType::AUDIO, aType); +} + +// https://w3c.github.io/media-capabilities/#audioconfiguration +// To check if a VideoConfiguration configuration is a valid video +// configuration, the following steps MUST be run... +template <typename CodingType> +ValidationResult IsValidVideoConfiguration(const VideoConfiguration& aConfig, + const CodingType& aType) { + static_assert(std::is_same_v<std::decay_t<CodingType>, MediaEncodingType> || + std::is_same_v<CodingType, MediaDecodingType>, + "tType must be MediaEncodingType or MediaDecodingType"); + + // Step 1: If framerate is not finite or is not greater than 0, + // return false and abort these steps. + if (!isfinite(aConfig.mFramerate) || !(aConfig.mFramerate > 0)) { + ValidationResult err = Err(ValidationError::FramerateInvalid); + LOG(("[Invalid VideoConfiguration (Framerate, %s) #1] Rejecting '%s'\n", + EnumValueToString(err.unwrapErr()), + NS_ConvertUTF16toUTF8(aConfig.mContentType).get())); + return err; + } + + // Step 2: If an optional member is specified for a MediaDecodingType or + // MediaEncodingType to which it’s not applicable, return false and abort + // these steps. See applicability rules in the member definitions below. + if constexpr (std::is_same_v<CodingType, MediaDecodingType>) { + // hdrMetadataType is only applicable to MediaDecodingConfiguration + // for types media-source and file. + if (aConfig.mHdrMetadataType.WasPassed() && + aType != MediaDecodingType::File && + aType != MediaDecodingType::Media_source) { + ValidationResult err = Err(ValidationError::InapplicableMember); + LOG(("[Invalid VideoConfiguration (HDR, %s) #2] Rejecting '%s'\n", + EnumValueToString(err.unwrapErr()), + NS_ConvertUTF16toUTF8(aConfig.mContentType).get())); + return err; + } + // colorGamut is only applicable to + // MediaDecodingConfiguration for types media-source and file. + if (aConfig.mColorGamut.WasPassed() && aType != MediaDecodingType::File && + aType != MediaDecodingType::Media_source) { + ValidationResult err = Err(ValidationError::InapplicableMember); + LOG(("[Invalid VideoConfiguration (Color Gamut, %s) #2] Rejecting '%s'\n", + EnumValueToString(err.unwrapErr()), + NS_ConvertUTF16toUTF8(aConfig.mContentType).get())); + return err; + } + + // transferFunction is only + // applicable to MediaDecodingConfiguration for types media-source and file. + if (aConfig.mTransferFunction.WasPassed() && + aType != MediaDecodingType::File && + aType != MediaDecodingType::Media_source) { + ValidationResult err = Err(ValidationError::InapplicableMember); + LOG( + ("[Invalid VideoConfiguration (Transfer Function, %s) #2] Rejecting " + "'%s'\n", + EnumValueToString(err.unwrapErr()), + NS_ConvertUTF16toUTF8(aConfig.mContentType).get())); + return err; + } + } + + // ScalabilityMode is only applicable to MediaEncodingConfiguration + // for type webrtc. + // TODO bug 1825286 + + // Step 3: Let mimeType be the result of running parse a MIME type with + // configuration’s contentType. + const Maybe<MediaExtendedMIMEType> mime = + MakeMediaExtendedMIMEType(aConfig.mContentType); + + // Step 4: If mimeType is failure, return false. + if (!mime) { + ValidationResult err = Err(ValidationError::InvalidVideoType); + LOG(("[Invalid VideoConfiguration (MIME failure, %s) #4] Rejecting '%s'\n", + EnumValueToString(err.unwrapErr()), + NS_ConvertUTF16toUTF8(aConfig.mContentType).get())); + return err; + } + + // Step 5: Return the result of running check MIME type validity + // with mimeType and video. + return CheckMIMETypeValidity(mime.ref(), AVType::VIDEO, AsVariant(aType)); +} + +template ValidationResult IsValidVideoConfiguration<MediaEncodingType>( + const VideoConfiguration&, const MediaEncodingType&); +template ValidationResult IsValidVideoConfiguration<MediaDecodingType>( + const VideoConfiguration&, const MediaDecodingType&); + +ValidationResult IsValidVideoConfiguration(const VideoConfiguration& aConfig, + const MediaType& aType) { + return aType.match( + [&](const MediaEncodingType& t) { + return IsValidVideoConfiguration(aConfig, t); + }, + [&](const MediaDecodingType& t) { + return IsValidVideoConfiguration(aConfig, t); + }); +} + +// https://w3c.github.io/media-capabilities/#mediaconfiguration +ValidationResult IsValidMediaConfiguration(const MediaConfiguration& aConfig, + const MediaType& aType) { + // Step 1: audio and/or video MUST exist. + if (!aConfig.mVideo.WasPassed() && !aConfig.mAudio.WasPassed()) { + ValidationResult err = Err(ValidationError::MissingType); + LOG(("[Invalid Media Configuration (No A/V, %s) #1] '%s'", + EnumValueToString(err.unwrapErr()), + GetMIMEDebugString(aConfig).get())); + return err; + } + + // Step 2: audio MUST be a valid audio configuration if it exists. + if (aConfig.mAudio.WasPassed()) { + auto rv = IsValidAudioConfiguration(aConfig.mAudio.Value(), aType); + if (rv.isErr()) { + LOG(("[Invalid Media Configuration (Invalid Audio, %s) #2] '%s'", + EnumValueToString(rv.unwrapErr()), + GetMIMEDebugString(aConfig).get())); + return rv; + } + } + + // Step 3: video MUST be a valid video configuration if it exists. + if (aConfig.mVideo.WasPassed()) { + auto rv = IsValidVideoConfiguration(aConfig.mVideo.Value(), aType); + if (rv.isErr()) { + LOG(("[Invalid Media Configuration (Invalid Video, %s) #3] '%s'", + EnumValueToString(rv.unwrapErr()), + GetMIMEDebugString(aConfig).get())); + return rv; + } + } + return Ok(); +} + +// No specific validation steps in the spec... +ValidationResult IsValidMediaEncodingConfiguration( + const MediaEncodingConfiguration& aConfig) { + return IsValidMediaConfiguration(aConfig, AsVariant(aConfig.mType)); +} + +// https://w3c.github.io/media-capabilities/#mediaconfiguration +ValidationResult IsValidMediaDecodingConfiguration( + const MediaDecodingConfiguration& aConfig) { + // For a MediaDecodingConfiguration to be a valid MediaDecodingConfiguration, + // all of the following conditions MUST be true: + + // Step 1: It MUST be a valid MediaConfiguration. + auto base = IsValidMediaConfiguration(aConfig, AsVariant(aConfig.mType)); + if (base.isErr()) { + LOG( + ("[Invalid MediaDecodingConfiguration (Invalid MediaConfiguration, %s) " + "#1]", + EnumValueToString(base.unwrapErr()))); + return base; + } + // Step 2: If keySystemConfiguration exists... + if (aConfig.mKeySystemConfiguration.WasPassed()) { + const auto& keySystemConfig = aConfig.mKeySystemConfiguration.Value(); + + // Step 2.1: The type MUST be media-source or file. + if (aConfig.mType != MediaDecodingType::File && + aConfig.mType != MediaDecodingType::Media_source) { + ValidationResult err = Err(ValidationError::KeySystemWrongType); + LOG(("[Invalid MediaDecodingConfiguration (keysystem, %s) #2.1]", + EnumValueToString(err.unwrapErr()))); + return err; + } + + // Step 2.2: If keySystemConfiguration.audio exists, audio MUST also exist. + if (keySystemConfig.mAudio.WasPassed() && !aConfig.mAudio.WasPassed()) { + ValidationResult err = Err(ValidationError::KeySystemAudioMissing); + LOG(("[Invalid MediaDecodingConfiguration (keysystem, %s) #2.2]", + EnumValueToString(err.unwrapErr()))); + return err; + } + + // Step 2.3: If keySystemConfiguration.video exists, video MUST also exist. + if (keySystemConfig.mVideo.WasPassed() && !aConfig.mVideo.WasPassed()) { + ValidationResult err = Err(ValidationError::KeySystemVideoMissing); + LOG(("[Invalid MediaDecodingConfiguration (keysystem, %s) #2.3]", + EnumValueToString(err.unwrapErr()))); + return err; + } + } + return Ok(); +} + +///////////////////////////////// +// Helper functions begin here // +///////////////////////////////// + +void RejectWithValidationResult(Promise* aPromise, const ValidationError aErr) { + switch (aErr) { + case ValidationError::MissingType: + aPromise->MaybeRejectWithTypeError( + "'audio' or 'video' member of argument of MediaCapabilities"); + return; + case ValidationError::InvalidAudioConfiguration: + aPromise->MaybeRejectWithTypeError("Invalid AudioConfiguration!"); + return; + case ValidationError::InvalidAudioType: + aPromise->MaybeRejectWithTypeError( + "Invalid AudioConfiguration MIME type"); + return; + case ValidationError::InvalidVideoConfiguration: + aPromise->MaybeRejectWithTypeError("Invalid VideoConfiguration!"); + return; + case ValidationError::InvalidVideoType: + aPromise->MaybeRejectWithTypeError("Invalid Video MIME type"); + return; + case ValidationError::SingleCodecHasParams: + aPromise->MaybeRejectWithTypeError("Single codec has parameters"); + return; + case ValidationError::ContainerMissingCodecsParam: + aPromise->MaybeRejectWithTypeError("Container missing codec parameters"); + return; + case ValidationError::ContainerCodecsNotSingle: + aPromise->MaybeRejectWithTypeError("Container has more than one codec"); + return; + case ValidationError::FramerateInvalid: + aPromise->MaybeRejectWithTypeError("Invalid frame rate"); + return; + case ValidationError::InapplicableMember: + aPromise->MaybeRejectWithTypeError("Inapplicable member"); + return; + case ValidationError::KeySystemWrongType: + case ValidationError::KeySystemAudioMissing: + case ValidationError::KeySystemVideoMissing: + aPromise->MaybeRejectWithTypeError("Invalid keysystem configuration"); + return; + default: + MOZ_ASSERT_UNREACHABLE("Unhandled MediaCapabilities validation error!"); + return; + } +} + +void ThrowWithValidationResult(ErrorResult& aRv, const ValidationError aErr) { + switch (aErr) { + case ValidationError::MissingType: + aRv.ThrowTypeError<MSG_MISSING_REQUIRED_DICTIONARY_MEMBER>( + "'audio' or 'video' member of argument of MediaCapabilities"); + return; + case ValidationError::InvalidAudioConfiguration: + aRv.ThrowTypeError<MSG_INVALID_MEDIA_AUDIO_CONFIGURATION>(); + return; + case ValidationError::InvalidAudioType: + case ValidationError::KeySystemAudioMissing: + aRv.ThrowTypeError<MSG_INVALID_MEDIA_AUDIO_CONFIGURATION>(); + return; + case ValidationError::InvalidVideoConfiguration: + case ValidationError::InvalidVideoType: + case ValidationError::SingleCodecHasParams: + case ValidationError::ContainerMissingCodecsParam: + case ValidationError::ContainerCodecsNotSingle: + case ValidationError::FramerateInvalid: + case ValidationError::InapplicableMember: + aRv.ThrowTypeError<MSG_INVALID_MEDIA_VIDEO_CONFIGURATION>(); + return; + case ValidationError::KeySystemWrongType: + case ValidationError::KeySystemVideoMissing: + aRv.ThrowTypeError<MSG_INVALID_MEDIA_VIDEO_CONFIGURATION>(); + return; + default: + MOZ_ASSERT_UNREACHABLE("Unhandled MediaCapabilities validation error!"); + return; + } +} + +template <size_t N> +static bool MimePrefixStartsWith( + const MediaExtendedMIMEType& aMime, + const std::array<nsLiteralCString, N>& aPrefixes) { + const nsACString& s = aMime.OriginalString(); + return std::any_of(aPrefixes.begin(), aPrefixes.end(), [&](const auto& p) { + return StringBeginsWith(s, p, nsCaseInsensitiveCStringComparator); + }); +} +static bool IsContainerType(const MediaExtendedMIMEType& aMime) { + return MimePrefixStartsWith(aMime, kContainerTypes); +} +static bool IsSingleCodecType(const MediaExtendedMIMEType& aMime) { + return MimePrefixStartsWith(aMime, kSingleWebRTCCodecTypes); +} + +static nsAutoCString GetMIMEDebugString(const MediaConfiguration& aConfig) { + nsAutoCString result; + result.SetCapacity(64); + result.AssignLiteral("Audio MIME: "); + if (aConfig.mAudio.WasPassed()) { + result.Append(NS_ConvertUTF16toUTF8(aConfig.mAudio.Value().mContentType)); + } else { + result.AppendLiteral("(none)"); + } + result.AppendLiteral(" Video MIME: "); + if (aConfig.mVideo.WasPassed()) { + result.Append(NS_ConvertUTF16toUTF8(aConfig.mVideo.Value().mContentType)); + } else { + result.AppendLiteral("(none)"); + } + return result; +} + +} // namespace mozilla::mediacaps +#undef LOG diff --git a/dom/media/mediacapabilities/MediaCapabilitiesValidation.h b/dom/media/mediacapabilities/MediaCapabilitiesValidation.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef DOM_MEDIA_MEDIACAPABILITIES_MEDIACAPABILITIESVALIDATION_H_ +#define DOM_MEDIA_MEDIACAPABILITIES_MEDIACAPABILITIESVALIDATION_H_ +#include "mozilla/DefineEnum.h" +#include "mozilla/Result.h" +#include "mozilla/Variant.h" +// Media Capabilities API spec validation check functions. +// These functions are used as a first pass to filter out non-compliant +// configurations according to the spec. Lower-level SW/HW compability checks +// are handled in MediaCapabilities.cpp. +// +// See also: +// https://github.com/w3c/media-capabilities +// commit: b9d2f30c00c534ac44179f546bc60f421ce78070 +namespace mozilla { +class ErrorResult; + +namespace dom { +class Promise; +struct MediaDecodingConfiguration; +struct MediaEncodingConfiguration; +enum class MediaEncodingType : uint8_t; +enum class MediaDecodingType : uint8_t; +} // namespace dom + +namespace mediacaps { +enum class AVType { AUDIO, VIDEO }; +MOZ_DEFINE_ENUM_CLASS_WITH_TOSTRING( + ValidationError, + (MissingType, InvalidAudioConfiguration, InvalidVideoConfiguration, + InvalidMIMEType, InvalidAudioType, InvalidVideoType, SingleCodecHasParams, + ContainerMissingCodecsParam, ContainerCodecsNotSingle, FramerateInvalid, + InapplicableMember, KeySystemWrongType, KeySystemAudioMissing, + KeySystemVideoMissing, SENTINEL)); + +// Variant to consolidate encoding/decoding checks into the same functions +using MediaType = Variant<dom::MediaEncodingType, dom::MediaDecodingType>; +using ValidationResult = mozilla::Result<mozilla::Ok, ValidationError>; + +// https://w3c.github.io/media-capabilities/#mediaconfiguration +ValidationResult IsValidMediaDecodingConfiguration( + const dom::MediaDecodingConfiguration& aConfig); + +// NOTE: No formal validation steps in the spec. +// Currently just calls IsValidMediaConfiguration. +ValidationResult IsValidMediaEncodingConfiguration( + const dom::MediaEncodingConfiguration& aConfig); + +// Helpers which also convert the validation error to text +void RejectWithValidationResult(dom::Promise* aPromise, + const ValidationError aErr); +void ThrowWithValidationResult(ErrorResult& aRv, const ValidationError aErr); +} // namespace mediacaps +} // namespace mozilla + +#endif diff --git a/dom/media/mediacapabilities/moz.build b/dom/media/mediacapabilities/moz.build @@ -9,6 +9,7 @@ EXPORTS.mozilla.dom += [ UNIFIED_SOURCES += [ "MediaCapabilities.cpp", + "MediaCapabilitiesValidation.cpp", ] include("/ipc/chromium/chromium-config.mozbuild")