无法使用带有 socket.io 的媒体源从媒体记录器跳转到流

2024-07-01

当首先加载视频观察客户端然后加载网络摄像头客户端时,以下代码可以正常工作,但是,如果顺序交换或以任何方式中断流,例如通过刷新任一客户端,则流将失败并且媒体源会将其就绪状态更改为关闭。

我的假设是,在开始时接收的视频需要初始化标头才能启动,并且由于流是在中流读取的,因此它永远不会获得所述初始化标头。我不确定如何将这样的标头添加到 webm 文件中。

我尝试更改源缓冲区上的序列模式,但没有执行任何操作。我尝试重新启动录像机并且可行,但我的最终计划是拥有多个观察客户端,并且每次重新连接时重新启动录像机并不是最佳选择。

相机客户端

main();
function main() {
    if (hasGetUserMedia()) {
        const constraints = {
            video: {
                facingMode: 'environment',
                frameRate: {
                    ideal: 10,
                    max: 15
                }
            },
            audio: true
        };

        navigator.mediaDevices.getUserMedia(constraints).
        then(stream => {
            setupRecorder(stream);
        });
    }
}

function setupRecorder(stream) {
    let mediaRecorder = new MediaRecorder(stream, {
        mimeType: 'video/webm; codecs="opus, vp9"'
    });

    mediaRecorder.ondataavailable = e => {
        var blob = e.data;
        socket.emit('video', blob);
    }

    mediaRecorder.start(500);
}

服务器只广播收到的任何内容

观察客户

var sourceBuffer;
var queue = [];
var mediaSource = new MediaSource();
mediaSource.addEventListener('sourceopen', sourceOpen, false);
main();

socket.on('stream', data => {
    if (mediaSource.readyState == "open") {
        if (sourceBuffer.updating || queue.length > 0) {
            queue.push(data.video);
        } else {
            sourceBuffer.appendBuffer(data.video);
        }
    }
});

function main() {
    videoElement = document.querySelector('#video');
    videoElement.src = URL.createObjectURL(mediaSource);
}

function sourceOpen(e) {
    console.log('open');
    sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="opus, vp9"');
    sourceBuffer.addEventListener('updateend', () => {
        console.log(sourceBuffer.updating, mediaSource.readyState);

        if (queue.length > 0 && !sourceBuffer.updating) {
            sourceBuffer.appendBuffer(queue.shift());
        }
    });
}

因此,实际上,代码的工作方式不正确,因此套接字发送的服务器没有任何问题。它与 MediaRecorder 或 MediaSource 有关。


我的假设是,在开始时接收的视频需要初始化标头才能启动,并且由于流是在中流读取的,因此它永远不会获得所述初始化标头。

Correct!

要解决这个问题,您需要了解一些 WebM 格式。 WebM 只是 Matroska (MKV) 的一个子集。Matroska https://www.matroska.org/technical/diagram/index.html是用于在 EBML 中存储媒体的模式规范。EBML http://matroska-org.github.io/libebml/specs.html是一种可以具有任意块的二进制文件格式。将其视为二进制 XML。

这意味着您可以使用类似的工具EBML 查看器 https://code.google.com/archive/p/ebml-viewer/downloads检查 WebM 文件,并参考 Matroska 规范来了解发生了什么。例如:

这是对预先录制的 WebM 文件的检查。它将在浏览器中正常运行。您会注意到有些元素是嵌套的。

每个 WebM 文件中都有两个顶级元素。EBML,它定义了这个二进制文件,并且Segment其中包含之后的所有内容。

Within Segment有几个因素对您来说很重要。其中之一是Tracks。您会注意到该文件有两个轨道,一个用于 Opus 中的音频,一个用于 VP9 中的视频。另一个重要的块是Info,其中包含有关时间刻度的信息和有关复用器的一些元数据。

在所有这些元数据之后,您会发现Cluster, Cluster, Cluster, etc. 这些是您可以剪切 WebM 流的地方,假设每个Cluster从关键帧开始。

换句话说,您的代码应该执行以下操作:

  • 保存第一个之前的所有数据Cluster作为“初始化数据”。
  • 分裂于Cluster在那之后。

播放时:

  • 使用之前保存的“初始化数据”作为加载的第一个数据。
  • 开始加载Cluster之后,从流中您想要的任何位置开始。

现在,谁集群需要关键帧这一点很重要。据我所知,没有办法配置 MediaRecorder 来执行此操作,并且浏览器对此特别挑剔。至少,您必须在服务器端重新混合......您甚至可能需要重新编码。也可以看看:将 FFMPEG 编码为 MPEG-DASH – 或使用关键帧簇的 WebM – 用于 MediaSource API https://stackoverflow.com/questions/24152810/encoding-ffmpeg-to-mpeg-dash-or-webm-with-keyframe-clusters-for-mediasource/45172617#45172617

通过 socket.io 使用媒体源

