1. 术语定义
- 编解码器
-
泛指
AudioDecoder
、AudioEncoder
、VideoDecoder
或VideoEncoder
的实例。 - 关键块
-
一种编码块,在解码时不依赖于其他帧。也常被称为“关键帧”。
- 内部待输出
-
编解码器输出,如
VideoFrame
,当前处于底层编解码器实现的内部管道中。底层编解码器实现 可以 仅在有新输入时产生新输出。底层编解码器实现 必须 在 flush 时输出所有待输出内容。 - 编解码器系统资源
-
包括 CPU 内存、GPU 内存,以及对特定解码/编码硬件的独占句柄等资源,这些资源 可以 由用户代理在编解码器配置或生成
AudioData
和VideoFrame
对象时分配。此类资源 可以 很快耗尽,应当 在不再使用时立即释放。 - 时间层
-
一组
EncodedVideoChunk
,其时间戳节奏产生特定帧率。参见scalabilityMode
。 - 渐进式图像
-
一种支持多级细节解码的图像,在编码数据尚未完全缓冲时,较低级别的细节即可被解码获得。
- 渐进式图像帧代数
-
用于标识某个 渐进式图像解码输出的代数标识。每一代都会为解码输出增加更多细节。帧代数的计算机制由实现者自行定义。
- 主图像轨道
-
由图像文件标记为默认轨道的图像轨道。主轨道的标识机制由具体格式定义。
- RGB 格式
-
一种
VideoPixelFormat
,包含红、绿、蓝色通道,通道顺序和布局(交错或平面)不限,是否包含 alpha 通道也不限。 - sRGB 色彩空间
-
一个
VideoColorSpace
对象,初始化如下:-
[[primaries]]
设为bt709
, -
[[matrix]]
设为rgb
, -
[[full range]]
设为true
-
- Display P3 色彩空间
-
一个
VideoColorSpace
对象,初始化如下:-
[[matrix]]
设为rgb
, -
[[full range]]
设为true
- REC709 色彩空间
-
一个
VideoColorSpace
对象,初始化如下:-
[[primaries]]
设为bt709
, -
[[transfer]]
设为bt709
, -
[[matrix]]
设为bt709
, -
[[full range]]
设为false
-
- 编解码器饱和
-
底层编解码器实现处于活动解码或编码请求数量达到实现特定最大值的状态,此时暂时无法接受更多工作。最大值可以大于1的任意值,包括无限(无最大值)。饱和时,对
decode()
或encode()
的额外调用会被缓冲到 控制消息队列,并会增加decodeQueuSize
和encodeQueueSize
属性。编解码器实现在当前工作取得足够进展后将恢复为未饱和状态。
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"
表示此时不能处理该消息,应保留在 控制消息队列中以便稍后重试。
要处理控制消息队列,请执行以下步骤:
-
当 [[message queue blocked]] 为
false
且 [[control message queue]] 非空时:-
令 front message 为 [[control message queue]] 中的第一个消息。
-
令 outcome 为运行 控制消息步骤 所得结果。
-
如果 outcome 等于
"not processed"
,则跳出循环。 -
否则,将 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]]
[[state]]
-
此
AudioDecoder
的当前CodecState
。 [[decodeQueueSize]]
-
待处理解码请求的数量。该数值会在底层编解码器准备接受新输入时减少。
[[pending flush promises]]
-
由调用
flush()
返回的未解决 promise 列表。 [[dequeue event scheduled]]
-
一个布尔值,指示
dequeue
事件是否已安排触发。用于避免事件刷屏。
3.2. 构造函数
AudioDecoder(init)
-
令 d 为一个新的
AudioDecoder
对象。 -
为
[[control message queue]]
分配一个新的 队列。 -
为
[[message queue blocked]]
赋值false
。 -
为
[[codec implementation]]
赋值null
。 -
为
[[codec work queue]]
赋值为新启动的 并行队列。 -
为
[[codec saturated]]
赋值false
。 -
为
[[output callback]]
赋值 init.output。 -
为
[[error callback]]
赋值 init.error。 -
为
[[key chunk required]]
赋值true
。 -
为
[[state]]
赋值"unconfigured"
。 -
为
[[decodeQueueSize]]
赋值0
。 -
为
[[pending flush promises]]
分配一个新的 列表。 -
为
[[dequeue event scheduled]]
赋值false
。 -
返回 d。
3.3. 属性
state
, 类型为 CodecState,只读-
返回
[[state]]
的值。 decodeQueueSize
, 类型为 unsigned long,只读-
返回
[[decodeQueueSize]]
的值。 ondequeue
, 类型为 EventHandler-
一个 事件处理 IDL 属性,其 事件类型为
dequeue
。
3.4. 事件概述
dequeue
-
当
AudioDecoder
的decodeQueueSize
减少时触发。
3.5. 方法
configure(config)
-
入队一个控制消息,用于根据 config 的描述配置音频解码器以解码数据块。
注意:如果 User Agent 不支持 config,此方法会触发
NotSupportedError
。 建议作者在调用本方法前,先通过isConfigSupported()
检查支持情况。 User Agent 不需要支持任何特定的编解码类型或配置。调用时,执行以下步骤:
-
如果 config 不是一个 有效的 AudioDecoderConfig,则抛出
TypeError
。 -
如果
[[state]]
为“closed”
,则抛出InvalidStateError
。 -
将
[[state]]
设为"configured"
。 -
将
[[key chunk required]]
设为true
。 -
入队一个控制消息,用 config 配置解码器。
运行控制消息以配置解码器时,执行以下步骤:
-
将
true
赋值给[[message queue blocked]]
。 -
将以下步骤入队到
[[codec work queue]]
:-
令 supported 为使用 config 运行 检查配置支持算法的结果。
-
如果 supported 为
false
,入队一个任务,运行 关闭 AudioDecoder算法,并传入NotSupportedError
,然后中止这些步骤。 -
如有需要,将
[[codec implementation]]
赋值为支持 config 的实现。 -
用 config 配置
[[codec implementation]]
。 -
入队一个任务,执行以下步骤:
-
将
false
赋值给[[message queue blocked]]
。
-
-
-
返回
"processed"
。
-
decode(chunk)
-
入队一个控制消息,用于解码给定的 chunk。
调用时,执行以下步骤:
-
如果
[[state]]
不为"configured"
,则抛出InvalidStateError
。 -
如果
[[key chunk required]]
为true
:-
实现者 建议检查 chunk 的
[[internal data]]
,以验证其确实为 key chunk。如发现不匹配,则抛出DataError
。 -
否则,将
false
赋值给[[key chunk required]]
。
-
入队一个控制消息,用于解码 chunk。
运行控制消息以解码数据块时,执行以下步骤:
-
如果
[[codec saturated]]
等于true
,则返回"not processed"
。 -
如果解码数据块会导致
[[codec implementation]]
变为 饱和,则将true
赋值给[[codec saturated]]
。 -
递减
[[decodeQueueSize]]
,并运行 调度 Dequeue 事件算法。 -
将以下步骤入队到
[[codec work queue]]
:-
尝试使用
[[codec implementation]]
解码数据块。 -
如果解码出错,入队一个任务,运行 关闭 AudioDecoder算法,并传入
EncodingError
,然后返回。 -
如果
[[codec saturated]]
等于true
且[[codec implementation]]
不再 饱和,入队一个任务,执行以下步骤:-
将
false
赋值给[[codec saturated]]
。
-
-
令 decoded outputs 为由
[[codec implementation]]
产生的解码音频数据输出的 列表。 -
如果 decoded outputs 非空,入队一个任务,运行 输出 AudioData算法,并传入 decoded outputs。
-
-
返回
"processed"
。
-
flush()
-
完成 控制消息队列中的所有消息,并输出所有结果。
调用时,执行以下步骤:
-
如果
[[state]]
不为"configured"
,则返回 一个被拒绝的 promise,错误为InvalidStateError
DOMException
。 -
将
[[key chunk required]]
设为true
。 -
令 promise 为一个新的 Promise。
-
将 promise 添加到
[[pending flush promises]]
。 -
入队一个控制消息,用 promise 刷新编解码器。
-
返回 promise。
运行控制消息以刷新编解码器时,使用 promise 执行以下步骤:
-
将以下步骤入队到
[[codec work queue]]
:-
通知
[[codec implementation]]
输出所有 内部待输出数据。 -
令 decoded outputs 为由
[[codec implementation]]
产生的解码音频数据输出的 列表。 -
入队一个任务,执行以下步骤:
-
如果 decoded outputs 非空,运行 输出 AudioData 算法,并传入 decoded outputs。
-
从
[[pending flush promises]]
中移除 promise。 -
解决 promise。
-
-
-
返回
"processed"
。
-
reset()
-
立即重置所有状态,包括配置、控制消息队列中的消息,以及所有待处理的回调。
调用时,使用
AbortError
DOMException
,运行 重置 AudioDecoder算法。 close()
-
立即中止所有待处理工作并释放 系统资源。
关闭操作是最终的。
调用时,使用
AbortError
DOMException
,运行 关闭 AudioDecoder算法。 isConfigSupported(config)
-
返回一个 promise,指示 User Agent 是否支持所提供的 config。
注意:返回的
AudioDecoderSupport
config
只包含 User Agent 识别的字典成员。未识别的成员将被忽略。作者可通过比较config
与其提供的 config 来检测未识别的成员。调用时,执行以下步骤:
-
如果 config 不是一个 有效的 AudioDecoderConfig,则返回 一个被拒绝的 promise,错误为
TypeError
。 -
令 p 为一个新的 Promise。
-
令 checkSupportQueue 为新启动的 并行队列。
-
将以下步骤入队到 checkSupportQueue:
-
返回 p。
-
3.6. 算法
- 调度 Dequeue 事件
-
-
如果
[[dequeue event scheduled]]
等于true
,则返回。 -
将
true
赋值给[[dequeue event scheduled]]
。 -
入队一个任务,执行以下步骤:
-
将
false
赋值给[[dequeue event scheduled]]
。
-
- 输出 AudioData (with outputs)
-
执行以下步骤:
-
对于 outputs 中的每个 output:
-
令 data 为一个
AudioData
, 按如下方式初始化:-
将
false
赋值给[[Detached]]
。 -
令 resource 为 output 描述的 媒体资源。
-
令 resourceReference 为 resource 的引用。
-
将 resourceReference 赋值给
[[resource reference]]
。 -
令 timestamp 为与 output 关联的
EncodedAudioChunk
的[[timestamp]]
。 -
将 timestamp 赋值给
[[timestamp]]
。 -
如果 output 使用已识别的
AudioSampleFormat
, 则将该格式赋值给[[format]]
; 否则,将null
赋值给[[format]]
。 -
根据 output,为
[[sample rate]]
、[[number of frames]]
、[[number of channels]]
赋值。
-
-
用 data 调用
[[output callback]]
。
-
-
- 重置 AudioDecoder (with exception)
-
执行以下步骤:
-
如果
[[state]]
为"closed"
,则抛出InvalidStateError
。 -
将
[[state]]
设为"unconfigured"
。 -
通知
[[codec implementation]]
停止为之前的配置产生输出。 -
从
[[control message queue]]
中移除所有 控制消息。 -
如果
[[decodeQueueSize]]
大于零:-
将
[[decodeQueueSize]]
设为零。 -
运行 调度 Dequeue 事件算法。
-
-
对于
[[pending flush promises]]
中的每个 promise:-
用 exception 拒绝 promise。
-
从
[[pending flush promises]]
中移除 promise。
-
-
- 关闭 AudioDecoder (with exception)
-
执行以下步骤:
-
用 exception 运行 重置 AudioDecoder算法。
-
将
[[state]]
设为"closed"
。 -
清空
[[codec implementation]]
并释放相关的 系统资源。 -
如果 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]]
[[state]]
-
此
VideoDecoder
的当前CodecState
。 [[decodeQueueSize]]
-
待处理解码请求的数量。该数值会在底层编解码器准备好接受新输入时减少。
[[pending flush promises]]
-
由调用
flush()
返回的未解决 promise 列表。 [[dequeue event scheduled]]
-
一个布尔值,指示是否已安排触发
dequeue
事件。用于避免事件泛滥。
4.2. 构造函数
VideoDecoder(init)
-
令 d 为一个新的
VideoDecoder
对象。 -
为
[[control message queue]]
分配一个新的 队列。 -
为
[[message queue blocked]]
赋值false
。 -
为
[[codec implementation]]
赋值null
。 -
为
[[codec work queue]]
分配一个新启动的 并行队列。 -
为
[[codec saturated]]
赋值false
。 -
为
[[output callback]]
赋值 init.output。 -
为
[[error callback]]
赋值 init.error。 -
为
[[active decoder config]]
赋值null
。 -
为
[[key chunk required]]
赋值true
。 -
为
[[state]]
赋值"unconfigured"
。 -
为
[[decodeQueueSize]]
赋值0
。 -
为
[[pending flush promises]]
分配一个新的 列表。 -
为
[[dequeue event scheduled]]
赋值false
。 -
返回 d。
4.3. 属性
state
, 类型为 CodecState,只读-
返回
[[state]]
的值。 decodeQueueSize
, 类型为 unsigned long,只读-
返回
[[decodeQueueSize]]
的值。 ondequeue
, 类型为 EventHandler-
一个 事件处理 IDL 属性,其 事件类型为
dequeue
。
4.4. 事件概述
dequeue
-
当
VideoDecoder
的decodeQueueSize
减少时触发。
4.5. 方法
configure(config)
-
入队一个控制消息,用于根据 config 的描述配置视频解码器以解码数据块。
注意:如果 User Agent 不支持 config,此方法会触发
NotSupportedError
。 建议作者在调用本方法前,先通过isConfigSupported()
检查支持情况。 User Agent 不需要支持任何特定的编解码类型或配置。调用时,执行以下步骤:
-
如果 config 不是一个 有效的 VideoDecoderConfig,则抛出
TypeError
。 -
如果
[[state]]
为“closed”
,则抛出InvalidStateError
。 -
将
[[state]]
设为"configured"
。 -
将
[[key chunk required]]
设为true
。 -
入队一个控制消息,用 config 配置解码器。
运行控制消息以配置解码器时,执行以下步骤:
-
将
true
赋值给[[message queue blocked]]
。 -
将以下步骤入队到
[[codec work queue]]
:-
令 supported 为使用 config 运行 检查配置支持算法的结果。
-
如果 supported 为
false
,入队一个任务,运行 关闭 VideoDecoder算法,并传入NotSupportedError
,然后中止这些步骤。 -
如有需要,将
[[codec implementation]]
赋值为支持 config 的实现。 -
用 config 配置
[[codec implementation]]
。 -
入队一个任务,执行以下步骤:
-
将
false
赋值给[[message queue blocked]]
。
-
-
-
返回
"processed"
。
-
decode(chunk)
-
入队一个控制消息,用于解码给定的 chunk。
注意:建议作者在输出的
VideoFrame
不再需要时立即调用close()
。底层 媒体资源 归VideoDecoder
所有,未及时释放(或等待垃圾回收)可能导致解码阻塞。注意:
VideoDecoder
要求帧按预期展示顺序输出(即 presentation order)。某些[[codec implementation]]
下,User Agent 需将输出重新排序为展示顺序。调用时,执行以下步骤:
-
如果
[[state]]
不为"configured"
,则抛出InvalidStateError
。 -
如果
[[key chunk required]]
为true
:-
实现者 建议检查 chunk 的
[[internal data]]
,以验证其确实为 key chunk。如发现不匹配,则抛出DataError
。 -
否则,将
false
赋值给[[key chunk required]]
。
-
入队一个控制消息,用于解码 chunk。
运行控制消息以解码数据块时,执行以下步骤:
-
如果
[[codec saturated]]
等于true
,则返回"not processed"
。 -
如果解码数据块会导致
[[codec implementation]]
变为 饱和,则将true
赋值给[[codec saturated]]
。 -
递减
[[decodeQueueSize]]
,并运行 调度 Dequeue 事件算法。 -
将以下步骤入队到
[[codec work queue]]
:-
尝试使用
[[codec implementation]]
解码数据块。 -
如果解码出错,入队一个任务,运行 关闭 VideoDecoder算法,并传入
EncodingError
,然后返回。 -
如果
[[codec saturated]]
等于true
且[[codec implementation]]
不再 饱和,入队一个任务,执行以下步骤:-
将
false
赋值给[[codec saturated]]
。
-
-
令 decoded outputs 为由
[[codec implementation]]
产生的解码视频数据输出的 列表(按展示顺序)。 -
如果 decoded outputs 非空,入队一个任务,运行 输出 VideoFrame算法,并传入 decoded outputs。
-
-
返回
"processed"
。
-
flush()
-
完成 控制消息队列中的所有消息,并输出所有结果。
调用时,执行以下步骤:
-
如果
[[state]]
不为"configured"
,则返回 一个被拒绝的 promise,错误为InvalidStateError
DOMException
。 -
将
[[key chunk required]]
设为true
。 -
令 promise 为一个新的 Promise。
-
将 promise 添加到
[[pending flush promises]]
。 -
入队一个控制消息,用 promise 刷新编解码器。
-
返回 promise。
运行控制消息以刷新编解码器时,使用 promise 执行以下步骤:
-
将以下步骤入队到
[[codec work queue]]
:-
通知
[[codec implementation]]
输出所有 内部待输出数据。 -
令 decoded outputs 为由
[[codec implementation]]
产生的解码视频数据输出的 列表。 -
入队一个任务,执行以下步骤:
-
如果 decoded outputs 非空,运行 输出 VideoFrame 算法,并传入 decoded outputs。
-
从
[[pending flush promises]]
中移除 promise。 -
解决 promise。
-
-
-
返回
"processed"
。
-
reset()
-
立即重置所有状态,包括配置、控制消息队列中的消息,以及所有待处理的回调。
调用时,使用
AbortError
DOMException
,运行 重置 VideoDecoder算法。 close()
-
立即中止所有待处理工作并释放 系统资源。
关闭操作是最终的。
调用时,使用
AbortError
DOMException
,运行 关闭 VideoDecoder算法。 isConfigSupported(config)
-
返回一个 promise,指示 User Agent 是否支持所提供的 config。
注意:返回的
VideoDecoderSupport
config
只包含 User Agent 识别的字典成员。未识别的成员将被忽略。作者可通过比较config
与其提供的 config 来检测未识别的成员。调用时,执行以下步骤:
-
如果 config 不是一个 有效的 VideoDecoderConfig,则返回 一个被拒绝的 promise,错误为
TypeError
。 -
令 p 为一个新的 Promise。
-
令 checkSupportQueue 为新启动的 并行队列。
-
将以下步骤入队到 checkSupportQueue:
-
返回 p。
-
4.6. 算法
- 调度出队事件
-
-
如果
[[dequeue event scheduled]]
等于true
,则返回。 -
将
true
赋值给[[dequeue event scheduled]]
。 -
队列一个任务以运行以下步骤:
-
将
false
赋值给[[dequeue event scheduled]]
。
-
- 输出 VideoFrames (带 outputs)
-
执行以下步骤:
-
对于 outputs 中的每个 output:
-
令 displayAspectWidth 和 displayAspectHeight 为未定义。
-
如果
displayAspectWidth
和displayAspectHeight
存在于[[active decoder config]]
, 则分别将其值赋给 displayAspectWidth 和 displayAspectHeight。 -
令 colorSpace 为编解码器实现检测到的
VideoColorSpace
。 如果未检测到VideoColorSpace
, 则令 colorSpace 为undefined
。注意: 编解码器实现可以通过分析比特流检测
VideoColorSpace
。 检测是尽力而为,具体方法由实现者定义且与编解码器相关。作者可以通过在VideoDecoderConfig
中提供colorSpace
来覆盖检测到的VideoColorSpace
。 -
如果
colorSpace
存在于[[active decoder config]]
, 则将其值赋给 colorSpace。 -
令 frame 为使用 output、timestamp、duration、 displayAspectWidth、displayAspectHeight、 colorSpace、rotation 和 flip 运行 创建 VideoFrame 算法的结果。
-
用 frame 调用
[[output callback]]
。
-
- 重置 VideoDecoder (带 exception)
-
执行以下步骤:
-
如果
state
为"closed"
,则抛出InvalidStateError
。 -
将
state
设为"unconfigured"
。 -
通知
[[codec implementation]]
停止为先前配置产生输出。 -
从
[[control message queue]]
中移除所有 控制消息。 -
如果
[[decodeQueueSize]]
大于零:-
将
[[decodeQueueSize]]
设为零。 -
运行 调度出队事件算法。
-
-
对于
[[pending flush promises]]
中的每个 promise:-
用 exception 拒绝 promise。
-
从
[[pending flush promises]]
中移除 promise。
-
-
- 关闭 VideoDecoder (带 exception)
-
执行以下步骤:
-
用 exception 运行 重置 VideoDecoder算法。
-
将
state
设为"closed"
。 -
清除
[[codec implementation]]
并释放相关 系统资源。 -
如果 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]]
-
描述如何解码最近发出的
EncodedAudioChunk
的AudioDecoderConfig
。 [[state]]
-
此
AudioEncoder
的当前CodecState
。 [[encodeQueueSize]]
-
待处理编码请求的数量。该数值会随着底层编解码器准备好接受新输入而减少。
[[pending flush promises]]
-
由调用
flush()
返回的未解决 promise 列表。 [[dequeue event scheduled]]
-
一个布尔值,指示是否已经安排了
dequeue
事件。用于避免事件泛滥。
5.2. 构造函数
AudioEncoder(init)
-
令 e 为一个新的
AudioEncoder
对象。 -
为
[[control message queue]]
赋值为一个新的 队列。 -
将
false
赋值给[[message queue blocked]]
。 -
将
null
赋值给[[codec implementation]]
。 -
将启动一个新的 并行队列的结果赋值给
[[codec work queue]]
。 -
将
false
赋值给[[codec saturated]]
。 -
将 init.output 赋值给
[[output callback]]
。 -
将 init.error 赋值给
[[error callback]]
。 -
将
null
赋值给[[active encoder config]]
。 -
将
null
赋值给[[active output config]]
。 -
将
"unconfigured"
赋值给[[state]]
-
将
0
赋值给[[encodeQueueSize]]
。 -
为
[[pending flush promises]]
赋值为一个新的 列表。 -
将
false
赋值给[[dequeue event scheduled]]
。 -
返回 e。
5.3. 属性
state
, 类型为 CodecState,只读-
返回
[[state]]
的值。 encodeQueueSize
, 类型为 unsigned long,只读-
返回
[[encodeQueueSize]]
的值。 ondequeue
, 类型为 EventHandler-
一个 事件处理器 IDL 属性,其 事件处理器事件类型为
dequeue
。
5.4. 事件摘要
dequeue
-
当
AudioEncoder
的encodeQueueSize
减少时触发。
5.5. 方法
configure(config)
-
入队一个控制消息,用于根据 config 配置音频编码器以编码音频数据。
注意: 如果用户代理不支持 config,此方法会触发
NotSupportedError
。 建议作者在调用isConfigSupported()
并传入 config 以先检查支持情况。 用户代理不必支持任何特定的编解码器类型或配置。调用时,执行以下步骤:
-
如果 config 不是一个 有效的 AudioEncoderConfig,则抛出
TypeError
。 -
如果
[[state]]
为"closed"
,则抛出InvalidStateError
。 -
将
[[state]]
设为"configured"
。 -
入队一个控制消息,用 config 配置编码器。
运行控制消息以配置编码器时,执行以下步骤:
-
将
true
赋值给[[message queue blocked]]
。 -
将以下步骤入队到
[[codec work queue]]
:-
令 supported 为用 config 运行 检查配置支持算法的结果。
-
如果 supported 为
false
,队列一个任务,用NotSupportedError
运行 关闭 AudioEncoder 算法,并中止这些步骤。 -
如有需要,将支持 config 的实现赋值给
[[codec implementation]]
。 -
用 config 配置
[[codec implementation]]
。 -
队列一个任务,执行以下步骤:
-
将
false
赋值给[[message queue blocked]]
。
-
-
-
返回
"processed"
。
-
encode(data)
-
入队一个控制消息,用于编码给定的 data。
调用时,执行以下步骤:
-
如果 data 的
[[Detached]]
内部插槽值为true
,则抛出TypeError
。 -
如果
[[state]]
不为"configured"
,则抛出InvalidStateError
。 -
令 dataClone 为用 data 运行 克隆 AudioData算法的结果。
-
入队一个控制消息,用于编码 dataClone。
运行控制消息以编码数据时,执行以下步骤:
-
如果
[[codec saturated]]
等于true
,则返回"not processed"
。 -
如果编码 data 会导致
[[codec implementation]]
变为 饱和,则将true
赋值给[[codec saturated]]
。 -
递减
[[encodeQueueSize]]
, 并运行 调度出队事件算法。 -
将以下步骤入队到
[[codec work queue]]
:-
尝试使用
[[codec implementation]]
编码由 dataClone 描述的 媒体资源。 -
如果编码出错,队列一个任务,用
EncodingError
运行 关闭 AudioEncoder算法并返回。 -
如果
[[codec saturated]]
等于true
且[[codec implementation]]
不再 饱和,队列一个任务,执行以下步骤:-
将
false
赋值给[[codec saturated]]
。
-
-
令 encoded outputs 为由
[[codec implementation]]
发出的编码音频数据输出的 列表。 -
如果 encoded outputs 非空,队列一个任务,用 encoded outputs 运行 输出 EncodedAudioChunks算法。
-
-
返回
"processed"
。
-
flush()
-
完成 控制消息队列中的所有控制消息,并发出所有输出。
调用时,执行以下步骤:
-
如果
[[state]]
不为"configured"
,则返回 一个被拒绝的 promise,原因为InvalidStateError
DOMException
。 -
令 promise 为一个新的 Promise。
-
将 promise 添加到
[[pending flush promises]]
。 -
入队一个控制消息,用 promise 刷新编解码器。
-
返回 promise。
运行控制消息以刷新编解码器时,使用 promise 执行以下步骤:
-
将以下步骤入队到
[[codec work queue]]
:-
通知
[[codec implementation]]
发出所有 内部待输出。 -
令 encoded outputs 为由
[[codec implementation]]
发出的编码音频数据输出的 列表。 -
队列一个任务,执行以下步骤:
-
如果 encoded outputs 非空,则用 encoded outputs 运行 输出 EncodedAudioChunks算法。
-
从
[[pending flush promises]]
中移除 promise。 -
解决 promise。
-
-
-
返回
"processed"
。
-
reset()
-
立即重置所有状态,包括配置、控制消息队列中的控制消息,以及所有待处理的回调。
调用时,使用
AbortError
DOMException
,运行 重置 AudioEncoder算法。 close()
-
立即中止所有待处理工作并释放系统资源。
关闭操作是最终的。
调用时,使用
AbortError
DOMException
,运行 关闭 AudioEncoder算法。 isConfigSupported(config)
-
返回一个 promise,指示用户代理是否支持所提供的 config。
注意: 返回的
AudioEncoderSupport
config
只包含用户代理识别的字典成员。未识别的字典成员将被忽略。作者可通过比较config
与其提供的 config 来检测未识别的成员。调用时,执行以下步骤:
-
如果 config 不是一个 有效的 AudioEncoderConfig,则返回 一个被拒绝的 promise,原因为
TypeError
。 -
令 p 为一个新的 Promise。
-
令 checkSupportQueue 为启动一个新的 并行队列的结果。
-
将以下步骤入队到 checkSupportQueue:
-
返回 p。
-
5.6. 算法
- 调度出队事件
-
-
如果
[[dequeue event scheduled]]
等于true
,则返回。 -
将
true
赋值给[[dequeue event scheduled]]
。 -
队列一个任务以运行以下步骤:
-
将
false
赋值给[[dequeue event scheduled]]
。
-
- 输出 EncodedAudioChunks (带 outputs)
-
执行以下步骤:
-
对于 outputs 中的每个 output:
-
令 chunkInit 为一个
EncodedAudioChunkInit
,包含以下键: -
令 chunk 为用 chunkInit 构造的新
EncodedAudioChunk
。 -
令 chunkMetadata 为一个新的
EncodedAudioChunkMetadata
。 -
令 encoderConfig 为
[[active encoder config]]
。 -
令 outputConfig 为一个新的
AudioDecoderConfig
, 用于描述 output。初始化 outputConfig 如下:-
将 encoderConfig.
sampleRate
赋值给 outputConfig.sampleRate
。 -
将 encoderConfig.
numberOfChannels
赋值给 outputConfig.numberOfChannels
。 -
用由
[[codec implementation]]
决定的一系列编解码器特定字节赋值给 outputConfig.description
。 用户代理 必须确保所提供的 description 可用于正确解码输出。注意: 填充
description
的编解码器特定要求见 [WEBCODECS-CODEC-REGISTRY]。
-
如果 outputConfig 和
[[active output config]]
不是 等价字典:-
将 outputConfig 赋值给 chunkMetadata.
decoderConfig
。 -
将 outputConfig 赋值给
[[active output config]]
。
-
-
用 chunk 和 chunkMetadata 调用
[[output callback]]
。
-
-
- 重置 AudioEncoder (带 exception)
-
执行以下步骤:
-
如果
[[state]]
为"closed"
,则抛出InvalidStateError
。 -
将
[[state]]
设为"unconfigured"
。 -
将
[[active encoder config]]
设为null
。 -
将
[[active output config]]
设为null
。 -
通知
[[codec implementation]]
停止为先前配置产生输出。 -
从
[[control message queue]]
中移除所有 控制消息。 -
如果
[[encodeQueueSize]]
大于零:-
将
[[encodeQueueSize]]
设为零。 -
运行 调度出队事件算法。
-
-
对于
[[pending flush promises]]
中的每个 promise:-
用 exception 拒绝 promise。
-
从
[[pending flush promises]]
中移除 promise。
-
-
- 关闭 AudioEncoder (带 exception)
-
执行以下步骤:
-
用 exception 运行 重置 AudioEncoder算法。
-
将
[[state]]
设为"closed"
。 -
清除
[[codec implementation]]
并释放相关 系统资源。 -
如果 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]]
-
用于描述如何解码最近发出的
EncodedVideoChunk
的VideoDecoderConfig
。 [[state]]
-
此
VideoEncoder
的当前CodecState
。 [[encodeQueueSize]]
-
挂起的编码请求数量。随着底层编解码器准备好接受新输入,此数字会减少。
[[pending flush promises]]
-
由调用
flush()
返回的未解决 Promise 列表。 [[dequeue event scheduled]]
-
一个布尔值,指示是否已有
dequeue
事件计划触发。用于避免事件泛滥。 [[active orientation]]
-
一个整数与布尔值的组合,表示在
configure()
之后第一次传给encode()
的VideoFrame
的[[flip]]
和[[rotation]]
。
6.2. 构造函数
VideoEncoder(init)
-
令 e 为一个新的
VideoEncoder
对象。 -
为
[[control message queue]]
分配一个新的 队列。 -
将
false
赋给[[message queue blocked]]
。 -
将
null
赋给[[codec implementation]]
。 -
启动一个新的 parallel queue,并将其结果赋给
[[codec work queue]]
。 -
将
false
赋给[[codec saturated]]
。 -
将
init.output
赋给[[output callback]]
。 -
将
init.error
赋给[[error callback]]
。 -
将
null
赋给[[active encoder config]]
。 -
将
null
赋给[[active output config]]
。 -
将
"unconfigured"
赋给[[state]]
。 -
将
0
赋给[[encodeQueueSize]]
。 -
为
[[pending flush promises]]
分配一个新的 列表。 -
将
false
赋给[[dequeue event scheduled]]
。 -
返回 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 的支持。用户代理不需要支持任何特定的编码器类型或配置。调用时,执行以下步骤:
-
如果 config 不是一个 有效的 VideoEncoderConfig,则抛出
TypeError
。 -
如果
[[state]]
为"closed"
,则抛出InvalidStateError
。 -
将
[[state]]
设为"configured"
。 -
将
[[active orientation]]
设为null
。 -
入队一个控制消息,使用 config 配置编码器。
运行控制消息 以配置编码器时,需要执行以下步骤:
-
将
true
赋给[[message queue blocked]]
。 -
将以下步骤入队到
[[codec work queue]]
:-
令 supported 为使用 config 运行 Check Configuration Support 算法的结果。
-
如果 supported 为
false
,则 排队一个任务 来运行 Close VideoEncoder 算法并带上NotSupportedError
,然后中止这些步骤。 -
如有需要,将一个支持 config 的实现赋给
[[codec implementation]]
。 -
使用 config 配置
[[codec implementation]]
。 -
排队一个任务 来运行以下步骤:
-
将
false
赋给[[message queue blocked]]
。
-
-
-
返回
"processed"
。
-
encode(frame, options)
-
入队一个控制消息,用于对给定的 frame 进行编码。
调用时,执行以下步骤:
-
如果 frame 的
[[Detached]]
内部插槽的值为true
,则抛出TypeError
。 -
如果
[[state]]
不是"configured"
,则抛出InvalidStateError
。 -
如果
[[active orientation]]
非空且与 frame 的[[rotation]]
与[[flip]]
不匹配,则抛出DataError
。 -
如果
[[active orientation]]
为null
,则将其设为 frame 的[[rotation]]
与[[flip]]
。 -
令 frameClone 为使用 Clone VideoFrame 算法对 frame 的结果。
-
将
[[encodeQueueSize]]
增加。 -
入队一个控制消息 来编码 frameClone。
运行控制消息 以编码该帧时,需要执行以下步骤:
-
如果
[[codec saturated]]
等于true
,则返回"not processed"
。 -
如果编码 frame 会导致
[[codec implementation]]
变为 saturated,则将true
赋给[[codec saturated]]
。 -
将
[[encodeQueueSize]]
减少,并运行 Schedule Dequeue Event 算法。 -
将以下步骤入队到
[[codec work queue]]
:-
尝试使用
[[codec implementation]]
根据 options 对 frameClone 进行编码。 -
如果编码导致错误,排队一个任务 来运行 Close VideoEncoder 算法并带上
EncodingError
,然后返回。 -
如果
[[codec saturated]]
等于true
且[[codec implementation]]
不再处于 saturated 状态, 则 排队一个任务 来执行以下步骤:-
将
false
赋给[[codec saturated]]
。
-
-
令 encoded outputs 为
[[codec implementation]]
发出的编码视频数据输出的 列表。 -
如果 encoded outputs 非空,排队一个任务 来运行 Output EncodedVideoChunks 算法,参数为 encoded outputs。
-
-
返回
"processed"
。
-
flush()
-
完成控制消息队列中的所有 控制消息
并输出所有编码产出。
调用时,执行以下步骤:
-
如果
[[state]]
不是"configured"
,则返回 一个以InvalidStateError
DOMException
被拒绝的 Promise。 -
令 promise 为一个新的 Promise。
-
将 promise 附加到
[[pending flush promises]]
。 -
入队一个控制消息 来使用 promise 刷新编解码器。
-
返回 promise。
运行控制消息 以刷新编解码器时,需对该 promise 执行以下步骤:
-
将以下步骤入队到
[[codec work queue]]
:-
通知
[[codec implementation]]
发出所有内部挂起输出(internal pending outputs)。 -
令 encoded outputs 为
[[codec implementation]]
发出的编码视频数据输出的 列表。 -
排队一个任务 来执行以下步骤:
-
如果 encoded outputs 非空,则使用 encoded outputs 运行 Output EncodedVideoChunks 算法。
-
从
[[pending flush promises]]
中移除 promise。 -
解析 promise。
-
-
-
返回
"processed"
。
-
reset()
-
立即重置所有状态,包括配置、控制消息队列中的 控制消息,以及所有挂起的回调。
调用时,使用一个带有
AbortError
的DOMException
来运行 Reset VideoEncoder 算法。 close()
-
立即中止所有挂起的工作并释放 系统资源。Close 为最终操作。
调用时,使用一个带有
AbortError
的DOMException
来运行 Close VideoEncoder 算法。 isConfigSupported(config)
-
返回一个 Promise,指示所提供的 config 是否被用户代理支持。
注意:返回的
VideoEncoderSupport
的config
只会包含用户代理识别的字典成员。未识别的字典成员将被忽略。作者可以通过将返回的config
与自己提供的 config 进行比较以检测未识别的成员。调用时,执行以下步骤:
-
如果 config 不是一个 有效的 VideoEncoderConfig,则返回 一个以
TypeError
被拒绝的 Promise。 -
令 p 为一个新的 Promise。
-
令 checkSupportQueue 为启动一个新的 parallel queue 的结果。
-
将以下步骤入队到 checkSupportQueue:
-
令 supported 为使用 config 运行 Check Configuration Support 算法的结果。
-
排队一个任务 来运行以下步骤:
-
令 encoderSupport 为新构造的
VideoEncoderSupport
,并按如下方式初始化:-
将
config
设为使用 config 运行 Clone Configuration 算法的结果。 -
将
supported
设为 supported。
-
-
-
使用 encoderSupport 解析 p。
-
-
返回 p。
-
6.6. 算法
- Schedule Dequeue Event
-
-
如果
[[dequeue event scheduled]]
等于true
,则返回。 -
将
true
赋给[[dequeue event scheduled]]
。 -
排队一个任务 来运行以下步骤:
-
将
false
赋给[[dequeue event scheduled]]
。
-
- Output EncodedVideoChunks (with outputs)
-
运行这些步骤:
-
对于 outputs 中的每个 output:
-
令 chunkInit 为一个
EncodedVideoChunkInit
,包含以下键:-
令
data
包含来自 output 的已编码视频数据。 -
令
type
为 output 的EncodedVideoChunkType
。 -
令
timestamp
为与 output 关联的VideoFrame
的[[timestamp]]
。 -
令
duration
为与 output 关联的VideoFrame
的[[duration]]
。
-
-
令 chunk 为使用 chunkInit 构造的新
EncodedVideoChunk
。 -
令 chunkMetadata 为新建的
EncodedVideoChunkMetadata
。 -
令 encoderConfig 为
[[active encoder config]]
。 -
令 outputConfig 为描述 output 的一个
VideoDecoderConfig
。按如下方式初始化 outputConfig:-
将
encoderConfig.codec
赋给outputConfig.codec
。 -
将
encoderConfig.width
赋给outputConfig.codedWidth
。 -
将
encoderConfig.height
赋给outputConfig.codedHeight
。 -
将
encoderConfig.displayWidth
赋给outputConfig.displayAspectWidth
。 -
将
encoderConfig.displayHeight
赋给outputConfig.displayAspectHeight
。 -
将与 output 关联的
VideoFrame
的[[rotation]]
赋给outputConfig.rotation
。 -
将与 output 关联的
VideoFrame
的[[flip]]
赋给outputConfig.flip
。 -
按
[[codec implementation]]
确定的方式,赋值outputConfig
的其余键。用户代理 MUST 确保该配置被完整描述,以便 outputConfig 可用于正确解码 output。注意:有关填充
description
的编解码器特定要求,请参见 [WEBCODECS-CODEC-REGISTRY]。
-
-
如果 outputConfig 与
[[active output config]]
不是 equal dictionaries:-
将 outputConfig 赋给 chunkMetadata.
decoderConfig
。 -
将 outputConfig 赋给
[[active output config]]
。
-
-
如果 encoderConfig.
scalabilityMode
描述了多个 temporal layers:-
令 svc 为新建的
SvcOutputMetadata
实例。 -
令 temporal_layer_id 为描述 output 的 temporal layer 的从零开始的索引。
-
将 temporal_layer_id 赋给 svc.
temporalLayerId
。 -
将 svc 赋给 chunkMetadata.
svc
。
-
-
如果 encoderConfig.
alpha
设置为"keep"
:-
令 alphaSideData 为 output 中的编码 alpha 数据。
-
将 alphaSideData 赋给 chunkMetadata.
alphaSideData
。
-
-
用 chunk 和 chunkMetadata 调用
[[output callback]]
。
-
-
- Reset VideoEncoder (with exception)
-
运行这些步骤:
-
如果
[[state]]
为"closed"
,则抛出InvalidStateError
。 -
将
[[state]]
设为"unconfigured"
。 -
将
[[active encoder config]]
设为null
。 -
将
[[active output config]]
设为null
。 -
通知
[[codec implementation]]
停止为先前配置产生输出。 -
如果
[[encodeQueueSize]]
大于零:-
将
[[encodeQueueSize]]
设为零。 -
运行 Schedule Dequeue Event 算法。
-
-
对于
[[pending flush promises]]
中的每个 promise:-
用 exception 拒绝 promise。
-
从
[[pending flush promises]]
中移除 promise。
-
-
- Close VideoEncoder (with exception)
-
运行这些步骤:
-
以 exception 运行 Reset VideoEncoder 算法。
-
将
[[state]]
设为"closed"
。 -
清除
[[codec implementation]]
并释放相关的 system resources。 -
如果 exception 不是一个带有
AbortError
的DOMException
,则用 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)
运行这些步骤:-
如果 config.codec 中的 codec string 不是一个 有效的 codec string,或者被用户代理无法识别,则返回
false
。 -
如果 config 是一个
AudioDecoderConfig
或VideoDecoderConfig
, 且用户代理无法提供可以解码 config.codec 中所指示的确切 profile(如有)、level(如有)和约束位(如有)的 codec,则返回false
。 -
如果 config 是一个
AudioEncoderConfig
或VideoEncoderConfig
:-
如果 config.codec 中的 codec string 包含 profile,且用户代理无法提供能够编码该 profile 的 codec,则返回
false
。 -
如果 config.codec 中的 codec string 包含 level,且用户代理无法提供能够编码到小于或等于该 level 的 codec,则返回
false
。 -
如果 config.codec 中的 codec string 包含约束位,且用户代理无法提供能够生成至少与该约束同等受限的编码比特流的 codec,则返回
false
。
-
-
如果用户代理可以提供一个 codec,以支持 config 的所有条目(包括对未包含键的适用默认值),则返回
true
。注意:类型
AudioDecoderConfig
、VideoDecoderConfig
、AudioEncoderConfig
、 和VideoEncoderConfig
各自定义了其配置项和默认值。注意:对给定配置的支持可能会因硬件改变(例如外接 GPU 被拔出)或关键硬件资源被耗尽而动态变化。用户代理应基于查询时可用的资源以尽力而为的方式描述支持情况。
-
否则,返回
false
。
7.2. 克隆配置 (with config)
注意:该算法仅会复制用户代理识别为该字典类型一部分的字典成员。
运行这些步骤:
-
令 dictType 为 config 的字典类型。
-
令 clone 为 dictType 的一个新的空实例。
-
对于在 dictType 上定义的每个字典成员 m:
-
如果 m 在 config 中不存在,则 继续 下一个成员。
-
如果
config[m]
是嵌套字典,则将clone[m]
设为递归运行 Clone Configuration 算法(参数为config[m]
) 的结果。 -
否则,将
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. 编解码器字符串
编解码器字符串用于描述要用于编码或解码的特定编解码器格式。一个 有效的编解码器字符串 必须 满足以下条件。
-
根据相关编解码器规范有效(见下面示例)。
-
它描述单一的编解码器。
-
对于定义这些概念的编解码器,它对配置文件(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,
请运行下列步骤:
-
如果
codec
在去除首尾 ASCII 空白字符后为空,则返回false
。 -
如果
description
已经是 [detached],则返回false
。 -
返回
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,请运行下列步骤:
-
如果
codec
在去除前导与尾随 ASCII 空白字符后为空,则返回false
。 -
如果
codedWidth
或codedHeight
中有一个提供但另一个未提供,则返回false
。 -
如果
codedWidth
= 0 或codedHeight
= 0,则返回false
。 -
如果
displayAspectWidth
或displayAspectHeight
中有一个提供但另一个未提供,则返回false
。 -
如果
displayAspectWidth
= 0 或displayAspectHeight
= 0,则返回false
。 -
如果
description
已为 [detached],则返回false
。 -
返回
true
。
codec
, 类型为 DOMString- 包含用于描述该编解码器的 编解码器字符串。
description
, 类型为 AllowSharedBufferSource-
一序列与编解码器相关的字节,通常称为 extradata(扩展数据)。
注意:在 [WEBCODECS-CODEC-REGISTRY] 中的注册会根据提供的
codec
说明是否以及如何填充该字节序列。 codedWidth
, 类型为 unsigned long- VideoFrame 的宽度(以像素为单位),可能包含不可见的填充,并且在考虑显示比例调整之前。
codedHeight
, 类型为 unsigned long-
VideoFrame 的高度(以像素为单位),可能包含不可见的填充,并且在考虑显示比例调整之前。
注意:
codedWidth
与codedHeight
会在选择[[codec implementation]]
时使用。 displayAspectWidth
, 类型为 unsigned long- VideoFrame 在显示时的横向纵横比分子(水平尺寸)。
displayAspectHeight
, 类型为 unsigned long-
VideoFrame 在显示时的纵向纵横比分母(垂直尺寸)。
注意:
displayWidth
与displayHeight
可以与displayAspectWidth
与displayAspectHeight
不同,但在创建视频帧时应用缩放后比率应相同(参见创建视频帧的相关步骤)。 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,请运行下列步骤:
-
如果
codec
在去除前导与尾随 ASCII 空白字符后为空,则返回false
。 -
如果该
AudioEncoderConfig
含有 codec-specific 扩展,且 [WEBCODECS-CODEC-REGISTRY] 中相应的注册定义了用于检查该扩展是否有效的步骤,则返回运行那些步骤的结果。 -
如果
sampleRate
或numberOfChannels
等于零,则返回false
。 -
返回
true
。
codec
, 类型为 DOMString- 包含用于描述该编解码器的 编解码器字符串。
sampleRate
, 类型为 unsigned long- 每秒的帧采样数量。
numberOfChannels
, 类型为 unsigned long- 音频通道数。
bitrate
, 类型为 unsigned long long- 编码后音频的平均比特率,单位为比特每秒。
bitrateMode
, 类型为 BitrateMode,默认值为"variable"
-
配置编码器使用
constant
或variable
比特率,定义见 [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,请运行下列步骤:
-
如果
codec
在去除前导与尾随 ASCII 空白字符后为空,则返回false
。 -
如果
displayWidth
= 0 或displayHeight
= 0,则返回false
。 -
返回
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
。
width
与 height
不同的 displayWidth
或
displayHeight
表明在解码后应对片段进行缩放以达到最终显示纵横比。
对于许多编解码器,这只是透传信息,但某些编解码器有时可能在比特流中包含显示尺寸。
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-hardware
和
prefer-software
是提示值。用户代理在可能时应当尊重这些值,但在某些或所有情况下,用户代理可能会因任何原因忽略这些值。
为防止指纹识别,如果用户代理实现了 [media-capabilities],
用户代理必须确保对某个 HardwareAcceleration
偏好的拒绝或接受不会泄露除用户代理本身已知及 [media-capabilities] 已公开的信息之外的额外信息。如果用户代理因指纹识别原因未实现
[media-capabilities],则应当忽略 HardwareAcceleration
偏好。
prefer-hardware
或
prefer-software
的典型场景包括用户隐私原因,或用户代理认为其他设置更适合最终用户的情况。
大多数作者使用默认值
no-preference
会获得最佳体验。这让用户代理可以根据其对系统和配置的了解进行优化。常见策略是在高分辨率时优先使用硬件加速,若硬件加速失败则回退到软件编解码器。
建议作者在设置硬件加速偏好时仔细权衡利弊。具体权衡会因设备而异,但一般可预期如下:
-
设置
prefer-hardware
或prefer-software
可能会显著限制支持的配置。可能出现用户设备不支持任何编解码器加速,或仅支持旧编解码器的常见配置文件,也可能某些用户代理缺乏软件编解码器实现。 -
硬件加速并不意味着编码/解码一定更快。硬件加速通常启动延迟更高,但吞吐性能更稳定。加速通常会降低 CPU 负载。
-
对于解码,硬件加速对输入数据的健壮性通常低于软件实现,尤其是输入标签错误或不符合相关编解码器规范时。
-
硬件加速通常比纯软件编解码器更节能。
-
对于低分辨率内容,硬件加速带来的额外开销可能导致性能和能效低于纯软件编解码器。
鉴于这些权衡,“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
-
表示用户代理应当优化编码质量。在此模式下:
realtime
-
表示用户代理应当优化低延迟。在此模式下:
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 ; // microsecondsreadonly attribute unsigned long long ?duration ; // microsecondsreadonly attribute unsigned long byteLength ;undefined copyTo (AllowSharedBufferSource ); };
destination dictionary {
EncodedAudioChunkInit required EncodedAudioChunkType ; [
type EnforceRange ]required long long ; // microseconds [
timestamp EnforceRange ]unsigned long long ; // microseconds
duration 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)
-
If init.
transfer
contains more than one reference to the sameArrayBuffer
, then throw aDataCloneError
DOMException
. -
For each transferable in init.
transfer
:-
If
[[Detached]]
internal slot istrue
, then throw aDataCloneError
DOMException
.
-
-
Let chunk be a new
EncodedAudioChunk
object, initialized as follows-
Assign
init.type
to[[type]]
. -
Assign
init.timestamp
to[[timestamp]]
. -
If
init.duration
exists, assign it to[[duration]]
, or assignnull
otherwise. -
Assign
init.data.byteLength
to[[byte length]]
; -
If init.
transfer
contains anArrayBuffer
referenced by init.data
the 用户代理 MAY choose to:-
Let resource be a new media resource referencing sample data in init.
data
.
-
-
Otherwise:
-
Assign a copy of init.
data
to[[internal data]]
.
-
-
-
For each transferable in init.
transfer
:-
Perform DetachArrayBuffer on transferable
-
-
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)
-
调用时,执行以下步骤:
-
如果此
[[byte length]]
的值大于 destination 中的空间,则抛出TypeError
。 -
将
[[internal data]]
复制到 destination。
-
8.1.5. 序列化
EncodedAudioChunk
序列化步骤(带 value,serialized,和 forStorage)如下:-
-
如果 forStorage 为
true
,抛出DataCloneError
。 -
对于 value 中每个
EncodedAudioChunk
内部插槽,将每个内部插槽的值赋值到 serialized 中与该内部插槽同名的字段。
-
EncodedAudioChunk
反序列化步骤(带 serialized 和 value)如下:-
-
对于 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 ; // microsecondsreadonly attribute unsigned long long ?duration ; // microsecondsreadonly attribute unsigned long byteLength ;undefined copyTo (AllowSharedBufferSource ); };
destination dictionary {
EncodedVideoChunkInit required EncodedVideoChunkType ; [
type EnforceRange ]required long long ; // microseconds [
timestamp EnforceRange ]unsigned long long ; // microseconds
duration required AllowSharedBufferSource ;
data sequence <ArrayBuffer >= []; };
transfer enum {
EncodedVideoChunkType ,
"key" , };
"delta"
8.2.1. 内部插槽
[[internal data]]
-
表示已编码块数据的字节数组。
[[type]]
[[timestamp]]
-
呈现时间戳,单位为微秒。
[[duration]]
-
呈现持续时间,单位为微秒。
[[byte length]]
-
[[internal data]]
的字节长度。
8.2.2. 构造函数
EncodedVideoChunk(init)
-
如果 init.
transfer
包含对同一个ArrayBuffer
多个引用,则抛出DataCloneError
DOMException
。 -
对于 init.
transfer
中的每个 transferable:-
如果
[[Detached]]
内部插槽为true
,则抛出DataCloneError
DOMException
。
-
-
令 chunk 为新建的
EncodedVideoChunk
对象,初始化如下:-
将
init.type
赋值给[[type]]
。 -
将
init.timestamp
赋值给[[timestamp]]
。 -
如果 init 中存在 duration,则将
init.duration
赋值给[[duration]]
。否则,将null
赋值给[[duration]]
。 -
将
init.data.byteLength
赋值给[[byte length]]
; -
如果 init.
transfer
包含 init.data
所引用的ArrayBuffer
,用户代理 MAY 可以选择:-
令 resource 为新建的 media resource,其引用 init.
data
中的样本数据。
-
-
否则:
-
将 init.
data
的副本赋值给[[internal data]]
。
-
-
-
对于 init.
transfer
中的每个 transferable:-
对 transferable 执行 DetachArrayBuffer
-
-
返回 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)
-
调用时,执行如下步骤:
-
如果
[[byte length]]
大于 destination 的[[byte length]]
,则抛出TypeError
。 -
将
[[internal data]]
复制到 destination。
-
8.2.5. 序列化
EncodedVideoChunk
序列化步骤(带 value,serialized,和 forStorage)如下:-
-
如果 forStorage 为
true
,抛出DataCloneError
。 -
对于 value 中每个
EncodedVideoChunk
内部插槽,将每个内部插槽的值赋值到 serialized 中与该内部插槽同名的字段。
-
EncodedVideoChunk
反序列化步骤(带 serialized 和 value)如下:-
-
对于 serialized 的所有命名字段,将每个字段的值赋值到 value 中与该字段同名的
EncodedVideoChunk
内部插槽。
-
注:由于 EncodedVideoChunk
是不可变的,用户代理可以选择使用类似 § 9.4.7 传递与序列化 的引用计数模型实现序列化。
9. 未编码媒体接口
这些接口表示未编码(原始)的媒体。9.1. 内存模型
9.1.1. 背景
本节为非规范性内容。
解码后的媒体数据可能占用大量系统内存。为了减少昂贵的拷贝需求,本规范定义了引用计数方案(clone()
和
close()
)。
注:建议作者在帧不再需要时立即调用 close()
。
9.1.2. 引用计数
media resource 是VideoFrame
或
AudioData
所描述的实际像素数据或音频样本数据的存储。
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. 传递与序列化
本节为非规范性内容。
AudioData
和
VideoFrame
均为
可传递对象
和
可序列化对象。它们的传递和
序列化步骤分别定义在 § 9.2.6 传递与序列化 和
§ 9.4.7 传递与序列化 中。
传递 AudioData
或
VideoFrame
会将其 [[resource reference]]
移动到目标对象,并关闭(如 close()
)源对象。作者可以利用此机制在不同 realm 之间移动 AudioData
或
VideoFrame
,而无需拷贝底层
media resource。
序列化 AudioData
或
VideoFrame
实际上是对源对象进行克隆(如
clone()
),会得到两个引用同一个
media
resource 的对象。作者可以利用此机制将 AudioData
或
VideoFrame
克隆到另一个 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 ; // microsecondsreadonly attribute long long timestamp ; // microsecondsunsigned 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 ; // microseconds
timestamp 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]]
[[number of channels]]
-
此
AudioData
的音频声道数。 [[timestamp]]
-
此
AudioData
的展示时间戳,单位为微秒。
9.2.2. 构造函数
AudioData(init)
-
如果 init 不是 有效的 AudioDataInit,则抛出
TypeError
。 -
如果 init.
transfer
包含对同一个ArrayBuffer
多个引用,则抛出DataCloneError
DOMException
。 -
对于 init.
transfer
中的每个 transferable:-
如果
[[Detached]]
内部插槽为true
,则抛出DataCloneError
DOMException
。
-
-
令 frame 为新建的
AudioData
对象,初始化如下:-
将
false
赋值给[[Detached]]
。 -
将 init.
format
赋值给[[format]]
。 -
将 init.
sampleRate
赋值给[[sample rate]]
。 -
将 init.
numberOfFrames
赋值给[[number of frames]]
。 -
将 init.
numberOfChannels
赋值给[[number of channels]]
。 -
将 init.
timestamp
赋值给[[timestamp]]
。 -
如果 init.
transfer
包含被 init.data
引用的ArrayBuffer
,用户代理 可以选择:-
令 resource 为新建的 media resource,引用 data 中的样本数据。
-
-
否则:
-
令 resource 为包含 init.
data
副本的 media resource。
-
-
令 resourceReference 为 resource 的引用。
-
将 resourceReference 赋值给
[[resource reference]]
。
-
-
对于 init.
transfer
中的每个 transferable:-
对 transferable 执行 DetachArrayBuffer
-
-
返回 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, 只读-
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 步骤如下:-
令 microsecondsPerSecond 为
1,000,000
。 -
令 durationInSeconds 为
[[number of frames]]
除以[[sample rate]]
的结果。 -
返回 durationInSeconds 与 microsecondsPerSecond 的乘积。
-
9.2.4. 方法
allocationSize(options)
-
返回保存 options 所描述样本所需的字节数。
调用时,执行以下步骤:
-
如果
[[Detached]]
为true
,抛出InvalidStateError
DOMException
。 -
令 copyElementCount 为用 options 运行 计算拷贝元素数量算法的结果。
-
令 destFormat 为
[[format]]
的值。 -
令 bytesPerSample 为 destFormat 定义的每个样本的字节数。
-
返回 bytesPerSample 与 copyElementCount 的乘积。
-
copyTo(destination, options)
-
将
AudioData
指定平面的样本复制到目标缓冲区。调用时,执行以下步骤:
-
如果
[[Detached]]
为true
,抛出InvalidStateError
DOMException
。 -
令 copyElementCount 为用 options 运行 计算拷贝元素数量算法的结果。
-
令 destFormat 为
[[format]]
的值。 -
令 bytesPerSample 为 destFormat 定义的每个样本的字节数。
-
如果 bytesPerSample 与 copyElementCount 的乘积大于
destination.byteLength
,则抛出RangeError
。 -
令 resource 为
[[resource reference]]
所引用的 media resource。 -
令 planeFrames 为 resource 中对应 options.
planeIndex
区域。 -
将 planeFrames 元素复制到 destination,从 options.
frameOffset
所定位的 帧开始,复制 copyElementCount 个样本后停止。如果 destFormat 不等于[[format]]
,则在复制时将元素转换为 destFormat 的AudioSampleFormat
。
-
clone()
-
创建一个新的 AudioData,其引用与原对象相同的 media resource。
调用时,执行以下步骤:
-
如果
[[Detached]]
为true
,抛出InvalidStateError
DOMException
。 -
返回用 克隆 AudioData 算法和 this 运行的结果。
-
close()
-
清除所有状态并释放对 media resource 的引用。关闭是不可逆的。
调用时,使用 关闭 AudioData 算法和 this 运行。
9.2.5. 算法
- 计算拷贝元素数量(带 options)
-
执行以下步骤:
-
令 destFormat 为
[[format]]
的值。 -
如果 destFormat 描述的是 交错
AudioSampleFormat
,且 options.planeIndex
大于0
,则抛出RangeError
。 -
否则,如果 destFormat 描述的是 分离
AudioSampleFormat
,且 options.planeIndex
大于等于[[number of channels]]
,则抛出RangeError
。 -
如果
[[format]]
不等于 destFormat 且用户代理不支持请求的AudioSampleFormat
转换,则抛出NotSupportedError
DOMException
。必须始终支持转换为f32-planar
。 -
令 frameCount 为由 options.
planeIndex
标识的平面中的帧数。 -
如果 options.
frameOffset
大于等于 frameCount,则抛出RangeError
。 -
令 copyFrameCount 为 frameCount 减去 options.
frameOffset
的结果。 -
如果 options.
frameCount
存在:-
如果 options.
frameCount
大于 copyFrameCount,则抛出RangeError
。 -
否则,将 options.
frameCount
赋值给 copyFrameCount。
-
-
令 elementCount 为 copyFrameCount。
-
如果 destFormat 描述的是 交错
AudioSampleFormat
,则将 elementCount 乘以[[number of channels]]
。 -
返回 elementCount。
-
- 克隆 AudioData(带 data)
-
执行以下步骤:
-
令 clone 为新建的
AudioData
,初始化如下:-
令 resource 为 data 的
[[resource reference]]
所引用的 media resource。 -
令 reference 为 resource 新的引用。
-
将 reference 赋值给
[[resource reference]]
。 -
将 data 的
[[Detached]]
、[[format]]
、[[sample rate]]
、[[number of frames]]
、[[number of channels]]
和[[timestamp]]
槽的值赋值到 clone 的对应槽。
-
-
返回 clone。
-
- 关闭 AudioData(带 data)
-
执行以下步骤:
-
将
true
赋值给 data 的[[Detached]]
内部插槽。 -
将
null
赋值给 data 的[[resource reference]]
。 -
将
0
赋值给 data 的[[sample rate]]
。 -
将
0
赋值给 data 的[[number of frames]]
。 -
将
0
赋值给 data 的[[number of channels]]
。 -
将
null
赋值给 data 的[[format]]
。
-
- 要检查
AudioDataInit
是否为 有效的 AudioDataInit,执行以下步骤: -
-
如果
sampleRate
小于或等于0
,返回false
。 -
如果
numberOfFrames
=0
,返回false
。 -
如果
numberOfChannels
=0
,返回false
。 -
通过以下步骤验证
data
的数据量是否足够:-
令 totalSamples 为
numberOfFrames
与numberOfChannels
的乘积。 -
令 bytesPerSample 为
format
定义的每个样本字节数。 -
令 totalSize 为 bytesPerSample 乘以 totalSamples 的结果。
-
令 dataSize 为
data
的字节大小。 -
如果 dataSize 小于 totalSize,返回 false。
-
-
返回
true
。
-
9.2.6. 传递与序列化
AudioData
传递步骤(带 value 和 dataHolder)如下:-
-
如果 value 的
[[Detached]]
为true
,抛出DataCloneError
DOMException
。 -
对于 value 中所有
AudioData
的内部插槽,将每个槽的值赋值到 dataHolder 中同名字段。 -
用 value 执行 关闭 AudioData 算法。
-
AudioData
传递接收步骤(带 dataHolder 和 value)如下:-
-
对于 dataHolder 中所有命名字段,将每个字段的值赋值到 value 中同名
AudioData
的内部插槽。
-
AudioData
序列化步骤(带 value、serialized 和 forStorage)如下:-
-
如果 value 的
[[Detached]]
为true
,抛出DataCloneError
DOMException
。 -
如果 forStorage 为
true
,抛出DataCloneError
。 -
令 resource 为 value 的
[[resource reference]]
所引用的 media resource。 -
令 newReference 为 resource 的新引用。
-
将 newReference 赋值给 |serialized.resource reference|。
-
对于 value 中除
[[resource reference]]
外的所有AudioData
内部插槽,将每个槽的值赋值到 serialized 的同名字段。
-
AudioData
反序列化步骤(带 serialized 和 value)如下:-
-
对于 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位浮点数)的数值类型,以及不同声道样本的排列方式,分为交错或分离。音频样本类型仅指用于存储数据的数值类型和间隔,即 u8
、
s16
、
s32
或 f32
,分别代表无符号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
s16
s32
f32
u8-planar
s16-planar
s32-planar
f32-planar
9.3.1. 音频缓冲区排列
当 AudioData
的
AudioSampleFormat
为 交错
时,不同声道的音频样本在同一个缓冲区中连续排列,顺序见 § 9.3.3 音频声道顺序。AudioData
只有一个平面,其元素数量等于 [[number of frames]]
*
[[number of channels]]
。
当 AudioData
的
AudioSampleFormat
为 分离 时,不同声道的音频样本在不同缓冲区中排列,顺序见
§ 9.3.3 音频声道顺序。AudioData
的平面数量等于
AudioData
的
[[number of channels]]
。每个平面包含
[[number of frames]]
个元素。
注:Web Audio API 目前只使用 f32-planar
。
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位样本时,应当将这些样本存放在 s32
或 f32
中。如果样本存放于 s32
,每个样本必须左移8位。这样,超出有效24位范围([-8388608, +8388607])的样本会被截断。为避免截断并保证无损传输,样本可以转换为 f32
。
注:由于存储类型限制,u8
、
s16
和 s32
样本不可避免会被削波(clipping),但实现应当在处理 f32
样本时避免削波。
9.3.3. 音频声道顺序
解码时,生成的 AudioData
中音频声道的顺序必须与 EncodedAudioChunk
中的保持一致。
编码时,生成的 EncodedAudioChunk
中音频声道的顺序必须与给定的 AudioData
中的保持一致。
换句话说,编码和解码时不会进行声道重排。
注:容器要么隐含要么指定了声道映射,即某个声道索引所对应的声道类型。
9.4. VideoFrame 接口
注:VideoFrame
是一个 CanvasImageSource
。
VideoFrame
可以传递给所有接受 CanvasImageSource
的方法,包括
CanvasDrawImage
的
drawImage()
。
[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 ; // microsecondsreadonly attribute long long timestamp ; // microsecondsreadonly 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 ; // microseconds
duration long long ; // microseconds
timestamp AlphaOption = "keep"; // 默认匹配图片。可用于高效裁剪。除非显式给出 displayWidth 和 displayHeight,否则会根据图片的像素纵横比重新计算 displayWidth 和 displayHeight。
alpha DOMRectInit ;
visibleRect double = 0;
rotation 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 ; // microseconds [
timestamp EnforceRange ]unsigned long long ; // microseconds // 默认布局是紧密排列。
duration sequence <PlaneLayout >; // 默认可见区域为编码尺寸,定位为 (0,0)
layout DOMRectInit ;
visibleRect double = 0;
rotation boolean =
flip false ; // 默认显示尺寸与 visibleRect 匹配。 [EnforceRange ]unsigned long ; [
displayWidth EnforceRange ]unsigned long ;
displayHeight VideoColorSpaceInit ;
colorSpace sequence <ArrayBuffer >= [];
transfer VideoFrameMetadata ; };
metadata dictionary { // 可能的成员记录在 VideoFrame Metadata Registry。 };
VideoFrameMetadata
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)
-
检查 image 参数可用性。如果抛出异常或返回 bad,则抛出
InvalidStateError
DOMException
。 -
如果 image 不是 origin-clean,则抛出
SecurityError
DOMException
。 -
令 frame 为新的
VideoFrame
。 -
根据 image 类型分支:
注:建议作者提供有意义的 timestamp,除非它已由
CanvasImageSource
在构造时隐式提供。消费VideoFrame
的接口可以依赖此值做时序决策。例如VideoEncoder
可用timestamp
指导速率控制(参见framerate
)。-
-
如果 image 的媒体数据没有 自然尺寸 (如为无内容尺寸的矢量图),则抛出
InvalidStateError
DOMException
。 -
令 resource 为新的 media resource,其内容为 image 的媒体数据副本。如果是动图,则 image 的 bitmap 数据 必须只取自动画的默认图片(格式定义在不支持或禁用动画时应使用的图片),如无则取动画的第一帧。
-
令 codedWidth 和 codedHeight 为 resource 的宽高。
-
令 baseRotation 和 baseFlip 描述 image 相对 resource 的旋转与翻转。
-
令 defaultDisplayWidth 和 defaultDisplayHeight 为 image 的 自然宽 和 自然高。
-
用 init、frame、resource、codedWidth、codedHeight、baseRotation、baseFlip、defaultDisplayWidth 和 defaultDisplayHeight 运行 帧初始化算法。
-
-
如果 image 的
networkState
属性为NETWORK_EMPTY
,则抛出InvalidStateError
DOMException
。 -
令 currentPlaybackFrame 为 当前播放位置的
VideoFrame
。 -
如果
metadata
不在 init 中存在,则赋值 currentPlaybackFrame.[[metadata]]
。 -
用 init、frame 和 currentPlaybackFrame 运行 帧从其他帧初始化算法。
-
-
-
用 init、frame 和 image 运行 帧从其他帧初始化算法。
-
-
返回 frame。
VideoFrame(data, init)
-
如果 init 不是有效的 VideoFrameBufferInit,则抛出
TypeError
。 -
令 defaultRect 为 «[ "x:" →
0
, "y" →0
, "width" → init.codedWidth
, "height" → init.codedWidth
]»。 -
令 overrideRect 为
undefined
。 -
如果 init.
visibleRect
存在,则将其值赋值给 overrideRect。 -
令 parsedRect 为用 defaultRect, overrideRect, init.
codedWidth
, init.codedHeight
, 和 init.format
运行 可见矩形解析算法的结果。 -
如果 parsedRect 是异常,则返回 parsedRect。
-
令 optLayout 为
undefined
。 -
令 combinedLayout 为用 parsedRect, init.
format
, 和 optLayout 运行 布局与分配大小计算算法的结果。 -
如果 combinedLayout 是异常,则抛出 combinedLayout。
-
如果
data.byteLength
小于 combinedLayout 的 allocationSize,则抛出TypeError
。 -
如果 init.
transfer
包含对同一个ArrayBuffer
的多个引用,则抛出DataCloneError
DOMException
。 -
对于 init.
transfer
中的每个 transferable:-
如果
[[Detached]]
内部插槽为true
,则抛出DataCloneError
DOMException
。
-
-
如果 init.
transfer
包含一个被 data 引用的ArrayBuffer
,用户代理可以选择:-
令 resource 为新建的 media resource,其引用 data 中的像素数据。
-
-
否则:
-
令 resource 为新建的 media resource,其内容为 data 的副本。用
visibleRect
和layout
判断每个 plane 的像素在 data 中的位置。用户代理可以选择分配更大的编码尺寸和 plane 步幅以优化内存对齐。编码尺寸变化会反映在
codedWidth
和codedHeight
上。此外,用户代理可以利用visibleRect
只复制可见矩形,并可以在 resource 内重新定位可见矩形。最终位置会反映在visibleRect
。
-
-
对于 init.
transfer
中的每个 transferable:-
对 transferable 执行 DetachArrayBuffer
-
-
令 resourceCodedWidth 为 resource 的编码宽度。
-
令 resourceCodedHeight 为 resource 的编码高度。
-
令 resourceVisibleLeft 为 resource 的可见矩形左偏移。
-
令 resourceVisibleTop 为 resource 的可见矩形上偏移。
本规范应当提供编码尺寸、可见矩形和显示尺寸的定义(及图示)。见 #166。
-
令 frame 为新建的
VideoFrame
对象,初始化如下:-
将 resourceCodedWidth、resourceCodedHeight、resourceVisibleLeft 和 resourceVisibleTop 分别赋值给
[[coded width]]
、[[coded height]]
、[[visible left]]
、[[visible top]]
。 -
如果 init.
visibleRect
存在:-
令 truncatedVisibleWidth 为
visibleRect
.width
截断后的值。 -
将 truncatedVisibleWidth 赋值给
[[visible width]]
。 -
令 truncatedVisibleHeight 为
visibleRect
.height
截断后的值。 -
将 truncatedVisibleHeight 赋值给
[[visible height]]
。
-
-
否则:
-
将
[[coded width]]
赋值给[[visible width]]
。
-
-
将用 init.
rotation
运行 旋转解析算法的结果赋值给[[rotation]]
。 -
如果
displayWidth
和displayHeight
存在于 init 中,则分别赋值给[[display width]]
和[[display height]]
。 -
否则:
-
如果
[[rotation]]
等于0
或180
: -
否则:
-
-
将 init 的
timestamp
和duration
分别赋值给[[timestamp]]
和[[duration]]
。 -
令 colorSpace 为
undefined
。 -
如果 init.
colorSpace
存在,则赋值给 colorSpace。 -
将 init 的
format
赋值给[[format]]
。 -
用 colorSpace 和
[[format]]
运行 色彩空间选择算法,并赋值给[[color space]]
。 -
用 init 的
metadata
调用 VideoFrame 元数据复制,并赋值给 frame.[[metadata]]
。
-
-
返回 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
,其width
和height
与codedWidth
和codedHeight
相同,x
和y
为(0,0)
。便于与allocationSize()
和copyTo()
一起使用。codedRect
的 getter 步骤为:-
如果
[[Detached]]
为true
,返回null
。 -
令 rect 为新建的
DOMRectReadOnly
,初始化如下:-
将
[[coded width]]
和[[coded height]]
分别赋值给width
和height
。
-
返回 rect。
-
visibleRect
, 类型为 DOMRectReadOnly,只读,可为 null-
一个
DOMRectReadOnly
,描述该VideoFrame
的可见像素矩形。visibleRect
的 getter 步骤为:-
如果
[[Detached]]
为true
,返回null
。 -
令 rect 为新建的
DOMRectReadOnly
,初始化如下:-
将
[[visible left]]
、[[visible top]]
、[[visible width]]
和[[visible height]]
分别赋值给x
、y
、width
和height
。
-
-
返回 rect。
-
rotation
, 类型为 double,只读-
渲染 VideoFrame 时应用的旋转角度,单位为顺时针度数。旋转在翻转之前应用。
rotation
的 getter 步骤为返回[[rotation]]
。 flip
, 类型为 boolean,只读-
渲染
VideoFrame
时是否应用水平翻转。翻转在旋转之后应用。 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 是一个 结构体,包含:-
allocationSize(一个
unsigned long
) -
computedLayouts(一个 列表,元素为 computed plane layout 结构体)。
computed plane layout 是一个 结构体,包含:
-
destinationOffset(一个
unsigned long
) -
destinationStride(一个
unsigned long
) -
sourceTop(一个
unsigned long
) -
sourceHeight(一个
unsigned long
) -
sourceLeftBytes(一个
unsigned long
) -
sourceWidthBytes(一个
unsigned long
)
9.4.5. 方法
allocationSize(options)
-
返回用于
BufferSource
的最小有效字节长度,可与指定 options 一起用于copyTo()
。调用时,执行以下步骤:
-
如果
[[Detached]]
为true
,抛出InvalidStateError
DOMException
。 -
如果
[[format]]
为null
,抛出NotSupportedError
DOMException
。 -
用 options 运行 VideoFrameCopyToOptions 解析算法,令结果为 combinedLayout。
-
如果 combinedLayout 是异常,则抛出 combinedLayout。
-
返回 combinedLayout 的 allocationSize。
-
copyTo(destination, options)
-
异步将当前帧的 plane 按 options 复制到 destination。数据格式为 options.
format
(如果存在),否则为 thisVideoFrame
的format
。注:多次调用
copyTo()
返回的 Promise 不保证按调用顺序 resolve。调用时,执行以下步骤:
-
如果
[[Detached]]
为true
,返回一个被拒绝的 promise,错误为InvalidStateError
DOMException
。 -
如果
[[format]]
为null
,返回一个被拒绝的 promise,错误为NotSupportedError
DOMException
。 -
用 options 运行 VideoFrameCopyToOptions 解析算法,令结果为 combinedLayout。
-
如果 combinedLayout 是异常,则返回一个被拒绝的 promise,错误为 combinedLayout。
-
如果
destination.byteLength
小于 combinedLayout 的 allocationSize,则返回一个被拒绝的 promise,错误为TypeError
。 -
令 p 为新建的
Promise
。 -
令 copyStepsQueue 为新建的 并行队列。
-
令 planeLayouts 为新建的 列表。
-
将以下步骤入队到 copyStepsQueue:
-
令 resource 为
[[resource reference]]
所引用的 media resource。 -
令 numPlanes 为
[[format]]
定义的 plane 数量。 -
令 planeIndex 为
0
。 -
当 planeIndex 小于 combinedLayout 的 numPlanes 时:
-
令 sourceStride 为 resource 中由 planeIndex 标识的 plane 步幅。
-
令 computedLayout 为 combinedLayout 的 computedLayouts 列表中第 planeIndex 个元素。
-
令 sourceOffset 为 computedLayout 的 sourceTop 乘以 sourceStride 的结果。
-
将 computedLayout 的 sourceLeftBytes 加到 sourceOffset 上。
-
令 destinationOffset 为 computedLayout 的 destinationOffset。
-
令 rowBytes 为 computedLayout 的 sourceWidthBytes。
-
令 layout 为新建的
PlaneLayout
,其中offset
设为 destinationOffset,stride
设为 rowBytes。 -
令 row 为
0
。 -
当 row 小于 computedLayout 的 sourceHeight 时:
-
将 resource 从 sourceOffset 起的 rowBytes 字节复制到 destination 的 destinationOffset 起。
-
令 sourceOffset 加上 sourceStride。
-
令 destinationOffset 加上 computedLayout 的 destinationStride。
-
令 row 加
1
。
-
-
令 planeIndex 加
1
。 -
将 layout 添加到 planeLayouts。
-
-
队列任务,用 planeLayouts resolve p。
-
-
返回 p。
-
clone()
-
创建一个新的
VideoFrame
,其引用与原 media resource 相同。调用时,执行以下步骤:
-
如果 frame 的
[[Detached]]
内部插槽值为true
,抛出InvalidStateError
DOMException
。 -
用 VideoFrame 克隆算法和 this 运行,并返回结果。
-
close()
-
清除所有状态,并释放对 media resource 的引用。 关闭操作是最终的。
调用时,使用 关闭 VideoFrame 算法和 this 执行。
metadata()
-
获取与该帧关联的
VideoFrameMetadata
。调用时,执行以下步骤:
-
如果
[[Detached]]
为true
, 抛出InvalidStateError
DOMException
。 -
返回用
[[metadata]]
调用 VideoFrame 元数据复制 的结果。
-
9.4.6. 算法
- 创建 VideoFrame(带 output, timestamp, duration, displayAspectWidth, displayAspectHeight, colorSpace, rotation, 和 flip)
-
-
令 frame 为新的
VideoFrame
,初始化如下:-
将
false
赋值给[[Detached]]
。 -
令 resource 为 output 所描述的 media resource。
-
令 resourceReference 为 resource 的引用。
-
将 resourceReference 赋值给
[[resource reference]]
。 -
如果 output 使用已知的
VideoPixelFormat
,则将该格式赋值给[[format]]
;否则将null
赋值给[[format]]
。 -
令 codedWidth 和 codedHeight 为 output 的编码宽高(像素)。
-
令 visibleLeft、visibleTop、visibleWidth、visibleHeight 为 output 可见矩形的左、上、宽、高。
-
令 displayWidth 和 displayHeight 为 output 的显示尺寸(像素)。
-
如果提供了 displayAspectWidth 和 displayAspectHeight,则增大 displayWidth 或 displayHeight,直到其比例与 displayAspectWidth : displayAspectHeight 一致。
-
将 codedWidth、codedHeight、visibleLeft、 visibleTop、 visibleWidth、visibleHeight、displayWidth 和 displayHeight 分别赋值为
[[coded width]]
、[[coded height]]
、[[visible left]]
、[[visible top]]
、[[visible width]]
、 以及[[visible height]]
。 -
将 duration 和 timestamp 分别赋值给
[[duration]]
和[[timestamp]]
。 -
用 colorSpace 和
[[format]]
运行 色彩空间选择算法,并赋值给[[color space]]
。
-
-
返回 frame。
-
- 色彩空间选择(带 overrideColorSpace 和 format)
-
-
如果提供了 overrideColorSpace,则返回用 overrideColorSpace 构造的新
VideoColorSpace
。用户代理可以用实现者自定义的启发式方法替换 overrideColorSpace 中的
null
成员。 -
否则,如果
[[format]]
为 RGB 格式,则返回新的 sRGB 色彩空间实例。 -
否则,返回新的 REC709 色彩空间实例。
-
- 校验 VideoFrameInit(带 format, codedWidth, codedHeight)
-
-
如果
visibleRect
存在:-
用 format 和 visibleRect 运行 矩形偏移对齐校验,结果为 validAlignment。
-
如果 validAlignment 为
false
,返回false
。 -
如果
visibleRect
的任意属性为负或非有限值,返回false
。 -
如果
visibleRect
.width
==0
或visibleRect
.height
==0
,返回false
。 -
如果
visibleRect
.y
+visibleRect
.height
> codedHeight,返回false
。 -
如果
visibleRect
.x
+visibleRect
.width
> codedWidth,返回false
。
-
-
如果 codedWidth = 0 或 codedHeight = 0,返回
false
。 -
如果
displayWidth
和displayHeight
只有一个 存在,返回false
。 -
如果
displayWidth
==0
或displayHeight
==0
,返回false
。 -
返回
true
。
-
- 要检查
VideoFrameBufferInit
是否为 有效的 VideoFrameBufferInit,执行以下步骤: -
-
如果
codedWidth
= 0 或codedHeight
= 0,返回false
。 -
如果
visibleRect
的任意属性为负或非有限值,返回false
。 -
如果
visibleRect
.y
+visibleRect
.height
>codedHeight
,返回false
。 -
如果
visibleRect
.x
+visibleRect
.width
>codedWidth
,返回false
。 -
如果
displayWidth
和displayHeight
只有一个 存在,返回false
。 -
如果
displayWidth
= 0 或displayHeight
= 0,返回false
。 -
返回
true
。
-
- 从其他帧初始化 VideoFrame(带 init, frame, otherFrame)
-
-
令 format 为 otherFrame.
format
。 -
如果 init.
alpha
为discard
, 则将 otherFrame.format
的 等效不透明格式 赋值给 format。 -
令 validInit 为用 format、otherFrame 的
[[coded width]]
和[[coded height]]
运行 校验 VideoFrameInit 算法的结果。 -
如果 validInit 为
false
,则抛出TypeError
。 -
令 resource 为 otherFrame 的
[[resource reference]]
所引用的 media resource。 -
为 resource 生成新引用,赋值给 frame 的
[[resource reference]]
。 -
将 otherFrame 的以下属性赋值给 frame:
codedWidth
、codedHeight
、colorSpace
。 -
令 defaultVisibleRect 为对 otherFrame 执行
visibleRect
的 getter 步骤的结果。 -
令 baseRotation 和 baseFlip 分别为 otherFrame 的
[[rotation]]
和[[flip]]
。 -
令 defaultDisplayWidth 和 defaultDisplayHeight 分别为 otherFrame 的
[[display width]]
和[[display height]]
。 -
用 init、frame、defaultVisibleRect、baseRotation、baseFlip、defaultDisplayWidth、defaultDisplayHeight 运行 可见矩形、方向与显示尺寸初始化算法。
-
如果
duration
在 init 中存在,则赋值给 frame 的[[duration]]
; 否则,将 otherFrame.duration
赋值给 frame 的[[duration]]
。 -
如果
timestamp
在 init 中存在,则赋值给 frame 的[[timestamp]]
; 否则,将 otherFrame 的timestamp
赋值给 frame 的[[timestamp]]
。 -
将 format 赋值给 frame.
[[format]]
。 -
用 init 的
metadata
调用 VideoFrame 元数据复制,赋值给 frame.[[metadata]]
。
-
- 用资源初始化帧(带 init, frame, resource, codedWidth, codedHeight, baseRotation, baseFlip, defaultDisplayWidth, defaultDisplayHeight)
-
-
令 format 为
null
。 -
如果 resource 使用已知的
VideoPixelFormat
, 将 resource 的VideoPixelFormat
赋值给 format。 -
令 validInit 为用 format、width 和 height 运行 校验 VideoFrameInit 算法的结果。
-
如果 validInit 为
false
,则抛出TypeError
。 -
为 resource 生成新引用,赋值给 frame 的
[[resource reference]]
。 -
将 format 赋值给
[[format]]
-
将 codedWidth 和 codedHeight 分别赋值给 frame 的
[[coded width]]
和[[coded height]]
。 -
令 defaultVisibleRect 为用 «[ "x:" →
0
, "y" →0
, "width" → codedWidth, "height" → codedHeight ]» 构造的新DOMRect
。 -
用 init、frame、defaultVisibleRect、defaultDisplayWidth、defaultDisplayHeight 运行 可见矩形、方向与显示尺寸初始化算法。
-
将
init
.duration
赋值给 frame 的[[duration]]
。 -
将
init
.timestamp
赋值给 frame 的[[timestamp]]
。 -
如果 resource 有已知的
VideoColorSpace
, 将其赋值给[[color space]]
。 -
否则,创建一个新的用空
VideoColorSpaceInit
构造的VideoColorSpace
,赋值给[[color space]]
。
-
- 初始化可见矩形、方向与显示尺寸 (参数:init, frame, defaultVisibleRect, baseRotation, baseFlip, defaultDisplayWidth, defaultDisplayHeight)
-
-
令 visibleRect = defaultVisibleRect。
-
如果 init.
visibleRect
存在,则赋值给 visibleRect。 -
将 visibleRect 的
x
、y
、width
、height
分别赋值给 frame 的[[visible left]]
、[[visible top]]
、[[visible width]]
、[[visible height]]
。 -
用 baseRotation、baseFlip、rotation 执行 旋转叠加算法,将其结果赋值给 frame 的
[[rotation]]
。 -
如果 baseFlip 等于 init.
flip
,则将false
赋值给 frame 的[[flip]]
;否则赋值true
给 frame 的[[flip]]
。 -
如果 init 中
displayWidth
和displayHeight
存在,则分别赋值给[[display width]]
和[[display height]]
。 -
否则:
-
如果 baseRotation 等于
0
或180
: -
否则:
-
令 displayWidth 为
|frame| 的 {{VideoFrame/[[visible width]]}} * |widthScale|
,四舍五入为最近的整数。 -
令 displayHeight 为
|frame| 的 {{VideoFrame/[[visible height]]}} * |heightScale|
,四舍五入为最近的整数。 -
如果 rotation 等于
0
或180
:-
将 displayWidth 赋值给 frame 的
[[display width]]
。 -
将 displayHeight 赋值给 frame 的
[[display height]]
。
-
-
否则:
-
将 displayHeight 赋值给 frame 的
[[display width]]
。 -
将 displayWidth 赋值给 frame 的
[[display height]]
。
-
-
-
- 克隆 VideoFrame(参数:frame)
-
-
令 clone 为新建的
VideoFrame
,初始化如下:-
令 resource 为 frame 的
[[resource reference]]
所引用的 media resource。 -
令 newReference 为 resource 的新引用。
-
将 newReference 赋值给 clone 的
[[resource reference]]
。 -
将 frame 的剩余所有内部插槽(除
[[resource reference]]
外)赋值给 clone 的同名槽。
-
-
返回 clone。
-
- 关闭 VideoFrame(参数:frame)
-
-
将
null
赋值给 frame 的[[resource reference]]
。 -
将
true
赋值给 frame 的[[Detached]]
。 -
将
null
赋值给 frame 的format
。 -
将
0
赋值给 frame 的[[coded width]]
、[[coded height]]
、[[visible left]]
、[[visible top]]
、[[visible width]]
、[[visible height]]
、[[rotation]]
、[[display width]]
和[[display height]]
。 -
将
false
赋值给 frame 的[[flip]]
。 -
创建一个新的
VideoFrameMetadata
,赋值给 frame.[[metadata]]
。
-
- 解析旋转(参数 rotation)
-
-
令 alignedRotation 为最接近
90
的倍数,四舍五入取正无穷的 rotation。 -
令 fullTurns 为小于等于 alignedRotation 的最大
360
的倍数。 -
返回
|alignedRotation| - |fullTurns|
。
-
- 旋转叠加(参数 baseRotation, baseFlip, rotation)
-
-
如果 baseFlip 为
false
,令 combinedRotation =|baseRotation| + |rotation|
;否则令 combinedRotation =|baseRotation| - |rotation|
。 -
令 fullTurns 为小于等于 combinedRotation 的最大
360
的倍数。 -
返回
|combinedRotation| - |fullTurns|
。
-
- 解析 VideoFrameCopyToOptions(参数 options)
-
-
令 defaultRect 为执行
visibleRect
的 getter 步骤所得结果。 -
令 overrideRect 为
undefined
。 -
令 parsedRect 为用 defaultRect、overrideRect、
[[coded width]]
、[[coded height]]
和[[format]]
运行 解析可见矩形算法的结果。 -
如果 parsedRect 是异常,返回 parsedRect。
-
令 optLayout 为
undefined
。 -
令 format 为
undefined
。 -
如果 options.
format
不存在,则将[[format]]
赋值给 format。 -
否则,如果 options.
format
等于RGBA
、RGBX
、BGRA
、BGRX
之一,则将 options.format
赋值给 format;否则返回NotSupportedError
。 -
令 combinedLayout 为用 parsedRect、format 和 optLayout 运行 布局与分配大小计算算法的结果。
-
返回 combinedLayout。
-
- 校验矩形偏移对齐(参数 format, rect)
-
-
如果 format 为
null
,返回true
。 -
令 planeIndex =
0
。 -
令 numPlanes 为 format 定义的 plane 数量。
-
当 planeIndex 小于 numPlanes 时:
-
返回
true
。
-
- 解析可见矩形(参数 defaultRect, overrideRect, codedWidth, codedHeight, format)
- 布局与分配大小计算(参数 parsedRect, format, layout)
-
-
令 numPlanes 为 format 定义的 plane 数量。
-
如果 layout 不为
undefined
且其长度不等于 numPlanes,则抛出TypeError
。 -
令 minAllocationSize =
0
。 -
令 computedLayouts 为新建的 列表。
-
令 endOffsets 为新建的 列表。
-
令 planeIndex =
0
。 -
当 planeIndex < numPlanes 时:
-
令 plane 为 format 定义的由 planeIndex 标识的 Plane。
-
令 sampleBytes 为 plane 的每个样本字节数。
-
令 sampleWidth 为 plane 每个子采样的水平子采样因子。
-
令 sampleHeight 为 plane 每个子采样的垂直子采样因子。
-
令 computedLayout 为新建的 computed plane layout。
-
将截断后的 parsedRect.
y
除以 sampleHeight,向上取整赋值给 computedLayout 的 sourceTop。 -
将截断后的 parsedRect.
height
除以 sampleHeight,向上取整赋值给 computedLayout 的 sourceHeight。 -
将截断后的 parsedRect.
x
整除 sampleWidth 后乘以 sampleBytes赋值给 computedLayout 的 sourceLeftBytes。 -
将截断后的 parsedRect.
width
整除 sampleWidth 后乘以 sampleBytes赋值给 computedLayout 的 sourceWidthBytes。 -
如果 layout 不为
undefined
:-
令 planeLayout 为 layout 中第 planeIndex 项的
PlaneLayout
。 -
如果 planeLayout.
stride
小于 computedLayout 的 sourceWidthBytes,返回TypeError
。 -
将 planeLayout.
offset
赋值给 computedLayout 的 destinationOffset。 -
将 planeLayout.
stride
赋值给 computedLayout 的 destinationStride。
-
-
否则:
注:未提供显式布局时,以下步骤默认紧密打包。
-
将 minAllocationSize 赋值给 computedLayout 的 destinationOffset。
-
将 computedLayout 的 sourceWidthBytes 赋值给 computedLayout 的 destinationStride。
-
-
令 planeSize 为 computedLayout 的 destinationStride 与 sourceHeight 的乘积。
-
令 planeEnd 为 planeSize 与 computedLayout 的 destinationOffset 之和。
-
如果 planeSize 或 planeEnd 大于
unsigned long
的最大范围,返回TypeError
。 -
将 planeEnd 添加到 endOffsets。
-
将 minAllocationSize 与 planeEnd 的最大值赋值给 minAllocationSize。
注:上一步用 max 是为了允许用户指定的 plane offset 重新排序 plane。
-
令 earlierPlaneIndex =
0
。 -
当 earlierPlaneIndex 小于 planeIndex 时:
-
令 earlierLayout =
computedLayouts[earlierPlaneIndex]
。 -
如果
endOffsets[planeIndex]
小于等于 earlierLayout 的 destinationOffset,或endOffsets[earlierPlaneIndex]
小于等于 computedLayout 的 destinationOffset,则 continue。注:如果 plane A 结束早于 plane B 起始,两者不重叠。
-
否则返回
TypeError
。 -
earlierPlaneIndex 加
1
。
-
-
将 computedLayout 添加到 computedLayouts。
-
planeIndex 加
1
。
-
-
令 combinedLayout 为新建的 combined buffer layout,初始化如下:
-
将 computedLayouts 赋值给 computedLayouts。
-
将 minAllocationSize 赋值给 allocationSize。
-
-
返回 combinedLayout。
-
- 预定义色彩空间转 VideoColorSpace(参数 colorSpace)
-
-
断言:colorSpace 等于
srgb
或display-p3
。 -
如果 colorSpace 等于
display-p3
,返回新的 Display P3 色彩空间实例。
-
- 转为RGB帧(参数 frame, format, colorSpace)
-
-
令 convertedFrame 为新建的
VideoFrame
,初始化如下:-
将
false
赋值给[[Detached]]
。 -
将 format 赋值给
[[format]]
。 -
令 width = frame 的
[[visible width]]
。 -
令 height = frame 的
[[visible height]]
。 -
将 width、height、0、0、width、height、width、height 分别赋值给
[[coded width]]
、[[coded height]]
、[[visible left]]
、[[visible top]]
、[[visible width]]
、[[visible height]]
。 -
将 frame 的
[[duration]]
和[[timestamp]]
分别赋值给[[duration]]
和[[timestamp]]
。 -
用 colorSpace 运行 预定义色彩空间转 VideoColorSpace 算法,并赋值给
[[color space]]
。 -
令 resource 为新建的 media resource,内容为 frame 的
[[resource reference]]
所引用的 media resource 按[[color space]]
和[[format]]
转换后的结果。 -
将 resource 的引用赋值给
[[resource reference]]
。
-
-
返回 convertedFrame。
- VideoFrame 元数据复制(参数 metadata)
-
-
令 metadataCopySerialized 为 StructuredSerialize(metadata)。
-
令 metadataCopy 为 StructuredDeserialize(metadataCopySerialized, 当前 Realm)。
-
返回 metadataCopy。
-
该算法的目标是确保 VideoFrame
所拥有的元数据是不可变的。
9.4.7. 传输与序列化
VideoFrame
传输步骤(带 value 和 dataHolder) 如下:-
-
如果 value 的
[[Detached]]
为true
,则抛出DataCloneError
DOMException
。 -
对于 value 中所有
VideoFrame
内部插槽,将每个内部插槽的值赋给 dataHolder 中同名字段。 -
使用 value 运行 关闭 VideoFrame 算法。
-
VideoFrame
传输接收步骤(带 dataHolder 和 value)如下:-
-
对于 dataHolder 中所有命名字段,将每个字段的值赋给 value 中同名的
VideoFrame
内部插槽。
-
VideoFrame
序列化步骤(带 value、 serialized 和 forStorage)如下:-
-
如果 value 的
[[Detached]]
为true
,则抛出DataCloneError
DOMException
。 -
如果 forStorage 为
true
,则抛出DataCloneError
。 -
令 resource 为 value 的
[[resource reference]]
所引用的 媒体资源。 -
令 newReference 为 resource 的新引用。
-
将 newReference 赋值给 |serialized.resource reference|。
-
对于 value 中所有剩余
VideoFrame
内部插槽(不包括[[resource reference]]
), 将每个内部插槽的值赋给 serialized 中同名字段。
-
VideoFrame
反序列化步骤(带 serialized 和 value) 如下:-
-
对于 serialized 中所有命名字段,将每个字段的值赋给 value 中同名的
VideoFrame
内部插槽。
-
9.4.8. 渲染
被渲染时,例如通过 CanvasDrawImage
drawImage()
,
VideoFrame
必须
被转换为与渲染目标兼容的色彩空间,除非明确禁用色彩转换。
ImageBitmap
构建过程中的色彩空间转换由
ImageBitmapOptions
的
colorSpaceConversion
控制。
设置为 "none"
时会禁用色彩空间转换。
VideoFrame
的渲染通过 媒体资源 生成,
并应用必要的色彩空间转换、裁剪到
visibleRect
,
顺时针旋转 rotation
度,并在 flip
为 true
时进行水平翻转。
9.5. VideoFrame CopyTo() 选项
用于指定要复制的像素矩形、它们的格式,以及目标缓冲区中各平面的偏移和步幅的选项。dictionary {
VideoFrameCopyToOptions DOMRectInit rect ;sequence <PlaneLayout >layout ;VideoPixelFormat format ;PredefinedColorSpace colorSpace ; };
copyTo()
或 allocationSize()
的步骤将强制执行以下要求:
-
rect
的坐标必须与[[format]]
所确定的采样对齐。 -
如果
layout
存在,则所有平面都需提供PlaneLayout
。
rect
, 类型为 DOMRectInit-
一个
DOMRectInit
描述要从VideoFrame
复制的像素矩形。 如果未指定,则使用visibleRect
。注意:可以通过传递
VideoFrame
的codedRect
来指定编码矩形。注意:默认的
rect
不一定满足采样对齐要求,可能导致copyTo()
或allocationSize()
被拒绝。 layout
, 类型为 sequence<PlaneLayout>-
每个平面的
PlaneLayout
, 可选地为目标BufferSource
中的每个平面指定偏移和步幅。 如果未指定,各平面将紧密排列。指定重叠平面是无效的。 format
, 类型为 VideoPixelFormat-
目标
BufferSource
中像素数据的VideoPixelFormat
。 可选值包括:RGBA
、RGBX
、BGRA
、BGRX
。 如果未存在,目标BufferSource
与format
格式相同。 colorSpace
, 类型为 PredefinedColorSpace-
一个
PredefinedColorSpace
,它必须作为目标像素数据的色彩空间用于目标BufferSource
, 但仅当format
为RGBA
、RGBX
、BGRA
、BGRX
之一,否则将被忽略。 如果未存在,则使用srgb
。
9.6. VideoFrame中的DOMRect
VideoFrame
接口使用 DOMRect
来指定像素矩形的位置和尺寸。
DOMRectInit
与 copyTo()
及 allocationSize()
搭配使用,用于描述源矩形的尺寸。
VideoFrame
定义了 codedRect
和 visibleRect
以便分别方便地复制编码尺寸和可见区域。
注意:VideoFrame的像素只能用整数寻址。所有传递给 DOMRectInit
的浮点值都将被截断。
9.7. 平面布局
PlaneLayout
是一个字典,用于指定 VideoFrame
某个平面在被复制到 BufferSource
后的偏移和步幅。
一组 PlaneLayout
可以被传递给 VideoFrame
的
copyTo()
,
用于指定平面在目标 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 { // 4:2:0 Y, U, V
VideoPixelFormat "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-sampled,factor 为 2。
该格式中每个样本为 8 位。
Y 平面有
codedWidth
*codedHeight
个样本(因此也是字节),从图像左上角开始按codedHeight
行,每行codedWidth
个样本排列。U 和 V 平面的行数等于将
codedHeight
除以 2 后向上取整的结果。每行的样本数等于将codedWidth
除以 2 后向上取整的结果。样本从图像左上角开始排列。可见矩形的偏移(
visibleRect
.x
和visibleRect
.y
) 必须为偶数。 I420P10
-
该格式由三个不同的平面组成:一个亮度平面和两个色度平面,分别记为 Y、U 和 V,按此顺序存在。
与 Y 平面相比,U 和 V 平面在水平方向和垂直方向上都按 sub-sampled,factor 为 2。
该格式中每个样本为 10 位,按小端字节序编码为 16 位整数。
Y 平面有
codedWidth
*codedHeight
个样本,从图像左上角开始按codedHeight
行,每行codedWidth
个样本排列。U 和 V 平面的行数等于将
codedHeight
除以 2 后向上取整的结果。每行的样本数等于将codedWidth
除以 2 后向上取整的结果。样本从图像左上角开始排列。可见矩形的偏移(
visibleRect
.x
和visibleRect
.y
) 必须为偶数。 I420P12
-
该格式由三个不同的平面组成:一个亮度平面和两个色度平面,分别记为 Y、U 和 V,按此顺序存在。
与 Y 平面相比,U 和 V 平面在水平方向和垂直方向上都按 sub-sampled,factor 为 2。
该格式中每个样本为 12 位,按小端字节序编码为 16 位整数。
Y 平面有
codedWidth
*codedHeight
个样本,从图像左上角开始按codedHeight
行,每行codedWidth
个样本排列。U 和 V 平面的行数等于将
codedHeight
除以 2 后向上取整的结果。每行的样本数等于将codedWidth
除以 2 后向上取整的结果。样本从图像左上角开始排列。可见矩形的偏移(
visibleRect
.x
和visibleRect
.y
) 必须为偶数。 I420A
-
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。它通常也称为带 alpha 通道的 Planar YUV 4:2:0。
与 Y 和 Alpha 平面相比,U 和 V 平面在水平方向和垂直方向上都按 sub-sampled,factor 为 2。
该格式中每个样本为 8 位。
Y 和 Alpha 平面有
codedWidth
*codedHeight
个样本(因此也是字节),从图像左上角开始按codedHeight
行,每行codedWidth
个样本排列。U 和 V 平面的行数等于将
codedHeight
除以 2 后向上取整的结果。每行的样本数等于将codedWidth
除以 2 后向上取整的结果。样本从图像左上角开始排列。可见矩形的偏移(
visibleRect
.x
和visibleRect
.y
) 必须为偶数。 I420AP10
-
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。
与 Y 和 Alpha 平面相比,U 和 V 平面在水平方向和垂直方向上都按 sub-sampled,factor 为 2。
该格式中每个样本为 10 位,按小端字节序编码为 16 位整数。
Y 和 Alpha 平面有
codedWidth
*codedHeight
个样本,从图像左上角开始按codedHeight
行,每行codedWidth
个样本排列。U 和 V 平面的行数等于将
codedHeight
除以 2 后向上取整的结果。每行的样本数等于将codedWidth
除以 2 后向上取整的结果。样本从图像左上角开始排列。可见矩形的偏移(
visibleRect
.x
和visibleRect
.y
) 必须为偶数。 I420AP12
-
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。
与 Y 和 Alpha 平面相比,U 和 V 平面在水平方向和垂直方向上都按 sub-sampled,factor 为 2。
该格式中每个样本为 12 位,按小端字节序编码为 16 位整数。
Y 和 Alpha 平面有
codedWidth
*codedHeight
个样本,从图像左上角开始按codedHeight
行,每行codedWidth
个样本排列。U 和 V 平面的行数等于将
codedHeight
除以 2 后向上取整的结果。每行的样本数等于将codedWidth
除以 2 后向上取整的结果。样本从图像左上角开始排列。可见矩形的偏移(
visibleRect
.x
和visibleRect
.y
) 必须为偶数。 I422
-
该格式由三个不同的平面组成:一个亮度平面和两个色度平面,分别记为 Y、U 和 V,按此顺序存在。它通常也称为 Planar YUV 4:2:2。
与 Y 平面相比,U 和 V 平面在水平方向上按 sub-sampled,factor 为 2, 在垂直方向上不进行 sub-sampled。
该格式中每个样本为 8 位。
Y 平面有
codedWidth
*codedHeight
个样本(因此也是字节),从图像左上角开始按codedHeight
行,每行codedWidth
个样本排列。U 和 V 平面有
codedHeight
行。每行的样本数等于将codedWidth
除以 2 后向上取整的结果。样本从图像左上角开始排列。可见矩形的水平偏移(
visibleRect
.x
) 必须为偶数。 I422P10
-
该格式由三个不同的平面组成:一个亮度平面和两个色度平面,分别记为 Y、U 和 V,按此顺序存在。
与 Y 平面相比,U 和 V 平面在水平方向上按 sub-sampled,factor 为 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-sampled,factor 为 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-sampled,factor 为 2, 在垂直方向上不进行 sub-sampled。
该格式中每个样本为 8 位。
Y 和 Alpha 平面有
codedWidth
*codedHeight
个样本(因此也是字节),从图像左上角开始按codedHeight
行,每行codedWidth
个样本排列。U 和 V 平面有
codedHeight
行。每行的样本数等于将codedWidth
除以 2 后向上取整的结果。样本从图像左上角开始排列。可见矩形的水平偏移(
visibleRect
.x
) 必须为偶数。 I422AP10
-
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。
与 Y 和 Alpha 平面相比,U 和 V 平面在水平方向上按 sub-sampled,factor 为 2, 在垂直方向上不进行 sub-sampled。
该格式中每个样本为 10 位,按小端字节序编码为 16 位整数。
Y 和 Alpha 平面有
codedWidth
*codedHeight
个样本,从图像左上角开始按codedHeight
行,每行codedWidth
个样本排列。U 和 V 平面有
codedHeight
行。每行的样本数等于将codedWidth
除以 2 后向上取整的结果。样本从图像左上角开始排列。可见矩形的水平偏移(
visibleRect
.x
) 必须为偶数。 I422AP12
-
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。
与 Y 和 Alpha 平面相比,U 和 V 平面在水平方向上按 sub-sampled,factor 为 2, 在垂直方向上不进行 sub-sampled。
该格式中每个样本为 12 位,按小端字节序编码为 16 位整数。
Y 和 Alpha 平面有
codedWidth
*codedHeight
个样本,从图像左上角开始按codedHeight
行,每行codedWidth
个样本排列。U 和 V 平面有
codedHeight
行。每行的样本数等于将codedWidth
除以 2 后向上取整的结果。样本从图像左上角开始排列。可见矩形的水平偏移(
visibleRect
.x
) 必须为偶数。 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
个样本排列。 I444AP10
-
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。
该格式不使用 sub-sampling。
该格式中每个样本为 10 位,按小端字节序编码为 16 位整数。
四个平面中均有
codedWidth
*codedHeight
个样本,从图像左上角开始按codedHeight
行,每行codedWidth
个样本排列。 I444AP12
-
该格式由四个不同的平面组成:一个亮度平面、两个色度平面(Y、U、V)以及一个 Alpha 平面,按此顺序存在。
该格式不使用 sub-sampling。
该格式中每个样本为 12 位,按小端字节序编码为 16 位整数。
四个平面中均有
codedWidth
*codedHeight
个样本,从图像左上角开始按codedHeight
行,每行codedWidth
个样本排列。 NV12
-
该格式由两个不同的平面组成:先是一个亮度平面,然后是包含两个色度分量的另一个平面。两个平面按此顺序存在,分别称为 Y 平面和 UV 平面。
与 Y 平面中的分量相比,U 和 V 分量在水平方向和垂直方向上都按 sub-sampled,factor 为 2。
该格式中每个样本为 8 位。
Y 平面有
codedWidth
*codedHeight
个样本(因此也是字节),从图像左上角开始按codedHeight
行,每行codedWidth
个样本排列。UV 平面由交错的 U 和 V 值组成,其行数等于将
codedHeight
除以 2 后向上取整的结果。每行的元素数等于将codedWidth
除以 2 后向上取整的结果。每个元素由两个色度样本(U 和 V,按此顺序)组成。样本从图像左上角开始排列。可见矩形的偏移(
visibleRect
.x
和visibleRect
.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
个样本排列。 RGBX
-
该格式由单个平面组成,编码四个分量:Red、Green、Blue 和一个填充值,按照此顺序存在。
该格式中每个样本为 8 位。每个像素的第四个元素应被忽略,图像始终为完全不透明。
单个平面中有
codedWidth
*codedHeight
* 4 个样本(因此也是字节),从图像左上角开始按codedHeight
行,每行codedWidth
个样本排列。 BGRA
-
该格式由单个平面组成,编码四个分量:Blue、Green、Red 和 alpha 值,按照此顺序存在。
该格式中每个样本为 8 位。
单个平面中有
codedWidth
*codedHeight
* 4 个样本(因此也是字节),从图像左上角开始按codedHeight
行,每行codedWidth
个样本排列。 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)
-
令 c 为一个新的
VideoColorSpace
对象,初始化如下:-
将
init.primaries
赋值给[[primaries]]
。 -
将
init.transfer
赋值给[[transfer]]
。 -
将
init.matrix
赋值给[[matrix]]
。 -
将
init.fullRange
赋值给[[full range]]
。
-
-
返回 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
遵循此模式,这也促使其接口设计与 VideoDecoder
和 AudioDecoder
明显不同。
尽管存在这些差异,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 是否受支持。用户代理无需支持任何特定类型。调用时,执行以下步骤:
-
如果 init 不是 有效的 ImageDecoderInit,抛出
TypeError
。 -
如果 init.
transfer
包含对同一个ArrayBuffer
的多个引用,则抛出DataCloneError
DOMException
。 -
对于 init.
transfer
中的每个 transferable:-
如果
[[Detached]]
内部插槽为true
, 则抛出DataCloneError
DOMException
。
-
-
令 d 为新的
ImageDecoder
对象。下述所有提及ImageDecoder
成员均指 d,除非另有说明。 -
为
[[control message queue]]
赋值一个新的 队列。 -
将
false
赋值给[[message queue blocked]]
。 -
将新启动的 并行队列赋值给
[[codec work queue]]
。 -
将
[[ImageTrackList]]
赋值为新建的ImageTrackList
,初始化如下:-
将新建的 列表赋值给
[[track list]]
。 -
将
-1
赋值给[[selected index]]
。
-
-
将
null
赋值给[[codec implementation]]
。 -
如果
init.preferAnimation
存在, 将init.preferAnimation
赋值给[[prefer animation]]
内部插槽,否则赋值为 null。 -
将新建的 列表赋值给
[[pending decode promises]]
。 -
将
-1
赋值给[[internal selected track index]]
。 -
将
false
赋值给[[tracks established]]
。 -
将
false
赋值给[[closed]]
。 -
将新建的 映射赋值给
[[progressive frame generations]]
。 -
如果 init 的
data
成员类型为ReadableStream
:-
将新建的 列表赋值给
[[encoded data]]
。 -
将
false
赋值给[[complete]]
。 -
并行地,在 d 上以 reader 执行 流数据获取循环。
-
-
否则:
-
断言
init.data
类型为BufferSource
。 -
如果 init.
transfer
中包含被 init.data
引用的ArrayBuffer
,用户代理 可以选择:-
令
[[encoded data]]
引用 data 中表示编码图像的字节。
-
-
否则:
-
将
init.data
的副本赋值给[[encoded data]]
。
-
-
将
true
赋值给[[complete]]
。 -
向控制消息队列入队,以 配置图像解码器,参数为 init。
-
向控制消息队列入队,以 解码轨道元数据。
-
-
对于 init.
transfer
中的每个 transferable:-
对 transferable 执行 DetachArrayBuffer
-
-
返回 d。
运行控制消息以 配置图像解码器 ,表示执行以下步骤:
-
令 supported 为以
init.type
运行 检查类型支持算法的结果。 -
如果 supported 为
false
,则使用Close ImageDecoder
算法,传入NotSupportedError
DOMException
,并返回"processed"
。 -
否则,将
[[codec implementation]]
内部插槽赋值为支持init.type
的实现。 -
将
true
赋值给[[message queue blocked]]
。 -
将以下步骤入队到
[[codec work queue]]
:-
按照
colorSpaceConversion
、desiredWidth
、 和desiredHeight
的值配置[[codec implementation]]
。 -
将
false
赋值给[[message queue blocked]]
。
-
-
返回
"processed"
。
运行控制消息以 解码轨道元数据 ,表示执行以下步骤:
-
将以下步骤入队到
[[codec work queue]]
:-
运行 建立轨道算法。
-
-
10.2.3. 属性
type
, 类型为 DOMString,只读-
一个字符串,反映构造时给定的 MIME
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 解码帧。
调用时,执行如下步骤:
-
如果
[[closed]]
为true
,返回一个Promise
,其状态为 rejected,错误为InvalidStateError
DOMException
。 -
如果
[[ImageTrackList]]
的[[selected index]]
为 '-1',返回一个Promise
,其状态为 rejected,错误为InvalidStateError
DOMException
。 -
如果 options 为
undefined
,则为 options 分配一个新的ImageDecodeOptions
。 -
令 promise 为一个新的
Promise
。 -
将 promise 添加到
[[pending decode promises]]
。 -
控制消息入队,以 options 和 promise 解码图像。
-
返回 promise。
运行控制消息以解码图像,表示执行如下步骤:
-
将以下步骤入队到
[[codec work queue]]
:-
等待
[[tracks established]]
变为true
。 -
如果 options.
completeFramesOnly
为false
且该图像为 渐进式图像,并且用户代理支持渐进解码,则以 options.frameIndex
和 promise 运行 解码渐进帧算法。 -
否则,以 options.
frameIndex
和 promise 运行 解码完整帧算法。
-
-
reset()
-
立即中止所有待处理工作。
调用时,以
Reset ImageDecoder
算法和AbortError
DOMException
运行。 close()
-
立即中止所有待处理工作并释放系统资源。关闭后无法再次使用。
调用时,以
Close ImageDecoder
算法和AbortError
DOMException
运行。 isTypeSupported(type)
-
返回一个 promise,指示用户代理是否支持所提供的配置。
调用时,执行如下步骤:
-
如果 type 不是 有效的图像 MIME 类型,返回一个
Promise
,其状态为 rejected,错误为TypeError
。 -
令 p 为一个新的
Promise
。 -
并行地,以 type 运行 检查类型支持算法,并将结果 resolve 到 p。
-
返回 p。
-
10.2.5. 算法
- 获取流数据循环 (带 reader)
-
执行以下步骤:
-
令 readRequest 为如下 读取请求。
- chunk 步骤,给定 chunk
-
-
如果
[[closed]]
为true
,则中止这些步骤。 -
如果 chunk 不是 Uint8Array 对象,入队一个任务以运行 关闭 ImageDecoder 算法,使用
DataError
DOMException
,并中止这些步骤。 -
令 bytes 为该 Uint8Array 对象所表示的字节序列。
-
将 bytes 追加到
[[encoded data]]
内部插槽。 -
如果
[[tracks established]]
为false
,则运行 建立轨道 算法。 -
否则,运行 更新轨道算法。
-
使用 reader 运行 获取流数据循环算法。
-
- close 步骤
-
-
将
true
赋值给[[complete]]
-
- error 步骤
-
-
入队一个任务以运行 关闭 ImageDecoder 算法,使用
NotReadableError
DOMException
。
-
-
使用 readRequest 从 reader 读取一个 chunk。
-
- 建立轨道
-
执行以下步骤:
-
断言
[[tracks established]]
为false
。 -
如果
[[encoded data]]
没有足够数据来确定轨道数量:-
如果
complete
为true
,入队一个任务以运行 关闭 ImageDecoder 算法, 使用InvalidStateError
DOMException
。 -
中止这些步骤。
-
-
如果轨道数为
0
,入队一个任务以运行 关闭 ImageDecoder 算法并中止这些步骤。 -
令 newTrackList 为新的 列表。
-
对于在
[[encoded data]]
中找到的每个 image track:-
令 newTrack 为新的
ImageTrack
,初始化如下:-
将 this 赋值给
[[ImageDecoder]]
。 -
将
tracks
赋值给[[ImageTrackList]]
。 -
如果 image track 被判定为动画,将
true
赋值给 newTrack 的[[animated]]
内部插槽,否则赋值为false
。 -
如果 image track 描述了帧数,将该数赋值给 newTrack 的
[[frame count]]
内部插槽,否则赋值0
。注意:如果 this 构造时
data
为ReadableStream
, 则随着更多字节追加到[[encoded data]]
,frameCount
可变化。参见 更新轨道算法。 -
如果 image track 描述了重复次数,将该数赋值给
[[repetition count]]
内部插槽,否则赋值0
。注意:值为
Infinity
表示无限重复。 -
将
false
赋值给 newTrack 的[[selected]]
内部插槽。
-
-
将 newTrack 添加到 newTrackList。
-
-
令 selectedTrackIndex 为以 newTrackList 运行 获取默认选中轨道索引算法的结果。
-
令 selectedTrack 为 newTrackList 中位置 selectedTrackIndex 的轨道。
-
将
true
赋值给 selectedTrack 的[[selected]]
内部插槽。 -
将 selectedTrackIndex 赋值给
[[internal selected track index]]
。 -
将
true
赋值给[[tracks established]]
。 -
入队一个任务以执行以下步骤:
-
将 newTrackList 赋值给
tracks
的[[track list]]
内部插槽。 -
将 selectedTrackIndex 赋值给
tracks
的[[selected index]]
。
-
-
- 获取默认选中轨道索引 (参数 trackList)
-
执行以下步骤:
-
如果
[[encoded data]]
标识了一个 主图像轨道:-
令 primaryTrack 为 trackList 中描述 主图像轨道 的
ImageTrack
。 -
令 primaryTrackIndex 为 primaryTrack 在 trackList 中的位置。
-
如果
[[prefer animation]]
为null
,返回 primaryTrackIndex。 -
如果 primaryTrack.
animated
等于[[prefer animation]]
, 返回 primaryTrackIndex。
-
-
如果 trackList 中有任何
ImageTrack
的animated
等于[[prefer animation]]
, 返回 trackList 中最早出现的此类轨道的位置。 -
返回
0
。
-
- 更新轨道
-
轨道更新结构体 是一个 结构体,包含 轨道索引 (
unsigned long
) 和 帧数 (unsigned long
)。执行以下步骤:
-
断言
[[tracks established]]
为true
。 -
令 trackChanges 为一个新的 列表。
-
令 trackList 为
tracks
的[[track list]]
的副本。 -
对于 trackList 中的每个 track:
-
令 trackIndex 为 track 在 trackList 中的位置。
-
令 latestFrameCount 为
[[encoded data]]
中对应 track 的轨道所指示的帧数。 -
断言 latestFrameCount 必须大于等于
track.frameCount
。 -
如果 latestFrameCount 大于
track.frameCount
:
-
-
如果 tracksChanges 为空,则中止本步骤。
-
队列一个任务以执行以下步骤:
-
对于 trackChanges 中的每个 update:
-
令 updateTrack 为
ImageTrack
在update.trackIndex
位置, 于tracks
的[[track list]]
内。 -
将
update.frameCount
赋值给 updateTrack 的[[frame count]]
。
-
-
-
- 解码完整帧 (使用 frameIndex 和 promise)
-
-
断言
[[tracks established]]
为true
。 -
断言
[[internal selected track index]]
不为-1
。 -
令 encodedFrame 为由 frameIndex 和
[[internal selected track index]]
标识的编码帧。 -
等待下列任一条件成立(以先发生者为准):
-
[[encoded data]]
包含足够字节以完全解码 encodedFrame。 -
[[encoded data]]
被判定为格式错误。 -
complete
为true
。 -
[[closed]]
为true
。
-
-
如果
[[encoded data]]
被判定为格式错误,执行 致命拒绝错误数据 算法并中止本步骤。 -
如果
[[encoded data]]
不包含足够字节以完全解码 encodedFrame,则使用 promise 执行 拒绝不可行解码 算法并中止本步骤。 -
尝试使用
[[codec implementation]]
解码 encodedFrame。 -
如果解码产生错误,则执行 致命拒绝错误数据 算法并中止本步骤。
-
如果
[[progressive frame generations]]
包含以 frameIndex 为键的条目,则从该 map 中移除该条目。 -
令 output 为由
[[codec implementation]]
解码 encodedFrame 后产生的图像数据。 -
令 decodeResult 为新
ImageDecodeResult
并初始化如下:-
将 'true' 赋值给
complete
。 -
令 duration 为 output 的展示持续时间(由 encodedFrame 描述)。如果 encodedFrame 没有持续时间,则赋值
null
。 -
令 timestamp 为 output 的展示时间戳(由 encodedFrame 描述)。如果 encodedFrame 没有时间戳:
-
如果 encodedFrame 是静态图像,则赋值
0
给 timestamp。 -
如果 encodedFrame 是恒定速率动画图像且 duration 不为
null
,则赋值|frameIndex| * |duration|
给 timestamp。 -
如果可以直接由元数据生成 timestamp,则赋值该值。
-
否则赋值
0
给 timestamp。
-
-
如果
[[encoded data]]
包含方向元数据,则描述为 rotation 和 flip,否则 rotation 为 0,flip 为 false。 -
将
image
赋值为使用 创建 VideoFrame 算法,参数为 output、timestamp、duration、rotation、flip 的结果。
-
-
使用 promise 和 decodeResult 执行 完成解码算法。
-
- 解码渐进帧 (使用 frameIndex 和 promise)
-
-
断言
[[tracks established]]
为true
。 -
断言
[[internal selected track index]]
不为-1
。 -
令 encodedFrame 为由 frameIndex 和
[[internal selected track index]]
标识的编码帧。 -
令 lastFrameGeneration 为
null
。 -
如果
[[progressive frame generations]]
包含以 frameIndex 为键的条目,则将该条目的值赋值给 lastFrameGeneration。 -
等待下列任一条件成立(以先发生者为准):
-
[[encoded data]]
包含足够字节以解码 encodedFrame,产生一个其 渐进图像帧代数 超过 lastFrameGeneration 的输出。 -
[[encoded data]]
被判定为格式错误。 -
complete
为true
。 -
[[closed]]
为true
。
-
-
如果
[[encoded data]]
被判定为格式错误,则执行 致命拒绝错误数据 算法并中止本步骤。 -
否则,如果
[[encoded data]]
不包含足够字节以解码 encodedFrame,产生一个其 渐进图像帧代数 超过 lastFrameGeneration 的输出,则使用 promise 执行 拒绝不可行解码 算法并中止本步骤。 -
尝试使用
[[codec implementation]]
解码 encodedFrame。 -
如果解码产生错误,则执行 致命拒绝错误数据 算法并中止本步骤。
-
令 output 为由
[[codec implementation]]
解码 encodedFrame 后产生的图像数据。 -
令 decodeResult 为新
ImageDecodeResult
。 -
如果 output 是 encodedFrame 的最终全细节渐进输出:
-
将
true
赋值给 decodeResult 的complete
。 -
如果
[[progressive frame generations]]
包含以 frameIndex 为键的条目,则从该 map 中移除该条目。
-
-
否则:
-
将
false
赋值给 decodeResult 的complete
。 -
令 frameGeneration 为 output 的 渐进图像帧代数。
-
向
[[progressive frame generations]]
添加以 frameIndex 为键、frameGeneration 为值的新条目。
-
-
令 duration 为 output 的展示持续时间(由 encodedFrame 描述)。如果 encodedFrame 没有描述持续时间,则赋值
null
。 -
令 timestamp 为 output 的展示时间戳(由 encodedFrame 描述)。如果 encodedFrame 没有时间戳:
-
如果 encodedFrame 是静态图像,则赋值
0
给 timestamp。 -
如果 encodedFrame 是恒定速率动画图像且 duration 不为
null
,则赋值|frameIndex| * |duration|
给 timestamp。 -
如果可以直接由元数据生成 timestamp,则赋值该值。
-
否则赋值
0
给 timestamp。
-
-
如果
[[encoded data]]
包含方向元数据,则描述为 rotation 和 flip,否则 rotation 为 0,flip 为 false。 -
将
image
赋值为使用 创建 VideoFrame 算法,参数为 output、timestamp、duration、rotation、flip 的结果。 -
从
[[pending decode promises]]
中移除 promise。 -
使用 decodeResult 解析 promise。
-
- 完成解码(使用 promise 和 result)
-
-
队列一个任务以执行以下步骤:
-
如果
[[closed]]
,则中止这些步骤。 -
断言 promise 是
[[pending decode promises]]
的一个元素。 -
将 promise 从
[[pending decode promises]]
移除。 -
以 result 解析 promise。
-
-
- 拒绝不可行解码(使用 promise)
-
-
断言
complete
为true
或[[closed]]
为true
。 -
如果
complete
为true
,令 exception 为RangeError
。 否则,令 exception 为InvalidStateError
DOMException
。 -
队列一个任务以执行以下步骤:
-
如果
[[closed]]
,则中止这些步骤。 -
断言 promise 是
[[pending decode promises]]
的一个元素。 -
将 promise 从
[[pending decode promises]]
移除。 -
以 exception 拒绝 promise。
-
-
- 致命拒绝错误数据
-
-
队列一个任务以执行以下步骤:
-
如果
[[closed]]
,则中止这些步骤。 -
使用
关闭 ImageDecoder
算法,参数为EncodingError
DOMException
。
-
-
- 检查类型支持(使用 type)
-
-
如果用户代理可以提供编解码器以支持解码 type,则返回
true
。 -
否则,返回
false
。
-
- 重置 ImageDecoder(使用 exception)
-
-
通知
[[codec implementation]]
中止任何活动的解码操作。 -
对于
[[pending decode promises]]
中的每个 decodePromise:-
以 exception 拒绝 decodePromise。
-
将 decodePromise 从
[[pending decode promises]]
移除。
-
-
- 关闭 ImageDecoder(使用 exception)
-
-
使用 重置 ImageDecoder 算法,参数为 exception。
-
将
true
赋值给[[closed]]
。 -
清空
[[codec implementation]]
并释放相关 系统资源。 -
如果
[[ImageTrackList]]
为空,则以 exception 拒绝[[ready promise]]
。 否则执行以下步骤,-
移除
[[ImageTrackList]]
的所有条目。 -
将
-1
赋值给[[ImageTrackList]]
的[[selected index]]
。
-
-
如果
[[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,
执行以下步骤:
-
如果 type 不是有效的图片 MIME 类型,返回
false
。 -
如果 data 类型为
ReadableStream
且该 ReadableStream 已被 扰动或锁定,返回false
。 -
如果 data 类型为
BufferSource
: -
如果
desiredWidth
存在,但desiredHeight
不存在,则返回false
。 -
如果
desiredHeight
存在,但desiredWidth
不存在,则返回false
。 -
返回
true
。
有效的图片 MIME
类型是指一个字符串,
它是一个有效的 MIME 类型字符串,
并且根据 [RFC9110] 的第 8.3.1 节,
其 type
为 image
。
type
, 类型为 DOMString-
包含待解码图片文件的 MIME 类型的字符串。
data
, 类型为 ImageBufferSource-
表示图片文件编码字节的
BufferSource
或ReadableStream
, 其 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()
只有在完整细节图片解码完成时才会返回结果。注意:对于渐进图片,设置completeFramesOnly
为false
,可为用户提供网络读取中的图片预览(通过data
ReadableStream
)。当解码完整细节图片时,
ImageDecodeResult
的complete
会被设置为 true。
10.5. ImageDecodeResult 接口
dictionary {
ImageDecodeResult required VideoFrame image ;required boolean complete ; };
image
, 类型为 VideoFrame-
解码后的图片。
complete
, 类型为 boolean-
表示
image
是否为最终完整细节输出。注意:当
decode()
调用时completeFramesOnly
设置为true
,complete
总是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。注意:
ImageTrack
的frameCount
在complete
为true
之前可以被持续更新。 [[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 步骤为:-
如果
[[selected index]]
为-1
,返回null
。 -
否则,返回
[[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]]
-
构造该
ImageTrack
的ImageDecoder
实例。 [[ImageTrackList]]
-
包含该
ImageTrack
的ImageTrackList
实例。 [[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 步骤如下:-
如果
[[ImageDecoder]]
的[[closed]]
插槽为true
,则中止这些步骤。 -
令 newValue 为给定值。
-
如果 newValue 等于
[[selected]]
,则中止这些步骤。 -
将 newValue 赋值给
[[selected]]
。 -
令 parentTrackList 为
[[ImageTrackList]]
-
令 oldSelectedIndex 为 parentTrackList 的
[[selected index]]
的值。 -
如果 oldSelectedIndex 不为
-1
:-
令 oldSelectedTrack 为
ImageTrack
,位于 parentTrackList 的[[track list]]
的 oldSelectedIndex 位置。 -
将
false
赋值给 oldSelectedTrack 的[[selected]]
-
-
如果 newValue 为
true
,令 selectedIndex 为 thisImageTrack
在 parentTrackList 的[[track list]]
中的索引;否则令 selectedIndex 为-1
。 -
将 selectedIndex 赋值给 parentTrackList 的
[[selected index]]
。 -
对
[[ImageDecoder]]
执行 重置 ImageDecoder 算法。 -
队列一个控制消息到
[[ImageDecoder]]
的 控制消息队列,以使用 selectedIndex 更新内部选中轨道索引。 -
处理属于
[[ImageDecoder]]
的 控制消息队列。
执行控制消息以更新内部选中轨道索引时,需执行如下步骤:
-
将以下步骤加入
[[ImageDecoder]]
的[[codec work queue]]
:-
将 selectedIndex 赋值给
[[internal selected track index]]
。 -
清空
[[progressive frame generations]]
的所有条目。
-
-
11. 资源回收
当资源受限时,用户代理 可以 主动回收编解码器。尤其是在硬件编解码器有限,且被多个网页或平台应用共享时。
要回收编解码器,用户代理 必须 执行相应的关闭算法(包括 关闭 AudioDecoder、
关闭 AudioEncoder、
关闭 VideoDecoder
和 关闭
VideoEncoder),并传入 QuotaExceededError
。
决定何时可以回收编解码器的规则,取决于该编解码器是活动、非活动,以及是否为后台编解码器。
活动编解码器指过去 10 秒
内曾在[[codec
work queue]]上有进展的编解码器。
注意: 判断工作队列进展的可靠标志是调用 output()
回调。
非活动编解码器是指不满足活动编解码器定义的任何编解码器。
后台编解码器指其
ownerDocument
(或对于 worker 编解码器,owner set 的 Document
)
具有
属性且值为
true
的编解码器。
用户代理 必须 只回收属于非活动编解码器、后台编解码器或两者的编解码器。用户代理 不得 回收既是活动又在前台(即不是后台编解码器)的编解码器。
-
编码器,例如
AudioEncoder
或VideoEncoder
。注意: 这样可以防止长时间编码任务被中断。
-
AudioDecoder
或VideoDecoder
,当同一全局对象中分别存在 活动AudioEncoder
或VideoEncoder
时。注意: 这样可防止长时间转码任务被打断。
-
AudioDecoder
,当其标签页正在播放声音时。
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。