Copyright © 2025 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映射、时间戳偏移(如编辑列表)等。
字节流格式注册表中的 字节流格式规范包含格式相关示例。
包含某一 媒体时间线片段的分包及带时间戳的媒体数据的字节序列。媒体分段总是与最近追加的 初始化分段关联。
字节流格式注册表中的 字节流格式规范包含格式相关示例。
一个 MediaSource 对象 URL 是通过 createObjectURL()
创建的唯一 blob URL。它用于将 MediaSource 对象绑定到 HTMLMediaElement。
这些 URL 与 blob URLs
相同,但其定义中凡涉及 File 和 Blob 对象的内容,也适用于 MediaSource 对象。
MediaSource 对象 URL 的 origin 是调用 createObjectURL()
时 相关设置对象的
this。
某个 SourceBuffer 对象的父媒体源是创建它的
MediaSource 对象。
展示起始时间是演示中最早的时间点,指定初始 播放位置和 最早可能位置。所有用本规范创建的演示的展示起始时间均为0。
在判断 HTMLMediaElement
的
buffered
是否包含当前播放位置时,允许实现在展示起始时间及其后、首个 TimeRanges
之前的当前播放位置播放首个 TimeRanges,
如果该区间在展示起始时间后很短(如1秒)内开始。这样可兼容复用流通常不会让所有轨道精确从展示起始时间开始的实际情况。实现必须报告实际缓冲区范围,不受此允许影响。
某个 编码帧的展示区间是从其 展示时间戳到 展示时间戳加上 编码帧时长的时间区间。例如,若编码帧展示时间戳为10秒,时长为100毫秒,则展示区间为[10-10.1)。注意区间起点为包含,终点为不包含。
编码帧在演示中被渲染的顺序。展示顺序通过按编码帧的 展示时间戳单调递增排序实现。
演示中某一特定时间的引用。编码帧中的展示时间戳表示该帧应被渲染的时间。
媒体分段中可在不依赖前序数据的情况下开始解码和连续播放的位置。视频通常为I帧位置,音频多数帧都可视为随机访问点。由于视频轨道随机访问点分布稀疏,复用流通常以这些点为流的随机访问点。
描述 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 对象都有一个 [[has ever been
attached]] 内部槽,用于存储一个 boolean。在
MediaSource 创建时初始化为 false,在扩展的
HTMLMediaElement
的 资源获取算法中(参见 绑定到媒体元素 算法)被设置为 true。扩展的
资源获取算法会用此内部槽条件性地阻止通过
MediaSourceHandle
绑定到 HTMLMediaElement
的
srcObject
属性的 MediaSource 对象绑定。
WebIDLenum ReadyState {
"closed",
"open",
"ended",
};
closed
open
SourceBuffer 对象(在 MediaSource 的 sourceBuffers 属性中)追加数据。
ended
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 对象的句柄尚未创建,则执行以下步骤:
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 类型,则抛出 NotSupportedError
异常并终止步骤。
QuotaExceededError
异常并终止步骤。
例如,用户代理 可以 在媒体元素已达 HAVE_METADATA
readyState 时抛出 QuotaExceededError
异常。这种情况可能出现在用户代理的媒体引擎不支持在播放期间添加更多轨道时。
readyState 属性不处于 "open" 状态,则抛出 InvalidStateError
异常并终止步骤。
ManagedMediaSource,则为新建 ManagedSourceBuffer
实例,否则为新建 SourceBuffer 实例,并关联各自的资源。
[[generate timestamps flag]] 设置为
Media Source Extensions™
字节流格式注册表中与 type 关联的条目的“生成时间戳标志”值。
[[generate timestamps flag]] 为
true,则将 buffer 的 mode 设为 "sequence";否则设为 "segments"。
sourceBuffers。
addsourcebuffer,目标为 this 的 sourceBuffers。
从 SourceBuffer 从 sourceBuffers 移除一个 SourceBuffer。
sourceBuffers 中,则抛出 NotFoundError 异常,并终止后续步骤。
updating 属性为 true,则执行以下步骤:
audioTracks 返回的 AudioTrackList
对象。
AudioTrack
对象,执行:
sourceBuffer 属性设为
null。
AudioTrack
对象。
此操作应触发 AudioTrackList
[HTML] 的逻辑,排队任务以 触发事件,事件名为 removetrack,使用
TrackEvent,其
track
属性初始化为该 AudioTrack
对象,目标为 SourceBuffer audioTracks
list。若移除步骤开始时 enabled
属性为 true,还应触发 AudioTrackList
[HTML] 的逻辑,排队任务以触发事件名为 change,目标为
SourceBuffer audioTracks list。
Window
中移除该 AudioTrack
对象(或如 MediaSource
对象是在 DedicatedWorkerGlobalScope
构造,则移除其 Window 镜像):
audioTracks
属性返回的 AudioTrackList
对象。
AudioTrack
对象。
此操作应触发 AudioTrackList
[HTML] 的逻辑,排队任务以 触发事件,事件名为
removetrack,使用
TrackEvent,其
track
属性初始化为该 AudioTrack
对象,目标为 HTMLMediaElement audioTracks
list。如果移除步骤开始时 enabled
属性为 true,还应触发 AudioTrackList
[HTML] 的逻辑,排队任务以触发事件名为 change,目标为
HTMLMediaElement audioTracks
list。
videoTracks 返回的 VideoTrackList
对象。
VideoTrack
对象,执行:
sourceBuffer 属性设为
null。
VideoTrack
对象。
此操作应触发 VideoTrackList
[HTML] 的逻辑,排队任务以 触发事件,事件名为 removetrack,使用
TrackEvent,其
track
属性初始化为该 VideoTrack
对象,目标为 SourceBuffer videoTracks
list。若移除步骤开始时 selected
属性为 true,还应触发 VideoTrackList
[HTML] 的逻辑,排队任务以触发事件名为 change,目标为
SourceBuffer videoTracks list。
Window
中移除该 VideoTrack
对象(或如 MediaSource
对象是在 DedicatedWorkerGlobalScope
构造,则移除其 Window 镜像):
videoTracks
属性返回的 VideoTrackList
对象。
VideoTrack
对象。
此操作应触发 VideoTrackList
[HTML] 的逻辑,排队任务以 触发事件,事件名为
removetrack,使用
TrackEvent,其
track
属性初始化为该 VideoTrack
对象,目标为 HTMLMediaElement videoTracks
list。若移除步骤开始时 selected
属性为 true,还应触发 VideoTrackList
[HTML] 的逻辑,排队任务以触发事件名为 change,目标为
HTMLMediaElement videoTracks
list。
textTracks 返回的 TextTrackList
对象。
TextTrack
对象,执行:
sourceBuffer 属性设为
null。
TextTrack
对象。
此操作应触发 TextTrackList
[HTML] 的逻辑,排队任务以 触发事件,事件名为 removetrack,使用
TrackEvent,其
track
属性初始化为该 TextTrack
对象,目标为 SourceBuffer textTracks
list。若移除步骤开始时 mode
属性为
"showing"
或
"hidden",还应触发
TextTrackList
[HTML] 的逻辑,排队任务以触发事件名为 change,目标为
SourceBuffer textTracks list。
Window
中移除该 TextTrack
对象(或如 MediaSource
对象是在 DedicatedWorkerGlobalScope
构造,则移除其 Window 镜像):
textTracks
属性返回的 TextTrackList
对象。
TextTrack
对象。
此操作应触发 TextTrackList
[HTML] 的逻辑,排队任务以 触发事件,事件名为
removetrack,使用
TrackEvent,其
track
属性初始化为该 TextTrack
对象,目标为 HTMLMediaElement textTracks
list。如果移除步骤开始时 mode
属性为
"showing"
或
"hidden",还应触发
TextTrackList
[HTML] 的逻辑,排队任务以触发事件名为 change,目标为
HTMLMediaElement textTracks
list。
activeSourceBuffers 中,则将
sourceBuffer 从 activeSourceBuffers
中移除,并排队任务以 触发事件,事件名为 removesourcebuffer,目标为 SourceBufferList(由 activeSourceBuffers 返回)。
sourceBuffers 中移除,并排队任务以 触发事件,事件名为 removesourcebuffer,目标为 SourceBufferList(由 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 对象。
若资源不足,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 的 HTMLMediaElement
同样有 [[port to worker]] 内部槽(存储 MessagePort),以及
[[channel with worker]]
内部槽(存储 MessageChannel),两者在绑定期间建立、解绑期间清空。只有绑定到
DedicatedWorkerGlobalScope 的 MediaSource 时 [[port to worker]] 和 [[channel with worker]]
不为 null。
本规范中的算法若需在 Window 上下文的 HTMLMediaElement
与附加到 DedicatedWorkerGlobalScope 的 MediaSource
间通信,将隐式使用这些内部端口向对应方发送消息,消息的隐式处理程序根据算法描述运行步骤。
将 MediaSource 附加到媒体元素有不同方式,取决于该 MediaSource 对象是在哪构造的:在 Window
中,还是在 DedicatedWorkerGlobalScope
中:
将构造于 Window
的 MediaSource 进行附加,可以通过把该 MediaSource 对象 URL 赋值给媒体元素的 src
属性,或赋值给媒体元素内部某个 <source> 的 src 属性来完成。通过将一个 MediaSource 对象传给 createObjectURL()
可创建 MediaSource 对象 URL。
尽管实现 可以 在 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
执行 StructuredSerializeWithTransfer,
将其同时作为值与 transferList 的唯一成员,结果记为 serialized
port2。
MediaSource
的
DedicatedWorkerGlobalScope,使其将会
DedicatedWorkerGlobalScope
的
realm
执行 StructuredDeserializeWithTransfer,
并将 [[port to main]]
设为传输的 port2
值的反序列化克隆,来自 [[channel with worker]]。
readyState
属性设为
"open"。
sourceopen,
目标为
MediaSource。
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
变化可能触发该元素上的事件。
在播放过程中,如果
selected
视频轨道、
enabled
音频轨道或某个文本轨道的
mode
发生变化,则需要更新
activeSourceBuffers。
当发生一个或多个这样的变化时,需要遵循以下步骤。此外,当
MediaSource
构造于
DedicatedWorkerGlobalScope,
则每当之前由内部 create track mirror 消息的隐式处理程序创建的轨道之
Window
镜像发生变化时,也必须通过向
[[port to worker]]
发送内部 update track state 消息,将该变化应用到对应的
DedicatedWorkerGlobalScope
轨道上,其隐式处理程序执行该变更并运行以下步骤。同样地,发生在
DedicatedWorkerGlobalScope
轨道上的每个变化,也必须通过向
[[port to main]]
发送内部 update track state 消息,将该变化应用到对应的
Window
轨道镜像上,其隐式处理程序对镜像进行变更。
SourceBuffer
未与任何其他启用的轨道关联,则运行以下步骤:
SourceBuffer
尚未位于
activeSourceBuffers
中,则运行以下步骤:
SourceBuffer
未与任何其他启用或选中的轨道关联,则运行以下步骤:
activeSourceBuffers
中移除与该音频轨道关联的
SourceBuffer。
removesourcebuffer
到
activeSourceBuffers
SourceBuffer
尚未位于
activeSourceBuffers
中,则运行以下步骤:
SourceBuffer
添加到
activeSourceBuffers
addsourcebuffer
到
activeSourceBuffers
mode
变为
"disabled",
且与该轨道关联的
SourceBuffer
未与任何其他启用或选中的轨道关联,则运行以下步骤:
activeSourceBuffers
中移除与该文本轨道关联的
SourceBuffer
removesourcebuffer
到
activeSourceBuffers
mode
变为
"showing"
或
"hidden",
且与该轨道关联的
SourceBuffer
尚未位于
activeSourceBuffers
中,则运行以下步骤:
SourceBuffer
添加到
activeSourceBuffers
addsourcebuffer
到
activeSourceBuffers
当 duration 需要变更为 new duration 时,按照以下步骤操作。
duration 的值等于 new
duration,则直接返回。
SourceBuffer(在 sourceBuffers 中)缓冲的所有 编码帧的最大 展示时间戳,则抛出 InvalidStateError
异常并终止这些步骤。
SourceBuffer(在 sourceBuffers 中)内所有 轨道缓冲区的 缓冲区范围最大结束时间。
该情况可能由于 编码帧移除算法会保留移除区间起始之前的编码帧而出现。
duration 更新为 new
duration。
Window
上运行以下步骤以更新媒体元素的时长:
duration
更新为 new duration。
当应用通过 endOfStream()
调用或某算法需要信号解码错误时会调用此算法。
此算法接收一个 error 参数,指示是否需要发出错误信号。
readyState 属性值设置为
"ended"。
sourceended
到 MediaSource。
SourceBuffer(在 sourceBuffers
中)内所有 轨道缓冲区的 缓冲区范围最大结束时间为 new duration,运行 时长变更算法。
这样可使时长正确反映追加的媒体分段的结束。例如,若时长显式设置为10秒,实际只追加了0~5秒的媒体分段后调用了 endOfStream(), 那么时长会被更新为5秒。
network"
Window
上运行以下步骤:
HTMLMediaElement
的 readyState
属性等于 HAVE_NOTHING
HTMLMediaElement
的 readyState
属性大于 HAVE_NOTHING
decode"
Window
上运行以下步骤:
HTMLMediaElement
的 readyState
属性等于 HAVE_NOTHING
HTMLMediaElement
的 readyState
属性大于 HAVE_NOTHING
此算法用于在 Window
上运行步骤,无论 MediaSource 是在同一个 Window
还是在 DedicatedWorkerGlobalScope
上绑定,通常用于更新绑定的 HTMLMediaElement
的状态。此算法接收一个 steps 参数,列出要在 Window
上执行的步骤。
MediaSource 构造于 DedicatedWorkerGlobalScope:
[[port to main]] 发送内部
mirror on window 消息,其 Window
上的隐式处理程序将运行 steps。直接将控制权返回给调用者,无需等待该处理程序收到消息。
Window
上异步运行,而不是在其他 Window
任务执行过程中间插入;
DedicatedWorkerGlobalScope
上该算法的同步运行与返回。
MediaSourceHandle 接口表示 MediaSource 对象的代理,
用于将 DedicatedWorkerGlobalScope
上的 MediaSource 通过 Window
上的 HTMLMediaElement
使用 srcObject
进行绑定,具体见 绑定到媒体元素 算法。
为了能够跨上下文将 MediaSource 绑定到媒体元素,必须使用该独立对象,因为 MediaSource 本身不可传递(transferable),因其是事件目标。
每个 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
所暗示的“move”语义并不总是真实的。例如,postMessage 的扩展或内部广播实现可能导致被传递的 MediaSourceHandle 有多个接收方。
因此,实现建议:只有当底层 MediaSource
的任一句柄在媒体元素资源选择算法的异步部分被使用时,才确定哪个潜在克隆仍然有效。
这类似于通过 MediaSource 对象 URL 进行绑定的现有行为,
该 URL 可被轻易克隆,但所有克隆最多只允许一次绑定启动。
实现必须保证底层 MediaSource 对象只能通过 srcObject
进行一次绑定(加载),不论 MediaSourceHandle 是否因 Transferable
的不同实现而被克隆。
参考 绑定到媒体元素,了解媒体元素资源选择算法的异步部分如何强制执行此要求。
MediaSourceHandle 仅暴露在 Window
和 DedicatedWorkerGlobalScope
上下文,且不能在不同 agent
cluster
[ECMASCRIPT] 间成功传递。MediaSourceHandle 对象只能在同一个 agent
cluster 内传递成功。
例如,将 MediaSourceHandle 对象从
Window
或 DedicatedWorkerGlobalScope
传递到 SharedWorker 或 ServiceWorker 都不会成功。开发者应了解该限制与 MediaSource 对象 URL 的不同,后者是可通过多种方式传递的 DOMString。即便如此,通过 MediaSource 对象 URL 进行 绑定到媒体元素 也只能用于构造于 Window
上下文的 MediaSource。另见 Web 应用 API 的 agent
和 agent
cluster 形式化,[HTML] 中相关概念如 dedicated
worker agents。
传递步骤
对于 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;
readonly attribute AudioTrackList audioTracks;
readonly attribute VideoTrackList videoTracks;
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);
};
mode 类型
AppendMode
控制如何处理一系列 媒体分段。该属性在对象创建后由 addSourceBuffer()
初始化,
可通过 changeType()
或直接设置此属性进行更新。
读取时,返回初始值或最后一次成功设置的值。
设置时,执行如下步骤:
sourceBuffers(父媒体源)中移除,则抛出
InvalidStateError
异常并终止这些步骤。
updating 属性为 true,则抛出
InvalidStateError
异常并终止这些步骤。
[[generate timestamps flag]]
为 true 且 new mode
为 "segments",则抛出 TypeError
异常并终止这些步骤。
如果父媒体源的 readyState 属性为 "ended",则执行:
readyState 属性设为 "open"
sourceopen
到父媒体源。
[[append state]]
为 PARSING_MEDIA_SEGMENT,则抛出 InvalidStateError
并终止这些步骤。
sequence",则将 [[group start timestamp]] 设为
[[group end timestamp]]。
updating 类型 boolean,
只读
指示 appendBuffer() 或
remove()
操作的异步处理是否仍在进行。该属性在对象创建时初始为 false。
buffered 类型 TimeRanges,
只读
指示本 SourceBuffer 已缓冲了哪些 TimeRanges。创建时初始值为空
TimeRanges
对象。
读取该属性时,需执行以下步骤必须:
sourceBuffers(父媒体源)中移除,则抛出
InvalidStateError
异常并终止这些步骤。
TimeRanges
对象,内容为从 0 到 highest end time 的单个区间。
文本 轨道缓冲区参与计算 highest end time, 但本处缓冲区范围计算不包含文本轨道。文本轨道不一定连续,也不应因其不连续导致其他媒体轨道在同一区间连续时播放停顿。
readyState 为 "ended",则将 track ranges 最后一个区间的结束时间设为 highest end time。
timestampOffset 类型 double
控制追加到本 SourceBuffer 的后续 媒体分段 内时间戳应用的偏移量。初始值为 0,表示不应用偏移。
读取时,返回初始值或最后一次成功设置的值。
设置时,执行如下步骤:
sourceBuffers(父媒体源)中移除,则抛出
InvalidStateError
异常并终止这些步骤。
updating 属性为 true,则抛出
InvalidStateError
异常并终止这些步骤。
如果父媒体源的 readyState 属性为 "ended",则执行:
readyState 属性设为 "open"
sourceopen
到父媒体源。
[[append state]]
为 PARSING_MEDIA_SEGMENT,则抛出 InvalidStateError
并终止这些步骤。
mode 属性为 "sequence",则将 [[group start timestamp]] 设为
new timestamp offset。
audioTracks 类型 AudioTrackList,
只读
AudioTrack
对象列表。
videoTracks 类型 VideoTrackList,
只读
VideoTrack
对象列表。
textTracks 类型 TextTrackList,
只读
TextTrack
对象列表。
appendWindowStart 类型 double
展示时间戳,用于表示 追加窗口 的起始。该属性初始设为 展示起始时间。
获取时,返回初始值或最后一次成功设置的值。
设置时,执行如下步骤:
sourceBuffers(父媒体源)中移除,则抛出
InvalidStateError
异常并终止这些步骤。
updating 属性为 true,则抛出
InvalidStateError
异常并终止这些步骤。
appendWindowEnd,则抛出 TypeError
异常并终止这些步骤。
appendWindowEnd 类型 unrestricted double
展示时间戳,表示 追加窗口 的结束。该属性初始设为正无穷大。
获取时,返回初始值或最后一次成功设置的值。
设置时,执行如下步骤:
sourceBuffers(父媒体源)中移除,则抛出
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。
updatestart 到本 SourceBuffer 对象。
abort
中止当前分段并重置分段解析器。
调用此方法时,用户代理必须运行以下步骤:
sourceBuffers(父媒体源)中移除,则抛出
InvalidStateError
异常并终止这些步骤。
readyState 属性不是 "open",则抛出 InvalidStateError
异常并终止这些步骤。
InvalidStateError
异常并终止这些步骤。
updating 属性为 true,则运行以下步骤:
updating 属性设为 false。
abort 到本 SourceBuffer 对象。
updateend 到本
SourceBuffer 对象。
appendWindowStart 设为
展示开始时间。
appendWindowEnd 设为正无穷。
changeType
更改该对象关联的 MIME 类型。后续的 appendBuffer()
调用会要求新追加的字节与新类型一致。
调用此方法时,用户代理必须运行以下步骤:
TypeError
异常并终止这些步骤。
sourceBuffers(父媒体源)中移除,则抛出
InvalidStateError
异常并终止这些步骤。
updating 属性为 true,则抛出
InvalidStateError
异常并终止这些步骤。
SourceBuffer(在父媒体源的 sourceBuffers
属性中)当前或先前指定的类型不兼容,则抛出 NotSupportedError
异常并终止这些步骤。
如果父媒体源的 readyState 属性为 "ended",则执行:
readyState 属性设为 "open"。
sourceopen
到父媒体源。
SourceBuffer 对象更新 [[generate timestamps flag]]
的值。
[[generate timestamps flag]]
为 true:
mode 属性设为 "sequence",并运行属性被设置时的相关步骤。
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 对象有一个 [[buffer full
flag]] 内部槽,用于记录 appendBuffer()
是否允许接受更多字节。对象创建时设为 false,追加和移除数据时会更新。
每个 SourceBuffer 对象有一个 [[group start
timestamp]] 内部槽,用于记录 "sequence" 模式下新 编码帧组的起始时间戳。对象创建时未设置,mode 属性为 "sequence" 且 timestampOffset 属性被设置,或运行 编码帧处理算法时会更新。
每个 SourceBuffer 对象有一个 [[group end
timestamp]] 内部槽,存储当前 编码帧组所有 编码帧的最大 编码帧结束时间戳。创建对象时设为 0,运行 编码帧处理算法时更新。
[[group end timestamp]] 记录的是 编码帧结束时间戳 在一个 SourceBuffer 的所有 轨道缓冲区中的最大值。因此,在追加多轨道复用且时间戳未对齐分段时,需谨慎设置 mode 属性。
每个 SourceBuffer 对象有一个 [[generate timestamps
flag]] 内部槽,是个布尔值,用于记录传给 编码帧
处理算法的编码帧是否需要生成时间戳。该标志由 addSourceBuffer()
创建对象时设置,changeType() 可更新。
当调用分段解析循环算法时,运行以下步骤:
[[input buffer]] 为空,则跳转到下方 需要更多数据
步骤。
[[input buffer]]
包含违反 SourceBuffer 字节流格式规范
的字节,则运行 追加错误
算法并终止本算法。
[[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,则运行 追加错误算法并终止本算法。
[[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。
error,在此
SourceBuffer 对象上。
updateend,在此
SourceBuffer 对象上。
decode"。
当追加操作开始时,运行以下步骤以验证并准备 SourceBuffer。
SourceBuffer 已从 sourceBuffers
属性移除(属于 父媒体源),则抛出
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 属性的
父媒体源 处于
"ended" 状态,则运行以下步骤:
readyState 属性的
父媒体源 设置为
"open"
sourceopen,触发于 父媒体源。
如果 [[buffer full flag]] 等于 true,
则抛出
QuotaExceededError
异常并中止这些步骤。
这是实现无法清除足够数据以容纳追加内容或追加内容过大的信号。Web 应用应当使用
remove()
显式释放空间和/或减少追加数据量。
当调用 appendBuffer()
时,执行以下步骤处理追加的数据。
当调用者需要发起一个 JavaScript 可见的范围移除操作(该操作会阻塞其它 SourceBuffer 更新)时,按照以下步骤进行:
updating 属性设为 true。
updatestart 的事件,在此
SourceBuffer 对象上。
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,
则运行以下步骤:
如果某些编解码器未在最近一次成功的 changeType()
调用中传入的 type 参数(a),或者(b)若此对象尚未进行过成功的
changeType(),
则为创建该 SourceBuffer 对象的
addSourceBuffer()
中被指定,
用户代理 MAY 将本应受支持的编解码器视为此处“不受支持”。例如,如果最近一次成功的
changeType()
使用了 'video/webm' 或
'video/webm; codecs="vp8"',而初始化分段中出现了包含 vp9
的视频轨,则即便上述另外两项检查通过,用户代理也
MAY
利用此步骤触发解码错误。鼓励实现仅在该编解码器确实不受支持或另外两项检查失败时触发错误。鼓励 Web 作者使用带有精确编解码器参数的
changeType()、
addSourceBuffer()
和 isTypeSupported()
更主动地检测用户代理支持情况。当 SourceBuffer
对象的字节流格式发生变化时,必须调用
changeType()。
如果 [[first initialization segment received flag]]
为 false,
则运行以下步骤:
如果某些编解码器未在最近一次成功的 changeType()
(a)调用传入的 type 参数中指定,或者(b)若此对象尚未发生成功的
changeType(),则为创建该对象的
addSourceBuffer()
中指定,
用户代理 MAY 将本应受支持的编解码器视为“不受支持”,从而触发解码错误。例如,
MediaSource.isTypeSupported('video/webm;codecs="vp8,vorbis"')
可能返回 true,但如果 addSourceBuffer()
被调用时使用了
'video/webm;codecs="vp8"',而初始化分段中出现了 Vorbis 轨,则用户代理 MAY 使用此步骤触发解码错误。
鼓励实现仅在编解码器确实不受支持时触发错误。鼓励 Web 作者使用带有精确编解码器参数的
changeType()、
addSourceBuffer()
和
isTypeSupported()
更主动地检测用户代理支持情况。当 changeType()
为 SourceBuffer
对象更改字节流格式时是必需的。
对于该 初始化分段 中的每条音轨,运行以下步骤:
AudioTrack
对象。
id
属性。
language
属性。
label
属性。
kind
属性。
如果该 SourceBuffer
对象的 audioTracks
的 length
等于 0,则运行以下步骤:
enabled
属性设为 true。
audioTracks
属性中,
位于此 SourceBuffer
对象上。
这应当触发 AudioTrackList
[HTML]
逻辑,排队一个任务以
触发一个事件,事件名为
addtrack,
并使用 TrackEvent,
其 track
属性初始化为
new audio track,触发于由该 audioTracks
属性引用的 AudioTrackList
对象上,此对象位于该 SourceBuffer
上。
DedicatedWorkerGlobalScope
中构造的:
[[port to main]]
发送一条内部 create track mirror 消息,
其在 Window
中的隐式处理器运行以下步骤:
AudioTrack
对象。
audioTracks
属性中。
audioTracks
属性中。
这应当触发 AudioTrackList
[HTML]
逻辑,排队一个任务以
触发一个事件,事件名为
addtrack,
并使用 TrackEvent,
其 track
属性初始化为
mirrored audio track 或 new audio track,触发于由
HTMLMediaElement 的
audioTracks
属性引用的 AudioTrackList
对象上。
对于该 初始化分段 中的每条视频轨,运行以下步骤:
VideoTrack
对象。
id
属性。
language
属性。
label
属性。
kind
属性。
如果该 SourceBuffer
对象的 videoTracks
的 length
等于 0,则运行以下步骤:
selected
属性设为 true。
videoTracks
属性中,
位于此 SourceBuffer
对象上。
这应当触发 VideoTrackList
[HTML]
逻辑,排队一个任务以
触发一个事件,事件名为
addtrack,
并使用 TrackEvent,
其 track
属性初始化为
new video track,触发于由该 videoTracks
属性引用的 VideoTrackList
对象上,此对象位于该 SourceBuffer
上。
DedicatedWorkerGlobalScope
中构造的:
[[port to main]]
发送一条内部 create track mirror 消息,
其在 Window
中的隐式处理器运行以下步骤:
VideoTrack
对象。
videoTracks
属性中。
videoTracks
属性中。
这应当触发 VideoTrackList
[HTML]
逻辑,排队一个任务以
触发一个事件,事件名为
addtrack,
并使用 TrackEvent,
其 track
属性初始化为
mirrored video track 或 new video track,触发于由
HTMLMediaElement 的
videoTracks
属性引用的 VideoTrackList
对象上。
对于该 初始化分段 中的每条文本轨,运行以下步骤:
TextTrack
对象。
id
属性。
language
属性。
label
属性。
kind
属性。
mode
属性等于
"showing"
或
"hidden",
则将 active track flag 设为 true。
textTracks
属性中,
位于此 SourceBuffer
对象上。
这应当触发 TextTrackList
[HTML]
逻辑,排队一个任务以
触发一个事件,事件名为
addtrack,
并使用 TrackEvent,
其 track
属性初始化为
new text track,触发于由该 textTracks
属性引用的 TextTrackList
对象上,此对象位于该 SourceBuffer
上。
DedicatedWorkerGlobalScope
中构造的:
[[port to main]]
发送一条内部 create track mirror 消息,
其在 Window
中的隐式处理器运行以下步骤:
TextTrack
对象。
textTracks
属性中。
textTracks
属性中。
这应当触发 TextTrackList
[HTML]
逻辑,排队一个任务以
触发一个事件,事件名为
addtrack,
并使用 TrackEvent,
其 track
属性初始化为
mirrored text track 或 new text track,触发于由
HTMLMediaElement 的
textTracks
属性引用的 TextTrackList
对象上。
SourceBuffer 添加到 activeSourceBuffers。
addsourcebuffer,触发于
activeSourceBuffers
[[first initialization segment received flag]]
设为 true。
[[pending initialization segment for changeType flag]]
设为
false。
Window
中运行以下步骤:
HTMLMediaElement
的
readyState 属性
大于 HAVE_CURRENT_DATA,
则将
HTMLMediaElement
的
readyState 属性设为
HAVE_METADATA。
根据
HTMLMediaElement ready states
[HTML] 逻辑,HTMLMediaElement
的
readyState 变化可能会在
HTMLMediaElement 上触发事件。
sourceBuffers 中的每个对象(属于 父媒体源)
的 [[first initialization segment received flag]]
都为 true,则使用
父媒体源 的 必要时镜像 算法在
Window
中运行以下步骤:
HTMLMediaElement
的
readyState 属性为
HAVE_NOTHING,
则将 HTMLMediaElement
的
readyState 属性设为 HAVE_METADATA。
根据
HTMLMediaElement ready states
[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 上。
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 ready states
[HTML] 逻辑,HTMLMediaElement
的
readyState 变化可能在该元素上触发事件。
如果 HTMLMediaElement
的
readyState 属性为
HAVE_CURRENT_DATA
且新的 编码帧 使
HTMLMediaElement
的
buffered
拥有一个 TimeRanges,
该 TimeRanges 覆盖当前播放位置并延伸至当前播放位置之后一段时间,则将 HTMLMediaElement
的
readyState
属性设为 HAVE_FUTURE_DATA。
根据
HTMLMediaElement ready states
[HTML] 逻辑,HTMLMediaElement
的
readyState 变化可能在该元素上触发事件。
如果 HTMLMediaElement
的
readyState 属性为
HAVE_FUTURE_DATA
且新的 编码帧 使
HTMLMediaElement
的
buffered
拥有一个 TimeRanges,
该 TimeRanges 覆盖当前播放位置并具有足够数据以确保不间断播放,则将 HTMLMediaElement
的
readyState
属性设为 HAVE_ENOUGH_DATA。
根据
HTMLMediaElement ready states
[HTML] 逻辑,HTMLMediaElement
的
readyState 变化可能在该元素上触发事件。
duration 的数据,
则运行 时长变更 算法,并将 new
duration 设为当前时长与 [[group end timestamp]] 的最大值。
当需要从 SourceBuffer 移除特定时间范围的 编码帧 时,请按照以下步骤操作:
对该 SourceBuffer 中的每个
轨道缓冲区,运行以下步骤:
duration 的值。
如果此 轨道缓冲区 有一个大于等于 end 的 随机访问点时间戳,则将 remove end timestamp 更新为该随机访问点时间戳。
不同轨道的随机访问点时间戳可能不同,因为同一轨道内编码帧的依赖关系通常不同于另一轨道内的依赖关系。
一直移除到下一个 随机访问点,是对解码依赖的保守估计,因为这假设在被移除帧与下一个随机访问点之间的所有帧都依赖于已被移除的那些帧。
如果此对象在 activeSourceBuffers
中,
当前播放位置大于等于 start 且小于 remove end timestamp,
并且 HTMLMediaElement
的
readyState 大于
HAVE_METADATA,
则将 HTMLMediaElement
的
readyState 属性设为 HAVE_METADATA,
并暂停播放。
根据
HTMLMediaElement ready states
[HTML] 逻辑,HTMLMediaElement
的
readyState 变化可能会在该元素上触发事件。
此状态变化发生是因为当前播放位置的媒体数据被移除了。只有在为当前播放位置追加了媒体数据,或发生了 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
对象并中止这些步骤。
此情况旨在处理如下实现:当某个在 DedicatedWorkerGlobalScope 中构造的 MediaSource 因
terminate()
或用户代理执行
终止
worker
而结束时,实现可能不再保留任何关于该 MediaSource 的已缓冲或可寻址媒体的历史信息;例如,这也可能是
close()
执行的最终结果。
当所附加的 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]]。
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
对象并中止这些步骤。
此情况旨在处理如下实现:当一个在 DedicatedWorkerGlobalScope 中构造的 MediaSource 因
terminate()
或用户代理执行
终止
worker
而结束时,实现可能不再保留任何关于该 MediaSource 的已缓冲或可寻址媒体的历史信息;例如,这也可能是
close()
执行的最终结果。
当所附加的 worker MediaSource 的上下文被销毁时,是否应当发生某种(最终的)媒体元素错误状态转换?Chromium 的实验性 worker MSE 实现会保持元素的 readyState、networkState 和 error 与销毁前一致,但 seekable 与 buffered 属性会各自返回一个空的 TimeRange。
MediaSource 在
Window
中构造
TimeRanges
对象。
activeSourceBuffers.length
不为 0,则运行以下步骤:
buffered
的返回结果,针对 SourceBuffer 的每个对象,
这些对象位于
activeSourceBuffers
中。
TimeRanges
对象,
其包含从 0 到 highest end time 的单一范围。
SourceBuffer
中的每个对象(位于
activeSourceBuffers
中),运行以下步骤:
buffered
属性返回的范围集合。
readyState
为 "ended",
则将 source ranges
中最后一个范围的结束时间设为
highest end time。
Window
情况下步骤所得的
TimeRanges,
但使用位于其
DedicatedWorkerGlobalScope
中的该 MediaSource 及其
SourceBuffer 对象,
并在每次更新
activeSourceBuffers、
readyState 或任何会改变各
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,DedicatedWorker)]
partial interface AudioTrack {
readonly attribute SourceBuffer? sourceBuffer;
};
AudioTrack
需要同时对 Window 与 DedicatedWorker 暴露。
sourceBuffer,类型为 SourceBuffer,
只读,且可为空
获取时,运行以下步骤:
SourceBuffer
所创建,且该 SourceBuffer
尚未从其 sourceBuffers
属性(属于其 父媒体源)中被移除:
SourceBuffer。
DedicatedWorkerGlobalScope
的 SourceBuffer
通知其在 Window
中的内部 create track mirror 处理器创建了此轨道,则该轨道在
Window
中的副本对本属性将返回 null。
本节对 [HTML]
中 VideoTrack
的定义进行扩展。
WebIDL[Exposed=(Window,DedicatedWorker)]
partial interface VideoTrack {
readonly attribute SourceBuffer? sourceBuffer;
};
VideoTrack
需要同时对 Window 与 DedicatedWorker 暴露。
sourceBuffer,类型为 SourceBuffer,
只读,且可为空
获取时,运行以下步骤:
SourceBuffer
所创建,且该 SourceBuffer
尚未从其 sourceBuffers
属性(属于其 父媒体源)中被移除:
SourceBuffer。
DedicatedWorkerGlobalScope
的 SourceBuffer
通知其在 Window
中的内部 create track mirror 处理器创建了此轨道,则该轨道在
Window
中的副本对本属性将返回 null。
本节对 [HTML]
中 TextTrack
的定义进行扩展。
WebIDL[Exposed=(Window,DedicatedWorker)]
partial interface TextTrack {
readonly attribute SourceBuffer? sourceBuffer;
};
sourceBuffer,类型为 SourceBuffer,
只读,且可为空
获取时,运行以下步骤:
SourceBuffer
所创建,且该 SourceBuffer
尚未从其 sourceBuffers
属性(属于其 父媒体源)中被移除:
SourceBuffer。
DedicatedWorkerGlobalScope
的 SourceBuffer
通知其在 Window
中的内部 create track mirror 处理器创建了此轨道,则该轨道在
Window
中的副本对本属性将返回 null。
通过 appendBuffer() 提供给 SourceBuffer 的字节构成一个
逻辑字节流。此类字节流的格式与语义由 字节流格式规范 定义。字节流格式
注册表 [MSE-REGISTRY] 提供了可传递给
addSourceBuffer()、isTypeSupported() 或
changeType() 的 MIME 类型与
SourceBuffer 在解析新追加数据时所期望的字节流格式之间的映射。
鼓励各实现为其支持的字节流格式注册映射,以促进互操作性。字节流格式注册表
[MSE-REGISTRY] 是这些
映射的权威来源。若某实现宣称支持注册表中列出的某个 MIME 类型,则其
SourceBuffer 实现 必须 遵循注册项中所列的
字节流格式规范。
注册表中的字节流格式规范并不意在定义新的存储格式。它们仅概述了本规范实现所接受的 既有存储格式结构的子集。
字节流格式的解析与校验由 分段解析循环 算法实现。
本节为所有字节流格式规范提供通用要求:
AudioTrack、
VideoTrack 与
TextTrack
属性值的映射参考。
若某字节流格式涵盖的格式与带内轨道规范 [INBANDTRACKS] 所覆盖的某种格式相似,则其 应当 力求使用相同的属性映射,以便 使用与不使用 Media Source Extensions 的播放能提供相同的轨道信息。
轨道的数量与类型不一致。
不受支持的编解码器变更出现在不同的 初始化分段 之间。
参见 接收到初始化分段
算法、
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: