diff --git a/index.src.html b/index.src.html
index 1d4de8c0..6957d403 100644
--- a/index.src.html
+++ b/index.src.html
@@ -200,6 +200,17 @@
"matrix" → {{VideoMatrixCoefficients/bt709}},
"fullRange" → `false`]».
+: Codec Saturation
+:: The state of an underlying codec implementation where the number of active
+ decoding or encoding requests has reached an implementation specific
+ maximum such that it is temporarily unable to accept more work. The maximum
+ may be any value greater than 1, including infinity (no maximum). While
+ saturated, additional calls to `decode()` or `encode()` will be buffered
+ in the [=control message queue=], and will increment the respective
+ `decodeQueuSize` and `encodeQueueSize` attributes. The codec implementation
+ will become unsaturated after making sufficient progress on the current
+ workload.
+
Codec Processing Model {#codec-processing-model-section}
===================================================================
@@ -213,57 +224,72 @@
codec tasks can be scheduled while previous tasks are still pending. For
example, web authors can call `decode()` without waiting for a previous
`decode()` to complete. This is achieved by offloading underlying codec tasks
- to a separate thread for parallel execution.
+ to a separate [=parallel queue=] for parallel execution.
This section describes threading behaviors as they are visible from the
- perspective of web authors. Implementers can choose to use more or less
- threads as long as the exernally visible behaviors of blocking and sequencing
- are maintained as follows.
+ perspective of web authors. Implementers can choose to use more threads, as
+ long as the exernally visible behaviors of blocking and sequencing are
+ maintained as follows.
-Control Thread and Codec Thread {#control-thread-and-codec-thread}
-------------------------------------------------------------------
-
-All steps in this specification will run on either a [=control thread=] or
-a [=codec thread=].
-
-The control thread is the thread from which authors will construct
-a [=codec=] and invoke its methods. Invoking a codec's methods will typically
-result in the creation of [=control messages=] which are later executed on the
-[=codec thread=]. Each [=webappapis/global object=] has a separate control
-thread.
-
-The codec thread is the thread from which a [=codec=] will
-[=dequeue=] [=control messages=] and execute their steps. Each [=codec=]
-instance has a separate codec thread. The lifetime of a codec thread matches
-that of its associated [=codec=] instance.
-
-The [=control thread=] uses a traditional event loop, as described in
-[[!HTML]].
-
-The [=codec thread=] uses a specialized [=codec processing loop=].
+Control Messages {#control-messages}
+------------------------------------
-Communication from the [=control thread=] to the [=codec thread=] is done using
-[=control message=] passing. Communication in the other direction is done using
-regular event loop tasks.
+A control message defines a sequence of steps corresponding to a
+method invocation on a [=codec=] instance (e.g. `encode()`).
-Each [=codec=] instance has a single control message queue that is
-a [=queue=] of control messages.
+A control message queue is a a [=queue=] of
+[=control messages=]. Each [=codec=] instance has a control message queue
+stored in an internal slot named
+[[control message queue]].
Queuing a control
-message means [=enqueuing=] the message to a [=codec=]’s [=control
-message queue=]. Invoking codec methods will often queue a control message
+message means [=enqueuing=] the message to a [=codec=]’s [=[[control
+message queue]]=]. Invoking codec methods will generally queue a control message
to schedule work.
Running a control
message means performing a sequence of steps specified by the method
that enqueued the message.
-The codec processing loop MUST run these steps:
-1. While true:
- 1. If the [=control message queue=] is empty, [=continue=].
- 2. Dequeue |front message| from the [=control message queue=].
- 3. Run [=control message steps=] described by |front message|.
+The steps of a given control message can block processing later messages in the
+control message queue. Each [=codec=] instance has a boolean internal slot named
+[[message queue blocked]] that is set to `true` when this occurs. A
+blocking message will conclude by setting [=[[message queue blocked]]=] to
+`false` and rerunning the [=Process the control message queue=] steps.
+
+All control messages will return either `"processed"` or `"not processed"`.
+Returning `"processed"` indicates the message steps are being (or have been)
+executed and the message may be removed from the [=control message queue=].
+`"not processed"` indicates the message must could not be processed at this time
+and should remain in the [=control message queue=] to be retried later.
+
+To Process the control message queue, run these steps:
+1. While [=[[message queue blocked]]=] is `false` and
+ [=[[control message queue]]=] is not empty:
+ 1. Let |front message| be the first message in
+ [=[[control message queue]]=].
+ 2. Let |outcome| be the result of running the [=control message steps=]
+ described by |front message|.
+ 3. If |outcome| equals `"not processed"`, break.
+ 4. Otherwise, dequeue |front message| from the
+ [=[[control message queue]]=].
+
+Codec Work Parallel Queue {#codec-work-parallel-queue}
+------------------------------------------------------
+
+Each [=codec=] instance has an internal slot named
+[[codec work queue]] that is a [=parallel queue=].
+
+Each [=codec=] instance has an internal slot named
+[[codec implementation]] that refers to the underlying platform
+encoder or decoder. Except for assignment, any steps that reference
+[=[[codec implementation]]=] will be enqueued to the [=[[codec work queue]]=].
+
+Each [=codec=] instance has a unique codec task source. Tasks
+[=queue a task|queued=] from the [=[[codec work queue]]=] to the [=/event loop=]
+will use the [=codec task source=].
+
AudioDecoder Interface {#audiodecoder-interface}
================================================
@@ -295,8 +321,21 @@
Internal Slots {#audiodecoder-internal-slots}
---------------------------------------------
+: [[control message queue]]
+:: A [=queue=] of [=control messages=] to be performed upon this [=codec=]
+ instance. See [=[[control message queue]]=].
+: [[message queue blocked]]
+:: A boolean indicating when processing the
+ {{AudioDecoder/[[control message queue]]}} is blocked by a pending
+ [=control message=]. See [=[[message queue blocked]]=].
: [[codec implementation]]
:: Underlying decoder implementation provided by the User Agent.
+: [[codec work queue]]
+:: A [=parallel queue=] used for running parallel steps that reference the
+ {{AudioDecoder/[[codec implementation]]}}. See [=[[codec work queue]]=].
+: [[codec saturated]]
+:: A boolean indicating when the [[codec implementation]] is unable to accept
+ additional decoding work.
: [[output callback]]
:: Callback given at construction for decoded outputs.
: [[error callback]]
@@ -319,11 +358,19 @@
AudioDecoder(init)
1. Let d be a new {{AudioDecoder}} object.
-2. Assign init.output to {{AudioDecoder/[[output callback]]}}.
-3. Assign init.error to {{AudioDecoder/[[error callback]]}}.
-4. Assign `true` to {{AudioDecoder/[[key chunk required]]}}.
-5. Assign `"unconfigured"` to {{AudioDecoder/[[state]]}}
-6. Return d.
+2. Assign a new [=queue=] to {{AudioDecoder/[[control message queue]]}}.
+3. Assign `false` to {{AudioDecoder/[[message queue blocked]]}}.
+4. Assign `null` to {{AudioDecoder/[[codec implementation]]}}.
+5. Assign the result of starting a new [=parallel queue=] to
+ {{AudioDecoder/[[codec work queue]]}}.
+6. Assign `false` to {{AudioDecoder/[[codec saturated]]}}.
+7. Assign init.output to {{AudioDecoder/[[output callback]]}}.
+8. Assign init.error to {{AudioDecoder/[[error callback]]}}.
+9. Assign `true` to {{AudioDecoder/[[key chunk required]]}}.
+10. Assign `"unconfigured"` to {{AudioDecoder/[[state]]}}
+11. Assign `0` to {{AudioDecoder/[[decodeQueueSize]]}}.
+12. Assign a new [=list=] to {{AudioDecoder/[[pending flush promises]]}}.
+13. Return d.
Attributes {#audiodecoder-attributes}
-------------------------------------
@@ -360,6 +407,7 @@
3. Set {{AudioDecoder/[[state]]}} to `"configured"`.
4. Set {{AudioDecoder/[[key chunk required]]}} to `true`.
5. [=Queue a control message=] to configure the decoder with |config|.
+ 6. [=Process the control message queue=].
[=Running a control message=] to configure the decoder means running
these steps:
@@ -369,7 +417,13 @@
{{AudioDecoder/[[codec implementation]]}} with an implementation
supporting |config|.
3. Otherwise, run the Close AudioDecoder algorithm with
- {{NotSupportedError}}.
+ {{NotSupportedError}} and return `"processed"`.
+ 4. Assign `true` to {{AudioDecoder/[[message queue blocked]]}}.
+ 5. Enqueue the following steps to {{AudioDecoder/[[codec work queue]]}}:
+ 1. Configure {{AudioDecoder/[[codec implementation]]}} with |config|.
+ 2. Assign `false` to {{AudioDecoder/[[message queue blocked]]}}.
+ 3. [=Queue a task=] to [=Process the control message queue=].
+ 6. Return `"processed"`.
decode(chunk)
@@ -390,21 +444,31 @@
{{AudioDecoder/[[key chunk required]]}}.
3. Increment {{AudioDecoder/[[decodeQueueSize]]}}.
4. [=Queue a control message=] to decode the |chunk|.
+ 5. [=Process the control message queue=].
[=Running a control message=] to decode the chunk means performing these
steps:
- 1. Attempt to use {{AudioDecoder/[[codec implementation]]}} to decode the
- chunk.
- 2. If decoding results in an error, queue a task on the [=control thread=]
- event loop to run the [=Close AudioDecoder=] algorithm with
- {{EncodingError}}.
- 3. Queue a task on the [=control thread=] event loop to decrement
- {{AudioDecoder/[[decodeQueueSize]]}}.
- 4. Let |decoded outputs| be a [=list=] of decoded audio data outputs emitted
- by {{AudioDecoder/[[codec implementation]]}}.
- 5. If |decoded outputs| is not empty, queue a task on the [=control thread=]
- event loop to run the [=Output AudioData=] algorithm with
- |decoded outputs|.
+ 1. If {{AudioDecoder/[[codec saturated]]}} equals `true`, return `"not
+ processed"`.
+ 2. If decoding chunk will cause the
+ {{AudioDecoder/[[codec implementation]]}} to become [=saturated=],
+ assign `true` to {{AudioDecoder/[[codec saturated]]}}.
+ 3. Decrement {{AudioDecoder/[[decodeQueueSize]]}}.
+ 4. Enqueue the following steps to the {{AudioDecoder/[[codec work queue]]}}:
+ 1. Attempt to use {{AudioDecoder/[[codec implementation]]}} to decode
+ the chunk.
+ 2. If decoding results in an error, [=queue a task=] to run the
+ [=Close AudioDecoder=] algorithm with {{EncodingError}} and return.
+ 3. If {{AudioDecoder/[[codec saturated]]}} equals `true` and
+ {{AudioDecoder/[[codec implementation]]}} is no longer
+ [=saturated=], [=queue a task=] to perform the following steps:
+ 1. Assign `false` to {{AudioDecoder/[[codec saturated]]}}.
+ 2. [=Process the control message queue=].
+ 4. Let |decoded outputs| be a [=list=] of decoded audio data outputs
+ emitted by {{AudioDecoder/[[codec implementation]]}}.
+ 5. If |decoded outputs| is not empty, [=queue a task=] to run the
+ [=Output AudioData=] algorithm with |decoded outputs|.
+ 5. Return `"processed"`.
flush()
@@ -417,22 +481,24 @@
[=a promise rejected with=] {{InvalidStateError}} {{DOMException}}.
2. Set {{AudioDecoder/[[key chunk required]]}} to `true`.
3. Let |promise| be a new Promise.
- 4. [=Queue a control message=] to flush the codec with |promise|.
- 5. Append |promise| to {{AudioDecoder/[[pending flush promises]]}}.
- 6. Return |promise|.
+ 4. Append |promise| to {{AudioDecoder/[[pending flush promises]]}}.
+ 5. [=Queue a control message=] to flush the codec with |promise|.
+ 6. [=Process the control message queue=].
+ 7. Return |promise|.
- [=Running a control message=] to flush the codec means performing these steps
- with |promise|.
- 1. Signal {{AudioDecoder/[[codec implementation]]}} to emit all [=internal
- pending outputs=].
- 2. Let |decoded outputs| be a [=list=] of decoded audio data outputs emitted
- by {{AudioDecoder/[[codec implementation]]}}.
- 3. If |decoded outputs| is not empty, queue a task on the [=control thread=]
- event loop to run the [=Output AudioData=] algorithm with
- |decoded outputs|.
- 4. Queue a task on the [=control thread=] event loop to run these steps:
- 1. Remove |promise| from {{AudioDecoder/[[pending flush promises]]}}.
- 2. Resolve |promise|.
+ [=Running a control message=] to flush the codec means performing these
+ steps with |promise|.
+ 1. Enqueue the following steps to the {{AudioDecoder/[[codec work queue]]}}:
+ 1. Signal {{AudioDecoder/[[codec implementation]]}} to emit all
+ [=internal pending outputs=].
+ 2. Let |decoded outputs| be a [=list=] of decoded audio data outputs
+ emitted by {{AudioDecoder/[[codec implementation]]}}.
+ 3. [=Queue a task=] to perform these steps:
+ 1. If |decoded outputs| is not empty, run the [=Output AudioData=]
+ algorithm with |decoded outputs|.
+ 2. Remove |promise| from
+ {{AudioDecoder/[[pending flush promises]]}}.
+ 3. Resolve |promise|.
reset()
@@ -514,7 +580,8 @@
2. Set {{AudioDecoder/[[state]]}} to `"unconfigured"`.
3. Signal {{AudioDecoder/[[codec implementation]]}} to cease producing
output for the previous configuration.
- 4. Remove all [=control messages=] from the [=control message queue=].
+ 4. Remove all [=control messages=] from the
+ {{AudioDecoder/[[control message queue]]}}.
5. Set {{AudioDecoder/[[decodeQueueSize]]}} to zero.
6. For each |promise| in {{AudioDecoder/[[pending flush promises]]}}:
1. Reject |promise| with |exception|.
@@ -527,8 +594,8 @@
2. Set {{AudioDecoder/[[state]]}} to `"closed"`.
3. Clear {{AudioDecoder/[[codec implementation]]}} and release associated
[=system resources=].
- 4. If |exception| is not an {{AbortError}} {{DOMException}}, queue a task on
- the [=control thread=] event loop to invoke the {{AudioDecoder/[[error callback]]}} with |exception|.
+ 4. If |exception| is not an {{AbortError}} {{DOMException}},
+ [=queue a task=] to invoke the {{AudioDecoder/[[error callback]]}} with |exception|.
@@ -562,8 +629,21 @@
Internal Slots {#videodecoder-internal-slots}
---------------------------------------------
+: [[control message queue]]
+:: A [=queue=] of [=control messages=] to be performed upon this [=codec=]
+ instance. See [=[[control message queue]]=].
+: [[message queue blocked]]
+:: A boolean indicating when processing the
+ {{VideoDecoder/[[control message queue]]}} is blocked by a pending
+ [=control message=]. See [=[[message queue blocked]]=].
: [[codec implementation]]
:: Underlying decoder implementation provided by the User Agent.
+: [[codec work queue]]
+:: A [=parallel queue=] used for running parallel steps that reference the
+ {{VideoDecoder/[[codec implementation]]}}. See [=[[codec work queue]]=].
+: [[codec saturated]]
+:: A boolean indicating when the [[codec implementation]] is unable to accept
+ additional decoding work.
: [[output callback]]
:: Callback given at construction for decoded outputs.
: [[error callback]]
@@ -588,12 +668,21 @@
VideoDecoder(init)
-1. Let d be a new VideoDecoder object.
-2. Assign `init.output` to the {{VideoDecoder/[[output callback]]}} internal slot.
-3. Assign `init.error` to the {{VideoDecoder/[[error callback]]}} internal slot.
-4. Assign `true` to {{VideoDecoder/[[key chunk required]]}}.
-5. Assign `"unconfigured"` to {{VideoDecoder/[[state]]}}.
-5. Return d.
+1. Let d be a new {{VideoDecoder}} object.
+2. Assign a new [=queue=] to {{VideoDecoder/[[control message queue]]}}.
+3. Assign `false` to {{VideoDecoder/[[message queue blocked]]}}.
+4. Assign `null` to {{VideoDecoder/[[codec implementation]]}}.
+5. Assign the result of starting a new [=parallel queue=] to
+ {{VideoDecoder/[[codec work queue]]}}.
+6. Assign `false` to {{VideoDecoder/[[codec saturated]]}}.
+7. Assign init.output to {{VideoDecoder/[[output callback]]}}.
+8. Assign init.error to {{VideoDecoder/[[error callback]]}}.
+9. Assign `null` to {{VideoDecoder/[[active decoder config]]}}.
+10. Assign `true` to {{VideoDecoder/[[key chunk required]]}}.
+11. Assign `"unconfigured"` to {{VideoDecoder/[[state]]}}
+12. Assign `0` to {{VideoDecoder/[[decodeQueueSize]]}}.
+13. Assign a new [=list=] to {{VideoDecoder/[[pending flush promises]]}}.
+14. Return d.
Attributes {#videodecoder-attributes}
-------------------------------------
@@ -621,17 +710,19 @@
chunks as described by |config|.
NOTE: This method will trigger a {{NotSupportedError}} if the User Agent
- does not support |config|. Authors are encouraged to first check support by
- calling {{VideoDecoder/isConfigSupported()}} with |config|. User Agents
+ does not support |config|. Authors are encouraged to first check support
+ by calling {{VideoDecoder/isConfigSupported()}} with |config|. User Agents
don't have to support any particular codec type or configuration.
When invoked, run these steps:
1. If |config| is not a [=valid VideoDecoderConfig=], throw a
{{TypeError}}.
- 2. If {{VideoDecoder/[[state]]}} is `“closed”`, throw an {{InvalidStateError}}.
+ 2. If {{VideoDecoder/[[state]]}} is `“closed”`, throw an
+ {{InvalidStateError}}.
3. Set {{VideoDecoder/[[state]]}} to `"configured"`.
4. Set {{VideoDecoder/[[key chunk required]]}} to `true`.
5. [=Queue a control message=] to configure the decoder with |config|.
+ 6. [=Process the control message queue=].
[=Running a control message=] to configure the decoder means running
these steps:
@@ -641,8 +732,14 @@
{{VideoDecoder/[[codec implementation]]}} with an implementation
supporting |config|.
3. Otherwise, run the Close VideoDecoder algorithm with
- {{NotSupportedError}} and abort these steps.
- 4. Set {{VideoDecoder/[[active decoder config]]}} to `config`.
+ {{NotSupportedError}} and return `"processed"`.
+ 4. Assign `true` to {{VideoDecoder/[[message queue blocked]]}}.
+ 5. Enqueue the following steps to {{VideoDecoder/[[codec work queue]]}}:
+ 1. Configure {{VideoDecoder/[[codec implementation]]}} with |config|.
+ 2. Set {{VideoDecoder/[[active decoder config]]}} to `config`.
+ 3. Assign `false` to {{VideoDecoder/[[message queue blocked]]}}.
+ 4. [=Queue a task=] to [=Process the control message queue=].
+ 6. Return `"processed"`.
decode(chunk)
@@ -674,20 +771,31 @@
{{VideoDecoder/[[key chunk required]]}}.
3. Increment {{VideoDecoder/[[decodeQueueSize]]}}.
4. [=Queue a control message=] to decode the |chunk|.
+ 5. [=Process the control message queue=].
[=Running a control message=] to decode the chunk means performing these steps:
- 1. Attempt to use {{VideoDecoder/[[codec implementation]]}} to decode the
- chunk.
- 2. If decoding results in an error, queue a task on the [=control thread=]
- event loop to run the [=Close VideoDecoder=] algorithm with
- {{EncodingError}}.
- 3. Queue a task on the [=control thread=] event loop to decrement
- {{VideoDecoder/[[decodeQueueSize]]}}
- 4. Let |decoded outputs| be a [=list=] of decoded video data outputs emitted
- by {{VideoDecoder/[[codec implementation]]}} in presentation order.
- 5. If |decoded outputs| is not empty, queue a task on the [=control thread=]
- event loop to run the [=Output VideoFrames=] algorithm with
- |decoded outputs|.
+ 1. If {{VideoDecoder/[[codec saturated]]}} equals `true`, return `"not
+ processed"`.
+ 2. If decoding chunk will cause the
+ {{VideoDecoder/[[codec implementation]]}} to become [=saturated=],
+ assign `true` to {{VideoDecoder/[[codec saturated]]}}.
+ 3. Decrement {{VideoDecoder/[[decodeQueueSize]]}}.
+ 4. Enqueue the following steps to the {{VideoDecoder/[[codec work queue]]}}:
+ 1. Attempt to use {{VideoDecoder/[[codec implementation]]}} to decode
+ the chunk.
+ 2. If decoding results in an error, [=queue a task=] to run the
+ [=Close VideoDecoder=] algorithm with {{EncodingError}} and return.
+ 3. If {{VideoDecoder/[[codec saturated]]}} equals `true` and
+ {{VideoDecoder/[[codec implementation]]}} is no longer
+ [=saturated=], [=queue a task=] to perform the following steps:
+ 1. Assign `false` to {{VideoDecoder/[[codec saturated]]}}.
+ 2. [=Process the control message queue=].
+ 4. Let |decoded outputs| be a [=list=] of decoded video data outputs
+ emitted by {{VideoDecoder/[[codec implementation]]}} in
+ presentation order.
+ 5. If |decoded outputs| is not empty, [=queue a task=] to run the
+ [=Output VideoFrame=] algorithm with |decoded outputs|.
+ 5. Return `"processed"`.
flush()
@@ -700,22 +808,24 @@
[=a promise rejected with=] {{InvalidStateError}} {{DOMException}}.
2. Set {{VideoDecoder/[[key chunk required]]}} to `true`.
3. Let |promise| be a new Promise.
- 4. [=Queue a control message=] to flush the codec with |promise|.
- 5. Append |promise| to {{VideoDecoder/[[pending flush promises]]}}.
- 6. Return |promise|.
+ 4. Append |promise| to {{VideoDecoder/[[pending flush promises]]}}.
+ 5. [=Queue a control message=] to flush the codec with |promise|.
+ 6. [=Process the control message queue=].
+ 7. Return |promise|.
- [=Running a control message=] to flush the codec means performing these steps
- with |promise|.
- 1. Signal {{VideoDecoder/[[codec implementation]]}} to emit all [=internal
- pending outputs=].
- 2. Let |decoded outputs| be a [=list=] of decoded video data outputs emitted
- by {{VideoDecoder/[[codec implementation]]}}.
- 3. If |decoded outputs| is not empty, queue a task on the [=control thread=]
- event loop to run the [=Output VideoFrames=] algorithm with
- |decoded outputs|.
- 4. Queue a task on the [=control thread=] event loop to run these steps:
- 1. Remove |promise| from {{VideoDecoder/[[pending flush promises]]}}.
- 2. Resolve |promise|.
+ [=Running a control message=] to flush the codec means performing these
+ steps with |promise|.
+ 1. Enqueue the following steps to the {{VideoDecoder/[[codec work queue]]}}:
+ 1. Signal {{VideoDecoder/[[codec implementation]]}} to emit all
+ [=internal pending outputs=].
+ 2. Let |decoded outputs| be a [=list=] of decoded video data outputs
+ emitted by {{VideoDecoder/[[codec implementation]]}}.
+ 3. [=Queue a task=] to perform these steps:
+ 1. If |decoded outputs| is not empty, run the [=Output VideoFrame=]
+ algorithm with |decoded outputs|.
+ 2. Remove |promise| from
+ {{VideoDecoder/[[pending flush promises]]}}.
+ 3. Resolve |promise|.
reset()
@@ -807,7 +917,8 @@
2. Set {{VideoDecoder/state}} to `"unconfigured"`.
3. Signal {{VideoDecoder/[[codec implementation]]}} to cease producing
output for the previous configuration.
- 4. Remove all [=control messages=] from the [=control message queue=].
+ 4. Remove all [=control messages=] from the
+ {{VideoDecoder/[[control message queue]]}}.
5. Set {{VideoDecoder/[[decodeQueueSize]]}} to zero.
6. For each |promise| in {{VideoDecoder/[[pending flush promises]]}}:
1. Reject |promise| with |exception|.
@@ -820,9 +931,8 @@
2. Set {{VideoDecoder/state}} to `"closed"`.
3. Clear {{VideoDecoder/[[codec implementation]]}} and release associated
[=system resources=].
- 4. If |exception| is not an {{AbortError}} {{DOMException}}, queue a task on
- the [=control thread=] event loop to invoke the
- {{VideoDecoder/[[error callback]]}} with |exception|.
+ 4. If |exception| is not an {{AbortError}} {{DOMException}},
+ [=queue a task=] to invoke the {{VideoDecoder/[[error callback]]}} with |exception|.
@@ -859,47 +969,58 @@
Internal Slots {#audioencoder-internal-slots}
---------------------------------------------
-
-- [[codec implementation]]
-- Underlying encoder implementation provided by the User Agent.
-- [[output callback]]
-- Callback given at construction for encoded outputs.
-- [[error callback]]
-- Callback given at construction for encode errors.
-- [[active encoder config]]
-- The {{AudioEncoderConfig}} that is actively applied.
-- [[active output config]]
--
- The {{AudioDecoderConfig}} that describes how to decode the most recently
- emitted {{EncodedAudioChunk}}.
-
-- \[[state]]
--
- The current {{CodecState}} of this {{AudioEncoder}}.
-
-- \[[encodeQueueSize]]
--
- The number of pending encode requests. This number will decrease as the
- underlying codec is ready to accept new input.
-
-- [[pending flush promises]]
--
- A list of unresolved promises returned by calls to {{AudioEncoder/flush()}}.
-
-
+: [[control message queue]]
+:: A [=queue=] of [=control messages=] to be performed upon this [=codec=]
+ instance. See [=[[control message queue]]=].
+: [[message queue blocked]]
+:: A boolean indicating when processing the
+ {{AudioEncoder/[[control message queue]]}} is blocked by a pending
+ [=control message=]. See [=[[message queue blocked]]=].
+: [[codec implementation]]
+:: Underlying encoder implementation provided by the User Agent.
+: [[codec work queue]]
+:: A [=parallel queue=] used for running parallel steps that reference the
+ {{AudioEncoder/[[codec implementation]]}}. See [=[[codec work queue]]=].
+: [[codec saturated]]
+:: A boolean indicating when the [[codec implementation]] is unable to accept
+ additional encoding work.
+: [[output callback]]
+:: Callback given at construction for encoded outputs.
+: [[error callback]]
+:: Callback given at construction for encode errors.
+: [[active encoder config]]
+:: The {{AudioEncoderConfig}} that is actively applied.
+: [[active output config]]
+:: The {{AudioDecoderConfig}} that describes how to decode the most recently
+ emitted {{EncodedAudioChunk}}.
+: \[[state]]
+:: The current {{CodecState}} of this {{AudioEncoder}}.
+: \[[encodeQueueSize]]
+:: The number of pending encode requests. This number will decrease as the
+ underlying codec is ready to accept new input.
+: [[pending flush promises]]
+:: A list of unresolved promises returned by calls to {{AudioEncoder/flush()}}.
Constructors {#audioencoder-constructors}
-----------------------------------------
AudioEncoder(init)
-1. Let e be a new AudioEncoder object.
-2. Assign `init.output` to the {{AudioEncoder/[[output callback]]}} internal slot.
-3. Assign `init.error` to the {{AudioEncoder/[[error callback]]}} internal slot.
-4. Assign `"unconfigured"` to {{AudioEncoder/[[state]]}}.
-5. Assign `null` to {{AudioEncoder/[[active encoder config]]}}.
-6. Assign `null` to {{AudioEncoder/[[active output config]]}}.
-7. Return e.
+1. Let e be a new {{AudioEncoder}} object.
+2. Assign a new [=queue=] to {{AudioEncoder/[[control message queue]]}}.
+3. Assign `false` to {{AudioEncoder/[[message queue blocked]]}}.
+4. Assign `null` to {{AudioEncoder/[[codec implementation]]}}.
+5. Assign the result of starting a new [=parallel queue=] to
+ {{AudioEncoder/[[codec work queue]]}}.
+6. Assign `false` to {{AudioEncoder/[[codec saturated]]}}.
+7. Assign init.output to {{AudioEncoder/[[output callback]]}}.
+8. Assign init.error to {{AudioEncoder/[[error callback]]}}.
+9. Assign `null` to {{AudioEncoder/[[active encoder config]]}}.
+10. Assign `null` to {{AudioEncoder/[[active output config]]}}.
+11. Assign `"unconfigured"` to {{AudioEncoder/[[state]]}}
+12. Assign `0` to {{AudioEncoder/[[encodeQueueSize]]}}.
+13. Assign a new [=list=] to {{AudioEncoder/[[pending flush promises]]}}.
+14. Return e.
Attributes {#audioencoder-attributes}
-------------------------------------
@@ -932,20 +1053,28 @@
When invoked, run these steps:
1. If |config| is not a [=valid AudioEncoderConfig=], throw a
{{TypeError}}.
- 2. If {{AudioEncoder/[[state]]}} is `"closed"`, throw an {{InvalidStateError}}.
+ 2. If {{AudioEncoder/[[state]]}} is `"closed"`, throw an
+ {{InvalidStateError}}.
3. Set {{AudioEncoder/[[state]]}} to `"configured"`.
4. [=Queue a control message=] to configure the encoder using |config|.
+ 5. [=Process the control message queue=].
- [=Running a control message=] to configure the encoder means performing these
- steps:
+ [=Running a control message=] to configure the encoder means performing
+ these steps:
1. Let |supported| be the result of running the Check Configuration
Support algorithm with |config|.
2. If |supported| is `true`, assign
{{AudioEncoder/[[codec implementation]]}} with an implementation
supporting |config|.
3. Otherwise, run the Close AudioEncoder algorithm with
- {{NotSupportedError}} and abort these steps.
- 4. Assign |config| to {{AudioEncoder/[[active encoder config]]}}
+ {{NotSupportedError}} and return `"processed"`.
+ 4. Assign `true` to {{AudioEncoder/[[message queue blocked]]}}.
+ 5. Enqueue the following steps to {{AudioEncoder/[[codec work queue]]}}:
+ 1. Configure {{AudioEncoder/[[codec implementation]]}} with |config|.
+ 2. Set {{AudioEncoder/[[active encoder config]]}} to `config`.
+ 3. Assign `false` to {{AudioEncoder/[[message queue blocked]]}}.
+ 4. [=Queue a task=] to [=Process the control message queue=].
+ 6. Return `"processed"`.
encode(data)
@@ -953,27 +1082,39 @@
[=Enqueues a control message=] to encode the given |data|.
When invoked, run these steps:
- 1. If the value of |data|'s {{platform object/[[Detached]]}} internal slot is
- `true`, throw a {{TypeError}}.
+ 1. If the value of |data|'s {{platform object/[[Detached]]}} internal slot
+ is `true`, throw a {{TypeError}}.
2. If {{AudioEncoder/[[state]]}} is not `"configured"`, throw an
{{InvalidStateError}}.
3. Let |dataClone| hold the result of running the [=Clone AudioData=]
algorithm with |data|.
4. Increment {{AudioEncoder/[[encodeQueueSize]]}}.
5. [=Queue a control message=] to encode |dataClone|.
+ 6. [=Process the control message queue=].
- [=Running a control message=] to encode the data means performing these steps.
- 1. Attempt to use {{AudioEncoder/[[codec implementation]]}} to encode
- the [=media resource=] described by |dataClone|.
- 2. If encoding results in an error, queue a task on the [=control thread=]
- event loop to run the [=Close AudioEncoder=] algorithm with
- {{EncodingError}}.
- 3. Queue a task on the [=control thread=] event loop to decrement
- {{AudioEncoder/[[encodeQueueSize]]}}.
- 4. Let |encoded outputs| be a [=list=] of encoded audio data outputs
- emitted by {{AudioEncoder/[[codec implementation]]}}.
- 5. If |encoded outputs| is not empty, queue a task on the
- [=control thread=] event loop to run the [=Output EncodedAudioChunks=] algorithm with |encoded outputs|.
+ [=Running a control message=] to encode the data means performing these
+ steps:
+ 1. If {{AudioEncoder/[[codec saturated]]}} equals `true`, return `"not
+ processed"`.
+ 2. If encoding |data| will cause the
+ {{AudioEncoder/[[codec implementation]]}} to become [=saturated=],
+ assign `true` to {{AudioEncoder/[[codec saturated]]}}.
+ 3. Decrement {{AudioEncoder/[[encodeQueueSize]]}}.
+ 4. Enqueue the following steps to the {{AudioEncoder/[[codec work queue]]}}:
+ 1. Attempt to use {{AudioEncoder/[[codec implementation]]}} to encode
+ the [=media resource=] described by |dataClone|.
+ 2. If encoding results in an error, [=queue a task=] to run the
+ [=Close AudioEncoder=] algorithm with {{EncodingError}} and return.
+ 3. If {{AudioEncoder/[[codec saturated]]}} equals `true` and
+ {{AudioEncoder/[[codec implementation]]}} is no longer
+ [=saturated=], [=queue a task=] to perform the following steps:
+ 1. Assign `false` to {{AudioEncoder/[[codec saturated]]}}.
+ 2. [=Process the control message queue=].
+ 4. Let |encoded outputs| be a [=list=] of encoded audio data outputs
+ emitted by {{AudioEncoder/[[codec implementation]]}}.
+ 5. If |encoded outputs| is not empty, [=queue a task=] to run the
+ [=Output EncodedAudioChunks=] algorithm with |encoded outputs|.
+ 5. Return `"processed"`.
flush()
@@ -985,22 +1126,24 @@
1. If {{AudioEncoder/[[state]]}} is not `"configured"`, return
[=a promise rejected with=] {{InvalidStateError}} {{DOMException}}.
2. Let |promise| be a new Promise.
- 3. [=Queue a control message=] to flush the codec with |promise|.
- 4. Append |promise| to {{AudioEncoder/[[pending flush promises]]}}.
- 5. Return |promise|.
-
- [=Running a control message=] to flush the codec means performing these steps
- with |promise|.
- 1. Signal {{AudioEncoder/[[codec implementation]]}} to emit all [=internal
- pending outputs=].
- 2. Let |encoded outputs| be a [=list=] of encoded audio data outputs
- emitted by {{AudioEncoder/[[codec implementation]]}}.
- 3. If |encoded outputs| is not empty, queue a task on the [=control thread=]
- event loop to run the [=Output EncodedAudioChunks=] algorithm with
- |encoded outputs|.
- 4. Queue a task on the [=control thread=] event loop to run these steps:
- 1. Remove |promise| from {{AudioEncoder/[[pending flush promises]]}}.
- 2. Resolve |promise|.
+ 3. Append |promise| to {{AudioEncoder/[[pending flush promises]]}}.
+ 4. [=Queue a control message=] to flush the codec with |promise|.
+ 5. [=Process the control message queue=].
+ 6. Return |promise|.
+
+ [=Running a control message=] to flush the codec means performing these
+ steps with |promise|.
+ 1. Enqueue the following steps to the {{AudioEncoder/[[codec work queue]]}}:
+ 1. Signal {{AudioEncoder/[[codec implementation]]}} to emit all
+ [=internal pending outputs=].
+ 2. Let |encoded outputs| be a [=list=] of encoded audio data outputs
+ emitted by {{AudioEncoder/[[codec implementation]]}}.
+ 3. [=Queue a task=] to perform these steps:
+ 1. If |encoded outputs| is not empty, run the
+ [=Output EncodedAudioChunks=] algorithm with |encoded outputs|.
+ 2. Remove |promise| from
+ {{AudioEncoder/[[pending flush promises]]}}.
+ 3. Resolve |promise|.
reset()
@@ -1112,7 +1255,8 @@
4. Set {{AudioEncoder/[[active output config]]}} to `null`.
5. Signal {{AudioEncoder/[[codec implementation]]}} to cease producing
output for the previous configuration.
- 6. Remove all [=control messages=] from the [=control message queue=].
+ 6. Remove all [=control messages=] from the
+ {{AudioEncoder/[[control message queue]]}}.
7. Set {{AudioEncoder/[[encodeQueueSize]]}} to zero.
8. For each |promise| in {{AudioEncoder/[[pending flush promises]]}}:
1. Reject |promise| with |exception|.
@@ -1125,9 +1269,9 @@
2. Set {{AudioEncoder/[[state]]}} to `"closed"`.
3. Clear {{AudioEncoder/[[codec implementation]]}} and release associated
[=system resources=].
- 4. If |exception| is not an {{AbortError}} {{DOMException}}, queue a task on
- the [=control thread=] event loop to invoke the
- {{AudioDecoder/[[error callback]]}} with |exception|.
+ 4. If |exception| is not an {{AbortError}} {{DOMException}},
+ [=queue a task=] to invoke the
+ {{AudioEncoder/[[error callback]]}} with |exception|.
@@ -1180,45 +1324,58 @@
Internal Slots {#videoencoder-internal-slots}
---------------------------------------------
-
-- [[codec implementation]]
-- Underlying encoder implementation provided by the User Agent.
-- [[output callback]]
-- Callback given at construction for encoded outputs.
-- [[error callback]]
-- Callback given at construction for encode errors.
-- [[active encoder config]]
-- The {{VideoEncoderConfig}} that is actively applied.
-- [[active output config]]
--
- The {{VideoDecoderConfig}} that describes how to decode the most recently
- emitted {{EncodedVideoChunk}}.
-
-- \[[state]]
--
- The current {{CodecState}} of this {{VideoEncoder}}.
-
-- \[[encodeQueueSize]]
--
- The number of pending encode requests. This number will decrease as the
- underlying codec is ready to accept new input.
-
-- [[pending flush promises]]
--
- A list of unresolved promises returned by calls to {{VideoEncoder/flush()}}.
-
-
+: [[control message queue]]
+:: A [=queue=] of [=control messages=] to be performed upon this [=codec=]
+ instance. See [=[[control message queue]]=].
+: [[message queue blocked]]
+:: A boolean indicating when processing the
+ {{VideoEncoder/[[control message queue]]}} is blocked by a pending
+ [=control message=]. See [=[[message queue blocked]]=].
+: [[codec implementation]]
+:: Underlying encoder implementation provided by the User Agent.
+: [[codec work queue]]
+:: A [=parallel queue=] used for running parallel steps that reference the
+ {{VideoEncoder/[[codec implementation]]}}. See [=[[codec work queue]]=].
+: [[codec saturated]]
+:: A boolean indicating when the [[codec implementation]] is unable to accept
+ additional encoding work.
+: [[output callback]]
+:: Callback given at construction for encoded outputs.
+: [[error callback]]
+:: Callback given at construction for encode errors.
+: [[active encoder config]]
+:: The {{VideoEncoderConfig}} that is actively applied.
+: [[active output config]]
+:: The {{VideoDecoderConfig}} that describes how to decode the most recently
+ emitted {{EncodedVideoChunk}}.
+: \[[state]]
+:: The current {{CodecState}} of this {{VideoEncoder}}.
+: \[[encodeQueueSize]]
+:: The number of pending encode requests. This number will decrease as the
+ underlying codec is ready to accept new input.
+: [[pending flush promises]]
+:: A list of unresolved promises returned by calls to {{VideoEncoder/flush()}}.
Constructors {#videoencoder-constructors}
-----------------------------------------
VideoEncoder(init)
-1. Let e be a new VideoEncoder object.
-2. Assign `init.output` to the {{VideoEncoder/[[output callback]]}} internal slot.
-3. Assign `init.error` to the {{VideoEncoder/[[error callback]]}} internal slot.
-4. Assign "unconfigured" to {{VideoEncoder/[[state]]}}.
-5. Return e.
+1. Let e be a new {{VideoEncoder}} object.
+2. Assign a new [=queue=] to {{VideoEncoder/[[control message queue]]}}.
+3. Assign `false` to {{VideoEncoder/[[message queue blocked]]}}.
+4. Assign `null` to {{VideoEncoder/[[codec implementation]]}}.
+5. Assign the result of starting a new [=parallel queue=] to
+ {{VideoEncoder/[[codec work queue]]}}.
+6. Assign `false` to {{VideoEncoder/[[codec saturated]]}}.
+7. Assign init.output to {{VideoEncoder/[[output callback]]}}.
+8. Assign init.error to {{VideoEncoder/[[error callback]]}}.
+9. Assign `null` to {{VideoEncoder/[[active encoder config]]}}.
+10. Assign `null` to {{VideoEncoder/[[active output config]]}}.
+11. Assign `"unconfigured"` to {{VideoEncoder/[[state]]}}
+12. Assign `0` to {{VideoEncoder/[[encodeQueueSize]]}}.
+13. Assign a new [=list=] to {{VideoEncoder/[[pending flush promises]]}}.
+14. Return e.
Attributes {#videoencoder-attributes}
-------------------------------------
@@ -1252,20 +1409,28 @@
When invoked, run these steps:
1. If |config| is not a [=valid VideoEncoderConfig=], throw a
{{TypeError}}.
- 2. If {{VideoEncoder/[[state]]}} is `"closed"`, throw an {{InvalidStateError}}.
+ 2. If {{VideoEncoder/[[state]]}} is `"closed"`, throw an
+ {{InvalidStateError}}.
3. Set {{VideoEncoder/[[state]]}} to `"configured"`.
4. [=Queue a control message=] to configure the encoder using |config|.
+ 5. [=Process the control message queue=].
- [=Running a control message=] to configure the encoder means performing these
- steps:
+ [=Running a control message=] to configure the encoder means performing
+ these steps:
1. Let |supported| be the result of running the Check Configuration
Support algorithm with |config|.
2. If |supported| is `true`, assign
{{VideoEncoder/[[codec implementation]]}} with an implementation
supporting |config|.
3. Otherwise, run the Close VideoEncoder algorithm with
- {{NotSupportedError}} and abort these steps.
- 4. Assign |config| to {{VideoEncoder/[[active encoder config]]}}.
+ {{NotSupportedError}} and return `"processed"`.
+ 4. Assign `true` to {{VideoEncoder/[[message queue blocked]]}}.
+ 5. Enqueue the following steps to {{VideoEncoder/[[codec work queue]]}}:
+ 1. Configure {{VideoEncoder/[[codec implementation]]}} with |config|.
+ 2. Set {{VideoEncoder/[[active encoder config]]}} to `config`.
+ 3. Assign `false` to {{VideoEncoder/[[message queue blocked]]}}.
+ 4. [=Queue a task=] to [=Process the control message queue=].
+ 6. Return `"processed"`.
encode(|frame|, |options|)
@@ -1273,28 +1438,39 @@
[=Enqueues a control message=] to encode the given |frame|.
When invoked, run these steps:
- 1. If the value of |frame|'s {{platform object/[[Detached]]}} internal slot is
- `true`, throw a {{TypeError}}.
+ 1. If the value of |frame|'s {{platform object/[[Detached]]}} internal slot
+ is `true`, throw a {{TypeError}}.
2. If {{VideoEncoder/[[state]]}} is not `"configured"`, throw an
{{InvalidStateError}}.
3. Let |frameClone| hold the result of running the [=Clone VideoFrame=]
algorithm with |frame|.
4. Increment {{VideoEncoder/[[encodeQueueSize]]}}.
5. [=Queue a control message=] to encode |frameClone|.
+ 6. [=Process the control message queue=].
- [=Running a control message=] to encode the frame means performing these steps.
- 1. Attempt to use {{VideoEncoder/[[codec implementation]]}} to encode
- |frameClone| according to |options|.
- 2. If encoding results in an error, queue a task on the [=control thread=]
- event loop to run the [=Close VideoEncoder=] algorithm with
- {{EncodingError}}.
- 3. Queue a task on the [=control thread=] event loop to decrement
- {{VideoEncoder/[[encodeQueueSize]]}}.
- 4. Let |encoded outputs| be a [=list=] of encoded video data outputs
- emitted by {{VideoEncoder/[[codec implementation]]}}.
- 5. If |encoded outputs| is not empty, queue a task on the [=control thread=]
- event loop to run the [=Output EncodedVideoChunks=] algorithm with
- |encoded outputs|.
+ [=Running a control message=] to encode the frame means performing these
+ steps:
+ 1. If {{VideoEncoder/[[codec saturated]]}} equals `true`, return `"not
+ processed"`.
+ 2. If encoding |frame| will cause the
+ {{VideoEncoder/[[codec implementation]]}} to become [=saturated=],
+ assign `true` to {{VideoEncoder/[[codec saturated]]}}.
+ 3. Decrement {{VideoEncoder/[[encodeQueueSize]]}}.
+ 4. Enqueue the following steps to the {{VideoEncoder/[[codec work queue]]}}:
+ 1. Attempt to use {{VideoEncoder/[[codec implementation]]}} to encode
+ the |frameClone| according to |options|.
+ 2. If encoding results in an error, [=queue a task=] to run the
+ [=Close VideoEncoder=] algorithm with {{EncodingError}} and return.
+ 3. If {{VideoEncoder/[[codec saturated]]}} equals `true` and
+ {{VideoEncoder/[[codec implementation]]}} is no longer
+ [=saturated=], [=queue a task=] to perform the following steps:
+ 1. Assign `false` to {{VideoEncoder/[[codec saturated]]}}.
+ 2. [=Process the control message queue=].
+ 4. Let |encoded outputs| be a [=list=] of encoded video data outputs
+ emitted by {{VideoEncoder/[[codec implementation]]}}.
+ 5. If |encoded outputs| is not empty, [=queue a task=] to run the
+ [=Output EncodedVideoChunks=] algorithm with |encoded outputs|.
+ 5. Return `"processed"`.
flush()
@@ -1306,22 +1482,24 @@
1. If {{VideoEncoder/[[state]]}} is not `"configured"`, return
[=a promise rejected with=] {{InvalidStateError}} {{DOMException}}.
2. Let |promise| be a new Promise.
- 3. [=Queue a control message=] to flush the codec with |promise|.
- 4. Append |promise| to {{VideoEncoder/[[pending flush promises]]}}.
- 5. Return |promise|.
-
- [=Running a control message=] to flush the codec means performing these steps
- with |promise|.
- 1. Signal {{VideoEncoder/[[codec implementation]]}} to emit all [=internal
- pending outputs=].
- 2. Let |encoded outputs| be a [=list=] of encoded video data outputs
- emitted by {{VideoEncoder/[[codec implementation]]}}.
- 3. If |encoded outputs| is not empty, queue a task on the [=control thread=]
- event loop to run the [=Output EncodedVideoChunks=] algorithm with
- |encoded outputs|.
- 4. Queue a task on the [=control thread=] event loop to run these steps:
- 1. Remove |promise| from {{VideoEncoder/[[pending flush promises]]}}.
- 2. Resolve |promise|.
+ 3. Append |promise| to {{VideoEncoder/[[pending flush promises]]}}.
+ 4. [=Queue a control message=] to flush the codec with |promise|.
+ 5. [=Process the control message queue=].
+ 6. Return |promise|.
+
+ [=Running a control message=] to flush the codec means performing these
+ steps with |promise|:
+ 1. Enqueue the following steps to the {{VideoEncoder/[[codec work queue]]}}:
+ 1. Signal {{VideoEncoder/[[codec implementation]]}} to emit all
+ [=internal pending outputs=].
+ 2. Let |encoded outputs| be a [=list=] of encoded video data outputs
+ emitted by {{VideoEncoder/[[codec implementation]]}}.
+ 3. [=Queue a task=] to perform these steps:
+ 1. If |encoded outputs| is not empty, run the
+ [=Output EncodedVideoChunks=] algorithm with |encoded outputs|.
+ 2. Remove |promise| from
+ {{VideoEncoder/[[pending flush promises]]}}.
+ 3. Resolve |promise|.
reset()
@@ -1448,7 +1626,8 @@
4. Set {{VideoEncoder/[[active output config]]}} to `null`.
5. Signal {{VideoEncoder/[[codec implementation]]}} to cease producing
output for the previous configuration.
- 6. Remove all [=control messages=] from the [=control message queue=].
+ 6. Remove all [=control messages=] from the
+ {{VideoEncoder/[[control message queue]]}}.
7. Set {{VideoEncoder/[[encodeQueueSize]]}} to zero.
8. For each |promise| in {{VideoEncoder/[[pending flush promises]]}}:
1. Reject |promise| with |exception|.
@@ -1461,8 +1640,9 @@
2. Set {{VideoEncoder/[[state]]}} to `"closed"`.
3. Clear {{VideoEncoder/[[codec implementation]]}} and release associated
[=system resources=].
- 4. If |exception| is not an {{AbortError}} {{DOMException}}, queue a task on
- the [=control thread=] event loop to invoke the {{AudioDecoder/[[error callback]]}} with |exception|.
+ 4. If |exception| is not an {{AbortError}} {{DOMException}},
+ [=queue a task=] to invoke the {{VideoEncoder/[[error callback]]}} with
+ |exception|.
@@ -3358,7 +3538,7 @@
[=computed plane layout/destinationStride=].
4. Increment |row| by `1`.
9. Increment |planeIndex| by `1`.
- 5. Queue a task on the [=control thread=] event loop to resolve |p|.
+ 5. [=Queue a task=] to resolve |p|.
9. Return |p|.
: clone()
@@ -3709,7 +3889,8 @@
1. Assign |minAllocationSize| to |computedLayout|'s
[=computed plane layout/destinationOffset=].
- 2. Assign |computedLayout|'s [=computed plane layout/sourceWidthBytes=] to
+ 2. Assign |computedLayout|'s
+ [=computed plane layout/sourceWidthBytes=] to
|computedLayout|'s [=computed plane layout/destinationStride=].
13. Let |planeSize| be the product of multiplying |computedLayout|'s
[=computed plane layout/destinationStride=] and
@@ -4344,6 +4525,19 @@
### Internal Slots ### {#imagedecoder-internal-slots}
+: [[control message queue]]
+:: A [=queue=] of [=control messages=] to be performed upon this [=codec=]
+ instance. See [=[[control message queue]]=].
+
+: [[message queue blocked]]
+:: A boolean indicating when processing the
+ {{ImageDecoder/[[control message queue]]}} is blocked by a pending
+ [=control message=]. See [=[[message queue blocked]]=].
+
+: [[codec work queue]]
+:: A [=parallel queue=] used for running parallel steps that reference the
+ {{ImageDecoder/[[codec implementation]]}}. See [=[[codec work queue]]=].
+
: \[[ImageTrackList]]
:: An {{ImageTrackList}} describing the tracks found in
{{ImageDecoder/[[encoded data]]}}
@@ -4375,7 +4569,7 @@
: [[internal selected track index]]
:: Identifies the image track within {{ImageDecoder/[[encoded data]]}} that is
- used by decoding algorithms on the [=codec thread=].
+ used by decoding algorithms.
: [[tracks established]]
:: A boolean indicating whether the track list has been established in
@@ -4408,32 +4602,37 @@
2. Let |d| be a new {{ImageDecoder}} object. In the steps below, all
mentions of {{ImageDecoder}} members apply to |d| unless stated
otherwise.
- 3. Assign {{ImageDecoder/[[ImageTrackList]]}} a new {{ImageTrackList}}
+ 3. Assign a new [=queue=] to {{ImageDecoder/[[control message queue]]}}.
+ 4. Assign `false` to {{ImageDecoder/[[message queue blocked]]}}.
+ 5. Assign the result of starting a new [=parallel queue=] to
+ {{ImageDecoder/[[codec work queue]]}}.
+ 6. Assign {{ImageDecoder/[[ImageTrackList]]}} a new {{ImageTrackList}}
initialized as follows:
1. Assign a new [=list=] to {{ImageTrackList/[[track list]]}}.
2. Assign `-1` to {{ImageTrackList/[[selected index]]}}.
- 4. Assign {{ImageDecoderInit/type}} to {{ImageDecoder/[[type]]}}.
- 5. Assign `null` to {{ImageDecoder/[[codec implementation]]}}.
- 6. If `init.preferAnimation` [=map/exists=], assign `init.preferAnimation`
+ 7. Assign {{ImageDecoderInit/type}} to {{ImageDecoder/[[type]]}}.
+ 8. Assign `null` to {{ImageDecoder/[[codec implementation]]}}.
+ 9. If `init.preferAnimation` [=map/exists=], assign `init.preferAnimation`
to the {{ImageDecoder/[[prefer animation]]}} internal slot. Otherwise,
assign 'null' to {{ImageDecoder/[[prefer animation]]}} internal slot.
- 7. Assign a new [=list=] to {{ImageDecoder/[[pending decode promises]]}}.
- 8. Assign `-1` to {{ImageDecoder/[[internal selected track index]]}}.
- 9. Assign `false` to {{ImageDecoder/[[tracks established]]}}.
- 10. Assign `false` to {{ImageDecoder/[[closed]]}}.
- 11. Assign a new [=map=] to {{ImageDecoder/[[progressive frame
+ 10. Assign a new [=list=] to {{ImageDecoder/[[pending decode promises]]}}.
+ 11. Assign `-1` to {{ImageDecoder/[[internal selected track index]]}}.
+ 12. Assign `false` to {{ImageDecoder/[[tracks established]]}}.
+ 13. Assign `false` to {{ImageDecoder/[[closed]]}}.
+ 14. Assign a new [=map=] to {{ImageDecoder/[[progressive frame
generations]]}}.
- 12. If |init|'s {{ImageDecoderInit/data}} member is of type
+ 15. If |init|'s {{ImageDecoderInit/data}} member is of type
{{ReadableStream}}:
1. Assign a new [=list=] to {{ImageDecoder/[[encoded data]]}}.
2. Assign `false` to {{ImageDecoder/[[complete]]}}
3. [=Queue a control message=] to [=configure the image decoder=] with
|init|.
- 4. Let |reader| be the result of [=getting a reader=] for
+ 4. [=Process the control message queue=].
+ 5. Let |reader| be the result of [=getting a reader=] for
{{ImageDecoderInit/data}}.
- 5. In parallel, perform the [=Fetch Stream Data Loop=] on |d| with
+ 6. In parallel, perform the [=Fetch Stream Data Loop=] on |d| with
|reader|.
- 13. Otherwise:
+ 16. Otherwise:
1. Assert that `init.data` is of type {{BufferSource}}.
2. Assign a copy of `init.data` to {{ImageDecoder/[[encoded data]]}}.
3. Assign `true` to {{ImageDecoder/[[complete]]}}.
@@ -4441,28 +4640,33 @@
5. Queue a control message to [=configure the image decoder=] with
|init|.
6. Queue a control message to [=decode track metadata=].
- 14. return |d|.
+ 7. [=Process the control message queue=].
+ 17. return |d|.
[=Running a control message=] to configure the image decoder
means running these steps:
1. Let |supported| be the result of running the [=ImageDecoder/Check Type
Support=] algorithm with `init.type`.
- 2. If |supported| is `false`, queue a task on the [=control thread=] event
- loop to run the [=ImageDecoder/Close ImageDecoder=] algorithm
- with a {{NotSupportedError}} {{DOMException}} and abort
- these steps.
- 3. If |supported| is `true`, assign the
- {{ImageDecoder/[[codec implementation]]}} internal slot with an
- implementation supporting `init.type`
- 4. Configure {{ImageDecoder/[[codec implementation]]}} in accordance with
- the values given for {{ImageDecoderInit/premultiplyAlpha}},
- {{ImageDecoderInit/colorSpaceConversion}},
- {{ImageDecoderInit/desiredWidth}}, and
- {{ImageDecoderInit/desiredHeight}}.
+ 2. If |supported| is `false`, run the [=ImageDecoder/Close ImageDecoder=]
+ algorithm with a {{NotSupportedError}} {{DOMException}} and return
+ `"processed"`.
+ 3. Otherwise, assign the {{ImageDecoder/[[codec implementation]]}} internal
+ slot with an implementation supporting `init.type`
+ 3. Assign `true` to {{ImageDecoder/[[message queue blocked]]}}.
+ 3. Enqueue the following steps to the {{ImageDecoder/[[codec work queue]]}}:
+ 1. Configure {{ImageDecoder/[[codec implementation]]}} in accordance
+ with the values given for {{ImageDecoderInit/premultiplyAlpha}},
+ {{ImageDecoderInit/colorSpaceConversion}},
+ {{ImageDecoderInit/desiredWidth}}, and
+ {{ImageDecoderInit/desiredHeight}}.
+ 2. Assign `false` to {{ImageDecoder/[[message queue blocked]]}}.
+ 3. [=Queue a task=] to [=Process the control message queue=].
+ 4. Return `"processed"`.
[=Running a control message=] to decode track metadata means
running these steps:
- 1. Run the [=ImageDecoder/Establish Tracks=] algorithm.
+ 1. Enqueue the following steps to the {{ImageDecoder/[[codec work queue]]}}:
+ 1. Run the [=ImageDecoder/Establish Tracks=] algorithm.
### Attributes ### {#imagedecoder-attributes}
: type
@@ -4504,19 +4708,23 @@
3. If |options| is `undefined`, assign a new {{ImageDecodeOptions}} to
|options|.
4. Let |promise| be a new {{Promise}}.
- 5. [=Queue a control message=] to decode the image with |options|, and
+ 5. Append |promise| to {{ImageDecoder/[[pending decode promises]]}}.
+ 6. [=Queue a control message=] to decode the image with |options|, and
|promise|.
- 6. Append |promise| to {{ImageDecoder/[[pending decode promises]]}}.
- 7. Return |promise|.
+ 7. [=Process the control message queue=].
+ 8. Return |promise|.
[=Running a control message=] to decode the image means running these
steps:
- 1. Wait for {{ImageDecoder/[[tracks established]]}} to become `true`.
- 2. If |options|.{{ImageDecodeOptions/completeFramesOnly}} is `false` and
- the image is a [=Progressive Image=] for which the User Agent supports
- progressive decoding, run the [=Decode Progressive Frame=] algorithm with |options|.{{ImageDecodeOptions/frameIndex}} and |promise|.
- 3. Otherwise, run the [=Decode Complete Frame=] algorithm with
- |options|.{{ImageDecodeOptions/frameIndex}} and |promise|.
+ 1. Enqueue the following steps to the {{ImageDecoder/[[codec work queue]]}}:
+ 1. Wait for {{ImageDecoder/[[tracks established]]}} to become `true`.
+ 2. If |options|.{{ImageDecodeOptions/completeFramesOnly}} is `false` and
+ the image is a [=Progressive Image=] for which the User Agent
+ supports progressive decoding, run the [=Decode Progressive Frame=]
+ algorithm with |options|.{{ImageDecodeOptions/frameIndex}} and
+ |promise|.
+ 3. Otherwise, run the [=Decode Complete Frame=] algorithm with
+ |options|.{{ImageDecodeOptions/frameIndex}} and |promise|.
: reset()
:: Immediately aborts all pending work.
@@ -4551,9 +4759,8 @@
: [=read request/chunk steps=], given |chunk|
:: 1. If {{ImageDecoder/[[closed]]}} is `true`, abort these steps.
- 2. If |chunk| is not a Uint8Array object, queue a task on the
- [=control thread=] event loop to run the
- [=ImageDecoder/Close ImageDecoder=] algorithm with a
+ 2. If |chunk| is not a Uint8Array object, [=queue a task=] to run
+ the [=ImageDecoder/Close ImageDecoder=] algorithm with a
{{DataError}} {{DOMException}} and abort these steps.
3. Let |bytes| be the byte sequence represented by the Uint8Array
object.
@@ -4569,9 +4776,8 @@
2. Resolve {{ImageDecoder/[[completed promise]]}}.
: [=read request/error steps=]
- :: 1. Queue a task on the [=control thread=] event loop to run the
- [=ImageDecoder/Close ImageDecoder=] algorithm with a
- {{NotReadableError}} {{DOMException}}
+ :: 1. [=Queue a task=] to run the [=ImageDecoder/Close ImageDecoder=]
+ algorithm with a {{NotReadableError}} {{DOMException}}
2. Read a chunk from |reader| given |readRequest|.
@@ -4580,11 +4786,10 @@
1. Assert {{ImageDecoder/[[tracks established]]}} is `false`.
2. If {{ImageDecoder/[[encoded data]]}} does not contain enough data to
determine the number of tracks:
- 1. If {{ImageDecoder/complete}} is `true`, queue a task on the
- [=control thread=] event loop to run the [=ImageDecoder/Close ImageDecoder=] algorithm.
+ 1. If {{ImageDecoder/complete}} is `true`, [=queue a task=] to run the
+ [=ImageDecoder/Close ImageDecoder=] algorithm.
2. Abort these steps.
- 3. If the number of tracks is found to be `0`, queue a task on the
- [=control thread=] event loop to run the
+ 3. If the number of tracks is found to be `0`, [=queue a task=] to run the
[=ImageDecoder/Close ImageDecoder=] algorithm and abort these steps.
4. Let |newTrackList| be a new [=list=].
5. For each |image track| found in {{ImageDecoder/[[encoded data]]}}:
@@ -4624,8 +4829,7 @@
8. Assign |selectedTrackIndex| to {{ImageDecoder/[[internal selected track
index]]}}.
9. Assign `true` to {{ImageDecoder/[[tracks established]]}}.
- 10. Queue a task on the [=control thread=] event loop to perform the
- following steps:
+ 10. [=Queue a task=] to perform the following steps:
1. Assign |newTrackList| to the {{ImageDecoder/tracks}}
{{ImageTrackList/[[track list]]}} internal slot.
2. Assign |selectedTrackIndex| to {{ImageDecoder/tracks}}
@@ -4674,8 +4878,7 @@
[=track update struct/frame count=] is |latestFrameCount|.
2. Append |change| to |tracksChanges|.
5. If |tracksChanges| is [=list/empty=], abort these steps.
- 6. Queue a task on the [=control thread=] event loop to perform the
- following steps:
+ 6. [=Queue a task=] to perform the following steps:
1. For each update in |trackChanges|:
1. Let |updateTrack| be the {{ImageTrack}} at position
`update.trackIndex` within {{ImageDecoder/tracks}}'
@@ -4787,7 +4990,7 @@
18. Resolve |promise| with |decodeResult|.
: Resolve Decode (with |promise| and |result|)
-:: 1. Queue a task on the [=control thread=] event loop to run these steps:
+:: 1. [=Queue a task=] to perform these steps:
1. If {{ImageDecoder/[[closed]]}}, abort these steps.
2. Assert that |promise| is an element of
{{ImageDecoder/[[pending decode promises]]}}.
@@ -4800,7 +5003,7 @@
2. If {{ImageDecoder/complete}} is `true`, let |exception| be a
{{RangeError}}. Otherwise, let |exception| be an
{{InvalidStateError}} {{DOMException}}.
- 3. Queue a task on the [=control thread=] event loop to run these steps:
+ 3. [=Queue a task=] to perform these steps:
1. If {{ImageDecoder/[[closed]]}}, abort these steps.
2. Assert that |promise| is an element of
{{ImageDecoder/[[pending decode promises]]}}.
@@ -4808,7 +5011,7 @@
4. Reject |promise| with |exception|.
: Fatally Reject Bad Data
-:: 1. Queue a task on the [=control thread=] event loop to run these steps:
+:: 1. [=Queue a task=] to perform these steps:
1. If {{ImageDecoder/[[closed]]}}, abort these steps.
2. Run the [=ImageDecoder/Close ImageDecoder=] algorithm with an
{{EncodingError}} {{DOMException}}.
@@ -4870,7 +5073,7 @@
6. Return `true`.
A valid image MIME type is a string that is a [=valid MIME type
-string=] and for which the `type`, per Section 3.1.1.1 of [[RFC7231]], is
+string=] and for which the `type`, per Section 3.1.1.1 of [[RFC9110]], is
`image`.
: type
@@ -5106,13 +5309,17 @@
11. [=Queue a control message=] to {{ImageTrack/[[ImageDecoder]]}}'s
[=control message queue=] to update the internal selected track
index with |selectedIndex|.
+ 12. [=Process the control message queue=] belonging to
+ {{ImageTrack/[[ImageDecoder]]}}.
[=Running a control message=] to update the internal selected track index
means running these steps:
- 1. Assign |selectedIndex| to
- {{ImageDecoder/[[internal selected track index]]}}.
- 2. Remove all entries from
- {{ImageDecoder/[[progressive frame generations]]}}.
+ 1. Enqueue the following steps to {{ImageTrack/[[ImageDecoder]]}}'s
+ {{ImageDecoder/[[codec work queue]]}}:
+ 1. Assign |selectedIndex| to
+ {{ImageDecoder/[[internal selected track index]]}}.
+ 2. Remove all entries from
+ {{ImageDecoder/[[progressive frame generations]]}}.
### Event Summary ### {#imagetracklist-eventsummary}