vesna
vesna

Reputation: 335

GIF overlays blink with ffmpeg

I've been playing around with ffmpeg over the past months and can't get rid of an issue I'm facing when adding a GIF file as an overlay.

Basically what I'm trying to achieve is to add a transparent GIF animation as an overlay on top of a MP4 video.

Please find below an example command that I'm using:

ffmpeg \
  -i 0689a8a9-43b5-45d2-b0e8-acbea6905ce1.mp4 \
  -ignore_loop 0 \
  -i 02a6e696-969b-4a90-9444-e4b0b4d6f6da.gif \
  -t 10.000000 \
  -filter_complex "[0:v][1:v]overlay=enable='between(t, 1, 3)'[overlay]" \
  -map '[overlay]' \
  -pix_fmt yuv420p \
  output.mp4

For a better understanding, please note that:

However, when I run this command, a very few milliseconds before the GIF disapears (at 3s), it starts blinking. If I run take a look at it frame by frame, it actually disappears from the video, then comes back, and eventually goes away as expected.

Please find an example with a black background and a random GIF from giphy at this link. The assets can be found here.

I'm probably missing something here. Do you have any hints ?

I'm running ffmpeg in 4.3.1.

Thank you in advance

Upvotes: 6

Views: 880

Answers (2)

Anton Serov
Anton Serov

Reputation: 301

In the official FFmpeg community there is a ticket for this, which hasn't been fixed though: https://trac.ffmpeg.org/ticket/4803

The ticket mentions that a GIF is being shown before the specified enable time. On my tests, given a 60 fps video, a 10.42 fps GIF (that needs to be shown from 5 to 10 s) blinks once 5 frames before the desired time (at 4.933 s) and becomes visible again right at 5 s. Should be something connected to the GIF's fps which doesn't match the video's fps.

Anyways, I've found the most elegant workaround, which solves the problem in a single pass and doesn't require converting GIFs to temporary MP4s (because in some cases that could be undesired). So, given the video fps, to overlay a GIF at a certain position (x=10, y=20) from 5 to 10 s without blinking we should use the following:

ffmpeg -y -i "video.mp4" -ignore_loop 0 -i "giphy.gif" \
-filter_complex "[1:v]fps=60[gif];[0:v][gif]overlay=x=10:y=20:enable='between(t,5,10)'" \
-c:a copy -shortest "overlay.mp4"

We can go further and come up with a command line which doesn't require a prior knowledge of the video fps (but you should know the output video fps instead, which is 60 fps in this case):

ffmpeg -y -i "video.mp4" -ignore_loop 0 -i "giphy.gif" \ 
-filter_complex "[0:v]fps=60[video];[1:v]fps=60[gif];[video][gif]overlay=x=10:y=20:enable='between(t,5,10)'" \
-acodec copy -shortest "overlay.mp4"

Upvotes: 0

Suuuehgi
Suuuehgi

Reputation: 5010

I can replicate this with an arbitrary gif. I suspect a bug in the overlay filter. Feel free to present this to https://trac.ffmpeg.org.

This happens as soon as the temporal filtering is set (filter is listed as having timeline support) and furthermore changes depending on the time boundaries. The latter should never be the case.

MWE

ffmpeg \
  -t 10 -s qcif -f rawvideo -pix_fmt rgb24 -r 25 -i /dev/zero \
  -ignore_loop 0 -i 'https://media.tenor.com/images/c50ca435dffdb837914e7cb32c1e7edf/tenor.gif' \
  -filter_complex "overlay=enable='between(t,3,7)'" \
  -f flv - | ffplay -

You could try, as a workaround, converting the gif to an mp4 (ffmpeg -re -i <gif> [...]) and set the white areas to transparent.

Upvotes: 2

Related Questions