我应该指出,您甚至不需要 MediaSource。你绝对不需要Socket.IO。它可以像通过普通 HTTP 流输出此数据一样简单。这可以直接加载到<video>元素。 (如果您想要额外的控制,请务必使用 MediaSource,但这不是必需的。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

无法使用带有 socket.io 的媒体源从媒体记录器跳转到流 的相关文章

  • 如何在javascript中获取表中复选框的值

    我需要获取表行中提供跨度的复选框的值 下面的代码是我的项目的一部分 HTML 代码用于动态我的表格 而 javascript 代码用于获取不适用于复选框的元素的值 它适用于其他输入元素 我的桌子 var html tr class rows
  • 获取 ES6 符号的描述

    我想知道是否有一种很好的方法来获取符号的描述 例如 var s Symbol 5 toString 的默认实现将简单地打印 符号 5 我想找到一种方法来提取实际描述 即 5 Symbol description https develope
  • 角度变量初始化

    我在角度控制器中有一个变量 scope abc 我有 Sails 作为后端 scope abc的初始值可以由后端在生成页面时确定 页面显示给用户后 scope abc 可能会也可能不会被用户更改 我可以让后端生成一个完整的静态页面 并让 A
  • 为什么我的 OpenLayers 3 地图未在 Internet Explorer 11 中显示?

    I am trying to serve up a map in Internet Explorer that works fine in Firefox or Chrome While debugging I noticed that s
  • 在 location.reload() 之后保持滚动位置

    我使用ajax 来更新所选的照片 如果成功 则刷新页面 用户可以看到所选的图像 它将有一个CSS边框 但当页面刷新时 位置又会回到顶部 我想知道重载后如何保持位置 我搜索了很多网站 仍然无法得到它 请指导我一下谢谢 EDIT 我在这里找到了
  • 将元素粘贴到滚动上固定元素的底部?

    基本上 我想要实现的目标是让辅助导航在滚动时与主导航的底部相遇后立即粘在主导航的底部 我仍在学习 jQuery 并且我已经开始抓狂了 编辑 意识到我没有解释到目前为止我已经到了哪里 该类被添加到元素中 但是它没有固定在主标题下方 而是从视口
  • 使用 Razor,如何将布尔值渲染为 JavaScript 变量?

    如何将布尔值呈现给 cshtml 文件中的 JavaScript 变量 目前这显示了一个语法错误 您可能还想尝试 isFollowing Model IsFollowing true 更好的方法是使用 isFollowing Json En
  • 在另一个函数中使用两个不同的axios request函数

    如何在另一个函数中调用两个不同的axios函数 仅当第一个函数成功并返回 200 时 才能调用或实现第二个函数 functions js有两个函数将被导出以在server js 请求的正文是从 json 文件导入的 functions js
  • 如何从javascript中的base 64字符串获取图像文件大小? [复制]

    这个问题在这里已经有答案了 我有图像的 Base64 数据 data image png base64 iVBORw0KGgoAAAANSUhEUgAAAOcAAABnCAYAAAD7RFX4AAAACXBIWXMAAAsTAAALEwEA
  • 硒元素不相互作用

    我开始使用selenium node js 到目前为止一切正常 突然相同的脚本抛出错误 未处理的承诺拒绝警告元素不可交互 我尝试设置等待 直到什么也没有
  • 使用 Javascript 隐藏数据网格列?

    我有一个包含大约 20 列的 net 数据网格 我需要使用 JavaScript 通过单击按钮来切换列的可见性 有任何想法吗 您想使用 COLGROUP 来执行此操作 否则您必须应用样式every细胞开启everyrow 这将非常低效 并且
  • 限制 JavaScript 函数调用,但进行排队(不丢弃调用)

    函数如何限制其调用速率 如果调用过于频繁 则不应丢弃 而应排队并及时间隔开 相隔 X 毫秒 我看过throttle http drupalmotion com article debounce and throttle visual exp
  • Phantomjs / Casper.js 带有旋转代理?

    我有一个简单的目标 使用以下任一方式加载网页phantom js 开箱即用 或casper js 很好也更容易 但是使用代理并旋转它如果当前列表不好 即网页加载失败或类似情况 则从列表中选择 我知道 casper js 有 proxypar
  • 未捕获的 NotFoundError:无法在“Node”上执行“insertBefore”:

    我有一个div另外三个里面的哪里div附加如下 状态值是通过循环 api 的结果来设置的componentWillReceiveProps 但我遇到了一个错误的问题 Uncaught NotFoundError Failed to exec
  • 根据特殊性对一组 CSS 选择器进行排序

    如何根据 JS 函数中的 CSS 特殊性对一组 CSS 选择器进行排序 function SortByCssSpecificity input array of css selectors return sorted array of cs
  • Javascript“悬停时”循环

    任何人都可以帮助我解决这个问题 我有一个按钮 当悬停时会触发一个操作 但我希望只要按钮悬停就重复它 我很感激任何解决方案 无论是在 jquery 还是纯 javascript 中 这是我的代码此时的样子 在 jquery 中 var scr
  • 从 Verdaccio 软件包版本历史记录中删除版本

    我使用取消发布版本npm unpublish
  • HTML / Javascript - 通过单击父行来展开和折叠表行(子行)

    我几天来一直在尝试解决一个问题 终于明白 如 果没有帮助 我将不会成功 我想做一件我们每天在互联网上看到的常见事情 能够单击表格行以显示更多详细信息 但这里的更多细节并不意味着文本块 而是指与父行具有相同形状的子行 以下是 HTML 表格的
  • 为 div 标签设置属性

    我有一个简单的代码 div class content div 我想使用 javascript 回显 div 标签内的某些内容以显示这种方式 div class content div 我需要使用 javascript 因为如果屏幕宽于 9
  • 为 div 标签设置属性

    我有一个简单的代码 div class content div 我想使用 javascript 回显 div 标签内的某些内容以显示这种方式 div class content div 我需要使用 javascript 因为如果屏幕宽于 9

随机推荐