1

I want to fade-in/fade-out the saturation of a video based on the time (t). For three videos, the saturation should fade in and fade out at different points in time, starting with 0, 6, and 12 seconds.

Here is the script, using 1.5 seconds for fade-in and 2.0 seconds for fade-out. Each video should have saturation only for 6 seconds, with full saturation only for 2.5 seconds (6-2.0-1.5):

ffmpeg \
  -y \
  -f lavfi -i testsrc=size=640x480:rate=30:duration=18 \
  -f lavfi -i testsrc=size=640x480:rate=30:duration=18 \
  -f lavfi -i testsrc=size=640x480:rate=30:duration=18 \
  -filter_complex "
    [0:v]
      setpts=PTS-STARTPTS,drawtext=text='vid1 - %{pts}':fontsize=24:fontcolor=white,
      hue=s='clip(between(t,0,0+6) + ((t - 0)/1.5) * between(t,0,0+1.5) + (-(t-0+6)/2.0) * between(t,0+6-2.0,0+6), 0, 1)'
    [vid1];
    [1:v]
      setpts=PTS-STARTPTS,drawtext=text='vid2 - %{pts}':fontsize=24:fontcolor=white,
      hue=s='clip(between(t,6,6+6) + ((t - 6)/1.5) * between(t,6,6+1.5) + (-(t-6+6)/2.0) * between(t,6+6-2.0,6+6), 0, 1)'
    [vid2];
    [2:v]
      setpts=PTS-STARTPTS,drawtext=text='vid3 - %{pts}':fontsize=24:fontcolor=white,
      hue=s='clip(between(t,12,12+6) + ((t - 12)/1.5) * between(t,12,12+1.5) + (-(t-12+6)/2.0) * between(t,12+6-2.0,12+6), 0, 1)'
    [vid3];
    [vid1][vid2][vid3]
      hstack=inputs=3[out]" \
  -map "[out]" -pix_fmt yuv420p -f matroska - | ffplay -

The algorithm itself works, as I can use it in a Python program without problems. The issue is that the shift in saturation is instantaneous, i.e., the first video will have full saturation from 0-4, while it should have a fade-in and a fade-out with smooth transitions.

Why is that, and how can I fix it? It's not that t is integer-based … when I use pts*tb instead of t, the issue persists.

2 Answers 2

2

In the expr,

clip(between(t,0,0+6) + ((t - 0)/1.5) * between(t,0,0+1.5) + (-(t-0+6)/2.0) * between(t,0+6-2.0,0+6), 0, 1),

the first term will contribute 1 for the entire interval, and the fade-in clause can only add to that, and then ultimately get clipped to 1, so there's no progression for a fade-in to occur. For the fade-out, before clipping, the expr dips below 0 at once, and gets clipped to 0.

Use

hue=s=between(t\,0\,0+6) - (between(t\,0\,0+1.5)*(1-((t - 0)/1.5))+between(t\,0+6-2.0\,0+6)*((t-(6-2.0))/2.0))

1
  • Thanks for spotting this. I actually had not one but two (dumb) translation errors from Python to ffmpeg, that explains the issue (posted another answer with the correct solution based on the original filter).
    – slhck
    May 24, 2022 at 10:07
0

I had two errors in the script:

  1. The first between() function should begin not at 0, 6, … and end at 6, 12, …, but have the fade-in duration added to it, i.e. between(t,0+1.5,0+6-2.0) for the first one, and stop at the end minus the fade-out time.

  2. The calculation of the offset for the fade-out was wrong. Instead of (-(t-0+6)/2.0), the offset must be in parentheses, meaning I should use -(t-(0+6))/2.0) (as otherwise the sign is inverted).

Fully functioning code:

#!/usr/bin/env bash

ffmpeg \
  -y \
  -f lavfi -i testsrc=size=640x480:rate=30:duration=18 \
  -f lavfi -i testsrc=size=640x480:rate=30:duration=18 \
  -f lavfi -i testsrc=size=640x480:rate=30:duration=18 \
  -filter_complex "
    [0:v]
      setpts=PTS-STARTPTS,drawtext=text='vid1 - %{pts}':fontsize=24:fontcolor=white,
      hue=s='clip(between(t,0+1.5,0+6-2.0) + ((t-0)/1.5) * between(t,0,0+1.5) + (-(t-(0+6))/2.0) * between(t,0+6-2.0,0+6),0,1)'
    [vid1];
    [1:v]
      setpts=PTS-STARTPTS,drawtext=text='vid2 - %{pts}':fontsize=24:fontcolor=white,
      hue=s='clip(between(t,6+1.5,6+6-2.0) + ((t-6)/1.5) * between(t,6,6+1.5) + (-(t-(6+6))/2.0) * between(t,6+6-2.0,6+6),0,1)'
    [vid2];
    [2:v]
      setpts=PTS-STARTPTS,drawtext=text='vid3 - %{pts}':fontsize=24:fontcolor=white,
      hue=s='clip(between(t,12+1.5,12+6-2.0) + ((t-12)/1.5) * between(t,12,12+1.5) + (-(t-(12+6))/2.0) * between(t,12+6-2.0,12+6),0,1)'
    [vid3];
    [vid1][vid2][vid3]
      hstack=inputs=3[out]" \
  -map "[out]" -pix_fmt yuv420p -f matroska - | ffplay -

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.