Commit 95f61619 authored by Dan Sanders's avatar Dan Sanders Committed by Commit Bot

[webcodecs] Remove Streams from VideoDecoder

Change-Id: If11171fae55dc0b4fa492908884ab48d1805b18c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2092692
Commit-Queue: Dan Sanders <sandersd@chromium.org>
Reviewed-by: default avatarNate Chapin <japhet@chromium.org>
Reviewed-by: default avatarChrome Cunningham <chcunningham@chromium.org>
Cr-Commit-Position: refs/heads/master@{#755992}
parent e9e4edd6
......@@ -723,10 +723,13 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.idl",
"//third_party/blink/renderer/modules/webcodecs/encoded_video_config.idl",
"//third_party/blink/renderer/modules/webcodecs/video_decoder.idl",
"//third_party/blink/renderer/modules/webcodecs/video_decoder_init.idl",
"//third_party/blink/renderer/modules/webcodecs/video_decoder_output_callback.idl",
"//third_party/blink/renderer/modules/webcodecs/video_frame.idl",
"//third_party/blink/renderer/modules/webcodecs/video_track_reader.idl",
"//third_party/blink/renderer/modules/webcodecs/video_track_writer.idl",
"//third_party/blink/renderer/modules/webcodecs/video_track_writer_parameters.idl",
"//third_party/blink/renderer/modules/webcodecs/webcodecs_error_callback.idl",
"//third_party/blink/renderer/modules/webdatabase/database.idl",
"//third_party/blink/renderer/modules/webdatabase/sql_error.idl",
"//third_party/blink/renderer/modules/webdatabase/sql_result_set.idl",
......
......@@ -160,8 +160,12 @@ generated_modules_callback_function_files = [
"$bindings_modules_v8_output_dir/v8_storage_quota_callback.h",
"$bindings_modules_v8_output_dir/v8_storage_usage_callback.cc",
"$bindings_modules_v8_output_dir/v8_storage_usage_callback.h",
"$bindings_modules_v8_output_dir/v8_video_decoder_output_callback.cc",
"$bindings_modules_v8_output_dir/v8_video_decoder_output_callback.h",
"$bindings_modules_v8_output_dir/v8_video_frame_request_callback.cc",
"$bindings_modules_v8_output_dir/v8_video_frame_request_callback.h",
"$bindings_modules_v8_output_dir/v8_web_codecs_error_callback.cc",
"$bindings_modules_v8_output_dir/v8_web_codecs_error_callback.h",
"$bindings_modules_v8_output_dir/v8_xr_frame_request_callback.cc",
"$bindings_modules_v8_output_dir/v8_xr_frame_request_callback.h",
]
......
......@@ -10,8 +10,14 @@ modules_idl_files = [
"video_track_writer.idl",
]
modules_callback_function_idl_files = [
"video_decoder_output_callback.idl",
"webcodecs_error_callback.idl",
]
modules_dictionary_idl_files = [
"encoded_video_config.idl",
"video_decoder_init.idl",
"video_track_writer_parameters.idl",
]
......
......@@ -11,11 +11,6 @@
#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/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/streams/readable_stream.h"
#include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h"
#include "third_party/blink/renderer/core/streams/underlying_sink_base.h"
#include "third_party/blink/renderer/core/streams/underlying_source_base.h"
#include "third_party/blink/renderer/core/streams/writable_stream.h"
#include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h"
#include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h"
......@@ -27,214 +22,107 @@
namespace blink {
namespace {
// TODO(sandersd): Tune this number.
// Desired number of chunks queued in |underlying_sink_|.
constexpr size_t kDesiredInputQueueSize = 4;
// TODO(sandersd): Tune this number.
// Desired number of pending decodes + chunks queued in |underlying_source_|.
constexpr size_t kDesiredInternalQueueSize = 4;
std::unique_ptr<media::VideoDecoder> CreateVideoDecoder(
ScriptState* script_state) {
return nullptr;
}
} // namespace
class VideoDecoder::UnderlyingSink final : public UnderlyingSinkBase {
public:
explicit UnderlyingSink(VideoDecoder* parent) : parent_(parent) {}
// UnderlyingSinkBase overrides.
ScriptPromise start(ScriptState*,
WritableStreamDefaultController*,
ExceptionState& exception_state) override {
return parent_->Start(exception_state);
}
ScriptPromise write(ScriptState*,
ScriptValue chunk,
WritableStreamDefaultController*,
ExceptionState& exception_state) override {
return parent_->Write(chunk, exception_state);
}
ScriptPromise close(ScriptState*, ExceptionState& exception_state) override {
return parent_->Close(exception_state);
}
ScriptPromise abort(ScriptState*,
ScriptValue reason,
ExceptionState& exception_state) override {
return parent_->Abort(exception_state);
}
void Trace(Visitor* visitor) override {
visitor->Trace(parent_);
UnderlyingSinkBase::Trace(visitor);
}
private:
friend class VideoDecoder;
Member<VideoDecoder> parent_;
};
class VideoDecoder::UnderlyingSource final : public UnderlyingSourceBase {
public:
UnderlyingSource(ScriptState* script_state, VideoDecoder* parent)
: UnderlyingSourceBase(script_state), parent_(parent) {}
// UnderlyingSourceBase overrides.
ScriptPromise pull(ScriptState*) override { return parent_->Pull(); }
ScriptPromise Cancel(ScriptState*, ScriptValue reason) override {
return parent_->Cancel();
}
void Trace(Visitor* visitor) override {
visitor->Trace(parent_);
UnderlyingSourceBase::Trace(visitor);
}
private:
friend class VideoDecoder;
Member<VideoDecoder> parent_;
};
// static
VideoDecoder* VideoDecoder::Create(ScriptState* script_state) {
return MakeGarbageCollected<VideoDecoder>(script_state);
VideoDecoder* VideoDecoder::Create(ScriptState* script_state,
const VideoDecoderInit* init,
ExceptionState& exception_state) {
return MakeGarbageCollected<VideoDecoder>(script_state, init,
exception_state);
}
VideoDecoder::VideoDecoder(ScriptState* script_state)
VideoDecoder::VideoDecoder(ScriptState* script_state,
const VideoDecoderInit* init,
ExceptionState& exception_state)
: script_state_(script_state) {
DVLOG(1) << __func__;
// TODO(sandersd): Extract callbacks from |init|.
}
VideoDecoder::~VideoDecoder() {
DVLOG(1) << __func__;
// TODO(sandersd): Assert no outstanding promises. We should have been kept
// alive.
// TODO(sandersd): GC tests.
}
ScriptPromise VideoDecoder::CreateWritePromise() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!write_resolver_);
ScriptPromiseResolver* write_resolver =
MakeGarbageCollected<ScriptPromiseResolver>(script_state_);
write_resolver_ = write_resolver;
// Note: may release |write_resolver_|.
MaybeAcceptWrite();
return write_resolver->Promise();
int32_t VideoDecoder::decodeQueueSize() {
return requested_decodes_;
}
void VideoDecoder::MaybeAcceptWrite() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!has_error_);
if (write_resolver_ && decoder_ && underlying_source_ &&
pending_decodes_ < decoder_->GetMaxDecodeRequests() &&
pending_decodes_ < underlying_source_->Controller()->DesiredSize()) {
write_resolver_.Release()->Resolve();
}
}
void VideoDecoder::HandleError() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
has_error_ = true;
// TODO(sandersd): Reject other outstanding promises, error the output stream,
// etc.
int32_t VideoDecoder::decodeProcessingCount() {
return pending_decodes_.size();
}
ScriptPromise VideoDecoder::configure(const EncodedVideoConfig* config,
ExceptionState& exception_state) {
ExceptionState&) {
DVLOG(1) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Request* request = MakeGarbageCollected<Request>();
request->type = Request::Type::kConfigure;
request->config = config;
return EnqueueRequest(request);
}
if (configure_resolver_ || decoder_) {
exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
"Reconfiguration is not implemented.");
return ScriptPromise();
}
ScriptPromise VideoDecoder::decode(const EncodedVideoChunk* chunk,
ExceptionState&) {
DVLOG(3) << __func__;
requested_decodes_++;
Request* request = MakeGarbageCollected<Request>();
request->type = Request::Type::kDecode;
request->chunk = chunk;
return EnqueueRequest(request);
}
decoder_ = CreateVideoDecoder(script_state_);
if (!decoder_) {
exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
"No codec available.");
return ScriptPromise();
}
ScriptPromise VideoDecoder::flush(ExceptionState&) {
DVLOG(3) << __func__;
Request* request = MakeGarbageCollected<Request>();
request->type = Request::Type::kFlush;
return EnqueueRequest(request);
}
// VideoDecoder::Initialize() may call OnInitializeDone() reentrantly, in
// which case |configure_resolver_| will be nullptr.
DCHECK(!configure_resolver_);
ScriptPromiseResolver* configure_resolver =
ScriptPromise VideoDecoder::reset(ExceptionState&) {
DVLOG(3) << __func__;
requested_resets_++;
Request* request = MakeGarbageCollected<Request>();
request->type = Request::Type::kReset;
return EnqueueRequest(request);
}
ScriptPromise VideoDecoder::EnqueueRequest(Request* request) {
ScriptPromiseResolver* resolver =
MakeGarbageCollected<ScriptPromiseResolver>(script_state_);
configure_resolver_ = configure_resolver;
request->resolver = resolver;
requests_.push_back(request);
// TODO(sandersd): Convert |config| to VideoDecoderConfig.
decoder_->Initialize(
media::VideoDecoderConfig(
media::kCodecH264, media::H264PROFILE_BASELINE,
media::VideoDecoderConfig::AlphaMode::kIsOpaque,
media::VideoColorSpace::REC709(), media::kNoTransformation,
gfx::Size(320, 180), gfx::Rect(0, 0, 320, 180), gfx::Size(320, 180),
media::EmptyExtraData(), media::EncryptionScheme::kUnencrypted),
false, nullptr,
WTF::Bind(&VideoDecoder::OnInitializeDone, WrapWeakPersistent(this)),
WTF::BindRepeating(&VideoDecoder::OnOutput, WrapWeakPersistent(this)),
base::RepeatingCallback<void(media::WaitingReason)>());
// If there were no requests before, trigger request processing.
if (requests_.size() == 1)
ProcessRequests();
return configure_resolver->Promise();
return resolver->Promise();
}
ReadableStream* VideoDecoder::readable() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return readable_;
}
void VideoDecoder::ProcessRequests() {}
WritableStream* VideoDecoder::writable() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return writable_;
}
void VideoDecoder::HandleError() {}
void VideoDecoder::OnInitializeDone(media::Status status) {
DVLOG(3) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Request* request = requests_.TakeFirst();
DCHECK_EQ(request->type, Request::Type::kConfigure);
if (!status.is_ok()) {
// TODO(tmathmeyer) this drops the media error - should we consider logging
// it or converting it to the DOMException type somehow?
configure_resolver_.Release()->Reject(MakeGarbageCollected<DOMException>(
request->resolver.Release()->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotSupportedError, "Codec initialization failed."));
HandleError();
return;
}
underlying_sink_ = MakeGarbageCollected<UnderlyingSink>(this);
writable_ = WritableStream::CreateWithCountQueueingStrategy(
script_state_, underlying_sink_, kDesiredInputQueueSize);
underlying_source_ =
MakeGarbageCollected<UnderlyingSource>(script_state_, this);
readable_ = ReadableStream::CreateWithCountQueueingStrategy(
script_state_, underlying_source_, kDesiredInternalQueueSize);
configure_resolver_.Release()->Resolve();
MaybeAcceptWrite();
request->resolver.Release()->Resolve();
ProcessRequests();
}
void VideoDecoder::OnDecodeDone(media::DecodeStatus status) {
void VideoDecoder::OnDecodeDone(uint32_t id, media::DecodeStatus status) {
DVLOG(3) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(pending_decodes_.Contains(id));
if (status != media::DecodeStatus::OK) {
// TODO(sandersd): Handle ABORTED during Reset.
......@@ -242,112 +130,29 @@ void VideoDecoder::OnDecodeDone(media::DecodeStatus status) {
return;
}
pending_decodes_--;
MaybeAcceptWrite();
auto it = pending_decodes_.find(id);
it->value->resolver.Release()->Resolve();
pending_decodes_.erase(it);
ProcessRequests();
}
void VideoDecoder::OnOutput(scoped_refptr<media::VideoFrame> frame) {
DVLOG(3) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
underlying_source_->Controller()->Enqueue(ScriptValue::From(
script_state_, MakeGarbageCollected<VideoFrame>(frame)));
}
ScriptPromise VideoDecoder::Start(ExceptionState&) {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return CreateWritePromise();
}
ScriptPromise VideoDecoder::Write(ScriptValue chunk,
ExceptionState& exception_state) {
DVLOG(3) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Convert |chunk| to EncodedVideoChunk.
EncodedVideoChunk* encoded_video_chunk =
V8EncodedVideoChunk::ToImplWithTypeCheck(script_state_->GetIsolate(),
chunk.V8Value());
if (!encoded_video_chunk) {
// TODO(sandersd): Set |has_error| and reject promises.
exception_state.ThrowTypeError("Chunk is not an EncodedVideoChunk.");
return ScriptPromise();
}
// Convert |encoded_video_chunk| to DecoderBuffer.
scoped_refptr<media::DecoderBuffer> decoder_buffer =
media::DecoderBuffer::CopyFrom(
static_cast<uint8_t*>(encoded_video_chunk->data()->Data()),
encoded_video_chunk->data()->ByteLengthAsSizeT());
decoder_buffer->set_timestamp(
base::TimeDelta::FromMicroseconds(encoded_video_chunk->timestamp()));
// TODO(sandersd): Should a null duration be converted to kNoTimestamp?
bool is_null = false;
decoder_buffer->set_duration(base::TimeDelta::FromMicroseconds(
encoded_video_chunk->duration(&is_null)));
decoder_buffer->set_is_key_frame(encoded_video_chunk->type() == "key");
// TODO(sandersd): Add reentrancy checker; OnDecodeDone() could disturb
// |pending_decodes_|.
pending_decodes_++;
decoder_->Decode(
std::move(decoder_buffer),
WTF::Bind(&VideoDecoder::OnDecodeDone, WrapWeakPersistent(this)));
return CreateWritePromise();
}
ScriptPromise VideoDecoder::Close(ExceptionState& exception_state) {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(sandersd): This probably should be an implicit flush.
exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
"Not implemented yet.");
return ScriptPromise();
}
ScriptPromise VideoDecoder::Abort(ExceptionState& exception_state) {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(sandersd): Should this result in a reset?
exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
"Not implemented yet.");
return ScriptPromise();
}
ScriptPromise VideoDecoder::Pull() {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(sandersd): Only potentially possible if |underlying_source_| was
// previously full.
MaybeAcceptWrite();
// TODO(sandersd): No implementation holds a pull promise. Should we?
return ScriptPromise::CastUndefined(script_state_);
}
ScriptPromise VideoDecoder::Cancel() {
DVLOG(2) << __func__;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(sandersd): Close or abort the source.
return ScriptPromise::RejectWithDOMException(
script_state_,
MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotSupportedError,
"Not implemented yet."));
// TODO(sandersd): Call output callback.
// MakeGarbageCollected<VideoFrame>(frame)
}
void VideoDecoder::Trace(Visitor* visitor) {
visitor->Trace(script_state_);
visitor->Trace(underlying_sink_);
visitor->Trace(writable_);
visitor->Trace(underlying_source_);
visitor->Trace(readable_);
visitor->Trace(configure_resolver_);
visitor->Trace(write_resolver_);
visitor->Trace(requests_);
visitor->Trace(pending_decodes_);
ScriptWrappable::Trace(visitor);
}
void VideoDecoder::Request::Trace(Visitor* visitor) {
visitor->Trace(config);
visitor->Trace(chunk);
visitor->Trace(resolver);
}
} // namespace blink
......@@ -5,87 +5,84 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_VIDEO_DECODER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_VIDEO_DECODER_H_
#include <stdint.h>
#include <memory>
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "media/base/status.h"
#include "media/base/video_decoder.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/modules/modules_export.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/heap.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/heap/member.h"
namespace blink {
class EncodedVideoChunk;
class EncodedVideoConfig;
class ReadableStream;
class WritableStream;
class ExceptionState;
class ScriptState;
class VideoDecoderInit;
class MODULES_EXPORT VideoDecoder final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
static VideoDecoder* Create(ScriptState*);
static VideoDecoder* Create(ScriptState*,
const VideoDecoderInit*,
ExceptionState&);
VideoDecoder(ScriptState*);
VideoDecoder(ScriptState*, const VideoDecoderInit*, ExceptionState&);
~VideoDecoder() override;
// video_decoder.idl implementation.
ScriptPromise configure(const EncodedVideoConfig* config,
ExceptionState& exception_state);
ReadableStream* readable() const;
WritableStream* writable() const;
int32_t decodeQueueSize();
int32_t decodeProcessingCount();
ScriptPromise configure(const EncodedVideoConfig*, ExceptionState&);
ScriptPromise decode(const EncodedVideoChunk*, ExceptionState&);
ScriptPromise flush(ExceptionState&);
ScriptPromise reset(ExceptionState&);
// GarbageCollected override.
void Trace(Visitor*) override;
private:
SEQUENCE_CHECKER(sequence_checker_);
class UnderlyingSink;
class UnderlyingSource;
// Creates a new |write_resolver_| and returns a promise from it.
ScriptPromise CreateWritePromise();
// Resolves |write_resolver_| if the current state can accept a write.
void MaybeAcceptWrite();
// Rejects promises and shuts down streams.
struct Request : public GarbageCollected<Request> {
enum class Type {
kConfigure,
kDecode,
kFlush,
kReset,
};
void Trace(Visitor*);
Type type;
Member<const EncodedVideoConfig> config;
Member<const EncodedVideoChunk> chunk;
Member<ScriptPromiseResolver> resolver;
};
ScriptPromise EnqueueRequest(Request* request);
void ProcessRequests();
void HandleError();
// Called by |decoder_|.
void OnInitializeDone(media::Status status);
void OnDecodeDone(media::DecodeStatus);
void OnDecodeDone(uint32_t id, media::DecodeStatus);
void OnOutput(scoped_refptr<media::VideoFrame>);
// Called by UnderlyingSink.
ScriptPromise Start(ExceptionState&);
ScriptPromise Write(ScriptValue chunk, ExceptionState&);
ScriptPromise Close(ExceptionState&);
ScriptPromise Abort(ExceptionState&);
// Called by UnderlyingSource.
ScriptPromise Pull();
ScriptPromise Cancel();
Member<ScriptState> script_state_;
Member<UnderlyingSink> underlying_sink_;
Member<WritableStream> writable_;
Member<UnderlyingSource> underlying_source_;
Member<ReadableStream> readable_;
// Signals completion of configure().
Member<ScriptPromiseResolver> configure_resolver_;
// Signals ability to accept an input chunk.
Member<ScriptPromiseResolver> write_resolver_;
HeapDeque<Member<Request>> requests_;
int32_t requested_decodes_ = 0;
int32_t requested_resets_ = 0;
std::unique_ptr<media::VideoDecoder> decoder_;
bool has_error_ = false;
int pending_decodes_ = 0;
HeapHashMap<uint32_t, Member<Request>> pending_decodes_;
};
} // namespace blink
......
......@@ -4,23 +4,84 @@
// https://github.com/WICG/web-codecs
// 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.
[RuntimeEnabled=WebCodecs]
interface VideoDecoder {
// TODO(sandersd): Configure properties of streams (type and high water mark).
[CallWith=ScriptState] constructor();
// |init| includes an |output| callback for emitting VideoFrames and an
// |error| callback for emitting decode errors.
//
// When in an error state, methods other than reset() will fail.
//
// TODO(sandersd): Consider adding a state or last error attribute.
// TODO(sandersd): Consider aborting pending decodes on error, rather than
// waiting for reset().
[CallWith=ScriptState, RaisesException] constructor(VideoDecoderInit init);
// The number of queued decode requests. This does not include requests that
// have been taken for processing.
//
// Applications can minimize underflow by enqueueing decode requests until
// |decodeQueueSize| is greater than a constant.
readonly attribute long decodeQueueSize;
// The number of decode requests currently being processed.
//
// Applications can minimize resource consumption and decode latency by
// enqueueing decode requests only when |decodeQueueSize| and
// |decodeProcessingCount| are small.
//
// TODO(sandersd): Consider counting queued decode requests as well. This
// could be simpler for apps.
readonly attribute long decodeProcessingCount;
// Configure or reconfigure the decoder.
// Enqueue a request to set or change the stream configuration.
//
// The next enqueued decode request must be for a keyframe.
//
// |writable| and |readable| will be errored and set to null.
// Resolved after emitting output for all earlier decode requests.
//
// If configuration is successful, |writable| and |readable| will be set to
// new streams.
// TODO(sandersd): Test that resolution (a microtask) interleaves between
// outputs callback calls in all cases.
// TODO(sandersd): Move the keyframe rule into the bytestream registry.
[RaisesException] Promise<void> configure(EncodedVideoConfig config);
// Closing |writable| will flush the decoder, then close |readable|.
// Aborting |writable| will error |readable|.
readonly attribute WritableStream? writable; // of EncodedVideoChunk
// Enqueue a request to decode an input chunk.
//
// You must call configure() before calling enqueue() for the first time.
//
// Resolved after decoding of the input chunk has started (that is, after
// decreasing |decodeQueueSize|).
//
// TODO(sandersd): Change to a dictionary type.
// TODO(sandersd): Should we guarantee that resolution occurs in order?
// TODO(sandersd): Add status to result.
// TODO(sandersd): Buffer return.
[RaisesException] Promise<void> decode(EncodedVideoChunk chunk);
// Enqueue a request to finish decoding queued input chunks.
//
// The next enqueued input chunk must be a keyframe.
//
// Resolved after emitting output for all earlier decode requests.
//
// TODO(sandersd): Consider relaxing the keyframe requirement.
[RaisesException] Promise<void> flush();
// Canceling |readable| will error |writable|.
readonly attribute ReadableStream? readable; // of VideoFrame
// Discard all pending work.
//
// Output for earlier decode requests will not be emitted, even if processing
// has already started.
//
// The next enqueued input chunk must be a keyframe.
//
// Resolved after all earlier enqueue() promises have been resolved.
//
// TODO(sandersd): Require configure() after reset()?
[RaisesException] Promise<void> reset();
};
// 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.
// https://github.com/WICG/web-codecs
dictionary VideoDecoderInit {
VideoDecoderOutputCallback output;
WebCodecsErrorCallback error;
};
// Copyright 2020 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.
// https://github.com/WICG/web-codecs
[RuntimeEnabled=WebCodecs]
callback VideoDecoderOutputCallback = void(VideoFrame output);
// Copyright 2020 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.
// https://github.com/WICG/web-codecs
[RuntimeEnabled=WebCodecs]
callback WebCodecsErrorCallback = void(DOMException error);
......@@ -8718,10 +8718,13 @@ interface ValidityState
method constructor
interface VideoDecoder
attribute @@toStringTag
getter readable
getter writable
getter decodeProcessingCount
getter decodeQueueSize
method configure
method constructor
method decode
method flush
method reset
interface VideoFrame
attribute @@toStringTag
getter coded_height
......
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