8

The new WebKit feature for loading large images asynchronously introduced in Safari Tech Preview 26 causes mjpg-streamer webcam based streams to flicker, the boolean property that defaults to true, largeImageAsyncDecodingEnabled, causes this issue. Link to the property definition

I am trying to find a way to set this property to false on the html page with CSS or JS. Is this even possible? Or is there another way to do it?

This is for OctoPrint running OctoPi for a 3D printer server. I found through trial and error, any image over 453x453 px is loaded asynchronously and causes the flicker to happen; it's akin to an annoying strobe light effect. I am using a resolution of 1280x720 for the webcam, and there is no issue before tech preview 26.

Thank you for the help!

Community
  • 1
  • 1
klcjr89
  • 5,862
  • 10
  • 58
  • 91

3 Answers3

2

The issue has now been fixed in Safari Tech Preview 37. https://trac.webkit.org/changeset/219876/webkit/

klcjr89
  • 5,862
  • 10
  • 58
  • 91
1

You can't override the macro. But you may force the rest of the page to load after the image loaded.

By using CSS/JS? Why? Use plain HTML

There is a link rel preload markup exists. Read more here on W3C

The important parts are

The preload keyword on link elements provides a declarative fetch primitive that addresses the above use case of initiating an early fetch and separating fetching from resource execution. As such, preload keyword serves as a low-level primitive that enables applications to build custom resource loading and execution behaviors without hiding resources from the user agent and incurring delayed resource fetching penalties.

How to achieve that

<!-- preload stylesheet resource via declarative markup -->
<link rel="preload" href="url" as="image">

<!-- or, preload stylesheet resource via JavaScript -->
<script>
  var res = document.createElement("link");
  res.rel = "preload";
  res.as = "image";
  res.href = "url";
  document.head.appendChild(res);
</script>

If the load was successful, queue a task to fire a simple event named load at the link element. Otherwise, queue a task to fire a simple event named error at the link element.

if a resource is fetched via a preload link and the response contains a no-cache directive, the fetched response is retained by the user agent and is made immediately available when fetched with a matching same navigation request at a later time

Update

Based on comments discussion we hade,

You have 2 options. 1. Try to change the img tag to video since the issue only affect img tag.

Use the following code for that

$(document).ready(function(){
  var newTag=$('img')[0].cloneNode(true);
  newTag = $(newTag).wrap("<video></video>")[0].parentNode;
  newTag = $(newTag).wrap("<div></div>")[0];
  newTag = newTag.parentNode.innerHTML;
  newTag = newTag.replace("img","source");
  $('img').replaceWith(newTag);
});
  1. Force the user to choose another browser. That is if you detected it is Safari tech preview 26 by using window.userAgent, then navigate them to another page saying that this version of browser is not supported because of compatibility issues. Please downgrade/ choose another browser. - note that this may be temporary. Since it is a known issue(the flickering), they will provide a fix in the future.

