从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上
发布于 2016-12-25 13:30:23
您依赖于chrome bug。
根据specs的说法:
...当CanvasImageSource对象表示HTMLOrSVGImageElement中的动画图像时,在为CanvasRenderingContext2D API呈现图像时,用户代理必须使用动画的默认图像(格式定义的图像将在动画不受支持或禁用时使用),或者,如果没有此类图像,则使用动画的第一帧。
MJPEG流是这些动画图像的一部分,因此UAs必须仅返回第一帧。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 API获取块并将其显示在HTMLVideoElement中,这样您就可以不受限制地在画布上绘制。
https://stackoverflow.com/questions/41291610
复制相似问题