Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@okor
Copy link
Member

@okor okor commented Apr 16, 2017

This PR:

  • Adds a background_color option which only works with gifv
  • Moves the "scale to even pixel dimensions" work back to ffmpeg
  • Preserves proper gif delay durations

The reason we need the background color option is that some gifs contain transparency. These transparent regions will be converted to white by default. But white isn't always the correct color for a websites design. ffmpeg has no simple option to change the background as far as I could tell so we use this complex filter. Since ffmpeg will fill transparency with white every time and this new command is just as fast as the old one (benchmarked locally) we just use the same command every time even if no background option is specified - we just use white like default ffmpeg would. If a background_color is specified we use that color. Web applications will need to keep track and use the appropriate color for their design. ffmpeg is a bit pickier about colors - it doesn't allow hex short code for instance. So I added webcolors and a clumsy but robust logic for extracting colors while maintaining color format compatibility with the color options used in the background_color and fill filters that work with pngs. There may be a better way to do this, let me know if that's the case.

We also reintroduce the scale option to ffmpeg as well with the complex filter. Both the scale and canvas (background color) filters are performed at the same time to avoid extra passes / processing time. This simplifies maintenance of thumbor because we only have a single command.

  • This also works with transparent gifs with frames with transparency that are smaller than the full size of the gif. Using tools like imagemagic/convert handle that scenario poorly.
  • This works if a gif only has only two frames. The duration specified in the gif version will be preserved in the mp4/webm version correctly. Many many other methods of converting gifs to videos do not preserve the corrected durations - including fixed frame rate methods and/or other ffmpeg scaling methods all of which will break the duration of the last frame of the gif making it shorter than it should be (a single tick).
  • This does not add a background_color option to normal gifs. If present the option will simply be ignored.
  • I used background_color instead of fill because the latter implies that all transparency should be filled but as mentioned this will mess up a gif with overlaying frame where a later frame doesn't take up 100% of the size of the image canvas or should appear to float over previous frames. This is a true background color option.

This PR has been tested against ffmpeg version 3.2.4 There are known issues with using these filters with later releases such as 3.3 but earlier version may work as well. See open ffmpeg issue: https://trac.ffmpeg.org/ticket/6294 Since the gifv filter is still categorized as experimental I think it's ok to exclude some versions of ffmpeg. Hopefully ffmpeg will fix their bugs in the next release.

Example requests with identical output:
http://localhost:8888/unsafe/500x0/filters:gifv():background_color(ff00ff)/http://localhost/top_pin_wide.gif
http://localhost:8888/unsafe/500x0/filters:gifv():background_color(f0f)/http://localhost/top_pin_wide.gif
http://localhost:8888/unsafe/500x0/filters:gifv():background_color(magenta)/http://localhost/top_pin_wide.gif
http://localhost:8888/unsafe/500x0/filters:gifv():background_color(Magenta)/http://localhost/top_pin_wide.gif
http://localhost:8888/unsafe/500x0/filters:gifv():background_color(MaGeNTa)/http://localhost/top_pin_wide.gif

Example input with transparency:
top_pin_wide-1

Example output (mp4 converted back to gif manually, no mp4s supported in GH markdown)
top_pin_wide_ff00ff

@okor okor force-pushed the gifv-background branch 3 times, most recently from 7cb7ac5 to c2ecc75 Compare April 17, 2017 01:04
@masom
Copy link
Contributor

masom commented Apr 17, 2017

It would be nice if the option was documented :P

@okor
Copy link
Member Author

okor commented Apr 17, 2017

@masom haha, yes, totally agree. I'll work on that now.

@okor okor force-pushed the gifv-background branch from 383dcce to 84b29b7 Compare April 17, 2017 16:50
@okor
Copy link
Member Author

okor commented Apr 17, 2017

As noted in docs, latest release of ffmpeg breaks things. I'll see if I can pin the ffmpeg verion in the travis.yml

@okor okor force-pushed the gifv-background branch 5 times, most recently from fde4a79 to 4b473d1 Compare April 18, 2017 16:24
@okor
Copy link
Member Author

okor commented Apr 18, 2017

@masom I ended up having to build ffmpeg from source, those ppas won't work for 12.04 unfortunately. Also, 12.04 get EOL'ed in 10 days ... so we might want to consider testing on 14.04 or better.

@okor
Copy link
Member Author

okor commented Apr 18, 2017

@scorphus @andreaugusto Any thoughts on this?

Copy link
Member

@scorphus scorphus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's just incredible, @okor. I mean, look at the docs you've added! That's pretty amazing! Thank you so much!

Apart from the aforementioned changes requested below, are you done with it or willing to write tests for optimze? 😃

docs/gifv.rst Outdated

The gifv optimizer is able to convert gifs to mp4 or webm videos, often resulting in dramatically smaller sized files.

