Batch Process MP4 Files in Parallel Using FFmpeg

Processing video files one by one can be time-consuming, but you can significantly reduce encoding times by leveraging modern multi-core processors to process multiple files at the same time. This guide shows how to write a clean, reliable Bash script that uses ffmpeg alongside xargs to concurrently encode or modify every MP4 file in a specified directory while safely handling filenames that contain spaces.

The Bash Script

Create a script named process_videos.sh and add the following code:

#!/usr/bin/env bash

# Define input and output directories
INPUT_DIR="./input"
OUTPUT_DIR="./output"

# Set the maximum number of concurrent processes (e.g., 4 or use $(nproc) for all cores)
MAX_JOBS=4

# Create output directory if it does not exist
mkdir -p "$OUTPUT_DIR"

# Export variables and the processing function so subshells can access them
export OUTPUT_DIR

process_video() {
    input_file="$1"
    filename=$(basename -- "$input_file")
    output_file="$OUTPUT_DIR/${filename%.mp4}_processed.mp4"

    echo "Starting: $filename"
    
    # Replace this ffmpeg command with your desired options
    ffmpeg -v error -stats -y -i "$input_file" \
        -c:v libx264 -crf 23 -preset medium \
        -c:a aac -b:a 128k \
        "$output_file"

    echo "Completed: $filename"
}

export -f process_video

# Find all MP4 files and pass them to xargs for parallel execution
find "$INPUT_DIR" -maxdepth 1 -type f -name "*.mp4" -print0 | \
    xargs -0 -n 1 -P "$MAX_JOBS" -I {} bash -c 'process_video "$@"' _ {}

echo "All files processed successfully."

How It Works

  1. MAX_JOBS: Controls how many instances of ffmpeg run simultaneously. You can set this manually or replace the value with $(nproc) to automatically match the number of available CPU threads.
  2. find ... -print0: Scans the input folder for files ending in .mp4 and outputs them separated by a null byte (\0). This ensures filenames containing spaces, tabs, or special characters are passed without breaking.
  3. xargs -0 -n 1 -P "$MAX_JOBS":
    • -0 instructs xargs to read null-terminated input.
    • -n 1 passes exactly one file at a time to the command.
    • -P "$MAX_JOBS" enables parallel processing, keeping up to the designated number of worker processes running at once until the queue is finished.
  4. ffmpeg -v error -stats: Suppresses non-critical log output to keep the terminal readable, while -stats provides active encoding progress for each running process.

Running the Script

Make the script executable and run it from your terminal:

chmod +x process_videos.sh
./process_videos.sh