How to Dynamically Adjust Exposure in FFmpeg
This guide explains how to dynamically adjust video exposure using
FFmpeg's exposure filter. Because the filter accepts
constant floating-point values for exposure stops (-3.0 to 3.0 EV),
dynamic variations across playback are achieved by using timeline
expressions via the enable option, chaining staged filters,
or interpolating between streams using the blend filter.
Below are the precise syntax rules and command examples for time-based
triggers, stepped exposure changes, and smooth continuous exposure
transitions.
The exposure Filter
Syntax
The exposure filter modifies the exposure and black
level of a video stream:
exposure: Sets the exposure correction in EV (exposure value) stops. The valid range is from-3.0to3.0. Default is0.0.black: Sets the black level correction. The valid range is from-1.0to1.0. Default is0.0.
Because the exposure parameter accepts a fixed float
rather than an evaluated mathematical string expression per frame,
dynamic adjustments rely on FFmpeg's timeline evaluation or frame
blending.
Method 1:
Time-Based Activation Using enable
FFmpeg filters support the common enable option, which
evaluates expressions on every frame. You can use standard timeline
variables like t (current timestamp in seconds) or
n (frame number) to turn an exposure adjustment on or off
at specific timestamps.
Example: Apply Exposure Correction for a Specific Interval
To boost exposure by 1.5 EV between second 3 and second
8:
ffmpeg -i input.mp4 -vf "exposure=exposure=1.5:enable='between(t,3,8)'" -c:a copy output.mp4Method 2: Stepped Exposure Transitions
To create stepped adjustments across multiple sections of a video,
chain multiple instances of the exposure filter, each
constrained to a different time window using enable.
Example: Multi-Stage Brightness Adjustment
ffmpeg -i input.mp4 -vf "\
exposure=exposure=0.5:enable='between(t,2,4)',\
exposure=exposure=1.0:enable='between(t,4,6)',\
exposure=exposure=1.5:enable='between(t,6,8)'" \
-c:a copy output.mp4In this command:
- From 0 to 2 seconds: Original exposure (0 EV).
- From 2 to 4 seconds: Exposure increases by +0.5 EV.
- From 4 to 6 seconds: Exposure increases by +1.0 EV.
- From 6 to 8 seconds: Exposure increases by +1.5 EV.
- After 8 seconds: Reverts to original exposure.
Method 3: Smooth, Continuous Exposure Ramps
To smoothly ramp exposure up or down over time rather than jumping
abruptly, split the video into two streams, apply the target exposure to
one stream, and use the blend filter with a time-based
expression to interpolate between them.
Example: Linear Exposure Ramp Over 5 Seconds
To smoothly transition from standard exposure (0 EV) to +2.0 EV over the first 5 seconds:
ffmpeg -i input.mp4 -filter_complex "\
[0:v]split=2[base][target]; \
[target]exposure=exposure=2.0[bright]; \
[base][bright]blend=all_expr='if(lte(T,5), A*(1-T/5)+B*(T/5), B)'[v]" \
-map "[v]" -map 0:a? -c:a copy output.mp4How this works:
split=2duplicates the source video into[base]and[target].exposure=exposure=2.0elevates the exposure of[target]by 2 stops.blend=all_expr=...usesT(current time in seconds). For the first 5 seconds (lte(T,5)), it calculates a linear interpolation between streamA(original) and streamB(exposed). After 5 seconds, it holds streamBcompletely.
Example: Pulsing Exposure (Oscillation)
To make the exposure continuously oscillate between normal and +1.5 EV using a sine wave:
ffmpeg -i input.mp4 -filter_complex "\
[0:v]split=2[base][target]; \
[target]exposure=exposure=1.5[bright]; \
[base][bright]blend=all_expr='A*(0.5+0.5*cos(2*PI*T/3))+B*(0.5-0.5*cos(2*PI*T/3))'[v]" \
-map "[v]" -map 0:a? -c:a copy output.mp4This configuration completes a full exposure pulse cycle every 3 seconds.