MediaStream 录制

W3C 工作草案,

关于此文档的更多详细信息
本版本:
https://www.w3.org/TR/2026/WD-mediastream-recording-20260316/
最新发布版本:
https://www.w3.org/TR/mediastream-recording/
编辑草稿:
https://w3c.github.io/mediacapture-record/
以前的版本:
历史:
https://www.w3.org/standards/history/mediastream-recording/
反馈:
public-webrtc@w3.org 主题行为 “[mediastream-recording] … message topic …” (存档
GitHub
编辑:
(Google Inc.)
前任编辑:
Jim Barnett (Genesis)
(Microsoft Corp.)
参与:
邮件列表
GitHub 存储库 (新问题, 开放问题)
实现:
我可以使用媒体录制吗?
Chromium 编码加速支持

摘要

本文件定义了一个用于 MediaStream 的录制 API。

本文件状态

本节描述了本文件在发布日期时的状态。 当前W3C出版物列表及本技术报告的最新修订版 可在 W3C技术报告索引 中找到。

本文件由 Web实时通信工作组 作为工作草案发布,采用 建议路线。 本文件旨在成为W3C推荐标准。

如果您希望对本文件提出意见,请发送至 public-webrtc@w3.org订阅存档)。 发送邮件时, 请在主题中注明“mediastream-recording”, 最好如下格式: “[mediastream-recording] ……评论摘要……”。 欢迎所有评论。

作为工作草案发布并不代表 W3C 及其成员的认可。此为草稿文档,可能随时被 更新、替换或废止。除作为进行中的工作外,不应引用本文件。

本文件由一个遵循 W3C专利政策的工作组产出。 W3C维护一份与该组成果相关的专利披露公开列表; 该页面还包括专利披露的说明。 如个人确知某项专利包含必要权利要求,则必须依据 W3C专利政策第6节 进行信息披露。

本文件受2025年8月18日W3C流程文件管理。

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() 构造函数时,用户代理必须执行以下步骤:
  1. stream 为构造函数的第一个参数。
  2. options 为构造函数的第二个参数。
  3. typeoptionsmimeType
  4. 如果以 type 和 true 值调用 is type supported 后返回 false, 则抛出 NotSupportedError DOMException 并中止这些步骤。
  5. recorder 为新构造的 MediaRecorder 对象。
  6. recorder 拥有一个内部槽 [[ConstrainedMimeType]], 初始化为 optionsmimeType 成员的值。
  7. recorder 拥有一个内部槽 [[ConstrainedBitsPerSecond]], 初始化为 optionsbitsPerSecond 成员,如果存在,否则为 null
  8. recorder 拥有一个内部槽 [[VideoKeyFrameIntervalDuration]], 初始化为 optionsvideoKeyFrameIntervalDuration 成员,如果存在,否则为 null
  9. recorder 拥有一个内部槽 [[VideoKeyFrameIntervalCount]], 初始化为 optionsvideoKeyFrameIntervalCount 成员,如果存在,否则为 null
  10. 初始化 recorderstream 属性为 stream
  11. 初始化 recordermimeType 属性为 recorder[[ConstrainedMimeType]] 槽的值。
  12. 初始化 recorderstate 属性为 inactive
  13. 初始化 recordervideoBitsPerSecond 属性为 optionsvideoBitsPerSecond 成员的值,如果存在。否则由用户代理为视频选择一个其认为合理的目标值。
  14. 初始化 recorderaudioBitsPerSecond 属性为 optionsaudioBitsPerSecond 成员的值,如果存在。否则由用户代理为音频选择一个其认为合理的目标值。
  15. 如果 recorder[[ConstrainedBitsPerSecond]] 槽不为 null,则将 recordervideoBitsPerSecondaudioBitsPerSecond 属性设置为用户代理认为对相应媒体类型合理的值,使 videoBitsPerSecondaudioBitsPerSecond 之和接近 recorder[[ConstrainedBitsPerSecond]] 槽的值。
  16. 如果 recorder 支持由 optionsaudioBitrateMode 指定的 BitrateMode, 则初始化 recorderaudioBitrateMode 属性为 optionsaudioBitrateMode 成员的值, 否则将 recorderaudioBitrateMode 属性初始化为 "variable"。
  17. 返回 recorder

2.2. 属性

