HTML5 Video: Streaming Video with Blob URLs

后端 未结 1 798
情歌与酒
情歌与酒 2020-12-07 17:08

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

相关标签:
1条回答
  • 2020-12-07 17:56

    Solution

    After some significant Googling I managed to find the missing piece to the puzzle: MediaSource

    Effectively the process goes like this:

    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

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

    Caveats

    • 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

    Example Code

    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>
    

    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 = ...)

    0 讨论(0)
提交回复
热议问题