62 const std::string&
getServerId()
const {
return config_.camera_name; }
66 std::atomic<bool> running_{
false};
67 std::unique_ptr<CameraController> camera_controller_;
68 std::unique_ptr<HttpServer> http_server_;
72 std::mutex queue_cv_mutex_;
73 std::condition_variable queue_cv_;
76 std::atomic<bool> capture_running_{
false};
77 std::thread capture_thread_;
78 void captureFrameLoop();
83 std::atomic<bool> publisher_running_{
false};
84 std::thread publisher_thread_;
85 void publishFrameLoop();
88 std::mutex image_cache_mutex_;
89 std::vector<uint8_t> cached_image_data_;
90 std::shared_ptr<DataFrame> cached_frame_;
91 int cached_display_width_{0};
92 int cached_display_height_{0};
96 std::set<httplib::ws::WebSocket*> websocket_clients_;
97 std::chrono::steady_clock::time_point last_ws_frame_time_{std::chrono::steady_clock::now()};
100 std::atomic<bool> recording_active_{
false};
101 std::atomic<bool> recorder_running_{
false};
102 std::atomic<bool> recording_waiting_{
false};
103 std::thread recorder_thread_;
104 common::Queue<std::shared_ptr<DataFrame>> recording_queue_;
105 std::mutex recording_cv_mutex_;
106 std::condition_variable recording_cv_;
107 std::unique_ptr<FitsRecorder> fits_recorder_;
110 RecordingConfig active_recording_config_;
113 std::atomic<int> recording_frames_target_{0};
114 std::atomic<int> recording_frames_done_{0};
115 std::atomic<size_t> recording_bytes_done_{0};
116 std::chrono::steady_clock::time_point recording_start_time_;
117 std::atomic<double> recording_wait_remaining_{0};
120 std::atomic<uint32_t> recording_drop_count_{0};
121 std::chrono::steady_clock::time_point recording_last_drop_log_{std::chrono::steady_clock::now()};
124 std::mutex recording_files_mutex_;
125 std::vector<std::string> recording_written_files_;
128 void startRecording(
const RecordingConfig& cfg);
129 void stopRecording();
132 std::atomic<bool> telemetry_running_{
false};
133 std::thread telemetry_thread_;
134 void telemetryLoop();
137 struct TelemetrySample {
140 std::string camera_name;
144 std::mutex telemetry_mutex_;
145 std::map<std::string, TelemetrySample> telemetry_current_;
147 std::vector<std::string> telemetry_params_;
150 struct SlidingWindowStats {
151 std::vector<double> samples;
155 void init(
int capacity) { samples.resize(capacity, 0.0); pos = 0; count = 0; }
156 void push(
double v) {
158 pos = (pos + 1) %
static_cast<int>(samples.size());
159 if (count <
static_cast<int>(samples.size())) count++;
163 if (count == 0)
return {};
164 double sum = 0, mn = samples[0], mx = samples[0];
165 for (
int i = 0; i < count; i++) {
166 double v = samples[i];
171 double mean = sum / count;
173 for (
int i = 0; i < count; i++) {
174 double d = samples[i] - mean;
177 return {mean, (count > 1 ? std::sqrt(sq_sum / (count - 1)) : 0.0), mn, mx};
181 struct FrameStatistics {
182 SlidingWindowStats inter_frame;
183 SlidingWindowStats processing_latency;
184 uint64_t frames_total{0};
185 uint64_t bytes_total{0};
186 uint64_t frames_dropped_capture{0};
187 uint64_t frames_dropped_recording{0};
188 std::chrono::steady_clock::time_point acquisition_start;
189 std::chrono::steady_clock::time_point last_frame_time;
190 bool has_last_frame{
false};
193 SlidingWindowStats publish_interval;
194 SlidingWindowStats encode_time;
195 uint64_t frames_published{0};
196 uint64_t publish_bytes_total{0};
197 std::chrono::steady_clock::time_point last_publish_time;
198 bool has_last_publish{
false};
201 std::mutex stats_mutex_;
202 FrameStatistics frame_stats_;
203 void resetStatistics();
206 static void jpegWriteCallback(
void* context,
void* data,
int size);
207 std::vector<uint8_t> encodeFrameToJpeg(
const DataFrame& frame,
int quality,
208 int max_width,
int max_height,
209 int& out_width,
int& out_height);
210 std::vector<uint8_t> normalizeToUint8(
const DataFrame& frame);
211 static std::vector<uint8_t> downscaleGray(
const uint8_t* src,
int src_w,
int src_h,
212 int dst_w,
int dst_h);