APNG num_plays works in Firefox but not in Chrome - javascript

An APNG file specification for reference: https://wiki.mozilla.org/APNG_Specification
num_plays defines the number of times than an animated PNG should loop. 0 is a special value that means the animation will loop indefinitely.
I found some APNGs online that I want to display on a webpage. They all have num_plays set to 0. (In this particular example, an animated image of Ivysaur from a Pokémon game: https://cdn.bulbagarden.net/upload/c/c8/Spr_3e_002.png)
I had no problem displaying this original APNG in Chrome, where the animation looped endlessly.
But it's important to me that the animation play only once, and after that show the final frame. I tried some HTML- and JS-based solutions to this, such as waiting a couple of seconds and replacing the APNG img element with a canvas that I drew it to, but I wasn't able to get the results I wanted. The image would reset to the first frame at the end of the animation instead of the last frame, or sometimes the pixel offset of the image content inexplicably differed.
That's when I found out I could change the num_plays value in the acTL section of an APNG to change the number of times it looped to 1 - and so I did.
It works perfectly in Firefox! Here's an example that shows exactly the behavior that I want:
But in Chrome, the APNG no longer animates at all after changing num_plays.
What might be causing it to not animate in Chrome? Is a nonzero num_plays simply not supported? What alternatives would I have to get the same behavior as seen in Firefox?

The problem was that I modified an APNG I downloaded from the internet which originally had a num_plays of 0 using a hex editor. I neglected to update the acTL section's CRC when I did so; Firefox played the malformed APNG as I expected it to, but Chrome aborted because my APNG, in not having a correct CRC, failed to meet the spec.

Related

APNG gets out of sync after second page refresh

I have an app with an animated UI realised via APNG images.
Each block has 2 APNG images and one PNG one:
Appearing (APNG)
PingPong (APNG)
Static (PNG)
I need to play the second animation right after the first one is finished and only make visible the PNG image after a touch event. I've done it via setTimeout but, unfortunately, after second page refresh a browser completely ignores some animations, some of them start jittering, some disable in an inappropriate moment.
How can I fix the problem?
And can I catch the moment when APNG animation has finished? Do APNG images emit any events?
To check the problem, open the app on mobile device and scan the code.
Browsers don't have any built-in support for treating APNGs as anything other than an image: there is no way to determine when an APNG has started or stopped playing. You could probably fix the issue by just converting the APNGs to an actual video file format, and embedding the images with <video> instead, since that has an API for controlling playback. Alas, it doesn't seem that any browsers support treating APNGs as video so you'll need to convert it to another video format, such as WebM.
If you are really committed to not converting your APNGs to a video file format, you could work around the limitation in browsers by using a library such as pngjs to decode the APNG, extracting the fdAT chunks, and then manually animating through those extracted frames (each frame in an APNG is itself a (non-animated) PNG).

Video, memory management problems in Internet Explorer and Edge from many videos on page causing them to display dark/black and/or not play

We have a page that contains 77 or so video thumbnails. When a video thumbnail is hovered over, video starts playing within the thumbnail space.
A problem occurs after many (8 to 60 depending on the system/browser) of them get hovered over. The video starts playing incorrectly, or not playing. Basically the flat/redundant areas turn all dark. In Edge, this corrects itself after a second or two, but for our client this is very undesirable behavior.
We made an improvement by pausing each video on mouse out by calling pause(), removing the src attribute, and then calling load() on the element with an empty src attribute, like so:
function pauseVideo(e) {
$('video', this).get(0).pause();
$('video', this).get(0).removeAttribute('src');
$('video', this).get(0).load();
}
This clears up some memory, but the issue still occurs, though more of the videos can play before the problem becomes apparent.
I does appear to have something to do with memory, and exposes what appears to us to be a memory leak within the Microsoft browsers. Each video increases memory usage, and the memory never gets cleared, as it seems to in Chrome and Firefox. The problem usually occurs when memory usage approaches somewhere between 600mb to 1gb (depending on system) in the task manager. (Chrome always sits around ~500-550 megabytes.
Firefox sits around ~700-800 megabytes.)
We noticed some variance on when the behavior starts to occur that depends on video cards, but the issue always become present at some point.
All of these videos are showed in multiple places on the page. So one thing I was wondering was if it is possible to share video memory between elements.
There are a couple other issues that may be related. In IE the videos go completely black, and their dimensions change onscreen which can change the page layout.
Here is a related issue, but it is not a duplicate, as it doesn't not provide a question or solution about having to facilitate 80 or so videos on one page: How to properly unload/destroy a VIDEO element
We're testing on IE version 11.228.17134.0 and Edge version 42.17134.1.0, both currently the latest.
The desired functionality originally was for the videos to pause on the frame when the user moused off the video, but right now appears we wont be able to do that if we have to unload the video.
I will be adding more information about this issue throughout the day as it becomes available.
Our team has a script that detects if DOM elements are within the viewable area on the page, e.i. not scrolled above the top or below the bottom. As the user scrolls, the script adds/removes a class, and dispatches custom events for each element that has the behavior added. I was able to leverage this system to pause, remove, and dispose (garbage collect) video elements that are not in view, and then, repopulate them as they come back into view, with the original properties stored in an array of objects associated with each video/thumbnail.
This disposes the video. The function must be called with .call(), like: disposeVideo.call(videoElement);
var disposeVideo = function () {
this.pause();
delete(this);
$(this).remove();
}
It's odd that though delete(this) is a hack, and shouldn't work in any browser, it appears to work in all browsers, according to comments I've read around this issue, and my findings in IE/Edge.
On IE (not Edge) this has a side effect of slowing down page scrolling. This is caused by the our in-view checking applied to 80 items on the page, or if it is to do with re-downloading posters (thumbnail images) and video, because it does appear to not be effectively caching these assets to be immediately (re)available to the renderer.
Another side effect (also in IE) related to the above, is that as you scroll the videos appear blank until assets are re-downloaded. We're opting to use images layered behind the videos in favor of using the poster attribute for the videos elements that get removed. This way there will never be blank video thumbnails onscreen.
Update: It is possible that having two or more video elements onscreen can cause the problem. We resorted to only showing one (which worked 100%) but did not try to determine a likely maximum number of video elements.

Flickering Images despite preload

I am trying to simulate a video by switching image-frames via javascript. This works perfectly in Chrome while in Firefox (and IE/Edge) the background is shown while updating the frame. This occurs only the first time the image-source is rendered. It seems like the images are not in cache, however the network console shows that they get preloaded correctly.
The way the images are being replaced doesn't seem to matter. I tried changing the source from images/divs as well as controlling them via display, visibility, opacity and even by rearranging the z-index. The way I apply the css to it via jQuery (hide/show, animate, css) also seems to be indifferent. It doesn't even matter if other visible frames are "below" the current frame, it always flashes the background.
I managed to recreate the error:
https://jsfiddle.net/kL54ckLp/

cloneNode() makes html video lag and sometimes not render at all

When I click a video, it should animate from its original position to some target position. For reasons, I can't animate the original video element, so I animate a clone which is created by cloneNode(). I just cycle through about 5 videos (which are less than 20 seconds long) and 5 images when clicking. My animation method was causing only the videos to lag and sometimes not render at all while images seemed to be unaffected. I commented out all of my animation code except for a single line:
var clone = videoElement.cloneNode( false );
Without the animation code, the images/videos just teleport to the target position instantly (which is expected). But leaving that single line uncommented, when I click relatively quickly, causes the videos to lag a little (if I'm lucky) and sometimes not render at all in Chrome. In Edge, the videos take a few seconds to render. Removing that line, the videos load/render just fine no matter how fast I click.
Why does this happen? Is cloneNode really just that slow?
Are there any practical solutions to this problem?
It seemed like the problem was with cloneNode(), but it turns out it was because I was using mp4 files as the source for my videos. mp4 is deprecated in Chrome. As soon as I converted to webm video files, the lag/rendering problem completely disappeared.

Force image to reload in Javascript on Chrome?

I have two totally separate images called lock-icon.png and lock-unlock-icon.png. On a certain event, I change an image's source in Javascript with
document.getElementById("element").src = "/images/lock-unlock-icon.png";
This always works immediately on Firefox, but because I'm displaying a live HD video stream on the page that requires WebGL hardware acceleration, I need to use Chrome.
It sometimes works on Chrome, but pretty much never immediately; it seems like a random delay of at least a few seconds, at most never. If I examine the current "image location" of the icon after it should've changed, the url is the new, correct URL (which is obviously expected, because it's just querying the src property of the element).
What else should I be doing to force this image to reload in Chrome?
Load both images in separate divs, then just set display:inline on the currently viewable one, and display:none on the other. Then you can just toggle the two images by changing the CSS display property.

Categories