javascript - 如何将流分成可以使用 Media Source API 播放的块?
问题描述
我能够生成使用 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++])
})
}
但是,当我尝试不附加所有块时,问题就开始了。
- 如何跳过录制视频的开头?
- 如果缺少一个块,在新的块到达之前,视频是否有可能是空白的一秒钟?
我知道录制的媒体不仅包含原始视频数据,还包含某种标题信息。但在这一点上,我没有计划我在做什么。也许你们可以帮助我:
- 如何检查这些标头信息(非视频数据)?
- 我可以编辑或添加它们吗?有没有关于如何做到这一点的好资源?
我的目标是抓取任何记录的块,然后播放其中的视频数据。如果不知何故缺少一个块,它应该继续播放以下块。
背景
我正在尝试开发一个与 webRTC 一起使用 p2p 的实时流媒体解决方案。我知道我可以将流直接放入 RtcConnection 中。但据我所知,这意味着每个对等点只能与另一个对等点共享一个完整的流。如果每个对等方能够更灵活地为直播流做出贡献,例如共享 1.5 个流,那就太好了。所以我认为通过 RtcDataChannels 共享这些数据是有意义的,收集它们并通过 MediaSource API 播放它。如果你们对如何做到这一点有任何其他想法,我将不胜感激。
解决方案
但是,当我尝试不附加所有块时,问题就开始了。
你不能那样做™。
这些 MediaRecorder 流以一堆头信息开始,这些信息是在 MediaSource 中启动解码所必需的。他们不会重复这些信息。
而且,该标头信息与传递给ondataavailable
. 叹。
更重要的是,压缩视频(您从 getDisplayMedia / MediaRecorder 获得的内容)由关键帧和帧间组成。没有关键帧,帧间没有意义。
有可能解析出流以捕获标头信息。在Matroska中,它是EMBL head
元素和Segment
序幕。然后,您也许可以仅将其发送到 MediaSource,然后是最新的Cluster
元素。但我不知道有谁这样做过。
而且,如果您尝试进行多对多会话(所谓的“群”),您的客户端将需要将所有数据发送给其他所有客户端。这让带宽很快变得令人望而却步。
mediasoup和其他所谓的选择性转发单元为此提供了面向服务器的 WebRTC 解决方案。WebRTC 包含各种让流数据源刷新的东西——按需发送关键帧。
推荐阅读
- javascript - 地图函数的返回
- kubernetes - Kubernetes:如何实现 0 停机时间
- php - 在 WooCommerce 中的“销售”文本旁边添加销售百分比
- javascript - 使用 React 时我应该使用什么来代替 document.queryselector()?
- android - 如何在英语应用程序中管理 RTL 语言电话
- node.js - UnauthorizedError:无效算法 - Node.js express-jwt
- sql - 如何找到一年多一天订单超过 1 笔的客户
- asp.net - 创建表时出错:指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束
- node.js - URL 解析 NodeJS 已弃用
- javascript - 在 JavaScript 中将圆转换为折线