WebCodecs

W3C 工作草案

关于本文档的更多信息
本版本:
https://www.w3.org/TR/2025/WD-webcodecs-20250708/
最新发布版本:
https://www.w3.org/TR/webcodecs/
编辑草案:
https://w3c.github.io/webcodecs/
以往版本:
历史记录:
https://www.w3.org/standards/history/webcodecs/
反馈:
GitHub
规范内反馈
编辑者:
Paul Adenot (Mozilla)
Eugene Zemtsov (Google LLC)
前编辑者:
Bernard Aboba (Microsoft Corporation)
Chris Cunningham (Google Inc.)
参与方式:
Git 仓库
提交问题
版本历史:
https://github.com/w3c/webcodecs/commits

摘要

本规范定义了用于音频、视频和图像编码与解码的编解码器接口。

本规范不指定或要求任何特定的编解码器或编码/解码方法。其目的是为现有编解码技术的实现提供 JavaScript 接口,这些技术由其他地方开发。实现者可自由支持任意组合的编解码器,也可以完全不支持。

本文档状态

本节描述了本文档在发布时的状态。当前 W3C 出版物列表及本技术报告的最新修订版可在 W3C 标准与草案索引中查阅。

欢迎对本规范提出反馈和意见。 推荐在 GitHub Issues 上讨论本规范。也可发送邮件至媒体工作组的邮件列表 public-media-wg@w3.org存档)。 本草案突出了一些待工作组讨论的悬而未决问题。尚未对这些问题的结果做出决定,包括其是否有效。

本文档由 媒体工作组 作为工作草案发布,采用 推荐轨道。 本文档旨在成为 W3C 推荐标准。

作为工作草案发布并不意味着 W3C 及其成员的认可。

本文档为草稿,可能随时更新、替换或被其他文档废止。 除作为正在进行的工作外,不应引用本文档。

本文档由遵循 W3C 专利政策 的工作组制作。 W3C 维护着与本工作组交付物相关的 专利公开列表,该页面也包含专利披露说明。 任何个人如实际知晓某专利且认为其包含 必要权利要求,须按 W3C 专利政策第6节 披露相关信息。

本文档受 2023年11月3日 W3C 流程文件 管辖。

1. 术语定义

编解码器

泛指 AudioDecoderAudioEncoderVideoDecoderVideoEncoder 的实例。

关键块

一种编码块,在解码时不依赖于其他帧。也常被称为“关键帧”。

内部待输出

编解码器输出,如 VideoFrame,当前处于底层编解码器实现的内部管道中。底层编解码器实现 可以 仅在有新输入时产生新输出。底层编解码器实现 必须 在 flush 时输出所有待输出内容。

编解码器系统资源

包括 CPU 内存、GPU 内存,以及对特定解码/编码硬件的独占句柄等资源,这些资源 可以 由用户代理在编解码器配置或生成 AudioDataVideoFrame 对象时分配。此类资源 可以 很快耗尽,应当 在不再使用时立即释放。

时间层

一组 EncodedVideoChunk,其时间戳节奏产生特定帧率。参见 scalabilityMode

渐进式图像

一种支持多级细节解码的图像,在编码数据尚未完全缓冲时,较低级别的细节即可被解码获得。

渐进式图像帧代数

用于标识某个 渐进式图像解码输出的代数标识。每一代都会为解码输出增加更多细节。帧代数的计算机制由实现者自行定义。

主图像轨道

由图像文件标记为默认轨道的图像轨道。主轨道的标识机制由具体格式定义。

RGB 格式

一种 VideoPixelFormat,包含红、绿、蓝色通道,通道顺序和布局(交错或平面)不限,是否包含 alpha 通道也不限。

sRGB 色彩空间

一个 VideoColorSpace 对象,初始化如下:

  1. [[primaries]] 设为 bt709

  2. [[transfer]] 设为 iec61966-2-1

  3. [[matrix]] 设为 rgb

  4. [[full range]] 设为 true

Display P3 色彩空间

一个 VideoColorSpace 对象,初始化如下:

  1. [[primaries]] 设为 smpte432

  2. [[transfer]] 设为 iec61966-2-1

  3. [[matrix]] 设为 rgb

  4. [[full range]] 设为 true

REC709 色彩空间

一个 VideoColorSpace 对象,初始化如下:

  1. [[primaries]] 设为 bt709

  2. [[transfer]] 设为 bt709

  3. [[matrix]] 设为 bt709

  4. [[full range]] 设为 false

编解码器饱和

底层编解码器实现处于活动解码或编码请求数量达到实现特定最大值的状态,此时暂时无法接受更多工作。最大值可以大于1的任意值,包括无限(无最大值)。饱和时,对 decode()encode() 的额外调用会被缓冲到 控制消息队列,并会增加 decodeQueuSizeencodeQueueSize 属性。编解码器实现在当前工作取得足够进展后将恢复为未饱和状态。

2. 编解码器处理模型

2.1. 背景

本节为非规范性内容。

本规范定义的编解码器接口设计为可在前一个任务仍在等待时调度新的编解码器任务。例如,Web 作者可以在前一次 decode() 尚未完成时调用 decode()。这通过将底层编解码器任务卸载到单独的 并行队列以并行执行来实现。

本节描述了 Web 作者可见的线程行为。实现者可选择使用更多线程,只要外部可见的阻塞和顺序行为如下所述得以保持。

2.2. 控制消息

控制消息 指的是与 编解码器实例上的方法调用(如 encode())相关的一系列步骤。

控制消息队列是一个 队列, 包含 控制消息。每个 编解码器实例都有一个存储在名为 [[control message queue]] 的内部插槽中的控制消息队列。

队列控制消息指将消息 入队编解码器[[control message queue]]。调用编解码器方法通常会将控制消息入队以调度工作。

运行控制消息指执行由入队该消息的方法指定的一系列步骤。

某个控制消息的步骤可能会阻塞控制消息队列中后续消息的处理。每个 编解码器实例都有一个名为 [[message queue blocked]] 的布尔型内部插槽,在发生阻塞时设为 true。阻塞消息结束时会将 [[message queue blocked]] 设为 false,并重新运行 处理控制消息队列步骤。

所有控制消息将返回 "processed""not processed"。 返回 "processed" 表示消息步骤正在(或已)执行,消息可从 控制消息队列中移除。 "not processed" 表示此时不能处理该消息,应保留在 控制消息队列中以便稍后重试。

处理控制消息队列,请执行以下步骤:

  1. [[message queue blocked]]false[[control message queue]] 非空时:

    1. front message[[control message queue]] 中的第一个消息。

    2. outcome 为运行 控制消息步骤 所得结果。

    3. 如果 outcome 等于 "not processed",则跳出循环。

    4. 否则,将 front message[[control message queue]] 中移除。

2.3. 编解码器并行队列

每个 编解码器实例都有一个名为 [[codec work queue]] 的内部插槽, 它是一个 并行队列

每个 编解码器实例都有一个名为 [[codec implementation]] 的内部插槽,指向底层平台编码器或解码器。除初始赋值外,任何引用 [[codec implementation]] 的步骤都将入队到 [[codec work queue]]

每个 编解码器实例都有唯一的 编解码器任务源。 从 队列任务[[codec work queue]]再到 事件循环时, 都会使用 编解码器任务源

3. AudioDecoder 接口

[Exposed=(Window,DedicatedWorker), SecureContext]
interface AudioDecoder : EventTarget {
  constructor(AudioDecoderInit init);

  readonly attribute CodecState state;
  readonly attribute unsigned long decodeQueueSize;
  attribute EventHandler ondequeue;

  undefined configure(AudioDecoderConfig config);
  undefined decode(EncodedAudioChunk chunk);
  Promise<undefined> flush();
  undefined reset();
  undefined close();

  static Promise<AudioDecoderSupport> isConfigSupported(AudioDecoderConfig config);
};

dictionary AudioDecoderInit {
  required AudioDataOutputCallback output;
  required WebCodecsErrorCallback error;
};

callback AudioDataOutputCallback = undefined(AudioData output);

3.1. 内部插槽

[[control message queue]]

一个 队列, 包含要在此 编解码器实例上执行的 控制消息。 参见 [[control message queue]]

[[message queue blocked]]

一个布尔值,指示处理 [[control message queue]] 时是否被待处理的 控制消息阻塞。 参见 [[message queue blocked]]

[[codec implementation]]

由用户代理提供的底层解码器实现。参见 [[codec implementation]]

[[codec work queue]]

一个 并行队列,用于运行引用 [[codec implementation]] 的并行步骤。 参见 [[codec work queue]]

[[codec saturated]]

一个布尔值,指示 [[codec implementation]] 是否无法接受更多解码工作。

[[output callback]]

构造时传入的解码输出回调。

[[error callback]]

构造时传入的解码错误回调。

[[key chunk required]]

一个布尔值,指示下一个传递给 decode() 的 chunk 必须 描述为 关键块,由 [[type]] 指示。

[[state]]

AudioDecoder 的当前 CodecState

[[decodeQueueSize]]

待处理解码请求的数量。该数值会在底层编解码器准备接受新输入时减少。

[[pending flush promises]]

由调用 flush() 返回的未解决 promise 列表。

[[dequeue event scheduled]]

一个布尔值,指示 dequeue 事件是否已安排触发。用于避免事件刷屏。

3.2. 构造函数

AudioDecoder(init)
  1. 令 d 为一个新的 AudioDecoder 对象。

  2. [[control message queue]] 分配一个新的 队列

  3. [[message queue blocked]] 赋值 false

  4. [[codec implementation]] 赋值 null

  5. [[codec work queue]] 赋值为新启动的 并行队列

  6. [[codec saturated]] 赋值 false

  7. [[output callback]] 赋值 init.output。

  8. [[error callback]] 赋值 init.error。

  9. [[key chunk required]] 赋值 true

  10. [[state]] 赋值 "unconfigured"

  11. [[decodeQueueSize]] 赋值 0

  12. [[pending flush promises]] 分配一个新的 列表

  13. [[dequeue event scheduled]] 赋值 false

  14. 返回 d。

3.3. 属性

state, 类型为 CodecState,只读

返回 [[state]] 的值。

decodeQueueSize, 类型为 unsigned long,只读

返回 [[decodeQueueSize]] 的值。

ondequeue, 类型为 EventHandler

一个 事件处理 IDL 属性,其 事件类型dequeue

3.4. 事件概述

dequeue

AudioDecoderdecodeQueueSize 减少时触发。

3.5. 方法

configure(config)
入队一个控制消息,用于根据 config 的描述配置音频解码器以解码数据块。

注意:如果 User Agent 不支持 config,此方法会触发 NotSupportedError。 建议作者在调用本方法前,先通过 isConfigSupported() 检查支持情况。 User Agent 不需要支持任何特定的编解码类型或配置。

调用时,执行以下步骤:

  1. 如果 config 不是一个 有效的 AudioDecoderConfig,则抛出 TypeError

  2. 如果 [[state]]“closed”,则抛出 InvalidStateError

  3. [[state]] 设为 "configured"

  4. [[key chunk required]] 设为 true

  5. 入队一个控制消息,用 config 配置解码器。

  6. 处理控制消息队列

运行控制消息以配置解码器时,执行以下步骤:

  1. true 赋值给 [[message queue blocked]]

  2. 将以下步骤入队到 [[codec work queue]]

    1. supported 为使用 config 运行 检查配置支持算法的结果。

    2. 如果 supportedfalse入队一个任务,运行 关闭 AudioDecoder算法,并传入 NotSupportedError,然后中止这些步骤。

    3. 如有需要,将 [[codec implementation]] 赋值为支持 config 的实现。

    4. config 配置 [[codec implementation]]

    5. 入队一个任务,执行以下步骤:

      1. false 赋值给 [[message queue blocked]]

      2. 入队一个任务处理控制消息队列

  3. 返回 "processed"

decode(chunk)
入队一个控制消息,用于解码给定的 chunk

调用时,执行以下步骤:

  1. 如果 [[state]] 不为 "configured",则抛出 InvalidStateError

  2. 如果 [[key chunk required]]true

    1. 如果 chunk.[[type]] 不为 key, 则抛出 DataError

    2. 实现者 建议检查 chunk[[internal data]] ,以验证其确实为 key chunk。如发现不匹配,则抛出 DataError

    3. 否则,将 false 赋值给 [[key chunk required]]

  3. 递增 [[decodeQueueSize]]

  4. 入队一个控制消息,用于解码 chunk

  5. 处理控制消息队列

运行控制消息以解码数据块时,执行以下步骤:

  1. 如果 [[codec saturated]] 等于 true,则返回 "not processed"

  2. 如果解码数据块会导致 [[codec implementation]] 变为 饱和,则将 true 赋值给 [[codec saturated]]

  3. 递减 [[decodeQueueSize]],并运行 调度 Dequeue 事件算法。

  4. 将以下步骤入队到 [[codec work queue]]

    1. 尝试使用 [[codec implementation]] 解码数据块。

    2. 如果解码出错,入队一个任务,运行 关闭 AudioDecoder算法,并传入 EncodingError,然后返回。

    3. 如果 [[codec saturated]] 等于 true[[codec implementation]] 不再 饱和入队一个任务,执行以下步骤:

      1. false 赋值给 [[codec saturated]]

      2. 处理控制消息队列

    4. decoded outputs 为由 [[codec implementation]] 产生的解码音频数据输出的 列表

    5. 如果 decoded outputs 非空,入队一个任务,运行 输出 AudioData算法,并传入 decoded outputs

  5. 返回 "processed"

flush()
完成 控制消息队列中的所有消息,并输出所有结果。

调用时,执行以下步骤:

  1. 如果 [[state]] 不为 "configured",则返回 一个被拒绝的 promise,错误为 InvalidStateError DOMException

  2. [[key chunk required]] 设为 true

  3. promise 为一个新的 Promise。

  4. promise 添加到 [[pending flush promises]]

  5. 入队一个控制消息,用 promise 刷新编解码器。

  6. 处理控制消息队列

  7. 返回 promise

运行控制消息以刷新编解码器时,使用 promise 执行以下步骤:

  1. 将以下步骤入队到 [[codec work queue]]

    1. 通知 [[codec implementation]] 输出所有 内部待输出数据。

    2. decoded outputs 为由 [[codec implementation]] 产生的解码音频数据输出的 列表

    3. 入队一个任务,执行以下步骤:

      1. 如果 decoded outputs 非空,运行 输出 AudioData 算法,并传入 decoded outputs

      2. [[pending flush promises]] 中移除 promise

      3. 解决 promise

  2. 返回 "processed"

reset()
立即重置所有状态,包括配置、控制消息队列中的消息,以及所有待处理的回调。

调用时,使用 AbortError DOMException,运行 重置 AudioDecoder算法。

close()
立即中止所有待处理工作并释放 系统资源。 关闭操作是最终的。

调用时,使用 AbortError DOMException,运行 关闭 AudioDecoder算法。

isConfigSupported(config)
返回一个 promise,指示 User Agent 是否支持所提供的 config

注意:返回的 AudioDecoderSupport config 只包含 User Agent 识别的字典成员。未识别的成员将被忽略。作者可通过比较 config 与其提供的 config 来检测未识别的成员。

调用时,执行以下步骤:

  1. 如果 config 不是一个 有效的 AudioDecoderConfig,则返回 一个被拒绝的 promise,错误为 TypeError

  2. p 为一个新的 Promise。

  3. checkSupportQueue 为新启动的 并行队列

  4. 将以下步骤入队到 checkSupportQueue

    1. supported 为使用 config 运行 检查配置支持算法的结果。

    2. 入队一个任务,执行以下步骤:

      1. decoderSupport 为新构造的 AudioDecoderSupport, 初始化如下:

        1. config 设为使用 config 运行 克隆配置算法的结果。

        2. supported 设为 supported

      2. decoderSupport 解决 p

  5. 返回 p

3.6. 算法

调度 Dequeue 事件
  1. 如果 [[dequeue event scheduled]] 等于 true,则返回。

  2. true 赋值给 [[dequeue event scheduled]]

  3. 入队一个任务,执行以下步骤:

    1. this 上触发一个名为 dequeue 的简单事件。

    2. false 赋值给 [[dequeue event scheduled]]

输出 AudioData (with outputs)
执行以下步骤:
  1. 对于 outputs 中的每个 output

    1. data 为一个 AudioData, 按如下方式初始化:

      1. false 赋值给 [[Detached]]

      2. resourceoutput 描述的 媒体资源

      3. resourceReferenceresource 的引用。

      4. resourceReference 赋值给 [[resource reference]]

      5. timestamp 为与 output 关联的 EncodedAudioChunk[[timestamp]]

      6. timestamp 赋值给 [[timestamp]]

      7. 如果 output 使用已识别的 AudioSampleFormat, 则将该格式赋值给 [[format]]; 否则,将 null 赋值给 [[format]]

      8. 根据 output,为 [[sample rate]][[number of frames]][[number of channels]] 赋值。

    2. data 调用 [[output callback]]

重置 AudioDecoder (with exception)
执行以下步骤:
  1. 如果 [[state]]"closed",则抛出 InvalidStateError

  2. [[state]] 设为 "unconfigured"

  3. 通知 [[codec implementation]] 停止为之前的配置产生输出。

  4. [[control message queue]] 中移除所有 控制消息

  5. 如果 [[decodeQueueSize]] 大于零:

    1. [[decodeQueueSize]] 设为零。

    2. 运行 调度 Dequeue 事件算法。

  6. 对于 [[pending flush promises]] 中的每个 promise

    1. exception 拒绝 promise

    2. [[pending flush promises]] 中移除 promise

关闭 AudioDecoder (with exception)
执行以下步骤:
  1. exception 运行 重置 AudioDecoder算法。

  2. [[state]] 设为 "closed"

  3. 清空 [[codec implementation]] 并释放相关的 系统资源

  4. 如果 exception 不是 AbortError DOMException, 用 exception 调用 [[error callback]]

4. VideoDecoder 接口

[Exposed=(Window,DedicatedWorker), SecureContext]
interface VideoDecoder : EventTarget {
  constructor(VideoDecoderInit init);

  readonly attribute CodecState state;
  readonly attribute unsigned long decodeQueueSize;
  attribute EventHandler ondequeue;

  undefined configure(VideoDecoderConfig config);
  undefined decode(EncodedVideoChunk chunk);
  Promise<undefined> flush();
  undefined reset();
  undefined close();

  static Promise<VideoDecoderSupport> isConfigSupported(VideoDecoderConfig config);
};

dictionary VideoDecoderInit {
  required VideoFrameOutputCallback output;
  required WebCodecsErrorCallback error;
};

callback VideoFrameOutputCallback = undefined(VideoFrame output);

4.1. 内部插槽

[[control message queue]]

一个 队列,用于存放将在此 codec 实例上执行的 控制消息。详见 [[control message queue]]

[[message queue blocked]]

一个布尔值,指示处理 [[control message queue]] 时是否被待处理的 控制消息阻塞。详见 [[message queue blocked]]

[[codec implementation]]

User Agent 提供的底层解码器实现。详见 [[codec implementation]]

[[codec work queue]]

一个 并行队列,用于运行引用 [[codec implementation]] 的并行步骤。详见 [[codec work queue]]

[[codec saturated]]

一个布尔值,指示 [[codec implementation]] 是否无法接受更多解码工作。

[[output callback]]

构造时传入的解码输出回调。

[[error callback]]

构造时传入的解码错误回调。

[[active decoder config]]

当前应用的 VideoDecoderConfig

[[key chunk required]]

一个布尔值,指示下一个传递给 decode() 的数据块 必须key chunk,由 type 指示。

[[state]]

VideoDecoder 的当前 CodecState

[[decodeQueueSize]]

待处理解码请求的数量。该数值会在底层编解码器准备好接受新输入时减少。

[[pending flush promises]]

由调用 flush() 返回的未解决 promise 列表。

[[dequeue event scheduled]]

一个布尔值,指示是否已安排触发 dequeue 事件。用于避免事件泛滥。

4.2. 构造函数

VideoDecoder(init)
  1. 令 d 为一个新的 VideoDecoder 对象。

  2. [[control message queue]] 分配一个新的 队列

  3. [[message queue blocked]] 赋值 false

  4. [[codec implementation]] 赋值 null

  5. [[codec work queue]] 分配一个新启动的 并行队列

  6. [[codec saturated]] 赋值 false

  7. [[output callback]] 赋值 init.output。

  8. [[error callback]] 赋值 init.error。

  9. [[active decoder config]] 赋值 null

  10. [[key chunk required]] 赋值 true

  11. [[state]] 赋值 "unconfigured"

  12. [[decodeQueueSize]] 赋值 0

  13. [[pending flush promises]] 分配一个新的 列表

  14. [[dequeue event scheduled]] 赋值 false

  15. 返回 d。

4.3. 属性

state, 类型为 CodecState,只读

返回 [[state]] 的值。

decodeQueueSize, 类型为 unsigned long,只读

返回 [[decodeQueueSize]] 的值。

ondequeue, 类型为 EventHandler

一个 事件处理 IDL 属性,其 事件类型dequeue

4.4. 事件概述

dequeue

VideoDecoderdecodeQueueSize 减少时触发。

4.5. 方法

configure(config)
入队一个控制消息,用于根据 config 的描述配置视频解码器以解码数据块。

注意:如果 User Agent 不支持 config,此方法会触发 NotSupportedError。 建议作者在调用本方法前,先通过 isConfigSupported() 检查支持情况。 User Agent 不需要支持任何特定的编解码类型或配置。

调用时,执行以下步骤:

  1. 如果 config 不是一个 有效的 VideoDecoderConfig,则抛出 TypeError

  2. 如果 [[state]]“closed”,则抛出 InvalidStateError

  3. [[state]] 设为 "configured"

  4. [[key chunk required]] 设为 true

  5. 入队一个控制消息,用 config 配置解码器。

  6. 处理控制消息队列

运行控制消息以配置解码器时,执行以下步骤:

  1. true 赋值给 [[message queue blocked]]

  2. 将以下步骤入队到 [[codec work queue]]

    1. supported 为使用 config 运行 检查配置支持算法的结果。

    2. 如果 supportedfalse入队一个任务,运行 关闭 VideoDecoder算法,并传入 NotSupportedError,然后中止这些步骤。

    3. 如有需要,将 [[codec implementation]] 赋值为支持 config 的实现。

    4. config 配置 [[codec implementation]]

    5. 入队一个任务,执行以下步骤:

      1. false 赋值给 [[message queue blocked]]

      2. 入队一个任务处理控制消息队列

  3. 返回 "processed"

decode(chunk)
入队一个控制消息,用于解码给定的 chunk

注意:建议作者在输出的 VideoFrame 不再需要时立即调用 close()。底层 媒体资源VideoDecoder 所有,未及时释放(或等待垃圾回收)可能导致解码阻塞。

注意:VideoDecoder 要求帧按预期展示顺序输出(即 presentation order)。某些 [[codec implementation]] 下,User Agent 需将输出重新排序为展示顺序。

调用时,执行以下步骤:

  1. 如果 [[state]] 不为 "configured",则抛出 InvalidStateError

  2. 如果 [[key chunk required]]true

    1. 如果 chunk.type 不为 key, 则抛出 DataError

    2. 实现者 建议检查 chunk[[internal data]] ,以验证其确实为 key chunk。如发现不匹配,则抛出 DataError

    3. 否则,将 false 赋值给 [[key chunk required]]

  3. 递增 [[decodeQueueSize]]

  4. 入队一个控制消息,用于解码 chunk

  5. 处理控制消息队列

运行控制消息以解码数据块时,执行以下步骤:

  1. 如果 [[codec saturated]] 等于 true,则返回 "not processed"

  2. 如果解码数据块会导致 [[codec implementation]] 变为 饱和,则将 true 赋值给 [[codec saturated]]

  3. 递减 [[decodeQueueSize]],并运行 调度 Dequeue 事件算法。

  4. 将以下步骤入队到 [[codec work queue]]

    1. 尝试使用 [[codec implementation]] 解码数据块。

    2. 如果解码出错,入队一个任务,运行 关闭 VideoDecoder算法,并传入 EncodingError,然后返回。

    3. 如果 [[codec saturated]] 等于 true[[codec implementation]] 不再 饱和入队一个任务,执行以下步骤:

      1. false 赋值给 [[codec saturated]]

      2. 处理控制消息队列

    4. decoded outputs 为由 [[codec implementation]] 产生的解码视频数据输出的 列表(按展示顺序)。

    5. 如果 decoded outputs 非空,入队一个任务,运行 输出 VideoFrame算法,并传入 decoded outputs

  5. 返回 "processed"

flush()
完成 控制消息队列中的所有消息,并输出所有结果。

调用时,执行以下步骤:

  1. 如果 [[state]] 不为 "configured",则返回 一个被拒绝的 promise,错误为 InvalidStateError DOMException

  2. [[key chunk required]] 设为 true

  3. promise 为一个新的 Promise。

  4. promise 添加到 [[pending flush promises]]

  5. 入队一个控制消息,用 promise 刷新编解码器。

  6. 处理控制消息队列

  7. 返回 promise

运行控制消息以刷新编解码器时,使用 promise 执行以下步骤:

  1. 将以下步骤入队到 [[codec work queue]]

    1. 通知 [[codec implementation]] 输出所有 内部待输出数据。

    2. decoded outputs 为由 [[codec implementation]] 产生的解码视频数据输出的 列表

    3. 入队一个任务,执行以下步骤:

      1. 如果 decoded outputs 非空,运行 输出 VideoFrame 算法,并传入 decoded outputs

      2. [[pending flush promises]] 中移除 promise

      3. 解决 promise

  2. 返回 "processed"

reset()
立即重置所有状态,包括配置、控制消息队列中的消息,以及所有待处理的回调。

调用时,使用 AbortError DOMException,运行 重置 VideoDecoder算法。

close()
立即中止所有待处理工作并释放 系统资源。 关闭操作是最终的。

调用时,使用 AbortError DOMException,运行 关闭 VideoDecoder算法。

isConfigSupported(config)
返回一个 promise,指示 User Agent 是否支持所提供的 config

