54 const std::string&
getServerId()
const {
return config_.camera_name; }
58 std::atomic<bool> running_{
false};
59 std::unique_ptr<CameraController> camera_controller_;
60 std::unique_ptr<HttpServer> http_server_;
64 std::mutex queue_cv_mutex_;
65 std::condition_variable queue_cv_;
68 std::atomic<bool> capture_running_{
false};
69 std::thread capture_thread_;
70 void captureFrameLoop();
75 std::atomic<bool> publisher_running_{
false};
76 std::thread publisher_thread_;
77 void publishFrameLoop();
80 std::mutex image_cache_mutex_;
81 std::vector<uint8_t> cached_image_data_;
82 std::shared_ptr<DataFrame> cached_frame_;
83 int cached_display_width_{0};
84 int cached_display_height_{0};
88 std::set<httplib::ws::WebSocket*> websocket_clients_;
89 std::chrono::steady_clock::time_point last_ws_frame_time_{std::chrono::steady_clock::now()};
92 std::atomic<bool> recording_active_{
false};
93 std::atomic<bool> recorder_running_{
false};
94 std::atomic<bool> recording_waiting_{
false};
95 std::thread recorder_thread_;
96 common::Queue<std::shared_ptr<DataFrame>> recording_queue_;
97 std::mutex recording_cv_mutex_;
98 std::condition_variable recording_cv_;
99 std::unique_ptr<FitsRecorder> fits_recorder_;
102 RecordingConfig active_recording_config_;
105 std::atomic<int> recording_frames_target_{0};
106 std::atomic<int> recording_frames_done_{0};
107 std::atomic<size_t> recording_bytes_done_{0};
108 std::chrono::steady_clock::time_point recording_start_time_;
109 std::atomic<double> recording_wait_remaining_{0};
112 std::atomic<uint32_t> recording_drop_count_{0};
113 std::chrono::steady_clock::time_point recording_last_drop_log_{std::chrono::steady_clock::now()};
116 std::mutex recording_files_mutex_;
117 std::vector<std::string> recording_written_files_;
120 void startRecording(
const RecordingConfig& cfg);
121 void stopRecording();
124 std::atomic<bool> telemetry_running_{
false};
125 std::thread telemetry_thread_;
126 void telemetryLoop();
129 struct TelemetrySample {
132 std::string camera_name;
136 std::mutex telemetry_mutex_;
137 std::map<std::string, TelemetrySample> telemetry_current_;
139 std::vector<std::string> telemetry_params_;
142 struct SlidingWindowStats {
143 std::vector<double> samples;
147 void init(
int capacity) { samples.resize(capacity, 0.0); pos = 0; count = 0; }
148 void push(
double v) {
150 pos = (pos + 1) %
static_cast<int>(samples.size());
151 if (count <
static_cast<int>(samples.size())) count++;
155 if (count == 0)
return {};
156 double sum = 0, mn = samples[0], mx = samples[0];
157 for (
int i = 0; i < count; i++) {
158 double v = samples[i];
163 double mean = sum / count;
165 for (
int i = 0; i < count; i++) {
166 double d = samples[i] - mean;
169 return {mean, (count > 1 ? std::sqrt(sq_sum / (count - 1)) : 0.0), mn, mx};
173 struct FrameStatistics {
174 SlidingWindowStats inter_frame;
175 SlidingWindowStats processing_latency;
176 uint64_t frames_total{0};
177 uint64_t bytes_total{0};
178 uint64_t frames_dropped_capture{0};
179 uint64_t frames_dropped_recording{0};
180 std::chrono::steady_clock::time_point acquisition_start;
181 std::chrono::steady_clock::time_point last_frame_time;
182 bool has_last_frame{
false};
185 SlidingWindowStats publish_interval;
186 SlidingWindowStats encode_time;
187 uint64_t frames_published{0};
188 uint64_t publish_bytes_total{0};
189 std::chrono::steady_clock::time_point last_publish_time;
190 bool has_last_publish{
false};
193 std::mutex stats_mutex_;
194 FrameStatistics frame_stats_;
195 void resetStatistics();
198 static void jpegWriteCallback(
void* context,
void* data,
int size);
199 std::vector<uint8_t> encodeFrameToJpeg(
const DataFrame& frame,
int quality,
200 int max_width,
int max_height,
201 int& out_width,
int& out_height);
202 std::vector<uint8_t> normalizeToUint8(
const DataFrame& frame);
203 static std::vector<uint8_t> downscaleGray(
const uint8_t* src,
int src_w,
int src_h,
204 int dst_w,
int dst_h);