javascript - 自 Firefox 49 以来,MJPEG 流在第一帧卡住

标签 javascript css firefox html5-canvas

从 Firefox 49 及更高版本开始,来自 IP 摄像机的 MJPEG 流使用内部服务卡住在第一帧。这不会发生在 Chrome 中。我在 FF 49 更新日志中找不到任何可能导致此错误的更改。请记住,这段代码不是我的,而且非常旧,但它在 Chrome 中仍然可以正常工作。 我认为可能导致错误的代码片段:

CameraplayerUI.js
self.drawStream = function (image) {
            //#region Argument validation and sanitization

            if (typeof image === "undefined" || image === null) { return false; }
            if (typeof image.src === "undefined" || image.src === null) { return false; }
            if (!image.complete) { return false; }

            if (_stream.width !== image.width) { _stream.width = image.width; }

            if (_stream.height !== image.height) { _stream.height = image.height; }

            //#region Argument validation and sanitization

            if(_isLive !== true){
                _isLive = true;
                $(_image).hide();
                $(_stream).show();
            }

            _ctx.drawImage(image, 0, 0, _stream.width, _stream.height);
            self.source = image.src;
            return true;

/** Mjpegstream.js
         * Updates the current stream based on the elapsed time since last update.
         * Warning: Numeric representations for all parameters are used without validation for
         *          performance considerations.
         *
         * @param {Integer} time        - Current time}
         * @param {Integer} elapsedTime - Elapsed time since last update cycle.
         */
        this.update = function (time, elapsedTime) {
            if (!self.isOpen) { return false; }

            //#region Argument validation and sanitization

            time = +time; // Unary plus operation. Numeric representation.
            elapsedTime = +elapsedTime; // Unary plus operation. Numeric representation.

            //#endregion Argument validation and sanitization

            _serviceReauthenticationTimer = _serviceReauthenticationTimer - elapsedTime;
            if (_serviceReauthenticationTimer <= 0) {
                downloadAsync(_userId, _userKey, this.cameraId, update_callback);
            }

            // Firefox MJPEG stream fix.
             if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1) {
                if (this.data !== "undefined" && this.data !== null) {

                    self.data.src = _stream.src;

                }
            }

            return true;
        };

Cameraplayer.js
if (self.isLive) {
                _time = now;
                ui.setTime(_time);

                if (!_mjpegStream.isAuthenticated) {
                    ui.showAuthenticationNotification(false, _mjpegStream.error);
                    self.hasError = true;
                } else if (_mjpegStream.error !== null) {
                    ui.showError(true, _mjpegStream.error);
                    self.hasError = true;
                } else if (_mjpegStream.isOpen) {
                    ui.clearNotifications();
                    if (_mjpegStream.isPlaying) {
                        if (_mjpegStream.update(_time, elapsedTime)) {
                            ui.drawStream(_mjpegStream.data);
                        }
                    } else {
                        _mjpegStream.play();
                    }
                } else if (_mjpegStream.isConnecting) {
                    ui.showLoading(true);
                    return false;
                } else {
                    ui.showLoading(true);
                    _mjpegStream.open(_request);
                    return false;
                }
            } else {
                _time = time;

请记住,这个程序很大,我只是摘取了我认为可能会导致错误的片段。它适用于 49 之前的所有 Firefox 版本,目前适用于 Chrome

最佳答案

你依赖于 chrome bug .

根据 specs :

... when a CanvasImageSource object represents an animated image in an HTMLOrSVGImageElement, the user agent must use the default image of the animation (the one that the format defines is to be used when animation is not supported or is disabled), or, if there is no such image, the first frame of the animation, when rendering the image for CanvasRenderingContext2D APIs.

MJPEG 流是这些动画图像的一部分,因此 UA 必须仅返回第一帧。 Chrome 最近遵循了这部分规范,但用于 GIF 图像。

因此,通过在每次重绘时在请求中添加一个随机参数,强制完全重新加载 MJPEG 流的解决方法仍然存在,但您将失去 MJPEG 格式的所有优势并发出大量繁重的请求。

var url = 'http://webcam.st-malo.com/axis-cgi/mjpg/video.cgi?resolution=352x288';

var img = new Image();
img.onload = drawAndReload;
// check if there are already parameters in the passed url
var paramHead = url.indexOf('?') > 0 ? '&' : '?';
img.src = url;
var ctx = c.getContext('2d');

function drawAndReload(){
  if(c.width !== this.naturalWidth){
    c.width = this.naturalWidth;
    c.height = this.naturalHeight;
    }
  ctx.drawImage(this, 0, 0);
  // reset the image
  this.src = ''; // should not be necessary
  this.src = url + paramHead + Math.random(); // force no-cache
  }
<canvas id="c"></canvas>

一个真正的解决方案是将您的 MJPEG 流转换为视频流服务器端,然后使用 MediaSource用于获取 block 并将其显示在 HTMLVideoElement 中的 API,您将能够不受限制地在 Canvas 上绘制。

关于javascript - 自 Firefox 49 以来,MJPEG 流在第一帧卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41291610/

相关文章:

在 Visual Studio Code 中调试时 Firefox 未打开

javascript - Firefox 下拉列表行为

javascript - Three.js:在移动设备上旋转对象

javascript - 如何将零连接到数字?

html - 如何使文本可环绕以下 float 元素?

css - 使 flex 元素包裹在列方向容器中

javascript - 如何关闭最新版本 Mozilla Firefox 的窗口?

javascript - Highcharts 中选定列的不同边框

javascript - 运行时 Rails : generate . js 文件

html - Google pagespeed insights CSS 警告