注意:返回的 VideoDecoderSupport config 只包含 User Agent 识别的字典成员。未识别的成员将被忽略。作者可通过比较 config 与其提供的 config 来检测未识别的成员。

调用时,执行以下步骤:

  1. 如果 config 不是一个 有效的 VideoDecoderConfig,则返回 一个被拒绝的 promise,错误为 TypeError

  2. p 为一个新的 Promise。

  3. checkSupportQueue 为新启动的 并行队列

  4. 将以下步骤入队到 checkSupportQueue

    1. supported 为使用 config 运行 检查配置支持算法的结果。

    2. 入队一个任务,执行以下步骤:

      1. decoderSupport 为新构造的 VideoDecoderSupport, 初始化如下:

        1. config 设为使用 config 运行 克隆配置算法的结果。

        2. supported 设为 supported

      2. decoderSupport 解决 p

  5. 返回 p

4.6. 算法

调度出队事件
  1. 如果 [[dequeue event scheduled]] 等于 true,则返回。

  2. true 赋值给 [[dequeue event scheduled]]

  3. 队列一个任务以运行以下步骤:

    1. this 上触发一个名为 dequeue 的简单事件。

    2. false 赋值给 [[dequeue event scheduled]]

输出 VideoFrames (带 outputs)
执行以下步骤:
  1. 对于 outputs 中的每个 output

    1. timestampduration 为与 output 关联的 timestampduration

    2. displayAspectWidthdisplayAspectHeight 为未定义。

    3. 如果 displayAspectWidthdisplayAspectHeight 存在[[active decoder config]], 则分别将其值赋给 displayAspectWidthdisplayAspectHeight

    4. colorSpace 为编解码器实现检测到的 VideoColorSpace。 如果未检测到 VideoColorSpace, 则令 colorSpaceundefined

      注意: 编解码器实现可以通过分析比特流检测 VideoColorSpace。 检测是尽力而为,具体方法由实现者定义且与编解码器相关。作者可以通过在 VideoDecoderConfig 中提供 colorSpace 来覆盖检测到的 VideoColorSpace

    5. 如果 colorSpace 存在[[active decoder config]], 则将其值赋给 colorSpace

    6. rotationflip 的值分别赋给 rotationflip

    7. frame 为使用 outputtimestampdurationdisplayAspectWidthdisplayAspectHeightcolorSpacerotationflip 运行 创建 VideoFrame 算法的结果。

    8. frame 调用 [[output callback]]

重置 VideoDecoder (带 exception)
执行以下步骤:
  1. 如果 state"closed",则抛出 InvalidStateError

  2. state 设为 "unconfigured"

  3. 通知 [[codec implementation]] 停止为先前配置产生输出。

  4. [[control message queue]] 中移除所有 控制消息

  5. 如果 [[decodeQueueSize]] 大于零:

    1. [[decodeQueueSize]] 设为零。

    2. 运行 调度出队事件算法。

  6. 对于 [[pending flush promises]] 中的每个 promise

    1. exception 拒绝 promise

    2. [[pending flush promises]] 中移除 promise

关闭 VideoDecoder (带 exception)
执行以下步骤:
  1. exception 运行 重置 VideoDecoder算法。

  2. state 设为 "closed"

  3. 清除 [[codec implementation]] 并释放相关 系统资源

  4. 如果 exception 不是 AbortError DOMException, 则用 exception 调用 [[error callback]]

5. AudioEncoder 接口

[Exposed=(Window,DedicatedWorker), SecureContext]
        interface AudioEncoder : EventTarget {
          constructor(AudioEncoderInit init);
        
          readonly attribute CodecState state;
          readonly attribute unsigned long encodeQueueSize;
          attribute EventHandler ondequeue;
        
          undefined configure(AudioEncoderConfig config);
          undefined encode(AudioData data);
          Promise<undefined> flush();
          undefined reset();
          undefined close;
        
          static Promise<AudioEncoderSupport> isConfigSupported(AudioEncoderConfig config);
        };
        
        dictionary AudioEncoderInit {
          required EncodedAudioChunkOutputCallback output;
          required WebCodecsErrorCallback error;
        };
        
        callback EncodedAudioChunkOutputCallback =
            undefined (EncodedAudioChunk output,
                       optional EncodedAudioChunkMetadata metadata = {});
        

5.1. 内部插槽

[[control message queue]]

一个 队列, 包含要在此 编解码器实例上执行的 控制消息。 参见 [[control message queue]]

[[message queue blocked]]

一个布尔值,指示当有待处理的 [[control message queue]] 时,处理队列是否被阻塞。 参见 [[message queue blocked]]

[[codec implementation]]

由用户代理提供的底层编码器实现。参见 [[codec implementation]]

[[codec work queue]]

一个 并行队列,用于运行引用 [[codec implementation]] 的并行步骤。 参见 [[codec work queue]]

[[codec saturated]]

一个布尔值,指示 [[codec implementation]] 是否无法接受更多编码工作。

[[output callback]]

构造时提供的用于编码输出的回调。

[[error callback]]

构造时提供的用于编码错误的回调。

[[active encoder config]]

当前应用的 AudioEncoderConfig

[[active output config]]

描述如何解码最近发出的 EncodedAudioChunkAudioDecoderConfig

[[state]]

AudioEncoder 的当前 CodecState

[[encodeQueueSize]]

待处理编码请求的数量。该数值会随着底层编解码器准备好接受新输入而减少。

[[pending flush promises]]

由调用 flush() 返回的未解决 promise 列表。

[[dequeue event scheduled]]

一个布尔值,指示是否已经安排了 dequeue 事件。用于避免事件泛滥。

5.2. 构造函数

AudioEncoder(init)
  1. 令 e 为一个新的 AudioEncoder 对象。

  2. [[control message queue]] 赋值为一个新的 队列

  3. false 赋值给 [[message queue blocked]]

  4. null 赋值给 [[codec implementation]]

  5. 将启动一个新的 并行队列的结果赋值给 [[codec work queue]]

  6. false 赋值给 [[codec saturated]]

  7. 将 init.output 赋值给 [[output callback]]

  8. 将 init.error 赋值给 [[error callback]]

  9. null 赋值给 [[active encoder config]]

  10. null 赋值给 [[active output config]]

  11. "unconfigured" 赋值给 [[state]]

  12. 0 赋值给 [[encodeQueueSize]]

  13. [[pending flush promises]] 赋值为一个新的 列表

  14. false 赋值给 [[dequeue event scheduled]]

  15. 返回 e。

5.3. 属性

state, 类型为 CodecState,只读

返回 [[state]] 的值。

encodeQueueSize, 类型为 unsigned long,只读

返回 [[encodeQueueSize]] 的值。

ondequeue, 类型为 EventHandler

一个 事件处理器 IDL 属性,其 事件处理器事件类型dequeue

5.4. 事件摘要

dequeue

AudioEncoderencodeQueueSize 减少时触发。

5.5. 方法

configure(config)
入队一个控制消息,用于根据 config 配置音频编码器以编码音频数据。

注意: 如果用户代理不支持 config,此方法会触发 NotSupportedError。 建议作者在调用 isConfigSupported() 并传入 config 以先检查支持情况。 用户代理不必支持任何特定的编解码器类型或配置。

调用时,执行以下步骤:

  1. 如果 config 不是一个 有效的 AudioEncoderConfig,则抛出 TypeError

  2. 如果 [[state]]"closed",则抛出 InvalidStateError

  3. [[state]] 设为 "configured"

  4. 入队一个控制消息,用 config 配置编码器。

  5. 处理控制消息队列

运行控制消息以配置编码器时,执行以下步骤:

  1. true 赋值给 [[message queue blocked]]

  2. 将以下步骤入队到 [[codec work queue]]

    1. supported 为用 config 运行 检查配置支持算法的结果。

    2. 如果 supportedfalse队列一个任务,用 NotSupportedError 运行 关闭 AudioEncoder 算法,并中止这些步骤。

    3. 如有需要,将支持 config 的实现赋值给 [[codec implementation]]

    4. config 配置 [[codec implementation]]

    5. 队列一个任务,执行以下步骤:

      1. false 赋值给 [[message queue blocked]]

      2. 队列一个任务处理控制消息队列

  3. 返回 "processed"

encode(data)
入队一个控制消息,用于编码给定的 data

调用时,执行以下步骤:

  1. 如果 data[[Detached]] 内部插槽值为 true,则抛出 TypeError

  2. 如果 [[state]] 不为 "configured",则抛出 InvalidStateError

  3. dataClone 为用 data 运行 克隆 AudioData算法的结果。

  4. 递增 [[encodeQueueSize]]

  5. 入队一个控制消息,用于编码 dataClone

  6. 处理控制消息队列

运行控制消息以编码数据时,执行以下步骤:

  1. 如果 [[codec saturated]] 等于 true,则返回 "not processed"

  2. 如果编码 data 会导致 [[codec implementation]] 变为 饱和,则将 true 赋值给 [[codec saturated]]

  3. 递减 [[encodeQueueSize]], 并运行 调度出队事件算法。

  4. 将以下步骤入队到 [[codec work queue]]

    1. 尝试使用 [[codec implementation]] 编码由 dataClone 描述的 媒体资源

    2. 如果编码出错,队列一个任务,用 EncodingError 运行 关闭 AudioEncoder算法并返回。

    3. 如果 [[codec saturated]] 等于 true[[codec implementation]] 不再 饱和队列一个任务,执行以下步骤:

      1. false 赋值给 [[codec saturated]]

      2. 处理控制消息队列

    4. encoded outputs 为由 [[codec implementation]] 发出的编码音频数据输出的 列表

    5. 如果 encoded outputs 非空,队列一个任务,用 encoded outputs 运行 输出 EncodedAudioChunks算法。

  5. 返回 "processed"

flush()
完成 控制消息队列中的所有控制消息,并发出所有输出。

调用时,执行以下步骤:

  1. 如果 [[state]] 不为 "configured",则返回 一个被拒绝的 promise,原因为 InvalidStateError DOMException

  2. promise 为一个新的 Promise。

  3. promise 添加到 [[pending flush promises]]

  4. 入队一个控制消息,用 promise 刷新编解码器。

  5. 处理控制消息队列

  6. 返回 promise

运行控制消息以刷新编解码器时,使用 promise 执行以下步骤:

  1. 将以下步骤入队到 [[codec work queue]]

    1. 通知 [[codec implementation]] 发出所有 内部待输出

    2. encoded outputs 为由 [[codec implementation]] 发出的编码音频数据输出的 列表

    3. 队列一个任务,执行以下步骤:

      1. 如果 encoded outputs 非空,则用 encoded outputs 运行 输出 EncodedAudioChunks算法。

      2. [[pending flush promises]] 中移除 promise

      3. 解决 promise

  2. 返回 "processed"

reset()
立即重置所有状态,包括配置、控制消息队列中的控制消息,以及所有待处理的回调。

调用时,使用 AbortError DOMException,运行 重置 AudioEncoder算法。

close()
立即中止所有待处理工作并释放系统资源。 关闭操作是最终的。

调用时,使用 AbortError DOMException,运行 关闭 AudioEncoder算法。

isConfigSupported(config)
返回一个 promise,指示用户代理是否支持所提供的 config

注意: 返回的 AudioEncoderSupport config 只包含用户代理识别的字典成员。未识别的字典成员将被忽略。作者可通过比较 config 与其提供的 config 来检测未识别的成员。

调用时,执行以下步骤:

  1. 如果 config 不是一个 有效的 AudioEncoderConfig,则返回 一个被拒绝的 promise,原因为 TypeError

  2. p 为一个新的 Promise。

  3. checkSupportQueue 为启动一个新的 并行队列的结果。

  4. 将以下步骤入队到 checkSupportQueue

    1. supported 为用 config 运行 检查配置支持算法的结果。

    2. 队列一个任务,执行以下步骤:

      1. encoderSupport 为新构造的 AudioEncoderSupport, 初始化如下:

        1. config 设为用 config 运行 克隆配置算法的结果。

        2. supported 设为 supported

      2. encoderSupport 解决 p

  5. 返回 p

5.6. 算法

调度出队事件
  1. 如果 [[dequeue event scheduled]] 等于 true,则返回。

  2. true 赋值给 [[dequeue event scheduled]]

  3. 队列一个任务以运行以下步骤:

    1. this 上触发一个名为 dequeue 的简单事件。

    2. false 赋值给 [[dequeue event scheduled]]

输出 EncodedAudioChunks (带 outputs)
执行以下步骤:
  1. 对于 outputs 中的每个 output

    1. chunkInit 为一个 EncodedAudioChunkInit ,包含以下键:

      1. data 包含来自 output 的编码音频数据。

      2. typeoutputEncodedAudioChunkType

      3. timestamp 为与 output 关联的 AudioData 的 timestamp

      4. duration 为与 output 关联的 AudioData 的 duration

    2. chunk 为用 chunkInit 构造的新 EncodedAudioChunk

    3. chunkMetadata 为一个新的 EncodedAudioChunkMetadata

    4. encoderConfig[[active encoder config]]

    5. outputConfig 为一个新的 AudioDecoderConfig, 用于描述 output。初始化 outputConfig 如下:

      1. encoderConfig.codec 赋值给 outputConfig.codec

      2. encoderConfig.sampleRate 赋值给 outputConfig.sampleRate

      3. encoderConfig.numberOfChannels 赋值给 outputConfig.numberOfChannels

      4. 用由 [[codec implementation]] 决定的一系列编解码器特定字节赋值给 outputConfig.description。 用户代理 必须确保所提供的 description 可用于正确解码输出。

        注意: 填充 description 的编解码器特定要求见 [WEBCODECS-CODEC-REGISTRY]

    6. 如果 outputConfig[[active output config]] 不是 等价字典

      1. outputConfig 赋值给 chunkMetadata.decoderConfig

      2. outputConfig 赋值给 [[active output config]]

    7. chunkchunkMetadata 调用 [[output callback]]

重置 AudioEncoder (带 exception)
执行以下步骤:
  1. 如果 [[state]]"closed",则抛出 InvalidStateError

  2. [[state]] 设为 "unconfigured"

  3. [[active encoder config]] 设为 null

  4. [[active output config]] 设为 null

  5. 通知 [[codec implementation]] 停止为先前配置产生输出。

  6. [[control message queue]] 中移除所有 控制消息

  7. 如果 [[encodeQueueSize]] 大于零:

    1. [[encodeQueueSize]] 设为零。

    2. 运行 调度出队事件算法。

  8. 对于 [[pending flush promises]] 中的每个 promise

    1. exception 拒绝 promise

    2. [[pending flush promises]] 中移除 promise

关闭 AudioEncoder (带 exception)
执行以下步骤:
  1. exception 运行 重置 AudioEncoder算法。

  2. [[state]] 设为 "closed"

  3. 清除 [[codec implementation]] 并释放相关 系统资源

  4. 如果 exception 不是 AbortError DOMException, 则用 exception 调用 [[error callback]]

5.7. EncodedAudioChunkMetadata

以下元数据字典由 EncodedAudioChunkOutputCallback 与相关的 EncodedAudioChunk 一同发出。
dictionary EncodedAudioChunkMetadata {
          AudioDecoderConfig decoderConfig;
        };
        
decoderConfig, 类型为 AudioDecoderConfig

一个 AudioDecoderConfig ,作者 可以 用于解码相关的 EncodedAudioChunk

6. VideoEncoder 接口

[Exposed=(Window,DedicatedWorker), SecureContext]
interface VideoEncoder : EventTarget {
  constructor(VideoEncoderInit init);

  readonly attribute CodecState state;
  readonly attribute unsigned long encodeQueueSize;
  attribute EventHandler ondequeue;

  undefined configure(VideoEncoderConfig config);
  undefined encode(VideoFrame frame, optional VideoEncoderEncodeOptions options = {});
  Promise<undefined> flush();
  undefined reset();
  undefined close();

  static Promise<VideoEncoderSupport> isConfigSupported(VideoEncoderConfig config);
};

dictionary VideoEncoderInit {
  required EncodedVideoChunkOutputCallback output;
  required WebCodecsErrorCallback error;
};

callback EncodedVideoChunkOutputCallback =
    undefined (EncodedVideoChunk chunk,
               optional EncodedVideoChunkMetadata metadata = {});

6.1. 内部插槽

[[control message queue]]

一个 队列, 包含要在此 编解码器 实例上执行的 控制消息。 参见 [[control message queue]]

[[message queue blocked]]

一个布尔值,指示处理 [[control message queue]] 时是否被待处理的 控制消息 阻塞。 参见 [[message queue blocked]]

[[codec implementation]]

由用户代理提供的底层编码器实现。参见 [[codec implementation]]

[[codec work queue]]

一个 并行队列,用于运行引用 [[codec implementation]] 的并行步骤。 参见 [[codec work queue]]

[[codec saturated]]

一个布尔值,指示 [[codec implementation]] 无法接受更多编码工作时的状态。

[[output callback]]

在构造时提供的用于处理编码输出的回调。

[[error callback]]

在构造时提供的用于处理编码错误的回调。

[[active encoder config]]

当前生效的 VideoEncoderConfig

[[active output config]]

用于描述如何解码最近发出的 EncodedVideoChunkVideoDecoderConfig

[[state]]

VideoEncoder 的当前 CodecState

[[encodeQueueSize]]

挂起的编码请求数量。随着底层编解码器准备好接受新输入,此数字会减少。

[[pending flush promises]]

由调用 flush() 返回的未解决 Promise 列表。

[[dequeue event scheduled]]

一个布尔值,指示是否已有 dequeue 事件计划触发。用于避免事件泛滥。

[[active orientation]]

一个整数与布尔值的组合,表示在 configure() 之后第一次传给 encode()VideoFrame[[flip]][[rotation]]

6.2. 构造函数

VideoEncoder(init)
  1. e 为一个新的 VideoEncoder 对象。

  2. [[control message queue]] 分配一个新的 队列

  3. false 赋给 [[message queue blocked]]

  4. null 赋给 [[codec implementation]]

  5. 启动一个新的 parallel queue,并将其结果赋给 [[codec work queue]]

  6. false 赋给 [[codec saturated]]

  7. init.output 赋给 [[output callback]]

  8. init.error 赋给 [[error callback]]

  9. null 赋给 [[active encoder config]]

  10. null 赋给 [[active output config]]

  11. "unconfigured" 赋给 [[state]]

  12. 0 赋给 [[encodeQueueSize]]

  13. [[pending flush promises]] 分配一个新的 列表

  14. false 赋给 [[dequeue event scheduled]]

  15. 返回 e

6.3. 属性

state, of type CodecState, readonly

返回 [[state]] 的值。

encodeQueueSize, of type unsigned long, readonly

返回 [[encodeQueueSize]] 的值。

ondequeue, of type EventHandler

一个 事件处理程序 IDL 属性,其事件类型为 dequeue

6.4. 事件摘要

dequeue

encodeQueueSize 减少时,在 VideoEncoder 上触发。

6.5. 方法

configure(config)
入队一个控制消息,用于按照 config 描述配置视频编码器以对视频帧进行编码。

注意:如果用户代理不支持 config,此方法会抛出 NotSupportedError。 建议作者先通过使用 isConfigSupported() 检查对 config 的支持。用户代理不需要支持任何特定的编码器类型或配置。

调用时,执行以下步骤:

  1. 如果 config 不是一个 有效的 VideoEncoderConfig,则抛出 TypeError

  2. 如果 [[state]]"closed",则抛出 InvalidStateError

  3. [[state]] 设为 "configured"

  4. [[active orientation]] 设为 null

  5. 入队一个控制消息,使用 config 配置编码器。

  6. 处理控制消息队列

运行控制消息 以配置编码器时,需要执行以下步骤:

  1. true 赋给 [[message queue blocked]]

  2. 将以下步骤入队到 [[codec work queue]]

    1. supported 为使用 config 运行 Check Configuration Support 算法的结果。

    2. 如果 supportedfalse,则 排队一个任务 来运行 Close VideoEncoder 算法并带上 NotSupportedError,然后中止这些步骤。

    3. 如有需要,将一个支持 config 的实现赋给 [[codec implementation]]

    4. 使用 config 配置 [[codec implementation]]

    5. 排队一个任务 来运行以下步骤:

      1. false 赋给 [[message queue blocked]]

      2. 排队一个任务处理控制消息队列

  3. 返回 "processed"

encode(frame, options)
入队一个控制消息,用于对给定的 frame 进行编码。

调用时,执行以下步骤:

  1. 如果 frame[[Detached]] 内部插槽的值为 true,则抛出 TypeError

  2. 如果 [[state]] 不是 "configured",则抛出 InvalidStateError

  3. 如果 [[active orientation]] 非空且与 frame[[rotation]][[flip]] 不匹配,则抛出 DataError

  4. 如果 [[active orientation]]null,则将其设为 frame[[rotation]][[flip]]

  5. frameClone 为使用 Clone VideoFrame 算法对 frame 的结果。

  6. [[encodeQueueSize]] 增加。

  7. 入队一个控制消息 来编码 frameClone

  8. 处理控制消息队列

运行控制消息 以编码该帧时,需要执行以下步骤:

  1. 如果 [[codec saturated]] 等于 true,则返回 "not processed"

  2. 如果编码 frame 会导致 [[codec implementation]] 变为 saturated,则将 true 赋给 [[codec saturated]]

  3. [[encodeQueueSize]] 减少,并运行 Schedule Dequeue Event 算法。

  4. 将以下步骤入队到 [[codec work queue]]

    1. 尝试使用 [[codec implementation]] 根据 optionsframeClone 进行编码。

    2. 如果编码导致错误,排队一个任务 来运行 Close VideoEncoder 算法并带上 EncodingError,然后返回。

    3. 如果 [[codec saturated]] 等于 true[[codec implementation]] 不再处于 saturated 状态, 则 排队一个任务 来执行以下步骤:

      1. false 赋给 [[codec saturated]]

      2. 处理控制消息队列

    4. encoded outputs[[codec implementation]] 发出的编码视频数据输出的 列表

    5. 如果 encoded outputs 非空,排队一个任务 来运行 Output EncodedVideoChunks 算法,参数为 encoded outputs

  5. 返回 "processed"

flush()
完成控制消息队列中的所有 控制消息 并输出所有编码产出。

调用时,执行以下步骤:

  1. 如果 [[state]] 不是 "configured",则返回 一个以 InvalidStateError DOMException 被拒绝的 Promise。

  2. promise 为一个新的 Promise。

  3. promise 附加到 [[pending flush promises]]

  4. 入队一个控制消息 来使用 promise 刷新编解码器。

  5. 处理控制消息队列

  6. 返回 promise

运行控制消息 以刷新编解码器时,需对该 promise 执行以下步骤:

  1. 将以下步骤入队到 [[codec work queue]]

    1. 通知 [[codec implementation]] 发出所有内部挂起输出(internal pending outputs)。

    2. encoded outputs[[codec implementation]] 发出的编码视频数据输出的 列表

    3. 排队一个任务 来执行以下步骤:

      1. 如果 encoded outputs 非空,则使用 encoded outputs 运行 Output EncodedVideoChunks 算法。

      2. [[pending flush promises]] 中移除 promise

      3. 解析 promise

  2. 返回 "processed"

reset()
立即重置所有状态,包括配置、控制消息队列中的 控制消息,以及所有挂起的回调。

调用时,使用一个带有 AbortErrorDOMException 来运行 Reset VideoEncoder 算法。

close()
立即中止所有挂起的工作并释放 系统资源。Close 为最终操作。

调用时,使用一个带有 AbortErrorDOMException 来运行 Close VideoEncoder 算法。

isConfigSupported(config)
返回一个 Promise,指示所提供的 config 是否被用户代理支持。

注意:返回的 VideoEncoderSupportconfig 只会包含用户代理识别的字典成员。未识别的字典成员将被忽略。作者可以通过将返回的 config 与自己提供的 config 进行比较以检测未识别的成员。

调用时,执行以下步骤:

  1. 如果 config 不是一个 有效的 VideoEncoderConfig,则返回 一个以 TypeError 被拒绝的 Promise。

  2. p 为一个新的 Promise。

  3. checkSupportQueue 为启动一个新的 parallel queue 的结果。

  4. 将以下步骤入队到 checkSupportQueue

    1. supported 为使用 config 运行 Check Configuration Support 算法的结果。

    2. 排队一个任务 来运行以下步骤:

      1. encoderSupport 为新构造的 VideoEncoderSupport,并按如下方式初始化:

        1. config 设为使用 config 运行 Clone Configuration 算法的结果。

        2. supported 设为 supported

    3. 使用 encoderSupport 解析 p

  5. 返回 p

6.6. 算法

Schedule Dequeue Event
  1. 如果 [[dequeue event scheduled]] 等于 true,则返回。

  2. true 赋给 [[dequeue event scheduled]]

  3. 排队一个任务 来运行以下步骤:

    1. this 上触发名为 dequeue 的简单事件。

    2. false 赋给 [[dequeue event scheduled]]

Output EncodedVideoChunks (with outputs)
运行这些步骤:
  1. 对于 outputs 中的每个 output

    1. chunkInit 为一个 EncodedVideoChunkInit,包含以下键:

      1. data 包含来自 output 的已编码视频数据。

      2. typeoutputEncodedVideoChunkType

      3. timestamp 为与 output 关联的 VideoFrame[[timestamp]]

      4. duration 为与 output 关联的 VideoFrame[[duration]]

    2. chunk 为使用 chunkInit 构造的新 EncodedVideoChunk

    3. chunkMetadata 为新建的 EncodedVideoChunkMetadata

    4. encoderConfig[[active encoder config]]

    5. outputConfig 为描述 output 的一个 VideoDecoderConfig。按如下方式初始化 outputConfig

      1. encoderConfig.codec 赋给 outputConfig.codec

      2. encoderConfig.width 赋给 outputConfig.codedWidth

      3. encoderConfig.height 赋给 outputConfig.codedHeight

      4. encoderConfig.displayWidth 赋给 outputConfig.displayAspectWidth

      5. encoderConfig.displayHeight 赋给 outputConfig.displayAspectHeight

      6. 将与 output 关联的 VideoFrame[[rotation]] 赋给 outputConfig.rotation

      7. 将与 output 关联的 VideoFrame[[flip]] 赋给 outputConfig.flip

      8. [[codec implementation]] 确定的方式,赋值 outputConfig 的其余键。用户代理 MUST 确保该配置被完整描述,以便 outputConfig 可用于正确解码 output

        注意:有关填充 description 的编解码器特定要求,请参见 [WEBCODECS-CODEC-REGISTRY]

    6. 如果 outputConfig[[active output config]] 不是 equal dictionaries

      1. outputConfig 赋给 chunkMetadata.decoderConfig

      2. outputConfig 赋给 [[active output config]]

    7. 如果 encoderConfig.scalabilityMode 描述了多个 temporal layers

      1. svc 为新建的 SvcOutputMetadata 实例。

      2. temporal_layer_id 为描述 output 的 temporal layer 的从零开始的索引。

      3. temporal_layer_id 赋给 svc.temporalLayerId

      4. svc 赋给 chunkMetadata.svc

    8. 如果 encoderConfig.alpha 设置为 "keep"

      1. alphaSideDataoutput 中的编码 alpha 数据。

      2. alphaSideData 赋给 chunkMetadata.alphaSideData

    9. chunkchunkMetadata 调用 [[output callback]]

