How to Create an FFmpeg Watch Folder for Transcoding
This guide explains how to set up an automated watch folder system that detects newly added media files and automatically transcodes them using FFmpeg. By implementing an event-driven automation script, you can streamline your video processing workflow, eliminate manual command-line encoding, and ensure that converted media is automatically organized into an output directory.
Prerequisites
Before setting up the script, ensure you have the following installed on your system:
- FFmpeg: Must be installed and accessible in your
system's
PATH. - Python 3: Used to run the cross-platform watch script.
- Watchdog Library: A Python library that monitors file system events. Install it via pip:
pip install watchdogCreating the Automated Watch Folder Script
The most robust way to monitor directories across Windows, macOS, and
Linux is using Python with the watchdog library. This
method avoids polling overhead and catches file system events as they
happen.
Save the following code as ffmpeg_watcher.py:
import os
import time
import subprocess
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
# Configuration
WATCH_DIR = "/path/to/watch_folder"
OUTPUT_DIR = "/path/to/output_folder"
SUPPORTED_EXTENSIONS = ('.mp4', '.mkv', '.mov', '.avi', '.ts')
class TranscodeHandler(FileSystemEventHandler):
def on_created(self, event):
if event.is_directory:
return
file_path = event.src_path
file_name, file_ext = os.path.splitext(os.path.basename(file_path))
if file_ext.lower() in SUPPORTED_EXTENSIONS:
self.process_file(file_path, file_name)
def process_file(self, file_path, file_name):
# Ensure file copy operation has fully finished
self.wait_for_file_transfer(file_path)
output_path = os.path.join(OUTPUT_DIR, f"{file_name}_transcoded.mp4")
# FFmpeg command: H.264 video, AAC audio, faststart enabled for web
cmd = [
"ffmpeg",
"-y", # Overwrite output if it exists
"-i", file_path,
"-c:v", "libx264",
"-crf", "23",
"-preset", "medium",
"-c:a", "aac",
"-b:a", "128k",
"-movflags", "+faststart",
output_path
]
print(f"Started transcoding: {file_path}")
try:
subprocess.run(cmd, check=True)
print(f"Finished transcoding: {output_path}")
# Optional: Delete or archive the original file
# os.remove(file_path)
except subprocess.CalledProcessError as e:
print(f"Error transcoding {file_path}: {e}")
def wait_for_file_transfer(self, file_path):
"""Wait until file size remains constant to ensure copying is complete."""
historical_size = -1
while True:
try:
current_size = os.path.getsize(file_path)
if current_size == historical_size and current_size > 0:
break
historical_size = current_size
time.sleep(2)
except FileNotFoundError:
time.sleep(1)
if __name__ == "__main__":
os.makedirs(WATCH_DIR, exist_ok=True)
os.makedirs(OUTPUT_DIR, exist_ok=True)
event_handler = TranscodeHandler()
observer = Observer()
observer.schedule(event_handler, WATCH_DIR, recursive=False)
observer.start()
print(f"Watching directory: {WATCH_DIR}")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()How the Script Works
- Path Initialization: The script creates both the
input (
WATCH_DIR) and output (OUTPUT_DIR) folders if they do not already exist. - Event Detection: When a new file is placed in the
watch folder,
on_createdtriggers. - Lock Protection: The
wait_for_file_transferfunction monitors the file size until it stops growing. This prevents FFmpeg from attempting to encode a file while it is still being copied over the network or disk. - Encoding Execution:
subprocess.runexecutes the FFmpeg command using standard H.264 and AAC parameters. - Output Organization: The encoded file is deposited
into the output folder with
_transcoded.mp4appended to the name.
Running the Script in the Background
Linux (Systemd Service)
To run the script automatically on system boot:
- Create a service file:
/etc/systemd/system/ffmpeg-watcher.service - Add the following configuration:
[Unit]
Description=FFmpeg Watch Folder Service
After=network.target
[Service]
Type=simple
User=your_username
ExecStart=/usr/bin/python3 /path/to/ffmpeg_watcher.py
Restart=on-failure
[Install]
WantedBy=multi-user.target- Enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable --now ffmpeg-watcher.serviceWindows
On Windows, run the script via PowerShell or use a task manager
utility such as NSSM (Non-Sucking Service Manager) to run
python ffmpeg_watcher.py as a background Windows
Service.