Batch-convert and optimize video files for Wallpaper Engine/Or any high resolution wallpaper you have, using FFmpeg. Drop any mix of video formats into a folder, run the script, and get ready .mp4 files in an optimized/ subdirectory.
- ffmpeg and ffprobe (both must be on
$PATH) - bash 4+
Install on Arch:
sudo pacman -S ffmpegInstall on Debian-Based distros:
sudo apt install ffmpegInstall on Windows:
You should visit ffmpeg website
-
Open
wallpaper_optimizer.shand setINPUT_DIRto the directory containing your wallpapers:INPUT_DIR="/path/to/your/wallpapers" -
Run it:
chmod +x wallpaper_optimizer.sh ./wallpaper_optimizer.sh
-
Optimized files land in
<INPUT_DIR>/optimized/.
| Setting | Value | Why |
|---|---|---|
| Codec | H.264 (libx264) | Wallpaper Engine's built-in player expects H.264 |
| Profile/Level | High 4.2 | Broad hardware decode support, HDR-friendly profile |
| Resolution | 1920×1080 | Standard wallpaper size; scales + crops to fit |
| Pixel format | yuv420p | Maximum compatibility with players and hardware decoders |
| CRF | 23 | Visually lossless at 1080p; good size/quality tradeoff |
| Preset | slow |
Better compression per bitrate vs faster presets |
| Max bitrate | 8 Mbps | Caps spikes so complex scenes don't cause decode stutter |
| Buffer size | 16 MB | VBV buffer for the maxrate cap |
| GOP | ~2 seconds | Smooth seeking/looping without bloating file size |
| Keyframe min | 1 × FPS | Prevents keyframes closer than 1 second |
faststart |
✅ | Moves the moov atom to the start so playback begins instantly |
- Source > 60 fps → capped to 60 fps (avoids unnecessary decode overhead)
- Source ≤ 60 fps → kept as-is (no frame duplication)
Wallpaper Engine uses the BASS audio library, which can't decode Opus. The script detects Opus audio and transcodes it to AAC at 256 kbps — transparent quality for the typical low-bitrate wallpaper audio track.
Files that are already H.264, already 1920×1080, already under 10 Mbps, and have no Opus audio are remuxed (stream-copied) instead of re-encoded. No quality loss, instant operation.
If the output .mp4 already exists, the file is skipped. Safe to re-run.
.mp4 .mkv .mov .avi .webm .m4v — anything FFmpeg can read in these containers.
Edit the variables at the top of the script:
TARGET_WIDTH=1920 # output width
TARGET_HEIGHT=1080 # output height
TARGET_FPS=60 # fps cap
CRF=23 # quality (lower = better, 18–28 typical range)
PRESET="slow" # x264 preset: ultrafast → veryslow
MAXRATE="8M" # peak bitrate cap
BUFSIZE="16M" # VBV buffer
AUDIO_FALLBACK_CODEC="aac"
AUDIO_FALLBACK_BITRATE="256k"your_wallpapers/
├── video1.mp4 ← input (any supported format)
├── video2.mkv
├── video3.webm
└── optimized/ ← created by the script
├── video1.mp4 ← output (already optimized → remuxed)
├── video2.mp4 ← output (re-encoded)
└── video3.mp4
Do whatever you want with it.