mjpg html5,javascript - Stream local mjpg video to html canvas - Stack Overflow

According to specs about the CanvasRenderingContext2D drawImage method,

Specifically, when a CanvasImageSource object represents an animated

image in an HTMLImageElement, 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.

This applies to .gif, SMIL animated .svg and .mjpeg media. So once you fetched the data, only one frame should be drawn onto the canvas.

Note that chrome has a bug and only respect it for .gif images, but they may fix it someday.

One solution as you noticed yourself, is to fetch an other fresh frame, with the clear-cache hack ('your.url/?' + new Date().getTime();) but you will loose any advantages of the mjpeg format (partial frame content) and can't be sure when the refreshing will happen.

So a better solution if applicable, would be to use a video format. Each frame of a video can be drawn to the canvas.

Edit 2018

A third solution came to my little mind two years later:

UAs are not tied to keep in memory the same default image for all 2DContexts in the document.

While for others format we are still kinda stuck, for MJPEG streams, which don't have a well defined default image, we actually fall to the first frame of the animation.

So by drawing the containing our MJPEG stream on two different canvases, at different times, we can theoretically have two different frames of our same MJPEG stream to be drawn on the canvases.

Here is a proof of concept only tested on Firefox 62.

var ctx_stream = stream.getContext('2d');

var ctx_direct = direct.getContext('2d');

img.onload = function() {

stream.width = direct.width = this.naturalWidth;

stream.height = direct.height = this.naturalHeight;

// onload should fire multiple times

// but it seems it's not at every frames

// so we'll disable t and use an interval instead

this.onload = null;

setInterval(draw, 500);

};

function draw() {

// create a *new* 2DContext

var ctx_off = stream.cloneNode().getContext('2d');

ctx_off.drawImage(img, 0,0);

// and draw it back to our visible one

ctx_stream.drawImage(ctx_off.canvas, 0,0);

// draw the img directly on 'direct'

ctx_direct.drawImage(img, 0,0);

}

img.src = "http://webcam.st-malo.com/axis-cgi/mjpg/video.cgi?resolution=704x576&dummy=1491717369754";

canvas,img{

max-height: 75vh;

}

Using a new offcreen canvas every frame:

The original image:

Drawing directly the <img> (if this works your browser doesn't follow the specs):

So while this solution will obviously come with a performance impact (we are creating a whole new canvas element and its 2DContext every frame), it's still probably better than flooding the network. And all this should be Garbage Collected quite easily anyway.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值