stream, 类型为 MediaStream, 只读
要录制的 MediaStream [GETUSERMEDIA]
mimeType, 类型为 DOMString, 只读
MediaRecorder 对象使用的 MIME 类型(参见 [RFC2046])。 用户代理应能够回放其支持的任一录制 MIME 类型。 例如,应能够在 HTML <video> 标签中显示视频录制。
mimeType 通过 type/subtype 组合指定录制的媒体类型和容器格式,并在可能产生歧义的情况下指定 codecs 和/或 profiles 参数 [RFC6381]。 各个 codec 可能还有进一步的可选特定参数。
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)必须执行以下步骤:
  1. recorder 为方法被调用的 MediaRecorder 对象。
  2. timeslice 为方法的第一个参数(如有提供),否则为 undefined
  3. streamrecorderstream 属性的值。
  4. tracksstreamtrack set 中的 live 轨道集合。
  5. 如果 recorderstate 属性的值不是 inactive, 则抛出 InvalidStateError DOMException 并中止这些步骤。
  6. 如果 stream隔离属性不允许 recorder 访问, 则抛出 SecurityError DOMException 并中止这些步骤。
  7. 如果 streaminactive,则抛出 NotSupportedError DOMException 并中止这些步骤。
  8. 如果 [[ConstrainedMimeType]] 槽指定了媒体类型、容器或解码器, 则将 recorder 的配置约束为 [[ConstrainedMimeType]] 槽中指定的媒体类型、容器和解码器。
  9. 如果 recorder[[ConstrainedBitsPerSecond]] 槽不为 null,则将 recordervideoBitsPerSecondaudioBitsPerSecond 属性设置为用户代理认为对相应媒体类型在记录 tracks 中所有轨道时合理的值, 使得 videoBitsPerSecondaudioBitsPerSecond 之和接近 recorder[[ConstrainedBitsPerSecond]] 槽的值。
  10. videoBitraterecordervideoBitsPerSecond 属性的值,并将 recorder 的配置约束为针对将要记录的所有视频轨道 以 videoBitrate 位每秒的总比特率为目标。videoBitrate 是为编码器提供的提示, 该值可能被超出、无法达到,或仅在较长时间内才能达到。
  11. audioBitraterecorderaudioBitsPerSecond 属性的值,并将 recorder 的配置约束为针对将要记录的所有音频轨道 以 audioBitrate 位每秒的总比特率为目标。audioBitrate 是为编码器提供的提示, 该值可能被超出、无法达到,或仅在较长时间内才能达到。
  12. videoKeyFrameIntervalDurationrecorder.[[VideoKeyFrameIntervalDuration]],并令 videoKeyFrameIntervalCountrecorder.[[VideoKeyFrameIntervalCount]]。用户代理应当 约束 recorder 的配置,使视频编码器遵循下列规则:
    • 如果 videoKeyFrameIntervalDuration 不为 nullvideoKeyFrameIntervalCountnull, 则视频编码器在自上一个关键帧起经过 videoKeyFrameIntervalDuration 毫秒后到达的第一帧产生关键帧。
    • 如果 videoKeyFrameIntervalCount 不为 nullvideoKeyFrameIntervalDurationnull, 则视频编码器在自上一个关键帧起经过 videoKeyFrameIntervalCount 帧后到达的第一帧产生关键帧。
    • 如果 videoKeyFrameIntervalDurationvideoKeyFrameIntervalCount 都不为 null, 则抛出 NotSupportedError DOMException 并中止这些步骤。
    • 如果 videoKeyFrameIntervalDurationvideoKeyFrameIntervalCount 均为 null, 则用户代理可按其认为合适的方式发出关键帧。

    注意编码器有时会自行决定何时发出关键帧。

  13. recorder 的配置约束为使用 BitrateMode 中由 recorderaudioBitrateMode 属性指定的值对所有将被记录的音频轨道进行编码。
  14. 对于 tracks 中的每个轨道,如果用户代理无法使用当前配置记录该轨道, 则抛出 NotSupportedError DOMException 并中止这些步骤。
  15. recorderstate 设置为 recording, 并并行地运行下列步骤(in parallel):
    1. 如果用于录制的容器和解码器尚未完全指定,用户代理在 recorder 的当前配置中 指定它们。用户代理可以在决定使用哪个容器和解码器时考虑 tracks 中轨道的来源。
      通过在开始录制时查看 tracks 中轨道的来源,用户代理 可以选择避免对轨道内容重新编码的配置。例如,如果 MediaStreamTrack 是源自 RTCPeerConnection 的远端轨道,用户代理可以选择与该 MediaStreamTrack 的 RTP 流相同的解码器(如果已知)。然而,如果 RTP 流的解码器在录制期间发生变化,用户代理必须准备好对其进行重新编码以避免中断。
    2. 如果用户代理不支持 type/subtype、解码器与容器的指定组合, 则必须中止剩余步骤并排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤:
      1. 使 recorder 失活,参数为 recorder
      2. 触发一个错误事件,事件名称为 NotSupportedError ,在 recorder 上触发。
      3. 触发一个事件,事件名称为 stop,在 recorder 上触发。
    3. 使用 recorder 的当前配置开始记录 tracks 中的所有轨道并将数据收集到一个 Blob blob 中。排队一个使用 DOM 操作任务源的任务来运行以下步骤:
      1. extendedMimeTyperecorder[[ConstrainedMimeType]] 槽的值。
      2. 通过添加反映 MediaRecorder 用于记录 tracks 中所有轨道所使用配置的媒体类型、子类型与解码器参数来修改 extendedMimeType(如果尚未存在)。这可能包含配置参数(profiles parameter)[RFC6381] 或其他解码器特定参数。
      3. recordermimeType 属性设置为 extendedMimeType
      4. 触发一个事件,事件名称为 start,在 recorder 上触发。
    4. 如果在任何时刻 stream隔离属性 发生变化,导致 MediaRecorder 不再被允许访问它,UA 必须停止收集数据,丢弃已收集的任何数据,并排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤:
      1. 使 recorder 失活,参数为 recorder
      2. 触发一个错误事件,事件名称为 SecurityError ,在 recorder 上触发。
      3. 触发一个 blob 事件,事件名称为 dataavailable,在 recorder 上触发,携带 blob
      4. 触发一个事件,事件名称为 stop,在 recorder 上触发。
    5. 如果在任何时刻,streamtrack set 中添加或移除轨道,UA 必须停止收集数据,并排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤:
      1. 使 recorder 失活,参数为 recorder
      2. 触发一个错误事件,事件名称为 InvalidModificationError ,在 recorder 上触发。
      3. 触发一个 blob 事件,事件名称为 dataavailable,在 recorder 上触发,携带 blob
      4. 触发一个事件,事件名称为 stop,在 recorder 上触发。
    6. 如果 UA 在任何时刻因除 隔离属性streamtrack set 之外的原因无法继续收集数据, 则必须停止收集数据,并排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤:
      1. 使 recorder 失活,参数为 recorder
      2. 触发一个错误事件,事件名称为 UnknownError ,在 recorder 上触发。
      3. 触发一个 blob 事件,事件名称为 dataavailable,在 recorder 上触发,携带 blob
      4. 触发一个事件,事件名称为 stop,在 recorder 上触发。
    7. 如果 timeslice 不是 undefined,则一旦收集到至少 timeslice 毫秒的数据, 或者 UA 强加的某个最小时间片(以较大者为准),开始将数据收集到一个新的 Blob blob 中,并排队一个使用 DOM 操作任务源的任务,该任务 触发一个 blob 事件,事件名称为 dataavailable,在 recorder 上触发,携带 blob

      注意,timesliceundefined 值将被理解为最大的 unsigned long 值。

    8. 如果所有被记录的轨道都变为 ended, 则停止收集数据,并排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤:
      1. 使 recorder 失活,参数为 recorder
      2. 触发一个 blob 事件,事件名称为 dataavailable,在 recorder 上触发,携带 blob
      3. 触发一个事件,事件名称为 stop,在 recorder 上触发。

