3

webm ビデオのセグメントをロードするための VideoBuffer クラスを作成しました。各セグメントは、ビデオ要素で blob として開いた場合、または別のブラウザー タブで直接開いた場合に個別に機能しますが、ソース バッファーに追加する場合は機能しないようです。

エラーや例外がスローされることはなく、MediaSource の準備完了状態が閉じられ、SourceBufferList が空になります。主な違いは、FileReader からの結果を追加するのではなく、各 xhr 応答をバッファーに追加していることです

なぜこれが機能しないのか、またはどのようにデバッグすればよいのかについてのアイデアはありますか?

var EventEmitter = require("events").EventEmitter;

function VideoBuffer(options) {
  this.video = options.video;
  this.source = new MediaSource();
  this.video.src = URL.createObjectURL(this.source);
  this.url = options.url;
  this.segment = 0;
  this.time = 0;
  this.duration = options.duration;
  this.segments = Math.ceil(this.duration/10);
  this.preset = options.preset;
  this.source.addEventListener("sourceopen", this.onSourceOpen.bind(this));
  this.source.addEventListener("sourceended", this.onSourceEnded.bind(this));
  this.video.addEventListener("progress", this.onVideoProgress.bind(this));

  this.on("error", function(err){
    try {
      throw err;
    } catch (e) {
      console.error(e.stack);
    }
  });
}

VideoBuffer.prototype = Object.create(EventEmitter.prototype);

VideoBuffer.prototype.onSourceOpen = function (e) {
  this.debug("Source opened:", this.source);
  var buffer = this.source.addSourceBuffer('video/webm; codecs="vorbis,vp8"');
  buffer.addEventListener("updatestart", this.onBufferUpdateStart.bind(this));
  buffer.addEventListener("update", this.onBufferUpdate.bind(this));
  buffer.addEventListener("updateend", this.onBufferUpdateEnd.bind(this));
  this.debug("Added source buffer:", buffer);
  this.emit("source:open", e);
};

VideoBuffer.prototype.onSourceEnded = function (e) {
  this.debug("Source ended:", this.mediaSource);
  this.emit("source:ended", e);
};

VideoBuffer.prototype.onBufferUpdateStart = function (e) {
  this.emit("buffer:updatestart", e);
};

VideoBuffer.prototype.onBufferUpdate = function (e) {
  this.emit("buffer:update", e);
};

VideoBuffer.prototype.onBufferUpdateEnd = function (e) {
  this.emit("buffer:updateend", e);
  if (this.segment === 0) {
    this.debug("Got first segment, starting playback");
    this.debug(this);
    this.video.play();
  }
};

VideoBuffer.prototype.onVideoProgress = function (e) {
  this.debug("Video progress:", e);
  this.segment++;
  this.loadNextSegment();
}

VideoBuffer.prototype.loadNextSegment = function () {
  var url = this.url
    .replace("%segment", this.segment)
    .replace("%time", this.time)
    .replace("%preset", this.preset);

  this.debug("Loading segment:", this.segment, url);

  this.request = new XMLHttpRequest();
  this.request.responseType = "arraybuffer";
  this.request.open("GET", url, true);
  this.request.onload = this.onRequestLoad.bind(this);
  this.request.send(null);
}

VideoBuffer.prototype.onRequestLoad = function(e) {
  if (this.request.status != 200) {
    this.emit("error", new Error("Unexpected status code"));
    return false;
  }
  var ms = this.source;
  var sb = ms.sourceBuffers.length ? ms.sourceBuffers[0] : false;
  var buffer = new Uint8Array(this.request.response);

  this.debug("Got segment:", buffer.length, "bytes");

  if (buffer.length && sb) {
    try {
      this.debug("Appending segment to source buffer");
      sb.appendBuffer(buffer);
    } catch (e) {
      this.emit("error", new Error(e));
      return false;
    }
    if (this.segment === this.segments) {
      ms.endOfStream();
      return;
    }
  } else {
    this.emit("error", new Error("Empty response or missing source buffer"));
  }
}

VideoBuffer.prototype.play = function (time) {
  this.time = 0;
  this.segment = Math.floor(this.time/10);
  this.loadNextSegment();
};

VideoBuffer.prototype.debug = (function () {
  return console.log.bind(console);
}());

module.exports = VideoBuffer;

注: 上記のコードは browserify で読み込まれるため、CommonJS モジュールです。

実験を好む、または実験したい人のための要点。

4

1 に答える 1