raphaelameaume / fragment

[alpha] A web development environment for creative coding
https://fragment.tools
MIT License
835 stars 19 forks source link

Faster GIF encoding #14

Closed mattdesl closed 1 year ago

mattdesl commented 2 years ago

I notice the GIF encoder is pretty slow and hangs, and also seems to be a two-pass approach. You might like to look into gifenc which should be faster. Just to note, it uses a different quantization algorithm, so it may produce different results.

You can see an example in action below, rendering 150 frames at 1024x768px renders in ~1.5 seconds, compared to your tool which is something like 30+ seconds. :smile:

https://looom-tools.netlify.app/ (click the circle/record button)

It requires a little more setup but can give you some additional flexibility in terms of quantization, worker structure, and dithering.

Two example implementations:

There is also room for a two-pass approach with gifenc, such as generating a single palette from all frames in the first pass, and in the second pass doing the encoding with that fixed palette. This can produce better consistency across frames but is slower (although, to be honest, probably still faster than your current encoder).

Also pinging @jesi-rgb who is doing similar work with p5js, it would be nice to consolidate some of these ideas around fast GIF encoding for creative coding tools. See here and here.

jesi-rgb commented 2 years ago

Thanks so much for pinging, @mattdesl! It really is an honor.

The state of the PR for adding native gif encoding is very much not finished, but enough so to comply with the GSoC standards.

State of the art

There are still a ton of features I'd love to add such as dithering or better UX experience in general. Right now, I'd say that creative experts would use it for quick draft renders but will probably look otherwise (FFMPEG) for high quality, publishable work. I'll try to improve it as I learn, since I'm very much a newbie at this point :P

Implementation

As for the 2-pass approach, I indeed implemented that on what will become the new saveGif() function in p5.js, which is currently not public for everyone to use, but will be. And I take the approach that was explained in the blog, as you referenced!

Benchmarking

The details are:

Results

These results are not to be taken too seriously at all as I just run the algorithm and measured the time with my phone's clock app. But the fact that Firefox < Safari < Chrome is always consistent.

Conclusion

If I can help or can do anything at all to help on the release of the tool, I will be more than happy to contribute. Just bear in mind that I'm still figuring my way around all this technologies :)

The deadline for the GSoC is Sept 12th. By that time, the PR will have been merged and this feature will be available in the next release of p5.js, about which I have no idea of the scheduling.

That's it!

mySketch (5)

raphaelameaume commented 2 years ago

Indeed, the current implementation of GIF encoding is quite slow comparing to other encoders at your disposal in Fragment. To be honest, I added it using gif.js but I haven't use it much because of its slowness and my (total) absence of knowledge regarding the topic. This article by @jesi-rgb is a pure gem! And this transparency optimization trick is quite mind-blowing.

I missed on gifenc, which looks pretty cool. I think one of the first things we could do would be to switch from gif.js to gifenc in its current state.

Regarding the 2 passes, I think having the implementation possible would be a nice addition as result might really differ depending on what you'd be working on.

@jesi-rgb considering you implemented that on saveGif(), do you think this should live as a core function of the gif encoder or at a higher-level ?

@mattdesl the faster the better so using workers would be great. Curious about the numbers of workers that should be used in this case ? You're comparing without and with 4 workers in the gifenc README file but you seem to be using only 2 in the loom-tools implementation. Isn't it more workers, the faster the encoding happens ?

I think if we end up having two implementations, we could add a