1. 概述
此 API 旨在使基本录制非常简单,同时仍允许更复杂的用例。 在最简单的情况下,应用实例化一个 MediaRecorder
对象,调用 start()
然后调用 stop()
或等待 MediaStreamTrack(s)
[GETUSERMEDIA]
结束。录制内容将通过 ondataavailable
事件以平台默认编码的形式提供。可用函数可查询平台支持的一组编码,并在作者需要时选择想要的编码。应用还可以选择一次想要接收多少数据。默认情况下,录制结束时会返回包含整个录制内容的 Blob。然而,应用可以选择在固定间隔接收更小的数据缓冲区。
2. 媒体录制 API
[Exposed =Window ]interface :MediaRecorder EventTarget {constructor (MediaStream ,stream optional MediaRecorderOptions = {});options readonly attribute MediaStream stream ;readonly attribute DOMString mimeType ;readonly attribute RecordingState state ;attribute EventHandler onstart ;attribute EventHandler onstop ;attribute EventHandler ondataavailable ;attribute EventHandler onpause ;attribute EventHandler onresume ;attribute EventHandler onerror ;readonly attribute unsigned long videoBitsPerSecond ;readonly attribute unsigned long audioBitsPerSecond ;readonly attribute BitrateMode audioBitrateMode ;undefined start (optional unsigned long );timeslice undefined stop ();undefined pause ();undefined resume ();undefined requestData ();static boolean isTypeSupported (DOMString ); };type
2.1. 构造函数
MediaRecorder(MediaStream stream, optional MediaRecorderOptions options = {})-
当调用
MediaRecorder()构造函数时,用户代理必须执行以下步骤:- 令 stream 为构造函数的第一个参数。
- 令 options 为构造函数的第二个参数。
- 令 type 为 options 的
mimeType。 - 如果以 type 和 true 值调用 is
type supported 后返回 false,
则抛出
NotSupportedErrorDOMException并中止这些步骤。 - 令 recorder 为新构造的
MediaRecorder对象。 - 令 recorder 拥有一个内部槽 [[ConstrainedMimeType]],
初始化为 options 的
mimeType成员的值。 - 令 recorder 拥有一个内部槽 [[ConstrainedBitsPerSecond]],
初始化为 options 的
bitsPerSecond成员,如果存在,否则为null。 - 令 recorder 拥有一个内部槽 [[VideoKeyFrameIntervalDuration]],
初始化为 options 的
videoKeyFrameIntervalDuration成员,如果存在,否则为null。 - 令 recorder 拥有一个内部槽 [[VideoKeyFrameIntervalCount]],
初始化为 options 的
videoKeyFrameIntervalCount成员,如果存在,否则为null。 - 初始化 recorder 的
stream属性为 stream。 - 初始化 recorder 的
mimeType属性为 recorder 的 [[ConstrainedMimeType]] 槽的值。 - 初始化 recorder 的
state属性为inactive。 - 初始化 recorder 的
videoBitsPerSecond属性为 options 的videoBitsPerSecond成员的值,如果存在。否则由用户代理为视频选择一个其认为合理的目标值。 - 初始化 recorder 的
audioBitsPerSecond属性为 options 的audioBitsPerSecond成员的值,如果存在。否则由用户代理为音频选择一个其认为合理的目标值。 - 如果 recorder 的 [[ConstrainedBitsPerSecond]] 槽不为
null,则将 recorder 的videoBitsPerSecond和audioBitsPerSecond属性设置为用户代理认为对相应媒体类型合理的值,使videoBitsPerSecond与audioBitsPerSecond之和接近 recorder 的 [[ConstrainedBitsPerSecond]] 槽的值。 - 如果 recorder 支持由
options 的
audioBitrateMode指定的BitrateMode, 则初始化 recorder 的audioBitrateMode属性为 options 的audioBitrateMode成员的值, 否则将 recorder 的audioBitrateMode属性初始化为 "variable"。 - 返回 recorder。
2.2. 属性
stream, 类型为 MediaStream, 只读- 要录制的
MediaStream[GETUSERMEDIA]。 mimeType, 类型为 DOMString, 只读-
MediaRecorder对象使用的 MIME 类型(参见 [RFC2046])。 用户代理应能够回放其支持的任一录制 MIME 类型。 例如,应能够在 HTML <video> 标签中显示视频录制。 state, 类型为 RecordingState, 只读- 当前
MediaRecorder对象的状态。 onstart, 类型为 EventHandler- 用于处理 start 事件。
onstop, 类型为 EventHandler- 用于处理 stop 事件。
ondataavailable, 类型为 EventHandler- 用于处理 dataavailable 事件。录制数据的
Blob包含在该事件中,可通过其data属性访问。 onpause, 类型为 EventHandler- 用于处理 pause 事件。
onresume, 类型为 EventHandler- 用于处理 resume 事件。
onerror, 类型为 EventHandler- 用于处理
ErrorEvent。 videoBitsPerSecond, 类型为 unsigned long, 只读- 用于对视频轨道进行编码的目标比特率。
audioBitsPerSecond, 类型为 unsigned long, 只读- 用于对音频轨道进行编码的目标比特率。
audioBitrateMode, 类型为 BitrateMode, 只读- 用于对音频轨道进行编码的
BitrateMode。
2.3. 方法
state
并异步触发事件。 start(optional unsigned long timeslice)-
当一个
MediaRecorder对象的start()方法被调用时,用户代理(UA)必须执行以下步骤:- 令 recorder 为方法被调用的
MediaRecorder对象。 - 令 timeslice 为方法的第一个参数(如有提供),否则为
undefined。 - 令 stream 为 recorder 的
stream属性的值。 - 令 tracks 为 stream 的
track set 中的
live轨道集合。 - 如果 recorder 的
state属性的值不是inactive, 则抛出InvalidStateErrorDOMException并中止这些步骤。 - 如果 stream 的 隔离属性不允许 recorder 访问,
则抛出
SecurityErrorDOMException并中止这些步骤。 - 如果 stream 是 inactive,则抛出
NotSupportedErrorDOMException并中止这些步骤。 - 如果 [[ConstrainedMimeType]] 槽指定了媒体类型、容器或解码器, 则将 recorder 的配置约束为 [[ConstrainedMimeType]] 槽中指定的媒体类型、容器和解码器。
- 如果 recorder 的 [[ConstrainedBitsPerSecond]] 槽不为
null,则将 recorder 的videoBitsPerSecond和audioBitsPerSecond属性设置为用户代理认为对相应媒体类型在记录 tracks 中所有轨道时合理的值, 使得videoBitsPerSecond与audioBitsPerSecond之和接近 recorder 的 [[ConstrainedBitsPerSecond]] 槽的值。 - 令 videoBitrate 为 recorder 的
videoBitsPerSecond属性的值,并将 recorder 的配置约束为针对将要记录的所有视频轨道 以 videoBitrate 位每秒的总比特率为目标。videoBitrate 是为编码器提供的提示, 该值可能被超出、无法达到,或仅在较长时间内才能达到。 - 令 audioBitrate 为 recorder 的
audioBitsPerSecond属性的值,并将 recorder 的配置约束为针对将要记录的所有音频轨道 以 audioBitrate 位每秒的总比特率为目标。audioBitrate 是为编码器提供的提示, 该值可能被超出、无法达到,或仅在较长时间内才能达到。 -
令 videoKeyFrameIntervalDuration 为
recorder.[[VideoKeyFrameIntervalDuration]],并令
videoKeyFrameIntervalCount 为
recorder.[[VideoKeyFrameIntervalCount]]。用户代理应当
约束 recorder 的配置,使视频编码器遵循下列规则:
- 如果 videoKeyFrameIntervalDuration 不为
null且 videoKeyFrameIntervalCount 为null, 则视频编码器在自上一个关键帧起经过 videoKeyFrameIntervalDuration 毫秒后到达的第一帧产生关键帧。 - 如果 videoKeyFrameIntervalCount 不为
null且 videoKeyFrameIntervalDuration 为null, 则视频编码器在自上一个关键帧起经过 videoKeyFrameIntervalCount 帧后到达的第一帧产生关键帧。 - 如果 videoKeyFrameIntervalDuration 与
videoKeyFrameIntervalCount 都不为
null, 则抛出NotSupportedErrorDOMException并中止这些步骤。 - 如果 videoKeyFrameIntervalDuration 与
videoKeyFrameIntervalCount 均为
null, 则用户代理可按其认为合适的方式发出关键帧。
注意编码器有时会自行决定何时发出关键帧。
- 如果 videoKeyFrameIntervalDuration 不为
- 将 recorder 的配置约束为使用
BitrateMode中由 recorder 的audioBitrateMode属性指定的值对所有将被记录的音频轨道进行编码。 - 对于 tracks 中的每个轨道,如果用户代理无法使用当前配置记录该轨道,
则抛出
NotSupportedErrorDOMException并中止这些步骤。 -
将 recorder 的
state设置为recording, 并并行地运行下列步骤(in parallel):- 如果用于录制的容器和解码器尚未完全指定,用户代理在 recorder 的当前配置中
指定它们。用户代理可以在决定使用哪个容器和解码器时考虑 tracks
中轨道的来源。
通过在开始录制时查看 tracks 中轨道的来源,用户代理 可以选择避免对轨道内容重新编码的配置。例如,如果 MediaStreamTrack 是源自 RTCPeerConnection 的远端轨道,用户代理可以选择与该 MediaStreamTrack 的 RTP 流相同的解码器(如果已知)。然而,如果 RTP 流的解码器在录制期间发生变化,用户代理必须准备好对其进行重新编码以避免中断。
-
如果用户代理不支持 type/subtype、解码器与容器的指定组合,
则必须中止剩余步骤并排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤:
- 使 recorder 失活,参数为 recorder。
- 触发一个错误事件,事件名称为
NotSupportedError,在 recorder 上触发。 - 触发一个事件,事件名称为 stop,在 recorder 上触发。
-
使用 recorder 的当前配置开始记录 tracks 中的所有轨道并将数据收集到一个
Blobblob 中。排队一个使用 DOM 操作任务源的任务来运行以下步骤:- 令 extendedMimeType 为 recorder 的 [[ConstrainedMimeType]] 槽的值。
- 通过添加反映 MediaRecorder 用于记录 tracks 中所有轨道所使用配置的媒体类型、子类型与解码器参数来修改 extendedMimeType(如果尚未存在)。这可能包含配置参数(profiles parameter)[RFC6381] 或其他解码器特定参数。
- 将 recorder 的
mimeType属性设置为 extendedMimeType。 - 触发一个事件,事件名称为 start,在 recorder 上触发。
-
如果在任何时刻 stream 的 隔离属性 发生变化,导致
MediaRecorder不再被允许访问它,UA 必须停止收集数据,丢弃已收集的任何数据,并排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤:- 使 recorder 失活,参数为 recorder。
- 触发一个错误事件,事件名称为
SecurityError,在 recorder 上触发。 - 触发一个 blob 事件,事件名称为 dataavailable,在 recorder 上触发,携带 blob。
- 触发一个事件,事件名称为 stop,在 recorder 上触发。
-
如果在任何时刻,stream 的 track set 中添加或移除轨道,UA 必须停止收集数据,并排队一个使用 DOM
操作任务源的任务,该任务运行以下步骤:
- 使 recorder 失活,参数为 recorder。
- 触发一个错误事件,事件名称为
InvalidModificationError,在 recorder 上触发。 - 触发一个 blob 事件,事件名称为 dataavailable,在 recorder 上触发,携带 blob。
- 触发一个事件,事件名称为 stop,在 recorder 上触发。
-
如果 UA 在任何时刻因除 隔离属性或 stream 的
track set 之外的原因无法继续收集数据,
则必须停止收集数据,并排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤:
- 使 recorder 失活,参数为 recorder。
- 触发一个错误事件,事件名称为
UnknownError,在 recorder 上触发。 - 触发一个 blob 事件,事件名称为 dataavailable,在 recorder 上触发,携带 blob。
- 触发一个事件,事件名称为 stop,在 recorder 上触发。
-
如果 timeslice 不是
undefined,则一旦收集到至少 timeslice 毫秒的数据, 或者 UA 强加的某个最小时间片(以较大者为准),开始将数据收集到一个新的Blobblob 中,并排队一个使用 DOM 操作任务源的任务,该任务 触发一个 blob 事件,事件名称为 dataavailable,在 recorder 上触发,携带 blob。注意,timeslice 的
undefined值将被理解为最大的unsigned long值。 -
如果所有被记录的轨道都变为
ended, 则停止收集数据,并排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤:- 使 recorder 失活,参数为 recorder。
- 触发一个 blob 事件,事件名称为 dataavailable,在 recorder 上触发,携带 blob。
- 触发一个事件,事件名称为 stop,在 recorder 上触发。
- 如果用于录制的容器和解码器尚未完全指定,用户代理在 recorder 的当前配置中
指定它们。用户代理可以在决定使用哪个容器和解码器时考虑 tracks
中轨道的来源。
注意
stop()、requestData()、 和pause()也会影响录制行为。用户代理必须以一种在回放时能检索出原始轨道(Tracks)的方式记录
stream。 当返回多个Blob(由于timeslice或requestData()), 各个 Blob 无需可独立播放,但来自一次完整录制的所有 Blob 的组合必须可播放。如果
MediaStream内的任何 Track 在任一时刻为muted或未enabled, 则用户代理只会记录黑帧或静音,因为那是该 Track 产生的内容。给定 recorder 的 使 recorder 失活 算法如下:
- 将 recorder 的
mimeType属性设置为 [[ConstrainedMimeType]] 槽的值。 - 将 recorder 的
state属性设置为inactive。 - 如果 recorder 的 [[ConstrainedBitsPerSecond]] 槽不为
undefined,则将 recorder 的videoBitsPerSecond和audioBitsPerSecond属性设置为用户代理认为对相应媒体类型合理的值,使得videoBitsPerSecond与audioBitsPerSecond之和接近 recorder 的 [[ConstrainedBitsPerSecond]] 槽的值。
- 令 recorder 为方法被调用的
stop()-
当一个
MediaRecorder对象的stop()方法被调用时,UA 必须执行以下步骤:- 令 recorder 为方法被调用的
MediaRecorder对象。 - 如果 recorder 的
state属性为inactive, 则中止这些步骤。 - 使 recorder 失活,参数为 recorder。
-
排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤:
- 停止收集数据。
- 令 blob 为迄今收集的数据的 Blob,然后 触发一个 blob 事件,事件名称为 dataavailable,在 recorder 上触发,携带 blob。
- 触发一个事件,事件名称为 stop,在 recorder 上触发。
- 返回
undefined。
- 令 recorder 为方法被调用的
pause()-
当一个
MediaRecorder对象的pause()方法被调用时,UA 必须执行以下步骤:- 如果
state为inactive, 则抛出InvalidStateErrorDOMException并中止这些步骤。 - 如果
state为paused, 则中止这些步骤。 -
将
state设置为paused, 并排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤: - 返回
undefined。
- 如果
resume()-
当一个
MediaRecorder对象的resume()方法被调用时,UA 必须执行以下步骤:- 如果
state为inactive, 则抛出InvalidStateErrorDOMException并中止这些步骤。 - 如果
state为recording, 则中止这些步骤。 -
将
state设置为recording, 并排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤: - 返回
undefined。
- 如果
requestData()-
当一个
MediaRecorder对象的requestData()方法被调用时, UA 必须执行以下步骤:-
如果
state为inactive则抛出InvalidStateErrorDOMException并终止这些步骤。否则 UA 必须排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤:- 令 blob 为迄今收集的数据的
Blob,并令 target 为MediaRecorder上下文对象,然后 触发一个 blob 事件,事件名称为 dataavailable,在 target 上触发,携带 blob。 (注意,如果尚未收集到数据,blob 将为空。) - 创建一个新的 Blob 并将随后的数据收集到该 Blob 中。
- 令 blob 为迄今收集的数据的
- 返回
undefined。
-
如果
isTypeSupported(DOMString type)-
此方法已弃用;仅为旧有兼容性目的而存在。
同步公开的解码器标识符列表 为:
"vp8","vp9","h264"亦称"avc1","av1"亦称"av01","hvc1","hev1","avc1","avc3","opus", 以及"pcm"。由于同步检测硬件支持的难度,精确的答案可能依赖于时机。建议用户通过MediaCapabilities来发现具体的配置文件级别和较新的解码器,示例代码如下:const { supported} = await navigator. mediaCapabilities. encodingInfo({ type: "record" , video: { contentType: "video/webm;codecs=av01.0.19M.08" , width: 640 , height: 480 , framerate: 30 , bitrate: 300000 , } }); - 检查
MediaRecorder是否能够以指定的 MIME 类型进行记录。 如果此方法返回 true,仅表明MediaRecorder实现能够为指定的 MIME 类型生成Blob对象。若无足够资源支持具体的媒体编码,录制仍可能失败。当调用此方法时,用户代理必须返回抽象操作 is type supported 的结果,传入方法的第一个参数和布尔值 false。- is type supported 算法,给定 type 和布尔值 deferNewerCodecsCheck,由下列步骤组成。
- 如果 type 是空字符串,则返回 true(注意此情况基本等同于由 UA 决定容器和解码器)。
- 如果 type 不是有效的 MIME 类型字符串,则返回 false。
- 如果 MediaRecorder 不支持 type 中指定的媒体类型/子类型与容器的组合,则返回 false。
- 令 codecStrings 为在 type 中若存在
codecs=后面的字符串按","进行 严格拆分 的 列表 结果,否则为一个空的 列表。 - 如果 codecStrings 包含多于一个音频解码器或多于一个视频解码器,则返回 false。
- 令 codecIdentifiers 为一个空的 列表。
-
对于 codecStrings 中的每个 codecString,运行以下步骤:
- 令 codecIdentifier 为对 codecString 按
"."进行 严格拆分 后第一部分的 ASCII 小写。 - 将 codecIdentifier 追加到 codecIdentifiers。
本算法的其余部分仅测试解码器说明符的标识符部分(例如"av01"),忽略句点之后的任何部分(例如"av01.0.19M.08")。 - 令 codecIdentifier 为对 codecString 按
-
对于 codecIdentifiers 中每个通过 is synchronously exposed 的
codecIdentifier,运行以下步骤:
- 如果 MediaRecorder 不支持该 codecIdentifier 与 type 中指定的媒体类型/子类型和容器的组合,则返回 false。
- 如果 codecIdentifiers 中的任何 codecIdentifier 不是通过 is synchronously exposed 同步公开的,则返回 deferNewerCodecsCheck。
- 返回 true。
- is synchronously exposed 算法,给定 codecIdentifier,由下列步骤组成:
- 如果 同步公开的解码器标识符列表 中的任一项与 codecIdentifier 完全匹配,则返回 true,否则返回 false。
- 检查
2.4. 数据处理
“触发一个 blob 事件”
指用 Blob
类型的 blob,在 target 上
触发一个事件,事件类型为 BlobEvent,
其 data
属性初始化为 blob。
2.5. MediaRecorderOptions
dictionary {MediaRecorderOptions DOMString mimeType = "";unsigned long audioBitsPerSecond ;unsigned long videoBitsPerSecond ;unsigned long bitsPerSecond ;BitrateMode audioBitrateMode = "variable";DOMHighResTimeStamp videoKeyFrameIntervalDuration ;unsigned long videoKeyFrameIntervalCount ; };
2.5.1. 成员
mimeType, 类型为 DOMString,默认为""- 录制所用的容器和编解码格式 [RFC2046], 可包含针对该格式定义的任何参数。
audioBitsPerSecond, 类型为 unsigned long- 音频轨道(如有)的编码汇总目标比特率(位每秒)。
videoBitsPerSecond, 类型为 unsigned long- 视频轨道(如有)的编码汇总目标比特率(位每秒)。
bitsPerSecond, 类型为 unsigned long- 所有现有视频和音频轨道编码的总目标比特率(位每秒)。
此成员覆盖
audioBitsPerSecond或videoBitsPerSecond(如有)。UA 可以自行分配比特率到各轨编码器。 audioBitrateMode, 类型为 BitrateMode,默认为"variable"- 指定编码音频轨道应使用的
BitrateMode。 videoKeyFrameIntervalDuration, 类型为 DOMHighResTimeStamp- 指定编码视频流中关键帧的名义时间间隔。
UA 控制关键帧生成时会同时考虑此成员以及
videoKeyFrameIntervalCount。 videoKeyFrameIntervalCount, 类型为 unsigned long- 指定编码视频流中关键帧的帧数间隔。
UA 控制关键帧生成时会同时考虑此成员以及
videoKeyFrameIntervalDuration。
2.6. BitrateMode
enum {BitrateMode "constant" ,"variable" };
2.6.1. 取值
constant- 以固定比特率编码。
variable- 以可变比特率编码,使复杂信号得到更多空间,简单信号用更少空间。
2.7. RecordingState
enum {RecordingState "inactive" ,"recording" ,"paused" };
2.7.1. 取值
inactive- 未进行录制:要么尚未开始,要么已停止。
recording- 录制已开始,UA 正在捕获数据。
paused- 录制已开始,被暂停,但尚未停止或恢复。
3. Blob 事件
[Exposed =Window ]interface :BlobEvent Event {constructor (DOMString ,type BlobEventInit ); [eventInitDict SameObject ]readonly attribute Blob data ;readonly attribute DOMHighResTimeStamp timecode ; };
3.1. 构造函数
BlobEvent(DOMString type, BlobEventInit eventInitDict)
3.2. 属性
data, 类型为 Blob,只读- 编码后的
Blob, 其type属性指明了 blob 数据的编码类型。 timecode, 类型为 DOMHighResTimeStamp,只读- 对于 MediaRecorder 实例,第一个生成的
BlobEvent的timecode必须为 0。后续BlobEvent的timecode包含该BlobEvent中第一个分片创建时间戳与第一个生成的BlobEvent第一个分片时间戳的差值,作为DOMHighResTimeStamp[HR-TIME]。
3.3. BlobEventInit
dictionary :BlobEventInit EventInit {required Blob data ;DOMHighResTimeStamp timecode ; };
3.3.1. 成员
data, 类型为 Blob- 包含要通过
BlobEvent传递的数据的Blob对象。 timecode, 类型为 DOMHighResTimeStamp- 用于初始化
BlobEvent的时间码。
4. 错误处理
4.1. 一般原则
本节为非规范性内容。当错误在调用时即可被检测到时,UA 会抛出 DOMException。
在所有其他情况下,UA 会触发一个错误事件。如果录制已开始且尚未停止时发生错误,
则令 blob 为目前已收集数据的 Blob;
抛出错误后,UA 会触发一个
dataavailable 事件并携带 blob;
紧接着 UA 会触发一个名为 stop 的事件。
UA 可能会设置特定于平台的限制,例如支持的最小和最大 Blob
大小,或一次可录制的
MediaStreamTrack
数量。
如果超过这些限制,UA 会发出致命错误信号。
4.2. 错误事件
对 fire an error
event,意味着使用 ErrorEvent
作为 eventConstructor 触发事件。
4.3. 异常总结
本文件中定义的每一个异常都是具有特定类型的 DOMException。
| 名称 | 描述 |
|---|---|
InvalidStateError
| 在一个对象上执行了不允许的操作,或操作被调用的时机不允许,或对已删除或移除的源对象发起了请求。 |
NotSupportedError
| 因为不支持的 MIME 类型,或给定的轨道集合无法被该 MIME 类型录制,导致操作无法执行。
用户代理应在 message 属性中提供尽可能多的附加信息。
|
SecurityError
| MediaStream
的隔离属性不允许 MediaRecorder 访问该对象。
|
InvalidModificationError
| 被录制的 MediaStream
的 MediaStreamTrack
集合发生变化,导致无法继续录制。
|
5. 事件汇总
下列附加事件会在 MediaRecorder
对象上触发:
| 事件名称 | 接口 | 触发时机 |
|---|---|---|
start
| Event
| UA 已开始从 MediaStream 录制数据时触发。 |
stop
| Event
| UA 已停止从 MediaStream 录制数据时触发。 |
dataavailable
| BlobEvent
| UA 生成此事件以向应用返回数据。该事件的
data
属性包含已录制数据的 Blob。
|
pause
| Event
| UA 暂停从 MediaStream 录制数据时触发。 |
resume
| Event
| UA 恢复从 MediaStream 录制数据时触发。 |
error
| ErrorEvent
| 发生错误时触发,例如内存不足,或
stream
发生变更,导致无法继续录制
(如录制过程中有 Track 被添加或移除到该 stream)。
|
6. 隐私与安全考虑
本节为非规范性内容。
鉴于 MediaRecorder
的数据源始终会是 MediaStream,
大部分安全性实际上交由 [GETUSERMEDIA] 及其“隐私与安全性考虑”部分处理。
特别地,默认为数据源 MediaStream
来自 安全上下文。
6.1. 资源耗尽
视频和音频编码可能消耗大量资源。恶意网站可能尝试通过配置巨大的负载阻塞或拖垮 UA,如编码大分辨率和/或高帧率。
MediaRecorder
可通过 start()
的 timeslice
参数
设置,在一段时间内保存编码后的数据。time slice 参数过大可能让 UA 缓存大量数据,导致卡顿甚至内存耗尽。
UA 应采取措施防止编码与缓存过程耗尽资源。
6.2. 指纹识别
MediaRecorder
通过 isTypeSupported()
方法,提供对支持的视频和音频 MIME 类型的信息。当未在 MediaRecorderOptions
中指定时,也会为编码器和带宽分配选择合适组合,并可通过事件 type
属性查询;会尝试遵循指定的 MediaRecorderOptions
配置。
恶意网站可用这些信息做主动指纹识别,例如:
-
推测设备硬件特性或操作系统厂商/版本差异:如 UA 仅在特定平台(或系列)才支持特定 codec 或硬件编码加速,或分辨率/帧率有限制,易被指纹识别。
-
通过性能统计推断,如 UA 默认带宽分配因硬件不同而异,或 UA 在编码不同分辨率输入向量时测量系统负载。
UA 应通过如广泛支持特定 codec/MIME 类型并不依赖于体系架构/硬件型号/操作系统版本等方式,缓解指纹表面扩大,防止通过浏览器推断硬件特征。UA 还应通过合理的默认值限制 UA 能力的暴露与可识别性。
7. 示例
7.1. 检查 MediaRecorder
和内容类型支持
此示例检查实现是否支持一些流行的编解码器/容器组合。
if ( window. MediaRecorder== undefined ) { console. error( 'MediaRecorder not supported, boo' ); } else { var contentTypes= [ "video/webm" , "video/webm;codecs=vp8" , "video/x-matroska;codecs=avc1" , "audio/webm" , "video/mp4;codecs=avc1" , "video/invalid" ]; contentTypes. forEach( contentType=> { console. log( contentType+ ' is ' + ( MediaRecorder. isTypeSupported( contentType) ? 'supported' : 'NOT supported ' )); }); }
7.2. 录制摄像头视频及音频
此示例使用 MediaStream
结合 getUserMedia()
捕获视频+音频,
并塞入一个 <video> 标签进行预览,尝试录制并通过 ondataavailable
事件获取录制片段。注意,录制会一直持续直到 MediaRecorder 被 stop()
或被录制 MediaStreamTrack
均
ended。
< html> < body> < video autoplay/> < script> var recordedChunks= []; function gotMedia( stream) { // |video| shows a live view of the captured MediaStream. var video= document. querySelector( 'video' ); video. src= URL. createObjectURL( stream); var recorder= null ; try { recorder= new MediaRecorder( stream, { mimeType: "video/webm" }); } catch ( e) { console. error( 'Exception while creating MediaRecorder: ' + e); return ; } recorder. ondataavailable= ( event) => { console. log( ' Recorded chunk of size ' + event. data. size+ "B" ); recordedChunks. push( event. data); }; recorder. start( 100 ); } navigator. mediaDevices. getUserMedia({ video: true , audio: true }) . then( gotMedia) . catch ( e=> { console. error( 'getUserMedia() failed: ' + e); }); < /script>< /body>< /html>