Commit 68319bd3 authored by Chris Cunningham's avatar Chris Cunningham Committed by Commit Bot

WebCodecs: Evaluate decoder config codec strings

Updates Audio/Video Decoder to reject invalid codecs passed to
configure(). A TypeError should be thrown.

Additionally, if the config is valid but unsupported,
throw a NotSupportedError.

Adds wpt test to verify the behavior for validity. Support behavior
is difficult to wpt test (varies by build/platform) - tested manually.

Bug: 1113824
Change-Id: I647c476fa32e684d57816222e1787aeb8f723c25
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2360312Reviewed-by: default avatarThomas Guilbert <tguilbert@chromium.org>
Commit-Queue: Chrome Cunningham <chcunningham@chromium.org>
Auto-Submit: Chrome Cunningham <chcunningham@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799271}
parent 1f7499b3
...@@ -12,6 +12,7 @@ blink_modules_sources("webcodecs") { ...@@ -12,6 +12,7 @@ blink_modules_sources("webcodecs") {
"audio_decoder_broker.h", "audio_decoder_broker.h",
"audio_frame.cc", "audio_frame.cc",
"audio_frame.h", "audio_frame.h",
"codec_config_eval.h",
"decoder_selector.cc", "decoder_selector.cc",
"decoder_selector.h", "decoder_selector.h",
"decoder_template.cc", "decoder_template.cc",
......
...@@ -10,11 +10,14 @@ ...@@ -10,11 +10,14 @@
#include "media/base/channel_layout.h" #include "media/base/channel_layout.h"
#include "media/base/encryption_scheme.h" #include "media/base/encryption_scheme.h"
#include "media/base/media_util.h" #include "media/base/media_util.h"
#include "media/base/mime_util.h"
#include "media/base/supported_types.h"
#include "media/base/waiting.h" #include "media/base/waiting.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_init.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_config.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_config.h"
#include "third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.h" #include "third_party/blink/renderer/modules/webcodecs/audio_decoder_broker.h"
#include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h"
#include <memory> #include <memory>
#include <vector> #include <vector>
...@@ -29,11 +32,30 @@ AudioDecoderTraits::CreateDecoder(ExecutionContext& execution_context, ...@@ -29,11 +32,30 @@ AudioDecoderTraits::CreateDecoder(ExecutionContext& execution_context,
} }
// static // static
void AudioDecoderTraits::InitializeDecoder( CodecConfigEval AudioDecoderTraits::CreateMediaConfig(
MediaDecoderType& decoder,
const ConfigType& config, const ConfigType& config,
MediaDecoderType::InitCB init_cb, MediaConfigType* out_media_config,
MediaDecoderType::OutputCB output_cb) { String* out_console_message) {
media::AudioCodec codec = media::kUnknownAudioCodec;
bool is_codec_ambiguous = true;
bool parse_succeeded = ParseAudioCodecString("", config.codec().Utf8(),
&is_codec_ambiguous, &codec);
if (!parse_succeeded) {
*out_console_message = "Failed to parse codec string.";
return CodecConfigEval::kInvalid;
}
if (is_codec_ambiguous) {
*out_console_message = "Codec string is ambiguous.";
return CodecConfigEval::kInvalid;
}
if (!media::IsSupportedAudioType({codec})) {
*out_console_message = "Configuration is not supported.";
return CodecConfigEval::kUnsupported;
}
std::vector<uint8_t> extra_data; std::vector<uint8_t> extra_data;
if (config.hasDescription()) { if (config.hasDescription()) {
DOMArrayBuffer* buffer; DOMArrayBuffer* buffer;
...@@ -50,11 +72,27 @@ void AudioDecoderTraits::InitializeDecoder( ...@@ -50,11 +72,27 @@ void AudioDecoderTraits::InitializeDecoder(
extra_data.assign(start, start + size); extra_data.assign(start, start + size);
} }
// TODO(chcunningham): Convert the rest of blink config -> media config. media::ChannelLayout channel_layout =
auto media_config = config.numberOfChannels() > 8
media::AudioDecoderConfig(media::kCodecAAC, media::kSampleFormatPlanarF32, // GuesschannelLayout() doesn't know how to guess above 8 channels.
media::CHANNEL_LAYOUT_STEREO, 48000, extra_data, ? media::CHANNEL_LAYOUT_DISCRETE
media::EncryptionScheme::kUnencrypted); : media::GuessChannelLayout(config.numberOfChannels());
// TODO(chcunningham): Add sample format to IDL.
out_media_config->Initialize(
codec, media::kSampleFormatPlanarF32, channel_layout, config.sampleRate(),
extra_data, media::EncryptionScheme::kUnencrypted,
base::TimeDelta() /* seek preroll */, 0 /* codec delay */);
return CodecConfigEval::kSupported;
}
// static
void AudioDecoderTraits::InitializeDecoder(
MediaDecoderType& decoder,
const MediaConfigType& media_config,
MediaDecoderType::InitCB init_cb,
MediaDecoderType::OutputCB output_cb) {
decoder.Initialize(media_config, nullptr /* cdm_context */, decoder.Initialize(media_config, nullptr /* cdm_context */,
std::move(init_cb), output_cb, media::WaitingCB()); std::move(init_cb), output_cb, media::WaitingCB());
} }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_output_callback.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_output_callback.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_web_codecs_error_callback.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_web_codecs_error_callback.h"
#include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h"
#include "third_party/blink/renderer/modules/webcodecs/decoder_template.h" #include "third_party/blink/renderer/modules/webcodecs/decoder_template.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
...@@ -48,13 +49,17 @@ class MODULES_EXPORT AudioDecoderTraits { ...@@ -48,13 +49,17 @@ class MODULES_EXPORT AudioDecoderTraits {
using MediaDecoderType = media::AudioDecoder; using MediaDecoderType = media::AudioDecoder;
using OutputCallbackType = V8AudioFrameOutputCallback; using OutputCallbackType = V8AudioFrameOutputCallback;
using ConfigType = EncodedAudioConfig; using ConfigType = EncodedAudioConfig;
using MediaConfigType = media::AudioDecoderConfig;
using InputType = EncodedAudioChunk; using InputType = EncodedAudioChunk;
static std::unique_ptr<MediaDecoderType> CreateDecoder( static std::unique_ptr<MediaDecoderType> CreateDecoder(
ExecutionContext& execution_context, ExecutionContext& execution_context,
media::MediaLog* media_log); media::MediaLog* media_log);
static CodecConfigEval CreateMediaConfig(const ConfigType& config,
MediaConfigType* out_media_config,
String* out_console_message);
static void InitializeDecoder(MediaDecoderType& decoder, static void InitializeDecoder(MediaDecoderType& decoder,
const ConfigType& config, const MediaConfigType& media_config,
MediaDecoderType::InitCB init_cb, MediaDecoderType::InitCB init_cb,
MediaDecoderType::OutputCB output_cb); MediaDecoderType::OutputCB output_cb);
static int GetMaxDecodeRequests(const MediaDecoderType& decoder); static int GetMaxDecodeRequests(const MediaDecoderType& decoder);
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_CODEC_CONFIG_EVAL_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_CODEC_CONFIG_EVAL_H_
namespace blink {
// Possible outcomes of evaluating the user provided codec configurations (
// VideoDecoderConfig, VideoEncoderConfig, ...).
enum class CodecConfigEval {
// The codec config is not valid (e.g. bad codec string).
kInvalid,
// The codec config is valid, but unsupported.
kUnsupported,
// The codec config is valid and supported.
kSupported
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_CODEC_CONFIG_EVAL_H_
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/webcodecs/audio_decoder.h" #include "third_party/blink/renderer/modules/webcodecs/audio_decoder.h"
#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h" #include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
#include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h"
#include "third_party/blink/renderer/modules/webcodecs/video_decoder.h" #include "third_party/blink/renderer/modules/webcodecs/video_decoder.h"
#include "third_party/blink/renderer/modules/webcodecs/video_frame.h" #include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h" #include "third_party/blink/renderer/platform/bindings/exception_code.h"
...@@ -60,11 +61,30 @@ int32_t DecoderTemplate<Traits>::decodeQueueSize() { ...@@ -60,11 +61,30 @@ int32_t DecoderTemplate<Traits>::decodeQueueSize() {
template <typename Traits> template <typename Traits>
void DecoderTemplate<Traits>::configure(const ConfigType* config, void DecoderTemplate<Traits>::configure(const ConfigType* config,
ExceptionState&) { ExceptionState& exception_state) {
DVLOG(1) << __func__; DVLOG(1) << __func__;
auto media_config = std::make_unique<MediaConfigType>();
String console_message;
CodecConfigEval eval =
Traits::CreateMediaConfig(*config, media_config.get(), &console_message);
switch (eval) {
case CodecConfigEval::kInvalid:
exception_state.ThrowTypeError(console_message);
return;
case CodecConfigEval::kUnsupported:
exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
console_message);
return;
case CodecConfigEval::kSupported:
// Good, lets proceed.
break;
}
Request* request = MakeGarbageCollected<Request>(); Request* request = MakeGarbageCollected<Request>();
request->type = Request::Type::kConfigure; request->type = Request::Type::kConfigure;
request->config = config; request->media_config = std::move(media_config);
requests_.push_back(request); requests_.push_back(request);
ProcessRequests(); ProcessRequests();
} }
...@@ -141,7 +161,7 @@ bool DecoderTemplate<Traits>::ProcessConfigureRequest(Request* request) { ...@@ -141,7 +161,7 @@ bool DecoderTemplate<Traits>::ProcessConfigureRequest(Request* request) {
DVLOG(3) << __func__; DVLOG(3) << __func__;
DCHECK(!pending_request_); DCHECK(!pending_request_);
DCHECK_EQ(request->type, Request::Type::kConfigure); DCHECK_EQ(request->type, Request::Type::kConfigure);
DCHECK(request->config); DCHECK(request->media_config);
// TODO(sandersd): If we require configure() after reset() and there is a // TODO(sandersd): If we require configure() after reset() and there is a
// pending reset, then we could drop this request. // pending reset, then we could drop this request.
...@@ -165,7 +185,7 @@ bool DecoderTemplate<Traits>::ProcessConfigureRequest(Request* request) { ...@@ -165,7 +185,7 @@ bool DecoderTemplate<Traits>::ProcessConfigureRequest(Request* request) {
// case it must not call ProcessRequests(). // case it must not call ProcessRequests().
pending_request_ = request; pending_request_ = request;
Traits::InitializeDecoder( Traits::InitializeDecoder(
*decoder_, *pending_request_->config, *decoder_, *pending_request_->media_config,
WTF::Bind(&DecoderTemplate::OnInitializeDone, WrapWeakPersistent(this)), WTF::Bind(&DecoderTemplate::OnInitializeDone, WrapWeakPersistent(this)),
WTF::BindRepeating(&DecoderTemplate::OnOutput, WTF::BindRepeating(&DecoderTemplate::OnOutput,
WrapWeakPersistent(this))); WrapWeakPersistent(this)));
...@@ -290,7 +310,7 @@ void DecoderTemplate<Traits>::OnConfigureFlushDone(media::DecodeStatus status) { ...@@ -290,7 +310,7 @@ void DecoderTemplate<Traits>::OnConfigureFlushDone(media::DecodeStatus status) {
// Processing continues in OnInitializeDone(). // Processing continues in OnInitializeDone().
Traits::InitializeDecoder( Traits::InitializeDecoder(
*decoder_, *pending_request_->config, *decoder_, *pending_request_->media_config,
WTF::Bind(&DecoderTemplate::OnInitializeDone, WrapWeakPersistent(this)), WTF::Bind(&DecoderTemplate::OnInitializeDone, WrapWeakPersistent(this)),
WTF::BindRepeating(&DecoderTemplate::OnOutput, WrapWeakPersistent(this))); WTF::BindRepeating(&DecoderTemplate::OnOutput, WrapWeakPersistent(this)));
} }
...@@ -374,7 +394,6 @@ void DecoderTemplate<Traits>::Trace(Visitor* visitor) const { ...@@ -374,7 +394,6 @@ void DecoderTemplate<Traits>::Trace(Visitor* visitor) const {
template <typename Traits> template <typename Traits>
void DecoderTemplate<Traits>::Request::Trace(Visitor* visitor) const { void DecoderTemplate<Traits>::Request::Trace(Visitor* visitor) const {
visitor->Trace(config);
visitor->Trace(chunk); visitor->Trace(chunk);
visitor->Trace(resolver); visitor->Trace(resolver);
} }
......
...@@ -27,6 +27,7 @@ template <typename Traits> ...@@ -27,6 +27,7 @@ template <typename Traits>
class MODULES_EXPORT DecoderTemplate : public ScriptWrappable { class MODULES_EXPORT DecoderTemplate : public ScriptWrappable {
public: public:
typedef typename Traits::ConfigType ConfigType; typedef typename Traits::ConfigType ConfigType;
typedef typename Traits::MediaConfigType MediaConfigType;
typedef typename Traits::InputType InputType; typedef typename Traits::InputType InputType;
typedef typename Traits::InitType InitType; typedef typename Traits::InitType InitType;
typedef typename Traits::MediaDecoderType MediaDecoderType; typedef typename Traits::MediaDecoderType MediaDecoderType;
...@@ -48,7 +49,7 @@ class MODULES_EXPORT DecoderTemplate : public ScriptWrappable { ...@@ -48,7 +49,7 @@ class MODULES_EXPORT DecoderTemplate : public ScriptWrappable {
void Trace(Visitor*) const override; void Trace(Visitor*) const override;
private: private:
struct Request : public GarbageCollected<Request> { struct Request final : public GarbageCollected<Request> {
enum class Type { enum class Type {
kConfigure, kConfigure,
kDecode, kDecode,
...@@ -61,7 +62,7 @@ class MODULES_EXPORT DecoderTemplate : public ScriptWrappable { ...@@ -61,7 +62,7 @@ class MODULES_EXPORT DecoderTemplate : public ScriptWrappable {
Type type; Type type;
// For kConfigure Requests. // For kConfigure Requests.
Member<const ConfigType> config; std::unique_ptr<MediaConfigType> media_config;
// For kDecode Requests. // For kDecode Requests.
Member<const InputType> chunk; Member<const InputType> chunk;
......
...@@ -9,10 +9,10 @@ dictionary EncodedAudioConfig { ...@@ -9,10 +9,10 @@ dictionary EncodedAudioConfig {
required DOMString codec; required DOMString codec;
// Rate of samples per second. 44100, 48000, etc. // Rate of samples per second. 44100, 48000, etc.
unsigned long sampleRate; required unsigned long sampleRate;
// 1, 2, etc. // 1, 2, etc.
unsigned long numberOfChannels; required unsigned long numberOfChannels;
// Optional byte data required to initialize audio decoders such as Vorbis // Optional byte data required to initialize audio decoders such as Vorbis
// codebooks. // codebooks.
......
...@@ -10,11 +10,14 @@ ...@@ -10,11 +10,14 @@
#include "base/time/time.h" #include "base/time/time.h"
#include "media/base/decoder_buffer.h" #include "media/base/decoder_buffer.h"
#include "media/base/media_util.h" #include "media/base/media_util.h"
#include "media/base/mime_util.h"
#include "media/base/supported_types.h"
#include "media/base/video_decoder.h" #include "media/base/video_decoder.h"
#include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_config.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_config.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h"
#include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h" #include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h"
#include "third_party/blink/renderer/modules/webcodecs/video_decoder_broker.h" #include "third_party/blink/renderer/modules/webcodecs/video_decoder_broker.h"
#include "third_party/blink/renderer/modules/webcodecs/video_frame.h" #include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
...@@ -37,11 +40,37 @@ VideoDecoderTraits::CreateDecoder(ExecutionContext& execution_context, ...@@ -37,11 +40,37 @@ VideoDecoderTraits::CreateDecoder(ExecutionContext& execution_context,
} }
// static // static
void VideoDecoderTraits::InitializeDecoder( CodecConfigEval VideoDecoderTraits::CreateMediaConfig(
MediaDecoderType& decoder,
const ConfigType& config, const ConfigType& config,
MediaDecoderType::InitCB init_cb, MediaConfigType* out_media_config,
MediaDecoderType::OutputCB output_cb) { String* out_console_message) {
DCHECK(out_media_config);
DCHECK(out_console_message);
bool is_codec_ambiguous = true;
media::VideoCodec codec = media::kUnknownVideoCodec;
media::VideoCodecProfile profile = media::VIDEO_CODEC_PROFILE_UNKNOWN;
media::VideoColorSpace color_space = media::VideoColorSpace::REC709();
uint8_t level = 0;
bool parse_succeeded = media::ParseVideoCodecString(
"", config.codec().Utf8(), &is_codec_ambiguous, &codec, &profile, &level,
&color_space);
if (!parse_succeeded) {
*out_console_message = "Failed to parse codec string.";
return CodecConfigEval::kInvalid;
}
if (is_codec_ambiguous) {
*out_console_message = "Codec string is ambiguous.";
return CodecConfigEval::kInvalid;
}
if (!media::IsSupportedVideoType({codec, profile, level, color_space})) {
*out_console_message = "Configuration is not supported.";
return CodecConfigEval::kUnsupported;
}
std::vector<uint8_t> extra_data; std::vector<uint8_t> extra_data;
if (config.hasDescription()) { if (config.hasDescription()) {
DOMArrayBuffer* buffer; DOMArrayBuffer* buffer;
...@@ -58,22 +87,27 @@ void VideoDecoderTraits::InitializeDecoder( ...@@ -58,22 +87,27 @@ void VideoDecoderTraits::InitializeDecoder(
extra_data.assign(start, start + size); extra_data.assign(start, start + size);
} }
media::VideoCodec codec = media::kUnknownVideoCodec;
media::VideoCodecProfile profile = media::VIDEO_CODEC_PROFILE_UNKNOWN;
media::VideoColorSpace color_space = media::VideoColorSpace::REC709();
uint8_t level = 0;
media::ParseCodec(config.codec().Utf8(), codec, profile, level, color_space);
// TODO(sandersd): Either remove sizes from VideoDecoderConfig (replace with // TODO(sandersd): Either remove sizes from VideoDecoderConfig (replace with
// sample aspect) or parse the AvcC here to get the actual size. // sample aspect) or parse the AvcC here to get the actual size.
// For the moment, hard-code 720p to prefer hardware decoders. // For the moment, hard-code 720p to prefer hardware decoders.
gfx::Size size = gfx::Size(1280, 720); gfx::Size size = gfx::Size(1280, 720);
media::VideoDecoderConfig video_decoder_config(
codec, profile, media::VideoDecoderConfig::AlphaMode::kIsOpaque,
color_space, media::kNoTransformation, size,
gfx::Rect(gfx::Point(), size), size, extra_data,
media::EncryptionScheme::kUnencrypted);
decoder.Initialize(video_decoder_config, false /* low_delay */, out_media_config->Initialize(codec, profile,
media::VideoDecoderConfig::AlphaMode::kIsOpaque,
color_space, media::kNoTransformation, size,
gfx::Rect(gfx::Point(), size), size, extra_data,
media::EncryptionScheme::kUnencrypted);
return CodecConfigEval::kSupported;
}
// static
void VideoDecoderTraits::InitializeDecoder(
MediaDecoderType& decoder,
const MediaConfigType& media_config,
MediaDecoderType::InitCB init_cb,
MediaDecoderType::OutputCB output_cb) {
decoder.Initialize(media_config, false /* low_delay */,
nullptr /* cdm_context */, std::move(init_cb), output_cb, nullptr /* cdm_context */, std::move(init_cb), output_cb,
media::WaitingCB()); media::WaitingCB());
} }
......
...@@ -11,11 +11,13 @@ ...@@ -11,11 +11,13 @@
#include "media/base/media_log.h" #include "media/base/media_log.h"
#include "media/base/status.h" #include "media/base/status.h"
#include "media/base/video_decoder.h" #include "media/base/video_decoder.h"
#include "media/base/video_decoder_config.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_output_callback.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_output_callback.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_web_codecs_error_callback.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_web_codecs_error_callback.h"
#include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h"
#include "third_party/blink/renderer/modules/webcodecs/decoder_template.h" #include "third_party/blink/renderer/modules/webcodecs/decoder_template.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
...@@ -48,13 +50,17 @@ class MODULES_EXPORT VideoDecoderTraits { ...@@ -48,13 +50,17 @@ class MODULES_EXPORT VideoDecoderTraits {
using MediaDecoderType = media::VideoDecoder; using MediaDecoderType = media::VideoDecoder;
using OutputCallbackType = V8VideoFrameOutputCallback; using OutputCallbackType = V8VideoFrameOutputCallback;
using ConfigType = EncodedVideoConfig; using ConfigType = EncodedVideoConfig;
using MediaConfigType = media::VideoDecoderConfig;
using InputType = EncodedVideoChunk; using InputType = EncodedVideoChunk;
static std::unique_ptr<MediaDecoderType> CreateDecoder( static std::unique_ptr<MediaDecoderType> CreateDecoder(
ExecutionContext& execution_context, ExecutionContext& execution_context,
media::MediaLog* media_log); media::MediaLog* media_log);
static CodecConfigEval CreateMediaConfig(const ConfigType& config,
MediaConfigType* out_media_config,
String* out_console_message);
static void InitializeDecoder(MediaDecoderType& decoder, static void InitializeDecoder(MediaDecoderType& decoder,
const ConfigType& config, const MediaConfigType& media_config,
MediaDecoderType::InitCB init_cb, MediaDecoderType::InitCB init_cb,
MediaDecoderType::OutputCB output_cb); MediaDecoderType::OutputCB output_cb);
static int GetMaxDecodeRequests(const MediaDecoderType& decoder); static int GetMaxDecodeRequests(const MediaDecoderType& decoder);
......
<!DOCTYPE html>
<html>
<title>Test the AudioDecoder API.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
// Calls done after giving async output/error callbacks a final chance to run.
async function asyncDone(test) {
test.step_timeout(test.step_func_done(), 0);
}
async_test(async (t) => {
// AudioDecoderInit lacks required fields.
assert_throws_js(TypeError, () => { new AudioDecoder({}); });
// AudioDecoderInit has required fields.
let decoder = new AudioDecoder({
output(chunk) { t.unreached_func("Unexpected output").call(); },
error(error) { t.unreached_func("Unexpected error:" + error).call(); },
});
asyncDone(t);
}, 'Test AudioDecoder construction');
async_test(async (t) => {
let decoder = new AudioDecoder({
output(chunk) { t.unreached_func("Unexpected output").call(); },
error(error) { t.unreached_func("Unexpected error:" + error).call(); },
});
let config = {
sampleRate: 48000,
numberOfChannels: 2
}
// Empty codec rejected.
config.codec = '';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Invalid codec rejected.
config.codec = 'bogus';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Video codec rejected.
config.codec = 'vp8';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Codec with mime type rejected.
config.codec = 'audio/webm; codecs="opus"';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Valid audio codec accepted.
config.codec = 'opus';
decoder.configure(config);
asyncDone(t);
}, 'Test AudioDecoder.configure() codec validity');
</script>
</html>
<!DOCTYPE html>
<html>
<title>Test the VideoDecoder API.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
// Calls done after giving async output/error callbacks a final chance to run.
async function asyncDone(test) {
test.step_timeout(test.step_func_done(), 0);
}
async_test(async (t) => {
// VideoDecoderInit lacks required fields.
assert_throws_js(TypeError, () => { new VideoDecoder({}); });
// VideoDecoderInit has required fields.
let decoder = new VideoDecoder({
output(chunk) { t.unreached_func("Unexpected output").call(); },
error(error) { t.unreached_func("Unexpected error:" + error).call(); },
});
asyncDone(t);
}, 'Test VideoDecoder construction');
async_test(async (t) => {
let decoder = new VideoDecoder({
output(chunk) { t.unreached_func("Unexpected output").call(); },
error(error) { t.unreached_func("Unexpected error:" + error).call(); },
});
let config = {};
// Bogus codec rejected.
config.codec = 'bogus';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Audio codec rejected.
config.codec = 'vorbis';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Ambiguous codec rejected.
config.codec = 'vp9';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Codec with mime type rejected.
config.codec = 'video/webm; codecs="vp9"';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Valid unambiguous codec accepted.
config.codec = 'vp09.00.10.08';
decoder.configure(config);
asyncDone(t);
}, 'Test VideoDecoder.configure() codec validity');
</script>
</html>
...@@ -62,8 +62,6 @@ async_test(async (t) => { ...@@ -62,8 +62,6 @@ async_test(async (t) => {
// Configure should pass once incrementalConfig meets all requirements. // Configure should pass once incrementalConfig meets all requirements.
encoder.configure(incrementalConfig); encoder.configure(incrementalConfig);
encoder.configure(incrementalConfig);
encoder.close(); encoder.close();
asyncDone(t); asyncDone(t);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment