3

所以我正在尝试构建一个直播应用程序,并遇到了一个奇怪的问题。

所以我getUserMedia用来从用户那里捕获视频,然后将用户标记为广播公司。然后我用它MediaRecorder来获取实际的视频数据MediaStream并通过 websocket 发送它。

websocket 只是将视频数据广播到所有连接的客户端,但是由于某种原因,它只能在广播者的播放器上正确播放,但是当我尝试从不同的客户端播放相同的确切流时,它只会给我这个错误:

Uncaught DOMException: Failed to execute 'appendBuffer' on 'SourceBuffer': This SourceBuffer has been removed from the parent media source.

当我查看chrome://media-internals时,我看到了这个错误:

00:00:00 94 error Unexpected element ID 0x8c 00:00:00 94 error Append: stream parsing failed. Data size=33926 append_window_start=0 append_window_end=inf 00:00:00 94 pipeline_error CHUNK_DEMUXER_ERROR_APPEND_FAILED

两个客户端上的脚本和所有内容当然是相同的。唯一不同并且我认为可能是罪魁祸首的事实是广播公司的流没有立即开始,因为广播公司首先需要将视频数据发送到 websocket 服务器,以便服务器将任何内容转发回来。然而,非广播客户在流的“中间”跳跃。

唯一的另一个区别是广播是通过同一个套接字下载和上传视频数据,但我不知道这将如何影响问题。

编辑:在运行测试后,两个客户端都连接到 websocket 而没有流式传输视频,然后运行流,两个客户端都工作,这意味着问题确实源于其他客户端在中途跳入流,这将如何修复?

然而,我对这一切都很陌生,所以我不确定这是否是好的推理。作为参考,这是脚本:

var socket = new WebSocket('websocket');
socket.binaryType = 'arraybuffer';

var broadcastMs = new MediaSource();

var video = document.querySelector("#broadcast");
video.src = window.URL.createObjectURL(broadcastMs);

var msReady = false;
var sourceBuffer = false;
var queue = [];

broadcastMs.addEventListener('sourceopen', function(e)
{
    sourceBuffer = broadcastMs.addSourceBuffer('video/webm; codecs="opus,vp8"');

    sourceBuffer.addEventListener('update', function()
    {
        if ( queue.length > 0 && !sourceBuffer.updating )
            sourceBuffer.appendBuffer(queue.shift());
    });

    msReady = true;     
});

socket.onmessage = function(ev)
{
    setTimeout(function()
    {
        if ( msReady )
        {
            if ( sourceBuffer.updating )
                queue.push(ev.data);
            else
                sourceBuffer.appendBuffer(ev.data);
        }
    }, 50);
};
4

2 回答 2

1

您不能只将针放入 WebM 流中。您必须首先发送几个部分来初始化流。

获取 EBML 查看器的副本。 https://code.google.com/archive/p/ebml-viewer/downloads(EBML 是 Matroska 所基于的标准二进制格式。WebM 是 Matroska 的子集。)打开一个 WebM 文件。您将看到一个 Segment 元素,该元素将包含一组配置流的数据。(轨道、编解码器等)所有这些数据,直到第一个集群的开始,都必须首先发送到 MediaSource。之后,您可以从包含关键帧的任何片段开始。

我应该指出,您正在做的是一个已解决的问题。研究 WebRTC 以获得更有效的方法来做到这一点。你得到的控制更少......但很多东西都是免费的。

于 2018-05-08T14:09:28.463 回答
0

根据我使用 MediaRecorder 和 MediaSource 的经验,与视频冻结或返回错误相关的大多数错误可能是由于接收到的块不同步。我相信 webm(也许还有其他媒体类型)需要按照时间码的递增顺序接收块。记录、发送和接收块 Async 可能不会保留时间码的这种递增顺序。

所以,在上面分析了我自己使用 MediaRecorder/MediaSource 冻结视频的经验之后,我改变了我的代码以同步发送录制的块,而不是异步发送。

于 2021-09-11T14:22:19.320 回答