注意 stop()requestData()、 和 pause() 也会影响录制行为。

用户代理必须以一种在回放时能检索出原始轨道(Tracks)的方式记录 stream。 当返回多个 Blob(由于 timeslicerequestData()), 各个 Blob 无需可独立播放,但来自一次完整录制的所有 Blob 的组合必须可播放。

如果 MediaStream 内的任何 Track 在任一时刻为 muted 或未 enabled, 则用户代理只会记录黑帧或静音,因为那是该 Track 产生的内容。

给定 recorder使 recorder 失活 算法如下:

  1. recordermimeType 属性设置为 [[ConstrainedMimeType]] 槽的值。
  2. recorderstate 属性设置为 inactive
  3. 如果 recorder[[ConstrainedBitsPerSecond]] 槽不为 undefined,则将 recordervideoBitsPerSecondaudioBitsPerSecond 属性设置为用户代理认为对相应媒体类型合理的值,使得 videoBitsPerSecondaudioBitsPerSecond 之和接近 recorder[[ConstrainedBitsPerSecond]] 槽的值。
stop()
当一个 MediaRecorder 对象的 stop() 方法被调用时,UA 必须执行以下步骤:
  1. recorder 为方法被调用的 MediaRecorder 对象。
  2. 如果 recorderstate 属性为 inactive, 则中止这些步骤。
  3. 使 recorder 失活,参数为 recorder
  4. 排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤:
    1. 停止收集数据。
    2. blob 为迄今收集的数据的 Blob,然后 触发一个 blob 事件,事件名称为 dataavailable,在 recorder 上触发,携带 blob
    3. 触发一个事件,事件名称为 stop,在 recorder 上触发。
  5. 返回 undefined
