From 700a5d85661641333a7cf8422b13849a3148cf4a Mon Sep 17 00:00:00 2001 From: Chris Cunningham Date: Tue, 9 Aug 2022 18:01:30 +0000 Subject: [PATCH] [webcodecs] Add dequeue event to AudioDecoder + VideoDecoder interfaces Implementation is behind flag: --enable-blink-features=WebCodecsDequeueEvent Bug: 1341116 Change-Id: I8915e4573ee9175cb67c9923f0d93e1b28d6e9e2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3807054 Commit-Queue: Chrome Cunningham Reviewed-by: Kentaro Hara Auto-Submit: Chrome Cunningham Reviewed-by: Mike Taylor Reviewed-by: Thomas Guilbert Cr-Commit-Position: refs/heads/main@{#1033102} --- .../modules/event_target_modules_names.json5 | 2 + .../modules/webcodecs/audio_decoder.cc | 4 ++ .../modules/webcodecs/audio_decoder.h | 3 + .../modules/webcodecs/audio_decoder.idl | 7 +- .../modules/webcodecs/decoder_template.cc | 67 ++++++++++++++++++- .../modules/webcodecs/decoder_template.h | 13 +++- .../modules/webcodecs/encoder_base.cc | 1 - .../modules/webcodecs/video_decoder.cc | 4 ++ .../modules/webcodecs/video_decoder.h | 3 + .../modules/webcodecs/video_decoder.idl | 11 +-- .../audioDecoder-codec-specific.https.any.js | 44 ++++++++++++ .../videoDecoder-codec-specific.https.any.js | 45 +++++++++++++ ...face-listing-dedicated-worker-expected.txt | 4 +- .../global-interface-listing-expected.txt | 4 +- ...face-listing-dedicated-worker-expected.txt | 8 ++- .../global-interface-listing-expected.txt | 8 ++- 16 files changed, 210 insertions(+), 18 deletions(-) diff --git a/third_party/blink/renderer/modules/event_target_modules_names.json5 b/third_party/blink/renderer/modules/event_target_modules_names.json5 index a70b6e72132b70..e0129aac0eb27b 100644 --- a/third_party/blink/renderer/modules/event_target_modules_names.json5 +++ b/third_party/blink/renderer/modules/event_target_modules_names.json5 @@ -87,5 +87,7 @@ "WindowControlsOverlay", "AudioEncoder", "VideoEncoder", + "AudioDecoder", + "VideoDecoder", ], } diff --git a/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc b/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc index 02dcb12fd974b2..bce83af74e54c8 100644 --- a/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc +++ b/third_party/blink/renderer/modules/webcodecs/audio_decoder.cc @@ -269,4 +269,8 @@ AudioDecoder::MakeDecoderBuffer(const InputType& chunk, bool verify_key_frame) { return chunk.buffer(); } +const AtomicString& AudioDecoder::InterfaceName() const { + return event_target_names::kAudioDecoder; +} + } // namespace blink diff --git a/third_party/blink/renderer/modules/webcodecs/audio_decoder.h b/third_party/blink/renderer/modules/webcodecs/audio_decoder.h index e2e201ca246771..8afde1b9901015 100644 --- a/third_party/blink/renderer/modules/webcodecs/audio_decoder.h +++ b/third_party/blink/renderer/modules/webcodecs/audio_decoder.h @@ -95,6 +95,9 @@ class MODULES_EXPORT AudioDecoder : public DecoderTemplate { AudioDecoder(ScriptState*, const AudioDecoderInit*, ExceptionState&); ~AudioDecoder() override = default; + // EventTarget interface + const AtomicString& InterfaceName() const override; + protected: bool IsValidConfig(const ConfigType& config, String* js_error_message) override; diff --git a/third_party/blink/renderer/modules/webcodecs/audio_decoder.idl b/third_party/blink/renderer/modules/webcodecs/audio_decoder.idl index 68a0ba26383fe9..5cac7a70d5aece 100644 --- a/third_party/blink/renderer/modules/webcodecs/audio_decoder.idl +++ b/third_party/blink/renderer/modules/webcodecs/audio_decoder.idl @@ -9,7 +9,7 @@ SecureContext, RuntimeEnabled=WebCodecs, ActiveScriptWrappable -] interface AudioDecoder { +] interface AudioDecoder : EventTarget { // |init| includes an |output| callback for emitting AudioBuffers and an // |error| callback for emitting decode errors. All errors are permanent; // construct a new decoder to recover. @@ -24,6 +24,11 @@ // |decodeQueueSize| is greater than a constant. readonly attribute unsigned long decodeQueueSize; + // Fires to signal a decrease in decodeQueueSize. Will fire at most once for a + // given turn of the event loop. + [RuntimeEnabled=WebCodecsDequeueEvent] + attribute EventHandler ondequeue; + // Which state the decoder is in, indicating which methods can be called. readonly attribute CodecState state; diff --git a/third_party/blink/renderer/modules/webcodecs/decoder_template.cc b/third_party/blink/renderer/modules/webcodecs/decoder_template.cc index 10c583c9c2ab7a..8ae7dbef808b4c 100644 --- a/third_party/blink/renderer/modules/webcodecs/decoder_template.cc +++ b/third_party/blink/renderer/modules/webcodecs/decoder_template.cc @@ -29,7 +29,9 @@ #include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_init.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" +#include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" +#include "third_party/blink/renderer/core/probe/core_probes.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/webcodecs/audio_data.h" #include "third_party/blink/renderer/modules/webcodecs/audio_decoder.h" @@ -41,6 +43,7 @@ #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/heap/persistent.h" +#include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" #include "third_party/blink/renderer/platform/scheduler/public/thread.h" #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" @@ -131,6 +134,7 @@ template void DecoderTemplate::configure(const ConfigType* config, ExceptionState& exception_state) { DVLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (ThrowIfCodecStateClosed(state_, "decode", exception_state)) return; @@ -167,6 +171,7 @@ template void DecoderTemplate::decode(const InputType* chunk, ExceptionState& exception_state) { DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (ThrowIfCodecStateClosed(state_, "decode", exception_state)) return; @@ -199,6 +204,7 @@ void DecoderTemplate::decode(const InputType* chunk, template ScriptPromise DecoderTemplate::flush(ExceptionState& exception_state) { DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (ThrowIfCodecStateClosed(state_, "flush", exception_state)) return ScriptPromise(); @@ -223,6 +229,7 @@ ScriptPromise DecoderTemplate::flush(ExceptionState& exception_state) { template void DecoderTemplate::reset(ExceptionState& exception_state) { DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (ThrowIfCodecStateClosed(state_, "reset", exception_state)) return; @@ -234,6 +241,7 @@ void DecoderTemplate::reset(ExceptionState& exception_state) { template void DecoderTemplate::close(ExceptionState& exception_state) { DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (ThrowIfCodecStateClosed(state_, "close", exception_state)) return; @@ -243,6 +251,7 @@ void DecoderTemplate::close(ExceptionState& exception_state) { template void DecoderTemplate::ProcessRequests() { DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!IsClosed()); while (!pending_request_ && !requests_.IsEmpty()) { Request* request = requests_.front(); @@ -289,6 +298,7 @@ void DecoderTemplate::ProcessRequests() { template bool DecoderTemplate::ProcessConfigureRequest(Request* request) { DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!IsClosed()); DCHECK(!pending_request_); DCHECK_EQ(request->type, Request::Type::kConfigure); @@ -322,6 +332,7 @@ template void DecoderTemplate::ContinueConfigureWithGpuFactories( Request* request, media::GpuVideoAcceleratorFactories* gpu_factories) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(request); DCHECK_EQ(request->type, Request::Type::kConfigure); @@ -362,6 +373,7 @@ void DecoderTemplate::ContinueConfigureWithGpuFactories( template bool DecoderTemplate::ProcessDecodeRequest(Request* request) { DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_EQ(state_, V8CodecState::Enum::kConfigured); DCHECK(!pending_request_); DCHECK_EQ(request->type, Request::Type::kDecode); @@ -402,6 +414,7 @@ bool DecoderTemplate::ProcessDecodeRequest(Request* request) { ; pending_decodes_.Set(pending_decode_id_, request); --num_pending_decodes_; + ScheduleDequeueEvent(); if (media::ScopedDecodeTrace::IsEnabled()) { request->decode_trace = std::make_unique( @@ -417,6 +430,7 @@ bool DecoderTemplate::ProcessDecodeRequest(Request* request) { template bool DecoderTemplate::ProcessFlushRequest(Request* request) { DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!IsClosed()); DCHECK(!pending_request_); DCHECK_EQ(request->type, Request::Type::kFlush); @@ -445,6 +459,7 @@ bool DecoderTemplate::ProcessFlushRequest(Request* request) { template bool DecoderTemplate::ProcessResetRequest(Request* request) { DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!IsClosed()); DCHECK(!pending_request_); DCHECK_EQ(request->type, Request::Type::kReset); @@ -467,6 +482,7 @@ bool DecoderTemplate::ProcessResetRequest(Request* request) { template void DecoderTemplate::Shutdown(DOMException* exception) { DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (IsClosed()) return; @@ -525,6 +541,7 @@ void DecoderTemplate::Shutdown(DOMException* exception) { pending_decodes_.clear(); num_pending_decodes_ = 0; + ScheduleDequeueEvent(); // Fire the error callback if necessary. if (exception) @@ -533,6 +550,7 @@ void DecoderTemplate::Shutdown(DOMException* exception) { template void DecoderTemplate::ResetAlgorithm() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (state_ == V8CodecState::Enum::kUnconfigured) return; @@ -545,6 +563,7 @@ void DecoderTemplate::ResetAlgorithm() { // Any previous pending decode will be filtered by ProcessRequests(). Reset // the count immediately to report the correct value in decodeQueueSize(). num_pending_decodes_ = 0; + ScheduleDequeueEvent(); // Since configure is always required after reset we can drop any cached // configuration. @@ -560,6 +579,7 @@ void DecoderTemplate::ResetAlgorithm() { template void DecoderTemplate::OnFlushDone(media::DecoderStatus status) { DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (IsClosed()) return; @@ -603,6 +623,7 @@ void DecoderTemplate::OnFlushDone(media::DecoderStatus status) { template void DecoderTemplate::OnInitializeDone(media::DecoderStatus status) { DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (IsClosed()) return; @@ -654,6 +675,7 @@ template void DecoderTemplate::OnDecodeDone(uint32_t id, media::DecoderStatus status) { DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (IsClosed()) return; @@ -676,6 +698,7 @@ void DecoderTemplate::OnDecodeDone(uint32_t id, template void DecoderTemplate::OnResetDone() { DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (IsClosed()) return; @@ -690,6 +713,7 @@ template void DecoderTemplate::OnOutput(uint32_t reset_generation, scoped_refptr output) { DVLOG(3) << __func__; + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Suppress outputs belonging to an earlier reset_generation. if (reset_generation != reset_generation_) @@ -724,14 +748,51 @@ void DecoderTemplate::OnOutput(uint32_t reset_generation, template void DecoderTemplate::TraceQueueSizes() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); TRACE_COUNTER_ID2(kCategory, GetTraceNames()->requests_counter.c_str(), trace_counter_id_, "decodes", num_pending_decodes_, "other", requests_.size() - num_pending_decodes_); } +template +void DecoderTemplate::DispatchDequeueEvent(Event* event) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + probe::AsyncTask async_task(GetExecutionContext(), + event->async_task_context()); + dequeue_event_pending_ = false; + DispatchEvent(*event); +} + +template +void DecoderTemplate::ScheduleDequeueEvent() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!RuntimeEnabledFeatures::WebCodecsDequeueEventEnabled()) + return; + + if (dequeue_event_pending_) + return; + dequeue_event_pending_ = true; + + Event* event = Event::Create(event_type_names::kDequeue); + event->SetTarget(this); + event->async_task_context()->Schedule(GetExecutionContext(), event->type()); + + main_thread_task_runner_->PostTask( + FROM_HERE, WTF::Bind(&DecoderTemplate::DispatchDequeueEvent, + WrapWeakPersistent(this), WrapPersistent(event))); +} + +template +ExecutionContext* DecoderTemplate::GetExecutionContext() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return ExecutionContextLifecycleObserver::GetExecutionContext(); +} + template void DecoderTemplate::ContextDestroyed() { - // Deallocate resources and supress late callbacks from media thread. + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // Deallocate resources and suppress late callbacks from media thread. Shutdown(); } @@ -743,7 +804,7 @@ void DecoderTemplate::Trace(Visitor* visitor) const { visitor->Trace(requests_); visitor->Trace(pending_request_); visitor->Trace(pending_decodes_); - ScriptWrappable::Trace(visitor); + EventTargetWithInlineData::Trace(visitor); ExecutionContextLifecycleObserver::Trace(visitor); ReclaimableCodec::Trace(visitor); } @@ -751,6 +812,7 @@ void DecoderTemplate::Trace(Visitor* visitor) const { template void DecoderTemplate::OnCodecReclaimed(DOMException* exception) { TRACE_EVENT0(kCategory, GetTraceNames()->reclaimed.c_str()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(is_applying_codec_pressure()); if (state_.AsEnum() == V8CodecState::Enum::kUnconfigured) { @@ -768,6 +830,7 @@ void DecoderTemplate::OnCodecReclaimed(DOMException* exception) { template bool DecoderTemplate::HasPendingActivity() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return pending_request_ || !requests_.IsEmpty(); } diff --git a/third_party/blink/renderer/modules/webcodecs/decoder_template.h b/third_party/blink/renderer/modules/webcodecs/decoder_template.h index cba56fc3abec61..d9dd07d50c027d 100644 --- a/third_party/blink/renderer/modules/webcodecs/decoder_template.h +++ b/third_party/blink/renderer/modules/webcodecs/decoder_template.h @@ -16,6 +16,7 @@ #include "third_party/blink/renderer/bindings/modules/v8/v8_codec_state.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_webcodecs_error_callback.h" #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" +#include "third_party/blink/renderer/modules/event_target_modules.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/webcodecs/codec_logger.h" #include "third_party/blink/renderer/modules/webcodecs/codec_trace_names.h" @@ -40,7 +41,7 @@ namespace blink { template class MODULES_EXPORT DecoderTemplate - : public ScriptWrappable, + : public EventTargetWithInlineData, public ActiveScriptWrappable>, public ReclaimableCodec { public: @@ -59,6 +60,7 @@ class MODULES_EXPORT DecoderTemplate ~DecoderTemplate() override; uint32_t decodeQueueSize(); + DEFINE_ATTRIBUTE_EVENT_LISTENER(dequeue, kDequeue); void configure(const ConfigType*, ExceptionState&); void decode(const InputType*, ExceptionState&); ScriptPromise flush(ExceptionState&); @@ -66,6 +68,9 @@ class MODULES_EXPORT DecoderTemplate void close(ExceptionState&); String state() const { return state_; } + // EventTarget override. + ExecutionContext* GetExecutionContext() const override; + // ExecutionContextLifecycleObserver override. void ContextDestroyed() override; @@ -189,6 +194,10 @@ class MODULES_EXPORT DecoderTemplate void TraceQueueSizes() const; + void ScheduleDequeueEvent(); + void DispatchDequeueEvent(Event* event); + bool dequeue_event_pending_ = false; + Member script_state_; Member output_cb_; Member error_cb_; @@ -235,6 +244,8 @@ class MODULES_EXPORT DecoderTemplate // Task runner for main thread. scoped_refptr main_thread_task_runner_; + + SEQUENCE_CHECKER(sequence_checker_); }; } // namespace blink diff --git a/third_party/blink/renderer/modules/webcodecs/encoder_base.cc b/third_party/blink/renderer/modules/webcodecs/encoder_base.cc index 4d1b31e2c64dbb..d82425c3ba7ec3 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoder_base.cc +++ b/third_party/blink/renderer/modules/webcodecs/encoder_base.cc @@ -418,7 +418,6 @@ void EncoderBase::Trace(Visitor* visitor) const { visitor->Trace(error_callback_); visitor->Trace(requests_); EventTargetWithInlineData::Trace(visitor); - ScriptWrappable::Trace(visitor); ExecutionContextLifecycleObserver::Trace(visitor); ReclaimableCodec::Trace(visitor); } diff --git a/third_party/blink/renderer/modules/webcodecs/video_decoder.cc b/third_party/blink/renderer/modules/webcodecs/video_decoder.cc index bec771ff753958..36bc6967da9877 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_decoder.cc +++ b/third_party/blink/renderer/modules/webcodecs/video_decoder.cc @@ -599,4 +599,8 @@ VideoDecoder::MakeDecoderBuffer(const InputType& chunk, bool verify_key_frame) { return decoder_buffer; } +const AtomicString& VideoDecoder::InterfaceName() const { + return event_target_names::kVideoDecoder; +} + } // namespace blink diff --git a/third_party/blink/renderer/modules/webcodecs/video_decoder.h b/third_party/blink/renderer/modules/webcodecs/video_decoder.h index 7c5b7cf9e2f6d2..7910f8a3ba5802 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_decoder.h +++ b/third_party/blink/renderer/modules/webcodecs/video_decoder.h @@ -113,6 +113,9 @@ class MODULES_EXPORT VideoDecoder : public DecoderTemplate { VideoDecoder(ScriptState*, const VideoDecoderInit*, ExceptionState&); ~VideoDecoder() override = default; + // EventTarget interface + const AtomicString& InterfaceName() const override; + protected: bool IsValidConfig(const ConfigType& config, String* js_error_message) override; diff --git a/third_party/blink/renderer/modules/webcodecs/video_decoder.idl b/third_party/blink/renderer/modules/webcodecs/video_decoder.idl index 3633fabe3bcf75..cb6540652d88b1 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_decoder.idl +++ b/third_party/blink/renderer/modules/webcodecs/video_decoder.idl @@ -7,16 +7,12 @@ // A VideoDecoder processes a queue of configure, decode, and flush requests. // Requests are taken from the queue sequentially but may be processed // concurrently. -// -// TODO(sandersd): Specify a tune() implementation for changing decoder -// parameters (separate from stream parameters). This is more important for -// encoders. [ Exposed=(Window,DedicatedWorker), SecureContext, RuntimeEnabled=WebCodecs, ActiveScriptWrappable -] interface VideoDecoder { +] interface VideoDecoder : EventTarget { // |init| includes an |output| callback for emitting VideoFrames and an // |error| callback for emitting decode errors. // @@ -36,6 +32,11 @@ // TODO(sandersd): Consider emitting an event when this number decreases. readonly attribute unsigned long decodeQueueSize; + // Fires to signal a decrease in decodeQueueSize. Will fire at most once for a + // given turn of the event loop. + [RuntimeEnabled=WebCodecsDequeueEvent] + attribute EventHandler ondequeue; + // Which state the decoder is in, indicating which methods can be called. readonly attribute CodecState state; diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/audioDecoder-codec-specific.https.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/audioDecoder-codec-specific.https.any.js index 994aaf1d17b734..b53965c529d475 100644 --- a/third_party/blink/web_tests/external/wpt/webcodecs/audioDecoder-codec-specific.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webcodecs/audioDecoder-codec-specific.https.any.js @@ -324,3 +324,47 @@ promise_test(async t => { assert_equals(outputs, 1, 'outputs'); }, 'Test reset during flush'); + +promise_test(async t => { + const callbacks = {}; + const decoder = createAudioDecoder(t, callbacks); + + // No decodes yet. + assert_equals(decoder.decodeQueueSize, 0); + + decoder.configure(CONFIG); + + // Still no decodes. + assert_equals(decoder.decodeQueueSize, 0); + + let lastDequeueSize = Infinity; + decoder.ondequeue = () => { + assert_greater_than(lastDequeueSize, 0, "Dequeue event after queue empty"); + assert_greater_than(lastDequeueSize, decoder.decodeQueueSize, + "Dequeue event without decreased queue size"); + lastDequeueSize = decoder.decodeQueueSize; + }; + + for (let chunk of CHUNKS) + decoder.decode(chunk); + + assert_greater_than_equal(decoder.decodeQueueSize, 0); + assert_less_than_equal(decoder.decodeQueueSize, CHUNKS.length); + + await decoder.flush(); + // We can guarantee that all decodes are processed after a flush. + assert_equals(decoder.decodeQueueSize, 0); + // Last dequeue event should fire when the queue is empty. + assert_equals(lastDequeueSize, 0); + + // Reset this to Infinity to track the decline of queue size for this next + // batch of decodes. + lastDequeueSize = Infinity; + + for (let chunk of CHUNKS) + decoder.decode(chunk); + + assert_greater_than_equal(decoder.decodeQueueSize, 0); + decoder.reset(); + assert_equals(decoder.decodeQueueSize, 0); +}, 'AudioDecoder decodeQueueSize test'); diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/videoDecoder-codec-specific.https.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/videoDecoder-codec-specific.https.any.js index f94bee82d18de1..fab0b24220dc9b 100644 --- a/third_party/blink/web_tests/external/wpt/webcodecs/videoDecoder-codec-specific.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webcodecs/videoDecoder-codec-specific.https.any.js @@ -484,3 +484,48 @@ promise_test(async t => { }; }); }, 'Test low-latency decoding'); + + +promise_test(async t => { + const callbacks = {}; + const decoder = createVideoDecoder(t, callbacks); + + // No decodes yet. + assert_equals(decoder.decodeQueueSize, 0); + + decoder.configure(CONFIG); + + // Still no decodes. + assert_equals(decoder.decodeQueueSize, 0); + + let lastDequeueSize = Infinity; + decoder.ondequeue = () => { + assert_greater_than(lastDequeueSize, 0, "Dequeue event after queue empty"); + assert_greater_than(lastDequeueSize, decoder.decodeQueueSize, + "Dequeue event without decreased queue size"); + lastDequeueSize = decoder.decodeQueueSize; + }; + + for (let chunk of CHUNKS) + decoder.decode(chunk); + + assert_greater_than_equal(decoder.decodeQueueSize, 0); + assert_less_than_equal(decoder.decodeQueueSize, CHUNKS.length); + + await decoder.flush(); + // We can guarantee that all decodes are processed after a flush. + assert_equals(decoder.decodeQueueSize, 0); + // Last dequeue event should fire when the queue is empty. + assert_equals(lastDequeueSize, 0); + + // Reset this to Infinity to track the decline of queue size for this next + // batch of decodes. + lastDequeueSize = Infinity; + + for (let chunk of CHUNKS) + decoder.decode(chunk); + + assert_greater_than_equal(decoder.decodeQueueSize, 0); + decoder.reset(); + assert_equals(decoder.decodeQueueSize, 0); +}, 'VideoDecoder decodeQueueSize test'); diff --git a/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt index 00b27ce3ee5c50..14a0c62313f1bc 100644 --- a/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt @@ -32,7 +32,7 @@ Starting worker: resources/global-interface-listing-worker.js [Worker] method close [Worker] method constructor [Worker] method copyTo -[Worker] interface AudioDecoder +[Worker] interface AudioDecoder : EventTarget [Worker] static method isConfigSupported [Worker] attribute @@toStringTag [Worker] getter decodeQueueSize @@ -1683,7 +1683,7 @@ Starting worker: resources/global-interface-listing-worker.js [Worker] getter transfer [Worker] method constructor [Worker] method toJSON -[Worker] interface VideoDecoder +[Worker] interface VideoDecoder : EventTarget [Worker] static method isConfigSupported [Worker] attribute @@toStringTag [Worker] getter decodeQueueSize diff --git a/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-expected.txt index 8a891fc158e02f..54fcae3d924c8a 100644 --- a/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/platform/generic/virtual/stable/webexposed/global-interface-listing-expected.txt @@ -169,7 +169,7 @@ interface AudioData method close method constructor method copyTo -interface AudioDecoder +interface AudioDecoder : EventTarget static method isConfigSupported attribute @@toStringTag getter decodeQueueSize @@ -8227,7 +8227,7 @@ interface VideoColorSpace getter transfer method constructor method toJSON -interface VideoDecoder +interface VideoDecoder : EventTarget static method isConfigSupported attribute @@toStringTag getter decodeQueueSize diff --git a/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-dedicated-worker-expected.txt index d3f0dde59d99fa..7afbc315382901 100644 --- a/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-dedicated-worker-expected.txt @@ -32,10 +32,11 @@ Starting worker: resources/global-interface-listing-worker.js [Worker] method close [Worker] method constructor [Worker] method copyTo -[Worker] interface AudioDecoder +[Worker] interface AudioDecoder : EventTarget [Worker] static method isConfigSupported [Worker] attribute @@toStringTag [Worker] getter decodeQueueSize +[Worker] getter ondequeue [Worker] getter state [Worker] method close [Worker] method configure @@ -43,6 +44,7 @@ Starting worker: resources/global-interface-listing-worker.js [Worker] method decode [Worker] method flush [Worker] method reset +[Worker] setter ondequeue [Worker] interface AudioEncoder : EventTarget [Worker] static method isConfigSupported [Worker] attribute @@toStringTag @@ -1840,10 +1842,11 @@ Starting worker: resources/global-interface-listing-worker.js [Worker] getter transfer [Worker] method constructor [Worker] method toJSON -[Worker] interface VideoDecoder +[Worker] interface VideoDecoder : EventTarget [Worker] static method isConfigSupported [Worker] attribute @@toStringTag [Worker] getter decodeQueueSize +[Worker] getter ondequeue [Worker] getter state [Worker] method close [Worker] method configure @@ -1851,6 +1854,7 @@ Starting worker: resources/global-interface-listing-worker.js [Worker] method decode [Worker] method flush [Worker] method reset +[Worker] setter ondequeue [Worker] interface VideoEncoder : EventTarget [Worker] static method isConfigSupported [Worker] attribute @@toStringTag diff --git a/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-expected.txt index 168d5317cb5691..c3bcb2bc71a85e 100644 --- a/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/platform/generic/webexposed/global-interface-listing-expected.txt @@ -295,10 +295,11 @@ interface AudioData method close method constructor method copyTo -interface AudioDecoder +interface AudioDecoder : EventTarget static method isConfigSupported attribute @@toStringTag getter decodeQueueSize + getter ondequeue getter state method close method configure @@ -306,6 +307,7 @@ interface AudioDecoder method decode method flush method reset + setter ondequeue interface AudioDestinationNode : AudioNode attribute @@toStringTag getter maxChannelCount @@ -9329,10 +9331,11 @@ interface VideoColorSpace getter transfer method constructor method toJSON -interface VideoDecoder +interface VideoDecoder : EventTarget static method isConfigSupported attribute @@toStringTag getter decodeQueueSize + getter ondequeue getter state method close method configure @@ -9340,6 +9343,7 @@ interface VideoDecoder method decode method flush method reset + setter ondequeue interface VideoEncoder : EventTarget static method isConfigSupported attribute @@toStringTag