Special thanks to To markdown for converting HTML to Markdown within fraction of seconds (I don't have any affiliation)

Sagar V
  • 12,158
  • 7
  • 41
  • 68
  • May be I am wrong, but your answer seems to adress static image loading instead of a stream from a camera – vals Jun 11 '17 at 20:54
  • Your answer doesn't work after trying it. `` – klcjr89 Jun 12 '17 at 00:21
  • a live stream can't be pre-loaded. Also you can't turn off Webkit macro in client side by using JS / CSS. @aviatorken89 – Sagar V Jun 16 '17 at 10:04
  • I suggest an answer that can fix the issue then, regardless if it can be done with JS or CSS. Bounty is still open.. – klcjr89 Jun 16 '17 at 10:08
  • @aviatorken89 Webkit is maintained by apple and another main contributor is Google. Both of them gave high priority to security and hence the remote code execution can't be done. If you make a screencast video of the working and upload it in youtube, then I can try to help you. – Sagar V Jun 16 '17 at 10:13
  • @SagarV I will try to do a screen recording soon, hopefully today. I also emailed a head engineer of WebKit at Apple about the issue and he hasn't replied, which was a week ago so I doubt they care. – klcjr89 Jun 16 '17 at 10:15
  • I think they won't it. Because everyone develop for User not for developers. They introduced this as a new feature for improved UX. So, I think they won't care at all. If you share the youtube link, then I can make some hack for it using JS – Sagar V Jun 16 '17 at 10:17
  • Here's a quick YouTube video I just made. Taken with Safari tech preview 33 (latest). https://youtu.be/5ABeC_SaWoE – klcjr89 Jun 16 '17 at 10:20
  • From a UX and user standpoint, Apple needs to address this since alot of manufacturers of all kinds of webcams use similar mjpg streaming, so alot of people will experience this issue once the new WebKit is shipped publically later this fall. – klcjr89 Jun 16 '17 at 10:22
  • I made a PR but I am not sure whether they will merge it or not. You can track it here https://github.com/WebKit/webkit/pull/18 – Sagar V Jun 16 '17 at 12:22
  • If you can, try to give me some more details – Sagar V Jun 16 '17 at 12:23
  • You weren't able to come up with a hack? – klcjr89 Jun 16 '17 at 21:06
  • Your video is not enough. I want the console and the browser window. and at least 20 secs. Start recording before you enter the url – Sagar V Jun 17 '17 at 00:52
  • This is the best I'm probably going to be able to do: https://youtu.be/MEOLF4qKbXs If you need to see how mjpg-streamer works here is the github link: https://github.com/jacksonliam/mjpg-streamer. OctoPrint simply embeds it as an `` tag so there is no issues with OctoPrint but if you want to look here is the github for OctoPrint: https://github.com/foosel/OctoPrint/tree/devel – klcjr89 Jun 17 '17 at 01:14
  • @aviatorken89 I got a method. But I need a little bit info – Sagar V Jun 17 '17 at 17:11
  • @SagarV what do you need? – klcjr89 Jun 17 '17 at 22:08
  • @aviatorken89 right click on the IMG tag and click inspect. Give me an expanded view if the IMG and it's siblings – Sagar V Jun 18 '17 at 01:00
  • @aviatorken89 I will give you a script. Just try it on the page. Inside jquery document ready – Sagar V Jun 18 '17 at 09:57
  • Changing the tag from ` – klcjr89 Jun 18 '17 at 11:27
  • Try to change it to source tag under parent video. – Sagar V Jun 18 '17 at 11:43
  • I do not follow sorry. – klcjr89 Jun 18 '17 at 11:45
  • where are the remaining attributes? – Sagar V Jun 18 '17 at 11:48
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/146995/discussion-between-aviatorken89-and-sagar-v). – klcjr89 Jun 18 '17 at 11:48
  • @SagarV I think the only solution is to resize the 1280x720 image output to below that threshold where WebKit loads asynchronously. There will be a performance cost of doing this due to the frame rate. I think the Raspi3 should be able to do it. By resizing the image the quality should still be the same. – klcjr89 Jun 18 '17 at 23:52
  • If you change it in webcam, then it will affect on all devices. And need more resources that is time and cost. I personally suggest you don't go for that. – Sagar V Jun 19 '17 at 02:32
  • Webcam is connected to Raspi so im not sure what you mean. The Raspi is the server for OctoPrint. – klcjr89 Jun 19 '17 at 03:19
  • If you change casting resolution at raspi, then it will cast the stream in the same resolution even if you tried from another os – Sagar V Jun 19 '17 at 06:28
  • Is it is for your personnel use or are you developing for someone else? – Sagar V Jun 19 '17 at 06:29
  • It's for my personal use. And I wouldnt change the webcam resolution as that would degrade the quality, I would find a way to resize the jpg output to a smaller size while keeping the aspect ratio. – klcjr89 Jun 19 '17 at 07:13
  • then try to send the required resolution via url and resize based on it at raspi. the url should look like `webcam/?acton=stream&wh=434_434` – Sagar V Jun 19 '17 at 07:17
  • don't pre-define thins at server. Server should be configured in such a manner to handle different values. I am saying because if you configure it and then the issue solved at future, you have to play with raspi again. But if you pass it with url, then just remove the param and the job is completed – Sagar V Jun 19 '17 at 07:19
  • That doesn't work with mjpg streamer, at least from what I was able to research and trying. – klcjr89 Jun 19 '17 at 07:19
  • Oh I see. In this case, all I can do is to keep an eye on the PR I have made. I tried my best but sorry coz all of my attempts can't solve your issue. All the best for that try of resizing in raspi. – Sagar V Jun 19 '17 at 07:22
-1

I can't see any client side hack that won't turn into a full blown construction. You might be able to hack around it, but reporting it to WebKit seems to be the best way forward.

WebKit-bug 170640 is what stopped largeImageAsyncDecodingEnabled from being enabled. It was also causing a flickering. Once that was fixed, they enabled it by default. This however suggest that there is still an issue.


HTTP headers retrieved from GitHub

This might be helpful if anyone decides to submit a bug report to WebKit.

The standard header is the following

mjpg-streamer/mjpg-streamer-experimental/plugins/output_http/httpd.h

#define STD_HEADER "Connection: close\r\n" \
"Server: MJPG-Streamer/0.2\r\n" \
"Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n" \
"Pragma: no-cache\r\n" \
"Expires: Mon, 3 Jan 2000 12:34:56 GMT\r\n"

Then for the actual stream of images:

mjpg-streamer-experimental/plugins/output_http/httpd.c#L466

sprintf(buffer, "HTTP/1.0 200 OK\r\n" \
        "Access-Control-Allow-Origin: *\r\n" \
        STD_HEADER \
        "Content-Type: multipart/x-mixed-replace;boundary=" BOUNDARY "\r\n" \
        "\r\n" \
        "--" BOUNDARY "\r\n");

On a small note, there already seems to be a settings/toggle in WebKit to enable and/or disable the largeImageAsyncDecodingEnabled, check it out here. I doubt this is accessible through Safari's UI tho, and doesn't solve the issue without user interaction.

Penquin
  • 149
  • 6