mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-20 19:45:12 +00:00
LibWeb: Implement MediaCapabilities.decodingInfo()
This commit is contained in:
parent
3b577e6135
commit
0206697d36
Notes:
github-actions[bot]
2025-02-18 17:19:43 +00:00
Author: https://github.com/Psychpsyo Commit: https://github.com/LadybirdBrowser/ladybird/commit/0206697d365 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3548 Reviewed-by: https://github.com/ADKaster ✅ Reviewed-by: https://github.com/Lubrsi Reviewed-by: https://github.com/shannonbooth
10 changed files with 1047 additions and 1 deletions
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Psychpsyo <psychpsyo@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
// https://w3c.github.io/encrypted-media/#dom-mediakeysrequirement
|
||||
enum class MediaKeysRequirement {
|
||||
Required,
|
||||
Optional,
|
||||
NotAllowed
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
// https://w3c.github.io/encrypted-media/#dom-mediakeysrequirement
|
||||
enum MediaKeysRequirement {
|
||||
"required",
|
||||
"optional",
|
||||
"not-allowed"
|
||||
};
|
|
@ -64,9 +64,14 @@ enum class CanPlayTypeResult;
|
|||
enum class CanvasFillRule;
|
||||
enum class CanvasTextAlign;
|
||||
enum class CanvasTextBaseline;
|
||||
enum class ColorGamut;
|
||||
enum class DOMParserSupportedType;
|
||||
enum class EndingType;
|
||||
enum class HdrMetadataType;
|
||||
enum class ImageSmoothingQuality;
|
||||
enum class MediaDecodingType;
|
||||
enum class MediaEncodingType;
|
||||
enum class MediaKeysRequirement;
|
||||
enum class ReadableStreamReaderMode;
|
||||
enum class ReferrerPolicy;
|
||||
enum class RequestCache;
|
||||
|
@ -79,6 +84,7 @@ enum class RequestRedirect;
|
|||
enum class ResizeObserverBoxOptions;
|
||||
enum class ResponseType;
|
||||
enum class TextTrackKind;
|
||||
enum class TransferFunction;
|
||||
enum class XMLHttpRequestResponseType;
|
||||
}
|
||||
|
||||
|
@ -656,6 +662,17 @@ class MathMLElement;
|
|||
|
||||
namespace Web::MediaCapabilitiesAPI {
|
||||
class MediaCapabilities;
|
||||
|
||||
struct AudioConfiguration;
|
||||
struct KeySystemTrackConfiguration;
|
||||
struct MediaCapabilitiesDecodingInfo;
|
||||
struct MediaCapabilitiesEncodingInfo;
|
||||
struct MediaCapabilitiesInfo;
|
||||
struct MediaCapabilitiesKeySystemConfiguration;
|
||||
struct MediaConfiguration;
|
||||
struct MediaDecodingConfiguration;
|
||||
struct MediaEncodingConfiguration;
|
||||
struct VideoConfiguration;
|
||||
}
|
||||
|
||||
namespace Web::MediaSourceExtensions {
|
||||
|
|
|
@ -71,6 +71,9 @@ public:
|
|||
// https://websockets.spec.whatwg.org/#websocket-task-source
|
||||
WebSocket,
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#media-capabilities-task-source
|
||||
MediaCapabilities,
|
||||
|
||||
// !!! IMPORTANT: Keep this field last!
|
||||
// This serves as the base value of all unique task sources.
|
||||
// Some elements, such as the HTMLMediaElement, must have a unique task source per instance.
|
||||
|
|
|
@ -1,16 +1,114 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (c) 2025, Psychpsyo <psychpsyo@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/BooleanObject.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/Bindings/MediaCapabilitiesPrototype.h>
|
||||
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/MediaCapabilitiesAPI/MediaCapabilities.h>
|
||||
#include <LibWeb/Platform/EventLoopPlugin.h>
|
||||
|
||||
namespace Web::MediaCapabilitiesAPI {
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#valid-mediaconfiguration
|
||||
bool MediaConfiguration::is_valid_media_configuration() const
|
||||
{
|
||||
// For a MediaConfiguration to be a valid MediaConfiguration, all of the following conditions MUST be true:
|
||||
|
||||
// 1. audio and/or video MUST exist.
|
||||
if (!audio.has_value() && !video.has_value())
|
||||
return false;
|
||||
|
||||
// 2. audio MUST be a valid audio configuration if it exists.
|
||||
if (audio.has_value() && !audio.value().is_valid_audio_configuration())
|
||||
return false;
|
||||
|
||||
// 3. video MUST be a valid video configuration if it exists.
|
||||
if (video.has_value() && !video.value().is_valid_video_configuration())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#valid-mediadecodingconfiguration
|
||||
bool MediaDecodingConfiguration::is_valid_media_decoding_configuration() const
|
||||
{
|
||||
// For a MediaDecodingConfiguration to be a valid MediaDecodingConfiguration, all of the following
|
||||
// conditions MUST be true:
|
||||
|
||||
// 1. It MUST be a valid MediaConfiguration.
|
||||
if (!is_valid_media_configuration())
|
||||
return false;
|
||||
|
||||
// 2. If keySystemConfiguration exists:
|
||||
// FIXME: Implement this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#valid-audio-mime-type
|
||||
bool is_valid_audio_mime_type(StringView string)
|
||||
{
|
||||
// A valid audio MIME type is a string that is a valid media MIME type and for which the type per [RFC9110] is
|
||||
// either audio or application.
|
||||
auto mime_type = MimeSniff::MimeType::parse(string);
|
||||
if (!mime_type.has_value())
|
||||
return false;
|
||||
return mime_type->type() == "audio"sv || mime_type->type() == "application"sv;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#valid-video-mime-type
|
||||
bool is_valid_video_mime_type(StringView string)
|
||||
{
|
||||
// A valid video MIME type is a string that is a valid media MIME type and for which the type per [RFC9110] is
|
||||
// either video or application.
|
||||
auto mime_type = MimeSniff::MimeType::parse(string);
|
||||
if (!mime_type.has_value())
|
||||
return false;
|
||||
return mime_type->type() == "video"sv || mime_type->type() == "application"sv;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#valid-video-configuration
|
||||
bool VideoConfiguration::is_valid_video_configuration() const
|
||||
{
|
||||
// To check if a VideoConfiguration configuration is a valid video configuration, the following steps MUST be
|
||||
// run:
|
||||
|
||||
// 1. If configuration’s contentType is not a valid video MIME type, return false and abort these steps.
|
||||
if (!is_valid_video_mime_type(content_type))
|
||||
return false;
|
||||
|
||||
// 2. If framerate is not finite or is not greater than 0, return false and abort these steps.
|
||||
if (!isfinite(framerate) || framerate <= 0)
|
||||
return false;
|
||||
|
||||
// 3. 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.
|
||||
// FIXME: Implement this.
|
||||
|
||||
// 4. Return true.
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#valid-video-configuration
|
||||
bool AudioConfiguration::is_valid_audio_configuration() const
|
||||
{
|
||||
// To check if a AudioConfiguration configuration is a valid audio configuration, the following steps MUST be
|
||||
// run:
|
||||
|
||||
// 1. If configuration’s contentType is not a valid audio MIME type, return false and abort these steps.
|
||||
if (!is_valid_audio_mime_type(content_type))
|
||||
return false;
|
||||
|
||||
// 2. Return true.
|
||||
return true;
|
||||
}
|
||||
|
||||
GC_DEFINE_ALLOCATOR(MediaCapabilities);
|
||||
|
||||
GC::Ref<MediaCapabilities> MediaCapabilities::create(JS::Realm& realm)
|
||||
|
@ -29,4 +127,120 @@ void MediaCapabilities::initialize(JS::Realm& realm)
|
|||
WEB_SET_PROTOTYPE_FOR_INTERFACE(MediaCapabilities);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#queue-a-media-capabilities-task
|
||||
void queue_a_media_capabilities_task(JS::VM& vm, Function<void()> steps)
|
||||
{
|
||||
// When an algorithm queues a Media Capabilities task T, the user agent MUST queue a global task T on the
|
||||
// media capabilities task source using the global object of the the current realm record.
|
||||
queue_global_task(HTML::Task::Source::MediaCapabilities, vm.current_realm()->global_object(), GC::create_function(vm.current_realm()->heap(), move(steps)));
|
||||
}
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#dom-mediacapabilities-decodinginfo
|
||||
GC::Ref<WebIDL::Promise> MediaCapabilities::decoding_info(MediaDecodingConfiguration const& configuration)
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
// The decodingInfo() method MUST run the following steps:
|
||||
|
||||
// 1. If configuration is not a valid MediaDecodingConfiguration, return a Promise rejected with a newly created
|
||||
// TypeError.
|
||||
if (!configuration.is_valid_media_decoding_configuration()) {
|
||||
return WebIDL::create_rejected_promise_from_exception(realm, vm().throw_completion<JS::TypeError>("The given configuration is not a valid MediaDecodingConfiguration"sv));
|
||||
}
|
||||
|
||||
// 2. If configuration.keySystemConfiguration exists, run the following substeps:
|
||||
// FIXME: Implement this.
|
||||
|
||||
// 3. Let p be a new Promise.
|
||||
auto p = WebIDL::create_promise(realm);
|
||||
|
||||
// 4. Run the following steps in parallel:
|
||||
auto& vm = this->vm();
|
||||
Platform::EventLoopPlugin::the().deferred_invoke(GC::create_function(realm.heap(), [&vm, &realm, p, configuration]() mutable {
|
||||
HTML::TemporaryExecutionContext context(realm);
|
||||
// 1. Run the Create a MediaCapabilitiesDecodingInfo algorithm with configuration.
|
||||
auto result = create_a_media_capabilities_decoding_info(configuration).to_object(realm);
|
||||
|
||||
// Queue a Media Capabilities task to resolve p with its result.
|
||||
queue_a_media_capabilities_task(vm, [&realm, p, result] {
|
||||
HTML::TemporaryExecutionContext context(realm, HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
|
||||
WebIDL::resolve_promise(realm, p, JS::Value(result));
|
||||
});
|
||||
}));
|
||||
|
||||
// 5. Return p.
|
||||
return p;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#create-a-mediacapabilitiesdecodinginfo
|
||||
MediaCapabilitiesDecodingInfo create_a_media_capabilities_decoding_info(MediaDecodingConfiguration configuration)
|
||||
{
|
||||
// 1. Let info be a new MediaCapabilitiesDecodingInfo instance. Unless stated otherwise, reading and
|
||||
// writing apply to info for the next steps.
|
||||
MediaCapabilitiesDecodingInfo info = {};
|
||||
|
||||
// 2. Set configuration to be a new MediaDecodingConfiguration. For every property in configuration create
|
||||
// a new property with the same name and value in configuration.
|
||||
info.configuration = { { configuration.video, configuration.audio }, configuration.type, configuration.key_system_configuration };
|
||||
|
||||
// 3. If configuration.keySystemConfiguration exists:
|
||||
if (false) {
|
||||
// FIXME: Implement this.
|
||||
}
|
||||
// 4. Otherwise, run the following steps:
|
||||
else {
|
||||
// 1. Set keySystemAccess to null.
|
||||
// FIXME: Implement this.
|
||||
|
||||
// 2. If the user agent is able to decode the media represented by configuration, set supported to true.
|
||||
// 3. Otherwise, set it to false.
|
||||
info.supported = is_able_to_decode_media(configuration);
|
||||
}
|
||||
|
||||
// 5. If the user agent is able to decode the media represented by configuration at the indicated framerate without
|
||||
// dropping frames, set smooth to true. Otherwise set it to false.
|
||||
// FIXME: Actually check this.
|
||||
info.smooth = false;
|
||||
|
||||
// 6. If the user agent is able to decode the media represented by configuration in a power efficient manner, set
|
||||
// powerEfficient to true. Otherwise set it to false.
|
||||
// FIXME: Actually check this... somehow.
|
||||
info.power_efficient = false;
|
||||
|
||||
// 7. Return info.
|
||||
return info;
|
||||
}
|
||||
|
||||
bool is_able_to_decode_media(MediaDecodingConfiguration configuration)
|
||||
{
|
||||
if (configuration.type != Bindings::MediaDecodingType::MediaSource)
|
||||
return false;
|
||||
|
||||
if (configuration.video.has_value()) {
|
||||
auto video_mime_type = MimeSniff::MimeType::parse(configuration.video.value().content_type);
|
||||
if (!video_mime_type.has_value() || !Web::HTML::HTMLMediaElement::supported_video_subtypes.contains_slow(video_mime_type->subtype()))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (configuration.audio.has_value()) {
|
||||
auto audio_mime_type = MimeSniff::MimeType::parse(configuration.audio.value().content_type);
|
||||
if (!audio_mime_type.has_value() || !Web::HTML::HTMLMediaElement::supported_audio_subtypes.contains_slow(audio_mime_type->subtype()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GC::Ref<JS::Object> MediaCapabilitiesDecodingInfo::to_object(JS::Realm& realm)
|
||||
{
|
||||
auto object = JS::Object::create(realm, realm.intrinsics().object_prototype());
|
||||
|
||||
// FIXME: Also include configuration in this object.
|
||||
|
||||
MUST(object->create_data_property("supported", JS::BooleanObject::create(realm, supported)));
|
||||
MUST(object->create_data_property("smooth", JS::BooleanObject::create(realm, smooth)));
|
||||
MUST(object->create_data_property("powerEfficent", JS::BooleanObject::create(realm, power_efficient)));
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (c) 2025, Psychpsyo <psychpsyo@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -7,9 +8,100 @@
|
|||
#pragma once
|
||||
|
||||
#include <LibWeb/Bindings/PlatformObject.h>
|
||||
#include <LibWeb/EncryptedMediaExtensions/EncryptedMediaExtensions.h>
|
||||
|
||||
namespace Web::MediaCapabilitiesAPI {
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#dictdef-videoconfiguration
|
||||
struct VideoConfiguration {
|
||||
String content_type;
|
||||
WebIDL::UnsignedLong width;
|
||||
WebIDL::UnsignedLong height;
|
||||
Optional<WebIDL::UnsignedLongLong> bitrate;
|
||||
double framerate;
|
||||
Optional<bool> has_alpha_channel;
|
||||
Optional<Bindings::HdrMetadataType> hdr_metadata_type;
|
||||
Optional<Bindings::ColorGamut> color_gamut;
|
||||
Optional<Bindings::TransferFunction> transfer_function;
|
||||
Optional<String> scalability_mode;
|
||||
Optional<bool> spatial_scalability;
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#valid-video-configuration
|
||||
bool is_valid_video_configuration() const;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#dictdef-audioconfiguration
|
||||
struct AudioConfiguration {
|
||||
String content_type;
|
||||
Optional<String> channels;
|
||||
Optional<WebIDL::UnsignedLongLong> bitrate;
|
||||
Optional<WebIDL::UnsignedLong> samplerate;
|
||||
Optional<bool> spatial_rendering;
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#valid-audio-configuration
|
||||
bool is_valid_audio_configuration() const;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#dictdef-mediaconfiguration
|
||||
struct MediaConfiguration {
|
||||
Optional<VideoConfiguration> video;
|
||||
Optional<AudioConfiguration> audio;
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#valid-mediaconfiguration
|
||||
bool is_valid_media_configuration() const;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#keysystemtrackconfiguration
|
||||
struct KeySystemTrackConfiguration {
|
||||
String robustness;
|
||||
Optional<String> encryption_scheme;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#mediacapabilitieskeysystemconfiguration
|
||||
struct MediaCapabilitiesKeySystemConfiguration {
|
||||
String key_system;
|
||||
String init_data_type;
|
||||
Bindings::MediaKeysRequirement distinctive_identifier;
|
||||
Bindings::MediaKeysRequirement persistent_state;
|
||||
Optional<Vector<String>> session_types;
|
||||
Optional<KeySystemTrackConfiguration> audio;
|
||||
Optional<KeySystemTrackConfiguration> video;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#dictdef-mediadecodingconfiguration
|
||||
struct MediaDecodingConfiguration : public MediaConfiguration {
|
||||
Bindings::MediaDecodingType type;
|
||||
Optional<MediaCapabilitiesKeySystemConfiguration> key_system_configuration;
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#valid-mediadecodingconfiguration
|
||||
bool is_valid_media_decoding_configuration() const;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#dictdef-mediaencodingconfiguration
|
||||
struct MediaEncodingConfiguration : public MediaConfiguration {
|
||||
Bindings::MediaEncodingType type;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#media-capabilities-info
|
||||
struct MediaCapabilitiesInfo {
|
||||
bool supported;
|
||||
bool smooth;
|
||||
bool power_efficient;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#dictdef-mediacapabilitiesdecodinginfo
|
||||
struct MediaCapabilitiesDecodingInfo : public MediaCapabilitiesInfo {
|
||||
MediaDecodingConfiguration configuration;
|
||||
Optional<MediaCapabilitiesKeySystemConfiguration> key_system_configuration;
|
||||
|
||||
GC::Ref<JS::Object> to_object(JS::Realm&);
|
||||
};
|
||||
|
||||
struct MediaCapabilitiesEncodingInfo : public MediaCapabilitiesInfo {
|
||||
Optional<MediaEncodingConfiguration> configuration;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#media-capabilities-interface
|
||||
class MediaCapabilities final : public Bindings::PlatformObject {
|
||||
WEB_PLATFORM_OBJECT(MediaCapabilities, Bindings::PlatformObject);
|
||||
GC_DECLARE_ALLOCATOR(MediaCapabilities);
|
||||
|
@ -18,10 +110,29 @@ public:
|
|||
static GC::Ref<MediaCapabilities> create(JS::Realm&);
|
||||
virtual ~MediaCapabilities() override = default;
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#dom-mediacapabilities-decodinginfo
|
||||
GC::Ref<WebIDL::Promise> decoding_info(MediaDecodingConfiguration const&);
|
||||
|
||||
private:
|
||||
MediaCapabilities(JS::Realm&);
|
||||
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#valid-mediadecodingconfiguration
|
||||
bool is_valid_media_decoding_configuration() const;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#queue-a-media-capabilities-task
|
||||
void queue_a_media_capabilities_task(JS::VM& vm, Function<void()>);
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#create-a-mediacapabilitiesdecodinginfo
|
||||
MediaCapabilitiesDecodingInfo create_a_media_capabilities_decoding_info(MediaDecodingConfiguration);
|
||||
|
||||
bool is_able_to_decode_media(MediaDecodingConfiguration configuration);
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#valid-audio-mime-type
|
||||
bool is_valid_audio_mime_type(StringView);
|
||||
// https://w3c.github.io/media-capabilities/#valid-video-mime-type
|
||||
bool is_valid_video_mime_type(StringView);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,114 @@
|
|||
#import <EncryptedMediaExtensions/EncryptedMediaExtensions.idl>
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#mediaconfiguration
|
||||
dictionary MediaConfiguration {
|
||||
VideoConfiguration video;
|
||||
AudioConfiguration audio;
|
||||
};
|
||||
|
||||
dictionary MediaDecodingConfiguration : MediaConfiguration {
|
||||
required MediaDecodingType type;
|
||||
MediaCapabilitiesKeySystemConfiguration keySystemConfiguration;
|
||||
};
|
||||
|
||||
dictionary MediaEncodingConfiguration : MediaConfiguration {
|
||||
required MediaEncodingType type;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#enumdef-mediadecodingtype
|
||||
enum MediaDecodingType {
|
||||
"file",
|
||||
"media-source",
|
||||
"webrtc"
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#enumdef-mediaencodingtype
|
||||
enum MediaEncodingType {
|
||||
"record",
|
||||
"webrtc"
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#dictdef-videoconfiguration
|
||||
dictionary VideoConfiguration {
|
||||
required DOMString contentType;
|
||||
required unsigned long width;
|
||||
required unsigned long height;
|
||||
required unsigned long long bitrate;
|
||||
required double framerate;
|
||||
boolean hasAlphaChannel;
|
||||
HdrMetadataType hdrMetadataType;
|
||||
ColorGamut colorGamut;
|
||||
TransferFunction transferFunction;
|
||||
DOMString scalabilityMode;
|
||||
boolean spatialScalability;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#enumdef-hdrmetadatatype
|
||||
enum HdrMetadataType {
|
||||
"smpteSt2086",
|
||||
"smpteSt2094-10",
|
||||
"smpteSt2094-40"
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#enumdef-colorgamut
|
||||
enum ColorGamut {
|
||||
"srgb",
|
||||
"p3",
|
||||
"rec2020"
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#enumdef-transferfunction
|
||||
enum TransferFunction {
|
||||
"srgb",
|
||||
"pq",
|
||||
"hlg"
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#dictdef-audioconfiguration
|
||||
dictionary AudioConfiguration {
|
||||
required DOMString contentType;
|
||||
DOMString channels;
|
||||
unsigned long long bitrate;
|
||||
unsigned long samplerate;
|
||||
boolean spatialRendering;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#mediacapabilitieskeysystemconfiguration
|
||||
dictionary MediaCapabilitiesKeySystemConfiguration {
|
||||
required DOMString keySystem;
|
||||
DOMString initDataType = "";
|
||||
MediaKeysRequirement distinctiveIdentifier = "optional";
|
||||
MediaKeysRequirement persistentState = "optional";
|
||||
sequence<DOMString> sessionTypes;
|
||||
KeySystemTrackConfiguration audio;
|
||||
KeySystemTrackConfiguration video;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#keysystemtrackconfiguration
|
||||
dictionary KeySystemTrackConfiguration {
|
||||
DOMString robustness = "";
|
||||
DOMString? encryptionScheme = null;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#media-capabilities-info
|
||||
dictionary MediaCapabilitiesInfo {
|
||||
required boolean supported;
|
||||
required boolean smooth;
|
||||
required boolean powerEfficient;
|
||||
};
|
||||
|
||||
dictionary MediaCapabilitiesDecodingInfo : MediaCapabilitiesInfo {
|
||||
[FIXME, required] MediaKeySystemAccess keySystemAccess;
|
||||
MediaDecodingConfiguration configuration;
|
||||
};
|
||||
|
||||
dictionary MediaCapabilitiesEncodingInfo : MediaCapabilitiesInfo {
|
||||
MediaEncodingConfiguration configuration;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/media-capabilities/#mediacapabilities
|
||||
[Exposed=(Window, Worker)]
|
||||
interface MediaCapabilities {
|
||||
[FIXME, NewObject] Promise<MediaCapabilitiesDecodingInfo> decodingInfo(MediaDecodingConfiguration configuration);
|
||||
[NewObject] Promise<MediaCapabilitiesDecodingInfo> decodingInfo(MediaDecodingConfiguration configuration);
|
||||
[FIXME, NewObject] Promise<MediaCapabilitiesEncodingInfo> encodingInfo(MediaEncodingConfiguration configuration);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 40 tests
|
||||
|
||||
22 Pass
|
||||
18 Fail
|
||||
Pass Test that decodingInfo rejects if it doesn't get a configuration
|
||||
Pass Test that decodingInfo rejects if the MediaConfiguration isn't valid
|
||||
Pass Test that decodingInfo rejects if the MediaConfiguration does not have a type
|
||||
Pass Test that decodingInfo rejects if the configuration doesn't have an audio or video field
|
||||
Pass Test that decodingInfo rejects if the video configuration has a negative framerate
|
||||
Pass Test that decodingInfo rejects if the video configuration has a framerate set to 0
|
||||
Pass Test that decodingInfo rejects if the video configuration has a framerate set to Infinity
|
||||
Pass Test that decodingInfo rejects if the video configuration contentType doesn't parse
|
||||
Fail Test that decodingInfo rejects if the video configuration contentType is not a valid MIME type string
|
||||
Pass Test that decodingInfo rejects if the video configuration contentType isn't of type video
|
||||
Fail Test that decodingInfo rejects if the video configuration contentType is of type audio
|
||||
Fail Test that decodingInfo rejects if the audio configuration contentType is of type video
|
||||
Fail Test that decodingInfo rejects if the video configuration contentType has more than one parameter
|
||||
Fail Test that decodingInfo rejects if the video configuration contentType has one parameter that isn't codecs
|
||||
Fail Test that decodingInfo rejects if the video configuration contentType does not imply a single media codec but has no codecs parameter
|
||||
Fail Test that decodingInfo rejects if the video configuration contentType has a codecs parameter that indicates multiple video codecs
|
||||
Fail Test that decodingInfo rejects if the video configuration contentType has a codecs parameter that indicates both an audio and a video codec
|
||||
Pass Test that decodingInfo rejects framerate in the form of x/y
|
||||
Pass Test that decodingInfo rejects framerate in the form of x/0
|
||||
Pass Test that decodingInfo rejects framerate in the form of 0/y
|
||||
Pass Test that decodingInfo rejects framerate in the form of -x/y
|
||||
Pass Test that decodingInfo rejects framerate in the form of x/-y
|
||||
Pass Test that decodingInfo rejects framerate in the form of x/
|
||||
Pass Test that decodingInfo rejects framerate with trailing unallowed characters
|
||||
Pass Test that decodingInfo rejects if the audio configuration contentType doesn't parse
|
||||
Fail Test that decodingInfo rejects if the audio configuration contentType is not a valid MIME type string
|
||||
Pass Test that decodingInfo rejects if the audio configuration contentType isn't of type audio
|
||||
Fail Test that decodingInfo rejects if the audio configuration contentType has more than one parameter
|
||||
Fail Test that decodingInfo rejects if the audio configuration contentType has one parameter that isn't codecs
|
||||
Fail Test that decodingInfo rejects if the audio configuration contentType does not imply a single media codec but has no codecs parameter
|
||||
Fail Test that decodingInfo rejects if the audio configuration contentType has a codecs parameter that indicates multiple audio codecs
|
||||
Fail Test that decodingInfo rejects if the audio configuration contentType has a codecs parameter that indicates both an audio and a video codec
|
||||
Fail Test that decodingInfo returns a valid MediaCapabilitiesInfo objects
|
||||
Pass Test that decodingInfo rejects if the MediaConfiguration does not have a valid type
|
||||
Fail Test that decodingInfo with spatialRendering set returns a valid MediaCapabilitiesInfo objects
|
||||
Fail Test that decodingInfo with hdrMetadataType, colorGamut, and transferFunction set returns a valid MediaCapabilitiesInfo objects
|
||||
Fail Test that decodingInfo with mismatched codec color space is unsupported
|
||||
Pass Test that decodingInfo rejects if the video configuration has an empty hdrMetadataType
|
||||
Pass Test that decodingInfo rejects if the video configuration has a colorGamut set to true
|
||||
Pass Test that decodingInfo rejects if the video configuration has a transferFunction set to 3
|
|
@ -0,0 +1,15 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<meta name="timeout" content="long">
|
||||
<script>
|
||||
self.GLOBAL = {
|
||||
isWindow: function() { return true; },
|
||||
isWorker: function() { return false; },
|
||||
isShadowRealm: function() { return false; },
|
||||
};
|
||||
</script>
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
|
||||
<div id=log></div>
|
||||
<script src="../media-capabilities/decodingInfo.any.js"></script>
|
|
@ -0,0 +1,508 @@
|
|||
// META: timeout=long
|
||||
'use strict';
|
||||
|
||||
// Minimal VideoConfiguration that will be allowed per spec. All optional
|
||||
// properties are missing.
|
||||
const minimalVideoConfiguration = {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: 24,
|
||||
};
|
||||
|
||||
// Minimal AudioConfiguration that will be allowed per spec. All optional
|
||||
// properties are missing.
|
||||
const minimalAudioConfiguration = {
|
||||
contentType: 'audio/webm; codecs="opus"',
|
||||
};
|
||||
|
||||
// AudioConfiguration with optional spatialRendering param.
|
||||
const audioConfigurationWithSpatialRendering = {
|
||||
contentType: 'audio/webm; codecs="opus"',
|
||||
spatialRendering: true,
|
||||
};
|
||||
|
||||
// VideoConfiguration with optional hdrMetadataType, colorGamut, and
|
||||
// transferFunction properties.
|
||||
const videoConfigurationWithDynamicRange = {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08.00.09.16.09.00"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: 24,
|
||||
hdrMetadataType: 'smpteSt2086',
|
||||
colorGamut: 'rec2020',
|
||||
transferFunction: 'pq',
|
||||
};
|
||||
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo());
|
||||
}, "Test that decodingInfo rejects if it doesn't get a configuration");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({}));
|
||||
}, "Test that decodingInfo rejects if the MediaConfiguration isn't valid");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
video: minimalVideoConfiguration,
|
||||
audio: minimalAudioConfiguration,
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the MediaConfiguration does not have a type");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the configuration doesn't have an audio or video field");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: -1,
|
||||
},
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the video configuration has a negative framerate");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: 0,
|
||||
},
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the video configuration has a framerate set to 0");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: Infinity,
|
||||
},
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the video configuration has a framerate set to Infinity");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'fgeoa',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: 24,
|
||||
},
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the video configuration contentType doesn't parse");
|
||||
|
||||
// See https://mimesniff.spec.whatwg.org/#example-valid-mime-type-string
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm;',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: 24,
|
||||
},
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the video configuration contentType is not a valid MIME type string");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'audio/fgeoa',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: 24,
|
||||
},
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the video configuration contentType isn't of type video");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'application/ogg; codec=vorbis',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: 24,
|
||||
},
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the video configuration contentType is of type audio");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
audio: {
|
||||
contentType: 'application/ogg; codec=theora',
|
||||
channels: 2,
|
||||
},
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the audio configuration contentType is of type video");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08"; foo="bar"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: 24,
|
||||
},
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the video configuration contentType has more than one parameter");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; foo="bar"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: 24,
|
||||
},
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the video configuration contentType has one parameter that isn't codecs");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: 24,
|
||||
},
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the video configuration contentType does not imply a single media codec but has no codecs parameter");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08, vp8"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: 24,
|
||||
}
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the video configuration contentType has a codecs parameter that indicates multiple video codecs");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08, opus"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: 24,
|
||||
}
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the video configuration contentType has a codecs parameter that indicates both an audio and a video codec");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: '24000/1001',
|
||||
}
|
||||
}));
|
||||
}, "Test that decodingInfo rejects framerate in the form of x/y");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: '24000/0',
|
||||
}
|
||||
}));
|
||||
}, "Test that decodingInfo rejects framerate in the form of x/0");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: '0/10001',
|
||||
}
|
||||
}));
|
||||
}, "Test that decodingInfo rejects framerate in the form of 0/y");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: '-24000/10001',
|
||||
}
|
||||
}));
|
||||
}, "Test that decodingInfo rejects framerate in the form of -x/y");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: '24000/-10001',
|
||||
}
|
||||
}));
|
||||
}, "Test that decodingInfo rejects framerate in the form of x/-y");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: '24000/',
|
||||
}
|
||||
}));
|
||||
}, "Test that decodingInfo rejects framerate in the form of x/");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: '1/3x',
|
||||
}
|
||||
}));
|
||||
}, "Test that decodingInfo rejects framerate with trailing unallowed characters");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
audio: { contentType: 'fgeoa' },
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the audio configuration contentType doesn't parse");
|
||||
|
||||
// See https://mimesniff.spec.whatwg.org/#example-valid-mime-type-string
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
audio: { contentType: 'audio/mpeg;' },
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the audio configuration contentType is not a valid MIME type string");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
audio: { contentType: 'video/fgeoa' },
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the audio configuration contentType isn't of type audio");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
audio: { contentType: 'audio/webm; codecs="opus"; foo="bar"' },
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the audio configuration contentType has more than one parameter");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
audio: { contentType: 'audio/webm; foo="bar"' },
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the audio configuration contentType has one parameter that isn't codecs");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
audio: { contentType: 'audio/webm' },
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the audio configuration contentType does not imply a single media codec but has no codecs parameter");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
audio: { contentType: 'audio/webm; codecs="vorbis, opus"' },
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the audio configuration contentType has a codecs parameter that indicates multiple audio codecs");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
audio: { contentType: 'audio/webm; codecs="vp09.00.10.08, opus"' },
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the audio configuration contentType has a codecs parameter that indicates both an audio and a video codec");
|
||||
|
||||
promise_test(t => {
|
||||
return navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: minimalVideoConfiguration,
|
||||
audio: minimalAudioConfiguration,
|
||||
}).then(ability => {
|
||||
assert_equals(typeof ability.supported, "boolean");
|
||||
assert_equals(typeof ability.smooth, "boolean");
|
||||
assert_equals(typeof ability.powerEfficient, "boolean");
|
||||
assert_equals(typeof ability.keySystemAccess, "object");
|
||||
});
|
||||
}, "Test that decodingInfo returns a valid MediaCapabilitiesInfo objects");
|
||||
|
||||
async_test(t => {
|
||||
var validTypes = [ 'file', 'media-source' ];
|
||||
var invalidTypes = [ undefined, null, '', 'foobar', 'mse', 'MediaSource',
|
||||
'record', 'transmission' ];
|
||||
|
||||
var validPromises = [];
|
||||
var invalidCaught = 0;
|
||||
|
||||
validTypes.forEach(type => {
|
||||
validPromises.push(navigator.mediaCapabilities.decodingInfo({
|
||||
type: type,
|
||||
video: minimalVideoConfiguration,
|
||||
audio: minimalAudioConfiguration,
|
||||
}));
|
||||
});
|
||||
|
||||
// validTypes are tested via Promise.all(validPromises) because if one of the
|
||||
// promises fail, Promise.all() will reject. This mechanism can't be used for
|
||||
// invalid types which will be tested individually and increment invalidCaught
|
||||
// when rejected until the amount of rejection matches the expectation.
|
||||
Promise.all(validPromises).then(t.step_func(() => {
|
||||
for (var i = 0; i < invalidTypes.length; ++i) {
|
||||
navigator.mediaCapabilities.decodingInfo({
|
||||
type: invalidTypes[i],
|
||||
video: minimalVideoConfiguration,
|
||||
audio: minimalAudioConfiguration,
|
||||
}).then(t.unreached_func(), t.step_func(e => {
|
||||
assert_equals(e.name, 'TypeError');
|
||||
++invalidCaught;
|
||||
if (invalidCaught == invalidTypes.length)
|
||||
t.done();
|
||||
}));
|
||||
}
|
||||
}), t.unreached_func('Promise.all should not reject for valid types'));
|
||||
}, "Test that decodingInfo rejects if the MediaConfiguration does not have a valid type");
|
||||
|
||||
promise_test(t => {
|
||||
return navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
audio: audioConfigurationWithSpatialRendering,
|
||||
}).then(ability => {
|
||||
assert_equals(typeof ability.supported, "boolean");
|
||||
assert_equals(typeof ability.smooth, "boolean");
|
||||
assert_equals(typeof ability.powerEfficient, "boolean");
|
||||
assert_equals(typeof ability.keySystemAccess, "object");
|
||||
});
|
||||
}, "Test that decodingInfo with spatialRendering set returns a valid MediaCapabilitiesInfo objects");
|
||||
|
||||
promise_test(t => {
|
||||
return navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: videoConfigurationWithDynamicRange,
|
||||
}).then(ability => {
|
||||
assert_equals(typeof ability.supported, "boolean");
|
||||
assert_equals(typeof ability.smooth, "boolean");
|
||||
assert_equals(typeof ability.powerEfficient, "boolean");
|
||||
assert_equals(typeof ability.keySystemAccess, "object");
|
||||
});
|
||||
}, "Test that decodingInfo with hdrMetadataType, colorGamut, and transferFunction set returns a valid MediaCapabilitiesInfo objects");
|
||||
|
||||
promise_test(t => {
|
||||
// VP9 has a default color space of BT.709 in the codec string. So this will
|
||||
// mismatch against the provided colorGamut and transferFunction.
|
||||
let bt709Config = videoConfigurationWithDynamicRange;
|
||||
bt709Config.contentType = 'video/webm; codecs="vp09.00.10.08"';
|
||||
return navigator.mediaCapabilities
|
||||
.decodingInfo({
|
||||
type: 'file',
|
||||
video: bt709Config,
|
||||
})
|
||||
.then(ability => {
|
||||
assert_equals(typeof ability.supported, 'boolean');
|
||||
assert_equals(typeof ability.smooth, 'boolean');
|
||||
assert_equals(typeof ability.powerEfficient, 'boolean');
|
||||
assert_equals(typeof ability.keySystemAccess, 'object');
|
||||
assert_false(ability.supported);
|
||||
});
|
||||
}, 'Test that decodingInfo with mismatched codec color space is unsupported');
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: 24,
|
||||
hdrMetadataType: ""
|
||||
},
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the video configuration has an empty hdrMetadataType");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: 24,
|
||||
colorGamut: true
|
||||
},
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the video configuration has a colorGamut set to true");
|
||||
|
||||
promise_test(t => {
|
||||
return promise_rejects_js(t, TypeError, navigator.mediaCapabilities.decodingInfo({
|
||||
type: 'file',
|
||||
video: {
|
||||
contentType: 'video/webm; codecs="vp09.00.10.08"',
|
||||
width: 800,
|
||||
height: 600,
|
||||
bitrate: 3000,
|
||||
framerate: 24,
|
||||
transferFunction: 3
|
||||
},
|
||||
}));
|
||||
}, "Test that decodingInfo rejects if the video configuration has a transferFunction set to 3");
|
Loading…
Add table
Reference in a new issue