HTML5 视频:使用 Blob URL 流式传输视频 [英] HTML5 Video: Streaming Video with Blob URLs

查看:74
本文介绍了HTML5 视频:使用 Blob URL 流式传输视频的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Blob 数组(实际上是二进制数据——我可以表达它,但它是最有效的.我现在使用 Blob,但也许 Uint8Array 或其他东西会更好).每个 Blob 包含 1 秒的音频/视频数据.每秒都会生成一个新的 Blob 并将其附加到我的数组中.所以代码大致是这样的:

I have an array of Blobs (binary data, really -- I can express it however is most efficient. I'm using Blobs for now but maybe a Uint8Array or something would be better). Each Blob contains 1 second of audio/video data. Every second a new Blob is generated and appended to my array. So the code roughly looks like so:

var arrayOfBlobs = [];
setInterval(function() {
    arrayOfBlobs.append(nextChunk());
}, 1000);

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

My goal is to stream this audio/video data to an HTML5 element. I know that a Blob URL can be generated and played like so:

var src = URL.createObjectURL(arrayOfBlobs[0]);
var video = document.getElementsByTagName("video")[0];
video.src = src;

当然这只会播放视频的前 1 秒.我还假设我可以以某种方式简单地连接当前在我的阵列中的所有 Blob 以播放超过一秒钟:

Of course this only plays the first 1 second of video. I also assume I can trivially concatenate all of the Blobs currently in my array somehow to play more than one second:

// Something like this (untested)
var concatenatedBlob = new Blob(arrayOfBlobs);
var src = ...

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

However this will still eventually run out of data. As Blobs are immutable, I don't know how to keep appending data as it's received.

我确信这应该是可能的,因为 YouTube 和许多其他视频流服务使用 Blob URL 进行视频播放.他们是如何做到的?

I'm certain this should be possible because YouTube and many other video streaming services utilize Blob URLs for video playback. How do they do it?

推荐答案

解决方案

经过一些重要的谷歌搜索后,我设法找到了拼图的缺失部分:媒体来源

实际上这个过程是这样的:

Effectively the process goes like this:

  1. 创建一个MediaSource
  2. MediaSource
  3. 创建一个对象 URL
  4. 将视频的 src 设置为对象 URL
  5. sourceopen 事件上,创建一个 SourceBuffer
  6. 使用 SourceBuffer.appendBuffer() 将所有块添加到视频中
  1. Create a MediaSource
  2. Create an object URL from the MediaSource
  3. Set the video's src to the object URL
  4. On the sourceopen event, create a SourceBuffer
  5. Use SourceBuffer.appendBuffer() to add all of your chunks to the video

通过这种方式,您可以在不更改对象 URL 的情况下继续添加新的视频位.

This way you can keep adding new bits of video without changing the object URL.

  • SourceBuffer 对象对编解码器非常挑剔.这些必须声明,并且必须准确,否则将不起作用
  • 一次只能向 SourceBuffer 添加一个视频数据块,并且在第一个块完成(异步)处理之前不能添加第二个块
  • 如果在没有调用 .remove() 的情况下将过多数据附加到 SourceBuffer,那么最终会耗尽 RAM,视频将停止播放.我在笔记本电脑上达到了大约 1 小时的限制
  • The SourceBuffer object is very picky about codecs. These have to be declared, and must be exact, or it won't work
  • You can only append one blob of video data to the SourceBuffer at a time, and you can't append a second blob until the first one has finished (asynchronously) processing
  • If you append too much data to the SourceBuffer without calling .remove() then you'll eventually run out of RAM and the video will stop playing. I hit this limit around 1 hour on my laptop

根据您的设置,其中一些可能是不必要的(特别是我们在拥有 SourceBuffer 之前构建视频数据队列的部分,然后使用 updateend 慢慢地附加我们的队列代码>).如果您能够等到 SourceBuffer 创建后开始抓取视频数据,您的代码看起来会更好.

Depending on your setup, some of this may be unnecessary (particularly the part where we build a queue of video data before we have a SourceBuffer then slowly append our queue using updateend). If you are able to wait until the SourceBuffer has been created to start grabbing video data, your code will look much nicer.

<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>

作为一个额外的好处,这会自动为您提供实时流的 DVR 功能,因为您在缓冲区中保留了 20 分钟的视频数据(您只需使用 video.currentTime = ...)

As an added bonus this automatically gives you DVR functionality for live streams, because you're retaining 20 minutes of video data in your buffer (you can seek by simply using video.currentTime = ...)

这篇关于HTML5 视频:使用 Blob URL 流式传输视频的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