FFmpeg is an incredibly powerful tool for video processing. In this guide, we'll walk through a complete workflow for:
- Extracting individual frames from an H.264-encoded MP4 video as lossless PNG images.
- Removing a static watermark (logo) from those frames using the
delogofilter. - Re-encoding the cleaned frames back into H.264 MP4 videos at various quality levels, including lossless (CRF 0) and lower-bitrate options.
This frame-by-frame approach is useful when you need per-frame control (e.g., manual edits, AI upscaling, or complex processing). Note that it discards audio and can produce very large intermediate PNG files. If your watermark is static and you don't need per-frame edits, consider applying delogo directly during re-encoding (shown at the end).
We'll also cover important encoding flags like -movflags +faststart and compatibility considerations for consumer devices and hardware decoders.
Prerequisites
- Install FFmpeg (latest version recommended: https://ffmpeg.org/download.html).
- Basic command-line knowledge.
Step 1: Extract Frames as PNG Images
To extract every frame losslessly:
ffmpeg -i input.mp4 frame_%06d.png
%06dcreates filenames likeframe_000001.png(6-digit padding for correct ordering).- PNG is lossless, preserving exact pixel data from the source.
- This extracts all frames without dropping or duplicating (FFmpeg handles variable frame rates intelligently with image sequences).
Tip: If you want to force a specific frame rate (rarely needed), add -r 30 before -i.
Step 2: Remove Watermarks with the delogo Filter
The delogo filter removes a rectangular static logo by interpolating surrounding pixels. It works on video streams, so we apply it during extraction to get cleaned PNG frames directly.
First, find the logo coordinates:
ffmpeg -i input.mp4 -vf "delogo=x=100:y=100:w=200:h=50:show=1" -t 30 preview.mp4
x/y: top-left corner of the logo rectangle.w/h: width and height of the rectangle.show=1: draws a green rectangle overlay so you can preview positioning.-t 30: limits output to 30 seconds for quick testing.
Play preview.mp4 and adjust x:y:w:h until the green box perfectly covers the watermark. Common positions:
- Top-left corner logos: small
xandy. - Bottom-right: larger
x/y.
Once satisfied, extract cleaned frames (remove show=1):
ffmpeg -i input.mp4 -vf "delogo=x=100:y=100:w=200:h=50" cleaned_%06d.png
This produces cleaned PNG frames with the watermark removed/blended.
Note: delogo is simple interpolation — results are good for solid backgrounds but may look soft on complex areas. For better results, consider advanced tools like removelogo or AI inpainting after extraction.
Step 3: Re-encode Cleaned Frames to H.264 MP4
First, get the original frame rate for accurate timing:
ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate -of default=noprint_wrappers=1:nokey=1 input.mp4
This outputs something like 30/1 or 30000/1001. Use the value in the next commands (e.g., 30 for 30 fps).
Basic Re-encoding Template
ffmpeg -framerate 30 -i cleaned_%06d.png -c:v libx264 -pix_fmt yuv420p -movflags +faststart output.mp4
Key flags explained:
-framerate 30: matches original FPS (critical for correct speed).-pix_fmt yuv420p: 4:2:0 chroma subsampling — required for broad hardware compatibility (most devices/TVs/phones).-movflags +faststart: moves metadata ("moov atom") to file start for progressive playback (essential for web/streaming).
Quality/Bitrate Options
libx264 uses Constant Rate Factor (CRF) by default — lower CRF = higher quality, larger file.
Lossless (CRF 0) — mathematically perfect reconstruction:
ffmpeg -framerate 30 -i cleaned_%06d.png -c:v libx264 -crf 0 -preset veryslow -pix_fmt yuv420p -movflags +faststart lossless.mp4- File size: very large (often larger than original).
- Use
-preset veryslowfor best compression in lossless mode (slower encoding).
Visually Lossless (CRF 17–18) — indistinguishable from original for most viewers:
ffmpeg -framerate 30 -i cleaned_%06d.png -c:v libx264 -crf 17 -preset slow -pix_fmt yuv420p -movflags +faststart visually_lossless.mp4High Quality / Recommended Default (CRF 23) — excellent balance of quality and file size:
ffmpeg -framerate 30 -i cleaned_%06d.png -c:v libx264 -crf 23 -preset medium -pix_fmt yuv420p -movflags +faststart high_quality.mp4Good Quality / Smaller File (CRF 28):
ffmpeg -framerate 30 -i cleaned_%06d.png -c:v libx264 -crf 28 -preset fast -pix_fmt yuv420p -movflags +faststart smaller.mp4Target Bitrate (e.g., 5 Mbps) — use 2-pass for better quality:
# Pass 1 ffmpeg -framerate 30 -i cleaned_%06d.png -c:v libx264 -b:v 5000k -pass 1 -f null /dev/null # Pass 2 ffmpeg -framerate 30 -i cleaned_%06d.png -c:v libx264 -b:v 5000k -pass 2 -pix_fmt yuv420p -movflags +faststart bitrate_5mbps.mp4
Preset choices: ultrafast (fastest, larger files) → veryslow (slowest, smallest files at same CRF).
Compatibility with Consumer Devices/Hardware Decoders
Most modern devices (phones, TVs, game consoles, browsers) support:
- Profile: High (default for libx264 at higher resolutions).
- Level: 4.0–5.1 (FFmpeg auto-selects appropriately).
For maximum compatibility (older devices, some smart TVs):
-profile:v main -level 4.0
Example (add to any command):
... -c:v libx264 -profile:v main -level 4.0 -pix_fmt yuv420p ...
Avoid Baseline profile unless targeting very old devices (poorer compression).
Common issues:
- High Profile Level 5.2+ may fail on older hardware.
- 10-bit H.264 (
yuv420p10le) is poorly supported — stick to 8-bityuv420p. - No B-frames or CABAC on very old devices (use
-profile:v baselineif needed).
Handling Audio (Optional)
This workflow discards audio. To preserve it:
Extract audio:
ffmpeg -i input.mp4 -vn -c:a copy audio.aacAdd to final encode (after video-only pass):
ffmpeg -i video_only.mp4 -i audio.aac -c:v copy -c:a copy final_with_audio.mp4
Or combine in one step during re-encoding.
Faster Alternative: Apply delogo Directly (Recommended for Simple Cases)
If you don't need per-frame edits:
ffmpeg -i input.mp4 -vf "delogo=x=100:y=100:w=200:h=50" -c:v libx264 -crf 23 -preset medium -pix_fmt yuv420p -movflags +faststart -c:a copy cleaned_direct.mp4
Much faster, smaller intermediates, preserves audio/timing.
Conclusion
This workflow gives you full control over individual frames while leveraging FFmpeg's power. Start with lossless CRF 0 for archiving, then experiment with CRF 17–28 for distribution (remember: lower CRF = higher quality). Always test outputs on your target devices!
Happy encoding! 🚀