Search code examples
javascripthtmlxmlhttprequest

XMLHTTPrequest plain text to blob (video)


I achieved to get a video from php using this code :

var some_video_element = document.querySelector('video')
var req = new XMLHttpRequest();
req.onload = function () {
    var blob_uri = URL.createObjectURL(this.response);
    some_video_element.src = blob_uri;
    some_video_element.addEventListener('oncanplaythrough', (e) => {
       URL.revokeObjectURL(blob_uri);
    });
};
req.open("get", "vid.php", true);
req.overrideMimeType('blob');
req.send(null);

However, the loading is long so I want to show data as soon as I get it. From Mozilia, it is indicated we can use plain or "" as mime to get the text in progress. However, I can't achieve to convert plain/text to video/mp4 using a blob. Currently this is the code that doesn't work. I try to get the video when some part is available while the rest is still downloading.

var some_video_element = document.querySelector('video')
var req = new XMLHttpRequest();
req.onprogress = function () {
    var text = b64toBlob(Base64.encode(this.response), "video/mp4");
    var blob_uri = URL.createObjectURL(text);
    some_video_element.src = blob_uri;
    some_video_element.addEventListener('oncanplaythrough', (e) => {
       URL.revokeObjectURL(blob_uri);
    });
};
req.onload = function () {
    var text = b64toBlob(this.response, "video/mp4");
    var blob_uri = URL.createObjectURL(text);
    some_video_element.src = blob_uri;
    some_video_element.addEventListener('oncanplaythrough', (e) => {
       URL.revokeObjectURL(blob_uri);
    });
};
req.open("get", "vid.php", true);
req.overrideMimeType('text\/plain');
req.send(null);

Thanks. NB : This JavaScript is fetching for this php code : https://codesamplez.com/programming/php-html5-video-streaming-tutorial But echo data has been changed by echo base64_encode(data);


Solution

  • If you use the Fetch API instead of XMLHttpRequest you can consume the response as a ReadableStream which can be fed into a SourceBuffer. This will allow the video to be playable as soon as it starts to load instead of waiting for the full file to download. This does not require any special video container formats, back-end processing or third-party libraries.

    const vid = document.getElementById('vid');
    const format = 'video/webm; codecs="vp8,vorbis"';
    const mediaSource = new MediaSource();
    let sourceBuffer = null;
    
    mediaSource.addEventListener('sourceopen', event => {
      sourceBuffer = mediaSource.addSourceBuffer(format);
      fetch('https://bes.works/dev/samples/test.webm')
      .then(response => process(response.body.getReader()))
      .catch(err => console.error(err));
    }); vid.src = URL.createObjectURL(mediaSource);
    
    function process(stream) {
      return new Response(
        new ReadableStream({
          start(controller) {
            async function read() {
              let { done, value } = await stream.read();
              if (done) { controller.close(); return; }
              sourceBuffer.appendBuffer(value);
              sourceBuffer.addEventListener(
                'updateend', event => read(),
                { once: true }
              );
            } read();
          }
        })
      );
    }
    video { width: 300px; }
    <video id="vid" controls></video>