Reset VideoEncoder (with exception)
运行这些步骤:
  1. 如果 [[state]]"closed",则抛出 InvalidStateError

  2. [[state]] 设为 "unconfigured"

  3. [[active encoder config]] 设为 null

  4. [[active output config]] 设为 null

  5. 通知 [[codec implementation]] 停止为先前配置产生输出。

  6. [[control message queue]] 中移除所有 control messages

  7. 如果 [[encodeQueueSize]] 大于零:

    1. [[encodeQueueSize]] 设为零。

    2. 运行 Schedule Dequeue Event 算法。

  8. 对于 [[pending flush promises]] 中的每个 promise

    1. exception 拒绝 promise

    2. [[pending flush promises]] 中移除 promise

Close VideoEncoder (with exception)
运行这些步骤:
  1. exception 运行 Reset VideoEncoder 算法。

  2. [[state]] 设为 "closed"

  3. 清除 [[codec implementation]] 并释放相关的 system resources

  4. 如果 exception 不是一个带有 AbortErrorDOMException,则用 exception 调用 [[error callback]]

6.7. EncodedVideoChunkMetadata

以下元数据字典由 EncodedVideoChunkOutputCallback 与关联的 EncodedVideoChunk 一并发出。
dictionary EncodedVideoChunkMetadata {
          VideoDecoderConfig decoderConfig;
          SvcOutputMetadata svc;
          BufferSource alphaSideData;
        };
        
        dictionary SvcOutputMetadata {
          unsigned long temporalLayerId;
        };
        
decoderConfig, of type VideoDecoderConfig

一个 VideoDecoderConfig,作者 MAY 使用它来解码关联的 EncodedVideoChunk

svc, of type SvcOutputMetadata

描述该 EncodedVideoChunk 关于已配置的 scalabilityMode 的一组元数据。

alphaSideData, of type BufferSource

一个 BufferSource,包含 EncodedVideoChunk 的额外 alpha 通道数据。

temporalLayerId, of type unsigned long

一个数字,标识关联的 temporal layer,对应于该 EncodedVideoChunk

7. 配置

7.1. 检查配置支持 (with config)

运行这些步骤:
  1. 如果 config.codec 中的 codec string 不是一个 有效的 codec string,或者被用户代理无法识别,则返回 false

  2. 如果 config 是一个 AudioDecoderConfigVideoDecoderConfig, 且用户代理无法提供可以解码 config.codec 中所指示的确切 profile(如有)、level(如有)和约束位(如有)的 codec,则返回 false

  3. 如果 config 是一个 AudioEncoderConfigVideoEncoderConfig

    1. 如果 config.codec 中的 codec string 包含 profile,且用户代理无法提供能够编码该 profile 的 codec,则返回 false

    2. 如果 config.codec 中的 codec string 包含 level,且用户代理无法提供能够编码到小于或等于该 level 的 codec,则返回 false

    3. 如果 config.codec 中的 codec string 包含约束位,且用户代理无法提供能够生成至少与该约束同等受限的编码比特流的 codec,则返回 false

  4. 如果用户代理可以提供一个 codec,以支持 config 的所有条目(包括对未包含键的适用默认值),则返回 true

    注意:类型 AudioDecoderConfigVideoDecoderConfigAudioEncoderConfig、 和 VideoEncoderConfig 各自定义了其配置项和默认值。

    注意:对给定配置的支持可能会因硬件改变(例如外接 GPU 被拔出)或关键硬件资源被耗尽而动态变化。用户代理应基于查询时可用的资源以尽力而为的方式描述支持情况。

  5. 否则,返回 false

7.2. 克隆配置 (with config)

注意:该算法仅会复制用户代理识别为该字典类型一部分的字典成员。

运行这些步骤:

  1. dictTypeconfig 的字典类型。

  2. clonedictType 的一个新的空实例。

  3. 对于在 dictType 上定义的每个字典成员 m

    1. 如果 mconfig 中不存在,则 继续 下一个成员。

    2. 如果 config[m] 是嵌套字典,则将 clone[m] 设为递归运行 Clone Configuration 算法(参数为 config[m]) 的结果。

    3. 否则,将 config[m] 的副本赋给 clone[m]

注意:这实现了“深拷贝”。这些配置对象常被用作异步操作的输入。复制意味着在操作进行中修改原始对象不会改变该操作的结果。

7.3. 指示配置支持

7.3.1. AudioDecoderSupport

dictionary AudioDecoderSupport {
          boolean supported;
          AudioDecoderConfig config;
        };
        
supported, of type boolean
一个布尔值,表示对应的 config 是否被用户代理支持。
config, of type AudioDecoderConfig
一个 AudioDecoderConfig,用户代理用于确定 supported 的值。

7.3.2. VideoDecoderSupport

dictionary VideoDecoderSupport {
  boolean supported;
  VideoDecoderConfig config;
};
supported, 类型为 boolean
一个布尔值,指示对应的 config 是否被用户代理支持。
config, 类型为 VideoDecoderConfig
一个 VideoDecoderConfig ,用户代理用它来确定 supported 的值。

7.3.3. AudioEncoderSupport

dictionary AudioEncoderSupport {
    boolean supported;
    AudioEncoderConfig config;
};
supported, 类型为 boolean
一个布尔值,指示对应的 config 是否被用户代理支持。
config, 类型为 AudioEncoderConfig
一个 AudioEncoderConfig ,用户代理用它来确定 supported 的值。

7.3.4. VideoEncoderSupport

dictionary VideoEncoderSupport {
    boolean supported;
    VideoEncoderConfig config;
};
supported, 类型为 boolean
一个布尔值,指示对应的 config 是否被用户代理支持。
config, 类型为 VideoEncoderConfig
一个 VideoEncoderConfig ,用户代理用它来确定 supported 的值。

7.4. 编解码器字符串

编解码器字符串用于描述要用于编码或解码的特定编解码器格式。

一个 有效的编解码器字符串 必须 满足以下条件。

  1. 根据相关编解码器规范有效(见下面示例)。

  2. 它描述单一的编解码器。

  3. 对于定义这些概念的编解码器,它对配置文件(profile)、级别(level)和约束位(constraint bits)应无歧义。

