Copyright © 2026 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
HTMLMediaElement
[HTML],
允许 JavaScript 生成用于播放的媒体流。JavaScript 生成流可满足多种使用场景,如自适应流媒体和直播时移等。
本节描述本文档在发布时的状态。当前 W3C 发布文档及本技术报告最新修订版可在 W3C 标准与草案索引中查阅。
除编辑性更新外,自 W3C 推荐标准 2016年11月发布以来的实质性变化包括:
changeType()
方法,可在不同编解码器或字节流间切换
MediaSource 对象
createObjectURL()
对 URL 对象的扩展,相关功能已集成至 File API [FILEAPI]
ManagedMediaSource、ManagedSourceBuffer 和
BufferedChangeEvent
接口,支持节能流媒体和代理主动清理已缓冲媒体
完整变更列表请参见 提交历史。
工作组维护着编辑尚未处理的所有问题报告列表。
实现者需注意本规范并不稳定。未参与相关讨论的实现者可能会发现规范发生不兼容变化。有兴趣在本规范进入候选推荐阶段前进行实现的厂商应关注 GitHub 仓库并参与讨论。
作为工作草案发布,并不意味着 W3C 及其成员的认可。
本文档为草稿,可能随时被更新、替换或废止。除“进行中的工作”外,不适宜引用本文件。
本文档由遵循 W3C 专利政策 的小组制作。 W3C 维护着 本小组相关专利公开的公共列表; 该页面还包含专利披露说明。个人如获知某专利涉及 必要权利要求 ,须遵循 W3C 专利政策第6节进行披露。
本文档适用 2025年8月18日 W3C 流程文件。
本节为非规范内容。
本规范允许 JavaScript 动态构建 <audio> 和 <video> 的媒体流。它定义了一个 MediaSource 对象,可作为 HTMLMediaElement
的媒体数据源。MediaSource 对象包含一个或多个
SourceBuffer 对象。应用可以把数据分段追加到 SourceBuffer 对象,并能根据系统性能等因素调整追加数据的质量。SourceBuffer
对象中的数据会作为音频、视频和文本轨道缓冲区进行管理,解码后播放。与这些扩展配套使用的字节流规范可在字节流格式注册表 [MSE-REGISTRY] 中查阅。
本规范设计时考虑了以下目标:
本规范定义了:
为 轨道缓冲区,它们为
编码帧提供给
enabled
的 audioTracks、
selected
的 videoTracks,以及
处于
"showing"
或
"hidden"
状态的 textTracks。
所有这些轨道
都与 SourceBuffer 对象相关联,这些对象位于
activeSourceBuffers
列表中。
在追加时用于过滤掉 呈现时间戳范围之外的编码帧。
追加窗口表示具有单一起始时间
和结束时间的单个连续时间范围。呈现时间戳位于此
范围内的编码帧
可以追加到 SourceBuffer,而此
范围外的编码帧
会被过滤掉。追加窗口的起始时间和结束时间分别由
appendWindowStart 和 appendWindowEnd 属性
控制。
一个编码帧的持续时间。对于视频和文本,该持续时间表示 视频帧或文本应显示多长 时间。对于音频,该持续时间 表示编码帧中包含的所有采样之和。例如,如果一个音频帧 包含 441 个采样 @44100Hz,则该帧的持续时间为 10 毫秒。
一组彼此相邻且编码帧,其
解码时间戳无间隙地单调递增。由
编码帧处理
算法检测到的不连续以及 abort()
调用都会触发新
编码帧组的开始。
解码时间戳表示该帧最迟需要完成解码的时间, 假定该帧及任何依赖帧的解码和渲染都是瞬时完成的(这 等于在呈现顺序中最早依赖于该帧的帧的呈现时间戳)。如果 帧能够脱离 呈现顺序进行解码,则解码时间戳必须存在于字节流中或能够从 字节流中推导出来。如果不是 这种情况,用户代理必须运行追加错误算法。如果帧无法脱离呈现 顺序进行解码,并且字节流中不存在解码 时间戳,则解码时间戳等于 呈现时间戳。
一个字节序列,其中包含解码一系列媒体段所需的全部 初始化信息。这包括编解码器 初始化数据、复用段的 轨道 ID 映射以及时间戳 偏移量(例如编辑 列表)。
字节流格式注册表中的字节流格式规范 [MSE-REGISTRY] 包含特定于格式的示例。
一个字节序列,其中包含媒体时间线某一部分的 分组化且带时间戳的媒体数据。 媒体段始终与最近 追加的初始化段相关联。
字节流格式注册表中的字节流格式规范 [MSE-REGISTRY] 包含特定于格式的示例。
MediaSource 对象 URL 是由
createObjectURL()
创建的唯一blob URL。
它用于将 MediaSource 对象附加到
HTMLMediaElement。
这些 URL 与blob
URL相同,不同之处在于,该
特性的定义中任何引用 File 和 Blob 对象的内容,在此也扩展
为同样
适用于 MediaSource 对象。
MediaSource 对象 URL 的源是调用 createObjectURL()
期间
this 的相关
设置对象。
例如,MediaSource 对象 URL 的源会影响 媒体元素被 canvas 使用的方式。
SourceBuffer 对象的父媒体源是
创建该对象的 MediaSource 对象。
呈现开始时间是呈现中最早的时间点,并 指定初始播放 位置和最早可能 位置。使用本规范创建的所有呈现,其呈现 开始时间均为 0。
为确定 HTMLMediaElement
的
buffered
是否包含一个包含当前播放位置的TimeRanges,
实现
可以选择允许位于呈现开始时间或之后、
且位于第一个 TimeRanges
之前的当前播放位置播放第一个 TimeRanges,
前提是该
TimeRanges
在呈现开始时间之后相当短的时间内开始,例如 1 秒。此许可
是为了适应复用流
通常不会让所有轨道恰好在呈现开始时间开始这一实际情况。
无论此许可如何,实现必须报告实际的缓冲范围。
一个编码帧的呈现区间,是从其 呈现时间戳到该呈现时间戳加上该编码帧的持续时间之间的时间区间。例如, 如果一个编码帧的呈现 时间戳为 10 秒,且编码帧持续时间为 100 毫秒,则 呈现区间将为 [10-10.1)。请注意,该范围的起点 包含在内,而终点不包含在内。
对呈现中特定时间的引用。一个 编码帧中的呈现时间戳指示该帧何时应被渲染。
媒体段中的一个位置,可以从该位置开始解码和连续播放, 而无需依赖该段中任何先前的数据。对于视频,这通常是 I 帧所在的位置。对于音频,大多数音频帧都可以视为 随机访问点。由于视频轨道中的随机访问点往往分布得更加稀疏, 因而这些点的位置通常被视为复用流的随机 访问点。
描述 SourceBuffer 实例所接受字节
流格式的特定字节流格式规范。
对于一个 SourceBuffer 对象,其字节流格式规范最初
根据创建该对象时传递给 addSourceBuffer()
调用的
type 进行选择,并且可以通过对
该对象调用 changeType() 来更新。
SourceBuffer 配置
由单个 MediaSource 实例拥有,
并分布在一个或多个 SourceBuffer 对象中的一组特定轨道。
实现必须至少支持 1 个具有以下
配置的 MediaSource 对象:
MediaSource 对象必须支持上述每种配置,但它们 只需 一次支持一种配置。同时支持多种配置或 其他配置属于实现质量问题。
一种特定于字节流格式的结构,它提供单条轨道的轨道 ID、编解码器 配置以及其他元数据。单个 初始化段中的每个轨道描述都有唯一的轨道 ID。如果 轨道 ID在 初始化段内不唯一,则用户代理必须运行 追加错误算法。
轨道 ID 是一种特定于字节流格式的标识符,用于将字节 流的各部分标记为属于特定轨道。轨道 描述中的轨道 ID 标识媒体段的哪些部分属于该轨道。
MediaSource 接口表示用于
HTMLMediaElement
的媒体数据源。它会记录此源的 readyState 状态,以及可以用于向演示添加媒体数据的 SourceBuffer 对象列表。MediaSource 对象由 Web 应用创建,然后附加到
HTMLMediaElement。应用通过 SourceBuffer 对象与 sourceBuffers 向该源添加媒体数据。HTMLMediaElement
在播放时会从 MediaSource 对象获取媒体数据。
每个 MediaSource 对象都拥有一个 [[live seekable
range]] 内部槽,用于存储一个 标准化的 TimeRanges
对象。该对象在 MediaSource 创建时初始化为空的 TimeRanges 对象,通过 setLiveSeekableRange()
和
clearLiveSeekableRange()
维护,并在 10.
HTMLMediaElement 扩展
中用于修改 HTMLMediaElement
的
seekable
行为。
每个 MediaSource 对象都有一个 [[是否曾被
附加]]内部槽,用于存储一个 boolean。当
MediaSource 对象被创建时,它被初始化为 false,并在扩展的
HTMLMediaElement
的
资源获取
算法中,按照附加到媒体元素算法中的描述被设置为 true。扩展的
资源获取
算法使用此内部
槽,以有条件地使通过设置在 HTMLMediaElement
的
srcObject
属性上的 MediaSourceHandle
附加 MediaSource
的操作失败。
WebIDLenum ReadyState {
"closed",
"open",
"ended",
};
closed
open
SourceBuffer 对象(在 MediaSource 的 sourceBuffers 属性中)追加数据。
ended
MediaSource 的
endOfStream() 已被
调用。
WebIDLenum EndOfStreamError {
"network",
"decode",
};
network
终止播放并表示发生了网络错误。
JavaScript 应用 应当 使用该状态码以网络错误终止播放。例如,获取媒体数据时发生网络错误。
decode
终止播放并表示发生了解码错误。
JavaScript 应用 应当 使用该状态码以解码错误终止播放。例如,处理带外媒体数据时发生解析错误。
WebIDL[Exposed=(Window,DedicatedWorker)]
interface MediaSource : EventTarget {
constructor();
[SameObject, Exposed=DedicatedWorker]
readonly attribute MediaSourceHandle handle;
readonly attribute SourceBufferList sourceBuffers;
readonly attribute SourceBufferList activeSourceBuffers;
readonly attribute ReadyState readyState;
attribute unrestricted double duration;
attribute EventHandler onsourceopen;
attribute EventHandler onsourceended;
attribute EventHandler onsourceclose;
static readonly attribute boolean canConstructInDedicatedWorker;
SourceBuffer addSourceBuffer(DOMString type);
undefined removeSourceBuffer(SourceBuffer sourceBuffer);
undefined endOfStream(optional EndOfStreamError error);
undefined setLiveSeekableRange(double start, double end);
undefined clearLiveSeekableRange();
static boolean isTypeSupported(DOMString type);
};
包含一个用于将专用 worker MediaSource 对象通过 srcObject
附加到
HTMLMediaElement
的句柄。此句柄在本 MediaSource 对象多次访问时保持为同一个对象,但每个 MediaSource 对象各自独立。
本规范最终可能会允许在主 Window 上下文中的 MediaSource
对象上公开此属性。如果这样做,则需要在规范中谨慎处理,以防止
潜在的向后不兼容更改,例如访问此属性时抛出异常可能会导致这种情况。
获取时,按以下步骤执行:
MediaSource 对象的句柄尚未创建,则执行以下步骤:
MediaSourceHandle 对象及相关资源的结果,并与本
MediaSource 内部关联。
MediaSourceHandle 对象。
包含与本 SourceBuffer 关联的 MediaSource 对象列表。当 MediaSource 的 readyState 等于 "closed" 时,此列表为空。当 readyState 状态变为 "open" 时,可以使用 addSourceBuffer()
向该列表添加 SourceBuffer 对象。
包含 sourceBuffers 的子集,这些缓冲区为
selected
视频轨道、
enabled
音频轨道,以及
"showing"
或
"hidden"
文本轨道提供数据。
本列表中的 SourceBuffer 对象 必须 与 sourceBuffers 属性中的顺序一致;例如,若仅
sourceBuffers[0] 和 sourceBuffers[3] 在 activeSourceBuffers 中,则
activeSourceBuffers[0] 必须等于 sourceBuffers[0],activeSourceBuffers[1] 必须等于 sourceBuffers[3]。
3.15.5 选中/启用轨道状态变更 一节描述了此属性的更新机制。
表示 MediaSource 对象当前状态。创建 MediaSource
时,readyState 必须被设置为 "closed"。
允许 Web 应用设置演示时长。创建 MediaSource 对象时,时长初始为 NaN。
获取时,按以下步骤执行:
readyState 属性为 "closed",则返回 NaN 并终止步骤。
设置时,按以下步骤执行:
TypeError
异常并终止步骤。
readyState 属性不是 "open",则抛出 InvalidStateError
异常并终止步骤。
updating 属性在任意 SourceBuffer(在 sourceBuffers 中)上为 true,则抛出 InvalidStateError
异常并终止步骤。
时长变更算法会在当前已缓冲编码帧结束时间更大时自动上调 new duration。
appendBuffer()
和 endOfStream()
在某些情况下也会更新时长。
返回 true。
此属性用于在主线程和专用 worker 中检测是否支持在专用 worker 创建和使用 MediaSource 对象,减少需要高延迟检测 polyfill(如尝试在专用 worker
创建 MediaSource 对象,尤其在不支持该特性时)的需求。
将新的 SourceBuffer 添加到 sourceBuffers。
TypeError
异常并中止
这些步骤。
SourceBuffer 中为其他对象指定的类型
一起使用时不受支持的 MIME 类型,而这些对象位于
sourceBuffers 中,则抛出一个 NotSupportedError
异常并中止这些
步骤。
QuotaExceededError
异常并中止这些步骤。
例如,如果媒体
元素已达到 HAVE_METADATA
readyState,用户代理可以抛出一个 QuotaExceededError
异常。如果用户代理的媒体引擎不支持在播放期间添加更多轨道,
就可能发生这种情况。
readyState 属性不处于
"open" 状态,
则抛出一个 InvalidStateError
异常并中止这些步骤。
ManagedMediaSource,
则令 buffer 为一个新的 ManagedSourceBuffer 实例;
否则,为一个 SourceBuffer 实例,并带有它们各自关联的
资源。
[[generate timestamps flag]] 设置为
与 type 关联的
媒体源扩展™字节
流格式注册表条目中
“生成时间戳标志”列里的值。
[[generate timestamps flag]] 为
true,则将 buffer 的
mode 设置为 "sequence"。否则,将
buffer 的
mode 设置为 "segments"。
sourceBuffers。
sourceBuffers 上触发一个事件,
其名称为 addsourcebuffer。
从 SourceBuffer 从 sourceBuffers 移除一个 SourceBuffer。
sourceBuffers 中,则抛出一个 NotFoundError 异常
并中止这些
步骤。
updating 属性等于 true,则
执行以下步骤:
MediaSource 在 Window
中构造:
audioTracks
返回的 AudioTrackList
对象。
audioTracks
属性返回的
AudioTrackList
对象。
sourceBuffer
属性设为
null。
这应当触发 AudioTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件,事件名为
removetrack
,使用 TrackEvent
并将其 track
属性初始化为 audio
track,在
SourceBuffer audioTracks list
上触发。
如果 audio track 的
enabled
属性在该移除步骤开始时为 true,
那么这还应触发 AudioTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件,事件名为
change
,在
SourceBuffer audioTracks list
上触发。
这应当触发 AudioTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件,事件名为
removetrack
,使用
TrackEvent
并将 track
属性初始化为
audio track,在 HTMLMediaElement audioTracks
list 上触发。如果
audio track 的
enabled
属性在该移除步骤开始时为 true,
那么这还应触发
AudioTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件
,事件名为 change
,在 HTMLMediaElement audioTracks
list 上触发。
[[port to main]]
发送一个内部
remove track 消息,其在 Window
中的隐式处理器执行以下步骤:
AudioTrackList
对象,其由 media element 上的
audioTracks
属性返回。
这应当触发 AudioTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件,事件名为
removetrack
,使用
TrackEvent
并将 track
属性初始化为
audio track,在 HTMLMediaElement audioTracks
list 上触发。如果
audio track 的
enabled
属性在该移除步骤开始时为 true,
那么这还应触发
AudioTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件
,事件名为 change
,在 HTMLMediaElement audioTracks
list 上触发。
MediaSource 在 Window
中构造:
VideoTrackList
对象,其由 sourceBuffer.videoTracks 返回。
VideoTrackList
对象,其由 media element 上的
videoTracks
属性返回。
sourceBuffer
属性设为
null。
这应当触发 VideoTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件,事件名为
removetrack
,使用 TrackEvent
并将其 track
属性初始化为 video
track,在
SourceBuffer videoTracks list
上触发。
如果 video track 的
selected
属性在该移除步骤开始时为 true,
那么这还应触发 VideoTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件,事件名为
change
,在
SourceBuffer videoTracks list
上触发。
这应当触发 VideoTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件,事件名为
removetrack
,使用
TrackEvent
并将 track
属性初始化为
video track,在 HTMLMediaElement videoTracks
list 上触发。如果
video track 的
selected
属性在该移除步骤开始时为 true,
那么这还应触发
VideoTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件
,事件名为 change
,在 HTMLMediaElement videoTracks
list 上触发。
[[port to main]]
发送一个内部
remove track 消息,其在 Window
中的隐式处理器执行以下步骤:
VideoTrackList
对象,其由 media element 上的
videoTracks
属性返回。
这应当触发 VideoTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件,事件名为
removetrack
,使用
TrackEvent
并将 track
属性初始化为
video track,在 HTMLMediaElement videoTracks
list 上触发。如果
video track 的
selected
属性在该移除步骤开始时为 true,
那么这还应触发
VideoTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件,事件名为
change
,在 HTMLMediaElement videoTracks
list 上触发。
MediaSource 在 Window
中构造:
TextTrackList
对象,其由 sourceBuffer.textTracks 返回。
TextTrackList
对象,其由 media element 上的
textTracks
属性返回。
sourceBuffer
属性设为
null。
这应当触发 TextTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件,事件名为
removetrack
,使用 TrackEvent
并将其 track
属性初始化为 text
track,在
SourceBuffer textTracks
list 上触发。如果 mode
属性在
text track 上为
"showing"
或
"hidden"
在该移除步骤开始时为真,那么这还应当触发 TextTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件,事件名为
change
,在 SourceBuffer
textTracks list 上触发。
这应当触发 TextTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件,事件名为
removetrack
,使用 TrackEvent
并将其 track
属性初始化为 text
track,在
HTMLMediaElement textTracks
list 上触发。如果 mode
属性在 text track 上为
"showing"
或
"hidden"
在该移除步骤开始时为真,那么这还应当触发 TextTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件
,事件名为 change
,在 HTMLMediaElement textTracks
list 上触发。
[[port to main]]
发送一个内部
remove track 消息,其在 Window
中的隐式处理器执行以下步骤:
TextTrackList
对象,其由 media element 上的
textTracks
属性返回。
这应当触发 TextTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件,事件名为
removetrack
,使用 TrackEvent
并将其 track
属性初始化为 text
track,
在 HTMLMediaElement textTracks
list 上触发。如果
text track 的
mode
属性在
"showing"
或
"hidden"
在该移除步骤开始时为真,那么这还应当触发 TextTrackList
[HTML] 逻辑,
以排队一个任务
来触发事件,事件名为 change
,在 HTMLMediaElement textTracks
list 上触发。
activeSourceBuffers 中,则
将 sourceBuffer
从 activeSourceBuffers 中移除,并排队一个任务
,在返回的 SourceBufferList 上触发事件,
事件名为
removesourcebuffer,
该列表由
activeSourceBuffers 返回。
sourceBuffers 中移除,并排队一个任务
,在返回的 SourceBufferList 上触发事件,
事件名为 removesourcebuffer。
该列表由
sourceBuffers 返回。
标志流结束。
readyState 属性不是 "open" 状态,则抛出 InvalidStateError
异常并终止这些步骤。
updating 属性在任意 SourceBuffer(在 sourceBuffers 中)上为 true,则抛出 InvalidStateError
异常并终止这些步骤。
更新 [[live seekable range]],该属性用于
10.
HTMLMediaElement 扩展,以修改 HTMLMediaElement
的
seekable
行为。
调用该方法时,用户代理必须执行以下步骤:
readyState 属性不是 "open",则抛出 InvalidStateError
异常并终止这些步骤。
TypeError
异常并终止这些步骤。
[[live seekable range]] 设为包含一个范围(起始为
start,结束为 end)的新的 标准化
TimeRanges 对象。
更新 [[live seekable range]],该属性用于
10.
HTMLMediaElement 扩展,以修改 HTMLMediaElement
的
seekable
行为。
调用该方法时,用户代理必须执行以下步骤:
readyState 属性不是 "open",则抛出 InvalidStateError
异常并终止这些步骤。
[[live seekable range]] 包含范围,则将
[[live seekable range]] 设为新的空 TimeRanges
对象。
检查 MediaSource 是否能够为指定的 MIME 类型创建 SourceBuffer
对象。
如果此方法返回 true,这仅表示该 MediaSource
实现能够为指定的 MIME 类型创建 SourceBuffer 对象。
即使如此,如果没有足够的资源来支持添加新的 SourceBuffer,addSourceBuffer()
调用仍然应当失败。
此方法返回 true 意味着 HTMLMediaElement
的
canPlayType()
将返回 "maybe" 或 "probably",因为
MediaSource 支持一种
HTMLMediaElement 明知自己无法播放的类型是没有意义的。
当调用此方法时,用户代理必须执行以下步骤:
| 事件名称 | 接口 | 触发条件 |
|---|---|---|
| sourceopen |
Event
|
MediaSource 的 readyState 状态从
"closed"
变为 "open" 或从 "ended" 变为 "open" 时触发。
|
| sourceended |
Event
|
MediaSource 的 readyState 状态从
"open"
变为 "ended" 时触发。
|
| sourceclose |
Event
|
MediaSource 的 readyState 状态从
"open"
变为 "closed" 或 "ended" 变为 "closed" 时触发。
|
当一个 Window
HTMLMediaElement
与一个 DedicatedWorkerGlobalScope
MediaSource 关联时,
每个上下文都有依赖于另一个上下文信息的算法。
HTMLMediaElement
只暴露给 Window
上下文,但本规范定义的 MediaSource 及相关对象
会在 Window
和
DedicatedWorkerGlobalScope
上下文中暴露。这使得应用可以在这两种上下文中的任意一种里构造一个
MediaSource 对象,
并使用一个 MediaSource 对象 URL
或一个 MediaSourceHandle
将其附加到 HTMLMediaElement
对象上,且该对象位于 Window
上下文中,如附加到媒体元素
算法所述。MediaSource 对象不是 Transferable;
它只在其被创建的上下文中可见。
本节其余部分描述了一个用于限制
Window
媒体元素与一个
DedicatedWorkerGlobalScope
MediaSource 关联时信息延迟的模型。
尽管该模型描述了使用消息传递进行通信,
实现可以选择以可能更快的方式通信,例如使用共享内存和锁。
连接到一个 Window
MediaSource 的附加是同步的,
因而无需跨上下文通信就已经拥有这些信息。
一个在 DedicatedWorkerGlobalScope
中构造的 MediaSource
具有一个 [[port to main]] 内部槽,
该槽存储一个在附加时设置、在分离时置空的 MessagePort。
一个 Window
[[port to main]] 始终为 null。
由本规范扩展并附加到一个
DedicatedWorkerGlobalScope
MediaSource 的
HTMLMediaElement
也同样具有一个 [[port to worker]] 内部槽,
该槽存储一个 MessagePort,
以及一个 [[channel with worker]]
内部槽,
该槽存储一个 MessageChannel,
两者都在附加时设置、在分离时置空。[[port to worker]] 和 [[channel with worker]]
只有在附加到一个 DedicatedWorkerGlobalScope
MediaSource 时才非空。
本规范中需要将信息从一个 Window
HTMLMediaElement
传送到一个已附加的 DedicatedWorkerGlobalScope
MediaSource,
或反过来传送的算法,
会隐式使用这些内部端口向其对应端发送消息,而消息的隐式处理器将按这些算法所描述的步骤运行。
将 MediaSource 附加到媒体元素有不同方式,取决于该 MediaSource 对象是在哪构造的:在 Window
中,还是在 DedicatedWorkerGlobalScope
中:
可以通过将构造于 Window
中的 MediaSource
所对应的 MediaSource 对象 URL 赋给
媒体
元素的 src
属性或媒体元素内 <source> 的 src 属性,来附加该
MediaSource。MediaSource 对象 URL 是
通过将 MediaSource 对象传递给 createObjectURL()
创建的。
尽管实现可以允许在
DedicatedWorkerGlobalScope
中,为构造于该 worker 中的 MediaSource
创建MediaSource 对象 URL,
但尝试使用该 MediaSource 对象 URL
通过 src
属性或媒体元素内
<source> 的 src 属性将其附加到媒体元素,必须在媒体
元素的资源
获取算法中失败,如下文扩展所述。
将对象 URL 附加机制扩展到 worker 的 MediaSource 对象 URL 会进一步传播这种相比使用 srcObject 更不推荐的用法, 并且会不必要地增加用户代理的互操作性风险和 实现复杂度。
DedicatedWorkerGlobalScope
中的 MediaSource,
只能通过使用
handle 从中获取一个句柄,将该 MediaSourceHandle
传输到 Window
上下文,并将其赋给媒体元素的 srcObject
属性来完成。
为了使本规范与 HTMLMediaElement
资源
加载和获取算法保持一致,底层 DedicatedWorkerGlobalScope
中的 MediaSource 就是其中提到的 MediaSource 对象,
而
MediaSourceHandle
对象就是媒体提供者对象。
如果 资源获取算法
的调用中,媒体提供者对象是一个 MediaSource 对象、一个 MediaSourceHandle
对象,或其对象为 MediaSource 的 URL 记录,则令模式为本地(local),跳过 资源获取算法
的第一步(否则可能将模式设为远程),并继续执行该 资源获取算法。
预期 资源获取算法
的第一步最终会与“当 URL 记录的对象是媒体提供者对象时选择本地模式”的行为一致。其意图是:如果 HTMLMediaElement
的
src
属性或选中的子
source
的
src
属性在最近一次变更时是与某个 MediaSource 对象 URL 匹配的
blob: URL,那么该 MediaSource 对象会在 资源获取算法
的本地模式逻辑中被用作媒体提供者对象和当前媒体资源。这也意味着当 MediaSource 对象被附加时,包含对 preload 属性考量的远程模式逻辑会被跳过。即便未来在 [HTML] 中做出上述改变,在当前媒体资源是 MediaSource 对象时,仍需要在本地模式逻辑开头执行下列步骤。
在 资源获取算法 “否则(模式为本地)”部分的开头,执行以下附加步骤。
相对于触发媒体元素资源选择算法的动作,这些步骤是异步的。资源获取算法 会在调用资源选择算法的任务被允许继续并达到稳定状态后运行。实现可以延迟“否则”子句中的步骤,直到 MediaSource 对象已准备好使用。
MediaSource 对象、一个 MediaSourceHandle
对象,或其对象为 MediaSource 的 URL 记录,则:
DedicatedWorkerGlobalScope
的 MediaSource(例如尝试使用来自
DedicatedWorkerGlobalScope
的 MediaSource 的
MediaSource 对象 URL 时)
MediaSource 的 handle 从
DedicatedWorker 传到 Window 上下文,并赋给媒体元素的 srcObject
属性,是附加此类 MediaSource 的唯一方式。
MediaSourceHandle,其
[[Detached]]
内部槽为 true
MediaSourceHandle,且其底层
MediaSource 的
[[has ever been attached]]
内部槽为 true
MediaSourceHandle
对同一底层 MediaSource 进行多次加载,即便该 MediaSource 是在
Window
中构造并且此前曾通过 MediaSource 对象
URL 加载。这并不妨碍随后对某个
Window
中的 MediaSource 使用 MediaSource 对象
URL 并成功。
readyState 不是
"closed"
MediaSource 的 [[has ever been attached]]
内部槽设为 true。
MediaSource 构造于
DedicatedWorkerGlobalScope,
则建立 worker 附加通信并打开该 MediaSource:
[[channel with worker]]
设置为一个新的
MessageChannel。
[[port to worker]]
设置为
port1
的值,该值来自 [[channel with worker]]。
port2
(来自 [[channel with worker]])
同时作为值和
transferList 的唯一成员,
并令结果为 serialized
port2。
MediaSource
的
DedicatedWorkerGlobalScope
上排入
一个任务,该任务将
DedicatedWorkerGlobalScope
的
领域,
并将 [[port to main]]
设置为
已传输的
port2
值的反序列化克隆,该值来自 [[channel with worker]]。
readyState
属性设置为
"open"。
MediaSource
上触发
一个事件,其名称为 sourceopen。
MediaSource 构造于 Window:
[[channel with worker]]
设为 null。
[[port to worker]]
设为 null。
[[port to main]]
设为 null。
readyState
属性设为
"open"。
sourceopen,
目标为
MediaSource。
appendBuffer()
传入的数据。
MediaSource
已附加时,HTMLMediaElement 不会通过 HTTP 获取媒体数据。
在媒体元素将要切换到
NETWORK_EMPTY
并排队一个任务以
触发事件
emptied
到媒体元素的任何情况下,运行以下步骤。这些步骤应当在切换之前立即运行。
MediaSource
构造于
DedicatedWorkerGlobalScope:
[[port to worker]]
发送内部 detach 消息,通知
MediaSource。
[[port to worker]]
设为 null。
[[channel with worker]]
设为 null。
detach 通知的隐式消息处理程序在
DedicatedWorkerGlobalScope
中的
MediaSource
上运行余下的步骤。
MediaSource
构造于
Window:
Window
的
MediaSource
上继续余下的步骤。
[[port to main]]
设为 null。
readyState 属性设为
"closed"。
ManagedMediaSource,
则将 streaming
属性设为 false。
duration 更新为 NaN。
activeSourceBuffers
中移除所有
SourceBuffer
对象。
removesourcebuffer 到
activeSourceBuffers。
sourceBuffers
中移除所有
SourceBuffer
对象。
removesourcebuffer 到
sourceBuffers。
sourceclose
到 MediaSource。
展望未来,当已附加的(如果有)MediaSource
必须从媒体元素解绑时,预期外部调用并运行此算法。除了或替代媒体元素切换到
NETWORK_EMPTY
的情形外,它可以在 HTMLMediaElement
[HTML]
的 load() 操作以及
资源获取算法
失败时被调用。资源获取算法失败是指中止资源获取算法或资源选择算法的那些情况,但“最终步骤”(Final step)
[HTML]
不视为触发解绑的失败。
作为 seek 算法 中“等待用户代理确定新播放位置的媒体数据是否可用;若可用,等待其已解码足够数据以播放该位置” 步骤的一部分,运行以下步骤:
媒体元素会在
SourceBuffer
对象(位于
activeSourceBuffers
中)中查找包含
媒体分段
的 new playback position。在当前
HTMLMediaElement
的
buffered
属性值中的任何
TimeRanges
范围内的位置,都已为该位置缓冲了所有必要的媒体分段。
TimeRanges
中(来自
HTMLMediaElement
的
buffered)
HTMLMediaElement
的
readyState
属性大于
HAVE_METADATA,
则将其
readyState
设为
HAVE_METADATA。
按照
HTMLMediaElement ready states
[HTML] 的逻辑,
HTMLMediaElement
的
readyState
变化可能触发该元素上的事件。
appendBuffer()
调用,使
编码帧处理
算法将
HTMLMediaElement
的
readyState
设为大于
HAVE_METADATA
的值。
Web 应用可以使用
buffered
以及
HTMLMediaElement
的
buffered
来判定媒体元素恢复播放所需的数据。
如果 readyState
属性为 "ended",
且 new playback position 位于当前
HTMLMediaElement
的
buffered
所含的某个
TimeRanges
中,那么即使一个或多个当前选中或启用的轨道缓冲区的最大范围结束时间戳小于 new playback position,
也必须在此继续完成 seek 操作。该情况应仅因
buffered
在 readyState
为 "ended" 时的逻辑而出现。
在播放过程中会定期运行以下步骤,以确保
SourceBuffer
对象(位于
activeSourceBuffers
中)具有
足够数据以确保不间断播放。
对 activeSourceBuffers
的更改也会触发这些步骤,因为它们影响触发状态转换的条件。
具有
足够数据以确保不间断播放
是实现相关的条件,用户代理判定其当前拥有足够数据,可在有意义的一段时间内不发生停顿地播放。该条件被持续评估,以确定何时将媒体元素在
HAVE_ENOUGH_DATA
就绪状态之间进行转换。这些转换指示用户代理何时认为已缓冲足够数据,或分别需要更多数据。
实现可以选择使用已缓冲字节数、已缓冲时间、追加速率或任何其他认为合适的度量来判断何时拥有足够数据。所用度量可以
在播放期间变化,因此 Web 应用应当仅依赖
HTMLMediaElement
的
readyState
的值来判定是否需要更多数据。
当媒体元素需要更多数据时,用户代理应当及时将其从
HAVE_ENOUGH_DATA
切换到
HAVE_FUTURE_DATA,
以便 Web 应用能够在不造成播放中断的情况下响应。例如,当当前播放位置距离已缓冲数据的末尾还有 500ms 时进行切换,
可为应用留出约 500ms 的时间追加更多数据,以避免播放停顿。
HTMLMediaElement
的
readyState
属性等于
HAVE_NOTHING:
HTMLMediaElement
的
buffered
不包含覆盖当前播放位置的
TimeRanges:
HTMLMediaElement
的
readyState
属性设为
HAVE_METADATA。
按照
HTMLMediaElement ready states
[HTML] 的逻辑,
HTMLMediaElement
的
readyState
变化可能触发该元素上的事件。
HTMLMediaElement
的
buffered
包含覆盖当前播放位置的
TimeRanges
且具有
足够数据以确保不间断播放:
HTMLMediaElement
的
readyState
属性设为
HAVE_ENOUGH_DATA。
按照
HTMLMediaElement ready states
[HTML] 的逻辑,
HTMLMediaElement
的
readyState
变化可能触发该元素上的事件。
HAVE_CURRENT_DATA
而暂停播放,则此时可能恢复播放。
HTMLMediaElement
的
buffered
包含覆盖当前播放位置并向后延伸一段时间的
TimeRanges,
则运行以下步骤:
HTMLMediaElement
的
readyState
属性设为
HAVE_FUTURE_DATA。
按照
HTMLMediaElement ready states
[HTML] 的逻辑,
HTMLMediaElement
的
readyState
变化可能触发该元素上的事件。
HAVE_CURRENT_DATA
而暂停播放,则此时可能恢复播放。
HTMLMediaElement
的
buffered
包含的
TimeRanges
正好在当前播放位置结束,且在当前位置之后没有覆盖的范围:
HTMLMediaElement
的
readyState
属性设为
HAVE_CURRENT_DATA。
按照
HTMLMediaElement ready states
[HTML] 的逻辑,
HTMLMediaElement
的
readyState
变化可能触发该元素上的事件。
在播放过程中,如果
activeSourceBuffers 需要更新,
这是因为
selected
视频轨道、enabled
音频轨道,或
文本轨道的 mode
发生了变化。当这些变化中的一个或多个发生时,
需要遵循以下步骤。由于 AudioTrack、
VideoTrack
以及
TextTrack
对象及其 AudioTrackList、
VideoTrackList
和
TextTrackList
只在 Window
HTMLMediaElement
上暴露,
因此这些变化
总是发生在 Window
上下文中。当 MediaSource 在
DedicatedWorkerGlobalScope
中构造时,
则每一次此类变化必须通过发送到
[[port to worker]] 的内部
update track state 消息传达给
DedicatedWorkerGlobalScope,
其隐式处理器将针对创建受影响轨道的
SourceBuffer
执行以下步骤。当
MediaSource 在
Window
中构造时,
以下步骤直接执行。
SourceBuffer
不与任何其他已启用轨道关联,则执行以下步骤:
SourceBuffer 从 activeSourceBuffers
中移除。
activeSourceBuffers
上触发事件,事件名为 removesourcebuffer
SourceBuffer
尚未在 activeSourceBuffers
中,则执行以下步骤:
SourceBuffer 添加到 activeSourceBuffers
中。
activeSourceBuffers
上触发事件,事件名为 addsourcebuffer
SourceBuffer
不与任何其他已启用或已选中轨道关联,则执行以下步骤:
SourceBuffer 从
activeSourceBuffers
中移除
activeSourceBuffers
上触发事件,事件名为 removesourcebuffer
SourceBuffer
尚未在 activeSourceBuffers 中,
则执行以下步骤:
SourceBuffer
添加到
activeSourceBuffers
中
activeSourceBuffers
上触发事件,事件名为 addsourcebuffer
mode
变为
"disabled"
并且与该轨道关联的 SourceBuffer
不与任何其他
已启用或已选中轨道关联,则执行以下步骤:
SourceBuffer
从
activeSourceBuffers
中移除
activeSourceBuffers
上触发事件,事件名为 removesourcebuffer
mode
变为
"showing"
或
"hidden"
并且与该轨道关联的 SourceBuffer
尚未在 activeSourceBuffers 中,
则执行以下步骤:
SourceBuffer
添加到
activeSourceBuffers
中
activeSourceBuffers
上触发事件,事件名为 addsourcebuffer
当 duration 需要变为一个 新的
时长 时,按以下步骤执行。
duration 的值
等于 新的时长,则
返回。
SourceBuffer 对象的
sourceBuffers 中所有已缓冲
编码帧 的最高
呈现时间戳,则抛出一个
InvalidStateError
异常并中止
这些步骤。
SourceBuffer 对象的
sourceBuffers 中。
之所以会出现此条件,是因为 编码帧移除 算法会保留那些在移除范围起始之前开始的编码帧。
duration 更新为 新的时长。
Window
中执行以下步骤,以更新媒体元素的时长:
duration
更新为 新的时长。
当应用通过调用
endOfStream()
表示流结束,或者某个算法需要表示解码错误时,就会调用此算法。该
算法接受一个 error 参数,用于指示是否
将要发出错误信号。
readyState 属性值更改为
"ended"。
MediaSource 上触发一个
事件,事件名为 sourceended。
SourceBuffer 对象,
这些对象位于 sourceBuffers
中。
这可以使时长正确反映已附加媒体片段的末尾。例如,如果时长被显式设置为 10 秒, 而在调用 endOfStream() 之前只附加了 0 到 5 秒的媒体片段,那么时长将被更新为 5 秒。
network"
Window
中运行以下步骤:
HTMLMediaElement
的
readyState 属性
等于 HAVE_NOTHING
HTMLMediaElement
的
readyState 属性大于
HAVE_NOTHING
decode"
Window
中运行以下步骤:
HTMLMediaElement
的
readyState 属性
等于 HAVE_NOTHING
HTMLMediaElement
的
readyState 属性大于
HAVE_NOTHING
此算法用于从附加自
同一 Window
或 DedicatedWorkerGlobalScope
的 MediaSource 中,在
Window
上运行步骤,通常用于更新
所附加 HTMLMediaElement
的状态。
此算法接受一个 steps
参数,其中列出了要在 Window
上运行的步骤。
MediaSource 是在 DedicatedWorkerGlobalScope
中构造的:
[[port to main]] 发送一个内部
mirror on window 消息,其在 Window
中的隐式处理器将运行 steps。在该处理器收到消息之前,
将控制权返回给调用者,而不等待它。
Window
上的独立任务异步运行,而不是让这些
steps 以某种方式发生在其他 Window
任务执行的中间,并且
DedicatedWorkerGlobalScope
上
的同步执行和返回不会被阻塞。
MediaSourceHandle 接口表示一个代理,
该代理对应一个 MediaSource 对象,
它可用于通过 srcObject
将一个来自 DedicatedWorkerGlobalScope
的 MediaSource
附加到一个位于 Window
中的 HTMLMediaElement,
如 附加到媒体元素
算法所述。
之所以需要这个独立对象,是因为要将跨上下文的 MediaSource 附加到媒体
元素上;因为 MediaSource 对象本身
不是可传输的,原因是它们是事件目标。
每个 MediaSourceHandle 对象有一个 [[has ever
been assigned as srcobject]] 内部槽,存储一个 boolean。该槽在 MediaSourceHandle 对象创建时初始化为 false,在
扩展的 HTMLMediaElement
的 srcObject
setter(见 10.
HTMLMediaElement 扩展)中设置为 true,
若为 true,则会阻止该 MediaSourceHandle 的成功传递,具体见
4.1
传递。
MediaSourceHandle 对象是 Transferable,
每个对象有一个 [[Detached]] 内部槽,用于保证该实例在被传递后不可再次传递。
WebIDL[Transferable, Exposed=(Window,DedicatedWorker)]
interface MediaSourceHandle {};
MediaSourceHandle 的 传输步骤
和 传输接收
步骤 要求
实现维护一个隐式内部槽,该槽引用底层的
MediaSource,以便通过
srcObject
实现 附加到媒体元素
,并随后为该附加建立 跨上下文通信模型。
实现者应当注意,
Transferable
所暗示的“移动”语义并不总是符合实际情况。例如,扩展或内部
使用广播实现 postMessage 的方式可能会导致已传输的 MediaSourceHandle
意外出现多个接收者。
因此,建议实现在底层 MediaSource 对象的任一句柄
被用于媒体元素资源选择算法的异步部分之前,不要
确定已传输的 MediaSourceHandle
的哪个潜在克隆仍然有效
并可用于附加。
这类似于现有通过MediaSource 对象 URL
进行附加的行为,这类 URL 可以轻易克隆,而这样的 URL 最多只对一次附加开始有效
(跨其所有可能存在的多个克隆)。
实现必须支持:对于作为
MediaSourceHandle 底层对象的
MediaSource 对象,
通过 srcObject
进行的附加(加载)在任何情况下最多只能成功一次,
不受由于 Transferable
的不同实现而导致的 MediaSourceHandle
潜在克隆影响。
关于这一点如何在媒体元素资源选择算法的异步部分中强制执行,请参见 附加到媒体元素。
MediaSourceHandle 仅在 Window
和 DedicatedWorkerGlobalScope
上下文中暴露,并且不能在不同的 agent
clusters [ECMASCRIPT] 之间成功传输。
MediaSourceHandle 对象的传输只能在同一个
agent
cluster 内成功。
例如,从 Window
或
DedicatedWorkerGlobalScope
向 SharedWorker 或 ServiceWorker 传输一个 MediaSourceHandle 对象将不会成功。
开发者应当注意,这与 MediaSource 对象 URL 的区别在于,
后者是可以通过多种方式通信的 DOMString。
即便如此,使用 附加到媒体元素 并通过 MediaSource 对象 URL 进行附加,
也只能对一个在 Window
上下文中构造的 MediaSource 成功。
另请参见 Web Application APIs 中 agent 与 agent cluster 形式化的集成 [HTML],其中定义了诸如 专用 worker
agent
等相关概念。
传输步骤
对于一个 MediaSourceHandle 对象
必须包括以下步骤:
MediaSourceHandle 的
[[has ever been assigned as srcobject]]
内部槽为 true,则 传输步骤
必须通过抛出一个 DataCloneError 异常而失败。
WebIDLenum AppendMode {
"segments",
"sequence",
};
segments
sequence
timestampOffset 属性。设置 "sequence" 模式下的 timestampOffset
属性,可以让媒体分段放到时间线上的指定位置,而无需了解分段内时间戳。
WebIDL[Exposed=(Window,DedicatedWorker)]
interface SourceBuffer : EventTarget {
attribute AppendMode mode;
readonly attribute boolean updating;
readonly attribute TimeRanges buffered;
attribute double timestampOffset;
[Exposed=Window] readonly attribute AudioTrackList audioTracks;
[Exposed=Window] readonly attribute VideoTrackList videoTracks;
[Exposed=Window] readonly attribute TextTrackList textTracks;
attribute double appendWindowStart;
attribute unrestricted double appendWindowEnd;
attribute EventHandler onupdatestart;
attribute EventHandler onupdate;
attribute EventHandler onupdateend;
attribute EventHandler onerror;
attribute EventHandler onabort;
undefined appendBuffer(BufferSource data);
undefined abort();
undefined changeType(DOMString type);
undefined remove(double start, unrestricted double end);
};
audioTracks、videoTracks 和
textTracks 属性只对
Window
上下文暴露。当一个
SourceBuffer 由 DedicatedWorkerGlobalScope
使用时,其轨道则会在它所附加到的
Window
HTMLMediaElement
上创建并归其所有,如 初始化段
已接收 算法所述。
mode 的
类型为 AppendMode
控制一系列 媒体段 的处理方式。该属性
在对象创建后由 addSourceBuffer()
初始设置,并且可以通过 changeType() 或
设置此属性来更新。
在获取时,返回初始值或最近一次成功设置的值。
在设置时,运行以下步骤:
sourceBuffers 属性所指向的
父 media source 中移除,则抛出一个 InvalidStateError
异常并中止这些步骤。
updating 属性等于
true,则抛出一个
InvalidStateError
异常并中止这些步骤。
[[generate timestamps flag]]
等于 true 且 新模式
等于 "segments",则抛出一个 TypeError
异常并中止
这些步骤。
如果 readyState 属性
属于
父 media source,且处于
"ended" 状态,则运行以下步骤:
readyState 属性
设为 父 media source
的 "open"。
sourceopen
的事件触发到 父 media source 上。
[[append state]]
等于 PARSING_MEDIA_SEGMENT,则
抛出一个 InvalidStateError
并中止这些步骤。
sequence",则将
[[group start timestamp]]
设为
[[group end timestamp]]。
updating 的类型为 boolean,
只读
指示 appendBuffer()
或 remove()
操作的异步后续处理是否仍在进行中。该属性在对象创建时初始设为 false。
buffered 的类型为 TimeRanges,
只读
指示该 SourceBuffer 中缓冲了哪些
TimeRanges。
该属性在对象创建时初始设为空的
TimeRanges
对象。
读取该属性时,必须执行以下步骤:
sourceBuffers 属性所指向的
父 media source 中移除,则抛出一个 InvalidStateError
异常并中止这些步骤。
SourceBuffer 对象管理的
轨道缓冲范围 的最大结束时间,
其遍及所有 轨道缓冲区。
TimeRanges
对象。
SourceBuffer
所管理的每个音频和视频 轨道缓冲区,执行以下步骤:
文本 轨道缓冲区 也包含在上方 最高结束时间 的计算中, 但在这里的缓冲范围计算中被排除。它们不一定是连续的,也不应因其中的任何不连续而在其他媒体轨道在相同时间范围内连续时触发播放停顿。
readyState 是 "ended",则将
track ranges 中最后一个范围的结束
时间设置为 highest end time。
timestampOffset 的类型为 double
控制随后追加到该 SourceBuffer 的后续
媒体段
中时间戳所应用的偏移量。timestampOffset
初始设为 0,表示不应用偏移。
在获取时,返回初始值或最近一次成功设置的值。
在设置时,运行以下步骤:
sourceBuffers 属性所指向的
父 media source 中移除,则抛出一个 InvalidStateError
异常并中止这些步骤。
updating 属性等于
true,则抛出一个 InvalidStateError
异常并中止这些步骤。
如果 readyState 属性
所属的 父 media source 处于
"ended" 状态,则运行以下步骤:
readyState 属性
设为 父 media source
的 "open"。
sourceopen
的事件触发到 父 media source 上。
[[append state]]
等于 PARSING_MEDIA_SEGMENT,则
抛出一个 InvalidStateError
并中止这些步骤。
mode 属性等于 "sequence",则将
[[group start timestamp]]
设为 新 timestamp offset。
audioTracks 的类型为 AudioTrackList,
只读
AudioTrack
对象列表。该属性只对 Window
上下文暴露;当 SourceBuffer 在 DedicatedWorkerGlobalScope
中创建时不可用。
videoTracks 的类型为 VideoTrackList,
只读
VideoTrack
对象列表。该属性只对 Window
上下文暴露;当 SourceBuffer 在 DedicatedWorkerGlobalScope
中创建时不可用。
textTracks 的类型为 TextTrackList,
只读
TextTrack
对象列表。该属性只对 Window
上下文暴露;当 SourceBuffer 在 DedicatedWorkerGlobalScope
中创建时不可用。
appendWindowStart 的类型为 double
呈现时间戳,表示 追加窗口 的开始。该属性 初始设为 呈现开始时间。
在获取时,返回初始值或最近一次成功设置的值。
在设置时,运行以下步骤:
sourceBuffers 属性所指向的
父 media source 中移除,则抛出一个 InvalidStateError
异常并中止这些步骤。
updating 属性等于
true,则抛出一个
InvalidStateError
异常并中止这些步骤。
appendWindowEnd,则
抛出一个 TypeError
异常并中止这些
步骤。
appendWindowEnd 的类型为 unrestricted double
呈现时间戳,表示 追加窗口 的结束。该属性 初始设为正无穷大。
在获取时,返回初始值或最近一次成功设置的值。
在设置时,运行以下步骤:
sourceBuffers 属性所指向的
父 media source 中移除,则抛出一个 InvalidStateError
异常并中止这些步骤。
updating 属性等于
true,则抛出一个
InvalidStateError
异常并中止这些步骤。
TypeError
并中止这些步骤。
appendWindowStart,则
抛出一个 TypeError
异常并中止这些步骤。
onupdatestart 的类型为 EventHandler
updatestart 事件的事件处理器。
onupdate 的类型为 EventHandler
update 事件的事件处理器。
onupdateend 的类型为 EventHandler
updateend 事件的事件处理器。
onerror 的类型为 EventHandler
error 事件的事件处理器。
onabort 的类型为 EventHandler
abort 事件的事件处理器。
appendBuffer
将
BufferSource[WEBIDL] 中的段数据追加到
SourceBuffer。
调用此方法时,用户代理必须运行以下步骤:
[[input buffer]]的末尾。
updating属性设置为 true。
SourceBuffer 对象上触发一个事件,其名称为updatestart。
abort
中止当前段并重置段解析器。
调用此方法时,用户代理必须运行以下步骤:
sourceBuffers属性
中移除,则抛出一个InvalidStateError
异常并
中止这些步骤。
readyState属性
不处于 "open" 状态,则抛出一个InvalidStateError
异常
并中止这些步骤。
InvalidStateError
异常并中止这些步骤。
updating属性等于
true,则运行以下
步骤:
updating属性设置为
false。
SourceBuffer 对象上触发一个事件,其名称为
abort。
SourceBuffer 对象上触发一个事件,其名称为
updateend。
appendWindowStart设置为
呈现开始时间。
appendWindowEnd设置为
正无穷大。
changeType
更改与此对象关联的 MIME 类型。后续
appendBuffer()
调用将预期新追加的字节符合
新类型。
调用此方法时,用户代理必须运行以下步骤:
TypeError
异常并
中止这些步骤。
sourceBuffers属性
中移除,则抛出一个InvalidStateError
异常并
中止这些步骤。
updating属性等于
true,则抛出一个
InvalidStateError
异常并中止这些步骤。
sourceBuffers属性中
SourceBuffer 对象当前或之前指定的类型
一起使用时不受支持的 MIME 类型,则抛出一个NotSupportedError
异常并中止这些
步骤。
如果父媒体源的readyState属性
处于
"ended" 状态,则运行以下步骤:
readyState属性
设置为 "open"。
sourceopen。
SourceBuffer
对象上的[[generate timestamps flag]]
更新为字节流
格式注册表 [MSE-REGISTRY]
中与 type 关联的条目里的“生成时间戳标志”列中的值。
[[generate timestamps flag]]
等于 true:
SourceBuffer 对象上的mode属性设置为
"sequence",包括
运行设置该
属性所关联的步骤。
SourceBuffer 对象上的mode
属性的先前值,而不
运行设置该
属性所关联的任何步骤。
SourceBuffer
对象上的[[pending initialization segment for changeType flag]]
设置为 true。
remove
移除特定时间范围内的媒体。移除范围的 start,以从呈现开始时间起测量的秒数 表示。移除范围的 end,以从呈现开始时间起测量的秒数 表示。
调用此方法时,用户代理必须运行以下步骤:
sourceBuffers属性
中移除,则抛出一个InvalidStateError
异常并
中止这些步骤。
updating属性等于
true,则抛出一个
InvalidStateError
异常并中止这些步骤。
duration等于 NaN,则抛出
一个TypeError
异常并
中止这些步骤。
duration,则
抛出一个TypeError
异常并中止这些步骤。
TypeError
异常并中止这些步骤。
如果父媒体源的readyState属性
处于
"ended" 状态,则运行以下步骤:
readyState属性
设置为 "open"
sourceopen。
轨道缓冲区存储单个轨道的轨道
描述和编码帧。当初始化段和媒体段被追加到SourceBuffer时,轨道缓冲区会
随之更新。
每个轨道缓冲区都有一个最后解码时间戳 变量,用于存储当前编码帧组中最后追加的编码帧的解码时间戳,该 当前编码帧组。该变量最初为未设置状态,以 表示尚未追加任何 编码帧。
每个轨道缓冲区都有一个最后帧持续时间 变量,用于存储当前编码帧持续时间组中最后一个被追加的编码帧的编码帧持续时间,该组为 当前编码帧组。该变量最初为未设置状态,以 表示尚未追加任何 编码帧。
每个轨道缓冲区都有一个最高结束时间戳 变量,用于存储当前编码帧结束时间戳组中所有编码帧里最高的编码帧结束时间戳,这些编码帧位于当前编码帧 组中,并已追加到此轨道缓冲区。 该变量最初为未设置状态,以表示尚未追加任何编码帧 。
每个轨道缓冲区都有一个需要随机访问点标志 变量,用于跟踪轨道缓冲区是否正在等待一个随机访问点编码帧。该 变量最初设置为 true,以表示在任何内容可以添加到轨道缓冲区之前,需要一个随机访问 点编码帧。
每个轨道缓冲区都有一个轨道缓冲区范围 变量,用于表示当前存储在轨道缓冲区中的编码帧 所占据的呈现时间范围。
对于轨道缓冲区范围,这些呈现时间范围基于呈现时间戳、帧持续时间,以及
复用SourceBuffer中跨轨道缓冲区的编码
帧组可能具有的编码帧组开始时间。
出于规范目的,此信息被视为如同存储在
规范化
TimeRanges 对象中。相交后的轨道缓冲区范围用于
报告HTMLMediaElement的
buffered,
因此必须
支持在HTMLMediaElement的
buffered的每个范围内不间断播放。
| 事件名称 | 接口 | 在……时触发 |
|---|---|---|
| updatestart |
Event
|
SourceBuffer 的 updating 从
false 变为 true。
|
| update |
Event
|
SourceBuffer 的
追加或移除成功完成。SourceBuffer 的
updating 从
true 变为 false。
|
| updateend |
Event
|
SourceBuffer 的追加或移除结束。
|
| error |
Event
|
在向 SourceBuffer
追加期间发生错误。
updating
从 true 变为 false。
|
| abort |
Event
|
SourceBuffer 的
追加被一个 abort() 调用中止。
updating 从
true 变为 false。
|
每个 SourceBuffer 对象都有一个 [[append
state]] 内部槽,用于跟踪高层级的分段解析状态。
它在初始时设为 WAITING_FOR_SEGMENT,
并且随着数据追加可以转换到下列
状态。
| 追加状态名称 | 描述 |
|---|---|
| WAITING_FOR_SEGMENT | 等待要追加的 初始化段 或 媒体段 的开始。 |
| PARSING_INIT_SEGMENT | 正在解析一个 初始化段。 |
| PARSING_MEDIA_SEGMENT | 正在解析一个 媒体段。 |
每个 SourceBuffer 对象都有一个 [[input
buffer]] 内部槽,它是一个字节缓冲区,用于在多次
appendBuffer()
调用之间保存未解析的字节。
该缓冲区在 SourceBuffer
对象创建时为空。
每个 SourceBuffer 对象都有一个 [[buffer full
flag]] 内部槽,用于跟踪
appendBuffer()
是否允许接受更多字节。它在 SourceBuffer 对象创建时设为
false,
并在数据追加和移除时更新。
每个 SourceBuffer 对象都有一个 [[audio track
added flag]] 内部槽,用于跟踪是否已经为该 AudioTrack
为该 SourceBuffer 对象创建过一个轨道。它在
SourceBuffer 对象创建时设为 false,并由
初始化段
已接收 算法用于确定新创建的 AudioTrack
是否默认处于 enabled
状态。
每个 SourceBuffer 对象都有一个 [[video track
added flag]] 内部槽,用于跟踪是否已经为该 VideoTrack
为该 SourceBuffer 对象创建过一个轨道。它在
SourceBuffer 对象创建时设为 false,并由
初始化段
已接收 算法用于确定新创建的 VideoTrack
是否默认处于 selected
状态。
每个 SourceBuffer 对象都有一个 [[group start
timestamp]] 内部槽,用于跟踪在 "sequence" 模式下一个新的
编码帧组 的起始时间戳。该槽在
SourceBuffer 对象创建时未设置,并会在 mode
属性等于 "sequence" 且 timestampOffset
属性被设置时,或者在 编码帧处理
算法运行时更新。
每个 SourceBuffer 对象都有一个 [[group end
timestamp]] 内部槽,用于存储当前
编码帧组 中所有
编码帧 的最高
编码帧结束时间戳。
它在 SourceBuffer 对象创建时设为 0,并由
编码帧处理
算法更新。
[[group end timestamp]] 存储
SourceBuffer 中所有轨道缓冲区里的最高编码帧结束
时间戳。因此,在追加各轨道间时间戳未对齐的复用
段时,应谨慎设置mode 属性。
每个 SourceBuffer 对象都有一个 [[generate timestamps
flag]] 内部槽,它是一个布尔值,用于跟踪是否需要为传递给
编码帧处理
算法的 编码帧 生成时间戳。该标志在
addSourceBuffer()
创建 SourceBuffer 对象时设置,并由
changeType() 更新。
当调用 segment parser loop 算法时,运行以下步骤:
[[input buffer]] 为空,则跳转到下面的
需要更多数据 步骤。
[[input buffer]]
包含违反
SourceBuffer 字节流格式规范
的字节,则运行 append
error
算法并中止此算法。
[[input buffer]]
的开头移除任何字节,
这些字节是 字节流格式规范 指定必须忽略的。
如果 [[append state]]
等于 WAITING_FOR_SEGMENT,则运行以下步骤:
[[input buffer]] 的开头指示
一个 初始化段 的开始,则将
[[append state]] 设为
PARSING_INIT_SEGMENT。
[[input buffer]] 的开头指示
一个 媒体段 的开始,则将
[[append state]] 设为
PARSING_MEDIA_SEGMENT。
如果 [[append state]]
等于 PARSING_INIT_SEGMENT,则运行以下步骤:
[[input buffer]] 还不包含完整的
初始化段,
则跳转到下面的 需要更多数据 步骤。
[[input buffer]] 的开头移除
初始化段 字节。
[[append state]] 设为
WAITING_FOR_SEGMENT。
如果 [[append state]]
等于 PARSING_MEDIA_SEGMENT,则运行以下步骤:
[[first initialization segment received flag]]
为 false,或者 [[pending initialization segment for changeType flag]]
为
true,则运行 append error 算法并
中止此算法。
[[input buffer]] 包含一个或多个完整的
编码帧,则运行
编码帧处理 算法。
编码帧处理算法运行的频率由实现决定。编码帧处理算法可以在输入缓冲区包含完整媒体段时调用, 也可以在完整编码帧加入输入缓冲区时多次调用。
SourceBuffer
已满且无法再接受更多媒体数据,则将
[[buffer full flag]] 设为 true。
[[input buffer]] 还不包含完整的
媒体段,则跳转到下面的
需要更多数据 步骤。
[[input buffer]] 的开头移除
媒体段 字节。
[[append state]] 设为
WAITING_FOR_SEGMENT。
当需要重置解析器状态时,执行以下步骤:
[[append state]]
等于 PARSING_MEDIA_SEGMENT 并且
[[input buffer]]
包含一些完整的 编码帧,则运行
编码帧处理算法,直到所有这些完整的
编码帧
都被处理完毕。
mode 属性等于 "sequence",则将
[[group start timestamp]] 设置为
[[group end timestamp]]
[[input buffer]]
中的所有字节。
[[append state]] 设置为
WAITING_FOR_SEGMENT。
当追加过程中发生错误时调用此算法。
updating 属性设为 false。
SourceBuffer
对象上触发一个
事件,事件名为 error。
updateend,触发于此 SourceBuffer
对象上。
decode"。
当追加操作开始时,将运行以下步骤来验证并准备
SourceBuffer。
SourceBuffer 已从
sourceBuffers
属性所对应的 父 media source 中移除,则抛出
一个 InvalidStateError
异常
并中止这些步骤。
updating 属性等于 true,
则抛出一个
InvalidStateError
异常并中止这些步骤。
MediaSource 是在
Window
HTMLMediaElement
的
error 属性不为 null,则令
recent element error 为 true。若该属性为 null,则令
recent element error 为 false。
Window
情况下的步骤所得到的结果,但要在 Window
HTMLMediaElement
的 error 属性发生任何变化时,
并通过 [[port to worker]] 隐式消息进行通信。
如果尚未收到此类消息,则令 recent element error 为 false。
InvalidStateError
异常
并中止这些步骤。
如果 readyState 属性属于
父 media source,且处于
"ended" 状态,则运行以下步骤:
readyState 属性设为
父 media source 的
"open"
sourceopen 的事件触发到
父 media source 上。
如果 [[buffer full flag]] 等于 true,
则抛出一个
QuotaExceededError
异常并中止这些步骤。
这是实现无法清理出足够数据以容纳此次追加,或者追加内容太大的信号。
Web 应用应当使用
remove()
来显式释放空间和/或减小追加内容的大小。
当调用 appendBuffer()
时,执行以下步骤处理追加的数据。
updating 属性设为 false。
SourceBuffer
对象上触发一个
事件,事件名为 update。
updateend,触发于此 SourceBuffer
对象上。
当调用者需要发起一个 JavaScript 可见的范围移除操作(该操作会阻塞其它 SourceBuffer 更新)时,按照以下步骤进行:
updating 属性设为 true。
SourceBuffer 对象上触发一个
事件,事件名为 updatestart。
updating 属性设为 false。
update,触发于此 SourceBuffer
对象上。
updateend,触发于此 SourceBuffer
对象上。
当 分段解析循环 成功解析出一个完整的 初始化分段 时,运行以下步骤:
每个 SourceBuffer 对象都有一个用于跟踪是否已经由该算法追加并接收到首个 初始化分段 的内部插槽 [[first initialization segment received flag]]。该标志在创建 SourceBuffer 时被设为 false,并由下述算法进行更新。
每个 SourceBuffer 对象都有一个用于跟踪自最近一次 changeType() 起是否需要 初始化分段 的内部插槽 [[pending
initialization segment for changeType flag]]。该标志在创建 SourceBuffer 时设为 false,由 changeType() 设为
true,并由下述算法重置为 false。
duration 属性当前
等于 NaN,则更新该属性:
[[first initialization segment received flag]]
为 true,
则运行以下步骤:
如果原本受支持的编解码器未在传递给以下调用的 type
参数中指定,则用户代理可以在此将这些编解码器视为“不
受支持”:(a) 此 SourceBuffer
对象上最近一次成功的
changeType(),
或 (b) 如果此对象上尚未发生过
成功的 changeType(),
则为创建此 SourceBuffer
对象的 addSourceBuffer()。
例如,如果最近一次成功的
changeType()
是以 'video/webm' 或
'video/webm; codecs="vp8"' 调用的,而初始化段中出现了包含
vp9 的视频轨道,则即使上述另外两个属性检查
均通过,用户代理也可以使用此步骤
触发解码错误。建议实现仅在编解码器确实不受支持或另外两个属性
检查
失败时才在这些情况下触发错误。建议 Web 作者使用 changeType()、
addSourceBuffer()
和 isTypeSupported()
并使用精确的编解码器参数,以更主动地检测用户代理
支持情况。如果 SourceBuffer
对象的字节流格式正在发生变化,则必须调用 changeType()。
如果 [[first initialization segment received flag]]
为 false,
则运行以下步骤:
如果原本受支持的编解码器未在传递给以下调用的 type 参数
中指定,则用户代理可以在此将这些编解码器视为“不
受支持”:(a) 此 SourceBuffer 对象上最近一次成功的
changeType(),
或
(b) 如果此对象上尚未发生过成功的
changeType(),则为
创建此 SourceBuffer 对象的
addSourceBuffer()。
例如,
MediaSource.isTypeSupported('video/webm;codecs="vp8,vorbis"')
可能返回 true,但如果调用 addSourceBuffer()
时使用了
'video/webm;codecs="vp8"',而初始化段中出现了 Vorbis 轨道,则
用户代理可以使用此步骤触发解码
错误。
建议实现仅在该编解码器确实不受支持时才在这种情况下触发错误。建议 Web 作者使用
changeType()、
addSourceBuffer()
和
isTypeSupported()
并使用精确的编解码器参数,以更
主动地检测用户代理支持情况。如果 SourceBuffer 对象的
字节流格式正在发生变化,则必须调用 changeType()。
对初始化段中的每个音频轨道,运行 以下步骤:
SourceBuffer
对象的 [[audio track added flag]]
内部槽为 false,则运行以下步骤:
SourceBuffer
对象的 [[audio track added flag]]
内部槽设置为 true。
在 Window
HTMLMediaElement
上创建
AudioTrack,
并在 Window
中运行
以下步骤:
Window
中构造的:
AudioTrack
对象。
id
属性。
language、
label
和
kind
属性。
enabled
属性设置为 true。
SourceBuffer
对象上的 audioTracks
属性。
这应当触发 AudioTrackList
[HTML]
逻辑,以排入
一个任务,在此 audioTracks
属性所引用的 AudioTrackList
对象上,使用
TrackEvent
触发
一个事件,其名称为 addtrack,
并将 track
属性初始化为
new audio
track。该 audioTracks
属性位于此 SourceBuffer
对象上。
SourceBuffer
对象的父媒体
源所附加到的媒体元素。
audioTracks
属性。
这应当触发 AudioTrackList
[HTML]
逻辑,以排入
一个任务,在 media
element 上的 audioTracks
属性所引用的 AudioTrackList
对象上,使用
TrackEvent
触发
一个事件,其名称为 addtrack,
并将 track
属性初始化为
new audio
track。
[[port to main]]
发送一条内部 create track 消息,其在 Window
中的隐式处理程序运行以下步骤:
AudioTrack
对象。
id
属性。
language、
label
和
kind
属性。
enabled
属性设置为 true。
SourceBuffer
对象的父媒体
源所附加到的媒体元素。
audioTracks
属性。
这应当触发 AudioTrackList
[HTML]
逻辑,以排入
一个任务,在 media
element 上的 audioTracks
属性所引用的 AudioTrackList
对象上,使用
TrackEvent
触发
一个事件,其名称为 addtrack,
并将 track
属性初始化为
new audio
track。
对初始化段中的每个视频轨道,运行 以下步骤:
SourceBuffer
对象的 [[video track added flag]]
内部槽为 false,则运行以下步骤:
SourceBuffer
对象的 [[video track added flag]]
内部槽设置为 true。
在 Window
HTMLMediaElement
上创建
VideoTrack,
并在 Window
中运行
以下步骤:
Window
中构造的:
VideoTrack
对象。
id
属性。
language、
label
和
kind
属性。
selected
属性设置为 true。
SourceBuffer
对象上的 videoTracks
属性。
这应当触发 VideoTrackList
[HTML]
逻辑,以排入
一个任务,在此 videoTracks
属性所引用的
VideoTrackList
对象上,使用
TrackEvent
触发
一个事件,其名称为 addtrack,
并将 track
属性初始化为
new video
track。该 videoTracks
属性位于此 SourceBuffer
对象上。
SourceBuffer
对象的父媒体
源所附加到的媒体元素。
videoTracks
属性。
这应当触发 VideoTrackList
[HTML]
逻辑,以排入
一个任务,在 media
element 上的 videoTracks
属性所引用的 VideoTrackList
对象上,使用
TrackEvent
触发
一个事件,其名称为 addtrack,
并将 track
属性初始化为
new video
track。
[[port to main]]
发送一条内部 create track 消息,其在 Window
中的隐式处理程序运行以下步骤:
VideoTrack
对象。
id
属性。
language、
label
和
kind
属性。
selected
属性设置为 true。
SourceBuffer
对象的父媒体
源所附加到的媒体元素。
videoTracks
属性。
这应当触发 VideoTrackList
[HTML]
逻辑,以排入
一个任务,在 media
element 上的 videoTracks
属性所引用的 VideoTrackList
对象上,使用
TrackEvent
触发
一个事件,其名称为 addtrack,
并将 track
属性初始化为
new video
track。
对初始化段中的每个文本轨道,运行 以下步骤:
mode
值。
"showing"
或
"hidden",
则将 active track flag 设置为
true。
在 Window
HTMLMediaElement
上创建
TextTrack,
并在 Window
中运行
以下步骤:
Window
中构造的:
TextTrack
对象。
id
属性。
language、
label
和
kind
属性。
mode
属性设置为 text
track mode,并使用从
此轨道的初始化
段中确定的适当信息填充 new text
track 上的其余属性。
SourceBuffer
对象上的 textTracks
属性。
这应当触发 TextTrackList
[HTML]
逻辑,以排入
一个任务,在此 textTracks
属性所引用的
TextTrackList
对象上,使用
TrackEvent
触发
一个事件,其名称为 addtrack,
并将 track
属性初始化为
new text track。
该 textTracks
属性位于此 SourceBuffer
对象上。
SourceBuffer
对象的父媒体
源所附加到的媒体元素。
textTracks
属性。
这应当触发 TextTrackList
[HTML]
逻辑,以排入
一个任务,在 media
element 上的 textTracks
属性所引用的 TextTrackList
对象上,使用
TrackEvent
触发
一个事件,其名称为 addtrack,
并将 track
属性初始化为
new text track。
[[port to main]]
发送一条内部 create track 消息,其在 Window
中的隐式处理程序运行以下步骤:
TextTrack
对象。
id
属性。
language、
label
和
kind
属性。
mode
属性设置为 text
track mode,并使用从
此轨道的初始化
段中确定的适当信息填充 new text
track 上的其余属性。
SourceBuffer
对象的父媒体
源所附加到的媒体元素。
textTracks
属性。
这应当触发 TextTrackList
[HTML]
逻辑,以排入
一个任务,在 media
element 上的 textTracks
属性所引用的 TextTrackList
对象上,使用
TrackEvent
触发
一个事件,其名称为 addtrack,
并将 track
属性初始化为
new text track。
SourceBuffer 添加到 activeSourceBuffers。
activeSourceBuffers
上触发一个事件,
其名称为 addsourcebuffer
[[first initialization segment received flag]]
设置为 true。
[[pending initialization segment for changeType flag]]
设置为
false。
Window
中运行以下步骤:
HTMLMediaElement
的
readyState 属性
大于 HAVE_CURRENT_DATA,
则将
HTMLMediaElement
的
readyState 属性设置为
HAVE_METADATA。
根据
HTMLMediaElement 就绪状态
[HTML] 逻辑,HTMLMediaElement
的
readyState 发生变化时可能
在 HTMLMediaElement 上触发事件。
sourceBuffers 中的每个对象,
其 [[first initialization segment received flag]]
均等于 true,则使用
父媒体源的必要时镜像算法,在
Window
中运行以下
步骤:
HTMLMediaElement
的
readyState 属性为
HAVE_NOTHING,
则将 HTMLMediaElement
的
readyState 属性设置为 HAVE_METADATA。
根据
HTMLMediaElement 就绪状态
[HTML] 逻辑,HTMLMediaElement
的
readyState 发生变化时可能
在 HTMLMediaElement 上触发事件。如果发生从 HAVE_NOTHING
到
HAVE_METADATA
的转换,则它应当触发 HTMLMediaElement
逻辑,以排入
一个任务,在媒体元素上触发一个事件,
其名称为
loadedmetadata。
[[generate timestamps flag]]
等于 true:
由于定时文本帧的呈现 和 解码时间戳信息可能未 显式存在于底层格式中,或者可能 取决于帧的顺序,因此确定这些时间戳时可能需要特殊处理。某些元数据文本轨道,例如 MPEG2-TS PSI 数据,可能只有隐含的时间戳。针对这些 情况的格式特定规则应该包含在字节流格式 规范或 单独的扩展规范中。
实现不必在内部以 双精度 浮点表示存储时间戳。此表示 在这里使用,是因为它是 HTML 规范中时间戳所使用的表示。 这里的意图是在不向算法添加 不必要复杂性的情况下明确行为,以处理 添加 timestampOffset 可能导致 字节流格式所使用的底层时间戳表示发生时间戳回绕这一事实。 实现可以使用其 希望的任何内部时间戳表示,但 timestampOffset 的加法应该以类似于 使用双精度浮点 表示时所发生情况的方式表现。
mode 等于 "sequence",并且
[[group start timestamp]]
已设置,则运行以下步骤:
timestampOffset
设置为 [[group start timestamp]]
减去 presentation timestamp。
[[group end timestamp]]
设置为
[[group start timestamp]]。
[[group start timestamp]]。
如果 timestampOffset
不为 0,则运行以下步骤:
timestampOffset
加到 presentation timestamp 上。
timestampOffset
加到 decode timestamp 上。
mode
等于 "segments":
[[group end timestamp]]
设置为 presentation
timestamp。
mode
等于 "sequence":
[[group start timestamp]]
设置为
[[group end timestamp]]。
appendWindowStart,
则将需要随机访问点标志
设置为 true,丢弃该编码帧,并
跳转到循环顶部以开始处理下一个编码帧。
某些实现可以选择收集其中一些
presentation timestamp 小于 appendWindowStart
的编码帧,并使用
它们在第一个呈现
时间戳大于或等于 appendWindowStart
的编码帧处生成拼接,即使
该帧不是随机访问点。支持此行为
需要多个
解码器或快于实时的解码,因此目前此行为不会成为
规范性要求。
appendWindowEnd,
则
将需要随机访问点标志设置为 true,丢弃
该编码帧,并跳转
到循环顶部以开始处理下一个编码帧。
某些实现可以选择收集
presentation
timestamp 小于 appendWindowEnd
且 frame end timestamp
大于 appendWindowEnd
的编码帧,并使用它们在收集时
对所收集编码帧中位于追加窗口内的部分,以及之后处理的、仅
与所收集编码帧末尾部分重叠的帧的开头部分生成拼接。支持此行为
需要多个解码器或快于实时的解码,因此目前此
行为不会成为规范性要求。结合收集
跨越 appendWindowStart
的编码帧,实现可以
由此支持无缝音频拼接。
这是为了补偿帧 时间戳 计算中的微小误差,这些误差可能在 双精度浮点数与有理数之间 来回转换时出现。此 容差允许一个帧替换现有帧,只要其 与现有帧的开始 时间相差不超过 1 微秒。略微 早于现有帧的帧由 下面的移除步骤处理。
之所以需要大于检查,是因为编码帧之间的双向预测 可能导致 presentation timestamp 不会 单调递增, 即使解码时间戳是单调递增的。
[[group end timestamp]],
则将 [[group end timestamp]]
设置为 frame
end timestamp。
[[generate timestamps flag]]
等于 true,则将
timestampOffset
设置为 frame end timestamp。
如果 HTMLMediaElement
的
readyState 属性为
HAVE_METADATA,
并且新的编码帧使
HTMLMediaElement
的
buffered
具有一个覆盖
当前播放位置的 TimeRanges,
则将 HTMLMediaElement
的
readyState 属性设置为
HAVE_CURRENT_DATA。
根据
HTMLMediaElement 就绪状态
[HTML] 逻辑,HTMLMediaElement
的
readyState 发生变化时可能触发
HTMLMediaElement 上的事件。
如果 HTMLMediaElement
的
readyState 属性为
HAVE_CURRENT_DATA,
并且新的编码帧使
HTMLMediaElement
的
buffered
具有一个
包含当前播放位置以及当前播放
位置之后一段时间的 TimeRanges,则将
HTMLMediaElement
的
readyState
属性设置为 HAVE_FUTURE_DATA。
根据
HTMLMediaElement 就绪状态
[HTML] 逻辑,HTMLMediaElement
的
readyState 发生变化时可能触发
HTMLMediaElement 上的事件。
如果 HTMLMediaElement
的
readyState 属性为
HAVE_FUTURE_DATA,
并且新的编码帧使
HTMLMediaElement
的
buffered
具有一个
包含当前播放位置以及足以确保
不间断播放的数据的 TimeRanges,则将
HTMLMediaElement
的
readyState
属性设置为 HAVE_ENOUGH_DATA。
根据
HTMLMediaElement 就绪状态
[HTML] 逻辑,HTMLMediaElement
的
readyState 发生变化时可能触发
HTMLMediaElement 上的事件。
duration的数据,
则运行时长变更算法,并将 new
duration 设置
为当前时长与 [[group end timestamp]] 中的最大值。
当需要从 SourceBuffer 移除特定时间范围的 编码帧 时,请按照以下步骤操作:
对此 SourceBuffer
中的每个轨道缓冲区,运行以下
步骤:
duration
的当前值
如果此轨道缓冲区有一个 大于或等于 end 的随机访问点时间戳,则将 remove end timestamp 更新为该 随机访问点时间戳。
不同轨道的随机访问点时间戳可能不同,因为 一个轨道内编码帧之间的依赖关系通常不同于 另一个轨道中的依赖关系。
对每个被移除的帧,如果该帧的解码 时间戳等于 该帧所在轨道的最后解码 时间戳,则运行以下 步骤:
mode 等于
"segments":
[[group end timestamp]]
设置为呈现时间戳。
mode 等于
"sequence":
[[group start timestamp]]
设置为
[[group end timestamp]]。
如果此对象位于 activeSourceBuffers
中,
当前
播放位置大于或等于 start 且小于
remove end timestamp,并且 HTMLMediaElement
的
readyState 大于
HAVE_METADATA,
则将 HTMLMediaElement
的
readyState 属性设置为 HAVE_METADATA
并暂停播放。
根据
HTMLMediaElement 就绪状态
[HTML] 逻辑,HTMLMediaElement
的
readyState 发生变化时可能
在
HTMLMediaElement 上触发事件。
此转换发生是因为当前播放位置的媒体数据已被 移除。直到当前 播放位置的媒体被追加,或者发生 3.15.5 所选/已启用轨道状态的更改之前,播放都无法继续。
[[buffer full flag]] 等于 true,并且
此对象已准备好
接受更多字节,则将 [[buffer full flag]] 设置为 false。
此算法在向此 SourceBuffer 追加新数据时运行,以释放
空间。
这里需要增加一个步骤,说明如果实现预测到,在 [[input buffer]]
中任何现有字节的基础上再处理
new data 会超过 SourceBuffer 的容量,则实现可以决定
在此将
[[buffer full flag]] 设置为
true。
例如,这样的步骤能够让实现
在接受会导致资源溢出的 new data 之前,更
主动地施加反压。实际上,至少已有一个实现
这样做。
[[buffer full flag]] 等于 false,则
中止这些步骤。
实现可以使用不同的方法选择 removal
ranges,因此 Web
应用程序不应该依赖特定行为。Web
应用程序可以使用
buffered 属性来
观察已缓冲数据中的部分内容是否已被
驱逐。
当 编码帧处理算法需要为两个重叠的音频 编码帧 生成拼接帧时,按照以下步骤操作:
floor(x * sample_rate + 0.5) / sample_rate)。
例如,给定以下值:
presentation timestamp 和 decode timestamp 被更新为 10.0125,因为 10.01255 更接近 10 + 100/8000 (10.0125),而不是 10 + 101/8000 (10.012625)
某些实现可以对插入的静音两侧的 编码帧应用淡入/淡出静音效果,以使过渡不那么突兀。
这是为了允许将 new coded frame 添加到 track buffer 中,就如同 overlapped frame 一开始就不存在于 track buffer 中一样。
如果 new coded frame 的持续时间小于 5 毫秒,则 需要在 new coded frame 之后追加的编码 帧才能正确 渲染该拼接。
有关如何渲染此拼接帧的详细信息,请参阅音频拼接 渲染算法。
当由 音频拼接帧算法生成的拼接帧需要由媒体元素进行渲染时,运行以下步骤:
以下是该算法的图示。
当 编码帧处理算法需要为两个重叠的定时文本 编码帧 生成拼接帧时,运行以下步骤:
这是为了允许将 new coded frame 添加到 track buffer 中,就好像它 一开始就没有与 track buffer 中的任何帧重叠一样。
SourceBufferList 是用于 SourceBuffer
对象的简单容器对象。它提供只读的数组访问方式,并在列表被修改时触发事件。
WebIDL[Exposed=(Window,DedicatedWorker)]
interface SourceBufferList : EventTarget {
readonly attribute unsigned long length;
attribute EventHandler onaddsourcebuffer;
attribute EventHandler onremovesourcebuffer;
getter SourceBuffer (unsigned long index);
};
length 类型为 unsigned long,
只读
表示列表中 SourceBuffer 对象的数量。
onaddsourcebuffer 类型为 EventHandler
处理 addsourcebuffer
事件的事件处理器。
onremovesourcebuffer 类型为 EventHandler
处理 removesourcebuffer 事件的事件处理器。
允许通过数组操作符(即 [])访问列表中的 SourceBuffer 对象。
调用此方法时,用户代理必须运行以下步骤:
length 属性,则返回 undefined
并中止这些步骤。
SourceBuffer 对象。
| 事件名 | 接口 | 何时分发... |
|---|---|---|
| addsourcebuffer |
Event
|
当 SourceBuffer
被添加到列表时。
|
| removesourcebuffer |
Event
|
当 SourceBuffer
被从列表中移除时。
|
ManagedMediaSource 是一种会主动管理其内存内容的 MediaSource。
与 MediaSource 不同,用户代理可以出于任何
原因,通过 内存清理算法,从其 sourceBuffers
(其中填充的是 ManagedSourceBuffer)中驱逐
内容。
WebIDL[Exposed=(Window,DedicatedWorker)]
interface ManagedMediaSource : MediaSource {
constructor();
readonly attribute boolean streaming;
attribute EventHandler onstartstreaming;
attribute EventHandler onendstreaming;
};
streaming
获取时:
| 事件名 | 接口 | 何时分发... |
|---|---|---|
| startstreaming |
Event
|
当 ManagedMediaSource 的 streaming 属性从
false 变为 true 时。
|
| endstreaming |
Event
|
当 ManagedMediaSource 的 streaming 属性从
true 变为 false 时。
|
以下步骤会周期性运行,每当 SourceBuffer 监控算法被调度执行时。
拥有 足够的受管数据以确保不间断播放,是一个由实现定义的条件,用户代理判断当前拥有足够数据以在展示过程中避免长时间卡顿。该条件会被持续评估,以决定何时切换
streaming
的值。这些切换表示用户代理认为数据缓冲充足或仍需更多数据。
能以高效方式检索和缓冲数据,是一个由实现定义的条件,用户代理判断其能以节能的方式抓取新数据,同时实现所需内存使用。
MediaSource 的 SourceBuffer 监控算法。
buffered
属性包含一个 TimeRanges,覆盖当前播放位置且拥有
足够的受管数据以确保不间断播放,并且
能以高效方式检索和缓冲数据
streaming,在媒体元素上排队一个元素任务,其运行以下步骤:
streaming
属性设为 can play
uninterrupted and efficiently。
startstreaming,于 ManagedMediaSource
处触发。
endstreaming,于 ManagedMediaSource
处触发。
sourceBuffers 中的每个
buffer:
WebIDL[Exposed=(Window,DedicatedWorker)]
interface BufferedChangeEvent : Event {
constructor(DOMString type, optional BufferedChangeEventInit eventInitDict = {});
[SameObject] readonly attribute TimeRanges addedRanges;
[SameObject] readonly attribute TimeRanges removedRanges;
};
dictionary BufferedChangeEventInit : EventInit {
TimeRanges addedRanges;
TimeRanges removedRanges;
};
addedRanges
updatestart 与 updateend 事件之间新增的时间范围(这通常发生在上一次运行
编码帧处理 算法期间)。
removedRanges
updatestart 与 updateend 事件之间被移除的时间范围(这通常发生在上一次运行
编码帧移除
或 编码帧清除 算法期间,或当用户代理因
内存清理 而驱逐内容时)。
WebIDL[Exposed=(Window,DedicatedWorker)]
interface ManagedSourceBuffer : SourceBuffer {
attribute EventHandler onbufferedchange;
};
onbufferedchange
一个 事件处理程序
IDL 属性,
其 事件处理程序事件类型
为
bufferedchange。
| 事件名 | 接口 | 何时分发… |
|---|---|---|
| bufferedchange |
BufferedChangeEvent
|
在调用 appendBuffer()、
remove()、
endOfStream()
之后,或由于用户代理运行 内存清理 算法而导致
ManagedSourceBuffer
的缓冲范围发生变化时分发。
|
当对 ManagedSourceBuffer
buffer 的所有会导致该 buffer 的
buffered 发生变化的操作完成后,运行以下步骤。即,一旦
appendBuffer()、
remove() 或
内存清理 算法完成时。
buffered 属性的值。
buffered
TimeRanges。
BufferedChangeEventInit
字典,并用 added 初始化其
addedRanges,用
removed 初始化其
removedRanges。
bufferedchange,
在 buffer 上使用
BufferedChangeEvent 接口,
并用 eventInitDict 初始化。
ManagedMediaSource 父对象的
activeSourceBuffers
中:
currentTime
起直到能够再次获取该展示内容期间的连续播放。
不同实现可以采用不同策略选择 removal ranges,
因此 Web 应用不应依赖特定行为。Web 应用应监听
bufferedchange 事件以观察缓冲数据的部分是否被驱逐。
本节规定当一个 MediaSource 附加到元素时,现有
HTMLMediaElement
的
seekable
与
HTMLMediaElement
的
buffered
属性 必须 返回的内容,以及当其
srcObject
属性被设为 MediaSourceHandle 对象时,
现有 HTMLMediaElement
的
srcObject
属性 必须 执行的操作。
HTMLMediaElement
的
seekable
HTMLMediaElement
的
seekable
属性返回一个新的静态
规范化 TimeRanges
对象,按以下步骤创建:
MediaSource 是在一个
已终止或正在关闭的 DedicatedWorkerGlobalScope
中构造的,则返回一个空的 TimeRanges
对象,并中止这些
步骤。
此情况旨在处理这样的实现:对于在
已通过
terminate()
终止,或由用户代理为
MediaSource 的 DedicatedWorkerGlobalScope 执行终止
worker(例如最终由
close()
执行所导致)的 DedicatedWorkerGlobalScope 中构造的 MediaSource,实现可能不再保留任何
先前有关已缓冲或可寻址媒体的信息。
如果已附加的 worker MediaSource 的上下文被销毁,是否应该发生某种(最终的) 媒体元素错误状态转换?Chromium 的实验性 worker MSE 实现在该上下文销毁后仍保持元素的 readyState、networkState 和 error 与销毁前相同,不过 seekable 和 buffered 属性都会报告一个空的 TimeRange。
duration 和
[[live seekable range]] 的最近值,按
如下方式确定:
MediaSource 是
在 Window
中构造的
duration,并将 recent
live seekable
range 设置为 [[live seekable range]]。
duration 和 [[live seekable range]] 最近的值,
这些值通过处理 MediaSource 在每次 duration
或
[[live seekable range]]
发生变化时发送到其
[[port to main]]
的隐式消息来更新。
TimeRanges
对象。
HTMLMediaElement
的
buffered
属性的并集。
HTMLMediaElement
的
buffered
属性返回
一个空的 TimeRanges
对象,则返回一个空的 TimeRanges
对象,并
中止这些步骤。
HTMLMediaElement
的
buffered
属性所报告的最大结束时间。
HTMLMediaElement
的
buffered
HTMLMediaElement
的
buffered
属性返回一个静态的
规范化 TimeRanges
对象,按以下步骤计算。
MediaSource 是在一个
已终止或正在关闭的 DedicatedWorkerGlobalScope
中构造的,则返回一个空的 TimeRanges
对象,并中止这些
步骤。
此情况旨在处理这样的实现:对于在
已通过
terminate()
终止,或由用户代理为
MediaSource 的 DedicatedWorkerGlobalScope 执行终止
worker(例如最终由
close()
执行所导致)的 DedicatedWorkerGlobalScope 中构造的 MediaSource,实现可能不再保留任何
先前有关已缓冲或可寻址媒体的信息。
如果已附加的 worker MediaSource 的上下文被销毁,是否应该发生某种(最终的) 媒体元素错误状态转换?Chromium 的实验性 worker MSE 实现在该上下文销毁后仍保持元素的 readyState、networkState 和 error 与销毁前相同,不过 seekable 和 buffered 属性都会报告一个空的 TimeRange。
MediaSource 是
在 Window
中构造的
TimeRanges
对象。
activeSourceBuffers.length
不等于 0,则运行
以下步骤:
activeSourceBuffers
中每个 SourceBuffer 对象的
buffered
所返回的范围。
TimeRanges
对象,其中包含从 0 到 highest end time
的单个范围。
activeSourceBuffers
中的每个 SourceBuffer 对象,
运行以下步骤:
SourceBuffer
上的
buffered
属性所返回的范围。
readyState
为 "ended",
则将
source ranges
中最后一个范围的结束时间设置为 highest end
time。
Window
情况下的步骤所产生的 TimeRanges,
但这些步骤使用位于其 DedicatedWorkerGlobalScope
中的 MediaSource 及其
SourceBuffer
对象运行,并在每次
activeSourceBuffers、
readyState 或任何会改变
activeSourceBuffers
中各个 buffered 属性值的
缓冲状态发生更新时,通过
[[port to main]]
隐式消息进行通信。
如此频繁地重新计算和传递 recent intersection ranges 所产生的开销, 是允许实现灵活地使用其他机制(例如共享内存和锁)按需查询此 信息的原因之一,如跨上下文通信 模型中所述。
HTMLMediaElement
的
srcObject
如果某个 HTMLMediaElement
的
srcObject
属性被赋值为一个
MediaSourceHandle,则在调用元素的加载算法之前,
作为扩展的 HTMLMediaElement
的 srcObject
setter 的同步步骤的一部分,将该
MediaSourceHandle 的
[[has ever been assigned as srcobject]]
设为 true。
这可防止再次传输该
MediaSourceHandle 对象,
并在尝试时提供明确的同步异常。
需要将
MediaSourceHandle
添加到
HTMLMediaElement
的
MediaProvider IDL typedef 及其与媒体提供者对象相关的文本中。
本节对 [HTML]
中 AudioTrack 的定义进行扩展。
WebIDL[Exposed=Window]
partial interface AudioTrack {
readonly attribute SourceBuffer? sourceBuffer;
};
sourceBuffer,类型为 SourceBuffer,
只读,可为空
获取时,运行以下步骤:
SourceBuffer
创建的,并且该 SourceBuffer 与
此轨道创建于同一
领域
中,而且该 SourceBuffer
尚未从其 父媒体源的 sourceBuffers
属性中移除:
SourceBuffer。
MediaSource 是在
DedicatedWorkerGlobalScope
中构造的时,此轨道由内部 create track 处理程序在 Window
HTMLMediaElement
上创建,而创建它的
SourceBuffer
则存在于 DedicatedWorkerGlobalScope
中。
因为它们不位于同一 领域中,
所以此属性返回
null。
本节对 [HTML]
中 VideoTrack
的定义进行扩展。
WebIDL[Exposed=Window]
partial interface VideoTrack {
readonly attribute SourceBuffer? sourceBuffer;
};
sourceBuffer,类型为 SourceBuffer,
只读,可为空
获取时,运行以下步骤:
SourceBuffer
创建的,并且该 SourceBuffer 与
此轨道创建于同一
领域
中,而且该 SourceBuffer
尚未
从其 父媒体源的 sourceBuffers
属性中移除:
SourceBuffer。
MediaSource 是在
DedicatedWorkerGlobalScope
中构造的时,此轨道由内部 create track 处理程序在 Window
HTMLMediaElement
上创建,而创建它的
SourceBuffer
则存在于 DedicatedWorkerGlobalScope
中。
因为它们不位于同一 领域中,
所以此属性返回
null。
本节对 [HTML]
中 TextTrack
的定义进行扩展。
WebIDL[Exposed=Window]
partial interface TextTrack {
readonly attribute SourceBuffer? sourceBuffer;
};
sourceBuffer,类型为 SourceBuffer,
只读,可为空
获取时,运行以下步骤:
SourceBuffer
创建的,并且该 SourceBuffer 与
此轨道创建于同一
领域
中,而且该 SourceBuffer
尚未
从其 父媒体源的 sourceBuffers
属性中移除:
SourceBuffer。
MediaSource 是在
DedicatedWorkerGlobalScope
中构造的时,此轨道由内部 create track 处理程序在 Window
HTMLMediaElement
上创建,而创建它的
SourceBuffer
则存在于 DedicatedWorkerGlobalScope
中。
因为它们不位于同一 领域中,
所以此属性返回
null。
通过 appendBuffer() 为 SourceBuffer 提供的字节构成一个
逻辑字节流。这些字节流的格式和语义在 字节流格式规范中定义。字节流
格式
注册表 [MSE-REGISTRY] 提供了
可传递给
addSourceBuffer()、isTypeSupported() 或
changeType() 的 MIME 类型与
使用该 MIME 类型解析新追加数据的 SourceBuffer
所预期的字节流格式之间的映射。鼓励实现
为其支持的字节流格式注册映射,以促进互操作性。
字节流格式注册表 [MSE-REGISTRY] 是这些
映射的权威来源。如果某个实现声称支持注册表中列出的 MIME 类型,则其
SourceBuffer 实现必须符合注册表条目中列出的字节流
格式规范。
注册表中的字节流格式规范并非旨在定义新的 存储格式。它们只是概述本规范的实现将接受的现有存储格式结构 的子集。
字节流格式解析和验证在段 解析器循环 算法中实现。
本节提供适用于所有字节流格式规范的一般要求:
AudioTrack、
VideoTrack 和
TextTrack
的属性值。
如果字节流格式涵盖的格式与带内轨道 规范 [INBANDTRACKS] 中涵盖的某种格式类似, 则它应该尝试使用相同的属性映射,以便 媒体源扩展播放和非媒体源扩展播放提供 相同的轨道信息。
轨道的数量和类型不一致。
初始化段之间发生不受支持的编解码器变更。
有关编解码器变更的详细信息和
示例,请参阅收到初始化段算法、
addSourceBuffer()
和 changeType()。
例如,如果 I1 与 M1、M2、M3 相关联,则上述必须对 所有 组合 I1+M1、I1+M2、I1+M1+M2、I1+M2+M3 等成立。
字节流规范必须至少定义确保上述 要求成立的约束。可以定义额外约束,例如用于简化 实现。
除标记为非规范性的章节外,本规范中的所有编写指南、图示、示例与注记均为非规范性内容。除此之外的内容均为规范性内容。
本文中的关键词 MAY、MUST、MUST NOT、SHOULD 与 SHOULD NOT 按照 BCP 14 [RFC2119] 与 [RFC8174] 的描述进行解释,且仅当这些词以大写形式出现时(如本段所示)方适用。
<video id="v" autoplay></video>
<script>
const video = document.getElementById("v");
const mediaSource = new MediaSource();
mediaSource.addEventListener("sourceopen", onSourceOpen);
video.src = window.URL.createObjectURL(mediaSource);
async function onSourceOpen(e) {
const mediaSource = e.target;
if (mediaSource.sourceBuffers.length > 0) return;
const sourceBuffer = mediaSource.addSourceBuffer(
'video/webm; codecs="vorbis,vp8"',
);
video.addEventListener("seeking", (e) => onSeeking(mediaSource, e.target));
video.addEventListener("progress", () =>
appendNextMediaSegment(mediaSource),
);
try {
const initSegment = await getInitializationSegment();
if (initSegment == null) {
// 获取初始化分段出错。使用错误结束流。
mediaSource.endOfStream("network");
return;
}
// 追加初始化分段。
sourceBuffer.addEventListener("updateend", function firstAppendHandler() {
sourceBuffer.removeEventListener("updateend", firstAppendHandler);
// 追加一些初始媒体数据。
appendNextMediaSegment(mediaSource);
});
sourceBuffer.appendBuffer(initSegment);
} catch (error) {
// 处理在获取初始化分段期间可能发生的错误。
console.error("获取初始化分段出错:", error);
mediaSource.endOfStream("network");
}
}
async function appendNextMediaSegment(mediaSource) {
if (
mediaSource.readyState === "closed" ||
mediaSource.sourceBuffers[0].updating
)
return;
// 若流数据已用尽,则结束流。
if (!haveMoreMediaSegments()) {
mediaSource.endOfStream();
return;
}
try {
const mediaSegment = await getNextMediaSegment();
// 注意: 若 mediaSource.readyState == "ended",此 appendBuffer() 调用将
// 使其状态转为 "open"。Web 应用应准备处理多个 "sourceopen" 事件。
mediaSource.sourceBuffers[0].appendBuffer(mediaSegment);
}
catch (error) {
// 处理在获取媒体分段期间可能发生的错误。
console.error("获取媒体分段出错:", error);
mediaSource.endOfStream("network");
}
}
function onSeeking(mediaSource, video) {
if (mediaSource.readyState === "open") {
// 中止当前分段追加。
mediaSource.sourceBuffers[0].abort();
}
// 通知媒体分段加载逻辑从新的播放位置开始抓取数据。
seekToMediaSegmentAt(video.currentTime);
// 从新的播放位置追加一个媒体分段。
appendNextMediaSegment(mediaSource);
}
function onProgress(mediaSource, e) {
appendNextMediaSegment(mediaSource);
}
// 获取初始化分段的异步函数示例
async function getInitializationSegment() {
// 在此实现获取初始化分段的逻辑
// 这里只是占位函数
}
// 检查是否还有更多媒体分段的示例函数
function haveMoreMediaSegments() {
// 在此实现是否仍有更多媒体分段的判断逻辑
// 这里只是占位函数
}
// 获取下一个媒体分段的示例函数
async function getNextMediaSegment() {
// 在此实现获取下一个媒体分段的逻辑
// 这里只是占位函数
}
// 跳转到特定媒体分段的示例函数
function seekToMediaSegmentAt(currentTime) {
// 在此实现跳转逻辑
// 这里只是占位函数
}
</script>
<script>
async function setUpVideoStream() {
// 指定的视频格式与编解码器
const mediaType = 'video/mp4; codecs="mp4a.40.2,avc1.4d4015"';
// 检查该视频格式/编解码器是否受支持。
if (!window.ManagedMediaSource?.isTypeSupported(mediaType)) {
return; // 不受支持,采取其他方案。
}
// 设置视频与其受管源。
const video = document.createElement("video");
const source = new ManagedMediaSource();
video.controls = true;
await new Promise((resolve) => {
video.src = URL.createObjectURL(source);
source.addEventListener("sourceopen", resolve, { once: true });
document.body.appendChild(video);
});
const sourceBuffer = source.addSourceBuffer(mediaType);
// 设置事件处理程序
sourceBuffer.onbufferedchange = (e) => {
console.log("触发 onbufferedchange 事件。");
console.log(`新增范围: ${timeRangesToString(e.addedRanges)}`);
console.log(`移除范围: ${timeRangesToString(e.removedRanges)}`);
};
source.onstartstreaming = async () => {
const response = await fetch("./videos/bipbop.mp4");
const buffer = await response.arrayBuffer();
await new Promise((resolve) => {
sourceBuffer.addEventListener("updateend", resolve, { once: true });
sourceBuffer.appendBuffer(buffer);
});
};
source.onendstreaming = async () => {
// 在此停止抓取新分段
};
}
// 辅助函数...
function timeRangesToString(timeRanges) {
const ranges = [];
for (let i = 0; i < timeRanges.length; i++) {
ranges.push([timeRanges.start(i), timeRanges.end(i)]);
}
return "[" + ranges.map(([start, end]) => `[${start}, ${end})` ) + "]";
}
</script>
<body onload="setUpVideoStream()"></body>
编辑们感谢 Alex Giladi、Bob Lund、Chris Needham、Chris Poole、Chris Wilson、Cyril Concolato、Dale Curtis、David Dorwin、David Singer、Duncan Rowden、François Daoust、Frank Galligan、Glenn Adams、Jer Noble、Joe Steele、John Simmons、Kagami Sascha Rosylight、Kevin Streeter、Marcos Cáceres、Mark Vickers、Matt Ward、Matthew Gregan、 Michael(tm) Smith、Michael Thornburgh、Mounir Lamouri、Paul Adenot、Philip Jägenstedt、 Philippe Le Hegaret、Pierre Lemieux、Ralph Giles、Steven Robertson 与 Tatsuya Igarashi 对本规范所作的贡献。
本节为非规范性内容。
在本规范先前修订版中描述的视频播放质量指标(例如
候选推荐标准 的第 5 与第 10 节)
现已作为 [MEDIA-PLAYBACK-QUALITY] 的一部分进行制定。某些实现可能已支持较早草案中的
VideoPlaybackQuality 对象及
HTMLVideoElement
扩展方法 getVideoPlaybackQuality(),
这些均见于之前的修订版中。
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: