无法通过WebSocket向Firefox传输视频流

11

我编写了一些代码,用于在 websocket 上流式传输视频,使用 sourcebuffer 在 Chrome 和 Edge 中可行。

然而,在 Firefox 中运行时,视频从未播放,只显示旋转的轮动动画。当我检查 <video> 统计信息时,准备状态为 HAVE_METADATA,网络状态为 NETWORK_LOADING

代码如下:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
  </head>
  <body>
    <video controls></video>
    <script>
      var mime = 'video/mp4; codecs="avc1.4D401E,mp4a.40.2"';
      var address = 'ws://localhost:54132'

      /* Media Source */

      var source = new MediaSource();
      var video = document.querySelector('video');
      video.src = URL.createObjectURL(source);
      source.addEventListener('sourceopen', sourceOpen);

      /* Buffer */

      var buffer;
      var socket;
      var queue = [];
      var offset = -1;
      var timescale;

      // When the media source opens:
      function sourceOpen() {
        buffer = source.addSourceBuffer(mime);
        buffer.addEventListener('updateend', processQueue);

        socket = new WebSocket(address);
        socket.binaryType = 'arraybuffer';
        socket.onmessage = onMessage; 
      }

      // When more data is received.
      function onMessage(event) {
        queue.push(event.data);
        processQueue();
      }

      // Process queue if possible.
      function processQueue() {
        if ((queue.length == 0) || (buffer.updating)) {
          return;
        }

        var data = queue.shift();
        if (offset === -1) {
          var parsed = parseMP4(data);
          if (parsed.hasOwnProperty('moov')) {
            timescale = parsed.moov.mvhd.timescale;
          } else if (parsed.hasOwnProperty('moof')) {
            offset = 0 - (parsed.moof.traf[0].tfdt.baseMediaDecodeTime / this.timescale - 0.4);
            buffer.timestampOffset = offset;
          }
        }

        // console.log('appending ' + data.byteLength + ' bytes');
        buffer.appendBuffer(data);
      }

      // Parse out the offset.
      function parseMP4(data) {
        // SNIP for brevity
      }
    </script>
  </body>
</html>

1
你在视频元素或源缓冲区上是否遇到错误事件?当你直接使用视频URL作为“src”(而不是媒体源)时会发生什么? - sbr
没有错误事件。数据是由服务器即时生成的(例如来自IP流),因此我无法将视频元素指向任何URL。 - Hans
1
我没有看到你调用.endOfStream().play()的部分,所以它不会开始播放。 - dandavis
@dandavis 这是一个连续的视频流,因此没有结束流的时候。我知道没有播放调用。我正在使用视频元素控件手动触发播放。 - Hans
@guest271314,我不认为我理解那将如何帮助我创建一个plunkr?那个页面列出了媒体文件,我知道可以在Firefox的<video>元素中查看。我正在尝试从websocket读取视频内容。 - Hans
显示剩余6条评论
2个回答

3

无法重现在Firefox 47上不播放<video>元素。

合并方法在模拟Websocket消息事件,创建模拟的WebSocket事件; bufferAll.html演示在让我们制作一个Netflix 网络流媒体简介,用于MediaSource使用模式。

包含<progress>progress事件,以通知用户媒体加载状态。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
  </head>
  <body>
    <progress min="0" value="0"></progress><br><label></label><br>
    <video controls></video>
    <script>
        // http://nickdesaulniers.github.io/netfix/demo/bufferAll.html
        // http://jsfiddle.net/adamboduch/JVfkt/
        // The global web socket.    
        var sock, sourceBuffer;
        sock = new WebSocket( "ws://mock" );
        sock.onerror = function(e) {
          console.log("sock error", e)
        }
        // This is unchanging production code that doesn"t know
        // we"re mocking the web socket.
        sock.onmessage = function( e ) {
          console.log("socket message", e.data);
          sourceBuffer.appendBuffer(e.data);
        }; 
      var video = document.querySelector("video");
      var progress = document.querySelector("progress");
      var label = document.querySelector("label");
      var assetURL = "http://nickdesaulniers.github.io/netfix/"
                     + "demo/frag_bunny.mp4";
      // Need to be specific for Blink regarding codecs
      // ./mp4info frag_bunny.mp4 | grep Codec
      var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';

      if ("MediaSource" in window 
          && MediaSource.isTypeSupported(mimeCodec)) {
        var mediaSource = new MediaSource;
        //console.log(mediaSource.readyState); // closed
        video.src = URL.createObjectURL(mediaSource);
        mediaSource.addEventListener("sourceopen", sourceOpen);
      } else {
        console.error("Unsupported MIME type or codec: ", mimeCodec);
      }
      video.addEventListener("canplay", function() {
        alert("video canplay")
      })
      function sourceOpen (_) {
        //console.log(this.readyState); // open
        var mediaSource = this;
        sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
        fetchAB(assetURL, function (buf) {
          sourceBuffer.addEventListener("updateend", function (event) {
          console.log("sourceBuffer updateend event;"
                      + "mediaSource.readyState:"
                     , mediaSource.readyState);
            // mediaSource.endOfStream();
            // video.play();
            // console.log(mediaSource.readyState); // ended
          });
          
        });
      };
      // mock `WebSocket` message
      function fetchAB (url, cb) {
        var xhr = new XMLHttpRequest;
        xhr.open("get", url);
        var file = url.split("/").pop();
        xhr.responseType = "arraybuffer";
        xhr.onload = function () {
          // mock `WebSocket` message
          sock.dispatchEvent( new MessageEvent( "message", {
            data: xhr.response
        }));
        console.log("video sent to sock", sock);
        cb();
        };
        xhr.onprogress = function(e) {
           progress.max = e.total;
           progress.value = e.loaded;
           label.innerHTML = "loading " + file + " ...<br>"
                             + e.loaded + " of " 
                             + e.total + " bytes loaded";
        }
        xhr.send();
      };  
    </script>
  </body>
  </html>

