-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial implementation for FFmpeg support #1245
Conversation
Out traveling at the moment, but some quick answers:
On the top of my head, I just think that this is legacy. Would be very nice to hide it before 2.0.
No. In fact, it would be better if we always called them asynchronously.
We should absolutely move away from blocking IO. I'm not sure if moving to JS-land is the best approach though, it's possible to do it from C++ also. Might be easier in JS though so that might have merits.
Yes!
I don't know about the existing images, but might be a good idea to create
Sounds good 👍 we could also call ffmpeg directly from C++, might be faster. If you are interested in non-blocking work in C++, this is a very good helper class to use: https://github.com/nodejs/nan/blob/master/doc/asyncworker.md |
Btw. how large is the ffmpeg binary? An idea is to just ship that for Windows, macOS and Linux bundled, and otherwise use the system installed. That way we could probably drop all the other libraries for image decoding? 🤔 |
Fixing (1) I think requires moving the entirety of the (2) is #1007. (3) All of the image source setter code needs to be heavily cleaned up:
I was wondering about this too, or at least using avformat.h's API instead of spawning a process. I don't know how big it is, what dependencies it has or how its performance is (e.g. vs. libjpeg-turbo, which is a very heavily optimized lib). |
Thanks for the feedback. Seems that the following things remain to be done:
I'm working on it.
The FFmpeg itself is not that heavy. The main concern are probably performances. FFmpeg takes ~4ms on average to decode/encode 1080p image, but takes ~30ms to spawn FFmpeg process. Libpng and turbojpeg takes approximately the same time to decode an image, so FFmpeg is not slower in that sense.
This is how that idea seems to me:
Sounds interesting. That would definitely be faster than spawning a new process each time. So, what is the final consensus?
|
Sounds like this has brought some attention to things that needed improvement, which is great! I'm still wondering if this is trying to solve something that prebuilds already solves. Using FFmpeg as a fallback is a cool idea but we should also consider that it's more code paths to maintain. I would vote for linking against I don't think distributing FFmpeg makes a ton of sense since we could just distribute jpeg-turbo etc, which are faster and smaller. |
I thought that the problem was that jpeg-turbo doesn't support all of the different obscure jpeg-formats that ffmpeg supports? 🤔
Yeah, definitely a negative factor. That's why I started thinking about only using ffmpeg, if that supports all current, and even more, formats that could be cool. That would probably not work great with |
#1160 (edge-case JPEG) should work with libjpeg-turbo 9a. I haven't had a chance to dig into why that fails. #1235 (ditto) I also haven't had a chance to look at. #73 and #122 (edge-case PNGs) should be fixed if we move from canavs's toy API to libpng's API. The others (aside from webp and bmp format) are now closed (#117, #254, #297, #425) or not fixed by ffmpeg (or at least by this PR, #116, #378, #1183), I think. Webp I have a separate module for in node-gfx that, if not for the dependency trouble, could go in core. (Sorta side note, very recent builds of all of the dependencies needed for Windows, including libwebp, are available here: https://github.com/WebKitForWindows/WinCairoRequirements/releases.) BTW the way this PR is structured currently (all in JS), it could trivially go in a separate module that modifies canvas's Image prototype when it loads. I'm sorta hesitant to move away from libjpeg-turbo and libpng... |
Agreed.
* Except pango There's also up-to-date builds for Windows for nearly every popular open source library (including libwebp) here or via MinGW + pacman. They're pretty aggressive at updating libraries |
I also agree that dropping all current libraries would be too radical move, and that is not how this PR was planned. The main idea here is to allow user to load wide range of different image formats without installing 3rd-party libraries or modules.
Yes, but loading images should belong to the scope of this module. Do users need to install a new module (or patch the binding script / Image.prototype) in order to load a The ideal solution that I can think about is to literally make FFmpeg optional. It means: provide some variable (flag) that users can modify from JS code, which tells node-canvas how and when FFmpeg can be used. For example: var {Image, ffmpeg} = require('canvas');
ffmpeg.set('disabled'); // Disable FFmpeg (obscure images will throw error)
ffmpeg.set('default'); // Use FFmpeg as the primary image decoding software
ffmpeg.set('fallback'); // If node-canvas can't load, use FFmpeg It will be Thank you for insights so far. I'll go with this idea and see how it turns out. |
The wider range of formats is a fair point. I guess browsers do support more formats than we do for drawing as @zbjornson listed in #953 (comment). I haven't seen people ask for more than GIF/JPEG/PNG very often though. But the second part - don't need to install 3rd-party libraries - sounds like it might be solving the same issue that distributing prebuilt binaries solves. |
This might be a good approach 👍 The repo could live under node-gfx |
Ok, closing for now. I'll open another PR for Image prototype related stuff. |
This is initial implementation of basic FFmpeg support for loading rare and obscure image formats. Summary of this PR:
setSource
inlib/image.js
fixtures/159-crash1.jpg
file to make testcaptures errors from libjpeg
passIssues covered
Also fixes #1244.
Note: images used in the added tests contain the same problems (and without FFmpeg support report the same errors) as the reported images in the corresponding issues. However, these images are not the images that were originally posted in the issues, since the license of the original images is unknown / unclear / unspecified. The added tests contain only images that are licensed under the Creative Commons Zero License, making it easy to avoid any legal problems that may occur in the future.
Some questions
Image
has public propertysource
that can be accessed directly from user code? Shouldn't it be hidden and accessible only by calling some internal binding function, which is not exported by node-canvas interface?onload
andonerror
listeners need to be called synchronously? This may slow down the process, especially in a multi-threading application.Image::SetSource
performs unnecessary blocking IO operation, making the thread blocked until the file is loaded. Also, if decoding fails, FFmpeg has to load the file again. Is it a good idea to move it to JS lib, replacing it with asynchronousfs.readFile
? Then, even if decoding fails, FFmpeg doesn't need to load the file again - it can use the same buffer.onload
andonerror
calls. It implies thatspawnSync
must be used instead ofspawn
(for FFmpeg). Is it a good practice to refactor the existing tests and addapt them for asynchronous calls?Checklist