pause()
当一个 MediaRecorder 对象的 pause() 方法被调用时,UA 必须执行以下步骤:
  1. 如果 stateinactive, 则抛出 InvalidStateError DOMException 并中止这些步骤。
  2. 如果 statepaused, 则中止这些步骤。
  3. state 设置为 paused, 并排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤:
    1. 停止向 blob 收集数据(但保持其可用,以便将来可以恢复录制)。
    2. target 为 MediaRecorder 上下文对象。 触发一个事件,事件名称为 pause,在 target 上触发。
  4. 返回 undefined
resume()
当一个 MediaRecorder 对象的 resume() 方法被调用时,UA 必须执行以下步骤:
  1. 如果 stateinactive, 则抛出 InvalidStateError DOMException 并中止这些步骤。
  2. 如果 staterecording, 则中止这些步骤。
  3. state 设置为 recording, 并排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤:
    1. 恢复(或继续)向当前 blob 收集数据。
    2. target 为 MediaRecorder 上下文对象。 触发 一个事件,事件名称为 resume ,在 target 上触发。
  4. 返回 undefined
requestData()
当一个 MediaRecorder 对象的 requestData() 方法被调用时, UA 必须执行以下步骤:
  1. 如果 stateinactive 则抛出 InvalidStateError DOMException 并终止这些步骤。否则 UA 必须排队一个使用 DOM 操作任务源的任务,该任务运行以下步骤:
    1. blob 为迄今收集的数据的 Blob ,并令 targetMediaRecorder 上下文对象,然后 触发一个 blob 事件,事件名称为 dataavailable,在 target 上触发,携带 blob。 (注意,如果尚未收集到数据,blob 将为空。)
    2. 创建一个新的 Blob 并将随后的数据收集到该 Blob 中。
  2. 返回 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,由下列步骤组成。
  1. 如果 type 是空字符串,则返回 true(注意此情况基本等同于由 UA 决定容器和解码器)。
  2. 如果 type 不是有效的 MIME 类型字符串,则返回 false。
  3. 如果 MediaRecorder 不支持 type 中指定的媒体类型/子类型与容器的组合,则返回 false。
  4. codecStrings 为在 type 中若存在 codecs= 后面的字符串按 "," 进行 严格拆分列表 结果,否则为一个空的 列表
  5. 如果 codecStrings 包含多于一个音频解码器或多于一个视频解码器,则返回 false。
  6. codecIdentifiers 为一个空的 列表
  7. 对于 codecStrings 中的每个 codecString,运行以下步骤:
    1. codecIdentifier 为对 codecString"." 进行 严格拆分 后第一部分的 ASCII 小写
    2. codecIdentifier 追加到 codecIdentifiers
    本算法的其余部分仅测试解码器说明符的标识符部分(例如 "av01"),忽略句点之后的任何部分(例如 "av01.0.19M.08")。
  8. 对于 codecIdentifiers 中每个通过 is synchronously exposedcodecIdentifier,运行以下步骤:
    1. 如果 MediaRecorder 不支持该 codecIdentifiertype 中指定的媒体类型/子类型和容器的组合,则返回 false。
  9. 如果 codecIdentifiers 中的任何 codecIdentifier 不是通过 is synchronously exposed 同步公开的,则返回 deferNewerCodecsCheck
  10. 返回 true。
is synchronously exposed 算法,给定 codecIdentifier,由下列步骤组成:
  1. 如果 同步公开的解码器标识符列表 中的任一项与 codecIdentifier 完全匹配,则返回 true,否则返回 false。

2.4. 数据处理

触发一个 blob 事件” 指用 Blob 类型的 blob,在 target触发一个事件,事件类型为 BlobEvent, 其 data 属性初始化为 blob