plnkr http://plnkr.co/edit/RCIqDXTB2BL3lec9bhfz


1
在Firefox 47上一分钟后,我会看到一个旋转的圆圈,之后什么也不会发生。 - ManoDestra
在IE或Chrome上对我一点用也没有。奇怪。 - ManoDestra
1
@ManoDestra:“在使用Firefox 47一分钟后,我看到一个旋转的圆圈,之后什么都没发生。”你按了视频控件上的播放键吗?我无法在我的Firefox 47上重现这种效果。已调用alert(); 视频完整播放1分钟长度。是否在console中记录任何错误?不确定Chrome是否支持问题中特定的编解码器var mime ='video/mp4; codecs="avc1.4D401E,mp4a.40.2"';;你是否在Chrome的plnkr中检查了console?对于IE不确定。请注意,实际问题是针对Firefox的“无法通过websocket流式传输视频”。 - guest271314
1
在Firefox上,按下播放键一分钟后它可以工作,但之后就会出现旋转图标。第一分钟之后什么也没有发生。在IE和Chrome上,按下播放键根本无法工作。因此,在这里可能是有道理的。 - ManoDestra
1
@ManoDestra 是的,视频总时长为一分钟 1:00。另请参阅 https://hacks.mozilla.org/2015/07/streaming-media-on-demand-with-media-source-extensions/,https://w3c.github.io/media-source/,https://gist.github.com/granoeste/8727308。 - guest271314

0
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
  </head>
  <body>
    <progress min="0" value="0"></progress><br><label></label><br>
    <video controls></video>
    <script>
        // http://nickdesaulniers.github.io/netfix/demo/bufferAll.html
        // http://jsfiddle.net/adamboduch/JVfkt/
        // The global web socket.    
        var sock, sourceBuffer;
        sock = new WebSocket( "ws://mock" );
        sock.onerror = function(e) {
          console.log("sock error", e)
        }
        // This is unchanging production code that doesn"t know
        // we"re mocking the web socket.
        sock.onmessage = function( e ) {
          console.log("socket message", e.data);
          sourceBuffer.appendBuffer(e.data);
        }; 
      var video = document.querySelector("video");
      var progress = document.querySelector("progress");
      var label = document.querySelector("label");
      var assetURL = "http://nickdesaulniers.github.io/netfix/"
                     + "demo/frag_bunny.mp4";
      // Need to be specific for Blink regarding codecs
      // ./mp4info frag_bunny.mp4 | grep Codec
      var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';

      if ("MediaSource" in window 
          && MediaSource.isTypeSupported(mimeCodec)) {
        var mediaSource = new MediaSource;
        //console.log(mediaSource.readyState); // closed
        video.src = URL.createObjectURL(mediaSource);
        mediaSource.addEventListener("sourceopen", sourceOpen);
      } else {
        console.error("Unsupported MIME type or codec: ", mimeCodec);
      }
      video.addEventListener("canplay", function() {
        alert("video canplay")
      })
      function sourceOpen (_) {
        //console.log(this.readyState); // open
        var mediaSource = this;
        sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
        fetchAB(assetURL, function (buf) {
          sourceBuffer.addEventListener("updateend", function (event) {
          console.log("sourceBuffer updateend event;"
                      + "mediaSource.readyState:"
                     , mediaSource.readyState);
            // mediaSource.endOfStream();
            // video.play();
            // console.log(mediaSource.readyState); // ended
          });

        });
      };
      // mock `WebSocket` message
      function fetchAB (url, cb) {
        var xhr = new XMLHttpRequest;
        xhr.open("get", url);
        var file = url.split("/").pop();
        xhr.responseType = "arraybuffer";
        xhr.onload = function () {
          // mock `WebSocket` message
          sock.dispatchEvent( new MessageEvent( "message", {
            data: xhr.response
        }));
        console.log("video sent to sock", sock);
        cb();
        };
        xhr.onprogress = function(e) {
           progress.max = e.total;
           progress.value = e.loaded;
           label.innerHTML = "loading " + file + " ...<br>"
                             + e.loaded + " of " 
                             + e.total + " bytes loaded";
        }
        xhr.send();
      };  
    </script>
  </body>
  </html>

3
你是不是直接从之前的答案中复制了代码? - Hans

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接