FFmpeg eq filter complex: Contrast

You need to specify the options in the filter by name, so your original filter settings would need to be changed to...

-filter_complex "[0:v]eq=contrast=1:brightness=0:saturation=1:gamma=1:
gamma_r=1:gamma_g=1:gamma_b=1:gamma_weight=1[outv]"

...if you wanted set all of those parameters. Otherwise, the filter is going to ignore your settings and apply the default values, or it could possibly misinterpret one intended option's value for another (it shouldn't, but stranger things have happened with FFmpeg's filters).

As far as the selected values vs. end results go, the code slhck pointed out shows that the value one sets per option are run through a series of internal calculations, then the results are used to evaluate and make pixel-level adjustments. It appears that the "base" calculation for contrast is...

(param->contrast * 256 * 16)

...so the default value of 0 would result in 0, a specified value of 1 would result in 4096, a value of -0.00275 would result in -11.264, etc, and these base values are used in further calculations down the line. In other words, it would be best to consider the filter's handling of these parameters as unique, so spend some time playing around with them to see how they work. To get a true idea of the effects, you can tweak and survey the output of the eq settings using FFplay, e.g.:

ffplay -i input.jpg -vf "eq=contrast=1.5:brightness=-0.05:saturation=0.75"

As far as your original script goes, since you were using only one input (your jpeg), one filter (eq), and all options except contrast were carrying default values, you can reduce the script down to the following to get your 3-second MP4, providing that eq=contrast=1 produces desirable results:

ffmpeg -y -loop 1 -i input.jpg -vf "eq=contrast=1" -c:v libx264 \
-pix_fmt yuv420p -t 3 out.mp4

full disclosure: post edited 2016/06/19 for greater clarification and extended info


To answer your original question about contrast in FFmpeg vs. CSS, the code fragment below seems to suggest that contrast in FFmpeg only applies to luminance/luma (brightness), while saturation only applies to chrominance/chroma (colors).

static void set_contrast(EQContext *eq)
{
    eq->contrast = av_clipf(av_expr_eval(eq->contrast_pexpr, eq->var_values, eq), -1000.0, 1000.0);
    eq->param[0].contrast = eq->contrast;
    eq->param[0].lut_clean = 0;
    check_values(&eq->param[0], eq);
}

// ...

static void set_saturation(EQContext *eq)
{
    int i;

    eq->saturation = av_clipf(av_expr_eval(eq->saturation_pexpr, eq->var_values, eq), 0.0, 3.0);

    for (i = 1; i < 3; i++) {
        eq->param[i].contrast = eq->saturation;
        eq->param[i].lut_clean = 0;
        check_values(&eq->param[i], eq);
    }
}

Notice how in set_contrast, only param[0] (denoting the first color component, which in YUV is Y, the luma) is changed, while in set_saturation only param[1] and param[2] (denoting yellow and magenta, the chroma) are changed. This should account for the fact that you are seeing yellow and magenta, two chroma color components, when you decrease contrast to 0 in FFmpeg. When you set saturation to 0 also, I'm seeing a plain gray image similar to the one produced by CSS.

The relationship between CSS's contrast and saturate versus FFmpeg's contrast and saturation can be established as:

filter: contrast(c) saturate(s);

is equivalent to

eq=contrast=c:saturation=c*s

Obligatory screenshots showing c = 0.6 and s = 1.3:

CSS filter FFmpeg eq