1212from config import BabbleConfig , BabbleSettingsConfig
1313from utils .misc_utils import get_camera_index_by_name , list_camera_names
1414from enum import Enum
15+ import sys
1516
1617WAIT_TIME = 0.1
18+ BUFFER_SIZE = 32768
1719MAX_RESOLUTION : int = 600
18-
1920# Serial communication protocol:
20- # header-begin (2 bytes)
21- # header-type (2 bytes)
22- # packet-size (2 bytes)
23- # packet (packet-size bytes)
24- ETVR_HEADER = b"\xff \xa0 "
25- ETVR_HEADER_FRAME = b"\xff \xa1 "
21+ # header-begin (2 bytes) "\xff\xa0"
22+ # header-type (2 bytes) "\xff\xa1"
23+ # packet-size (2 bytes)
24+ # packet (packet-size bytes)
25+ ETVR_HEADER = b"\xff \xa0 \xff \xa1 "
2626ETVR_HEADER_LEN = 6
2727
2828
@@ -48,8 +48,6 @@ def __init__(
4848 self .settings = settings
4949 self .camera_index = camera_index
5050 self .camera_list = list_camera_names ()
51- # The variable is not used
52- # self.camera_address = config.capture_source
5351 self .camera_status_outgoing = camera_status_outgoing
5452 self .camera_output_outgoing = camera_output_outgoing
5553 self .capture_event = capture_event
@@ -59,15 +57,10 @@ def __init__(
5957
6058 self .serial_connection = None
6159 self .last_frame_time = time .time ()
62- self .frame_number = 0
6360 self .fps = 0
6461 self .bps = 0
6562 self .start = True
6663 self .buffer = b""
67- self .pf_fps = 0
68- self .prevft = 0
69- self .newft = 0
70- self .fl = [0 ]
7164 self .FRAME_SIZE = [0 , 0 ]
7265
7366 self .error_message = f'{ Fore .YELLOW } [{ lang ._instance .get_string ("log.warn" )} ] { lang ._instance .get_string ("info.enterCaptureOne" )} {{}} { lang ._instance .get_string ("info.enterCaptureTwo" )} { Fore .RESET } '
@@ -175,28 +168,18 @@ def get_cv2_camera_picture(self, should_push):
175168 raise RuntimeError (lang ._instance .get_string ("error.frame" ))
176169 self .FRAME_SIZE = image .shape
177170 frame_number = self .cv2_camera .get (cv2 .CAP_PROP_POS_FRAMES )
178- # Calculate the fps.
179- yeah = time .time ()
180- delta_time = yeah - self .last_frame_time
181- self .last_frame_time = yeah
182- if delta_time > 0 :
183- self .bps = len (image ) / delta_time
184- self .frame_number = self .frame_number + 1
185- self .fps = (self .fps + self .pf_fps ) / 2
186- self .newft = time .time ()
187- self .fps = 1 / (self .newft - self .prevft )
188- self .prevft = self .newft
189- self .fps = int (self .fps )
190- if len (self .fl ) < 60 :
191- self .fl .append (self .fps )
192- else :
193- self .fl .pop (0 )
194- self .fl .append (self .fps )
195- self .fps = sum (self .fl ) / len (self .fl )
196- # self.bps = image.nbytes
171+ # Calculate FPS
172+ current_frame_time = time .time () # Should be using "time.perf_counter()", not worth ~3x cycles?
173+ delta_time = current_frame_time - self .last_frame_time
174+ self .last_frame_time = current_frame_time
175+ current_fps = 1 / delta_time if delta_time > 0 else 0
176+ # Exponential moving average (EMA). ~1100ns savings, delicious..
177+ self .fps = 0.02 * current_fps + 0.98 * self .fps
178+ self .bps = image .nbytes * self .fps
179+
197180 if should_push :
198- self .push_image_to_queue (image , frame_number , self .fps )
199- except Exception as e :
181+ self .push_image_to_queue (image , frame_number + 1 , self .fps )
182+ except Exception :
200183 print (
201184 f'{ Fore .YELLOW } [{ lang ._instance .get_string ("log.warn" )} ] { lang ._instance .get_string ("warn.captureProblem" )} { Fore .RESET } '
202185 )
@@ -207,7 +190,7 @@ def get_next_packet_bounds(self):
207190 beg = - 1
208191 while beg == - 1 :
209192 self .buffer += self .serial_connection .read (2048 )
210- beg = self .buffer .find (ETVR_HEADER + ETVR_HEADER_FRAME )
193+ beg = self .buffer .find (ETVR_HEADER )
211194 # Discard any data before the frame header.
212195 if beg > 0 :
213196 self .buffer = self .buffer [beg :]
@@ -225,7 +208,8 @@ def get_next_jpeg_frame(self):
225208
226209 def get_serial_camera_picture (self , should_push ):
227210 conn = self .serial_connection
228- if conn is None :
211+ # Stop spamming "Serial capture source problem" if connection is lost
212+ if conn is None or self .camera_status == CameraState .DISCONNECTED :
229213 return
230214 try :
231215 if conn .in_waiting :
@@ -240,34 +224,25 @@ def get_serial_camera_picture(self, should_push):
240224 f'{ Fore .YELLOW } [{ lang ._instance .get_string ("log.warn" )} ] { lang ._instance .get_string ("warn.frameDrop" )} { Fore .RESET } '
241225 )
242226 return
243- # Discard the serial buffer. This is due to the fact that it
244- # may build up some outdated frames. A bit of a workaround here tbh.
245- if conn .in_waiting >= 32768 :
246- print (
247- f'{ Fore .CYAN } [{ lang ._instance .get_string ("log.info" )} ] { lang ._instance .get_string ("info.discardingSerial" )} ({ conn .in_waiting } bytes){ Fore .RESET } '
248- )
249- conn .reset_input_buffer ()
250- self .buffer = b""
251- # Calculate the fps.
252- yeah = time .time ()
253- delta_time = yeah - self .last_frame_time
254- self .last_frame_time = yeah
255- if delta_time > 0 :
256- self .bps = len (jpeg ) / delta_time
257- self .fps = (self .fps + self .pf_fps ) / 2
258- self .newft = time .time ()
259- self .fps = 1 / (self .newft - self .prevft )
260- self .prevft = self .newft
261- self .fps = int (self .fps )
262- if len (self .fl ) < 60 :
263- self .fl .append (self .fps )
264- else :
265- self .fl .pop (0 )
266- self .fl .append (self .fps )
267- self .fps = sum (self .fl ) / len (self .fl )
268- self .frame_number = self .frame_number + 1
227+ # Calculate FPS
228+ current_frame_time = time .time () # Should be using "time.perf_counter()", not worth ~3x cycles?
229+ delta_time = current_frame_time - self .last_frame_time
230+ self .last_frame_time = current_frame_time
231+ current_fps = 1 / delta_time if delta_time > 0 else 0
232+ # Exponential moving average (EMA). ~1100ns savings, delicious..
233+ self .fps = 0.02 * current_fps + 0.98 * self .fps
234+ self .bps = len (jpeg ) * self .fps
235+
269236 if should_push :
270- self .push_image_to_queue (image , self .frame_number , self .fps )
237+ self .push_image_to_queue (image , int (current_fps ), self .fps )
238+ # Discard the serial buffer. This is due to the fact that it,
239+ # may build up some outdated frames. A bit of a workaround here tbh.
240+ # Do this at the end to give buffer time to refill.
241+ if conn .in_waiting >= BUFFER_SIZE :
242+ print (f'{ Fore .CYAN } [{ lang ._instance .get_string ("log.info" )} ] { lang ._instance .get_string ("info.discardingSerial" )} ({ conn .in_waiting } bytes){ Fore .RESET } ' )
243+ conn .reset_input_buffer ()
244+ self .buffer = b""
245+
271246 except Exception :
272247 print (
273248 f'{ Fore .YELLOW } [{ lang ._instance .get_string ("log.warn" )} ] { lang ._instance .get_string ("info.serialCapture" )} { Fore .RESET } '
@@ -288,11 +263,10 @@ def start_serial_connection(self, port):
288263 if not any (p for p in com_ports if port in p ):
289264 return
290265 try :
291- conn = serial .Serial (
292- baudrate = 3000000 , port = port , xonxoff = False , dsrdtr = False , rtscts = False
293- )
266+ rate = 115200 if sys .platform == "darwin" else 3000000 # Higher baud rate not working on macOS
267+ conn = serial .Serial (baudrate = rate , port = port , xonxoff = False , dsrdtr = False , rtscts = False )
294268 # Set explicit buffer size for serial.
295- conn .set_buffer_size (rx_size = 32768 , tx_size = 32768 )
269+ conn .set_buffer_size (rx_size = BUFFER_SIZE , tx_size = BUFFER_SIZE )
296270
297271 print (
298272 f'{ Fore .CYAN } [{ lang ._instance .get_string ("log.info" )} ] { lang ._instance .get_string ("info.ETVRConnected" )} { port } { Fore .RESET } '
0 commit comments