注意:在其他媒体规范中,编解码器字符串传统上与 MIME 类型 一起作为 "codecs=" 参数出现 (isTypeSupported()canPlayType()[RFC6381]。 在本规范中,编码后的媒体不封装于容器;因此,仅接受 codecs 参数的值。

注意:对于定义了级别和约束位的编解码器,编码器在这些参数上有一定灵活性,但不会生成比请求更高级别或约束更少的比特流。

编解码器字符串的格式与语义由列在 [WEBCODECS-CODEC-REGISTRY] 中的编解码器注册定义。兼容的实现可以支持任意组合的编解码器注册,也可以完全不支持。

7.5. AudioDecoderConfig

dictionary AudioDecoderConfig {
    required DOMString codec;
    [EnforceRange] required unsigned long sampleRate;
    [EnforceRange] required unsigned long numberOfChannels;
    AllowSharedBufferSource description;
};

要检查 AudioDecoderConfig 是否是一个 有效的 AudioDecoderConfig, 请运行下列步骤:

  1. 如果 codec 在去除首尾 ASCII 空白字符后为空,则返回 false

  2. 如果 description 已经是 [detached],则返回 false

  3. 返回 true

codec, 类型为 DOMString
包含在 config.codec 中用于描述编解码器的 编解码器字符串
sampleRate, 类型为 unsigned long
每秒的帧采样数。
numberOfChannels, 类型为 unsigned long
音频通道数。
description, 类型为 AllowSharedBufferSource
一序列编解码器特定的字节,通常称为 extradata(扩展数据)。

注意:[WEBCODECS-CODEC-REGISTRY] 中的注册说明了应否/如何根据提供的 codec 来填充该字节序列。

7.6. VideoDecoderConfig

dictionary VideoDecoderConfig {
  required DOMString codec;
  AllowSharedBufferSource description;
  [EnforceRange] unsigned long codedWidth;
  [EnforceRange] unsigned long codedHeight;
  [EnforceRange] unsigned long displayAspectWidth;
  [EnforceRange] unsigned long displayAspectHeight;
  VideoColorSpaceInit colorSpace;
  HardwareAcceleration hardwareAcceleration = "no-preference";
  boolean optimizeForLatency;
  double rotation = 0;
  boolean flip = false;
};

要检查 VideoDecoderConfig 是否为 有效的 VideoDecoderConfig,请运行下列步骤:

  1. 如果 codec 在去除前导与尾随 ASCII 空白字符后为空,则返回 false

  2. 如果 codedWidthcodedHeight 中有一个提供但另一个未提供,则返回 false

  3. 如果 codedWidth = 0 或 codedHeight = 0,则返回 false

  4. 如果 displayAspectWidthdisplayAspectHeight 中有一个提供但另一个未提供,则返回 false

  5. 如果 displayAspectWidth = 0 或 displayAspectHeight = 0,则返回 false

  6. 如果 description 已为 [detached],则返回 false

  7. 返回 true

codec, 类型为 DOMString
包含用于描述该编解码器的 编解码器字符串
description, 类型为 AllowSharedBufferSource
一序列与编解码器相关的字节,通常称为 extradata(扩展数据)。

注意:[WEBCODECS-CODEC-REGISTRY] 中的注册会根据提供的 codec 说明是否以及如何填充该字节序列。

codedWidth, 类型为 unsigned long
VideoFrame 的宽度(以像素为单位),可能包含不可见的填充,并且在考虑显示比例调整之前。
codedHeight, 类型为 unsigned long
VideoFrame 的高度(以像素为单位),可能包含不可见的填充,并且在考虑显示比例调整之前。

注意: codedWidthcodedHeight 会在选择 [[codec implementation]] 时使用。

displayAspectWidth, 类型为 unsigned long
VideoFrame 在显示时的横向纵横比分子(水平尺寸)。
displayAspectHeight, 类型为 unsigned long
VideoFrame 在显示时的纵向纵横比分母(垂直尺寸)。

注意: displayWidthdisplayHeight 可以与 displayAspectWidthdisplayAspectHeight 不同,但在创建视频帧时应用缩放后比率应相同(参见创建视频帧的相关步骤)。

colorSpace, 类型为 VideoColorSpaceInit
配置与此 VideoFrame 相关的 colorSpace。 如果 colorSpace 存在,则其提供的值将覆盖比特流中的带内值。
hardwareAcceleration, 类型为 HardwareAcceleration,默认值为 "no-preference"
对该编解码器硬件加速的提示配置。参见 HardwareAcceleration
optimizeForLatency, 类型为 boolean
提示所选解码器 应当 配置为最小化必须解码以输出一个 VideoFrame 之前需要解码的 EncodedVideoChunk 数量。

注意:除用户代理与硬件限制外,某些编解码器比特流在产生任何输出之前需要最小数量的输入。

rotation, 类型为 double,默认值为 0
设置解码后帧的 rotation 属性。
flip, 类型为 boolean,默认值为 false
设置解码后帧的 flip 属性。

7.7. AudioEncoderConfig

dictionary AudioEncoderConfig {
  required DOMString codec;
  [EnforceRange] required unsigned long sampleRate;
  [EnforceRange] required unsigned long numberOfChannels;
  [EnforceRange] unsigned long long bitrate;
  BitrateMode bitrateMode = "variable";
};

注意:Codec-specific 对 AudioEncoderConfig 的扩展在 [WEBCODECS-CODEC-REGISTRY] 的注册中描述。

要检查 AudioEncoderConfig 是否为 有效的 AudioEncoderConfig,请运行下列步骤:

  1. 如果 codec 在去除前导与尾随 ASCII 空白字符后为空,则返回 false

  2. 如果该 AudioEncoderConfig 含有 codec-specific 扩展,且 [WEBCODECS-CODEC-REGISTRY] 中相应的注册定义了用于检查该扩展是否有效的步骤,则返回运行那些步骤的结果。

  3. 如果 sampleRatenumberOfChannels 等于零,则返回 false

  4. 返回 true

codec, 类型为 DOMString
包含用于描述该编解码器的 编解码器字符串
sampleRate, 类型为 unsigned long
每秒的帧采样数量。
numberOfChannels, 类型为 unsigned long
音频通道数。
bitrate, 类型为 unsigned long long
编码后音频的平均比特率,单位为比特每秒。
bitrateMode, 类型为 BitrateMode,默认值为 "variable"
配置编码器使用 constantvariable 比特率,定义见 [MEDIASTREAM-RECORDING]

注意:并非所有音频编解码器都支持特定的 BitrateMode, 建议作者通过调用 isConfigSupported() 并传入 config 来检查支持情况。

7.8. VideoEncoderConfig

dictionary VideoEncoderConfig {
  required DOMString codec;
  [EnforceRange] required unsigned long width;
  [EnforceRange] required unsigned long height;
  [EnforceRange] unsigned long displayWidth;
  [EnforceRange] unsigned long displayHeight;
  [EnforceRange] unsigned long long bitrate;
  double framerate;
  HardwareAcceleration hardwareAcceleration = "no-preference";
  AlphaOption alpha = "discard";
  DOMString scalabilityMode;
  VideoEncoderBitrateMode bitrateMode = "variable";
  LatencyMode latencyMode = "quality";
  DOMString contentHint;
};

注意:VideoEncoderConfig 的编解码器特定扩展在 [WEBCODECS-CODEC-REGISTRY] 的注册中有描述。

要检查 VideoEncoderConfig 是否为 有效的 VideoEncoderConfig,请运行下列步骤:

  1. 如果 codec 在去除前导与尾随 ASCII 空白字符后为空,则返回 false

  2. 如果 width = 0 或 height = 0,则返回 false

  3. 如果 displayWidth = 0 或 displayHeight = 0,则返回 false

  4. 返回 true

codec, 类型为 DOMString
包含在 config.codec 中用于描述该编解码器的 编解码器字符串
width, 类型为 unsigned long
编码输出 EncodedVideoChunk 的宽度(以像素为单位),在任何显示纵横比调整之前。

对于任何其 [[visible width]] 与该值不同的 VideoFrame, 编码器 必须 对其进行缩放。

height, 类型为 unsigned long
编码输出 EncodedVideoChunk 的高度(以像素为单位),在任何显示纵横比调整之前。

对于任何其 [[visible height]] 与该值不同的 VideoFrame, 编码器 必须 对其进行缩放。

displayWidth, 类型为 unsigned long
编码输出 EncodedVideoChunk 的目标显示宽度(以像素为单位)。 如果未提供,则默认值为 width
displayHeight, 类型为 unsigned long
编码输出 EncodedVideoChunk 的目标显示高度(以像素为单位)。 如果未提供,则默认值为 width
NOTE: 提供与 widthheight 不同的 displayWidthdisplayHeight 表明在解码后应对片段进行缩放以达到最终显示纵横比。

对于许多编解码器,这只是透传信息,但某些编解码器有时可能在比特流中包含显示尺寸。

bitrate, 类型为 unsigned long long
编码视频的平均比特率,单位为比特每秒。

注意:建议作者另外提供一个 framerate 以便为速率控制提供信息。

framerate, 类型为 double
预期的帧率(以每秒帧数计),如果已知。此值与帧的 timestamp 一起,应当 被视频编码器用来计算每个编码帧的最佳字节长度。此外,当 latencyMode 设置为 realtime 时,此值 应当 被视为输出编码片段的目标截止时间。
hardwareAcceleration, 类型为 HardwareAcceleration,默认值为 "no-preference"
关于该编解码器是否使用硬件加速的提示配置。参见 HardwareAcceleration
alpha, 类型为 AlphaOption,默认值为 "discard"
指示是否应在编码之前保留或丢弃输入 VideoFrame 的 alpha 分量。 如果 alpha 的值为 discard, 则始终丢弃 alpha 数据,无论 VideoFrame[[format]] 如何。
scalabilityMode, 类型为 DOMString
一个编码的 scalability mode identifier,定义见 [WebRTC-SVC]
bitrateMode, 类型为 VideoEncoderBitrateMode,默认值为 "variable"
配置编码使用由 VideoEncoderBitrateMode 指定的速率控制模式之一。

注意:两种模式下比特率波动的具体程度由实现决定。

latencyMode, 类型为 LatencyMode,默认值为 "quality"
配置与该编解码器相关的延迟行为。参见 LatencyMode
contentHint, 类型为 DOMString
一个编码的 video content hint,定义见 [mst-content-hint]

用户代理 可以 使用此提示来对传入的 VideoFrame 设定期望并改进编码质量。 如果使用该提示:

  • 用户代理 必须 在配置编码器时尊重其他显式设置的编码选项,无论这些选项是否为编解码器特定选项。

  • 用户代理 应当 尽最大努力使用额外的配置选项来根据相应的 video content hint 定义的目标来改进编码质量。

注意:某些编码器选项是实现相关的,且无法规定将 contentHint 映射到那些选项的具体方法。

如果用户代理不支持此内容提示,用户代理 不得 因此拒绝该配置。 参见 isConfigSupported()

7.9. 硬件加速

enum HardwareAcceleration {
  "no-preference",
  "prefer-hardware",
  "prefer-software",
};

当支持时,硬件加速会将编码或解码任务卸载到专用硬件上。prefer-hardwareprefer-software 是提示值。用户代理在可能时应当尊重这些值,但在某些或所有情况下,用户代理可能会因任何原因忽略这些值。

为防止指纹识别,如果用户代理实现了 [media-capabilities], 用户代理必须确保对某个 HardwareAcceleration 偏好的拒绝或接受不会泄露除用户代理本身已知及 [media-capabilities] 已公开的信息之外的额外信息。如果用户代理因指纹识别原因未实现 [media-capabilities],则应当忽略 HardwareAcceleration 偏好。

注意:用户代理可以忽略 prefer-hardwareprefer-software 的典型场景包括用户隐私原因,或用户代理认为其他设置更适合最终用户的情况。

大多数作者使用默认值 no-preference 会获得最佳体验。这让用户代理可以根据其对系统和配置的了解进行优化。常见策略是在高分辨率时优先使用硬件加速,若硬件加速失败则回退到软件编解码器。

建议作者在设置硬件加速偏好时仔细权衡利弊。具体权衡会因设备而异,但一般可预期如下:

鉴于这些权衡,“prefer-hardware”的典型用例是作者打算通过 WebAssembly 提供自己的软件回退方案。

而“prefer-software”的典型用例是作者对硬件加速通常带来的更高启动延迟或健壮性降低尤为敏感。

no-preference
表示用户代理可以在硬件加速可用且与编解码器配置其他方面兼容时使用硬件加速。
prefer-software
表示用户代理应当优先选择软件编解码器实现。用户代理可因任何原因忽略该值。

注意:在某些平台上,如果没有未加速的编解码器或与编解码器配置其他方面不兼容,可能导致该配置不被支持。

prefer-hardware
表示用户代理应当优先选择硬件加速。用户代理可因任何原因忽略该值。

注意:在某些平台上,如果没有加速的编解码器或与编解码器配置其他方面不兼容,可能导致该配置不被支持。

7.10. Alpha 选项

enum AlphaOption {
    "keep",
    "discard",
};

描述用户代理在处理 alpha 通道时应当如何行为,适用于多种不同操作。

keep
表示用户代理应当VideoFrame 存在 alpha 通道数据时予以保留。
discard
表示用户代理应当忽略或移除 VideoFrame 的 alpha 通道数据。

7.11. 延迟模式

enum LatencyMode {
  "quality",
  "realtime"
};
quality

表示用户代理应当优化编码质量。在此模式下:

  • 用户代理可以增加编码延迟以提升质量。

  • 用户代理必须不丢帧以达到目标 bitrate 和/或 framerate

  • framerate 不应作为输出编码片段的目标截止时间。

realtime

表示用户代理应当优化低延迟。在此模式下:

  • 用户代理可以牺牲质量以提升延迟表现。

  • 用户代理可以丢帧以达到目标 bitrate 和/或 framerate

  • framerate 应当作为输出编码片段的目标截止时间。

7.12. 配置等价性

两个字典是等价字典,如果它们包含相同的键和值。对于嵌套字典,递归应用此定义。

7.13. VideoEncoderEncodeOptions

dictionary VideoEncoderEncodeOptions {
  boolean keyFrame = false;
};

注意:VideoEncoderEncodeOptions 的编解码器特定扩展在 [WEBCODECS-CODEC-REGISTRY] 的注册中有描述。

keyFrame, 类型为 boolean,默认值为 false
当值为 true 时,表示该帧必须被编码为关键帧。值为 false 时,表示用户代理可自行决定该帧是否编码为关键帧

7.14. VideoEncoderBitrateMode

enum VideoEncoderBitrateMode {
  "constant",
  "variable",
  "quantizer"
};
constant
以恒定比特率进行编码。参见 bitrate.
variable
使用可变比特率进行编码,复杂信号可以使用更多空间,较简单的信号使用较少空间。 参见 bitrate
quantizer
使用量化器进行编码,该量化器在 VideoEncoderEncodeOptions 的编解码器特定扩展中为每个视频帧指定。

7.15. CodecState

enum CodecState {
  "unconfigured",
  "configured",
  "closed"
};
unconfigured
该编解码器尚未配置用于编码或解码。
configured
已提供有效配置。编解码器已准备好进行编码或解码。
closed
编解码器不再可用,底层的 system resources 已被释放。

7.16. WebCodecsErrorCallback

callback WebCodecsErrorCallback = undefined(DOMException error);

8. 已编码媒体接口(块)

这些接口表示已编码媒体的块。

8.1. EncodedAudioChunk 接口

[Exposed=(Window,DedicatedWorker), Serializable]
interface EncodedAudioChunk {
  constructor(EncodedAudioChunkInit init);
  readonly attribute EncodedAudioChunkType type;
  readonly attribute long long timestamp;          // microseconds
  readonly attribute unsigned long long? duration; // microseconds
  readonly attribute unsigned long byteLength;

  undefined copyTo(AllowSharedBufferSource destination);
};

dictionary EncodedAudioChunkInit {
  required EncodedAudioChunkType type;
  [EnforceRange] required long long timestamp;    // microseconds
  [EnforceRange] unsigned long long duration;     // microseconds
  required AllowSharedBufferSource data;
  sequence<ArrayBuffer> transfer = [];
};

enum EncodedAudioChunkType {
    "key",
    "delta",
};

8.1.1. 内部插槽

[[internal data]]

表示已编码块数据的字节数组。

[[type]]

描述该块是否为 key chunk

[[timestamp]]

呈现时间戳,单位为微秒。

[[duration]]

呈现持续时间,单位为微秒。

[[byte length]]

[[internal data]] 的字节长度。

8.1.2. 构造函数

EncodedAudioChunk(init)
  1. If init.transfer contains more than one reference to the same ArrayBuffer, then throw a DataCloneError DOMException.

  2. For each transferable in init.transfer:

    1. If [[Detached]] internal slot is true, then throw a DataCloneError DOMException.

  3. Let chunk be a new EncodedAudioChunk object, initialized as follows

    1. Assign init.type to [[type]].

    2. Assign init.timestamp to [[timestamp]].

    3. If init.duration exists, assign it to [[duration]], or assign null otherwise.

    4. Assign init.data.byteLength to [[byte length]];

    5. If init.transfer contains an ArrayBuffer referenced by init.data the 用户代理 MAY choose to:

      1. Let resource be a new media resource referencing sample data in init.data.

    6. Otherwise:

      1. Assign a copy of init.data to [[internal data]].

  4. For each transferable in init.transfer:

    1. Perform DetachArrayBuffer on transferable

  5. Return chunk.

8.1.3. 属性

type, of type EncodedAudioChunkType, readonly

返回 [[type]] 的值。

timestamp, of type long long, readonly

返回 [[timestamp]] 的值。

duration, of type unsigned long long, readonly, nullable

返回 [[duration]] 的值。

byteLength, of type unsigned long, readonly

返回 [[byte length]] 的值。

8.1.4. 方法

copyTo(destination)

调用时,执行以下步骤:

  1. 如果此 [[byte length]] 的值大于 destination 中的空间,则抛出 TypeError

  2. [[internal data]] 复制到 destination

8.1.5. 序列化

EncodedAudioChunk 序列化步骤(带 valueserialized,和 forStorage)如下:
  1. 如果 forStoragetrue,抛出 DataCloneError

  2. 对于 value 中每个 EncodedAudioChunk 内部插槽,将每个内部插槽的值赋值到 serialized 中与该内部插槽同名的字段。

EncodedAudioChunk 反序列化步骤(带 serializedvalue)如下:
  1. 对于 serialized 的所有命名字段,将每个字段的值赋值到 value 中与该字段同名的 EncodedAudioChunk 内部插槽。

注:由于 EncodedAudioChunk 是不可变的,用户代理可以选择使用类似 § 9.2.6 传递与序列化 的引用计数模型实现序列化。

8.2. EncodedVideoChunk 接口

[Exposed=(Window,DedicatedWorker), Serializable]
interface EncodedVideoChunk {
  constructor(EncodedVideoChunkInit init);
  readonly attribute EncodedVideoChunkType type;
  readonly attribute long long timestamp;             // microseconds
  readonly attribute unsigned long long? duration;    // microseconds
  readonly attribute unsigned long byteLength;

  undefined copyTo(AllowSharedBufferSource destination);
};

dictionary EncodedVideoChunkInit {
  required EncodedVideoChunkType type;
  [EnforceRange] required long long timestamp;        // microseconds
  [EnforceRange] unsigned long long duration;         // microseconds
  required AllowSharedBufferSource data;
  sequence<ArrayBuffer> transfer = [];
};

enum EncodedVideoChunkType {
    "key",
    "delta",
};

8.2.1. 内部插槽

[[internal data]]

表示已编码块数据的字节数组。

[[type]]

EncodedVideoChunkEncodedVideoChunkType

[[timestamp]]

呈现时间戳,单位为微秒。

[[duration]]

呈现持续时间,单位为微秒。

[[byte length]]

[[internal data]] 的字节长度。

8.2.2. 构造函数

EncodedVideoChunk(init)
  1. 如果 init.transfer 包含对同一个 ArrayBuffer 多个引用,则抛出 DataCloneError DOMException

  2. 对于 init.transfer 中的每个 transferable

    1. 如果 [[Detached]] 内部插槽为 true,则抛出 DataCloneError DOMException

  3. chunk 为新建的 EncodedVideoChunk 对象,初始化如下:

    1. init.type 赋值给 [[type]]

    2. init.timestamp 赋值给 [[timestamp]]

    3. 如果 init 中存在 duration,则将 init.duration 赋值给 [[duration]]。否则,将 null 赋值给 [[duration]]

    4. init.data.byteLength 赋值给 [[byte length]]

    5. 如果 init.transfer 包含 init.data 所引用的 ArrayBuffer,用户代理 MAY 可以选择:

      1. resource 为新建的 media resource,其引用 init.data 中的样本数据。

    6. 否则:

      1. init.data 的副本赋值给 [[internal data]]

  4. 对于 init.transfer 中的每个 transferable

    1. transferable 执行 DetachArrayBuffer

  5. 返回 chunk

8.2.3. 属性

type, 类型为 EncodedVideoChunkType, 只读

返回 [[type]] 的值。

timestamp, 类型为 long long, 只读

返回 [[timestamp]] 的值。

duration, 类型为 unsigned long long, 只读, 可为 null

返回 [[duration]] 的值。

byteLength, 类型为 unsigned long, 只读

返回 [[byte length]] 的值。

8.2.4. 方法

copyTo(destination)

调用时,执行如下步骤:

  1. 如果 [[byte length]] 大于 destination[[byte length]],则抛出 TypeError

  2. [[internal data]] 复制到 destination

8.2.5. 序列化

EncodedVideoChunk 序列化步骤(带 valueserialized,和 forStorage)如下:
  1. 如果 forStoragetrue,抛出 DataCloneError

  2. 对于 value 中每个 EncodedVideoChunk 内部插槽,将每个内部插槽的值赋值到 serialized 中与该内部插槽同名的字段。

EncodedVideoChunk 反序列化步骤(带 serializedvalue)如下:
  1. 对于 serialized 的所有命名字段,将每个字段的值赋值到 value 中与该字段同名的 EncodedVideoChunk 内部插槽。

注:由于 EncodedVideoChunk 是不可变的,用户代理可以选择使用类似 § 9.4.7 传递与序列化 的引用计数模型实现序列化。

9. 未编码媒体接口

这些接口表示未编码(原始)的媒体。

9.1. 内存模型

9.1.1. 背景

本节为非规范性内容。

解码后的媒体数据可能占用大量系统内存。为了减少昂贵的拷贝需求,本规范定义了引用计数方案(clone()close())。

注:建议作者在帧不再需要时立即调用 close()

9.1.2. 引用计数

media resourceVideoFrameAudioData 所描述的实际像素数据或音频样本数据的存储。

AudioData[[resource reference]]VideoFrame[[resource reference]] 内部插槽保存对 media resource 的引用。

VideoFrame.clone()AudioData.clone() 返回的新对象,其 [[resource reference]] 指向与原对象相同的 media resource

VideoFrame.close()AudioData.close() 会清除它们的 [[resource reference]] 槽,释放对其 media resource 的引用。

media resource 必须至少在被 [[resource reference]] 引用期间保持存活。

注:media resource 不再被 [[resource reference]] 引用时,该资源可以被销毁。鼓励用户代理快速销毁这些资源,以降低内存压力并促进资源复用。

9.1.3. 传递与序列化

本节为非规范性内容。

AudioDataVideoFrame 均为 可传递对象可序列化对象。它们的传递和 序列化步骤分别定义在 § 9.2.6 传递与序列化§ 9.4.7 传递与序列化 中。

传递 AudioDataVideoFrame 会将其 [[resource reference]] 移动到目标对象,并关闭(如 close())源对象。作者可以利用此机制在不同 realm 之间移动 AudioDataVideoFrame,而无需拷贝底层 media resource

序列化 AudioDataVideoFrame 实际上是对源对象进行克隆(如 clone()),会得到两个引用同一个 media resource 的对象。作者可以利用此机制将 AudioDataVideoFrame 克隆到另一个 realm,而无需拷贝底层 media resource

9.2. AudioData 接口

[Exposed=(Window,DedicatedWorker), Serializable, Transferable]
interface AudioData {
  constructor(AudioDataInit init);

  readonly attribute AudioSampleFormat? format;
  readonly attribute float sampleRate;
  readonly attribute unsigned long numberOfFrames;
  readonly attribute unsigned long numberOfChannels;
  readonly attribute unsigned long long duration;  // microseconds
  readonly attribute long long timestamp;          // microseconds

  unsigned long allocationSize(AudioDataCopyToOptions options);
  undefined copyTo(AllowSharedBufferSource destination, AudioDataCopyToOptions options);
  AudioData clone();
  undefined close();
};

dictionary AudioDataInit {
  required AudioSampleFormat format;
  required float sampleRate;
  [EnforceRange] required unsigned long numberOfFrames;
  [EnforceRange] required unsigned long numberOfChannels;
  [EnforceRange] required long long timestamp;  // microseconds
  required BufferSource data;
  sequence<ArrayBuffer> transfer = [];
};

9.2.1. 内部插槽

[[resource reference]]

对存储此 AudioData 音频样本数据的 media resource 的引用。

[[format]]

AudioData 使用的 AudioSampleFormat。 当底层格式无法映射到 AudioSampleFormat[[Detached]]true 时,该值为 null

[[sample rate]]

AudioData 的采样率(Hz)。

[[number of frames]]

AudioData数。

[[number of channels]]

AudioData 的音频声道数。

[[timestamp]]

AudioData 的展示时间戳,单位为微秒。

9.2.2. 构造函数

AudioData(init)
  1. 如果 init 不是 有效的 AudioDataInit,则抛出 TypeError

  2. 如果 init.transfer 包含对同一个 ArrayBuffer 多个引用,则抛出 DataCloneError DOMException

  3. 对于 init.transfer 中的每个 transferable

    1. 如果 [[Detached]] 内部插槽为 true,则抛出 DataCloneError DOMException

  4. frame 为新建的 AudioData 对象,初始化如下:

    1. false 赋值给 [[Detached]]

    2. init.format 赋值给 [[format]]

    3. init.sampleRate 赋值给 [[sample rate]]

    4. init.numberOfFrames 赋值给 [[number of frames]]

    5. init.numberOfChannels 赋值给 [[number of channels]]

    6. init.timestamp 赋值给 [[timestamp]]

    7. 如果 init.transfer 包含被 init.data 引用的 ArrayBuffer,用户代理 可以选择:

      1. resource 为新建的 media resource,引用 data 中的样本数据。

    8. 否则:

      1. resource 为包含 init.data 副本的 media resource

    9. resourceReferenceresource 的引用。

    10. resourceReference 赋值给 [[resource reference]]

  5. 对于 init.transfer 中的每个 transferable

    1. transferable 执行 DetachArrayBuffer

  6. 返回 frame

9.2.3. 属性

format, 类型为 AudioSampleFormat, 只读,可为 null

AudioData 使用的 AudioSampleFormat。 当底层格式无法映射到 AudioSampleFormat[[Detached]]true 时,该值为 null

format 的 getter 步骤为返回 [[format]]

sampleRate, 类型为 float, 只读

AudioData 的采样率(Hz)。

sampleRate 的 getter 步骤为返回 [[sample rate]]

numberOfFrames, 类型为 unsigned long, 只读

AudioData数。

numberOfFrames 的 getter 步骤为返回 [[number of frames]]

numberOfChannels, 类型为 unsigned long, 只读

AudioData 的音频声道数。

numberOfChannels 的 getter 步骤为返回 [[number of channels]]

timestamp, 类型为 long long, 只读

AudioData 的展示时间戳(微秒)。

numberOfChannels 的 getter 步骤为返回 [[timestamp]]

duration, 类型为 unsigned long long, 只读

AudioData 的持续时间(微秒)。

duration 的 getter 步骤如下:

  1. microsecondsPerSecond1,000,000

  2. durationInSeconds[[number of frames]] 除以 [[sample rate]] 的结果。

  3. 返回 durationInSecondsmicrosecondsPerSecond 的乘积。

9.2.4. 方法

allocationSize(options)

返回保存 options 所描述样本所需的字节数。

调用时,执行以下步骤:

  1. 如果 [[Detached]]true,抛出 InvalidStateError DOMException

  2. copyElementCount 为用 options 运行 计算拷贝元素数量算法的结果。

  3. destFormat[[format]] 的值。

  4. 如果 options.format 存在,则将 options.format 赋值给 destFormat

  5. bytesPerSampledestFormat 定义的每个样本的字节数。

  6. 返回 bytesPerSamplecopyElementCount 的乘积。

copyTo(destination, options)

AudioData 指定平面的样本复制到目标缓冲区。

调用时,执行以下步骤:

  1. 如果 [[Detached]]true,抛出 InvalidStateError DOMException

  2. copyElementCount 为用 options 运行 计算拷贝元素数量算法的结果。

  3. destFormat[[format]] 的值。

  4. 如果 options.format 存在,则将 options.format 赋值给 destFormat

  5. bytesPerSampledestFormat 定义的每个样本的字节数。

  6. 如果 bytesPerSamplecopyElementCount 的乘积大于 destination.byteLength,则抛出 RangeError

  7. resource[[resource reference]] 所引用的 media resource

  8. planeFramesresource 中对应 options.planeIndex 区域。

  9. planeFrames 元素复制到 destination,从 options.frameOffset 所定位的 开始,复制 copyElementCount 个样本后停止。如果 destFormat 不等于 [[format]],则在复制时将元素转换为 destFormatAudioSampleFormat

clone()

创建一个新的 AudioData,其引用与原对象相同的 media resource

调用时,执行以下步骤:

  1. 如果 [[Detached]]true,抛出 InvalidStateError DOMException

  2. 返回用 克隆 AudioData 算法和 this 运行的结果。

close()

清除所有状态并释放对 media resource 的引用。关闭是不可逆的。

调用时,使用 关闭 AudioData 算法和 this 运行。

9.2.5. 算法

计算拷贝元素数量(带 options

执行以下步骤:

  1. destFormat[[format]] 的值。

  2. 如果 options.format 存在,则将 options.format 赋值给 destFormat

  3. 如果 destFormat 描述的是 交错 AudioSampleFormat,且 options.planeIndex 大于 0,则抛出 RangeError

  4. 否则,如果 destFormat 描述的是 分离 AudioSampleFormat,且 options.planeIndex 大于等于 [[number of channels]],则抛出 RangeError

  5. 如果 [[format]] 不等于 destFormat 且用户代理不支持请求的 AudioSampleFormat 转换,则抛出 NotSupportedError DOMException。必须始终支持转换为 f32-planar

  6. frameCount 为由 options.planeIndex 标识的平面中的帧数。

  7. 如果 options.frameOffset 大于等于 frameCount,则抛出 RangeError

  8. copyFrameCountframeCount 减去 options.frameOffset 的结果。

  9. 如果 options.frameCount 存在

    1. 如果 options.frameCount 大于 copyFrameCount,则抛出 RangeError

    2. 否则,将 options.frameCount 赋值给 copyFrameCount

  10. elementCountcopyFrameCount

  11. 如果 destFormat 描述的是 交错 AudioSampleFormat,则将 elementCount 乘以 [[number of channels]]

  12. 返回 elementCount

克隆 AudioData(带 data

执行以下步骤:

  1. clone 为新建的 AudioData,初始化如下:

    1. resourcedata[[resource reference]] 所引用的 media resource

    2. referenceresource 新的引用。

    3. reference 赋值给 [[resource reference]]

    4. data[[Detached]][[format]][[sample rate]][[number of frames]][[number of channels]][[timestamp]] 槽的值赋值到 clone 的对应槽。

  2. 返回 clone

关闭 AudioData(带 data

执行以下步骤:

  1. true 赋值给 data[[Detached]] 内部插槽。

  2. null 赋值给 data[[resource reference]]

  3. 0 赋值给 data[[sample rate]]

  4. 0 赋值给 data[[number of frames]]

  5. 0 赋值给 data[[number of channels]]

  6. null 赋值给 data[[format]]

要检查 AudioDataInit 是否为 有效的 AudioDataInit,执行以下步骤:
  1. 如果 sampleRate 小于或等于 0,返回 false

  2. 如果 numberOfFrames = 0,返回 false

  3. 如果 numberOfChannels = 0,返回 false

  4. 通过以下步骤验证 data 的数据量是否足够:

    1. totalSamplesnumberOfFramesnumberOfChannels 的乘积。

    2. bytesPerSampleformat 定义的每个样本字节数。

    3. totalSizebytesPerSample 乘以 totalSamples 的结果。

    4. dataSizedata 的字节大小。

    5. 如果 dataSize 小于 totalSize,返回 false。

  5. 返回 true

注:期望 AudioDataInitdata 的 内存布局与 分离交错 format 的期望一致。没有真正的方法可以验证样本是否符合其 AudioSampleFormat

9.2.6. 传递与序列化

AudioData 传递步骤(带 valuedataHolder)如下:
  1. 如果 value[[Detached]]true,抛出 DataCloneError DOMException

  2. 对于 value 中所有 AudioData 的内部插槽,将每个槽的值赋值到 dataHolder 中同名字段。

  3. value 执行 关闭 AudioData 算法。

AudioData 传递接收步骤(带 dataHoldervalue)如下:
  1. 对于 dataHolder 中所有命名字段,将每个字段的值赋值到 value 中同名 AudioData 的内部插槽。

AudioData 序列化步骤(带 valueserializedforStorage)如下:
  1. 如果 value[[Detached]]true,抛出 DataCloneError DOMException

  2. 如果 forStoragetrue,抛出 DataCloneError

  3. resourcevalue[[resource reference]] 所引用的 media resource

  4. newReferenceresource 的新引用。

  5. newReference 赋值给 |serialized.resource reference|。

  6. 对于 value 中除 [[resource reference]] 外的所有 AudioData 内部插槽,将每个槽的值赋值到 serialized 的同名字段。

AudioData 反序列化步骤(带 serializedvalue)如下:
  1. 对于 serialized 中所有命名字段,将每个字段的值赋值到 value 中同名 AudioData 的内部插槽。

9.2.7. AudioDataCopyToOptions

dictionary AudioDataCopyToOptions {
  [EnforceRange] required unsigned long planeIndex;
  [EnforceRange] unsigned long frameOffset = 0;
  [EnforceRange] unsigned long frameCount;
  AudioSampleFormat format;
};
planeIndex, 类型为 unsigned long

要复制的平面索引。

frameOffset, 类型为 unsigned long,默认值为 0

源平面数据的偏移量,表示从哪个 开始复制。默认为 0

frameCount, 类型为 unsigned long

要复制的 数。如果未提供,则复制将包含从 frameOffset 开始的所有帧。

format, 类型为 AudioSampleFormat

目标数据的输出 AudioSampleFormat。如果未提供,则复制结果将使用 this AudioData 的 [[format]]。调用 copyTo() 时,如果不支持转换到请求的格式,则会抛出 NotSupportedError。必须始终支持从任何 AudioSampleFormat 转换到 f32-planar

注:希望与 [WEBAUDIO] 集成的作者可请求 f32-planar,并用复制的结果创建 AudioBuffer 或通过 AudioWorklet 渲染。

9.3. 音频采样格式

音频采样格式描述用于表示单个样本(如32位浮点数)的数值类型,以及不同声道样本的排列方式,分为交错分离音频样本类型仅指用于存储数据的数值类型和间隔,即 u8s16s32f32,分别代表无符号8位、有符号16位、有符号32位和32位浮点数。音频缓冲区排列仅指样本在内存中的布局方式(分离交错)。

样本指的是在某一时刻某一声道上的信号幅值。

或(采样帧)指的是某一时刻多声道信号的全部值集合。

注:因此,如果音频信号是单声道(仅有一个声道),帧和样本是同一个概念。

本规范中的所有音频样本均采用线性脉冲编码调制(Linear PCM):量化级在数值间均匀分布。

注:预计与本规范一起使用的 Web Audio API 也采用线性PCM。

enum AudioSampleFormat {
  "u8",
  "s16",
  "s32",
  "f32",
  "u8-planar",
  "s16-planar",
  "s32-planar",
  "f32-planar",
};
u8

8位无符号整数 样本交错 声道排列

s16

16位有符号整数 样本交错 声道排列

s32

32位有符号整数 样本交错 声道排列

f32

32位浮点数 样本交错 声道排列

u8-planar

8位无符号整数 样本分离 声道排列

s16-planar

16位有符号整数 样本分离 声道排列

s32-planar

32位有符号整数 样本分离 声道排列

f32-planar

32位浮点数 样本分离 声道排列

9.3.1. 音频缓冲区排列

AudioDataAudioSampleFormat交错 时,不同声道的音频样本在同一个缓冲区中连续排列,顺序见 § 9.3.3 音频声道顺序AudioData 只有一个平面,其元素数量等于 [[number of frames]] * [[number of channels]]

AudioDataAudioSampleFormat分离 时,不同声道的音频样本在不同缓冲区中排列,顺序见 § 9.3.3 音频声道顺序AudioData 的平面数量等于 AudioData[[number of channels]]。每个平面包含 [[number of frames]] 个元素。

注:Web Audio API 目前只使用 f32-planar

注:下图展示了 分离交错 AudioSampleFormat 的内存布局

Graphical representation the memory layout of interleaved and planar
    formats

9.3.2. 音频样本幅值

最小值最大值指的是某种音频样本类型下,低于(或高于)该值可能会发生音频削波(clipping)。除此之外,它们是常规类型,在中间处理时可取超出该区间的值。

偏置值指的是某种音频样本类型中常常对应于区间中间的那个值(但通常区间并不对称)。只包含偏置值的音频缓冲区是静音的。

样本类型 IDL 类型 最小值 偏置值 最大值
u8 octet 0 128 +255
s16 short -32768 0 +32767
s32 long -2147483648 0 +2147483647
f32 float -1.0 0.0 +1.0

注:没有能够方便存储24位信息的数据类型,但24位音频内容很常见,因此常用32位整数存放24位内容。

AudioData 包含24位样本时,应当将这些样本存放在 s32f32 中。如果样本存放于 s32,每个样本必须左移8位。这样,超出有效24位范围([-8388608, +8388607])的样本会被截断。为避免截断并保证无损传输,样本可以转换为 f32

注:由于存储类型限制,u8s16s32 样本不可避免会被削波(clipping),但实现应当在处理 f32 样本时避免削波。

9.3.3. 音频声道顺序

解码时,生成的 AudioData 中音频声道的顺序必须EncodedAudioChunk 中的保持一致。

编码时,生成的 EncodedAudioChunk 中音频声道的顺序必须与给定的 AudioData 中的保持一致。

换句话说,编码和解码时不会进行声道重排。

注:容器要么隐含要么指定了声道映射,即某个声道索引所对应的声道类型。

9.4. VideoFrame 接口

注:VideoFrame 是一个 CanvasImageSourceVideoFrame 可以传递给所有接受 CanvasImageSource 的方法,包括 CanvasDrawImagedrawImage()

[Exposed=(Window,DedicatedWorker), Serializable, Transferable]
interface VideoFrame {
  constructor(CanvasImageSource image, optional VideoFrameInit init = {});
  constructor(AllowSharedBufferSource data, VideoFrameBufferInit init);

  readonly attribute VideoPixelFormat? format;
  readonly attribute unsigned long codedWidth;
  readonly attribute unsigned long codedHeight;
  readonly attribute DOMRectReadOnly? codedRect;
  readonly attribute DOMRectReadOnly? visibleRect;
  readonly attribute double rotation;
  readonly attribute boolean flip;
  readonly attribute unsigned long displayWidth;
  readonly attribute unsigned long displayHeight;
  readonly attribute unsigned long long? duration;  // microseconds
  readonly attribute long long timestamp;           // microseconds
  readonly attribute VideoColorSpace colorSpace;

  VideoFrameMetadata metadata();

  unsigned long allocationSize(
      optional VideoFrameCopyToOptions options = {});
  Promise<sequence<PlaneLayout>> copyTo(
      AllowSharedBufferSource destination,
      optional VideoFrameCopyToOptions options = {});
  VideoFrame clone();
  undefined close();
};

dictionary VideoFrameInit {
  unsigned long long duration;  // microseconds
  long long timestamp;          // microseconds
  AlphaOption alpha = "keep";

  // 默认匹配图片。可用于高效裁剪。除非显式给出 displayWidth 和 displayHeight,否则会根据图片的像素纵横比重新计算 displayWidth 和 displayHeight。
  DOMRectInit visibleRect;

  double rotation = 0;
  boolean flip = false;

  // 默认匹配图片,除非提供了 visibleRect。
  [EnforceRange] unsigned long displayWidth;
  [EnforceRange] unsigned long displayHeight;

  VideoFrameMetadata metadata;
};

dictionary VideoFrameBufferInit {
  required VideoPixelFormat format;
  required [EnforceRange] unsigned long codedWidth;
  required [EnforceRange] unsigned long codedHeight;
  required [EnforceRange] long long timestamp;  // microseconds
  [EnforceRange] unsigned long long duration;  // microseconds

  // 默认布局是紧密排列。
  sequence<PlaneLayout> layout;

  // 默认可见区域为编码尺寸,定位为 (0,0)
  DOMRectInit visibleRect;

  double rotation = 0;
  boolean flip = false;

  // 默认显示尺寸与 visibleRect 匹配。
  [EnforceRange] unsigned long displayWidth;
  [EnforceRange] unsigned long displayHeight;

  VideoColorSpaceInit colorSpace;

  sequence<ArrayBuffer> transfer = [];

  VideoFrameMetadata metadata;
};

dictionary VideoFrameMetadata {
  // 可能的成员记录在 VideoFrame Metadata Registry。
};

9.4.1. 内部插槽

[[resource reference]]

指向存储该帧像素数据的 media resource 的引用。

[[format]]

描述该 VideoFrame 像素格式的 VideoPixelFormat。当底层格式无法映射到 VideoPixelFormat[[Detached]]true 时为 null

[[coded width]]

VideoFrame 的像素宽度,可能包含不可见的填充,且未考虑纵横比调整前的数值。

[[coded height]]

VideoFrame 的像素高度,可能包含不可见的填充,且未考虑纵横比调整前的数值。

[[visible left]]

定义可见矩形左侧偏移的像素数量。

[[visible top]]

定义可见矩形顶端偏移的像素数量。

[[visible width]]

可见矩形包含的像素宽度,从 [[visible left]] 开始。

[[visible height]]

可见矩形包含的像素高度,从 [[visible top]] 开始。

[[rotation]]

渲染该 VideoFrame 时应用的旋转角度,单位为顺时针度数。旋转在翻转之前应用。

[[flip]]

渲染该 VideoFrame 时是否应用水平翻转。翻转在旋转之后应用。

[[display width]]

应用纵横比调整后显示该 VideoFrame 时的宽度。

[[display height]]

应用纵横比调整后显示该 VideoFrame 时的高度。

[[duration]]

展示持续时间,单位为微秒。该持续时间从对应的 EncodedVideoChunk 复制而来。

[[timestamp]]

展示时间戳,单位为微秒。该时间戳从对应的 EncodedVideoChunk 复制而来。

[[color space]]

该帧关联的 VideoColorSpace

[[metadata]]

该帧关联的 VideoFrameMetadata。 可能的成员记录在 [webcodecs-video-frame-metadata-registry] 中。 所有 VideoFrameMetadata 属性均可序列化。

9.4.2. 构造函数

VideoFrame(image, init)

  1. 检查 image 参数可用性。如果抛出异常或返回 bad,则抛出 InvalidStateError DOMException

  2. 如果 image 不是 origin-clean,则抛出 SecurityError DOMException

  3. frame 为新的 VideoFrame

  4. 根据 image 类型分支:

    注:建议作者提供有意义的 timestamp,除非它已由 CanvasImageSource 在构造时隐式提供。消费 VideoFrame 的接口可以依赖此值做时序决策。例如 VideoEncoder 可用 timestamp 指导速率控制(参见 framerate)。

  5. 返回 frame

VideoFrame(data, init)

  1. 如果 init 不是有效的 VideoFrameBufferInit,则抛出 TypeError

  2. defaultRect 为 «[ "x:" → 0, "y" → 0, "width" → init.codedWidth, "height" → init.codedWidth ]»。

  3. overrideRectundefined

  4. 如果 init.visibleRect 存在,则将其值赋值给 overrideRect

  5. parsedRect 为用 defaultRect, overrideRect, init.codedWidth, init.codedHeight, 和 init.format 运行 可见矩形解析算法的结果。

  6. 如果 parsedRect 是异常,则返回 parsedRect

  7. optLayoutundefined

  8. 如果 init.layout 存在,则将其值赋值给 optLayout

  9. combinedLayout 为用 parsedRect, init.format, 和 optLayout 运行 布局与分配大小计算算法的结果。

  10. 如果 combinedLayout 是异常,则抛出 combinedLayout

  11. 如果 data.byteLength 小于 combinedLayoutallocationSize,则抛出 TypeError

  12. 如果 init.transfer 包含对同一个 ArrayBuffer 的多个引用,则抛出 DataCloneError DOMException

  13. 对于 init.transfer 中的每个 transferable

    1. 如果 [[Detached]] 内部插槽为 true,则抛出 DataCloneError DOMException

  14. 如果 init.transfer 包含一个被 data 引用的 ArrayBuffer,用户代理可以选择:

    1. resource 为新建的 media resource,其引用 data 中的像素数据。

  15. 否则:

    1. resource 为新建的 media resource,其内容为 data 的副本。用 visibleRectlayout 判断每个 plane 的像素在 data 中的位置。

      用户代理可以选择分配更大的编码尺寸和 plane 步幅以优化内存对齐。编码尺寸变化会反映在 codedWidthcodedHeight 上。此外,用户代理可以利用 visibleRect 只复制可见矩形,并可以resource 内重新定位可见矩形。最终位置会反映在 visibleRect

  16. 对于 init.transfer 中的每个 transferable

    1. transferable 执行 DetachArrayBuffer

  17. resourceCodedWidthresource 的编码宽度。

  18. resourceCodedHeightresource 的编码高度。

  19. resourceVisibleLeftresource 的可见矩形左偏移。

  20. resourceVisibleTopresource 的可见矩形上偏移。

    本规范应当提供编码尺寸、可见矩形和显示尺寸的定义(及图示)。见 #166

  21. frame 为新建的 VideoFrame 对象,初始化如下:

    1. resourceCodedWidthresourceCodedHeightresourceVisibleLeftresourceVisibleTop 分别赋值给 [[coded width]][[coded height]][[visible left]][[visible top]]

    2. 如果 init.visibleRect 存在

      1. truncatedVisibleWidthvisibleRect.width 截断后的值。

      2. truncatedVisibleWidth 赋值给 [[visible width]]

      3. truncatedVisibleHeightvisibleRect.height 截断后的值。

      4. truncatedVisibleHeight 赋值给 [[visible height]]

    3. 否则:

      1. [[coded width]] 赋值给 [[visible width]]

      2. [[coded height]] 赋值给 [[visible height]]

    4. 将用 init.rotation 运行 旋转解析算法的结果赋值给 [[rotation]]

    5. init.flip 赋值给 [[flip]]

    6. 如果 displayWidthdisplayHeight 存在init 中,则分别赋值给 [[display width]][[display height]]

    7. 否则:

      1. 如果 [[rotation]] 等于 0180

        1. [[visible width]] 赋值给 [[display width]]

        2. [[visible height]] 赋值给 [[display height]]

      2. 否则:

        1. [[visible height]] 赋值给 [[display width]]

        2. [[visible width]] 赋值给 [[display height]]

    8. inittimestampduration 分别赋值给 [[timestamp]][[duration]]

    9. colorSpaceundefined

    10. 如果 init.colorSpace 存在,则赋值给 colorSpace

    11. initformat 赋值给 [[format]]

    12. colorSpace[[format]] 运行 色彩空间选择算法,并赋值给 [[color space]]

    13. initmetadata 调用 VideoFrame 元数据复制,并赋值给 frame.[[metadata]]

  22. 返回 frame

9.4.3. 属性

format, 类型为 VideoPixelFormat,只读,可为 null

描述每个 plane 字节的排列方式,以及 plane 的数量和顺序。当底层格式无法映射到 VideoPixelFormat[[Detached]]true 时为 null

format 的 getter 步骤为返回 [[format]]

codedWidth, 类型为 unsigned long,只读

VideoFrame 的像素宽度,可能包含不可见的填充,未考虑纵横比调整。

codedWidth 的 getter 步骤为返回 [[coded width]]

codedHeight, 类型为 unsigned long,只读

VideoFrame 的像素高度,可能包含不可见的填充,未考虑纵横比调整。

codedHeight 的 getter 步骤为返回 [[coded height]]

codedRect, 类型为 DOMRectReadOnly,只读,可为 null

一个 DOMRectReadOnly,其 widthheightcodedWidthcodedHeight 相同,xy(0,0)。便于与 allocationSize()copyTo() 一起使用。

codedRect 的 getter 步骤为:

  1. 如果 [[Detached]]true,返回 null

  2. rect 为新建的 DOMRectReadOnly,初始化如下:

    1. 0 分别赋值给 xy

    2. [[coded width]][[coded height]] 分别赋值给 widthheight

  3. 返回 rect

visibleRect, 类型为 DOMRectReadOnly,只读,可为 null

一个 DOMRectReadOnly,描述该 VideoFrame 的可见像素矩形。

visibleRect 的 getter 步骤为:

  1. 如果 [[Detached]]true,返回 null

  2. rect 为新建的 DOMRectReadOnly,初始化如下:

    1. [[visible left]][[visible top]][[visible width]][[visible height]] 分别赋值给 xywidthheight

  3. 返回 rect

rotation, 类型为 double,只读

渲染 VideoFrame 时应用的旋转角度,单位为顺时针度数。旋转在翻转之前应用。

rotation 的 getter 步骤为返回 [[rotation]]

flip, 类型为 boolean,只读

渲染 VideoFrame 时是否应用水平翻转。翻转在旋转之后应用。

flip 的 getter 步骤为返回 [[flip]]

displayWidth, 类型为 unsigned long,只读

应用旋转和纵横比调整后显示 VideoFrame 的宽度。

displayWidth 的 getter 步骤为返回 [[display width]]

displayHeight, 类型为 unsigned long,只读

应用旋转和纵横比调整后显示 VideoFrame 的高度。

displayHeight 的 getter 步骤为返回 [[display height]]

timestamp, 类型为 long long,只读

展示时间戳(微秒)。解码时,时间戳从对应的 EncodedVideoChunk 复制到本 VideoFrame;编码时,时间戳从本 VideoFrame 复制到对应的 EncodedVideoChunk

timestamp 的 getter 步骤为返回 [[timestamp]]

duration, 类型为 unsigned long long,只读,可为 null

展示持续时间,单位为微秒。该持续时间从对应的 EncodedVideoChunk 复制到本 VideoFrame。

duration 的 getter 步骤为返回 [[duration]]

colorSpace, 类型为 VideoColorSpace,只读

该帧关联的 VideoColorSpace

colorSpace 的 getter 步骤为返回 [[color space]]

9.4.4. 内部结构

combined buffer layout 是一个 结构体,包含:

computed plane layout 是一个 结构体,包含:

9.4.5. 方法

allocationSize(options)

返回用于 BufferSource 的最小有效字节长度,可与指定 options 一起用于 copyTo()

调用时,执行以下步骤:

  1. 如果 [[Detached]]true,抛出 InvalidStateError DOMException

  2. 如果 [[format]]null,抛出 NotSupportedError DOMException

  3. options 运行 VideoFrameCopyToOptions 解析算法,令结果为 combinedLayout

  4. 如果 combinedLayout 是异常,则抛出 combinedLayout

  5. 返回 combinedLayoutallocationSize

copyTo(destination, options)

异步将当前帧的 plane 按 options 复制到 destination。数据格式为 options.format(如果存在),否则为 this VideoFrameformat

注:多次调用 copyTo() 返回的 Promise 不保证按调用顺序 resolve。

调用时,执行以下步骤:

  1. 如果 [[Detached]]true,返回一个被拒绝的 promise,错误为 InvalidStateError DOMException

  2. 如果 [[format]]null,返回一个被拒绝的 promise,错误为 NotSupportedError DOMException

  3. options 运行 VideoFrameCopyToOptions 解析算法,令结果为 combinedLayout

  4. 如果 combinedLayout 是异常,则返回一个被拒绝的 promise,错误为 combinedLayout

  5. 如果 destination.byteLength 小于 combinedLayoutallocationSize,则返回一个被拒绝的 promise,错误为 TypeError

  6. 如果 options.format 等于下列之一:RGBARGBXBGRABGRX,则:

    1. options 运行 配置克隆算法,得 newOptions

    2. undefined 赋值给 newOptions.format

    3. thisoptions.formatoptions.colorSpace 运行 转为RGB帧算法,令结果为 rgbFrame

    4. rgbFrame 使用 destinationnewOptions 调用 copyTo(),返回结果。

  7. p 为新建的 Promise

  8. copyStepsQueue 为新建的 并行队列

  9. planeLayouts 为新建的 列表

  10. 将以下步骤入队到 copyStepsQueue

    1. 令 resource 为 [[resource reference]] 所引用的 media resource

    2. numPlanes[[format]] 定义的 plane 数量。

    3. planeIndex0

    4. planeIndex 小于 combinedLayoutnumPlanes 时:

      1. sourceStrideresource 中由 planeIndex 标识的 plane 步幅。

      2. computedLayoutcombinedLayoutcomputedLayouts 列表中第 planeIndex 个元素。

      3. sourceOffsetcomputedLayoutsourceTop 乘以 sourceStride 的结果。

      4. computedLayoutsourceLeftBytes 加到 sourceOffset 上。

      5. destinationOffsetcomputedLayoutdestinationOffset

      6. rowBytescomputedLayoutsourceWidthBytes

      7. layout 为新建的 PlaneLayout,其中 offset 设为 destinationOffsetstride 设为 rowBytes

      8. row0

      9. row 小于 computedLayoutsourceHeight 时:

        1. resourcesourceOffset 起的 rowBytes 字节复制到 destinationdestinationOffset 起。

        2. sourceOffset 加上 sourceStride

        3. destinationOffset 加上 computedLayoutdestinationStride

        4. row1

      10. planeIndex1

      11. layout 添加到 planeLayouts

    5. 队列任务,用 planeLayouts resolve p

  11. 返回 p

clone()

创建一个新的 VideoFrame,其引用与原 media resource 相同。

调用时,执行以下步骤:

  1. 如果 frame[[Detached]] 内部插槽值为 true,抛出 InvalidStateError DOMException

  2. VideoFrame 克隆算法和 this 运行,并返回结果。

close()

清除所有状态,并释放对 media resource 的引用。 关闭操作是最终的。

调用时,使用 关闭 VideoFrame 算法和 this 执行。

metadata()

获取与该帧关联的 VideoFrameMetadata

调用时,执行以下步骤:

  1. 如果 [[Detached]]true, 抛出 InvalidStateError DOMException

  2. 返回用 [[metadata]] 调用 VideoFrame 元数据复制 的结果。

9.4.6. 算法

创建 VideoFrame(带 output, timestamp, duration, displayAspectWidth, displayAspectHeight, colorSpace, rotation, 和 flip
  1. frame 为新的 VideoFrame,初始化如下:

    1. false 赋值给 [[Detached]]

    2. resourceoutput 所描述的 media resource

    3. resourceReferenceresource 的引用。

    4. resourceReference 赋值给 [[resource reference]]

    5. 如果 output 使用已知的 VideoPixelFormat,则将该格式赋值给 [[format]];否则将 null 赋值给 [[format]]

    6. codedWidthcodedHeightoutput 的编码宽高(像素)。

    7. visibleLeftvisibleTopvisibleWidthvisibleHeightoutput 可见矩形的左、上、宽、高。

    8. displayWidthdisplayHeightoutput 的显示尺寸(像素)。

    9. 如果提供了 displayAspectWidthdisplayAspectHeight,则增大 displayWidthdisplayHeight,直到其比例与 displayAspectWidth : displayAspectHeight 一致。

    10. codedWidthcodedHeightvisibleLeftvisibleTopvisibleWidthvisibleHeightdisplayWidthdisplayHeight 分别赋值为 [[coded width]][[coded height]][[visible left]][[visible top]][[visible width]]、 以及 [[visible height]]

    11. durationtimestamp 分别赋值给 [[duration]][[timestamp]]

    12. colorSpace[[format]] 运行 色彩空间选择算法,并赋值给 [[color space]]

    13. rotationflip 分别赋值给 rotationflip

  2. 返回 frame

色彩空间选择(带 overrideColorSpaceformat
  1. 如果提供了 overrideColorSpace,则返回用 overrideColorSpace 构造的新 VideoColorSpace

    用户代理可以用实现者自定义的启发式方法替换 overrideColorSpace 中的 null 成员。

  2. 否则,如果 [[format]]RGB 格式,则返回新的 sRGB 色彩空间实例。

  3. 否则,返回新的 REC709 色彩空间实例。

校验 VideoFrameInit(带 format, codedWidth, codedHeight
  1. 如果 visibleRect 存在

    1. formatvisibleRect 运行 矩形偏移对齐校验,结果为 validAlignment

    2. 如果 validAlignmentfalse,返回 false

    3. 如果 visibleRect 的任意属性为负或非有限值,返回 false

    4. 如果 visibleRect.width == 0visibleRect.height == 0,返回 false

    5. 如果 visibleRect.y + visibleRect.height > codedHeight,返回 false

    6. 如果 visibleRect.x + visibleRect.width > codedWidth,返回 false

  2. 如果 codedWidth = 0 或 codedHeight = 0,返回 false

  3. 如果 displayWidthdisplayHeight 只有一个 存在,返回 false

  4. 如果 displayWidth == 0displayHeight == 0,返回 false

  5. 返回 true

要检查 VideoFrameBufferInit 是否为 有效的 VideoFrameBufferInit,执行以下步骤:
  1. 如果 codedWidth = 0 或 codedHeight = 0,返回 false

  2. 如果 visibleRect 的任意属性为负或非有限值,返回 false

  3. 如果 visibleRect.y + visibleRect.height > codedHeight,返回 false

  4. 如果 visibleRect.x + visibleRect.width > codedWidth,返回 false

  5. 如果 displayWidthdisplayHeight 只有一个 存在,返回 false

  6. 如果 displayWidth = 0 或 displayHeight = 0,返回 false

  7. 返回 true

从其他帧初始化 VideoFrame(带 init, frame, otherFrame
  1. formatotherFrame.format

  2. 如果 init.alphadiscard, 则将 otherFrame.format等效不透明格式 赋值给 format

  3. validInit 为用 formatotherFrame[[coded width]][[coded height]] 运行 校验 VideoFrameInit 算法的结果。

  4. 如果 validInitfalse,则抛出 TypeError

  5. resourceotherFrame[[resource reference]] 所引用的 media resource

  6. resource 生成新引用,赋值给 frame[[resource reference]]

  7. otherFrame 的以下属性赋值给 framecodedWidthcodedHeightcolorSpace

  8. defaultVisibleRect 为对 otherFrame 执行 visibleRect 的 getter 步骤的结果。

  9. baseRotationbaseFlip 分别为 otherFrame[[rotation]][[flip]]

  10. defaultDisplayWidthdefaultDisplayHeight 分别为 otherFrame[[display width]][[display height]]

  11. initframedefaultVisibleRectbaseRotationbaseFlipdefaultDisplayWidthdefaultDisplayHeight 运行 可见矩形、方向与显示尺寸初始化算法。

  12. 如果 durationinit存在,则赋值给 frame[[duration]]; 否则,将 otherFrame.duration 赋值给 frame[[duration]]

  13. 如果 timestampinit存在,则赋值给 frame[[timestamp]]; 否则,将 otherFrametimestamp 赋值给 frame[[timestamp]]

  14. format 赋值给 frame.[[format]]

  15. initmetadata 调用 VideoFrame 元数据复制,赋值给 frame.[[metadata]]

用资源初始化帧(带 init, frame, resource, codedWidth, codedHeight, baseRotation, baseFlip, defaultDisplayWidth, defaultDisplayHeight
  1. formatnull

  2. 如果 resource 使用已知的 VideoPixelFormat, 将 resourceVideoPixelFormat 赋值给 format

  3. validInit 为用 formatwidthheight 运行 校验 VideoFrameInit 算法的结果。

  4. 如果 validInitfalse,则抛出 TypeError

  5. resource 生成新引用,赋值给 frame[[resource reference]]

  6. 如果 init.alphadiscard, 则将 format等效不透明格式赋值给 format

  7. format 赋值给 [[format]]

  8. codedWidthcodedHeight 分别赋值给 frame[[coded width]][[coded height]]

  9. defaultVisibleRect 为用 «[ "x:" → 0, "y" → 0, "width" → codedWidth, "height" → codedHeight ]» 构造的新 DOMRect

  10. initframedefaultVisibleRectdefaultDisplayWidthdefaultDisplayHeight 运行 可见矩形、方向与显示尺寸初始化算法。

  11. init.duration 赋值给 frame[[duration]]

  12. init.timestamp 赋值给 frame[[timestamp]]

  13. 如果 resource 有已知的 VideoColorSpace, 将其赋值给 [[color space]]

  14. 否则,创建一个新的用空 VideoColorSpaceInit 构造的 VideoColorSpace,赋值给 [[color space]]

初始化可见矩形、方向与显示尺寸 (参数:init, frame, defaultVisibleRect, baseRotation, baseFlip, defaultDisplayWidth, defaultDisplayHeight
  1. visibleRect = defaultVisibleRect

  2. 如果 init.visibleRect 存在,则赋值给 visibleRect

  3. visibleRectxywidthheight 分别赋值给 frame[[visible left]][[visible top]][[visible width]][[visible height]]

  4. rotation 为用 init.rotation 执行 旋转解析算法的结果。

  5. baseRotationbaseFliprotation 执行 旋转叠加算法,将其结果赋值给 frame[[rotation]]

  6. 如果 baseFlip 等于 init.flip,则将 false 赋值给 frame[[flip]];否则赋值 trueframe[[flip]]

  7. 如果 initdisplayWidthdisplayHeight 存在,则分别赋值给 [[display width]][[display height]]

  8. 否则:

    1. 如果 baseRotation 等于 0180

      1. widthScale = defaultDisplayWidth / defaultVisibleRect.width

      2. heightScale = defaultDisplayHeight / defaultVisibleRect.height

    2. 否则:

      1. widthScale = defaultDisplayHeight / defaultVisibleRect.width

      2. heightScale = defaultDisplayWidth / defaultVisibleRect.height

    3. displayWidth|frame| 的 {{VideoFrame/[[visible width]]}} * |widthScale|,四舍五入为最近的整数。

    4. displayHeight|frame| 的 {{VideoFrame/[[visible height]]}} * |heightScale|,四舍五入为最近的整数。

    5. 如果 rotation 等于 0180

      1. displayWidth 赋值给 frame[[display width]]

      2. displayHeight 赋值给 frame[[display height]]

    6. 否则:

      1. displayHeight 赋值给 frame[[display width]]

      2. displayWidth 赋值给 frame[[display height]]

克隆 VideoFrame(参数:frame
  1. clone 为新建的 VideoFrame,初始化如下:

    1. resourceframe[[resource reference]] 所引用的 media resource

    2. newReferenceresource 的新引用。

    3. newReference 赋值给 clone[[resource reference]]

    4. frame 的剩余所有内部插槽(除 [[resource reference]] 外)赋值给 clone 的同名槽。

  2. 返回 clone

关闭 VideoFrame(参数:frame
  1. null 赋值给 frame[[resource reference]]

  2. true 赋值给 frame[[Detached]]

  3. null 赋值给 frameformat

  4. 0 赋值给 frame[[coded width]][[coded height]][[visible left]][[visible top]][[visible width]][[visible height]][[rotation]][[display width]][[display height]]

  5. false 赋值给 frame[[flip]]

  6. 创建一个新的 VideoFrameMetadata,赋值给 frame.[[metadata]]

解析旋转(参数 rotation
  1. alignedRotation 为最接近 90 的倍数,四舍五入取正无穷的 rotation

  2. fullTurns 为小于等于 alignedRotation 的最大 360 的倍数。

  3. 返回 |alignedRotation| - |fullTurns|

旋转叠加(参数 baseRotation, baseFlip, rotation
  1. 如果 baseFlipfalse,令 combinedRotation = |baseRotation| + |rotation|;否则令 combinedRotation = |baseRotation| - |rotation|

  2. fullTurns 为小于等于 combinedRotation 的最大 360 的倍数。

  3. 返回 |combinedRotation| - |fullTurns|

解析 VideoFrameCopyToOptions(参数 options
  1. defaultRect 为执行 visibleRect 的 getter 步骤所得结果。

  2. overrideRectundefined

  3. 如果 options.rect 存在,则将 options.rect 的值赋给 overrideRect

  4. parsedRect 为用 defaultRectoverrideRect[[coded width]][[coded height]][[format]] 运行 解析可见矩形算法的结果。

  5. 如果 parsedRect 是异常,返回 parsedRect

  6. optLayoutundefined

  7. 如果 options.layout 存在,则赋值给 optLayout

  8. formatundefined

  9. 如果 options.format存在,则将 [[format]] 赋值给 format

  10. 否则,如果 options.format 等于 RGBARGBXBGRABGRX 之一,则将 options.format 赋值给 format;否则返回 NotSupportedError

  11. combinedLayout 为用 parsedRectformatoptLayout 运行 布局与分配大小计算算法的结果。

  12. 返回 combinedLayout

校验矩形偏移对齐(参数 format, rect
  1. 如果 formatnull,返回 true

  2. planeIndex = 0

  3. numPlanesformat 定义的 plane 数量。

  4. planeIndex 小于 numPlanes 时:

    1. planeformat 定义的由 planeIndex 标识的 Plane。

    2. sampleWidthplane 每个子采样的水平子采样因子

    3. sampleHeightplane 每个子采样的垂直子采样因子

    4. 如果 rect.x 不是 sampleWidth 的倍数,返回 false

    5. 如果 rect.y 不是 sampleHeight 的倍数,返回 false

    6. planeIndex1

  5. 返回 true

解析可见矩形(参数 defaultRect, overrideRect, codedWidth, codedHeight, format
  1. sourceRect = defaultRect

  2. 如果 overrideRect 不为 undefined

    1. 如果 overrideRect.widthheight0,返回 TypeError

    2. 如果 overrideRect.xoverrideRect.width 之和大于 codedWidth,返回 TypeError

    3. 如果 overrideRect.yoverrideRect.height 之和大于 codedHeight,返回 TypeError

    4. overrideRect 赋值给 sourceRect

  3. validAlignment 为用 formatsourceRect 运行 校验矩形偏移对齐算法的结果。

  4. 如果 validAlignmentfalse,则抛出 TypeError

  5. 返回 sourceRect

布局与分配大小计算(参数 parsedRect, format, layout
  1. numPlanesformat 定义的 plane 数量。

  2. 如果 layout 不为 undefined 且其长度不等于 numPlanes,则抛出 TypeError

  3. minAllocationSize = 0

  4. computedLayouts 为新建的 列表

  5. endOffsets 为新建的 列表

  6. planeIndex = 0

  7. planeIndex < numPlanes 时:

    1. planeformat 定义的由 planeIndex 标识的 Plane。

    2. sampleBytesplane 的每个样本字节数。

    3. sampleWidthplane 每个子采样的水平子采样因子

    4. sampleHeightplane 每个子采样的垂直子采样因子

    5. computedLayout 为新建的 computed plane layout

    6. 将截断后的 parsedRect.y 除以 sampleHeight,向上取整赋值给 computedLayoutsourceTop

    7. 将截断后的 parsedRect.height 除以 sampleHeight,向上取整赋值给 computedLayoutsourceHeight

    8. 将截断后的 parsedRect.x 整除 sampleWidth 后乘以 sampleBytes赋值给 computedLayoutsourceLeftBytes

    9. 将截断后的 parsedRect.width 整除 sampleWidth 后乘以 sampleBytes赋值给 computedLayoutsourceWidthBytes

    10. 如果 layout 不为 undefined

      1. planeLayoutlayout 中第 planeIndex 项的 PlaneLayout

      2. 如果 planeLayout.stride 小于 computedLayoutsourceWidthBytes,返回 TypeError

      3. planeLayout.offset 赋值给 computedLayoutdestinationOffset

      4. planeLayout.stride 赋值给 computedLayoutdestinationStride

    11. 否则:

      注:未提供显式布局时,以下步骤默认紧密打包。

      1. minAllocationSize 赋值给 computedLayoutdestinationOffset

      2. computedLayoutsourceWidthBytes 赋值给 computedLayoutdestinationStride

    12. planeSizecomputedLayoutdestinationStridesourceHeight 的乘积。

    13. planeEndplaneSizecomputedLayoutdestinationOffset 之和。

    14. 如果 planeSizeplaneEnd 大于 unsigned long 的最大范围,返回 TypeError

    15. planeEnd 添加到 endOffsets

    16. minAllocationSizeplaneEnd 的最大值赋值给 minAllocationSize

      注:上一步用 max 是为了允许用户指定的 plane offset 重新排序 plane。

    17. earlierPlaneIndex = 0

    18. earlierPlaneIndex 小于 planeIndex 时:

      1. earlierLayout = computedLayouts[earlierPlaneIndex]

      2. 如果 endOffsets[planeIndex] 小于等于 earlierLayoutdestinationOffset,或 endOffsets[earlierPlaneIndex] 小于等于 computedLayoutdestinationOffset,则 continue。

        注:如果 plane A 结束早于 plane B 起始,两者不重叠。

      3. 否则返回 TypeError

      4. earlierPlaneIndex1

    19. computedLayout 添加到 computedLayouts

    20. planeIndex1

  8. combinedLayout 为新建的 combined buffer layout,初始化如下:

    1. computedLayouts 赋值给 computedLayouts

    2. minAllocationSize 赋值给 allocationSize

  9. 返回 combinedLayout

预定义色彩空间转 VideoColorSpace(参数 colorSpace
  1. 断言:colorSpace 等于 srgbdisplay-p3

  2. 如果 colorSpace 等于 srgb,返回新的 sRGB 色彩空间实例。

  3. 如果 colorSpace 等于 display-p3,返回新的 Display P3 色彩空间实例。

转为RGB帧(参数 frame, format, colorSpace
  1. 该算法必须仅当 format 等于 RGBARGBXBGRABGRX 时调用。

  2. convertedFrame 为新建的 VideoFrame,初始化如下:

    1. false 赋值给 [[Detached]]

    2. format 赋值给 [[format]]

    3. width = frame[[visible width]]

    4. height = frame[[visible height]]

    5. widthheight、0、0、widthheightwidthheight 分别赋值给 [[coded width]][[coded height]][[visible left]][[visible top]][[visible width]][[visible height]]

    6. frame[[duration]][[timestamp]] 分别赋值给 [[duration]][[timestamp]]

    7. colorSpace 运行 预定义色彩空间转 VideoColorSpace 算法,并赋值给 [[color space]]

    8. resource 为新建的 media resource,内容为 frame[[resource reference]] 所引用的 media resource[[color space]][[format]] 转换后的结果。

    9. resource 的引用赋值给 [[resource reference]]

  3. 返回 convertedFrame

VideoFrame 元数据复制(参数 metadata
  1. metadataCopySerializedStructuredSerialize(metadata)。

  2. metadataCopyStructuredDeserialize(metadataCopySerialized, 当前 Realm)。

  3. 返回 metadataCopy

该算法的目标是确保 VideoFrame 所拥有的元数据是不可变的。

9.4.7. 传输与序列化

VideoFrame 传输步骤(带 valuedataHolder) 如下:
  1. 如果 value[[Detached]]true,则抛出 DataCloneError DOMException

  2. 对于 value 中所有 VideoFrame 内部插槽,将每个内部插槽的值赋给 dataHolder 中同名字段。

  3. 使用 value 运行 关闭 VideoFrame 算法。

VideoFrame 传输接收步骤(带 dataHoldervalue)如下:
  1. 对于 dataHolder 中所有命名字段,将每个字段的值赋给 value 中同名的 VideoFrame 内部插槽。

VideoFrame 序列化步骤(带 valueserializedforStorage)如下:
  1. 如果 value[[Detached]]true,则抛出 DataCloneError DOMException

  2. 如果 forStoragetrue,则抛出 DataCloneError

  3. resourcevalue[[resource reference]] 所引用的 媒体资源

  4. newReferenceresource 的新引用。

  5. newReference 赋值给 |serialized.resource reference|。

  6. 对于 value 中所有剩余 VideoFrame 内部插槽(不包括 [[resource reference]]), 将每个内部插槽的值赋给 serialized 中同名字段。

VideoFrame 反序列化步骤(带 serializedvalue) 如下:
  1. 对于 serialized 中所有命名字段,将每个字段的值赋给 value 中同名的 VideoFrame 内部插槽。

9.4.8. 渲染

被渲染时,例如通过 CanvasDrawImage drawImage()VideoFrame 必须 被转换为与渲染目标兼容的色彩空间,除非明确禁用色彩转换。

ImageBitmap 构建过程中的色彩空间转换由 ImageBitmapOptionscolorSpaceConversion 控制。 设置为 "none" 时会禁用色彩空间转换。

VideoFrame 的渲染通过 媒体资源 生成, 并应用必要的色彩空间转换、裁剪到 visibleRect, 顺时针旋转 rotation 度,并在 fliptrue 时进行水平翻转。

9.5. VideoFrame CopyTo() 选项

用于指定要复制的像素矩形、它们的格式,以及目标缓冲区中各平面的偏移和步幅的选项。
dictionary VideoFrameCopyToOptions {
  DOMRectInit rect;
  sequence<PlaneLayout> layout;
  VideoPixelFormat format;
  PredefinedColorSpace colorSpace;
};
注意:copyTo()allocationSize() 的步骤将强制执行以下要求:
rect, 类型为 DOMRectInit

一个 DOMRectInit 描述要从 VideoFrame 复制的像素矩形。 如果未指定,则使用 visibleRect

注意:可以通过传递 VideoFramecodedRect 来指定编码矩形。

注意:默认的 rect 不一定满足采样对齐要求,可能导致 copyTo()allocationSize() 被拒绝。

layout, 类型为 sequence<PlaneLayout>

每个平面的 PlaneLayout, 可选地为目标 BufferSource 中的每个平面指定偏移和步幅。 如果未指定,各平面将紧密排列。指定重叠平面是无效的。

format, 类型为 VideoPixelFormat

目标 BufferSource 中像素数据的 VideoPixelFormat 。 可选值包括:RGBARGBXBGRABGRX。 如果未存在,目标 BufferSourceformat 格式相同。

colorSpace, 类型为 PredefinedColorSpace

一个 PredefinedColorSpace ,它必须作为目标像素数据的色彩空间用于目标 BufferSource, 但仅当 formatRGBARGBXBGRABGRX 之一,否则将被忽略。 如果未存在,则使用 srgb

9.6. VideoFrame中的DOMRect

VideoFrame 接口使用 DOMRect 来指定像素矩形的位置和尺寸。 DOMRectInitcopyTo()allocationSize() 搭配使用,用于描述源矩形的尺寸。 VideoFrame 定义了 codedRectvisibleRect 以便分别方便地复制编码尺寸和可见区域。

注意:VideoFrame的像素只能用整数寻址。所有传递给 DOMRectInit 的浮点值都将被截断。

9.7. 平面布局

PlaneLayout 是一个字典,用于指定 VideoFrame 某个平面在被复制到 BufferSource 后的偏移和步幅。 一组 PlaneLayout 可以被传递给 VideoFramecopyTo(), 用于指定平面在目标 BufferSource 的布局方式。 或者,调用者可以检查 copyTo() 返回的 PlaneLayout 序列, 以获知由用户代理决定的各平面的偏移和步幅。
dictionary PlaneLayout {
  [EnforceRange] required unsigned long offset;
  [EnforceRange] required unsigned long stride;
};
offset, 类型为 unsigned long

给定平面在 BufferSource 内开始的字节偏移量。

stride, 类型为 unsigned long

该平面在 BufferSource 内每行使用的字节数,包括填充。

9.8. 像素格式

像素格式描述了每个平面内字节的排列方式,以及平面的数量和顺序。每种格式将在其各自的小节中说明。
enum VideoPixelFormat {
  // 4:2:0 Y, U, V
  "I420",
  "I420P10",
  "I420P12",
  // 4:2:0 Y, U, V, A
  "I420A",
  "I420AP10",
  "I420AP12",
  // 4:2:2 Y, U, V
  "I422",
  "I422P10",
  "I422P12",
  // 4:2:2 Y, U, V, A
  "I422A",
  "I422AP10",
  "I422AP12",
  // 4:4:4 Y, U, V
  "I444",
  "I444P10",
  "I444P12",
  // 4:4:4 Y, U, V, A
  "I444A",
  "I444AP10",
  "I444AP12",
  // 4:2:0 Y, UV
  "NV12",
  // 4:4:4 RGBA
  "RGBA",
  // 4:4:4 RGBX (opaque)
  "RGBX",
  // 4:4:4 BGRA
  "BGRA",
  // 4:4:4 BGRX (opaque)
  "BGRX",
};

Sub-sampling 是一种技术,单个样本包含用于最终图像中多个像素的信息。 Sub-sampling 可以是水平的、垂直的或两者兼有,并且具有一个 factor,即从一个 sub-sampled 样本派生出的最终图像像素数量。

如果一个 VideoFrame 使用 I420 格式,那么第二个平面(U 平面)的第一个分量对应图像左上角的四个像素。因此,第二行的第一个分量对应位于这四个左上初始像素正下方的四个像素。sub-sampling factor 在水平方向和垂直方向上均为 2。

如果某个 VideoPixelFormat 包含 alpha 分量,则该格式的 equivalent opaque format 为去除 alpha 分量后的相同 VideoPixelFormat。如果某个 VideoPixelFormat 本身不包含 alpha 分量,则它自身就是其 equivalent opaque format

整数值均为无符号,除非另有说明。

I420
该格式由三个不同的平面组成:一个亮度平面和两个色度平面,分别记为 Y、U 和 V,按此顺序存在。它通常也称为 Planar YUV 4:2:0。

与 Y 平面相比,U 和 V 平面在水平方向和垂直方向上都按 sub-sampledfactor 为 2。

该格式中每个样本为 8 位。

Y 平面有 codedWidth * codedHeight 个样本(因此也是字节),从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

U 和 V 平面的行数等于将 codedHeight 除以 2 后向上取整的结果。每行的样本数等于将 codedWidth 除以 2 后向上取整的结果。样本从图像左上角开始排列。

可见矩形的偏移(visibleRect.xvisibleRect.y必须为偶数。

I420P10
该格式由三个不同的平面组成:一个亮度平面和两个色度平面,分别记为 Y、U 和 V,按此顺序存在。

与 Y 平面相比,U 和 V 平面在水平方向和垂直方向上都按 sub-sampledfactor 为 2。

该格式中每个样本为 10 位,按小端字节序编码为 16 位整数。

Y 平面有 codedWidth * codedHeight 个样本,从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

U 和 V 平面的行数等于将 codedHeight 除以 2 后向上取整的结果。每行的样本数等于将 codedWidth 除以 2 后向上取整的结果。样本从图像左上角开始排列。

可见矩形的偏移(visibleRect.xvisibleRect.y必须为偶数。

I420P12
该格式由三个不同的平面组成:一个亮度平面和两个色度平面,分别记为 Y、U 和 V,按此顺序存在。

与 Y 平面相比,U 和 V 平面在水平方向和垂直方向上都按 sub-sampledfactor 为 2。

该格式中每个样本为 12 位,按小端字节序编码为 16 位整数。

Y 平面有 codedWidth * codedHeight 个样本,从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

U 和 V 平面的行数等于将 codedHeight 除以 2 后向上取整的结果。每行的样本数等于将 codedWidth 除以 2 后向上取整的结果。样本从图像左上角开始排列。

可见矩形的偏移(visibleRect.xvisibleRect.y必须为偶数。

I420A
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。它通常也称为带 alpha 通道的 Planar YUV 4:2:0。

与 Y 和 Alpha 平面相比,U 和 V 平面在水平方向和垂直方向上都按 sub-sampledfactor 为 2。

该格式中每个样本为 8 位。

Y 和 Alpha 平面有 codedWidth * codedHeight 个样本(因此也是字节),从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

U 和 V 平面的行数等于将 codedHeight 除以 2 后向上取整的结果。每行的样本数等于将 codedWidth 除以 2 后向上取整的结果。样本从图像左上角开始排列。

可见矩形的偏移(visibleRect.xvisibleRect.y必须为偶数。

I420Aequivalent opaque formatI420

I420AP10
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。

与 Y 和 Alpha 平面相比,U 和 V 平面在水平方向和垂直方向上都按 sub-sampledfactor 为 2。

该格式中每个样本为 10 位,按小端字节序编码为 16 位整数。

Y 和 Alpha 平面有 codedWidth * codedHeight 个样本,从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

U 和 V 平面的行数等于将 codedHeight 除以 2 后向上取整的结果。每行的样本数等于将 codedWidth 除以 2 后向上取整的结果。样本从图像左上角开始排列。

可见矩形的偏移(visibleRect.xvisibleRect.y必须为偶数。

I420AP10equivalent opaque formatI420P10

I420AP12
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。

与 Y 和 Alpha 平面相比,U 和 V 平面在水平方向和垂直方向上都按 sub-sampledfactor 为 2。

该格式中每个样本为 12 位,按小端字节序编码为 16 位整数。

Y 和 Alpha 平面有 codedWidth * codedHeight 个样本,从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

U 和 V 平面的行数等于将 codedHeight 除以 2 后向上取整的结果。每行的样本数等于将 codedWidth 除以 2 后向上取整的结果。样本从图像左上角开始排列。

可见矩形的偏移(visibleRect.xvisibleRect.y必须为偶数。

I420AP12equivalent opaque formatI420P12

I422
该格式由三个不同的平面组成:一个亮度平面和两个色度平面,分别记为 Y、U 和 V,按此顺序存在。它通常也称为 Planar YUV 4:2:2。

与 Y 平面相比,U 和 V 平面在水平方向上按 sub-sampledfactor 为 2, 在垂直方向上不进行 sub-sampled

该格式中每个样本为 8 位。

Y 平面有 codedWidth * codedHeight 个样本(因此也是字节),从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

U 和 V 平面有 codedHeight 行。每行的样本数等于将 codedWidth 除以 2 后向上取整的结果。样本从图像左上角开始排列。

可见矩形的水平偏移(visibleRect.x必须为偶数。

I422P10
该格式由三个不同的平面组成:一个亮度平面和两个色度平面,分别记为 Y、U 和 V,按此顺序存在。

与 Y 平面相比,U 和 V 平面在水平方向上按 sub-sampledfactor 为 2, 在垂直方向上不进行 sub-sampled

该格式中每个样本为 10 位,按小端字节序编码为 16 位整数。

Y 平面有 codedWidth * codedHeight 个样本,从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

U 和 V 平面有 codedHeight 行。每行的样本数等于将 codedWidth 除以 2 后向上取整的结果。样本从图像左上角开始排列。

可见矩形的水平偏移(visibleRect.x必须为偶数。

I422P12
该格式由三个不同的平面组成:一个亮度平面和两个色度平面,分别记为 Y、U 和 V,按此顺序存在。

与 Y 平面相比,U 和 V 平面在水平方向上按 sub-sampledfactor 为 2, 在垂直方向上不进行 sub-sampled

该格式中每个样本为 12 位,按小端字节序编码为 16 位整数。

Y 平面有 codedWidth * codedHeight 个样本,从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

U 和 V 平面有 codedHeight 行。每行的样本数等于将 codedWidth 除以 2 后向上取整的结果。样本从图像左上角开始排列。

可见矩形的水平偏移(visibleRect.x必须为偶数。

I422A
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。它通常也称为带 alpha 通道的 Planar YUV 4:2:2。

与 Y 和 Alpha 平面相比,U 和 V 平面在水平方向上按 sub-sampledfactor 为 2, 在垂直方向上不进行 sub-sampled

该格式中每个样本为 8 位。

Y 和 Alpha 平面有 codedWidth * codedHeight 个样本(因此也是字节),从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

U 和 V 平面有 codedHeight 行。每行的样本数等于将 codedWidth 除以 2 后向上取整的结果。样本从图像左上角开始排列。

可见矩形的水平偏移(visibleRect.x必须为偶数。

I422Aequivalent opaque formatI422

I422AP10
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。

与 Y 和 Alpha 平面相比,U 和 V 平面在水平方向上按 sub-sampledfactor 为 2, 在垂直方向上不进行 sub-sampled

该格式中每个样本为 10 位,按小端字节序编码为 16 位整数。

Y 和 Alpha 平面有 codedWidth * codedHeight 个样本,从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

U 和 V 平面有 codedHeight 行。每行的样本数等于将 codedWidth 除以 2 后向上取整的结果。样本从图像左上角开始排列。

可见矩形的水平偏移(visibleRect.x必须为偶数。

I422AP10equivalent opaque formatI420P10

I422AP12
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。

与 Y 和 Alpha 平面相比,U 和 V 平面在水平方向上按 sub-sampledfactor 为 2, 在垂直方向上不进行 sub-sampled

该格式中每个样本为 12 位,按小端字节序编码为 16 位整数。

Y 和 Alpha 平面有 codedWidth * codedHeight 个样本,从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

U 和 V 平面有 codedHeight 行。每行的样本数等于将 codedWidth 除以 2 后向上取整的结果。样本从图像左上角开始排列。

可见矩形的水平偏移(visibleRect.x必须为偶数。

I422AP10equivalent opaque formatI420P10

I444
该格式由三个不同的平面组成:一个亮度平面和两个色度平面,分别记为 Y、U 和 V,按此顺序存在。它通常也称为 Planar YUV 4:4:4。

该格式不使用 sub-sampling

该格式中每个样本为 8 位。

三个平面中均有 codedWidth * codedHeight 个样本(因此也是字节),从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

I444P10
该格式由三个不同的平面组成:一个亮度平面和两个色度平面,分别记为 Y、U 和 V,按此顺序存在。

该格式不使用 sub-sampling

该格式中每个样本为 10 位,按小端字节序编码为 16 位整数。

三个平面中均有 codedWidth * codedHeight 个样本,从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

I444P12
该格式由三个不同的平面组成:一个亮度平面和两个色度平面,分别记为 Y、U 和 V,按此顺序存在。

该格式不使用 sub-sampling

该格式中每个样本为 12 位,按小端字节序编码为 16 位整数。

三个平面中均有 codedWidth * codedHeight 个样本,从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

I444A
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。

该格式不使用 sub-sampling

该格式中每个样本为 8 位。

四个平面中均有 codedWidth * codedHeight 个样本(因此也是字节),从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

I444Aequivalent opaque formatI444

I444AP10
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。

该格式不使用 sub-sampling

该格式中每个样本为 10 位,按小端字节序编码为 16 位整数。

四个平面中均有 codedWidth * codedHeight 个样本,从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

I444AP10equivalent opaque formatI444P10

I444AP12
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。

该格式不使用 sub-sampling

该格式中每个样本为 12 位,按小端字节序编码为 16 位整数。

四个平面中均有 codedWidth * codedHeight 个样本,从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

I444AP10equivalent opaque formatI444P10

NV12
该格式由两个不同的平面组成:先是一个亮度平面,然后是包含两个色度分量的另一个平面。两个平面按此顺序存在,分别称为 Y 平面和 UV 平面。

与 Y 平面中的分量相比,U 和 V 分量在水平方向和垂直方向上都按 sub-sampledfactor 为 2。

该格式中每个样本为 8 位。

Y 平面有 codedWidth * codedHeight 个样本(因此也是字节),从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

UV 平面由交错的 U 和 V 值组成,其行数等于将 codedHeight 除以 2 后向上取整的结果。每行的元素数等于将 codedWidth 除以 2 后向上取整的结果。每个元素由两个色度样本(U 和 V,按此顺序)组成。样本从图像左上角开始排列。

可见矩形的偏移(visibleRect.xvisibleRect.y必须为偶数。

宽度为 16 像素、高度为 10 像素的 NV12 像素格式图像在内存中的排列如下:
YYYYYYYYYYYYYYYY
YYYYYYYYYYYYYYYY
YYYYYYYYYYYYYYYY
YYYYYYYYYYYYYYYY
YYYYYYYYYYYYYYYY
YYYYYYYYYYYYYYYY
YYYYYYYYYYYYYYYY
YYYYYYYYYYYYYYYY
YYYYYYYYYYYYYYYY
YYYYYYYYYYYYYYYY
UVUVUVUVUVUVUVUV
UVUVUVUVUVUVUVUV
UVUVUVUVUVUVUVUV
UVUVUVUVUVUVUVUV
UVUVUVUVUVUVUVUV

所有样本在内存中是线性排列的。

RGBA
该格式由单个平面组成,编码四个分量:Red、Green、Blue 和 alpha 值,按照此顺序存在。

该格式中每个样本为 8 位,因此每个像素为 32 位。

单个平面中有 codedWidth * codedHeight * 4 个样本(因此也是字节),从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

RGBAequivalent opaque formatRGBX

RGBX
该格式由单个平面组成,编码四个分量:Red、Green、Blue 和一个填充值,按照此顺序存在。

该格式中每个样本为 8 位。每个像素的第四个元素应被忽略,图像始终为完全不透明。

单个平面中有 codedWidth * codedHeight * 4 个样本(因此也是字节),从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

BGRA
该格式由单个平面组成,编码四个分量:Blue、Green、Red 和 alpha 值,按照此顺序存在。

该格式中每个样本为 8 位。

单个平面中有 codedWidth * codedHeight * 4 个样本(因此也是字节),从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

BGRAequivalent opaque formatBGRX

BGRX
该格式由单个平面组成,编码四个分量:Blue、Green、Red 和一个填充值,按照此顺序存在。

该格式中每个样本为 8 位。每个像素的第四个元素应被忽略,图像始终为完全不透明。

单个平面中有 codedWidth * codedHeight * 4 个样本(因此也是字节),从图像左上角开始按 codedHeight 行,每行 codedWidth 个样本排列。

9.9. 视频色彩空间接口

[Exposed=(Window,DedicatedWorker)]
interface VideoColorSpace {
  constructor(optional VideoColorSpaceInit init = {});

  readonly attribute VideoColorPrimaries? primaries;
  readonly attribute VideoTransferCharacteristics? transfer;
  readonly attribute VideoMatrixCoefficients? matrix;
  readonly attribute boolean? fullRange;

  [Default] VideoColorSpaceInit toJSON();
};

dictionary VideoColorSpaceInit {
  VideoColorPrimaries? primaries = null;
  VideoTransferCharacteristics? transfer = null;
  VideoMatrixCoefficients? matrix = null;
  boolean? fullRange = null;
};

9.9.1. 内部插槽

[[primaries]]

色度基色。

[[transfer]]

传递特性。

[[matrix]]

矩阵系数。

[[full range]]

指示是否使用全范围色彩值。

9.9.2. 构造函数

VideoColorSpace(init)
  1. c 为一个新的 VideoColorSpace 对象,初始化如下:

    1. init.primaries 赋值给 [[primaries]]

    2. init.transfer 赋值给 [[transfer]]

    3. init.matrix 赋值给 [[matrix]]

    4. init.fullRange 赋值给 [[full range]]

  2. 返回 c

9.9.3. 属性

primaries, 类型为 VideoColorPrimaries,只读,可为 null

primaries 的 getter 步骤为返回 [[primaries]] 的值。

transfer, 类型为 VideoTransferCharacteristics,只读,可为 null

transfer 的 getter 步骤为返回 [[transfer]] 的值。

matrix, 类型为 VideoMatrixCoefficients,只读,可为 null

matrix 的 getter 步骤为返回 [[matrix]] 的值。

fullRange, 类型为 boolean,只读,可为 null

fullRange 的 getter 步骤为返回 [[full range]] 的值。

9.10. 视频色度基色

色度基色描述视频样本的色域。
enum VideoColorPrimaries {
  "bt709",
  "bt470bg",
  "smpte170m",
  "bt2020",
  "smpte432",
};
bt709
BT.709 和 sRGB 使用的色度基色,详见 [H.273] 第 8.1 节表 2 值 1。
bt470bg
BT.601 PAL 使用的色度基色,详见 [H.273] 第 8.1 节表 2 值 5。
smpte170m
BT.601 NTSC 使用的色度基色,详见 [H.273] 第 8.1 节表 2 值 6。
bt2020
BT.2020 和 BT.2100 使用的色度基色,详见 [H.273] 第 8.1 节表 2 值 9。
smpte432
P3 D65 使用的色度基色,详见 [H.273] 第 8.1 节表 2 值 12。

9.11. 视频传递特性

传递特性描述视频样本的光电传递特性。
enum VideoTransferCharacteristics {
  "bt709",
  "smpte170m",
  "iec61966-2-1",
  "linear",
  "pq",
  "hlg",
};
bt709
BT.709 使用的传递特性,详见 [H.273] 第 8.2 节表 3 值 1。
smpte170m
BT.601 使用的传递特性,详见 [H.273] 第 8.2 节表 3 值 6。(与 "bt709" 功能一致。)
iec61966-2-1
sRGB 使用的传递特性,详见 [H.273] 第 8.2 节表 3 值 13。
linear
线性 RGB 使用的传递特性,详见 [H.273] 第 8.2 节表 3 值 8。
pq
BT.2100 PQ 使用的传递特性,详见 [H.273] 第 8.2 节表 3 值 16。
hlg
BT.2100 HLG 使用的传递特性,详见 [H.273] 第 8.2 节表 3 值 18。

9.12. 视频矩阵系数

矩阵系数描述样本分量值与色彩坐标之间的关系。
enum VideoMatrixCoefficients {
  "rgb",
  "bt709",
  "bt470bg",
  "smpte170m",
  "bt2020-ncl",
};
rgb
sRGB 使用的矩阵系数,详见 [H.273] 第 8.3 节表 4 值 0。
bt709
BT.709 使用的矩阵系数,详见 [H.273] 第 8.3 节表 4 值 1。
bt470bg
BT.601 PAL 使用的矩阵系数,详见 [H.273] 第 8.3 节表 4 值 5。
smpte170m
BT.601 NTSC 使用的矩阵系数,详见 [H.273] 第 8.3 节表 4 值 6。(与 "bt470bg" 功能一致。)
bt2020-ncl
BT.2020 NCL 使用的矩阵系数,详见 [H.273] 第 8.3 节表 4 值 9。

10. 图像解码

10.1. 背景

本节为非规范性内容。

图像编解码器定义通常会伴随对应文件格式的定义。因此,图像解码器通常同时完成解包(解复用)和解码图像数据的任务。WebCodecs 的 ImageDecoder 遵循此模式,这也促使其接口设计与 VideoDecoderAudioDecoder 明显不同。

尽管存在这些差异,ImageDecoder 使用与其他编解码器接口相同的 编解码器处理模型。此外, ImageDecoder 使用 VideoFrame 接口描述解码输出。

10.2. ImageDecoder 接口

[Exposed=(Window,DedicatedWorker), SecureContext]
interface ImageDecoder {
  constructor(ImageDecoderInit init);

  readonly attribute DOMString type;
  readonly attribute boolean complete;
  readonly attribute Promise<undefined> completed;
  readonly attribute ImageTrackList tracks;

  Promise<ImageDecodeResult> decode(optional ImageDecodeOptions options = {});
  undefined reset();
  undefined close();

  static Promise<boolean> isTypeSupported(DOMString type);
};

10.2.1. 内部插槽

[[control message queue]]

一个 队列,包含要在此 编解码器实例上执行的 控制消息。参见 [[control message queue]]

[[message queue blocked]]

一个布尔值,指示处理 [[control message queue]] 时是否因有待处理的 控制消息而阻塞。 参见 [[message queue blocked]]

[[codec work queue]]

一个 并行队列,用于运行引用 [[codec implementation]] 的并行步骤。 参见 [[codec work queue]]

[[ImageTrackList]]

一个 ImageTrackList ,描述在 [[encoded data]] 中找到的轨道信息。

[[type]]

一个字符串,反映构造时给定的 MIME type 的值。

[[complete]]

一个布尔值,指示 [[encoded data]] 是否已完全缓冲。

[[completed promise]]

用于指示 [[complete]] 变为 true 时的 promise。

[[codec implementation]]

由用户代理提供的底层图像解码器实现。参见 [[codec implementation]]

[[encoded data]]

一个 字节序列,包含待解码的编码图像数据。

[[prefer animation]]

一个布尔值,反映构造时给定的 preferAnimation 的值。

[[pending decode promises]]

由 decode() 方法返回的未解决 promise 列表。

[[internal selected track index]]

标识 [[encoded data]] 中供解码算法使用的图像轨道。

[[tracks established]]

一个布尔值,指示轨道列表是否已在 [[ImageTrackList]] 中建立。

[[closed]]

一个布尔值,指示 ImageDecoder 是否处于永久关闭状态,无法再使用。

[[progressive frame generations]]

帧索引到 渐进式图像帧代数的映射。值表示最近一次通过 decode() 输出的 VideoFrame 所对应的渐进式图像帧代数。

10.2.2. 构造函数

ImageDecoder(init)

注意:在构造好的 ImageDecoder 上调用 decode() ,如果用户代理不支持 type,会触发 NotSupportedError 。建议作者先通过 isTypeSupported() 检查 type 是否受支持。用户代理无需支持任何特定类型。

调用时,执行以下步骤:

  1. 如果 init 不是 有效的 ImageDecoderInit,抛出 TypeError

  2. 如果 init.transfer 包含对同一个 ArrayBuffer 的多个引用,则抛出 DataCloneError DOMException

  3. 对于 init.transfer 中的每个 transferable

    1. 如果 [[Detached]] 内部插槽为 true, 则抛出 DataCloneError DOMException

  4. d 为新的 ImageDecoder 对象。下述所有提及 ImageDecoder 成员均指 d,除非另有说明。

  5. [[control message queue]] 赋值一个新的 队列

  6. false 赋值给 [[message queue blocked]]

  7. 将新启动的 并行队列赋值给 [[codec work queue]]

  8. [[ImageTrackList]] 赋值为新建的 ImageTrackList ,初始化如下:

    1. 将新建的 列表赋值给 [[track list]]

    2. -1 赋值给 [[selected index]]

  9. type 赋值给 [[type]]

  10. null 赋值给 [[codec implementation]]

  11. 如果 init.preferAnimation 存在, 将 init.preferAnimation 赋值给 [[prefer animation]] 内部插槽,否则赋值为 null。

  12. 将新建的 列表赋值给 [[pending decode promises]]

  13. -1 赋值给 [[internal selected track index]]

  14. false 赋值给 [[tracks established]]

  15. false 赋值给 [[closed]]

  16. 将新建的 映射赋值给 [[progressive frame generations]]

  17. 如果 initdata 成员类型为 ReadableStream

    1. 将新建的 列表赋值给 [[encoded data]]

    2. false 赋值给 [[complete]]

    3. 向控制消息队列入队,以 配置图像解码器,参数为 init

    4. 处理控制消息队列

    5. reader获取 reader 的结果,针对 data

    6. 并行地,在 d 上以 reader 执行 流数据获取循环

  18. 否则:

    1. 断言 init.data 类型为 BufferSource

    2. 如果 init.transfer 中包含被 init.data 引用的 ArrayBuffer ,用户代理 可以选择:

      1. [[encoded data]] 引用 data 中表示编码图像的字节。

    3. 否则:

      1. init.data 的副本赋值给 [[encoded data]]

    4. true 赋值给 [[complete]]

    5. 解决 [[completed promise]]

    6. 向控制消息队列入队,以 配置图像解码器,参数为 init

    7. 向控制消息队列入队,以 解码轨道元数据

    8. 处理控制消息队列

  19. 对于 init.transfer 中的每个 transferable

    1. transferable 执行 DetachArrayBuffer

  20. 返回 d

运行控制消息配置图像解码器 ,表示执行以下步骤:

  1. supported 为以 init.type 运行 检查类型支持算法的结果。

  2. 如果 supportedfalse,则使用 Close ImageDecoder 算法,传入 NotSupportedError DOMException ,并返回 "processed"

  3. 否则,将 [[codec implementation]] 内部插槽赋值为支持 init.type 的实现。

  4. true 赋值给 [[message queue blocked]]

  5. 将以下步骤入队到 [[codec work queue]]

    1. 按照 colorSpaceConversiondesiredWidth、 和 desiredHeight 的值配置 [[codec implementation]]

    2. false 赋值给 [[message queue blocked]]

    3. 入队一个任务处理控制消息队列

  6. 返回 "processed"

运行控制消息解码轨道元数据 ,表示执行以下步骤:

  1. 将以下步骤入队到 [[codec work queue]]

    1. 运行 建立轨道算法。

10.2.3. 属性

type, 类型为 DOMString,只读

一个字符串,反映构造时给定的 MIME type 的值。

type 的 getter 步骤是返回 [[type]]

complete, 类型为 boolean,只读

指示 [[encoded data]] 是否已完全缓冲。

complete 的 getter 步骤是返回 [[complete]]

completed, 类型为 Promise<undefined>,只读

用于指示 complete 变为 true 时的 promise。

completed 的 getter 步骤是返回 [[completed promise]]

tracks, 类型为 ImageTrackList,只读

返回一个 实时 ImageTrackList, 提供可用轨道的元数据以及选择解码轨道的机制。

tracks 的 getter 步骤是返回 [[ImageTrackList]]

10.2.4. 方法

decode(options)

将控制消息入队,按 options 解码帧。

调用时,执行如下步骤:

  1. 如果 [[closed]]true,返回一个 Promise ,其状态为 rejected,错误为 InvalidStateError DOMException

  2. 如果 [[ImageTrackList]][[selected index]] 为 '-1',返回一个 Promise ,其状态为 rejected,错误为 InvalidStateError DOMException

  3. 如果 optionsundefined,则为 options 分配一个新的 ImageDecodeOptions

  4. promise 为一个新的 Promise

  5. promise 添加到 [[pending decode promises]]

  6. 控制消息入队,以 optionspromise 解码图像。

  7. 处理控制消息队列

  8. 返回 promise

运行控制消息以解码图像,表示执行如下步骤:

  1. 将以下步骤入队到 [[codec work queue]]

    1. 等待 [[tracks established]] 变为 true

    2. 如果 options.completeFramesOnlyfalse 且该图像为 渐进式图像,并且用户代理支持渐进解码,则以 options.frameIndexpromise 运行 解码渐进帧算法。

    3. 否则,以 options.frameIndexpromise 运行 解码完整帧算法。

reset()

立即中止所有待处理工作。

调用时,以 Reset ImageDecoder 算法和 AbortError DOMException 运行。

close()

立即中止所有待处理工作并释放系统资源。关闭后无法再次使用。

调用时,以 Close ImageDecoder 算法和 AbortError DOMException 运行。

isTypeSupported(type)

返回一个 promise,指示用户代理是否支持所提供的配置。

调用时,执行如下步骤:

  1. 如果 type 不是 有效的图像 MIME 类型,返回一个 Promise ,其状态为 rejected,错误为 TypeError

  2. p 为一个新的 Promise

  3. 并行地,以 type 运行 检查类型支持算法,并将结果 resolve 到 p

  4. 返回 p

10.2.5. 算法

获取流数据循环 (带 reader)

执行以下步骤:

  1. readRequest 为如下 读取请求

    chunk 步骤,给定 chunk
    1. 如果 [[closed]]true,则中止这些步骤。

    2. 如果 chunk 不是 Uint8Array 对象,入队一个任务以运行 关闭 ImageDecoder 算法,使用 DataError DOMException ,并中止这些步骤。

    3. bytes 为该 Uint8Array 对象所表示的字节序列。

    4. bytes 追加到 [[encoded data]] 内部插槽。

    5. 如果 [[tracks established]]false,则运行 建立轨道 算法。

    6. 否则,运行 更新轨道算法。

    7. 使用 reader 运行 获取流数据循环算法。

    close 步骤
    1. true 赋值给 [[complete]]

    2. 解析 [[completed promise]]

    error 步骤
    1. 入队一个任务以运行 关闭 ImageDecoder 算法,使用 NotReadableError DOMException

  2. 使用 readRequestreader 读取一个 chunk。

建立轨道

执行以下步骤:

  1. 断言 [[tracks established]]false

  2. 如果 [[encoded data]] 没有足够数据来确定轨道数量:

    1. 如果 completetrue入队一个任务以运行 关闭 ImageDecoder 算法, 使用 InvalidStateError DOMException

    2. 中止这些步骤。

  3. 如果轨道数为 0入队一个任务以运行 关闭 ImageDecoder 算法并中止这些步骤。

  4. newTrackList 为新的 列表

  5. 对于在 [[encoded data]] 中找到的每个 image track

    1. newTrack 为新的 ImageTrack,初始化如下:

      1. this 赋值给 [[ImageDecoder]]

      2. tracks 赋值给 [[ImageTrackList]]

      3. 如果 image track 被判定为动画,将 true 赋值给 newTrack[[animated]] 内部插槽,否则赋值为 false

      4. 如果 image track 描述了帧数,将该数赋值给 newTrack[[frame count]] 内部插槽,否则赋值 0

        注意:如果 this 构造时 dataReadableStream, 则随着更多字节追加到 [[encoded data]]frameCount 可变化。参见 更新轨道算法。

      5. 如果 image track 描述了重复次数,将该数赋值给 [[repetition count]] 内部插槽,否则赋值 0

        注意:值为 Infinity 表示无限重复。

      6. false 赋值给 newTrack[[selected]] 内部插槽。

    2. newTrack 添加到 newTrackList

  6. selectedTrackIndex 为以 newTrackList 运行 获取默认选中轨道索引算法的结果。

  7. selectedTracknewTrackList 中位置 selectedTrackIndex 的轨道。

  8. true 赋值给 selectedTrack[[selected]] 内部插槽。

  9. selectedTrackIndex 赋值给 [[internal selected track index]]

  10. true 赋值给 [[tracks established]]

  11. 入队一个任务以执行以下步骤:

    1. newTrackList 赋值给 tracks[[track list]] 内部插槽。

    2. selectedTrackIndex 赋值给 tracks[[selected index]]

    3. 解析 [[ready promise]]

获取默认选中轨道索引 (参数 trackList

执行以下步骤:

  1. 如果 [[encoded data]] 标识了一个 主图像轨道

    1. primaryTracktrackList 中描述 主图像轨道ImageTrack

    2. primaryTrackIndexprimaryTracktrackList 中的位置。

    3. 如果 [[prefer animation]]null,返回 primaryTrackIndex

    4. 如果 primaryTrack.animated 等于 [[prefer animation]], 返回 primaryTrackIndex

  2. 如果 trackList 中有任何 ImageTrackanimated 等于 [[prefer animation]], 返回 trackList 中最早出现的此类轨道的位置。

  3. 返回 0

更新轨道

轨道更新结构体 是一个 结构体,包含 轨道索引 (unsigned long) 和 帧数 (unsigned long)。

执行以下步骤:

  1. 断言 [[tracks established]]true

  2. trackChanges 为一个新的 列表

  3. trackListtracks[[track list]] 的副本。

  4. 对于 trackList 中的每个 track

    1. trackIndextracktrackList 中的位置。

    2. latestFrameCount[[encoded data]] 中对应 track 的轨道所指示的帧数。

    3. 断言 latestFrameCount 必须大于等于 track.frameCount

    4. 如果 latestFrameCount 大于 track.frameCount

      1. change 为一个 轨道更新结构体,其 轨道索引trackIndex帧数latestFrameCount

      2. change 添加到 tracksChanges

  5. 如果 tracksChanges 为空,则中止本步骤。

  6. 队列一个任务以执行以下步骤:

    1. 对于 trackChanges 中的每个 update

      1. updateTrackImageTrackupdate.trackIndex 位置, 于 tracks[[track list]] 内。

      2. update.frameCount 赋值给 updateTrack[[frame count]]

解码完整帧 (使用 frameIndexpromise)
  1. 断言 [[tracks established]]true

  2. 断言 [[internal selected track index]] 不为 -1

  3. encodedFrame 为由 frameIndex[[internal selected track index]] 标识的编码帧。

  4. 等待下列任一条件成立(以先发生者为准):

    1. [[encoded data]] 包含足够字节以完全解码 encodedFrame

    2. [[encoded data]] 被判定为格式错误。

    3. completetrue

    4. [[closed]]true

  5. 如果 [[encoded data]] 被判定为格式错误,执行 致命拒绝错误数据 算法并中止本步骤。

  6. 如果 [[encoded data]] 不包含足够字节以完全解码 encodedFrame,则使用 promise 执行 拒绝不可行解码 算法并中止本步骤。

  7. 尝试使用 [[codec implementation]] 解码 encodedFrame

  8. 如果解码产生错误,则执行 致命拒绝错误数据 算法并中止本步骤。

  9. 如果 [[progressive frame generations]] 包含以 frameIndex 为键的条目,则从该 map 中移除该条目。

  10. output 为由 [[codec implementation]] 解码 encodedFrame 后产生的图像数据。

  11. decodeResult 为新 ImageDecodeResult 并初始化如下:

    1. 将 'true' 赋值给 complete

    2. durationoutput 的展示持续时间(由 encodedFrame 描述)。如果 encodedFrame 没有持续时间,则赋值 null

    3. timestampoutput 的展示时间戳(由 encodedFrame 描述)。如果 encodedFrame 没有时间戳:

      1. 如果 encodedFrame 是静态图像,则赋值 0timestamp

      2. 如果 encodedFrame 是恒定速率动画图像且 duration 不为 null,则赋值 |frameIndex| * |duration|timestamp

      3. 如果可以直接由元数据生成 timestamp,则赋值该值。

      4. 否则赋值 0timestamp

    4. 如果 [[encoded data]] 包含方向元数据,则描述为 rotationflip,否则 rotation 为 0,flip 为 false。

    5. image 赋值为使用 创建 VideoFrame 算法,参数为 outputtimestampdurationrotationflip 的结果。

  12. 使用 promisedecodeResult 执行 完成解码算法。

解码渐进帧 (使用 frameIndexpromise)
  1. 断言 [[tracks established]]true

  2. 断言 [[internal selected track index]] 不为 -1

  3. encodedFrame 为由 frameIndex[[internal selected track index]] 标识的编码帧。

  4. lastFrameGenerationnull

  5. 如果 [[progressive frame generations]] 包含以 frameIndex 为键的条目,则将该条目的值赋值给 lastFrameGeneration

  6. 等待下列任一条件成立(以先发生者为准):

    1. [[encoded data]] 包含足够字节以解码 encodedFrame,产生一个其 渐进图像帧代数 超过 lastFrameGeneration 的输出。

    2. [[encoded data]] 被判定为格式错误。

    3. completetrue

    4. [[closed]]true

  7. 如果 [[encoded data]] 被判定为格式错误,则执行 致命拒绝错误数据 算法并中止本步骤。

  8. 否则,如果 [[encoded data]] 不包含足够字节以解码 encodedFrame,产生一个其 渐进图像帧代数 超过 lastFrameGeneration 的输出,则使用 promise 执行 拒绝不可行解码 算法并中止本步骤。

  9. 尝试使用 [[codec implementation]] 解码 encodedFrame

  10. 如果解码产生错误,则执行 致命拒绝错误数据 算法并中止本步骤。

  11. output 为由 [[codec implementation]] 解码 encodedFrame 后产生的图像数据。

  12. decodeResult 为新 ImageDecodeResult

  13. 如果 outputencodedFrame 的最终全细节渐进输出:

    1. true 赋值给 decodeResultcomplete

    2. 如果 [[progressive frame generations]] 包含以 frameIndex 为键的条目,则从该 map 中移除该条目。

  14. 否则:

    1. false 赋值给 decodeResultcomplete

    2. frameGenerationoutput渐进图像帧代数

    3. [[progressive frame generations]] 添加以 frameIndex 为键、frameGeneration 为值的新条目。

  15. durationoutput 的展示持续时间(由 encodedFrame 描述)。如果 encodedFrame 没有描述持续时间,则赋值 null

  16. timestampoutput 的展示时间戳(由 encodedFrame 描述)。如果 encodedFrame 没有时间戳:

    1. 如果 encodedFrame 是静态图像,则赋值 0timestamp

    2. 如果 encodedFrame 是恒定速率动画图像且 duration 不为 null,则赋值 |frameIndex| * |duration|timestamp

    3. 如果可以直接由元数据生成 timestamp,则赋值该值。

    4. 否则赋值 0timestamp

  17. 如果 [[encoded data]] 包含方向元数据,则描述为 rotationflip,否则 rotation 为 0,flip 为 false。

  18. image 赋值为使用 创建 VideoFrame 算法,参数为 outputtimestampdurationrotationflip 的结果。

  19. [[pending decode promises]] 中移除 promise

  20. 使用 decodeResult 解析 promise

完成解码(使用 promiseresult
  1. 队列一个任务以执行以下步骤:

    1. 如果 [[closed]],则中止这些步骤。

    2. 断言 promise[[pending decode promises]] 的一个元素。

    3. promise[[pending decode promises]] 移除。

    4. result 解析 promise

拒绝不可行解码(使用 promise
  1. 断言 completetrue[[closed]]true

  2. 如果 completetrue,令 exceptionRangeError。 否则,令 exceptionInvalidStateError DOMException

  3. 队列一个任务以执行以下步骤:

    1. 如果 [[closed]],则中止这些步骤。

    2. 断言 promise[[pending decode promises]] 的一个元素。

    3. promise[[pending decode promises]] 移除。

    4. exception 拒绝 promise

致命拒绝错误数据
  1. 队列一个任务以执行以下步骤:

    1. 如果 [[closed]],则中止这些步骤。

    2. 使用 关闭 ImageDecoder 算法,参数为 EncodingError DOMException

检查类型支持(使用 type
  1. 如果用户代理可以提供编解码器以支持解码 type,则返回 true

  2. 否则,返回 false

重置 ImageDecoder(使用 exception
  1. 通知 [[codec implementation]] 中止任何活动的解码操作。

  2. 对于 [[pending decode promises]] 中的每个 decodePromise

    1. exception 拒绝 decodePromise

    2. decodePromise[[pending decode promises]] 移除。

关闭 ImageDecoder(使用 exception
  1. 使用 重置 ImageDecoder 算法,参数为 exception

  2. true 赋值给 [[closed]]

  3. 清空 [[codec implementation]] 并释放相关 系统资源

  4. 如果 [[ImageTrackList]] 为空,则以 exception 拒绝 [[ready promise]]。 否则执行以下步骤,

    1. 移除 [[ImageTrackList]] 的所有条目。

    2. -1 赋值给 [[ImageTrackList]][[selected index]]

  5. 如果 [[complete]] 为 false,则以 exception 解析 [[completed promise]]

10.3. ImageDecoderInit 接口

typedef (AllowSharedBufferSource or ReadableStream) ImageBufferSource;
dictionary ImageDecoderInit {
  required DOMString type;
  required ImageBufferSource data;
  ColorSpaceConversion colorSpaceConversion = "default";
  [EnforceRange] unsigned long desiredWidth;
  [EnforceRange] unsigned long desiredHeight;
  boolean preferAnimation;
  sequence<ArrayBuffer> transfer = [];
};

若要判断一个 ImageDecoderInit 是否为有效的 ImageDecoderInit, 执行以下步骤:

  1. 如果 type 不是有效的图片 MIME 类型,返回 false

  2. 如果 data 类型为 ReadableStream 且该 ReadableStream 已被 扰动锁定,返回 false

  3. 如果 data 类型为 BufferSource

    1. 如果 data 已被 [分离],返回 false。

    2. 如果 data 为空,返回 false

  4. 如果 desiredWidth 存在,但 desiredHeight 不存在,则返回 false

  5. 如果 desiredHeight 存在,但 desiredWidth 不存在,则返回 false

  6. 返回 true

有效的图片 MIME 类型是指一个字符串, 它是一个有效的 MIME 类型字符串, 并且根据 [RFC9110] 的第 8.3.1 节, 其 typeimage

type 类型为 DOMString

包含待解码图片文件的 MIME 类型的字符串。

data 类型为 ImageBufferSource

表示图片文件编码字节的 BufferSourceReadableStream, 其 MIME 类型由 type 描述。

colorSpaceConversion 类型为 ColorSpaceConversion,默认值为 "default"

控制解码输出的色彩空间是否转换或忽略, 定义见 colorSpaceConversion ,位于 ImageBitmapOptions 中。

desiredWidth 类型为 unsigned long

指示解码输出的期望宽度。实现为尽力而为;并非所有格式或解码器都 必须 支持按期望宽度解码。

desiredHeight 类型为 unsigned long

指示解码输出的期望高度。实现为尽力而为;并非所有格式或解码器都 必须 支持按期望高度解码。

preferAnimation 类型为 boolean

对于具有多个轨道的图片,表示初始轨道选择 应当 优先选择动画轨道。

注意:参见 获取默认选中轨道索引 算法。

10.4. ImageDecodeOptions 接口

dictionary ImageDecodeOptions {
  [EnforceRange] unsigned long frameIndex = 0;
  boolean completeFramesOnly = true;
};

frameIndex, 类型为 unsigned long,默认值为 0

要解码的帧索引。

completeFramesOnly, 类型为 boolean,默认值为 true

对于渐进图片,若值为 false,表示解码器 可以输出一个 image ,但细节较少。对同一个 frameIndex 多次调用 decode() ,每次会生成比上次更高 渐进图片帧代数 (图片细节更多)直到最终输出完整细节图片。

如果 completeFramesOnly 被赋值为 true,或图片不是 渐进图片,或用户代理不支持该图片类型的渐进解码,则 decode() 只有在完整细节图片解码完成时才会返回结果。

注意:对于渐进图片,设置 completeFramesOnlyfalse,可为用户提供网络读取中的图片预览(通过 data ReadableStream)。

当解码完整细节图片时,ImageDecodeResultcomplete 会被设置为 true。

10.5. ImageDecodeResult 接口

dictionary ImageDecodeResult {
  required VideoFrame image;
  required boolean complete;
};

image, 类型为 VideoFrame

解码后的图片。

complete, 类型为 boolean

表示 image 是否为最终完整细节输出。

注意:decode() 调用时 completeFramesOnly 设置为 truecomplete 总是 true

10.6. ImageTrackList 接口

[Exposed=(Window,DedicatedWorker)]
interface ImageTrackList {
  getter ImageTrack (unsigned long index);

  readonly attribute Promise<undefined> ready;
  readonly attribute unsigned long length;
  readonly attribute long selectedIndex;
  readonly attribute ImageTrack? selectedTrack;
};

10.6.1. 内部插槽

[[ready promise]]

用于指示 ImageTrackList 已被 ImageTrack 填充的 Promise。

注意: ImageTrackframeCountcompletetrue 之前可以被持续更新。

[[track list]]

由该 ImageTrackList 描述的 ImageTrack 列表。

[[selected index]]

[[track list]] 中选中的轨道索引。 若值为 -1,表示没有选中轨道。初始值为 -1

10.6.2. 属性

ready, 类型为 Promise<undefined>,只读

ready 的 getter 步骤为返回 [[ready promise]]

length, 类型为 unsigned long,只读

length 的 getter 步骤为返回 [[track list]] 的长度。

selectedIndex, 类型为 long,只读

selectedIndex 的 getter 步骤为返回 [[selected index]]

selectedTrack, 类型为 ImageTrack, 只读,可空

selectedTrack 的 getter 步骤为:

  1. 如果 [[selected index]]-1,返回 null

  2. 否则,返回 [[track list]] 中对应 [[selected index]] 位置的 ImageTrack。

10.7. ImageTrack 接口

[Exposed=(Window,DedicatedWorker)]
interface ImageTrack {
  readonly attribute boolean animated;
  readonly attribute unsigned long frameCount;
  readonly attribute unrestricted float repetitionCount;
  attribute boolean selected;
};

10.7.1. 内部插槽

[[ImageDecoder]]

构造该 ImageTrackImageDecoder 实例。

[[ImageTrackList]]

包含该 ImageTrackImageTrackList 实例。

[[animated]]

指示该轨道是否包含多帧的动画图片。

[[frame count]]

该轨道中的帧数。

[[repetition count]]

动画预期重复的次数。

[[selected]]

指示该轨道是否被选中用于解码。

10.7.2. 属性

animated, 类型为 boolean,只读

animated 的 getter 步骤为返回 [[animated]] 的值。

注意: 此属性可以早期指示 frameCount 最终会大于 0,适用于 frameCount 初始为 0,随着新的 ReadableStream data 数据块到达而增大时。

frameCount, 类型为 unsigned long,只读

frameCount 的 getter 步骤为返回 [[frame count]] 的值。

repetitionCount, 类型为 unrestricted float,只读

repetitionCount 的 getter 步骤为返回 [[repetition count]] 的值。

selected, 类型为 boolean

selected 的 getter 步骤为返回 [[selected]] 的值。

selected 的 setter 步骤如下:

  1. 如果 [[ImageDecoder]][[closed]] 插槽为 true,则中止这些步骤。

  2. newValue给定值

  3. 如果 newValue 等于 [[selected]],则中止这些步骤。

  4. newValue 赋值给 [[selected]]

  5. parentTrackList[[ImageTrackList]]

  6. oldSelectedIndexparentTrackList[[selected index]] 的值。

  7. 如果 oldSelectedIndex 不为 -1

    1. oldSelectedTrackImageTrack ,位于 parentTrackList[[track list]]oldSelectedIndex 位置。

    2. false 赋值给 oldSelectedTrack[[selected]]

  8. 如果 newValuetrue,令 selectedIndexthis ImageTrackparentTrackList[[track list]] 中的索引;否则令 selectedIndex-1

  9. selectedIndex 赋值给 parentTrackList[[selected index]]

  10. [[ImageDecoder]] 执行 重置 ImageDecoder 算法。

  11. 队列一个控制消息[[ImageDecoder]]控制消息队列,以使用 selectedIndex 更新内部选中轨道索引。

  12. 处理属于 [[ImageDecoder]]控制消息队列

执行控制消息以更新内部选中轨道索引时,需执行如下步骤:

  1. 将以下步骤加入 [[ImageDecoder]][[codec work queue]]

    1. selectedIndex 赋值给 [[internal selected track index]]

    2. 清空 [[progressive frame generations]] 的所有条目。

11. 资源回收

当资源受限时,用户代理 可以 主动回收编解码器。尤其是在硬件编解码器有限,且被多个网页或平台应用共享时。

回收编解码器,用户代理 必须 执行相应的关闭算法(包括 关闭 AudioDecoder关闭 AudioEncoder关闭 VideoDecoder关闭 VideoEncoder),并传入 QuotaExceededError

决定何时可以回收编解码器的规则,取决于该编解码器是活动非活动,以及是否为后台编解码器。

活动编解码器指过去 10 秒 内曾在[[codec work queue]]上有进展的编解码器。

注意: 判断工作队列进展的可靠标志是调用 output() 回调。

非活动编解码器是指不满足活动编解码器定义的任何编解码器。

后台编解码器指其 ownerDocument (或对于 worker 编解码器,owner setDocument) 具有 hidden 属性且值为 true 的编解码器。

用户代理 必须 只回收属于非活动编解码器后台编解码器或两者的编解码器。用户代理 不得 回收既是活动又在前台(即不是后台编解码器)的编解码器。

此外,用户代理 不得 回收下列情况的活动 后台编解码器:

12. 安全注意事项

本节为非规范性内容。

主要的安全影响在于该 API 的相关特性让攻击者更容易利用底层平台编解码器的漏洞。此外,对编解码器进行新配置和控制的能力也可能带来依赖于特定配置或操作序列的新攻击方式。

平台编解码器历史上一直是 HTMLMediaElement[WEBAUDIO][WebRTC] 等 API 的内部细节。因此,攻击者一直可以通过发送格式错误的媒体文件或流、调用各种 API 控制方法来攻击底层编解码器。

例如,可以先将任意流包装成媒体容器(比如 mp4),然后设置为 src ,用于 HTMLMediaElement。此时可以通过设置 <video>.currentTime,让底层视频编解码器被 reset() 调用。

WebCodecs 通过在输入提供时暴露底层控制并允许直接调用编解码器控制方法,使这类攻击变得更容易。这还让攻击者可以调用此前高级 API 所无法实现的控制方法序列。

工作组希望用户代理通过大量随机输入和控制方法调用对实现进行模糊测试来降低此风险。此外,建议用户代理将底层编解码器隔离在受限权限的进程(沙箱)中,作为防止攻击成功后读取用户数据的屏障。

另一个需要关注的问题是底层编解码器可能暴露输入变异竞态风险,例如允许站点在底层编解码器操作数据时修改编解码器输入或输出。通过确保输入和输出接口不可变,可以缓解这一问题。

13. 隐私注意事项

本节为非规范性内容。

主要的隐私影响在于通过查询不同编解码器能力来建立编解码器特征档案,从而提升了用户指纹识别能力。绝大多数特征已被现有 API 公开。这类特征档案极少会成为唯一标识,但可与其它指标结合形成指纹。

攻击者可以通过多次调用 IsConfigSupported() 方法并传入不同配置字典来收集编解码器特征档案。同样,攻击者也可以尝试用不同配置字典调用 configure() 编解码器,并观察哪些配置被接受。

攻击者也可以用现有 API 收集绝大多数编解码器特征。例如,[media-capabilities]decodingInfo() API 描述了支持哪些解码器,其 powerEfficient 属性可指示解码器是否使用硬件加速。同样,[WebRTC]getCapabilities() API 可用于确定支持哪些编码器, getStats() API 可用于判断编码器是否使用硬件加速。WebCodecs 还会以底层编解码器特性形式公开部分额外信息。

单独的编解码器特征档案一般不会成为唯一标识。底层编解码器通常完全由软件实现(可能是用户代理二进制或操作系统的一部分),因此所有运行该软件的用户会拥有相同能力集。此外,底层编解码器也常用硬件加速,而硬件是批量生产的,同类和同一制造日期的设备(如 2020 年旗舰手机)通常具有相同能力。当然也有少数异常(部分用户可能运行过时版本的软件编解码器或使用罕见的硬件组合),但绝大多数情况下某个编解码器特征档案会被一大群用户共享。

按编解码器特征档案分组用户,仍然会带来一些熵,可与其它指标联合唯一标识用户。用户代理 可以 在站点试图穷举探测编解码器能力时通过返回错误来部分缓解此问题。此外,用户代理 可以 实现“隐私预算”,随着作者使用 WebCodecs 及其它标识 API 耗尽预算。当预算耗尽时,编解码器能力可降至通用基线或提示用户确认。

14. WebCodecs 作者最佳实践

本节为非规范性内容。

虽然 WebCodecs 在内部以后台线程运行,但对于需要实时媒体或主线程竞争环境的作者,建议尽可能让媒体流水线在 worker 上完全独立于主线程运行。例如,VideoFrame 实时媒体处理通常应在 worker 上进行。

主线程存在高竞争和卡顿的潜在风险,这在开发阶段可能难以察觉,但会导致设备和用户代理间体验的不一致,甚至严重影响最终用户体验。确保媒体流水线与主线程解耦有助于为终端用户提供流畅体验。

如作者决定在主线程上运行媒体流水线,应明确目标帧率、主线程负载、应用嵌入方式,以及用户所用设备类型。

15. 致谢

编辑感谢 Alex Russell、Chris Needham、Dale Curtis、Dan Sanders、Eugene Zemtsov、Francois Daoust、Guido Urdaneta、Harald Alvestrand、Jan-Ivar Bruaroey、Jer Noble、Mark Foltz、Peter Thatcher、Steve Anton、Matt Wolenetz、Rijubrata Bhaumik、Thomas Guilbert、Tuukka Toivonen 和 Youenn Fablet 对本规范的贡献。也感谢所有通过邮件列表和 issue 参与规范讨论的其他人员。

工作组将本规范献给我们的同事 Bernard Aboba。

一致性

文档约定

一致性要求以描述性断言和 RFC 2119 术语表达。 在本规范的规范性部分,“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY” 和 “OPTIONAL” 这些关键词应按照 RFC 2119 中描述进行解释。 但为便于阅读,本规范未将这些词全部大写。

除明确标记为非规范性内容、示例和注释的部分外,规范文本均为规范性内容。[RFC2119]

本规范中的示例以“例如”引入,或用 class="example" 标记,与规范性文本区分,例如:

这是一个信息性示例。

信息性注释以“注意”开头,并以 class="note" 标记,与规范性文本区分,例如:

注意,这是一个信息性注释。

一致性算法

算法中的命令式要求(如“去除所有前导空格字符”或“返回 false 并中止这些步骤”)应结合算法说明中使用的关键词(“must”、“should”、“may”等)进行解释。

以算法或具体步骤表达的一致性要求可用任何方式实现,只要最终结果等效即可。尤其是,本规范定义的算法旨在易于理解,而非高性能。实现者可自行进行优化。

索引

本规范定义的术语

引用定义的术语

参考文献

规范性引用

[CSS-IMAGES-3]
Tab Atkins Jr.; Elika Etemad; Lea Verou. CSS Images Module Level 3. 2023年12月18日. CRD. URL: https://www.w3.org/TR/css-images-3/
[DOM]
Anne van Kesteren. DOM Standard. 活标准. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript Language Specification. URL: https://tc39.es/ecma262/multipage/
[GEOMETRY-1]
Simon Pieters; Chris Harrelson. Geometry Interfaces Module Level 1. 2018年12月4日. CR. URL: https://www.w3.org/TR/geometry-1/
[HTML]
Anne van Kesteren; 等. HTML Standard. 活标准. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. 活标准. URL: https://infra.spec.whatwg.org/
[MEDIASTREAM-RECORDING]
Miguel Casas-sanchez. MediaStream Recording. 2025年4月17日. WD. URL: https://www.w3.org/TR/mediastream-recording/
[MIMESNIFF]
Gordon P. Hemsley. MIME Sniffing Standard. 活标准. URL: https://mimesniff.spec.whatwg.org/
[MST-CONTENT-HINT]
Harald Alvestrand. MediaStreamTrack Content Hints. 2024年10月31日. WD. URL: https://www.w3.org/TR/mst-content-hint/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997年3月. 最佳当前实践. URL: https://datatracker.ietf.org/doc/html/rfc2119
[STREAMS]
Adam Rice; 等. Streams Standard. 活标准. URL: https://streams.spec.whatwg.org/
[SVG2]
Amelia Bellamy-Royds; 等. Scalable Vector Graphics (SVG) 2. 2018年10月4日. CR. URL: https://www.w3.org/TR/SVG2/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. 活标准. URL: https://webidl.spec.whatwg.org/
[WebRTC-SVC]
Bernard Aboba. Scalable Video Coding (SVC) Extension for WebRTC. 2024年8月17日. WD. URL: https://www.w3.org/TR/webrtc-svc/

参考性引用

[H.273]
Coding-independent code points for video signal type identification. 2016年12月. URL: https://www.itu.int/rec/T-REC-H.273/en
[MEDIA-CAPABILITIES]
Jean-Yves Avenard; Mark Foltz. Media Capabilities. 2025年6月23日. WD. URL: https://www.w3.org/TR/media-capabilities/
[MEDIA-SOURCE-2]
Jean-Yves Avenard; Mark Watson. Media Source Extensions™. 2025年4月17日. WD. URL: https://www.w3.org/TR/media-source-2/
[RFC6381]
R. Gellens; D. Singer; P. Frojdh. The 'Codecs' and 'Profiles' Parameters for "Bucket" Media Types. 2011年8月. 提案标准. URL: https://www.rfc-editor.org/rfc/rfc6381
[RFC9110]
R. Fielding, Ed.; M. Nottingham, Ed.; J. Reschke, Ed.. HTTP Semantics. 2022年6月. 互联网标准. URL: https://httpwg.org/specs/rfc9110.html
[WEBAUDIO]
Paul Adenot; Hongchan Choi. Web Audio API. 2021年6月17日. REC. URL: https://www.w3.org/TR/webaudio-1.0/
[WEBAUDIO-1.1]
Paul Adenot; Hongchan Choi. Web Audio API 1.1. 2024年11月5日. FPWD. URL: https://www.w3.org/TR/webaudio-1.1/
[WEBCODECS-CODEC-REGISTRY]
Paul Adenot; Bernard Aboba. WebCodecs Codec Registry. 2024年9月9日. DRY. URL: https://www.w3.org/TR/webcodecs-codec-registry/
[WEBCODECS-VIDEO-FRAME-METADATA-REGISTRY]
Youenn Fablet. WebCodecs VideoFrame Metadata Registry. ED. URL: https://w3c.github.io/webcodecs/video_frame_metadata_registry.html
[WebRTC]
Cullen Jennings; 等. WebRTC: Real-Time Communication in Browsers. 2025年3月13日. REC. URL: https://www.w3.org/TR/webrtc/

IDL 索引

[Exposed=(Window,DedicatedWorker), SecureContext]
interface AudioDecoder : EventTarget {
  constructor(AudioDecoderInit init);

  readonly attribute CodecState state;
  readonly attribute unsigned long decodeQueueSize;
  attribute EventHandler ondequeue;

  undefined configure(AudioDecoderConfig config);
  undefined decode(EncodedAudioChunk chunk);
  Promise<undefined> flush();
  undefined reset();
  undefined close();

  static Promise<AudioDecoderSupport> isConfigSupported(AudioDecoderConfig config);
};

dictionary AudioDecoderInit {
  required AudioDataOutputCallback output;
  required WebCodecsErrorCallback error;
};

callback AudioDataOutputCallback = undefined(AudioData output);

[Exposed=(Window,DedicatedWorker), SecureContext]
interface VideoDecoder : EventTarget {
  constructor(VideoDecoderInit init);

  readonly attribute CodecState state;
  readonly attribute unsigned long decodeQueueSize;
  attribute EventHandler ondequeue;

  undefined configure(VideoDecoderConfig config);
  undefined decode(EncodedVideoChunk chunk);
  Promise<undefined> flush();
  undefined reset();
  undefined close();

  static Promise<VideoDecoderSupport> isConfigSupported(VideoDecoderConfig config);
};

dictionary VideoDecoderInit {
  required VideoFrameOutputCallback output;
  required WebCodecsErrorCallback error;
};

callback VideoFrameOutputCallback = undefined(VideoFrame output);

[Exposed=(Window,DedicatedWorker), SecureContext]
interface AudioEncoder : EventTarget {
  constructor(AudioEncoderInit init);

  readonly attribute CodecState state;
  readonly attribute unsigned long encodeQueueSize;
  attribute EventHandler ondequeue;

  undefined configure(AudioEncoderConfig config);
  undefined encode(AudioData data);
  Promise<undefined> flush();
  undefined reset();
  undefined close();

  static Promise<AudioEncoderSupport> isConfigSupported(AudioEncoderConfig config);
};

dictionary AudioEncoderInit {
  required EncodedAudioChunkOutputCallback output;
  required WebCodecsErrorCallback error;
};

callback EncodedAudioChunkOutputCallback =
    undefined (EncodedAudioChunk output,
               optional EncodedAudioChunkMetadata metadata = {});

dictionary EncodedAudioChunkMetadata {
  AudioDecoderConfig decoderConfig;
};

[Exposed=(Window,DedicatedWorker), SecureContext]
interface VideoEncoder : EventTarget {
  constructor(VideoEncoderInit init);

  readonly attribute CodecState state;
  readonly attribute unsigned long encodeQueueSize;
  attribute EventHandler ondequeue;

  undefined configure(VideoEncoderConfig config);
  undefined encode(VideoFrame frame, optional VideoEncoderEncodeOptions options = {});
  Promise<undefined> flush();
  undefined reset();
  undefined close();

  static Promise<VideoEncoderSupport> isConfigSupported(VideoEncoderConfig config);
};

dictionary VideoEncoderInit {
  required EncodedVideoChunkOutputCallback output;
  required WebCodecsErrorCallback error;
};

callback EncodedVideoChunkOutputCallback =
    undefined (EncodedVideoChunk chunk,
               optional EncodedVideoChunkMetadata metadata = {});

dictionary EncodedVideoChunkMetadata {
  VideoDecoderConfig decoderConfig;
  SvcOutputMetadata svc;
  BufferSource alphaSideData;
};

dictionary SvcOutputMetadata {
  unsigned long temporalLayerId;
};

dictionary AudioDecoderSupport {
  boolean supported;
  AudioDecoderConfig config;
};

dictionary VideoDecoderSupport {
  boolean supported;
  VideoDecoderConfig config;
};

dictionary AudioEncoderSupport {
  boolean supported;
  AudioEncoderConfig config;
};

dictionary VideoEncoderSupport {
  boolean supported;
  VideoEncoderConfig config;
};

dictionary AudioDecoderConfig {
  required DOMString codec;
  [EnforceRange] required unsigned long sampleRate;
  [EnforceRange] required unsigned long numberOfChannels;
  AllowSharedBufferSource description;
};

dictionary VideoDecoderConfig {
  required DOMString codec;
  AllowSharedBufferSource description;
  [EnforceRange] unsigned long codedWidth;
  [EnforceRange] unsigned long codedHeight;
  [EnforceRange] unsigned long displayAspectWidth;
  [EnforceRange] unsigned long displayAspectHeight;
  VideoColorSpaceInit colorSpace;
  HardwareAcceleration hardwareAcceleration = "no-preference";
  boolean optimizeForLatency;
  double rotation = 0;
  boolean flip = false;
};

dictionary AudioEncoderConfig {
  required DOMString codec;
  [EnforceRange] required unsigned long sampleRate;
  [EnforceRange] required unsigned long numberOfChannels;
  [EnforceRange] unsigned long long bitrate;
  BitrateMode bitrateMode = "variable";
};

dictionary VideoEncoderConfig {
  required DOMString codec;
  [EnforceRange] required unsigned long width;
  [EnforceRange] required unsigned long height;
  [EnforceRange] unsigned long displayWidth;
  [EnforceRange] unsigned long displayHeight;
  [EnforceRange] unsigned long long bitrate;
  double framerate;
  HardwareAcceleration hardwareAcceleration = "no-preference";
  AlphaOption alpha = "discard";
  DOMString scalabilityMode;
  VideoEncoderBitrateMode bitrateMode = "variable";
  LatencyMode latencyMode = "quality";
  DOMString contentHint;
};

enum HardwareAcceleration {
  "no-preference",
  "prefer-hardware",
  "prefer-software",
};

enum AlphaOption {
  "keep",
  "discard",
};

enum LatencyMode {
  "quality",
  "realtime"
};

dictionary VideoEncoderEncodeOptions {
  boolean keyFrame = false;
};

enum VideoEncoderBitrateMode {
  "constant",
  "variable",
  "quantizer"
};

enum CodecState {
  "unconfigured",
  "configured",
  "closed"
};

callback WebCodecsErrorCallback = undefined(DOMException error);

[Exposed=(Window,DedicatedWorker), Serializable]
interface EncodedAudioChunk {
  constructor(EncodedAudioChunkInit init);
  readonly attribute EncodedAudioChunkType type;
  readonly attribute long long timestamp;          // microseconds
  readonly attribute unsigned long long? duration; // microseconds
  readonly attribute unsigned long byteLength;

  undefined copyTo(AllowSharedBufferSource destination);
};

dictionary EncodedAudioChunkInit {
  required EncodedAudioChunkType type;
  [EnforceRange] required long long timestamp;    // microseconds
  [EnforceRange] unsigned long long duration;     // microseconds
  required AllowSharedBufferSource data;
  sequence<ArrayBuffer> transfer = [];
};

enum EncodedAudioChunkType {
    "key",
    "delta",
};

[Exposed=(Window,DedicatedWorker), Serializable]
interface EncodedVideoChunk {
  constructor(EncodedVideoChunkInit init);
  readonly attribute EncodedVideoChunkType type;
  readonly attribute long long timestamp;             // microseconds
  readonly attribute unsigned long long? duration;    // microseconds
  readonly attribute unsigned long byteLength;

  undefined copyTo(AllowSharedBufferSource destination);
};

dictionary EncodedVideoChunkInit {
  required EncodedVideoChunkType type;
  [EnforceRange] required long long timestamp;        // microseconds
  [EnforceRange] unsigned long long duration;         // microseconds
  required AllowSharedBufferSource data;
  sequence<ArrayBuffer> transfer = [];
};

enum EncodedVideoChunkType {
    "key",
    "delta",
};

[Exposed=(Window,DedicatedWorker), Serializable, Transferable]
interface AudioData {
  constructor(AudioDataInit init);

  readonly attribute AudioSampleFormat? format;
  readonly attribute float sampleRate;
  readonly attribute unsigned long numberOfFrames;
  readonly attribute unsigned long numberOfChannels;
  readonly attribute unsigned long long duration;  // microseconds
  readonly attribute long long timestamp;          // microseconds

  unsigned long allocationSize(AudioDataCopyToOptions options);
  undefined copyTo(AllowSharedBufferSource destination, AudioDataCopyToOptions options);
  AudioData clone();
  undefined close();
};

dictionary AudioDataInit {
  required AudioSampleFormat format;
  required float sampleRate;
  [EnforceRange] required unsigned long numberOfFrames;
  [EnforceRange] required unsigned long numberOfChannels;
  [EnforceRange] required long long timestamp;  // microseconds
  required BufferSource data;
  sequence<ArrayBuffer> transfer = [];
};

dictionary AudioDataCopyToOptions {
  [EnforceRange] required unsigned long planeIndex;
  [EnforceRange] unsigned long frameOffset = 0;
  [EnforceRange] unsigned long frameCount;
  AudioSampleFormat format;
};

enum AudioSampleFormat {
  "u8",
  "s16",
  "s32",
  "f32",
  "u8-planar",
  "s16-planar",
  "s32-planar",
  "f32-planar",
};

[Exposed=(Window,DedicatedWorker), Serializable, Transferable]
interface VideoFrame {
  constructor(CanvasImageSource image, optional VideoFrameInit init = {});
  constructor(AllowSharedBufferSource data, VideoFrameBufferInit init);

  readonly attribute VideoPixelFormat? format;
  readonly attribute unsigned long codedWidth;
  readonly attribute unsigned long codedHeight;
  readonly attribute DOMRectReadOnly? codedRect;
  readonly attribute DOMRectReadOnly? visibleRect;
  readonly attribute double rotation;
  readonly attribute boolean flip;
  readonly attribute unsigned long displayWidth;
  readonly attribute unsigned long displayHeight;
  readonly attribute unsigned long long? duration;  // microseconds
  readonly attribute long long timestamp;           // microseconds
  readonly attribute VideoColorSpace colorSpace;

  VideoFrameMetadata metadata();

  unsigned long allocationSize(
      optional VideoFrameCopyToOptions options = {});
  Promise<sequence<PlaneLayout>> copyTo(
      AllowSharedBufferSource destination,
      optional VideoFrameCopyToOptions options = {});
  VideoFrame clone();
  undefined close();
};

dictionary VideoFrameInit {
  unsigned long long duration;  // microseconds
  long long timestamp;          // microseconds
  AlphaOption alpha = "keep";

  // Default matches image. May be used to efficiently crop. Will trigger
  // new computation of displayWidth and displayHeight using image's pixel
  // aspect ratio unless an explicit displayWidth and displayHeight are given.
  DOMRectInit visibleRect;

  double rotation = 0;
  boolean flip = false;

  // Default matches image unless visibleRect is provided.
  [EnforceRange] unsigned long displayWidth;
  [EnforceRange] unsigned long displayHeight;

  VideoFrameMetadata metadata;
};

dictionary VideoFrameBufferInit {
  required VideoPixelFormat format;
  required [EnforceRange] unsigned long codedWidth;
  required [EnforceRange] unsigned long codedHeight;
  required [EnforceRange] long long timestamp;  // microseconds
  [EnforceRange] unsigned long long duration;  // microseconds

  // Default layout is tightly-packed.
  sequence<PlaneLayout> layout;

  // Default visible rect is coded size positioned at (0,0)
  DOMRectInit visibleRect;

  double rotation = 0;
  boolean flip = false;

  // Default display dimensions match visibleRect.
  [EnforceRange] unsigned long displayWidth;
  [EnforceRange] unsigned long displayHeight;

  VideoColorSpaceInit colorSpace;

  sequence<ArrayBuffer> transfer = [];

  VideoFrameMetadata metadata;
};

dictionary VideoFrameMetadata {
  // Possible members are recorded in the VideoFrame Metadata Registry.
};

dictionary VideoFrameCopyToOptions {
  DOMRectInit rect;
  sequence<PlaneLayout> layout;
  VideoPixelFormat format;
  PredefinedColorSpace colorSpace;
};

dictionary PlaneLayout {
  [EnforceRange] required unsigned long offset;
  [EnforceRange] required unsigned long stride;
};

enum VideoPixelFormat {
  // 4:2:0 Y, U, V
  "I420",
  "I420P10",
  "I420P12",
  // 4:2:0 Y, U, V, A
  "I420A",
  "I420AP10",
  "I420AP12",
  // 4:2:2 Y, U, V
  "I422",
  "I422P10",
  "I422P12",
  // 4:2:2 Y, U, V, A
  "I422A",
  "I422AP10",
  "I422AP12",
  // 4:4:4 Y, U, V
  "I444",
  "I444P10",
  "I444P12",
  // 4:4:4 Y, U, V, A
  "I444A",
  "I444AP10",
  "I444AP12",
  // 4:2:0 Y, UV
  "NV12",
  // 4:4:4 RGBA
  "RGBA",
  // 4:4:4 RGBX (opaque)
  "RGBX",
  // 4:4:4 BGRA
  "BGRA",
  // 4:4:4 BGRX (opaque)
  "BGRX",
};

[Exposed=(Window,DedicatedWorker)]
interface VideoColorSpace {
  constructor(optional VideoColorSpaceInit init = {});

  readonly attribute VideoColorPrimaries? primaries;
  readonly attribute VideoTransferCharacteristics? transfer;
  readonly attribute VideoMatrixCoefficients? matrix;
  readonly attribute boolean? fullRange;

  [Default] VideoColorSpaceInit toJSON();
};

dictionary VideoColorSpaceInit {
  VideoColorPrimaries? primaries = null;
  VideoTransferCharacteristics? transfer = null;
  VideoMatrixCoefficients? matrix = null;
  boolean? fullRange = null;
};

enum VideoColorPrimaries {
  "bt709",
  "bt470bg",
  "smpte170m",
  "bt2020",
  "smpte432",
};

enum VideoTransferCharacteristics {
  "bt709",
  "smpte170m",
  "iec61966-2-1",
  "linear",
  "pq",
  "hlg",
};

enum VideoMatrixCoefficients {
  "rgb",
  "bt709",
  "bt470bg",
  "smpte170m",
  "bt2020-ncl",
};

[Exposed=(Window,DedicatedWorker), SecureContext]
interface ImageDecoder {
  constructor(ImageDecoderInit init);

  readonly attribute DOMString type;
  readonly attribute boolean complete;
  readonly attribute Promise<undefined> completed;
  readonly attribute ImageTrackList tracks;

  Promise<ImageDecodeResult> decode(optional ImageDecodeOptions options = {});
  undefined reset();
  undefined close();

  static Promise<boolean> isTypeSupported(DOMString type);
};


typedef (AllowSharedBufferSource or ReadableStream) ImageBufferSource;
dictionary ImageDecoderInit {
  required DOMString type;
  required ImageBufferSource data;
  ColorSpaceConversion colorSpaceConversion = "default";
  [EnforceRange] unsigned long desiredWidth;
  [EnforceRange] unsigned long desiredHeight;
  boolean preferAnimation;
  sequence<ArrayBuffer> transfer = [];
};


dictionary ImageDecodeOptions {
  [EnforceRange] unsigned long frameIndex = 0;
  boolean completeFramesOnly = true;
};


dictionary ImageDecodeResult {
  required VideoFrame image;
  required boolean complete;
};


[Exposed=(Window,DedicatedWorker)]
interface ImageTrackList {
  getter ImageTrack (unsigned long index);

  readonly attribute Promise<undefined> ready;
  readonly attribute unsigned long length;
  readonly attribute long selectedIndex;
  readonly attribute ImageTrack? selectedTrack;
};


[Exposed=(Window,DedicatedWorker)]
interface ImageTrack {
  readonly attribute boolean animated;
  readonly attribute unsigned long frameCount;
  readonly attribute unrestricted float repetitionCount;
  attribute boolean selected;
};


问题索引

规范建议提供编码尺寸、可见矩形和显示尺寸的定义(以及可能的图示)。 参见#166