【问题标题】:How to divide a stream into chunks that can be played with the Media Source API?如何将流分成可以使用 Media Source API 播放的块?
【发布时间】:2024-01-10 04:19:01
【问题描述】:

我能够生成使用 MediaRecorder API 记录的数据块。使用 MediaSource API 存储和播放它们。 如果我以正确的顺序将所有块附加到 sourceBuffer,这可以正常工作。

async function recordScreen() {
  recordedChunks = []
  stream = await navigator.mediaDevices.getDisplayMedia(getDisplayMediaOptions)
  mediaRecorder = new MediaRecorder(stream)

  mediaRecorder.ondataavailable = event => {
    if (event.data.size > 0) {
      recordedChunks.push(event.data)
    }
  }
  const interval = setInterval(() => {
    if (isRecording) {
      mediaRecorder.requestData()
    } else {
      clearInterval(interval)
    }
  }, 1000)
  mediaRecorder.start()
  isRecording = true
}

function replay(chunks) {
  const mediaSource = new MediaSource()
  video.src = URL.createObjectURL(mediaSource)

  mediaSource.addEventListener('sourceopen', () => {
    const sourceBuffer = mediaSource.addSourceBuffer()
    const appendChunk = chunk => chunk.arrayBuffer().then(data => sourceBuffer.appendBuffer(data))
    sourceBuffer.addEventListener('updateend', () => {
      if (chunks[i]) {
        appendChunk(chunks[i++])
      } else {
        mediaSource.endOfStream()
      }
    })
    appendChunk(chunks[i++])
  })
}

jsfidle

但是,当我尝试不附加所有块时,问题就开始了。

  • 如何跳过录制视频的开头部分?
  • 如果缺少一个块,在新的块到达之前,视频会不会有一秒钟是空白的?

我知道录制的媒体不仅包含原始视频数据,还包含某种标题信息。但在这一点上,我没有计划我在做什么。 也许你们可以帮助我:

  • 如何检查这些标头信息(非视频数据)?
  • 我可以编辑或添加它们吗?有没有关于如何做到这一点的好资源?

我的目标是抓取任何记录的块,然后播放其中的视频数据。如果不知何故缺少一个块,它应该继续播放以下块。

背景

我正在尝试开发一种可与 webRTC 一起使用 p2p 的实时流媒体解决方案。我知道我可以将流直接放入 RtcConnection 中。但据我所知,这意味着每个对等点只能与另一个对等点共享一个完整的流。如果每个对等方在为实时流做出贡献时会更加灵活,例如共享 1.5 个流。所以我认为通过 RtcDataChannels 共享这些数据是有意义的,收集它们并通过 MediaSource API 播放它。 如果你们对如何做到这一点有任何其他想法,我将不胜感激。

【问题讨论】:

  • “例如共享 1.5 个流”是什么意思?如果要共享多个流,为什么不能启动多个 RTC 连接?关于 X-Y 问题的 Y,你可能很幸运,只需要第一个块,但我不会打赌它会永远在任何地方工作。
  • 我需要为每个连接共享 1 个完整的流。但是,如果一个节点没有能力处理另一个完整的节点怎么办?所以我想尽可能地拆分它
  • 但是“拆分”流是什么意思?像只有一半的视频和音频中只有高于 800Hz 的频率?
  • 我真的不知道。这是我的问题的一部分。我的想法是将流分成数据块,我可以传输给对等方,然后使用 MediaSource API 播放它们。
  • 让我们退后一步,您面临并试图解决的真正问题是什么?

标签: javascript webrtc media-source web-mediarecorder


【解决方案1】:

但是,当我尝试不附加所有块时,问题就开始了。

You Can't Do That™。

这些 MediaRecorder 流以一堆头信息开始,这些信息是在 MediaSource 中启动解码所必需的。他们不会重复这些信息。

而且,该标头信息与传递给ondataavailable 的块并没有很好地对齐。叹息。

此外,压缩视频(您从 getDisplayMedia / MediaRecorder 获得的内容)由关键帧和帧间组成。没有关键帧,帧间就没有意义。

可能会解析出流以捕获标头信息。在Matroska 中,它是EMBL head 元素和Segment 序言。然后,您也许可以仅将其发送到 MediaSource,然后是最新的 Cluster 元素。但我不知道有谁这样做过。

而且,如果您尝试进行多对多会话(所谓的“群”),您的每个客户端都需要将所有数据发送给其他所有客户端。这让带宽很快变得令人望而却步。

mediasoup 和其他所谓的选择性转发单元为此提供了面向服务器的 WebRTC 解决方案。 WebRTC 包含各种让流数据源刷新的东西——按需发送关键帧。

【讨论】:

  • "有可能解析出流来捕获标头信息"我该怎么做?
  • 第一步。了解 Matroska(视频/网络拳击格式)。第二步:使用浏览器中的ebml 代码来解析流并捕获您想要的内容。对此进行解释远远超出了 Stack Overflow 答案的范围,除非有人已经创建了一个包来执行此操作。我没有。