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}