**Gifv is categorized as experimental and should be used with caution.** It uses ffmpeg to convert gifs to videos and so it's sensetive to changes with ffmpeg. It's recommended to lock your ffmpeg version with a fixed version (chef, docker, etc) and if updating make sure to check that the update doesn't break gifv. **FFmpeg version 3.2.4 is the current recommended version.** Later version, such as 3.3 will break the proper conversion of gif delays to frame durations in videos ... meaning videos will not be the same length as equivelant gifs.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a small typo here: s/sensetive/sensitive/

Also, “Later versions, such as 3.3, will break” reads best IMHO.

docs/gifv.rst Outdated
'thumbor.optimizers.gifv',
]
Once activated, you must add the ``gifv()`` option to your filters list. And example request might look like this:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/And/An/ I guess?

if color_string and bg_color_hex is None:
logger.error("background_color value could not be parsed")

return bg_color_hex
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could be simplified a bit:

def normalize_color_to_hex(self, color_string):
    try:
        return webcolors.normalize_hex("#" + color_string)
    except ValueError:
        pass

    try:
        return webcolors.name_to_hex(color_string)
    except ValueError:
        pass

    try:
        return webcolors.normalize_hex(color_string)
    except ValueError:
        pass

    if color_string:
        logger.error('background_color value could not be parsed')

@scorphus
Copy link
Member

@okor, I forgot to mention: good work with the gifv optimizer also!

@okor
Copy link
Member Author

okor commented Apr 21, 2017

@scorphus Hey, you can merge this now if you want but I'm going to add some more robust tests for gifv either way.

@okor
Copy link
Member Author

okor commented Apr 22, 2017

@scorphus It occurs to me that it might be faster to pipe buffers into and out of ffmpeg, instead of using files. Are input_file and output_file on the disk? If they are it seems like it would be better to use buffers. Let me know what you think.

@okor
Copy link
Member Author

okor commented Apr 22, 2017

Actually looks like tempfile is in memory and probably pretty fast. Never mind ; )

@andreaugusto
Copy link

Just in time: This PR looks great! Nothing to add to the discussion. :)

@okor okor force-pushed the gifv-background branch from a29be29 to 6f43bd2 Compare April 24, 2017 13:27
@okor
Copy link
Member Author

okor commented Apr 25, 2017

Ok, we all seem to be good with this. Gonna' merge.

@scorphus What version do you think this should be bumped to?

@okor okor merged commit b8af65a into thumbor:master Apr 25, 2017
@okor okor deleted the gifv-background branch April 25, 2017 14:13
@scorphus
Copy link
Member

Right on! Superb job, @okor! 👍 Thanks once again!

@scorphus What version do you think this should be bumped to?

I believe we're almost good to go with 6.4.0, as soon as we're done with some PR such as #878.

@Kmaschta Kmaschta mentioned this pull request Jan 5, 2018
9 tasks
kkopachev added a commit to kkopachev/thumbor that referenced this pull request Jun 7, 2018
'reverse' complex filter has to buffer entire video content in memory
before next filter can chop off last frame. In case of long big gif
inputs, amount of memory could exceed few gigabytes. If thumbor server
at the same time tries to optimize 2 gifv files, it's likely to run out
of memory and be killed with OOM killer. When ffmpeg process killed,
optimizer throws exception, but due to the fact thumbor misuses futures,
exception is never retrieved, so request waits until timeout happens.
There is a high chance that many requests will hang at the same time,
effectively exhausting open files limit and rendering service
interruption.
Reverse filter needed to overcome issue with ffmpeg dropping last frame
duration when used with overlay filter, which, in turn, was used to add
color-background for input gifs with transparency.
Turns out, that ffmpeg's gif decoder can be supplied with -trans_color
parameter, which does exactly that, but on decoding stage. This allows
to remove memory-heavy reverse filter and overlay all together.
As a side effect, previously broken ffmpeg 3.3 should also work fine.

see thumbor#907
heynemann pushed a commit that referenced this pull request Jun 11, 2018
'reverse' complex filter has to buffer entire video content in memory
before next filter can chop off last frame. In case of long big gif
inputs, amount of memory could exceed few gigabytes. If thumbor server
at the same time tries to optimize 2 gifv files, it's likely to run out
of memory and be killed with OOM killer. When ffmpeg process killed,
optimizer throws exception, but due to the fact thumbor misuses futures,
exception is never retrieved, so request waits until timeout happens.
There is a high chance that many requests will hang at the same time,
effectively exhausting open files limit and rendering service
interruption.
Reverse filter needed to overcome issue with ffmpeg dropping last frame
duration when used with overlay filter, which, in turn, was used to add
color-background for input gifs with transparency.
Turns out, that ffmpeg's gif decoder can be supplied with -trans_color
parameter, which does exactly that, but on decoding stage. This allows
to remove memory-heavy reverse filter and overlay all together.
As a side effect, previously broken ffmpeg 3.3 should also work fine.

see #907
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants