Mentions légales du service

Skip to content
Snippets Groups Projects
Commit ae027665 authored by MOLLI Martin's avatar MOLLI Martin
Browse files

Fixed stuff

parent 0b84aa71
No related branches found
No related tags found
No related merge requests found
Pipeline #1142347 passed
Showing
with 325 additions and 139 deletions
......@@ -12,6 +12,8 @@ WORKDIR /app
COPY . .
# Install required Python packages
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && apt install -y libzmq3-dev && rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir -r requirements.txt
# Set environment variables with default values
......@@ -20,7 +22,6 @@ ENV CAMERA="false" \
APPEARANCE_RATE=600 \
MDHOST="localhost" \
MDPORT=9998
# Expose the port (if needed)
# EXPOSE <port_number>
......
......@@ -7,4 +7,5 @@ opentelemetry-sdk
opentelemetry-exporter-jaeger
opentelemetry-exporter-otlp
opentelemetry-exporter-otlp-proto-grpc
pyzmq
\ No newline at end of file
pyzmq
cffi
\ No newline at end of file
import logging
import os # Import os for environment variables
import random
import time
from time import perf_counter, sleep, perf_counter_ns
from contextlib import contextmanager
import cv2
import imutils # pip install imutils
import zmq
from opentelemetry.propagate import inject
from zmq.backend.cffi import Socket
from services.common.camera_to_motiondetector_packet import CameraToMotionDetectorPacket
from camera_to_motiondetector_packet import CameraToMotionDetectorPacket
from telemetry.tracerprovider import tracer, meter
......@@ -29,23 +28,23 @@ logging.basicConfig(
level=logging.INFO, # You can change this to DEBUG, ERROR, etc.
handlers=[
logging.StreamHandler(), # Log to console
logging.FileHandler("/app/output/camera.log") # Log to a file
#logging.FileHandler("/app/output/camera.log") # Log to a file
]
)
frametime_histogram = meter.create_gauge(
name="camera_frame_time",
description="Frames time",
unit="ms"
)
sleep_time_between_frame = meter.create_gauge(
name="camera_sleep_time_between_frame",
description="sleep_time_between_frame",
unit="ms"
)
frame_rate:int = 30
frame_rate:int = 10
MIN_FRAME_TIME:float = 1.0 / frame_rate
# Get environment variables (with defaults if not set)
......@@ -58,9 +57,9 @@ port = int(os.getenv("MDPORT", 9998))
# Map animal to the appropriate video filenames
animal_map = {
'bear': ('footage/bear/no_bear.mp4', 'footage/bear/with_bear.mp4'),
'tiger': ('footage/tiger/no_tiger.mp4', 'footage/tiger/with_tiger.mp4'),
'wolf': ('footage/wolf/no_wolf.mp4', 'footage/wolf/with_wolf.mp4')
'bear': ('../footage/bear/no_bear.mp4', '../footage/bear/with_bear.mp4'),
'tiger': ('../footage/tiger/no_tiger.mp4', '../footage/tiger/with_tiger.mp4'),
'wolf': ('../footage/wolf/no_wolf.mp4', '../footage/wolf/with_wolf.mp4')
}
if animal_name not in animal_map:
......@@ -95,8 +94,8 @@ def main():
socket = context.socket(zmq.PAIR)
logging.info(f"Attempting to connect to {host_ip}:{port}")
socket.connect(f"tcp://{host_ip}:{port}")
stream_video_clip(socket)
logging.info(f"Connected to {host_ip}:{port}")
stream_video_clip(socket)
......@@ -105,7 +104,7 @@ def stream_video_clip(socket):
return
# Initialize FPS calculation
app_start_time = time.time()
app_start_time = perf_counter()
while True:
# Time no_motion_clip_length between motion to sample fivode
with tracer.start_as_current_span("sending frame from camera") as frame_span:
......@@ -116,14 +115,17 @@ def stream_video_clip(socket):
# Alternate between video with motion and video without motion
for motion in (False, True):
# Initialize FPS calculation
frame_beginning_time = time.time()
frame_number = 0
# Open the appropriate video file
video_path = with_animal_video if motion else no_animal_video
with videocapture(video_path) as video_capture:
if(video_capture is None):
logging.error("Could not open video capture.")
exit(1)
# Determine the number of frames to process according to the clip length
if motion:
max_frames = int(video_capture.get(cv2.CAP_PROP_FRAME_COUNT)) # Process the entire clip to avoid creating incoherent clip
......@@ -133,9 +135,12 @@ def stream_video_clip(socket):
logging.info(f"Motion: {motion}, Max Frame Count: {max_frames}")
while frame_number < max_frames:
# Initialize FPS calculation
frame_beginning_time = perf_counter()
frame_number += 1
success, frame = video_capture.read()
frame_start_time = time.time()
#Loop video clip if there are no more frame or if we cannot read the next frame.
# Used for looping the short clip where no animal are present
......@@ -153,18 +158,20 @@ def stream_video_clip(socket):
packet= CameraToMotionDetectorPacket(frame, str(camera_index), carrier)
socket.send(packet.pickle())
logging.info(f"Frame sent: {frame_number}, {motion}, {frame_beginning_time}")
frame_number += 1
#Metric logging
frametime = time.time() - app_start_time
frametime = perf_counter() - frame_beginning_time
logging.info(f"Frame time: {frametime}")
frametime_histogram.set(frametime)
#Sleep if needed to maintain frame rate
elapsed_time = time.time() - frame_beginning_time
sleep_time = MIN_FRAME_TIME - elapsed_time
sleep_time = MIN_FRAME_TIME - frametime
logging.info(f"fps: {1/frametime}, sleep time: {sleep_time}, fps at sleep time: {1/sleep_time}")
sleep_time_between_frame.set(sleep_time)
time.sleep(max(0.0, sleep_time))
sleep(max(0.0, sleep_time))
except Exception as error:
logging.error(f"Error sending frame: {error}")
socket.close()
......
import datetime
import pickle
import time
from time import perf_counter
import cv2
import numpy as np
class CameraToMotionDetectorPacket:
def __init__(self, opencv_frame: np.ndarray, source_camera_identifier: str, telemetry_carrier: dict):
self._opencv_frame: np.ndarray = opencv_frame
self.source_camera_identifier = source_camera_identifier
self.timestamp = perf_counter()
self.telemetry_carrier = telemetry_carrier
def pickle (self):
#Make sure timestamp is up to date before sending
self.timestamp= perf_counter()
return pickle.dumps(self)
def decode_frame(self):
return self._opencv_frame
@staticmethod
def unpickle(buffer):
return pickle.loads(buffer)
\ No newline at end of file
......@@ -14,34 +14,76 @@ file_name = "Camera "
index_value = os.environ.get("INDEX", str(random.randint(1, 10)))
# Generate a random integer
resource=Resource.create({SERVICE_NAME: f"{file_name}{index_value}"})
DISABLE_OTEL = os.getenv("DISABLE_OTEL", "false").lower() == "true"
if DISABLE_OTEL:
class Dummy():
'''
Dummy that can be called and is also a context manager.
It will always return itself, so that you can chain calls.
'''
# Accessing attributes
def __getattr__(self, name):
return self
# Callable
def __call__(self, *args, **kwargs):
return self
# Context manager
def __enter__(self):
return self
def __exit__(self, *args, **kwargs):
pass
# Indexing, Subscripting, Slicing
def __getitem__(self, *args, **kwargs):
return self
def __setitem__(self, key, value):
self
# String representation
def __str__(self) -> str:
return '<Just a Dummy>'
tracer = Dummy()
meter = Dummy()
else:
# Set up the tracer provider for tracing
trace.set_tracer_provider(
TracerProvider(
resource=resource
trace.set_tracer_provider(
TracerProvider(
resource=resource
)
)
)
# Create an OpenTelemetry Collector exporter for exporting traces
otlp_trace_exporter = OTLPSpanExporter(endpoint="otel-collector:4317", insecure=True)
# Create an OpenTelemetry Collector exporter for exporting traces
otlp_trace_exporter = OTLPSpanExporter(endpoint="otel-collector:4317", insecure=True)
# Add the OpenTelemetry Collector exporter to the tracer provider
trace.get_tracer_provider().add_span_processor(
BatchSpanProcessor(otlp_trace_exporter)
)
tracer = trace.get_tracer("camera_tracer")
# Add the OpenTelemetry Collector exporter to the tracer provider
trace.get_tracer_provider().add_span_processor(
BatchSpanProcessor(otlp_trace_exporter)
)
tracer = trace.get_tracer("camera_tracer")
# Set up the meter provider for metrics
meter_provider = MeterProvider()
# Set up the meter provider for metrics
meter_provider = MeterProvider()
# Create an OpenTelemetry Collector exporter for exporting metrics
otlp_metrics_exporter = OTLPMetricExporter(endpoint="http://otel-collector:4317", insecure=True)
# Create an OpenTelemetry Collector exporter for exporting metrics
otlp_metrics_exporter = OTLPMetricExporter(endpoint="http://otel-collector:4317", insecure=True)
# Register the OpenTelemetry Collector exporter with the metrics provider
# Register the OpenTelemetry Collector exporter with the metrics provider
reader = PeriodicExportingMetricReader(
OTLPMetricExporter(endpoint="http://otel-collector:4317",insecure=True)
)
meterProvider = MeterProvider(resource=resource, metric_readers=[reader])
metrics.set_meter_provider(meterProvider)
meter = metrics.get_meter("camera_meter")
\ No newline at end of file
reader = PeriodicExportingMetricReader(
OTLPMetricExporter(endpoint="http://otel-collector:4317",insecure=True)
)
meterProvider = MeterProvider(resource=resource, metric_readers=[reader])
metrics.set_meter_provider(meterProvider)
meter = metrics.get_meter("camera_meter")
\ No newline at end of file
......@@ -16,17 +16,7 @@ class MotionDetectorToObjectRecognizerPacket:
def pickle(self):
self.timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
data = {
"opencv_frame": self._opencv_frame,
"source_camera_identifier": self.source_camera_identifier,
"timestamp": self.timestamp,
"camera_timestamp" : self.camera_timestamp,
"telemetry_carrier": self.telemetry_carrier,
"contour": self.contour
}
return pickle.dumps(data)
return pickle.dumps(self)
def decode_frame(self):
......@@ -34,11 +24,5 @@ class MotionDetectorToObjectRecognizerPacket:
@staticmethod
def unpickle(buffer):
data = pickle.loads(buffer)
return MotionDetectorToObjectRecognizerPacket(cv2.imdecode(data["opencv_frame"], cv2.IMREAD_COLOR),
data["source_camera_identifier"],
data["camera_timestamp"],
data["telemetry_carrier"],
data["contour"])
return pickle.loads(buffer)
# Use the official Python image as base
FROM python:3.12-slim as build
FROM python:3.12-slim-bookworm as build
# Set the working directory inside the container
WORKDIR /app
......@@ -13,6 +13,8 @@ WORKDIR /app
COPY . .
# Install required Python packages
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && apt install -y libzmq3-dev && rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir -r requirements.txt
# Set environment variables
......
......@@ -7,4 +7,5 @@ opentelemetry-exporter-jaeger
opentelemetry-exporter-otlp
opentelemetry-exporter-otlp-proto-grpc
psutil
pyzmq
\ No newline at end of file
pyzmq
cffi
\ No newline at end of file
import datetime
import pickle
import time
import cv2
import numpy as np
class CameraToMotionDetectorPacket:
def __init__(self, opencv_frame: np.ndarray, source_camera_identifier: str, telemetry_carrier: dict):
self._opencv_frame: np.ndarray = opencv_frame
self.source_camera_identifier = source_camera_identifier
self.timestamp = time.perf_counter()
self.telemetry_carrier = telemetry_carrier
def pickle (self):
#Make sure timestamp is up to date before sending
self.timestamp= time.perf_counter()
return pickle.dumps(self)
def decode_frame(self):
return self._opencv_frame
@staticmethod
def unpickle(buffer):
return pickle.loads(buffer)
\ No newline at end of file
......@@ -3,8 +3,9 @@ import datetime
import logging # Import the logging module
import os
import pickle
import socket
import time
from time import perf_counter
import cv2
import imutils
......@@ -12,8 +13,8 @@ import psutil
import zmq
from opentelemetry.propagate import extract, inject
from services.common.camera_to_motiondetector_packet import CameraToMotionDetectorPacket
from services.common.motion_detector_to_object_recognizer_packet import MotionDetectorToObjectRecognizerPacket
from camera_to_motiondetector_packet import CameraToMotionDetectorPacket
from motion_detector_to_object_recognizer_packet import MotionDetectorToObjectRecognizerPacket
from telemetry.tracerprovider import tracer, meter
# Configure logging
......@@ -22,10 +23,11 @@ logging.basicConfig(
level=logging.INFO, # You can change this to DEBUG, ERROR, etc.
handlers=[
logging.StreamHandler(), # Log to console
logging.FileHandler("/app/output/motion_detector.log") # Log to a file
#logging.FileHandler("/app/output/motion_detector.log") # Log to a file
]
)
fps_histo = meter.create_histogram(
name="md_fps_histo",
description="Frames per second",
......@@ -73,7 +75,6 @@ def detect_motion(frame, source_camera_identifier, trace_carrier):
with tracer.start_as_current_span("processing the frame",context=extracted_context) as span:
try:
inject(trace_carrier)
logging.debug("Frame loaded for processing.")
logging.debug(f"FRAME RECEIVE FROM CLIENT: {source_camera_identifier} | TIME: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
......@@ -82,7 +83,7 @@ def detect_motion(frame, source_camera_identifier, trace_carrier):
if first_frame is None:
first_frame = gray
logging.info("Initialized reference frame for motion detection.")
logging.debug("Initialized reference frame for motion detection.")
continue
starting_processing_time = time.time()
......@@ -102,6 +103,9 @@ def detect_motion(frame, source_camera_identifier, trace_carrier):
cv2.CHAIN_APPROX_SIMPLE)
contours = imutils.grab_contours(contours)
if len(contours) == 0:
logging.debug("No contours detected.")
detected_cnt = 0
detected = False
bounding_rectangle = ()
......@@ -110,7 +114,7 @@ def detect_motion(frame, source_camera_identifier, trace_carrier):
continue
detected = True
detected_cnt += 1
logging.debug(f"Motion detected. Contour area: {cv2.contourArea(contour)}.")
logging.info(f"Motion detected. Contour area: {cv2.contourArea(contour)}.")
(x, y, w, h) = cv2.boundingRect(contour)
bounding_rectangle = (x, y, w, h)
......@@ -133,49 +137,53 @@ def main():
# Retrieve environment variables instead of command-line arguments
or_host_ip = os.getenv('OR_HOST', 'localhost') # Default to 'localhost'
or_port = int(os.getenv('OR_PORT', 9999)) # Default to 9999
host_name = socket.gethostname()
host_ip = socket.gethostbyname(host_name)
logging.info(f'HOST IP: {host_ip}')
#host_name = socket.gethostname()
#host_ip = socket.gethostbyname(host_name)
#logging.info(f'HOST IP: {host_ip}')
host_port = 9998
context = zmq.Context
context = zmq.Context()
camera_socket = context.socket(zmq.PAIR)
camera_socket.bind(f"tcp://{host_ip}:{host_port}")
camera_socket.bind(f"tcp://localhost:{host_port}")
logging.info(f'Camera socket bound to {host_port}')
or_socket_context = zmq.Context()
or_socket = or_socket_context.socket(zmq.PAIR)
or_socket = context.socket(zmq.PAIR)
logging.info(f"Connecting to {or_host_ip}:{or_port}")
or_socket.connect(f"tcp://{or_host_ip}:{or_port}")
logging.info(f"connected to {or_host_ip}:{or_port}")
while True:
try:
message = camera_socket.recv()
camera_packet: CameraToMotionDetectorPacket = pickle.loads(message)
transmission_time = datetime.datetime.now() - camera_packet.timestamp
transmission_time_in_seconds = transmission_time.total_seconds()
c2e_transmission_time.set(transmission_time_in_seconds)
logging.info(f"Frame received with transmission time: {transmission_time_in_seconds} seconds.")
starting_processing_time = time.time()
frame = camera_packet.decode_frame()
flag, contours = detect_motion(frame, camera_packet.source_camera_identifier,
camera_packet.telemetry_carrier)
if flag:
md_packet = MotionDetectorToObjectRecognizerPacket(frame, camera_packet.source_camera_identifier,
camera_packet.telemetry_carrier, contours)
pickled = md_packet.pickle()
logging.info(f"Packet size: {len(pickled)} bytes.") # Log the size of the packet
or_socket.send(pickled)
logging.info("Frame successfully sent to Object Recognizer.")
processing_time.set(time.time() - starting_processing_time)
logging.debug("Processing time logged for frame.")
except Exception as error:
logging.error(f"Error in event loop: {error}")
time.sleep(1)
continue
message = camera_socket.recv()
camera_packet: CameraToMotionDetectorPacket = pickle.loads(message)
transmission_time = perf_counter() - camera_packet.timestamp
c2e_transmission_time.set(transmission_time)
logging.info(f"Frame received with transmission time: {transmission_time} seconds.")
starting_processing_time = perf_counter()
frame = camera_packet.decode_frame()
cv2.imshow("Frame", frame)
cv2.waitKey(1)
if frame is None:
logging.error("Invalid frame received.")
flag, contours = detect_motion(frame, camera_packet.source_camera_identifier,
camera_packet.telemetry_carrier)
#logging.INFO(str(flag),str(contours))
if flag:
md_packet = MotionDetectorToObjectRecognizerPacket(frame, camera_packet.source_camera_identifier,
camera_packet.timestamp,
camera_packet.telemetry_carrier, contours)
pickled = md_packet.pickle()
logging.info(f"Packet size: {len(pickled)} bytes.") # Log the size of the packet
or_socket.send(pickled)
logging.info("Frame successfully sent to Object Recognizer.")
processing_time.set(time.time() - starting_processing_time)
logging.debug("Processing time logged for frame.")
......
import datetime
import pickle
import cv2
import numpy as np
class MotionDetectorToObjectRecognizerPacket:
def __init__(self, opencv_frame: np.ndarray, source_camera_identifier: str, camera_timestamp, telemetry_carrier: dict, contour: np.ndarray):
_, self._opencv_frame = cv2.imencode('.jpg', opencv_frame)
self.source_camera_identifier = source_camera_identifier
self.timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.camera_timestamp = camera_timestamp
self.telemetry_carrier = telemetry_carrier
self.contour = contour # OpenCV contour data
def pickle(self):
self.timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return pickle.dumps(self)
def decode_frame(self):
return cv2.imdecode(self._opencv_frame, cv2.IMREAD_COLOR)
@staticmethod
def unpickle(buffer):
return pickle.loads(buffer)
......@@ -11,42 +11,70 @@ from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
# Extract the file name without extension
file_name = "Motion Detector "
# try:
# with open('../index.txt', 'r') as file:
# index_value = int(file.read().strip())
# except (FileNotFoundError, ValueError) as e:
# print(f"Error reading index.txt: {e}")
# index_value = random.randint(1, 10)
index_value = os.environ.get("INDEX", str(random.randint(1, 10)))
resource=Resource.create({SERVICE_NAME: f"{file_name}{index_value}"})
# Set up the tracer provider for tracing
trace.set_tracer_provider(
TracerProvider(
resource=resource
# Disable OpenTelemetry if running locally
DISABLE_OTEL = os.environ.get("DISABLE_OTEL", 'False')
if DISABLE_OTEL:
class Dummy():
'''
Dummy that can be called and is also a context manager.
It will always return itself, so that you can chain calls.
'''
# Accessing attributes
def __getattr__(self, name):
return self
# Callable
def __call__(self, *args, **kwargs):
return self
# Context manager
def __enter__(self):
return self
def __exit__(self, *args, **kwargs):
pass
# Indexing, Subscripting, Slicing
def __getitem__(self, *args, **kwargs):
return self
def __setitem__(self, key, value):
self
# String representation
def __str__(self) -> str:
return '<Just a Dummy>'
tracer = Dummy()
meter = Dummy()
else:
# Set up the tracer provider for tracing
trace.set_tracer_provider(
TracerProvider(
resource=resource
)
)
)
# Create an OpenTelemetry Collector exporter for exporting traces
otlp_trace_exporter = OTLPSpanExporter(endpoint="otel-collector:4317", insecure=True)
# Create an OpenTelemetry Collector exporter for exporting traces
otlp_trace_exporter = OTLPSpanExporter(endpoint="otel-collector:4317", insecure=True)
# Add the OpenTelemetry Collector exporter to the tracer provider
trace.get_tracer_provider().add_span_processor(
BatchSpanProcessor(otlp_trace_exporter)
)
tracer = trace.get_tracer("motion detector tracer")
# Add the OpenTelemetry Collector exporter to the tracer provider
trace.get_tracer_provider().add_span_processor(
BatchSpanProcessor(otlp_trace_exporter)
)
tracer = trace.get_tracer("motion detector tracer")
# Set up the meter provider for metrics
meter_provider = MeterProvider()
# Set up the meter provider for metrics
meter_provider = MeterProvider()
# Create an OpenTelemetry Collector exporter for exporting metrics
otlp_metrics_exporter = OTLPMetricExporter(endpoint="http://otel-collector:4317", insecure=True)
# Create an OpenTelemetry Collector exporter for exporting metrics
otlp_metrics_exporter = OTLPMetricExporter(endpoint="http://otel-collector:4317", insecure=True)
# Register the OpenTelemetry Collector exporter with the metrics provider
# Register the OpenTelemetry Collector exporter with the metrics provider
reader = PeriodicExportingMetricReader(
OTLPMetricExporter(endpoint="http://otel-collector:4317",insecure=True)
)
meterProvider = MeterProvider(resource=resource, metric_readers=[reader])
metrics.set_meter_provider(meterProvider)
meter = metrics.get_meter("motion detector meter")
\ No newline at end of file
reader = PeriodicExportingMetricReader(
OTLPMetricExporter(endpoint="http://otel-collector:4317",insecure=True)
)
meterProvider = MeterProvider(resource=resource, metric_readers=[reader])
metrics.set_meter_provider(meterProvider)
meter = metrics.get_meter("motion detector meter")
\ No newline at end of file
......@@ -11,8 +11,9 @@ WORKDIR /app
# Copy the server code into the container
COPY . .
# Install required Python packages
RUN pip install --no-cache-dir -r requirements.txt
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && apt install -y libzmq3-dev && rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir -r requirements.txt
# Expose port 5000
EXPOSE 5000
......
......@@ -8,4 +8,5 @@ opentelemetry-exporter-otlp
opentelemetry-exporter-otlp-proto-grpc
docker
flask
pyzmq
\ No newline at end of file
pyzmq
cffi
\ No newline at end of file
import datetime
import pickle
import cv2
import numpy as np
class MotionDetectorToObjectRecognizerPacket:
def __init__(self, opencv_frame: np.ndarray, source_camera_identifier: str, camera_timestamp, telemetry_carrier: dict, contour: np.ndarray):
_, self._opencv_frame = cv2.imencode('.jpg', opencv_frame)
self.source_camera_identifier = source_camera_identifier
self.timestamp = datetime.datetime.now()
self.camera_timestamp = camera_timestamp
self.telemetry_carrier = telemetry_carrier
self.contour = contour # OpenCV contour data
def pickle(self):
self.timestamp = datetime.datetime.now()
return pickle.dumps(self)
def decode_frame(self):
return cv2.imdecode(self._opencv_frame, cv2.IMREAD_COLOR)
@staticmethod
def unpickle(buffer):
return pickle.loads(buffer)
......@@ -8,7 +8,7 @@ import zmq
from opentelemetry.propagate import extract
from model.model import recognize
from services.common.motion_detector_to_object_recognizer_packet import MotionDetectorToObjectRecognizerPacket
from motion_detector_to_object_recognizer_packet import MotionDetectorToObjectRecognizerPacket
from telemetry.tracerprovider import meter, tracer
from webserver import run_flask
......@@ -103,6 +103,7 @@ def main():
while True:
try:
logging.info("Waiting for new frame...")
receive_frames(server_socket, frame_queue)
except Exception as e:
logging.error(f"Error in server loop: {e}")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment