Purpose: Record grayscale scientific camera frames to MP4 video using CPU-only H.264 encoding (libx264), with optional timestamp and scale bar overlays.
The traditional workflow for creating videos from microscopy is tedious: µManager → TIFF stack → ImageJ/Fiji → adjust contrast → export → FFmpeg → finally MP4.
This plugin eliminates those steps. Common use cases:
- Quick demos — Show a colleague what's happening on the scope right now
- Presentations — Get a polished video for PowerPoint/Keynote without post-processing
- Teaching — Record live demonstrations for students
For quantitative analysis, you still want raw data. But when morphology and dynamics are what matters — and lossy compression is acceptable — this plugin gets you from Live mode to shareable video in seconds.
Bit depth conversion: Scientific cameras output 12-bit or 16-bit images, but video is 8-bit. This plugin uses Micro-Manager's display settings (the brightness/contrast sliders) to map your data to 8-bit. What you see is what you get — adjust contrast before or during recording.
Important: This plugin records the Live view only: the single-channel grayscale image currently displayed. Not for multi-channel acquisitions or MDA. Ideal for transmitted light (brightfield, phase contrast, DIC) or single-channel fluorescence. Output is always grayscale regardless of LUT.
- Real-time MP4 encoding via FFmpeg pipe (no intermediate files)
- Three recording modes:
- Constant FPS — Maintains steady output framerate (duplicates/drops frames as needed)
- Real-time (VFR) — Records every frame exactly once, preserving actual timing
- Time-lapse compression — Compresses playback time (e.g., 10x = plays 10× faster)
- Automatic segment numbering — Prevents file overwrites, auto-increments filenames
- Live display scaling — Uses Micro-Manager's current brightness/contrast settings
- Customizable overlays:
- Δt timestamp — Shows elapsed time (HH:MM:SS.mmm) in top-left corner
- Scale bar — Automatic scale bar in bottom-right (uses pixel size from MM config)
- Text color — White or black text with optional contrasting background
- Immediate finalization — MP4 closes properly when Live mode stops (event-driven)
- Watchdog timeout — Finalizes recording if no frames arrive (prevents hung sessions)
- Micro-Manager 2.x (tested with MM Studio 2.0.3, MMCore 11.11.0)
- FFmpeg — Either on system PATH or configured via settings
- JDK 8+ for building (only if building from source)
- Apache Ant for building (only if building from source)
FFmpeg is required for video encoding. Download and install from:
- Windows: gyan.dev/ffmpeg/builds — download "essentials" build, extract, add
bin/folder to PATH - macOS:
brew install ffmpeg - Linux:
sudo apt install ffmpeg(Debian/Ubuntu) or equivalent
Verify installation: ffmpeg -version
Alternatively, set the full path to ffmpeg.exe in the plugin settings.
- Download
MP4Stream.jarfrom the releases page orbuild/jar/folder - Copy to your Micro-Manager
mmplugins/folder - Restart Micro-Manager
- Clone this repository
- Build:
ant jar - Copy
build/jar/MP4Stream.jarto your Micro-Managermmplugins/folder - Restart Micro-Manager
Plugins → On-The-Fly Image Processing → Configure Processor Pipeline
Check the box under "Enabled" next to "MP4 Stream (FFmpeg)" to enable recording.
The Snap/Live toggle controls when the plugin processes images. Set it to Live or Both — the plugin only records during Live mode, so "Snap only" effectively disables recording.
Note: My dream is for this plugin to be merged into Micro-Manager in the future. Until then, download from this repository.
Click the Configure... button next to the plugin to open settings:
| Setting | Description |
|---|---|
| Output file | Base path for MP4 output (actual files get _WxH_segNNN.mp4 suffix) |
| FFmpeg path | Path to ffmpeg.exe (leave empty to use system PATH) |
| Recording Mode | See Recording Modes below |
| FPS | Target output framerate (Constant FPS and Time-lapse modes) |
| Time-lapse factor | Playback speedup multiplier (for Time-lapse mode) |
| Setting | Description |
|---|---|
| Show timestamp (Δt) | Elapsed time overlay (top-left) |
| Text color | White or black |
| Font size | Overlay text size in pixels (8-72, default 18) |
| Contrasting background | Adds semi-transparent background box behind text for readability |
| Show scale bar | Draws a scale bar in bottom-right corner (requires pixel size to be configured in MM) |
| Scale bar length | Fixed length in µm, or 0 for auto (~15% of image width) |
The scale bar displays in µm or mm depending on length.
Constant FPS and Time-lapse modes output video at the configured target FPS (default 30 fps). Real-time mode writes every frame once at actual capture timing. The modes differ in how they handle incoming frames:
- Output video plays at exactly the specified FPS
- If camera is slower: duplicates last frame to fill gaps
- If camera is faster: drops frames to match target rate
- Best for: Fast acquisitions where smooth playback is desired
- Every frame from the camera is written exactly once
- Playback timing matches actual capture timing
- Best for: Recording at maximum camera speed while preserving every frame
- Compresses real time into shorter playback time
- Factor of 10× means 30 seconds of recording plays in 3 seconds
- Output FPS is still the target FPS (e.g., 30 fps)
- Best for: Long exposures (100ms+), time-lapses
Example — Time-lapse 10× with 30 fps output:
| Camera Speed | Real Time | Frames Captured | Video Duration | Frames Written |
|---|---|---|---|---|
| 1 fps (1000ms) | 30s | 30 | 3s | ~90 (duplicated) |
| 10 fps (100ms) | 30s | 300 | 3s | ~90 (some dropped) |
| 100 fps (10ms) | 30s | 3000 | 3s | ~90 (most dropped) |
Example — Time-lapse 100× with 30 fps output (6-hour experiment):
| Camera Speed | Real Time | Frames Captured | Video Duration | Frames Written |
|---|---|---|---|---|
| 0.1 fps (10s) | 360 min | 2,160 | 3.6 min | ~6,480 (duplicated) |
| 1 fps (1s) | 360 min | 21,600 | 3.6 min | ~6,480 (some dropped) |
| 10 fps (100ms) | 360 min | 216,000 | 3.6 min | ~6,480 (most dropped) |
Recommendation: For fast cameras (short exposures), use Constant FPS or Real-time mode instead of Time-lapse to avoid losing frames.
Files are named: {basename}_{width}x{height}_seg{NNN}.mp4
Example: experiment_2304x2304_seg001.mp4
- Segment numbers auto-increment to avoid overwrites
- New segment starts if resolution changes mid-session
- Each Live start/stop creates a new segment
See TESTING.md for comprehensive test checklist.
A BeanShell script is included for automated testing:
- Enable MP4Stream in the Processor Pipeline
- Configure output path in plugin settings
- Run via Tools → Script Panel → load
test_mp4stream.bsh
The script tests basic recording, fast/slow cameras, rapid start/stop, and objective changes.
Tested on Windows 11 with MM Studio 2.0.3 (nightly 20260116), MMCore 11.11.0, Java 11.0.27
Note: Testing has only been performed on Windows 11. macOS/Linux users may encounter platform-specific issues — please report them.
Demo Camera (512×512)
| Test | Mode | Exposure | Frames | Result |
|---|---|---|---|---|
| Basic recording | Constant 30fps | 33ms | 882 | ✓ |
| Fast camera | Constant 30fps | 10ms | 275 | ✓ Frame dropping |
| Slow camera | Constant 30fps | 500ms | 301 | ✓ Frame duplication |
| Real-time | VFR | 100ms | 99 | ✓ 1:1 capture |
| Time-lapse | 10x @30fps | 1000ms | 178 | ✓ Compression |
| Immediate finalization | Any | Any | 1 | ✓ Event-driven |
Real Microscope — Hamamatsu ORCA-Fusion C14440-20UP
Hardware: 2304×2304 resolution, pixel size 0.1091 µm
| Test | Mode | Frames | Result |
|---|---|---|---|
| Basic recording | Constant 30fps | 856 | ✓ |
| Fast camera | Constant 30fps | 249 | ✓ Frame dropping |
| Slow camera (500ms) | Constant 30fps | 271 | ✓ Frame duplication |
| Real-time (100ms) | VFR | 58 | ✓ 1:1 capture |
| Time-lapse | 10x @30fps | 179 | ✓ Compression |
| Overlay | Scale bar + timestamp | 9 | ✓ White/black text |
Real Microscope — Photometrics Prime 95B (MM Studio 2.0.3 nightly 20251006, MMCore 11.11.0)
Hardware: 1608×1608 resolution, Prior XY stage
| Test | Objective | Binning | Pixel Size | Scale Bar | Frames | Result |
|---|---|---|---|---|---|---|
| Recording + overlay | 10× | 1×1 | 1.12 µm | 200 µm | 115 | ✓ |
| Resolution change | 10× | 2×2 | 1.12 µm | 100 µm | 136 | ✓ |
| Objective change | 10× → 40× | 1×1 | 0.22 µm | 50 µm | 82 | ✓ |
| High magnification | 60× | 2×2 | 0.45 µm | 50 µm | 89 | ✓ |
| Binning change | 60× | 2×2 | 0.57 µm | 50 µm | 69 | ✓ |
| 40× no binning | 40× | 1×1 | 0.29 µm | 50 µm | 102 | ✓ |
The plugin logs to the Micro-Manager CoreLog (Help → View Core Log...).
Log Levels:
[IFO]— Important events: recording start/stop, finalization[dbg]— Debug details: FFmpeg command, overlay settings, scaling changes
Example log output:
[IFO,App] [MP4Stream] Starting FFmpeg: output_2304x2304_seg001.mp4 (2304x2304, constant @30.0 fps)
[dbg,App] [MP4Stream] Overlay settings: timestamp=true (color=white, bg=true, font=18px), scalebar=true
[IFO,App] [MP4Stream] Live mode stopped - finalizing MP4 immediately.
[IFO,App] [MP4Stream] FFmpeg finalized successfully (856 frames written).
To enable debug logging, use Micro-Manager's debug mode or check the CoreLog after recording.
- Ensure ffmpeg.exe is on system PATH, or
- Set explicit path in plugin settings
- Videos under 1 second may not play in all players
- Use VLC for best compatibility
- Verify with
ffprobethat file is valid
- Ensure plugin is enabled (checkbox checked)
- Verify output path is set and writable
- Check log for error messages
- Mode changes apply to the next recording, not current
- Stop and restart Live to use new settings
ffmpeg -f rawvideo -pix_fmt gray -s WxH -r FPS -i -
-an -c:v libx264 -preset veryfast -crf 18 -pix_fmt yuv420p output.mp4
MP4StreamProcessor— Frame processing and FFmpeg pipe managementMP4StreamConfigurator— Settings UI and persistenceMP4StreamFactory— Processor instantiationMP4StreamPlugin— Plugin registration
Code follows Micro-Manager Coding Style and Conventions.
- Subscribes to
LiveModeEventfor immediate finalization - Finalizes MP4 immediately when Live mode stops
- Watchdog thread provides backup timeout
Copyright (c) 2026 Jens Eriksson
Licensed under the BSD 3-Clause License. See LICENSE file.
Issues and pull requests welcome. Please include:
- Micro-Manager version
- Camera model
- Relevant log excerpts
- Steps to reproduce (see TESTING.md)

