Using N.I.N.A.? My RTSP Timelapse Control plugin starts and stops the capture with your imaging sequence, renders the video when it ends, and can caption the timelapse with session events such as autofocus runs and meridian flips.
RTSP Timelapse Capture
A Windows app that records timelapses from any RTSP or IP camera, with twilight-based overnight scheduling, one-click MP4 export and automatic delivery of each night’s video.
README View on GitHub
A professional Windows desktop application for capturing and creating timelapse videos from RTSP camera streams.
Complete end-to-end timelapse workflow: capture stills + export to video + manage it all from one GUI.
- RTSP stream capture (always TCP transport, for stability).
- Multi-threaded bufferless capture for accurate timestamps (±5 second precision).
- Proactive reconnection to prevent camera firmware timeouts (100% capture success rate).
- Outage-resilient: a camera dropout never ends the session — capture keeps retrying with escalating backoff (shown as an orange Reconnecting status) until the window ends.
- Smart scheduling that supports overnight windows (e.g., 20:00 → 08:00).
- Automatic interval capture from 1 to 3600 seconds.
- Automatic date-based folder structure for snapshots.
- Adjustable JPEG output quality (1–100%).
- Live preview with auto-scaling and JPEG compression control.
- Session statistics with uptime, success rate, and error tracking.
- One-click export from image folders to MP4.
- Six built-in presets plus unlimited custom presets.
- Full control over frame rate, CRF quality, resolution, and playback speed.
- Non-destructive—source images are never modified.
- Real-time progress, ETA, and output size estimates.
- Optional frame counter overlay.
- Session-event overlays — events reported during the night (autofocus,
meridian flip, filter changes…) burned in as captions at the moment they occurred, the
imaging target as a standing bottom-right label, and an optional
<video>.events.csvwith wall-clock time and video timecode per event. - Delete snapshots after creating video (optional) — removes exactly the frames that went into the video; manual exports ask for confirmation first.
- Long-term capture planning with calendar-based date selection.
- Twilight calculations for automatic darkness detection (civil, nautical, astronomical).
- Manual time mode as alternative to twilight-based scheduling.
- Two-month calendar view showing captured dates, scheduled dates, and today.
- Auto video creation after each night's capture session completes — session-aware: a night that crosses the folder rollover hour renders whole, and only the session's frames.
- Pairs with Delete snapshots after creating video (on the Video Export tab since v3.6) to free disk space once the night's video exists.
- Color-coded scheduler log for monitoring automated capture activity.
- Start/end time offsets to fine-tune the darkness window.
- Discord webhook upload automatically posts each night's generated timelapse to a Discord channel.
- MQTT video delivery as an alternative: publish the finished video to an MQTT broker and let another machine relay it — for rigs with no internet, or a custom pipeline.
- Upload size handling with a configurable max size, optional auto quality reduction (re-encodes to fit), and an export-resolution selector.
- Delete video after successful upload/delivery to remove the exported MP4 once it has been sent.
- Minimize to tray — start in the tray and/or send the window there with the minimize button (headless or always-running setups).
- Start automatically when Windows starts (per-user, no admin) for unattended rigs.
- Opt-in localhost HTTP API to start/stop capture and create videos from external software (e.g. N.I.N.A.).
- Scheduled timelapse — a single call starts capture and auto-stops (and optionally renders the video) at a set time.
- Local-only, no auth token — bound to
127.0.0.1; mutually exclusive with automatic scheduling. - Session events — external software can record what happened during the night (autofocus, meridian flip, filter change); optionally burned into the timelapse as captions and/or exported as a CSV alongside the video.
- Ready-to-use NINA scripts in
examples/(seeexamples/README.md).
- Four-tab interface: Capture, Video Export, Scheduling, and Integrations.
- Comprehensive tooltip system with 85 hover tooltips explaining every control.
- Keyboard shortcuts for common actions.
- Auto-save configuration when switching tabs and on app close.
- Thread-safe capture engine keeps the UI responsive.
- Color-coded activity log with timestamps.
- Cross-platform Python source (Windows-focused release builds).
A live overnight session: Camera, Capture Window and Capture Settings groups (including the Folder Rollover Hour), connection status, real-time all-sky preview, session statistics, and the activity log.
Video export: input selection, video settings with live duration/size estimates, output options (temp folder, delete snapshots after creating the video), presets, and the Session Events group — overlay events as captions and write the events CSV.
Astronomical scheduling: twilight or manual time modes with tonight's computed window, the two-month capture calendar (captured / scheduled / past), auto video creation, and the scheduler control/log.
Integrations: Video Delivery with the delivery method choice — Discord webhook or MQTT broker — plus size limit and auto quality reduction, application options (minimize to tray, start with Windows), and the Remote Control API for NINA and other external software.
-
Clone the repository
git clone https://github.com/HiranD/RTSP-Timelapse-Capture.git cd RTSP-Timelapse-Capture -
Install dependencies
# Create virtual environment python -m venv .venv # Activate (Windows) .venvScriptsactivate # Activate (Linux/Mac) source .venv/bin/activate # Install packages pip install -r requirements.txt
-
Install FFmpeg (required for video export)
- Download from ffmpeg.org.
- Add
ffmpeg.exeto your PATH or place it in abin/folder beside the app. - Verify with
ffmpeg -version.
-
Launch the application
python run_gui.py
Note: The system tray startup feature requires the
pystraydependency, which is installed automatically bypip install -r requirements.txt.
Hover your mouse over any button, input field, or checkbox for helpful tooltips that explain:
- What the control does
- Expected values and formats
- Recommended settings
- Keyboard shortcuts
- Common examples
Example tooltips:
- IP Address: "IP address of your RTSP camera on the local network. Example: 192.168.0.101"
- Proactive Reconnect: "Automatically reconnect every N seconds to prevent timeouts. Recommended: 420s for Annke cameras"
- Frame Rate: "Video playback speed in fps. 24 = cinematic, 30 = smooth, 60 = ultra-smooth"
-
Configure Camera
Camera Settings: IP Address: 192.168.0.101 Username: admin Password: ******** Stream Path: /stream1 (must match your camera - see Common RTSP Paths) -
Set Schedule
Schedule: Start Time: 20:00 (8:00 PM) End Time: 08:00 (8:00 AM) Interval: 30 (seconds) -
Start Capture
- Click Test Connection to verify credentials and stream.
- Click Start Capture to begin the timelapse session.
- Watch the live preview, session statistics, and activity log.
-
Output Structure
snapshots/ 20251015/ 20251015-224000.jpg 20251015-224020.jpg ... 20251016/ 20251016-070000.jpg ...
- Switch to the Video Export tab.
- Click Quick Select and choose the desired date folder.
- Pick a preset:
- Standard 24fps – Balanced quality.
- High Quality 30fps – Lower compression, smoother output.
- Fast Motion 60fps – Every 4th frame for ultra-smooth motion.
- Web Optimized – Ready for YouTube/social uploads.
- Storage Saver – Small files for archival use.
- Ultra Speed 16x – Extreme speed-ups for rapid reviews.
- Click Create Video. The video opens automatically if you enable that option.
- Frame Rate: 1–120 fps (24 for cinematic, 30 for smooth, 60 for ultra-smooth).
- Quality (CRF): 18 = visually lossless, 20 = default, 23+ = smaller files.
- Speed Multiplier: Skip frames to speed up (2×, 4×, 8×, 16×, 32×).
- Resolution: Keep original size or scale to 4K / 1080p / 720p / 480p / 360p.
- Overlay: Optional frame counter overlay for QA workflows. An app setting (not part of the preset) — it applies to every render, including scheduled and remote-API videos, until unticked.
Example outputs for 1,234 images captured over 6 hours:
Standard Export:
24 fps, 1x speed → 51 s video, ~12 MB
Fast Motion:
60 fps, 4x speed → 5 s video, ~3 MB
Ultra Speed:
30 fps, 16x speed → 2.5 s video, ~1 MB
The Scheduling tab enables automated long-term capture planning based on astronomical twilight times or manual schedules.
Before using the Scheduling tab, configure the Capture and Video Export tabs:
-
Capture Tab - Set up these settings:
- RTSP URL for your camera
- Capture interval (recommended: 30 seconds)
- Output folder for snapshots
- JPEG quality
- Settings are auto-saved when you switch tabs
-
Video Export Tab - Set up these settings:
- Select a video preset (or create a custom one)
- Set your preferred output location
- These settings are used by auto video creation
-
Scheduling Tab - Now configure automated scheduling:
- The scheduler uses Capture tab settings for image capture
- Auto video creation uses Video Export tab settings
Choose between two scheduling modes:
Twilight-based Mode (Default):
- Set your location (latitude/longitude)
- Select twilight type: Civil (-6°), Nautical (-12°), or Astronomical (-18°)
- The app calculates darkness windows automatically
- Optionally add start/end offsets to fine-tune the window
Manual Mode:
- Set fixed start and end times (HH:MM format)
- Supports overnight spans (e.g., 22:00 - 06:00)
- No location settings required
-
Configure Time Settings
Twilight-based: Latitude: 42.0 (Northern Hemisphere) Longitude: -7.0 Twilight: Astronomical (true darkness) Offsets: Start +0 min, End +0 min OR Manual: Start Time: 22:00 End Time: 06:00 -
Select Dates on Calendar
- Click dates to toggle selection (blue = scheduled)
- Green dates = past dates captured by the scheduler
- Plum dates = past dates captured manually or via the remote API (NINA plugin)
- Gray dates = past dates without captures
- Hover a captured date to see its sessions (source, times, frame count, video)
- Red border = today
- Use Select All / Clear All buttons for bulk operations
- Navigate months with < and > buttons
-
Configure Auto Video (Optional)
[✓] Create video after each night's session- Enabling Create video after each night's session is also what unlocks the optional video delivery (Discord webhook or MQTT broker) — configure it on the Integrations tab (see Using the Integrations Tab).
- To free disk space afterwards, tick Delete snapshots after creating video on the Video Export tab (moved there in v3.6; applies to every video and deletes only the frames that went into it). Note: Uses preset and output folder from Video Export tab
-
Enable Scheduler
- Check "Enable automatic scheduling"
- The scheduler monitors twilight/manual times
- Capture starts automatically when darkness begins
- Capture stops automatically when darkness ends
- Videos are created automatically if enabled
-
Startup & Tray Options
- Minimize to tray and Start automatically when Windows starts now live on the Integrations tab (see Using the Integrations Tab).
- Restore a tray-minimized window by double-clicking the tray icon or choosing
Open.
- Scheduler: Inactive - Scheduler is disabled
- Scheduler: Active (waiting) - Waiting for darkness window
- Scheduler: Capturing - Currently capturing frames
Monitor scheduler activity in the color-coded log:
- INFO (black): Normal operations
- WARNING (orange): Non-critical issues
- ERROR (red): Problems requiring attention
Optional, set-once integrations and unattended-operation options live on their own tab.
Automatically send each night's generated timelapse somewhere — a Discord channel, or an MQTT broker for another machine to pick up.
Requires Create video after each night's session on the Scheduling tab — delivery runs as part of that auto-video step (or when
POST /video/createrenders one). The Video Export tab's own button never sends anything.
Delivery method picks between the two: the dropdown is always visible, only the selected method's fields are shown beneath it, and the method shown is always the method used. The settings below the two field groups apply to whichever is selected.
Every setting on this tab — including all the MQTT ones — is written to config/app_config.json the moment you change it: when a field loses focus, when you press Enter, or when you tick a box. Closing the app flushes the tab as well, so a value typed just before quitting isn't lost either. There is no Save button.
| Setting | Description |
|---|---|
| Delivery method | Discord webhook (upload straight to Discord — needs internet) or MQTT broker (publish for an external consumer to relay). |
| Max upload size (MB) | Largest file to send (default 8). If the video is bigger, delivery is skipped — unless Auto reduce quality is on. Discord's webhook limit is ~10 MB; a broker's is its own max message size. |
| Auto reduce quality if too large | Re-encode an oversized video to fit: quality steps down through CRF 20 → 45 at the selected export resolution, stopping at the first encode under the size limit. If even the lowest quality can't fit, delivery is skipped and the original is kept locally. |
| Export resolution | Frame size used only when auto-reduce re-encodes (original, 720p, 480p, 360p). Smaller resolutions reach the size limit with less visible quality loss than compression alone. |
| Delete video after successful upload/delivery | Removes the exported MP4 once it has been sent. Use with caution — deletion is permanent. |
| Keep the re-encoded copy that was sent | Keeps the smaller re-encoded video (date-stamped, inside .discord_encode/) instead of discarding it. |
| Setting | Description |
|---|---|
| Discord Webhook URL | Webhook to upload the generated video to. Leave blank to disable uploads. |
For an observatory PC with no internet: instead of uploading, the app publishes the finished video to an MQTT broker, and a consumer on an internet-connected machine relays it onward. It's equally a generic hook — anything that can subscribe can act on the video.
| Setting | Description |
|---|---|
| Broker host / Port | Broker address and TCP port (1883 plain, 8883 typically TLS). |
| Username / Password | Broker credentials; leave the username blank for an anonymous broker. Stored in plain text in config/app_config.json, like the camera password. |
| Base topic | Topic prefix the video is published under (default rtsp-timelapse). No wildcards. |
| QoS | 1 (recommended) waits for the broker to acknowledge, so the app can report real success. 0 is fire-and-forget. |
| Use TLS | Encrypt the broker connection using the system certificate store. |
Topic contract — what a consumer subscribes to:
| Topic | Payload | Notes |
|---|---|---|
<base>/metadata |
JSON {"message", "filename", "date", "size_bytes"} |
Published first, at the configured QoS, never retained. filename is always the render's own timelapse-YYYY-MM-DD.<ext>, even when an oversized video was re-encoded to fit |
<base>/video |
Raw MP4/WebM bytes | Published second; consumers must tolerate metadata being absent |
Nothing is retained, so a consumer that connects later picks up the next video rather than replaying the last one. What it does with it — post it somewhere, archive it, trigger a pipeline — is up to you.
| Setting | Description |
|---|---|
| Minimize to tray | Starts the app minimized in the system tray, and hides the window to the tray when you minimize it; restore from the tray icon (Open). |
| Start automatically when Windows starts | Registers the app to launch at logon (per-user, no admin). Pair with persistent scheduling for an unattended rig. Note: a GUI needs a desktop session, so enable Windows auto-login on a headless machine. |
Delivery and tray settings are saved to config/app_config.json; "Start automatically when Windows starts" is stored in the Windows registry (per-user Run key), not in the config file.
Trigger capture from external software (e.g. N.I.N.A.) over a small, opt-in HTTP API that runs inside the app.
- Enable it on the Integrations tab → Remote Control (off by default).
- Local only: the server binds to
127.0.0.1and rejects non-loopback requests — there is no auth token, so only programs on this PC can reach it. - Mutually exclusive with automatic scheduling: turning one on greys out the other.
Using it with NINA:
- Example scripts (available now) — ready-to-use
.batfiles and a PowerShell variant (no install; they usecurl), wired into NINA via the External Script instruction. The full endpoint reference and step-by-step setup live inexamples/README.md, shipped in theexamples/folder next to the app. - NINA plugin — RTSP Timelapse Control, a native plugin that drives this API from inside NINA (start/stop, a scheduled timelapse that auto-stops and renders the video, and — from plugin 1.5.0 — a Report Timelapse Events trigger that sends autofocus runs, filter changes, meridian flips, target changes and guiding loss automatically for captioning). Install from github.com/HiranD/nina-rtsp-timelapse.
Session events:
POST /events records what happened during the night — Autofocus Complete, Meridian Flip, Filter: L-Extreme — timestamped against the running capture. Tick Overlay session events on the Video Export tab to have them appear as captions at the moment they occurred, turning the timelapse into a diagnostic record of the session as well as a visual one. Write events CSV (same tab, independent) saves them alongside the video with wall-clock time and video timecode. Full reference in examples/README.md.
| Setting | Description | Example |
|---|---|---|
| IP Address | Camera IP on your network | 192.168.0.101 |
| Username | RTSP authentication user | admin |
| Password | RTSP authentication pass | YourPassword123 |
| Stream Path | Camera-specific RTSP path | /stream1 |
The stream path is appended to the RTSP URL exactly as entered, including any query string. Leave it
blank to fall back to /stream1. Connections always use TCP transport.
Common RTSP Paths
- Hikvision:
/Streaming/Channels/101 - Dahua:
/cam/realmonitor?channel=1&subtype=0 - Ubiquiti/UniFi:
/s0 - Generic:
/stream1,/live,/h264
| Setting | Description | Example |
|---|---|---|
| Start Time | Capture start (24-hour HH:MM) | 22:40 |
| End Time | Capture end (24-hour HH:MM) | 07:00 |
| Interval | Seconds between captures | 20 |
| Rollover | Hour after midnight to switch day (Folder Rollover Hour on the Capture tab) | 12 |
Overnight windows (start later than end) are handled automatically.
| Setting | Description | Default |
|---|---|---|
| Output Folder | Base folder for snapshots | snapshots |
| Interval (seconds) | Time between captures | 30 |
| JPEG Quality | Saved image quality (higher = better quality but larger files) | 95 |
| Buffer Frames | Frames to buffer in OpenCV | 1 |
| Max Retries | Quick connection attempts before escalating backoff takes over (the session is never given up) | 3 |
| Proactive Reconnect (s) | Reconnect interval to prevent camera timeout | 300 (5 min) |
v2.3.0 Defaults: Optimized for maximum timestamp accuracy and reliability. These ready to use values achieve ±5 second precision with 100% capture success rate.
Stored in the astro_schedule and ui sections of config/app_config.json, except where noted.
| Setting | Config key | Default | Notes |
|---|---|---|---|
| Delivery method | astro_schedule.delivery_method |
"discord" |
discord (webhook) / mqtt (broker) |
| Discord Webhook URL | astro_schedule.discord_webhook_url |
"" |
Blank disables Discord upload |
| MQTT broker host | astro_schedule.mqtt_broker_host |
"127.0.0.1" |
Only used when the method is mqtt |
| MQTT broker port | astro_schedule.mqtt_broker_port |
1883 |
8883 is the usual TLS port |
| MQTT username / password | astro_schedule.mqtt_username / mqtt_password |
"" |
Blank username = anonymous; password is plain text |
| MQTT base topic | astro_schedule.mqtt_base_topic |
"rtsp-timelapse" |
Publishes <base>/metadata then <base>/video |
| MQTT QoS | astro_schedule.mqtt_qos |
1 |
0 or 1; 1 waits for the broker's ack |
| MQTT TLS | astro_schedule.mqtt_use_tls |
false |
Uses the system certificate store |
| Max upload size (MB) | astro_schedule.discord_max_video_size_mb |
8 |
Skip delivery if exceeded (unless auto-reduce) |
| Auto reduce quality | astro_schedule.discord_auto_quality_reduction |
false |
Re-encode CRF 20→45 to fit |
| Export resolution | astro_schedule.discord_export_resolution |
"original" |
original / 720p / 480p / 360p |
| Delete after upload/delivery | astro_schedule.delete_video_after_discord_upload |
false |
Deletes the original MP4 after a successful delivery |
| Keep re-encoded copy | astro_schedule.discord_keep_reencoded |
false |
Keep the sent re-encode in .discord_encode/ |
| Minimize to tray | ui.minimize_to_tray |
false |
|
| Start with Windows | (Windows registry, per-user Run key) | off | Not stored in the JSON config |
- Verify credentials: Use VLC or
ffplayto confirm IP, username, password, and stream path before configuring the app. - TCP always: Many consumer IP cameras are unreliable over UDP, so every connection uses TCP transport - there is nothing to configure.
- Mind network latency: For remote cameras, increase
buffer_frames(e.g., to 6-8) if you frequently see reconnect messages. - Deal with overnight lighting: Configure the camera's own exposure or IR settings; the app captures whatever the RTSP feed delivers.
- Multiple cameras: Copy
config/app_config_example.jsonper device and load them through the GUI to swap configurations quickly. - Security: Store configs in a protected location if the RTSP password is sensitive; the app saves the password in plain text JSON.
- Prevent camera timeouts: Enable Proactive Reconnect to maintain 100% capture success rate. Most IP cameras have firmware timeouts (typically 5-10 minutes). Set the reconnect interval to ~40 seconds before your camera's timeout for uninterrupted captures.
Based on extensive testing with Annke I81EM IP cameras, two configurations are recommended depending on your needs:
Camera Settings (Web Interface) - Same for Both Configurations:
- Frame Rate:
10 FPS(provides fresh frames without overwhelming buffer) - I Frame Interval:
4(keyframe every 0.4 seconds for accurate timestamps) - Max Bitrate:
3072 Kbpsor lower (stable streaming over network)
Best for: Most timelapse applications where timestamp precision matters
Application Settings:
- Capture Interval:
30 seconds - Buffer Frames:
1(minimal buffer for freshest frames) - Proactive Reconnect:
300 seconds(5 minutes - before 460s camera timeout)
Performance Results:
- 100% capture success rate
- Timestamp accuracy: ±5 seconds (stable throughout session) - 96% improvement over baseline
- Extremely stable and predictable behavior
- No drift accumulation over time
- Lower system overhead
- 120 frames per hour
| Metric | Baseline (Pre-v2.3.0) | v2.3.0 Multi-threaded | Improvement |
|---|---|---|---|
| Timestamp Accuracy (initial) | +35 seconds | +19 seconds | 46% better |
| Timestamp Accuracy (steady) | -4m 50s (-290s) | ±5 seconds | 96% better |
| Drift stability | Accumulates over time | Stable (no accumulation) | Major improvement |
| Success rate | 100% | 100% | Maintained |
| Frames per hour | 120 frames | 120 frames | Same |
| System overhead | Moderate | Low | Reduced |
Recommendation: Version 2.3.0's multi-threaded bufferless capture achieves exceptional ±5 second timestamp accuracy with zero drift accumulation, making it ready for all timelapse applications requiring timestamp precision.
Note: Other Annke models may have different timeout intervals. Test your camera's behavior and adjust the proactive reconnect interval to ~40 seconds before the observed timeout.
| Shortcut | Action |
|---|---|
Ctrl+T |
Test camera connection |
Space |
Start capture |
Esc |
Stop capture |
Note: Configuration is auto-saved when switching tabs and before closing the app.
| Shortcut | Action |
|---|---|
Ctrl+E |
Focus export tab |
Ctrl+B |
Browse for folder |
Enter |
Begin export |
Esc |
Cancel export |
tests/test_backend.pyexercises configuration management and capture logic with interactive prompts.tests/test_backend_auto.pyruns the same checks without user input (connection tests will fail harmlessly if no camera is reachable).tests/test_video_export.pyvalidates the export pipeline; provide a populatedsnapshots/YYYYMMDDfolder before running it.
build_release.batbuilds a PyInstaller executable and packages a release folder (optionally bundling FFmpeg).bundle_ffmpeg.batcopies FFmpeg/FFprobe into the release bundle.RTSP_Timelapse.specdefines the PyInstaller build (GUI-only executable with bundled resources).
Cannot connect to camera:
- Verify camera IP with
ping 192.168.0.101. - Test the stream URL in VLC:
rtsp://user:pass@ip/stream1. If VLC works and the app does not, copy VLC's path (Media -> Open Network Stream) into Stream Path verbatim - the Activity Log prints the exact URL the app dials (with the password masked), so compare the two. - Check port 554 (RTSP) is not blocked by firewall.
Connection drops frequently:
- Enable Proactive Reconnect to reconnect before camera timeout (recommended: 420 seconds for Annke cameras).
- Check network stability between PC and camera.
- Increase capture interval to reduce request frequency.
- Check camera settings for session timeout/keepalive options.
- If drops occur at exact intervals (e.g., every 460 seconds), this is a camera firmware timeout - use proactive reconnect set to ~40 seconds before the timeout.
FFmpeg not found:
- Download FFmpeg from ffmpeg.org.
- Add to system PATH or place in
bin/folder next to executable. - Ensure all FFmpeg DLL files are present (~150 MB total).
- Click Test FFmpeg button to verify installation.
Export is slow:
- Lower resolution (720p or 480p instead of original).
- Increase CRF quality value (23-28 for smaller files).
- Use speed multiplier (2×, 4×) to skip frames.
- Close other applications to free system resources.
Video won't play:
- Ensure using MP4 format (most compatible).
- Try opening in VLC media player.
- Check FFmpeg log for encoding errors.
GUI is slow or laggy:
- Disable live preview (uncheck "Enable Preview").
- Lower JPEG quality (70-80 instead of 90).
- Increase capture interval (30s+ instead of 20s).
- Close background applications.
Disk filling up:
- Monitor available disk space regularly.
- Lower JPEG quality to reduce file sizes.
- Delete old snapshots after exporting to video.
- Use "Storage Saver" preset for smaller video files.
Disk Space Calculator:
At quality 90, each 1280×720 frame ≈ 400 KB
Formula: (3600 / interval) × hours × 0.4 MB
Example: 20s interval for 8 hours
= (3600/20) × 8 × 0.4
= 576 MB for images
+ ~50 MB for final video
= ~625 MB total
For built executable (.exe):
- Windows 10/11 (64-bit)
- 4 GB RAM
- 2 GB free disk space (plus additional storage for captures and videos)
- Network connection to RTSP camera
- FFmpeg (for video export)
For running from source:
- Windows 10/11, Linux, or macOS
- Python 3.9 or higher
- Dependencies from requirements.txt
- FFmpeg (for video export)
RTSP/
├── run_gui.py # Application launcher
├── requirements.txt # Python dependencies
├── README.md # This file
├── LICENSE # MIT License
├── .gitignore # Git ignore rules
│
├── src/ # Source code
│ ├── gui_app.py # Main GUI (tabbed interface)
│ ├── capture_engine.py # RTSP capture logic
│ ├── config_manager.py # Configuration management
│ ├── video_export_panel.py # Video export GUI
│ ├── video_export_controller.py # Video export logic
│ ├── ffmpeg_wrapper.py # FFmpeg integration
│ ├── preset_manager.py # Preset management
│ ├── tooltip.py # Tooltip helper class
│ ├── video_export_tooltips.py # Video export tooltip messages
│ ├── capture_tooltips.py # Capture tab tooltip messages
│ ├── scheduling_panel.py # Astronomical scheduling GUI (NEW v3.0)
│ ├── scheduling_tooltips.py # Scheduling tab tooltip messages (NEW v3.0)
│ ├── calendar_widget.py # Two-month calendar widget (NEW v3.0)
│ ├── twilight_calculator.py # Twilight time calculations (NEW v3.0)
│ ├── astro_scheduler.py # Automated scheduling engine (NEW v3.0)
│ ├── integrations_panel.py # Integrations tab GUI (NEW v3.3)
│ └── startup_manager.py # Windows start-at-logon registration (NEW v3.3)
│
├── assets/ # Application icon (NEW v3.3)
│ ├── icon.svg # Master vector source
│ ├── icon.ico # Multi-size Windows icon (generated)
│ └── icon.png # 256px PNG (generated)
│
├── scripts/ # Build/utility scripts (NEW v3.3)
│ └── build_icon.py # Regenerate icon.ico/.png from icon.svg
│
├── tests/ # Test files
│ ├── test_backend.py # Interactive backend tests
│ ├── test_backend_auto.py # Automated tests
│ └── test_video_export.py # Video export tests
│
├── config/ # Configuration files
│ └── app_config_example.json # Template
│
├── user_data/ # User-generated data (gitignored)
│ ├── capture_history.json # Session history for calendar
│ └── video_export_presets.json # Custom video presets
│
└── snapshots/ # Captured images (gitignored)
└── YYYYMMDD/ # Date-organized folders
└── YYYYMMDD-HHMMSS.jpg # Timestamped images
Q: Can I use multiple cameras? A: Currently supports one camera per instance. Run multiple instances for multiple cameras with separate config folders.
Q: Does it work on Linux/macOS? A: Yes! The Python source is cross-platform. Install dependencies and FFmpeg for your OS. Windows releases include pre-built executables.
Q: Can I run it headless (no GUI)?
A: Not currently. The legacy CLI version (src/main.py) exists but isn't maintained. The GUI is recommended.
Q: What RTSP URL format do I use?
A: Depends on your camera brand. See Camera Settings for common paths. Test with VLC first: rtsp://user:pass@ip/path.
Q: My camera requires a specific port. How do I set it?
A: Include port in IP address field: 192.168.0.101:8554
Q: What's the best preset for YouTube? A: Use "Web Optimized" (30fps, 720p) or "High Quality 30fps" (original resolution).
Q: How do I make a very fast timelapse? A: Use "Ultra Speed 16×" preset or set Speed Multiplier to 8×/16×/32×.
Q: Can I add music to the video? A: Not built-in. Use video editing software (like DaVinci Resolve, Premiere, or OpenShot) to add audio after export.
Q: Why are my original files safe?
A: The export works on temporary numbered copies staged outside your output folder (under %TEMP%RTSP_Timelapse by default). Your originals are never renamed or modified, and the temp folder is automatically deleted after export.
Q: What is Proactive Reconnect and should I use it? A: Proactive Reconnect automatically disconnects and reconnects to the camera at a scheduled interval before the camera's firmware timeout occurs. This prevents failed captures during timeout periods. Enable it if you notice connection drops at regular intervals (e.g., every 5-10 minutes). Set the value to ~40 seconds before your camera's timeout. For Annke I81EM cameras, use 420 seconds (7 minutes).
Q: How do I know what reconnect interval to use? A: Monitor your logs for "Connection lost" messages. If they occur at regular intervals (e.g., exactly every 460 seconds), that's your camera's timeout. Set Proactive Reconnect to that value minus 40 seconds. Example: 460s timeout → use 420s reconnect interval.
Q: Why are my snapshot timestamps off by 30 seconds? A: This is normal! The timestamp in the filename is when the capture was initiated. The timestamp embedded by the camera in the image is when the frame was encoded. With optimal settings (10 FPS, I-frame 4), this difference should be 5-33 seconds with Configuration A (30s/300s) or 33s-4min with Configuration B (20s/420s). This is acceptable for timelapse purposes.
Q: What capture interval should I use?
A: 30-second intervals are optimal for balancing timestamp accuracy, frame rate, and system performance. Based on extensive testing documented in docs/TIMESTAMP_ACCURACY_ANALYSIS.md:
Experimental Results (60s vs 30s intervals):
- Post-reconnect accuracy: 30s achieves +23s drift vs 60s achieves -7s drift
- Sign flip significance: Positive drift (+23s) means fresher frames vs negative drift (-7s) means stale frames
- Frame density: 30s provides 120 frames/hour vs 60s provides only 60 frames/hour
- Staleness accumulation: 30s accumulates drift at half the rate of 60s intervals
- Reliability: Both achieve 100% capture success rate
Why 30s is better: The buffer staleness accumulates proportionally to the capture interval. At 30s intervals, frames are captured twice as often, so the buffer never gets as stale as with 60s intervals. The positive post-reconnect drift (+23s) indicates the captured frame is only 23 seconds old, versus 60s intervals where negative drift (-7s) indicates frames from the bottom of a stale buffer.
When to adjust:
- Faster scenes (clouds, traffic): Use 20s for 180 frames/hour (more storage needed)
- Slower scenes (construction, plants): 30s is perfect for 120 frames/hour
- Very slow scenes (astronomy, shadows): 60s for 60 frames/hour is acceptable
v2.3.0 ships with 30s as the default - optimized for the best balance of accuracy and performance.
Q: What does timestamp accuracy mean for my timelapse? A: Timestamp accuracy is the difference between the filename timestamp (when your PC saved the file) and the camera-embedded timestamp (when the camera actually encoded that frame).
Why it matters:
- Visual continuity: Frames should represent actual temporal progression, not stale buffered frames
- Scientific applications: Astronomical/weather timelapses need accurate time correlation
- Quality indicator: Large drift (minutes) indicates buffering issues in your setup
v2.3.0 Performance: With the new multi-threaded bufferless capture, you get:
- ±5 seconds steady-state accuracy (vs baseline -4m 50s, that's 96% improvement)
- Zero drift accumulation across the entire session
- Stable accuracy even after multiple reconnection cycles
For timelapse playback: Even with older versions showing 1-2 minute drift, this is visually imperceptible when played at 24-30 fps. Your timelapse will look smooth and continuous.
For scientific/critical applications: v2.3.0's ±5 second precision is suitable for:
- Weather pattern analysis
- Astronomical observations
- Construction documentation with precise time-stamping
- Any application requiring sub-minute accuracy
The days of worrying about timestamp drift are over with v2.3.0!
Q: How do I learn what each setting does? A: Simply hover your mouse over any control (button, input field, checkbox, etc.) and wait ~500ms. A helpful tooltip will appear explaining what it does, expected values, and recommendations. The app has 37 tooltips covering every important control.
Q: Can I disable tooltips? A: Tooltips are built into the interface and cannot be disabled. However, they only appear when you hover for 500ms, so they won't interfere with normal usage. They disappear instantly when you move your mouse away.
Session Events + MQTT Delivery
- New: Session events (#15) — external programs (e.g. the RTSP Timelapse Control NINA plugin 1.5.0) can
POST /eventsto record what happened during the night. Overlay session events (Video Export tab) burns them into the video as captions at the moment they occurred; the imaging target is drawn as a standing bottom-right label; Write events CSV saves a<video>.events.csvwith wall-clock time and video timecode. - New: MQTT delivery — the Integrations tab's Discord Upload section is now Video Delivery: send the finished video to a Discord webhook (as before) or publish it to an MQTT broker (
<base>/metadatathen<base>/video), so a capture PC with no internet can hand it to a local broker. - New: Folder Rollover Hour is editable in the app (Capture tab).
- Changed: renders driven by a session start are session-aware — they cover every date folder from the session's start onward, so a night crossing the rollover hour renders whole, and the nightly auto-video renders exactly the session.
- Changed: Delete snapshots after creating video moved to the Video Export tab, applies to every video (manual exports confirm first), and deletes only the frames that went into the video.
- Changed: every render names its video
timelapse-YYYY-MM-DD.<ext>, and a delivered video keeps that name even when re-encoded to fit the size limit. - Fixed: a camera outage no longer ends the session — capture retries with escalating backoff (orange Reconnecting status) until stopped or the window ends.
- Fixed: starting the scheduler mid-window (or after midnight) captures the remainder of the window instead of instantly completing; scheduled end times can never land in the past.
- Fixed: a UTF-8 BOM in
app_config.jsonno longer silently resets every setting; an Integrations field typed just before closing the app is no longer lost.
Start Now + Stream Path fix
- New: Start Now on the Capture tab. The Capture Window offers a Start choice — At time (wait until the Start Time) or Now (begin immediately and still auto-stop at the End Time). No more setting a Start Time in the past just to start right away. Session-only, defaults to At time.
- New: the Capture tab's single "Camera Configuration" box is reorganized into three groups — Camera, Capture Window, and Capture Settings — so the schedule fields no longer sit under a "camera" heading.
- Fixed: the Stream Path setting was never used — the app always requested
/stream1, so Hikvision (/Streaming/Channels/101), Dahua (/cam/realmonitor?channel=1&subtype=0) and UniFi (/s0) cameras could not connect no matter what was entered, in both Test Connection and Start Capture (#16). The configured path is now used exactly as typed, query string included; a blank field falls back to/stream1. - Fixed: the URL is no longer mangled by a bogus
?tcpsuffix, which turned a Dahua path into a doubled query string. - Fixed: the Activity Log now shows the stream URL being opened (password masked) for both Test Connection and Start Capture, so a wrong path is visible instead of silent.
- Fixed: a config file containing settings this version no longer has is no longer rejected outright — previously one unknown key failed the whole load and silently reset every setting to defaults.
- Removed: the Force TCP checkbox. It never switched transport — every connection already used TCP — so behaviour is unchanged; existing configs load fine and the stale key is dropped automatically.
Remote Control / External API for NINA & other tools
- New: Opt-in, localhost-only Remote Control HTTP API so external software (e.g. N.I.N.A.) can drive capture — enable it on the Integrations tab → Remote Control. Bound to
127.0.0.1with no auth token; mutually exclusive with automatic scheduling. - New: Endpoints —
GET /health,GET /status,POST /capture/start,POST /capture/stop,POST /capture/schedule,POST /video/create. - New:
/capture/schedulestarts capture if needed and arms an app-owned timer that auto-stops at a set time (optionally rendering the video), so the stop fires regardless of the external sequence. - New:
/video/createtriggers video creation for the newest or a given session, with an optionalsincefilter so one session renders cleanly when several share a date folder. - New:
/statusexposessession_start_timeso a client can render exactly the current/most-recent session (read it, pass it back assince). - New: Ready-to-use NINA example scripts (
.bat+ a PowerShell variant) bundled underexamples/(seeexamples/README.md).
Integrations: Discord Upload, Tray & Custom Icon
- New: Integrations tab consolidating optional, set-once integrations and unattended-operation options (Discord upload + application/startup options).
- New: Discord webhook upload — automatically posts the generated timelapse video to a Discord channel after each night's session. Includes a configurable max upload size, optional auto quality reduction (re-encodes to fit the limit), and an export-resolution selector.
- New: "Delete video after successful Discord upload" option to remove the exported MP4 once it has been posted.
- New: "Keep the re-encoded copy sent to Discord" option — keep the smaller uploaded video (date-stamped, inside the
.discord_encodefolder) instead of deleting it. - New: Minimize to tray option — sends the window to the system tray instead of the taskbar; the app can start minimized in the tray and the minimize button also hides it there (restore from the tray icon).
- New: Custom application icon (
assets/icon.svg) for the window, taskbar, tray, and executable, plus a build script (scripts/build_icon.py) to regenerateicon.ico/icon.pngfrom the SVG. - New: Hover tooltips on every Integrations control (44 tooltips total across the app).
- Changed: "Start automatically when Windows starts" (added in v3.2.0) moved from the Scheduling tab to the Integrations tab.
Bug Fix Release
- Fixed: The scheduler status label could get stuck on "Capturing" after a scheduled session ended. It now always reflects the scheduler's real state — Capturing / Active (waiting) / Inactive — via a corrected stop sequence plus a self-healing periodic refresh.
Unattended Startup
- New: "Start automatically when Windows starts" toggle on the Scheduling tab. Registers the app to launch at user logon (per-user Windows startup, no admin). Paired with persistent automatic scheduling, the rig resumes capture on its own after a reboot — boot → login → app launches → scheduler re-arms.
- Note: a GUI app needs a desktop session, so enable Windows auto-login on a headless machine.
Persistent Scheduling
- New: "Enable automatic scheduling" now persists across restarts and re-arms the scheduler on launch — ideal for unattended/headless rigs (closes #3)
- Improved: Scheduler now checks every 15 seconds instead of 60, so it reacts faster to calendar changes and twilight/manual window boundaries
- Fixed: Clearing the calendar while a capture is running now stops the session cleanly (and runs post-processing) instead of orphaning it
- Fixed: If a startup restore fails (e.g. invalid location), the disabled state is now saved so it doesn't retry the same failing restore every launch
Bug Fix Release
- Fixed: Scheduler no longer starts capture on unscheduled dates
- Bug: If Dec 31 was scheduled but Jan 1 was not, scheduler would incorrectly start on Jan 1
- Fix: Only continue overnight sessions if capture is already active
Major Release: Astronomical Scheduling
New third tab for automated long-term capture planning based on twilight times or manual schedules.
New Features:
- Scheduling Tab: Complete astronomical scheduling interface
- Twilight Calculations: Automatic darkness window detection (civil/nautical/astronomical)
- Manual Time Mode: Fixed start/end times as alternative to twilight-based scheduling
- Two-Month Calendar: Visual date selection with capture history indicators
- Auto Video Creation: Automatically create timelapse videos (uses Video Export tab settings)
- Auto Delete Snapshots: Option to free disk space after video creation
- Scheduler Log: Color-coded activity monitoring (INFO/WARNING/ERROR)
- Location Settings: Latitude/longitude with hemisphere indicator
- Capture History: Calendar shows captured dates even after snapshots are deleted
- Preset Memory: Last selected video preset is remembered across sessions
Improvements:
- Auto-save configuration when switching tabs and before closing app (no manual save/load needed)
- Smart folder creation: Browse buttons auto-create folders if they don't exist
- Output folder paths saved as full absolute paths for clarity
- Video Export Browse opens at exe location, Quick Select opens at configured snapshots folder
- Scheduler correctly uses calculated twilight times
- Default "Open video when complete" to unchecked
- Default schedule times changed to 20:00-08:00
- Config consolidated to
config/app_config.json - User data (capture history, presets) moved to
user_data/folder - Removed unused config fields for cleaner configuration
UI Improvements:
- Three-tab interface (Capture | Video Export | Scheduling)
- Two-column layout for Twilight vs Manual time settings
- Radio buttons to switch between time modes
- Calendar legend on right side under buttons
- Compact layout with all settings visible
Technical:
- New
AstroSchedulerclass for background schedule monitoring TwilightCalculatorfor accurate sun position calculationsTwoMonthCalendarcustom widget with date status indicatorsCaptureHistoryManagerfor persistent session tracking- New config fields:
use_manual_times,manual_start_time,manual_end_time - Scheduler integrates with existing capture engine
Major Release: Multi-Threaded Bufferless Capture
- Revolutionary timestamp accuracy: ±5 seconds throughout entire capture session (96% improvement over baseline)
- Multi-threaded capture engine: Background thread continuously reads frames, discards stale ones
- Zero drift accumulation: Maintains stable ±5s accuracy across multiple reconnection cycles
- FFmpeg low-latency flags: Optimized RTSP streaming with minimal buffering
- Production-ready defaults: Optimal Configuration A values pre-configured out of the box
- Validated extensively: 26-minute and 4-hour test sessions with 100% success rate
Technical Improvements:
- Implemented
RTSPBufferlessCaptureclass with queue-based architecture (maxsize=1) - Queue automatically discards old frames, keeps only latest
- Compatible API with cv2.VideoCapture for seamless integration
- Logs show "Multi-threaded bufferless mode" for verification
- Cleaner logging with technical terminology
Default Configuration Updates:
- Interval: 20s → 30s (optimal for accuracy)
- JPEG Quality: 90 → 95 (archival quality)
- Buffer Frames: 2 → 1 (minimal for multi-threaded)
- Max Retries: 5 → 3 (quick failure detection)
- Proactive Reconnect: 0 → 300s (enabled by default)
Performance Results:
- Initial capture: +19s (vs baseline +35s, 46% better)
- Steady-state: ±5s (vs baseline -4m 50s, 96% better)
- Drift behavior: Stable (vs accumulating over time)
- Success rate: 100% maintained
GUI Improvements:
- Button and UI automatically reset when capture window ends
- Stop button changes to "Start Capture" when session completes
- Configuration inputs re-enable automatically
Bug Fixes:
- Fixed Stop button remaining active after end time reached
- Fixed configuration inputs not re-enabling after capture end
Initial Release Features:
- RTSP camera capture with live preview and overnight scheduling support
- Complete video export functionality with FFmpeg integration
- 6 built-in presets + custom preset management
- Tabbed interface (Capture | Video Export)
- Session statistics and monitoring
- Configuration management with JSON
- Thread-safe architecture with responsive GUI
- Keyboard shortcuts for common actions
- Comprehensive Tooltip System: 37 hover tooltips across both tabs
- Smart positioning with 500ms delay
- Helpful explanations with examples and recommendations
- Output Path Memory: Video export remembers last export location
- Proactive Reconnection: Automatically reconnect before camera firmware timeouts
- Optimized buffer settings for RTSP streaming
Bug Fixes:
- Fixed PyInstaller executable build issues
- Bundled all FFmpeg DLLs (~150 MB) for video export
- Fixed Tkinter DLL dependencies for Windows
- Increased FFmpeg subprocess timeout to prevent false failures
- Video export works properly in standalone executable
Contributions welcome! Please:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes and add tests
- Commit:
git commit -m "Add amazing feature" - Push:
git push origin feature/amazing-feature - Open a Pull Request
- Documentation: Check this README and
docs/folder [TODO] - Bug Reports: Open an issue
- Feature Requests: Open an issue
- Discussions: GitHub Discussions
Useful Resources:
- OpenCV - RTSP streaming and image processing
- FFmpeg - Professional video encoding
- Tkinter - Python GUI framework
- PIL/Pillow - Image manipulation
- PyInstaller - Executable packaging
- Python Community - Amazing ecosystem and support
Released under the MIT License. See version_info.txt for Windows executable metadata.