Ever found yourself with gigabytes of security camera footage and wondered if anything actually happened? If you're working with MJPEG stream files from IP cameras or surveillance systems, manually reviewing hours of footage is tedious and time-consuming. In this guide, I'll show you how to automate motion detection using a powerful bash script that extracts only the moments that matter.

The Problem with MJPEG Streams

MJPEG (Motion JPEG) streams are commonly used by security cameras and IP cameras. Unlike traditional video formats, MJPEG stores each frame as a separate JPEG image within a single file. While this format is simple and widely supported, it creates unique challenges:

  • Massive file sizes: An hour of footage can easily exceed 1GB
  • Difficult to analyze: Standard video tools may not recognize the format
  • Time-consuming review: Scrubbing through hours of mostly static footage is impractical

The solution? Automated motion detection that extracts only the sequences where something actually happens.

How the Motion Detection Script Works

The script I've developed performs three key operations:

  1. Frame Extraction: Converts MJPEG streams into individual JPEG frames at your specified frame rate
  2. Motion Analysis: Compares consecutive frames to detect pixel changes using FFmpeg's sophisticated difference algorithms
  3. Sequence Generation: Bundles detected motion into separate video files and GIFs for easy review

Prerequisites

Before getting started, ensure you have FFmpeg installed on your Ubuntu system:

sudo apt update
sudo apt install ffmpeg

That's it! The script is pure bash with FFmpeg doing the heavy lifting.

Using the Script

Basic Usage

The simplest way to run the script is by navigating to your directory containing MJPEG files (named in HHMM-HHMM.jpeg format like 1045-1100.jpeg) and running:

./mjpeg_exctract_detected_motions.sh

This uses default settings:

  • Motion threshold: 5% pixel change
  • Minimum sequence length: 5 frames
  • Extraction rate: 1 frame per second

Custom Parameters

The script accepts five parameters for fine-tuned control:

./mjpeg_exctract_detected_motions.sh [input_dir] [output_dir] [threshold] [min_frames] [fps]

Example 1: Process files in the current directory with a higher motion threshold:

./mjpeg_exctract_detected_motions.sh . motion_results 10 3 1

This sets:

  • Input: Current directory (.)
  • Output: motion_results folder
  • Threshold: 10% (less sensitive, catches bigger movements)
  • Minimum sequence: 3 frames
  • Extraction: 1 FPS

Example 2: High-sensitivity detection for subtle movements:

./mjpeg_exctract_detected_motions.sh /path/to/streams output 3 5 2

This configuration:

  • Extracts 2 frames per second (more granular)
  • Detects movements affecting just 3% of pixels
  • Requires 5 consecutive frames to qualify as a sequence

Understanding the Output

After processing, you'll find several items in your output directory:

Directory Structure

motion_sequences/
├── extracted_frames/          # All individual frames
│   ├── frame_1004-1014_000001.jpg
│   ├── frame_1004-1014_000002.jpg
│   └── ...
├── sequence_1/                # Frames with motion detected
│   ├── frame_1004-1014_000023.jpg
│   └── ...
├── sequence_1.mp4             # Video compilation
├── sequence_1.gif             # Animated preview
└── sequence_2.mp4

Video Files

Each detected motion sequence is compiled into an MP4 file playing at 2 FPS, making it easy to review what triggered the detection.

GIF Previews

Preview GIFs (480px width) let you quickly scan through sequences without opening video files.

Tuning Motion Detection

Getting optimal results depends on your specific use case:

For Busy Streets

  • Threshold: 10-20%
  • Min frames: 5-10
  • FPS: 1

This filters out minor movements like swaying trees and focuses on people or vehicles.

For Indoor Monitoring

  • Threshold: 3-8%
  • Min frames: 3-5
  • FPS: 2

More sensitive settings catch smaller movements in controlled environments.

For Wildlife Cameras

  • Threshold: 5-15%
  • Min frames: 3-7
  • FPS: 0.5

Lower extraction rate saves processing time while still capturing animal activity.

Performance Considerations

Processing large MJPEG streams is resource-intensive. Here's what to expect:

  • 1GB file: Approximately 5-10 minutes on a modern CPU
  • Disk space: Extracted frames require 2-3x the original file size temporarily
  • Memory: Minimal impact, FFmpeg handles streaming efficiently

The script automatically cleans up temporary files after processing.

Advanced Tips

Batch Processing Multiple Days

Create a simple loop to process multiple directories:

for dir in /media/recordings/2024-*/; do
    ./mjpeg_exctract_detected_motions.sh "$dir" "${dir}/motion_detected" 8 5 1
done

Skip Frame Extraction (Reprocessing)

If you've already extracted frames and want to adjust detection parameters, modify the script to skip Step 1 and reuse existing frames.

Custom FFmpeg Filters

For specialized scenarios (night vision, specific areas of interest), you can modify the FFmpeg filter chain around line 98 to add:

  • Brightness normalization
  • Region-of-interest masking
  • Noise reduction

Troubleshooting

"Not a JPEG file" error: Your files are MJPEG streams, which is correct. The script handles this automatically.

No motion detected: Try lowering the threshold or check if your camera is capturing significant pixel changes.

Out of disk space: The script needs temporary space equal to 2-3x your input file size.

Conclusion

Automated motion detection transforms how you work with surveillance footage. Instead of reviewing hours of static images, you get condensed clips of actual events. Whether you're monitoring a storefront, tracking wildlife, or analyzing traffic patterns, this script saves time and storage space.

The best part? It's completely free, open-source, and runs on any Linux system with FFmpeg. No cloud services, no subscription fees, just efficient local processing.

Download the script, adjust the parameters to your needs, and let automation handle the tedious work of finding what matters in your MJPEG streams.

The source code is available at GitHub

Bash Script GitHub Download
Follow my work on GitHub!

Need an Android Developer or a full-stack website developer?

I specialize in Kotlin, Jetpack Compose, and Material Design 3. For websites, I use modern web technologies to create responsive and user-friendly experiences. Check out my portfolio or get in touch to discuss your project.