HTML5视频:具有Blob URL的流视频

ste*_*esu 3 javascript video html5 blob html5-video

我有一个Blob数组(二进制数据,实际上-我可以表示它是最有效的。我现在正在使用Blobs,但也许a Uint8Array或某些方法会更好)。每个Blob包含1秒的音频/视频数据。每秒钟都会生成一个新的Blob,并将其附加到我的数组中。因此,代码大致如下所示:

var arrayOfBlobs = [];
setInterval(function() {
    arrayOfBlobs.append(nextChunk());
}, 1000);
Run Code Online (Sandbox Code Playgroud)

我的目标是将音频/视频数据流传输到HTML5元素。我知道可以像这样生成和播放Blob URL:

var src = URL.createObjectURL(arrayOfBlobs[0]);
var video = document.getElementsByTagName("video")[0];
video.src = src;
Run Code Online (Sandbox Code Playgroud)

当然,这只会播放视频的前1秒。我还假设我可以以某种方式将当前数组中的所有Blob小级连接起来,以播放一秒钟以上的时间:

// Something like this (untested)
var concatenatedBlob = new Blob(arrayOfBlobs);
var src = ...
Run Code Online (Sandbox Code Playgroud)

但是,这最终仍然会耗尽数据。由于Blob是不可变的,因此我不知道如何在接收到数据时继续追加数据。

我敢肯定,这是有可能的,因为YouTube和许多其他视频流服务都使用Blob URL进行视频播放。他们是如何做到的?

ste*_*esu 11

经过大量的谷歌搜索后,我设法找到了拼图的缺失部分:MediaSource

有效的过程如下:

  1. 创建一个 MediaSource
  2. MediaSource
  3. 将视频设置src为对象网址
  4. sourceopen活动中,创建一个SourceBuffer
  5. 使用SourceBuffer.appendBuffer()您的所有块添加到视频

这样,您可以在不更改对象URL的情况下继续添加新的视频片段。

注意事项

  • SourceBuffer对象对编解码器非常挑剔。这些必须声明,并且必须准确,否则将不起作用
  • 您一次只能将一个Blob附加到视频数据SourceBuffer,并且直到第一个Blob完成(异步)处理后才能附加第二个Blob。
  • 如果您在SourceBuffer没有调用的情况下向追加了太多数据,.remove()则最终将耗尽RAM,视频将停止播放。我在笔记本电脑上约1小时达到了此限制

范例程式码

根据您的设置,某些操作可能是不必要的(尤其是在我们先创建视频数据队列,SourceBuffer然后再使用缓慢添加队列的部分updateend)。如果您能够等到SourceBuffer创建后开始抓取视频数据,您的代码就会看起来更好。

<html>
<head>
</head>
<body>
    <video id="video"></video>
    <script>
        // As before, I'm regularly grabbing blobs of video data
        // The implementation of "nextChunk" could be various things:
        //   - reading from a MediaRecorder
        //   - reading from an XMLHttpRequest
        //   - reading from a local webcam
        //   - generating the files on the fly in JavaScript
        //   - etc
        var arrayOfBlobs = [];
        setInterval(function() {
            arrayOfBlobs.append(nextChunk());
            // NEW: Try to flush our queue of video data to the video element
            appendToSourceBuffer();
        }, 1000);

        // 1. Create a `MediaSource`
        var mediaSource = new MediaSource();

        // 2. Create an object URL from the `MediaSource`
        var url = URL.createObjectURL(mediaSource);

        // 3. Set the video's `src` to the object URL
        var video = document.getElementById("video");
        video.src = url;

        // 4. On the `sourceopen` event, create a `SourceBuffer`
        var sourceBuffer = null;
        mediaSource.addEventListener("sourceopen", function()
        {
            // NOTE: Browsers are VERY picky about the codec being EXACTLY
            // right here. Make sure you know which codecs you're using!
            sourceBuffer = mediaSource.addSourceBuffer("video/webm; codecs=\"opus,vp8\"");

            // If we requested any video data prior to setting up the SourceBuffer,
            // we want to make sure we only append one blob at a time
            sourceBuffer.addEventListener("updateend", appendToSourceBuffer);
        });

        // 5. Use `SourceBuffer.appendBuffer()` to add all of your chunks to the video
        function appendToSourceBuffer()
        {
            if (
                mediaSource.readyState === "open" &&
                sourceBuffer &&
                sourceBuffer.updating === false
            )
            {
                sourceBuffer.appendBuffer(arrayOfBlobs.shift());
            }

            // Limit the total buffer size to 20 minutes
            // This way we don't run out of RAM
            if (
                video.buffered.length &&
                video.buffered.end(0) - video.buffered.start(0) > 1200
            )
            {
                sourceBuffer.remove(0, video.buffered.end(0) - 1200)
            }
        }
    </script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

此外,这会自动为您提供实时流的DVR功能,因为您会将20分钟的视频数据保留在缓冲区中(只需使用即可查找video.currentTime = ...

  • 嗯,这是在同一侧播放录制的视频块的实现。但是如何从服务器到客户端连续播放视频标签中接收到的视频 blob 数组的缝隙。请参阅我的问题:/sf/ask/3576773931/日 (2认同)