Giter VIP home page Giter VIP logo

Comments (3)

anuragteapot avatar anuragteapot commented on September 4, 2024 3

@IShinji @dstaubsauger

I try this code

`var video = document.querySelector("video");

  var assetURL = "frag_bunny.mp4";
  var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
  var totalSegments;
  var segmentLength = 0;
  var segmentDuration = 0;
  var seeking = false;
  var bytesFetched = 0;

  var requestedSegments = [];

  var mediaSource = null;
  if ("MediaSource" in window && MediaSource.isTypeSupported(mimeCodec)) {
    mediaSource = new MediaSource();
    video.src = URL.createObjectURL(mediaSource);
    mediaSource.addEventListener("sourceopen", sourceOpen);
  } else {
    console.error("Unsupported MIME type or codec: ", mimeCodec);
  }
  var sourceBuffer = null;

  function sourceOpen(_) {
    sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
    sourceBuffer.mode = "sequence";
    getFileLength(assetURL, function(fileLength) {
      // console.log((fileLength / 1024 / 1024).toFixed(2), "MB");
      totalSegments = (fileLength / 1024 / 1024).toFixed(0);
      for (var i = 0; i < totalSegments; ++i) requestedSegments[i] = false;

      segmentLength = Math.round(fileLength / totalSegments);

      fetchRange(assetURL, 0, segmentLength, appendSegment);
      requestedSegments[0] = true;
      video.addEventListener("timeupdate", checkBuffer);
      video.addEventListener("canplay", function() {
        segmentDuration = video.duration / totalSegments;
        const promise = video.play();
        if (promise !== undefined) {
          promise
            .then(_ => {
              console.log(_);
              // Autoplay started!
            })
            .catch(error => {
              // Autoplay was prevented.
              // Show a "Play" button so that user can start playback.
            });
        }
      });

      video.addEventListener("seeking", debounce(handleSeek, 500));
      video.addEventListener("seeked", onSeeked);
    });
  }

  function debounce(func, wait, immediate) {
    var timeout;
    return function() {
      var context = this;
      var args = arguments;
      var later = function() {
        timeout = null;
        if (!immediate) func.apply(context, args);
      };
      var callNow = immediate && !timeout;
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
      if (callNow) func.apply(context, args);
    };
  }

  function getFileLength(url, cb) {
    var xhr = new XMLHttpRequest();
    xhr.open("head", url);
    xhr.onload = function() {
      cb(xhr.getResponseHeader("content-length"));
    };
    xhr.send();
  }

  function onSeeked() {
    console.log("seeked");
  }

  function fetchRange(url, start, end, cb) {
    return new Promise((resolve, reject) => {
      var xhr = new XMLHttpRequest();
      xhr.open("get", url);
      xhr.responseType = "arraybuffer";
      xhr.setRequestHeader("Range", "bytes=" + start + "-" + end);
      xhr.onload = function() {
        console.log("fetched bytes: ", start, end);
        bytesFetched += end - start + 1;
        resolve(cb(xhr.response));
      };
      xhr.send();
    });
  }

  function appendSegment(chunk) {
    return sourceBuffer.appendBuffer(chunk);
  }

  async function checkBuffer() {
    console.log("check Buffer");
    if (seeking) {
      return true;
    }
    var nextSegment = getNextSegment();
    if (nextSegment === totalSegments && haveAllSegments()) {
      mediaSource.endOfStream();
      video.removeEventListener("timeupdate", checkBuffer);
    } else if (shouldFetchNextSegment(nextSegment)) {
      requestedSegments[nextSegment] = true;

      await fetchRange(
        assetURL,
        bytesFetched,
        bytesFetched + segmentLength,
        appendSegment
      );
    }
  }

  async function handleSeek() {
    console.log("seeking");
    seeking = true;
    var nextSegment = getNextSegment();
    if (nextSegment === totalSegments && haveAllSegments()) {
      mediaSource.endOfStream();
      video.removeEventListener("timeupdate", checkBuffer);
    } else {
      // sourceBuffer.abort();
      for (let segment = 1; segment < nextSegment; segment++) {
        if (shouldFetchNextSegment(segment)) {
          requestedSegments[segment] = true;

          // console.log({ bytesFetched, next: bytesFetched + segmentLength });

          await fetchRange(
            assetURL,
            bytesFetched,
            bytesFetched + segmentLength,
            appendSegment
          );
        }
      }
    }
    seeking = false;
  }

  function seek(e) {
    if (mediaSource.readyState === "open") {
      handleSeek();
    } else {
      console.log("seek but not open?");
      console.log(mediaSource.readyState);
    }
  }

  function getNextSegment() {
    return ((video.currentTime / segmentDuration) | 0) + 1;
  }

  function haveAllSegments() {
    return requestedSegments.every(function(val) {
      return !!val;
    });
  }

  function shouldFetchNextSegment(nextSegment) {
    // console.log(nextSegment);
    // console.log({
    //   nextSegment,
    //   currentTime: video.currentTime,
    //   val: segmentDuration * nextSegment * 0.1,
    //   bool: requestedSegments[nextSegment]
    // });
    return (
      video.currentTime > segmentDuration * nextSegment * 0.1 &&
      requestedSegments[nextSegment] == false
    );
  }`

from netfix.

IShinji avatar IShinji commented on September 4, 2024

Yeah, I have found the some problem. Can anybody help? I had try to fix it, but it didn't work.

from netfix.

IShinji avatar IShinji commented on September 4, 2024

……Author knew the issue. See here, https://hacks.mozilla.org/2015/07/streaming-media-on-demand-with-media-source-extensions/

My demo is a little naive and has a few issues:

It doesn’t show how to properly handle seeking during playback.
It assumes bandwidth is constant (always fetching the next segment at 80% playback of the previous segment), which it isn’t.
It starts off by loading only one segment (it might be better to fetch the first few, then wait to fetch the rest).
It doesn’t switch between segments of varying resolution, instead only fetching segments of one quality.
It doesn’t remove segments (part of the MSE API), although this can be helpful on memory constrained devices. Unfortunately, this requires you to re-fetch content when seeking backwards.

from netfix.

Related Issues (10)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.