Watermark video with FFmpeg: logo overlay, transparency, and broadcast-bug positioning
Overlay a PNG logo or watermark onto video. Top-right corner with padding, semi-transparent, and the alpha-channel handling that prevents the most common rendering bugs.
When to use this
You watermark video for brand recognition (broadcast bug, logo bug), copyright assertion (anti-piracy visible mark), or pre-release content tracking (different watermark per recipient = forensic identification). The visible watermark trade-off: it permanently alters the frames, costs encoder compute, and can't be removed without re-encoding from a clean source. For piracy tracing without visible alteration, see forensic invisible watermarking (out of scope here — vendors like NexGuard, Witbe, Verimatrix specialize).
Command variants
ffmpeg -i input.mp4 -i logo.png \
-filter_complex "[1:v]scale=120:-1[wm];[0:v][wm]overlay=W-w-20:20" \
-c:a copy \
output.mp4Standard broadcast-bug placement. 120px wide logo, 20px padding from edges. Audio stream-copy unchanged.
ffmpeg -i input.mp4 -i logo.png \
-filter_complex "[1:v]format=rgba,colorchannelmixer=aa=0.5[wm];[0:v][wm]overlay=W-w-20:20" \
-c:a copy \
output.mp4colorchannelmixer aa=0.5 = 50% opacity. Use 0.3-0.5 for unobtrusive bug-style watermarking.
ffmpeg -i input.mp4 -i logo.png \
-filter_complex "[1:v]format=rgba,colorchannelmixer=aa=0.4[wm];[0:v][wm]overlay=(W-w)/2:(H-h)/2" \
-c:a copy \
output.mp4Centered watermark is typical for pre-release screeners. Higher opacity (0.4-0.6) makes it harder to crop out.
ffmpeg -i input.mp4 -i logo.png \
-filter_complex "[1:v]format=rgba,colorchannelmixer=aa=0.5[wm];[0:v][wm]overlay=W-w-20:20:enable='between(t,0,10)'" \
-c:a copy \
output.mp4Watermark only during specified time range. Useful for promotional / sponsorship tags.
What each parameter does
overlay=W-w-20:20Position formula. W = main video width, w = overlay width. (W-w-20) places overlay 20px from right edge. The second argument is Y position (20px from top).
scale=120:-1Scale logo to 120px wide, height auto-calculated to preserve aspect ratio. Use -1 for auto on either dimension.
format=rgba,colorchannelmixer=aa=0.5Convert to RGBA + scale alpha channel by 0.5 = 50% opacity. The standard semi-transparency idiom.
enable='between(t,0,10)'Watermark only between seconds 0 and 10. Useful for time-limited overlays.
-c:a copyAudio passes through unchanged. Watermarking is a video-only operation.
What this outputs
A re-encoded video file with the watermark permanently rendered into the frames. File size and quality match the encoder settings (defaults to libx264 medium-preset). The watermark cannot be removed without re-encoding from a clean source.
Pitfalls
- Logo PNGs without alpha channels render with a white box around the logo — always use transparent PNGs for proper compositing.
- Logo too small at high resolution (scale=120 looks tiny on 4K) or too big at low resolution (looks oversized on 360p). Calibrate logo size relative to source resolution.
- Forgetting -c:a copy re-encodes the audio along with video, which doubles the compute cost. Always stream-copy audio for watermarking.
- Filter syntax is whitespace-sensitive: spaces in `[1:v] scale=120:-1 [wm]` vs `[1:v]scale=120:-1[wm]` matter. Stick with the no-space convention.
- enable expression syntax requires single quotes around the expression and proper escape if used in shell scripts.
- Re-encoding always introduces some quality loss. If you watermark video that was already encoded, you encode it twice — quality compounds.
At production scale
Watermarking is libx264-bound at production scale. NVENC GPU-accelerated watermarking works but has occasional alpha-blending artifacts at edges. For broadcast-grade output, stick with libx264 + filter_complex. At >100K minutes/month with watermarking as a standard step, the compute cost roughly doubles vs unwatermarked encoding. Consider conditional watermarking: only apply when the customer's use case requires it (e.g., screener delivery vs final master).
MpegFlow models watermarking as a parameterized DAG stage so the watermark file, opacity, position, and timing are per-job inputs. This lets you watermark differently per recipient (forensic tracing) without rebuilding the pipeline per customer.