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

时间:2019-05-09 03:46:40

标签: javascript socket.io video-streaming media-source web-mediarecorder

下面的代码在先加载视频观察客户端然后再加载网络摄像头客户端时可以正常工作,但是,如果切换了顺序或以任何方式中断流(例如通过刷新任一客户端),则流将完美运行失败,媒体源将其就绪状态更改为关闭。

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

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

相机客户端

Node* new_node = new Node;

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

观察客户

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

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

1 个答案:

答案 0 :(得分:0)

  

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

正确!

要解决此问题,您需要对WebM格式有所了解。 WebM只是Matroska(MKV)的子集。 Matroska是用于在EBML中存储媒体的架构的规范。 EBML是二进制文件格式,可以具有任意块。可以将其视为二进制XML。

这意味着您可以使用EBML Viewer之类的工具来检查WebM文件,并参考Matroska规范以了解正在发生的情况。例如:

EBMLViewer Example

这是对预先记录的WebM文件的检查。它将在浏览器中正常播放。您会注意到其中嵌套了一些元素。

每个WebM文件中都有两个顶级元素。 EBML(定义此二进制文件)和Segment(包含其后的所有内容)。

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

在所有这些元数据之后,您会找到ClusterClusterCluster等。这些是您可以在其中剪切WebM流的地方 ,前提是每个Cluster都以关键帧开头。

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

  • 将第一个Cluster之前的所有数据保存为“初始化数据”。​​
  • 此后在Cluster上拆分。

播放时:

  • 首先使用之前保存的“初始化数据”。​​
  • 此后Cluster s开始加载,从流中的任意位置开始。

现在,谁需要一个关键帧位很重要。据我所知,无法配置MediaRecorder来做到这一点,浏览器对此特别挑剔。至少,您必须重新混合服务器端...您甚至可能需要重新编码。另请参阅:Encoding FFMPEG to MPEG-DASH – or WebM with Keyframe Clusters – for MediaSource API

  

将媒体源与socket.io一起使用

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