12
12
from config import BabbleConfig , BabbleSettingsConfig
13
13
from utils .misc_utils import get_camera_index_by_name , list_camera_names
14
14
from enum import Enum
15
+ import sys
15
16
16
17
WAIT_TIME = 0.1
18
+ BUFFER_SIZE = 32768
17
19
MAX_RESOLUTION : int = 600
18
-
19
20
# 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 "
26
26
ETVR_HEADER_LEN = 6
27
27
28
28
@@ -48,8 +48,6 @@ def __init__(
48
48
self .settings = settings
49
49
self .camera_index = camera_index
50
50
self .camera_list = list_camera_names ()
51
- # The variable is not used
52
- # self.camera_address = config.capture_source
53
51
self .camera_status_outgoing = camera_status_outgoing
54
52
self .camera_output_outgoing = camera_output_outgoing
55
53
self .capture_event = capture_event
@@ -59,15 +57,10 @@ def __init__(
59
57
60
58
self .serial_connection = None
61
59
self .last_frame_time = time .time ()
62
- self .frame_number = 0
63
60
self .fps = 0
64
61
self .bps = 0
65
62
self .start = True
66
63
self .buffer = b""
67
- self .pf_fps = 0
68
- self .prevft = 0
69
- self .newft = 0
70
- self .fl = [0 ]
71
64
self .FRAME_SIZE = [0 , 0 ]
72
65
73
66
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):
175
168
raise RuntimeError (lang ._instance .get_string ("error.frame" ))
176
169
self .FRAME_SIZE = image .shape
177
170
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
+
197
180
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 :
200
183
print (
201
184
f'{ Fore .YELLOW } [{ lang ._instance .get_string ("log.warn" )} ] { lang ._instance .get_string ("warn.captureProblem" )} { Fore .RESET } '
202
185
)
@@ -207,7 +190,7 @@ def get_next_packet_bounds(self):
207
190
beg = - 1
208
191
while beg == - 1 :
209
192
self .buffer += self .serial_connection .read (2048 )
210
- beg = self .buffer .find (ETVR_HEADER + ETVR_HEADER_FRAME )
193
+ beg = self .buffer .find (ETVR_HEADER )
211
194
# Discard any data before the frame header.
212
195
if beg > 0 :
213
196
self .buffer = self .buffer [beg :]
@@ -225,7 +208,8 @@ def get_next_jpeg_frame(self):
225
208
226
209
def get_serial_camera_picture (self , should_push ):
227
210
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 :
229
213
return
230
214
try :
231
215
if conn .in_waiting :
@@ -240,34 +224,25 @@ def get_serial_camera_picture(self, should_push):
240
224
f'{ Fore .YELLOW } [{ lang ._instance .get_string ("log.warn" )} ] { lang ._instance .get_string ("warn.frameDrop" )} { Fore .RESET } '
241
225
)
242
226
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
+
269
236
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
+
271
246
except Exception :
272
247
print (
273
248
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):
288
263
if not any (p for p in com_ports if port in p ):
289
264
return
290
265
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 )
294
268
# 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 )
296
270
297
271
print (
298
272
f'{ Fore .CYAN } [{ lang ._instance .get_string ("log.info" )} ] { lang ._instance .get_string ("info.ETVRConnected" )} { port } { Fore .RESET } '
0 commit comments