{"id":2213,"date":"2022-08-30T15:22:59","date_gmt":"2022-08-30T15:22:59","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2014\/01\/04\/canvas-vs-image-for-faux-video-player-collection-of-common-programming-errors\/"},"modified":"2022-08-30T15:22:59","modified_gmt":"2022-08-30T15:22:59","slug":"canvas-vs-image-for-faux-video-player-collection-of-common-programming-errors","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2022\/08\/30\/canvas-vs-image-for-faux-video-player-collection-of-common-programming-errors\/","title":{"rendered":"Canvas vs Image for faux video player-Collection of common programming errors"},"content":{"rendered":"<p>I have a server that generates pngs very rapidly and I need to make this into a poor-man&#8217;s video feed. Actually creating a video feed is not an option.<\/p>\n<p>What I have working right now is a recursive loop that looks a little like this (in pseudo-code):<\/p>\n<pre><code>function update() {\n    image.src = imagepath + '?' + timestamp; \/\/ ensures the image will update\n    image.onload = function () {update()};\n}\n<\/code><\/pre>\n<p>This works, however after a while, it crashes the browser (Google Chrome, after more than 10 minutes or so). These images are being updated very frequently (several times a second). It seems the images are caching, which causes the browser to run out of memory.<\/p>\n<p><strong>Which of these solutions would solve the problem while maintaining fast refresh:<\/strong><\/p>\n<ul>\n<li>HTML5 canvas with drawImage<\/li>\n<li>HTML5 canvas with <code>CanvasPixelArray<\/code> (raw pixel manipulation)<\/li>\n<\/ul>\n<p>I have access to the raw binary as a Uint8Array, and the image isn&#8217;t too large (less than 50 kb or so, 720 x 480 pixels).<\/p>\n<p><strong>Alternatively, is there anyway to clear old images from the cache or to avoid caching altogether?<\/strong><\/p>\n<p>EDIT:<\/p>\n<p>Note, this is not a tool for regular users. It&#8217;s a tool for diagnosing analog hardware problems for engineers. The reason for the browser is platform independence (should work on Linux, Windows, Mac, iPad, etc without any software changes).<\/p>\n<ol>\n<li>\n<p>The crashing is due to http:\/\/code.google.com\/p\/chromium\/issues\/detail?id=36142. Try creating object URLs (use XHR2 <code>responseType = \"arraybuffer\"<\/code> along with <code>BlobBuilder<\/code>) and revoking (using <code>URL.revokeObjectURL<\/code>) the previous frame after the next frame is loaded.<\/p>\n<p>Edit: You really should be processing these into a live low-fps video stream on the server side, which will end up giving you greatly decreased latency and faster load times.<\/p>\n<\/li>\n<li>\n<p>@Eli Grey seems to have identified the source of your crashing. It looks like they have a fix in the works, so if you don&#8217;t want to modify your approach hopefully that will be resolved soon.<\/p>\n<p>With regard to your other question, you should definitely stick with <code>drawImage()<\/code> if you can. If I understand your intention of using the <code>CanvasPixelArray<\/code>, you are considering iterating over each pixel in the canvas and updating it with your new pixel information? If so, this will be <em>nowhere<\/em> near as efficient as <code>drawImage()<\/code>. Furthermore, this approach is completely unnecessary for you because you (presumably) do not need to reference the data in the previous frame.<\/p>\n<p>Whether fortunately or not, you cannot directly swap out the internal <code>CanvasPixelArray<\/code> object stored within an HTML5 canvas. If you have a properly-formatted array of pixel data, the only way you can update a canvas element is by calling either <code>drawImage()<\/code> or <code>putImageData()<\/code>. Right now, <code>putImageData()<\/code> is much slower than <code>drawImage()<\/code>, as you can see here: http:\/\/jsperf.com\/canvas-drawimage-vs-putimagedata. If you have any sort of transparency in the frames of your video, you will likely want to clear the canvas and then use <code>drawImage()<\/code> (otherwise you could see through to previous frames).<\/p>\n<p>Having said all that, I don&#8217;t know that you really even need to use a canvas for this. Was your motivation for looking into using a canvas so that you could avoid caching (which now doesn&#8217;t seem to be the underlying issue for you)?<\/p>\n<\/li>\n<li>\n<p>If the &#8220;movie&#8221; is data-driven (ie. based on numbers and calculations), you may be able to push MUCH more data to the browser as text and then have javascript render it client-side into a movie. The &#8220;player&#8221; in the client can then request the data in batches as it needs it.<\/p>\n<p>If not, one thing you could do is simply limit the frames-per-second (fps) of the script, possibly a hard-coded value, or a slider \/ setable value. Assuming this doesn&#8217;t limit the utility of the tool, at the very least it would let the browser run longer w\/o crashing.<\/p>\n<p>Lastly, there are lots of things that can be done with headers (eg. in the .htaccess file) to indicate to browsers to cache or not cache content.<\/p>\n<\/li>\n<li>\n<p>iPad, you say ?.. Nevertheless, i would advice using Flash\/video or HTML5\/video.<\/p>\n<p>Because WebKit is very easily crashed with even moderate influx of images, either just big images or just a huge number of small ones..<\/p>\n<p>From the other side, XHR with base64 image data or pixel array MIGHT work. I have had short polling app, which was able to run for 10-12 hours with XHR polling server every 10 seconds.<\/p>\n<p>Also, consider delta compression, &#8211; like, if its histogram with abscissa being time scale &#8211; you can only send a little slice from the rigth, &#8211; of course, for things like heat-maps, you cannot do that.<\/p>\n<blockquote>\n<p>These images are being updated very frequently (several times a second).<\/p>\n<\/blockquote>\n<p>.. if its critical to update at such a high rate &#8211; you MUST use long polling.<\/p>\n<\/li>\n<\/ol>\n<p id=\"rop\"><small>Originally posted 2014-01-04 14:19:48. <\/small><\/p>","protected":false},"excerpt":{"rendered":"<p>I have a server that generates pngs very rapidly and I need to make this into a poor-man&#8217;s video feed. Actually creating a video feed is not an option. What I have working right now is a recursive loop that looks a little like this (in pseudo-code): function update() { image.src = imagepath + &#8216;?&#8217; [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2213","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/2213","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=2213"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/2213\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=2213"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=2213"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=2213"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}