通常 blob 是 UA 在最近一次切换到 recording state 后收集的数据。

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], 可包含针对该格式定义的任何参数。
mimeType 通过 type/subtype 的组合指定录制的媒体类型和容器格式, 如有歧义,还可指定 codecs 和/或 profiles 参数 [RFC6381]。 不同的编解码器还可拥有其它可选或必需的特定参数。
audioBitsPerSecond, 类型为 unsigned long
音频轨道(如有)的编码汇总目标比特率(位每秒)。
videoBitsPerSecond, 类型为 unsigned long
视频轨道(如有)的编码汇总目标比特率(位每秒)。
bitsPerSecond, 类型为 unsigned long
所有现有视频和音频轨道编码的总目标比特率(位每秒)。 此成员覆盖 audioBitsPerSecondvideoBitsPerSecond (如有)。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 实例,第一个生成的 BlobEventtimecode 必须为 0。后续 BlobEventtimecode 包含该 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 被录制的 MediaStreamMediaStreamTrack 集合发生变化,导致无法继续录制。

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/MIME 类型并不依赖于体系架构/硬件型号/操作系统版本等方式,缓解指纹表面扩大,防止通过浏览器推断硬件特征。UA 还应通过合理的默认值限制 UA 能力的暴露与可识别性。

7. 示例

这些示例的略微修改版本可在例如 该 codepen 集合中找到。

7.1. 检查 MediaRecorder 和内容类型支持

此示例检查实现是否支持一些流行的编解码器/容器组合。

下述示例也可以在例如 此 codepen 上找到,基本无修改。
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() 或被录制 MediaStreamTrackended

下述示例也可在例如 此 codepen 上找到,基本未改动。
<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>
可以使用例如 MediaRecorder Web Fundamentals 文章中的 download() 函数将 recordedChunks 保存成文件。

索引

本规范定义的术语

引用定义的术语

参考文献

规范性引用

[DOM]
Anne van Kesteren. DOM 标准。现行标准。 URL: https://dom.spec.whatwg.org/
[FileAPI]
Marijn Kruisselbrink. 文件 API。2025年12月3日。 WD。URL: https://www.w3.org/TR/FileAPI/
[FINGERPRINTING-GUIDANCE]
Nick Doty;Tom Ritter。Web 规范中的浏览器指纹规避。2025年9月25日。NOTE。URL: https://www.w3.org/TR/fingerprinting-guidance/
[GETUSERMEDIA]
Cullen Jennings 等。媒体捕获与流。2025年10月9日。CRD。URL: https://www.w3.org/TR/mediacapture-streams/
[HR-TIME]
Yoav Weiss。高分辨率时间。2026年3月2日。 WD。URL: https://www.w3.org/TR/hr-time-3/
[HTML]
Anne van Kesteren 等。HTML 标准。 现行标准。URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren;Domenic Denicola。Infra 标准。现行标准。URL: https://infra.spec.whatwg.org/
[RFC2046]
N. Freed;N. Borenstein。多用途网际邮件扩展(MIME)第二部分:媒体类型。1996年11月。草案标准。URL: https://www.rfc-editor.org/rfc/rfc2046
[WEBDRIVER-BIDI]
James Graham;Alex Rudenko;Maksim Sadym。WebDriver BiDi。2026年3月9日。WD。URL: https://www.w3.org/TR/webdriver-bidi/
[WEBIDL]
Edgar Chen;Timothy Gu。Web IDL 标准。现行标准。URL: https://webidl.spec.whatwg.org/

补充性引用

[MEDIA-CAPABILITIES]
Jean-Yves Avenard;Mark Foltz。媒体能力。2026年3月16日。WD。URL: https://www.w3.org/TR/media-capabilities/
[RFC6381]
R. Gellens;D. Singer;P. Frojdh。“Bucket”媒体类型的“Codecs”和“Profiles”参数。2011年8月。建议标准。URL: https://www.rfc-editor.org/rfc/rfc6381

IDL 索引

[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);
};

dictionary MediaRecorderOptions {
  DOMString mimeType = "";
  unsigned long audioBitsPerSecond;
  unsigned long videoBitsPerSecond;
  unsigned long bitsPerSecond;
  BitrateMode audioBitrateMode = "variable";
  DOMHighResTimeStamp videoKeyFrameIntervalDuration;
  unsigned long videoKeyFrameIntervalCount;
};

enum BitrateMode {
  "constant",
  "variable"
};

enum RecordingState {
  "inactive",
  "recording",
  "paused"
};

[Exposed=Window]
interface BlobEvent : Event {
  constructor(DOMString type, BlobEventInit eventInitDict);
  [SameObject] readonly attribute Blob data;
  readonly attribute DOMHighResTimeStamp timecode;
};

dictionary BlobEventInit : EventInit {
  required Blob data;
  DOMHighResTimeStamp timecode;
};