continuous daytime capture
This PR adds continuous daytime capture feature to the capture code. When enabled, the code runs capture throughout day and night, while also switching between the implemented daytime and nighttime modes within CameraControl.py.
This is great. Can't wait to try it out.
This is a great start! As suggested by @Cybis320 (I presume the message was edited), there should be a fundamental difference between nighttime and daytime capture. Perhaps BufferedCapture could be modified so it switches between the two modes on an external call (e.g. bc.switchDaytimeCapture() and bc.switchNighttimeCapture()). The nighttime capture should remain unchanged, but the daytime capture should only capture those individual frames and optionally capture the video to disk. This will keep the current diurnal cycle and keep the meteor capture unaffected. The new daytime frame capture will collect contrail data during the day and the daytime timelapse can be uploaded with the daily uploads. The daytime video capture will enable daytime fireball observations and perhaps used for other things too.
Something like that?
graph TD
A[StartCapture] --> B[Initialize RTSP Stream]
B --> C[Start Pipeline Sinks]
C --> I[App Sink]
C --> J[ MKV Video Sink]
J --> N[Start MKV Making]
I --> M[Save every Nth Frame]
I --> D{Day or Night?}
D -->|Day| E[Stop Compressor]
E --> F[Set Day Camera Settings]
F --> X[Post Process]
D -->|Night| G[Set Night Camera Settings]
G --> H[Start Compressor]
H --> L[Detection]
X --> K[Time Delay]
L --> K
K --> D
That's a great flowchart, that should exactly be it!
That's a great flowchart, that should exactly be it!
That might be my new fav thing to do :) I just discovered you can do this:
(replace ' with ` to actually display the chart) '''mermaid graph TD A[StartCapture] --> B[Initialize RTSP Stream] B --> C[Start Pipeline Sinks] C --> I[App Sink] C --> J[ MKV Video Sink] J --> N[Start MKV Making] I --> M[Save every Nth Frame] I --> D{Day or Night?} D -->|Day| E[Stop Compressor] E --> F[Set Day Camera Settings] F --> X[Post Process] D -->|Night| G[Set Night Camera Settings] G --> H[Start Compressor] H --> L[Detection] X --> K[Time Delay] L --> K K --> D '''
Needs testing, but the updates are summarized below.
.config and ConfigReader.py:
-
Includes options for continuous capture, raw video saving, raw frame saving and timelapse generation from the raw frames. These are enabled by default for this version.
-
Raw frames go to ~/RMS_data/FramesFiles by default
-
Raw videos go to ~/RMS_data/VideoFiles by default
-
Raw frame interval (in seconds), quality, and file type (jpg/png) is configurable
BufferedCapture.py and RawFrameSave.py:
- During daytime, compression is not performed so the shared arrays (with the Compressor) aren't accessed
- A similar shared memory setup to the Compressor is implemented for frame saving (RawFrameSave.py), saving one frame every defined interval (intended to run regardless of day/night). Frames and corresponding timestamps are transferred through this array
- Accurate timestamping of raw videos is still a WIP. Currently, raw video clip saving have been tied to a custom gstreamer callback function (move_segment), which moves every video clip to its correct path under VideoFiles. TimestampRMS does not temporarily work as a result.
- RawFrameSaver saves frames and their corresponding frame count / timestamps in 10 frame blocks (can be configured in BufferedCapture.py)
- The frame counts / timestamps are saved in a separate "framestamps.json" file aside the (current day's) frames directory
CameraControl.py and CameraModeSwitcher.py:
- Added functions to CameraControl to switch to night and daytime modes.
- CameraModeSwitcher calls these functions when the sun is 10 degrees below horizon (at sunset, sunrise), and waits until next switch. This function actually facilitates the switch by modifying a shared variable (daytime_mode) at the right time.
DeleteObservations.py:
- Added functions to clean up and manage special directory structure of FramesFiles and VideoFiles (explained below)
- Last 8 days of FrameFiles are kept when cleaning up
- Last 2 days of VideoFiles are kept when cleaning up
StartCapture.py:
- The wait function has been modified to conditionally break when camera mode switches at sunset/sunrise
- Control flow of runCapture has been modified to allow both standard and continuous capture modes based on the config - might need cleaning up
- Continuous capture can only be exited using Ctrl + C for now
The new directory structure for VideoFiles and FramesFiles is as follows (Thanks @Cybis320):
~/RMS_data/
└── XX0001/
├── ArchivedFiles/
├── CapturedFiles/
├── VideoFiles/ # similar structure as FramesFiles, but for mkv video clips
└── FramesFiles/
├── 2024/
│ ├── 20240101-01/
│ │ ├── 00/
│ │ │ ├── XX0001_20240101_000001_122577.jpg
│ │ │ ├── XX0001_20240101_000011_122585.jpg
│ │ │ └── ...
│ │ ├── 01/
│ │ │ ├── XX0001_20240101_010001_122577.jpg
│ │ │ ├── XX0001_20240101_010011_122585.jpg
│ │ │ └── ...
│ │ ├── ...
│ │ └── 23/
│ │ ├── XX0001_20240101_230001_122577.jpg
│ │ ├── XX0001_20240101_230011_122585.jpg
│ │ └── ...
│ ├── ...
│ ├── 20241230-365/
│ └── 20241231-366/
├── 2025/
│ ...
└── ...
Reprocess.py and GenerateTimelapse.py:
- Frame timelapses, archived frames are created and generated only for past days, as capture might be running for the current day.
- These exist at the "year" directory level. After creation, the corresponding day directory (ex. 20241230-365) in FramesFiles is deleted. The framestamps.json file per day is also stored at the "year" level.
Testing with the initRawFrameArrays method above. It's capturing in day mode right now :) Thank you @MaadhyamRana !
The code has been modified so that it checks if the raw frame shape has changed at the frame level (instead of at the block level), thanks for the help @Cybis320 !
Thank you @MaadhyamRana ! Testing right now on my station... sunset in 1 hr.
Unfortunately, it did not like the camera switch at sunset. I'm not sure if it's because all six cameras are being sent the same commands at the same moment in a rapid fire manner, but all six camera just hung for 30 minutes at the changeover, and only show signs of having changed some of their settings. I made some changes to the CameraControl and CameraModeSwitcher and re-started capture on all six. Will see what happens at sunrise.
Video and Frame directories (days) are deleted first in case of less disk space, so the relatively smaller Capture data is preserved
@MaadhyamRana, I'm seeing cases where camera switching commands are not being received by the cameras. This seems to happen during the transition from night to day mode. One possibility is that the machine is overwhelmed at that exact moment. I'm testing to see if postprocess_delay will help. I'm also experimenting with setting a low niceness value for BufferedCapture. In addition, we need a way to resend commands on reconnects. Currently, there's no capturing during the first 25 minutes of post-processing. When the cameras resume capture, they are supposed to be in day mode, but because they missed the day commands, they remain in night mode. Therefore, we need to implement a mechanism to resend commands when cameras reconnect.
When there is no capturing for those first 25 minutes, is BufferedCapture looping on L1168? If so, we can import CameraControl and use the present daytime_mode.value to resend the appropriate commands (SwitchDayTime or SwitchNightTime) from within that loop.
it tries pinging the camera for 25 minutes. I don't understand why exactly. The overwhelmed RTSP client might have an effect on the RTSP server upstream somehow? That would be strange especially since it broadcast in UDP - the server shouldn't care about what's happening downstream. Or maybe, the pinging utility itself is stuck? I tried probing the rstp server itself, bypassing ping, it's a better approach overall, but same results in this case. Maybe the network interface itself is affected - I'll add some debug code to find out. I think we really need something at the stage just before we (re)establish a rtsp stream, just after:
# Init the video device
log.info("Initializing the video device...")
log.info("Device: " + str(self.config.deviceID))
Another clue is that all 6 cameras drop offline and come back online at the same instant... so it's probably a network interface thing. They all drop at the exact moment of the switch to daytime capture and all come back together 25 minutes later.
I'll experiment staggering the mode switches with config.postprocess_delay. Maybe, all the TCP commands at once are overwhelming?
Update: staggering the mode switching with config.postprocess_delay added in CameraModeSwitcher solved the issue. All cameras running on all cylinders!
I did look at the system logs for the event prior to this experiment, the network interface did drop for 24 minutes at the night to day mode transition. It could a network buffer size issue or a cpu irq issue. In any case, staggering and backing it up with a mode check on reconnects is the way to go.