Watch for broken frames using JPEG end bytes, and log error

This commit is contained in:
Joel Collins 2020-12-08 18:07:05 +00:00
parent d2488c566a
commit 68380385cb

View file

@ -8,6 +8,7 @@ from typing import BinaryIO, List, NamedTuple, Optional, Tuple, Type, Union
from labthings import ClientEvent, StrictLock from labthings import ClientEvent, StrictLock
JPEG_END_BYTES: bytes = b"\xff\xd9"
# Class to store a frames metadata # Class to store a frames metadata
class TrackerFrame(NamedTuple): class TrackerFrame(NamedTuple):
@ -42,6 +43,8 @@ class FrameStream(io.BytesIO):
# We use a ClientEvent so that each thread can call getvalue() independantly # We use a ClientEvent so that each thread can call getvalue() independantly
self.new_frame: ClientEvent = ClientEvent() self.new_frame: ClientEvent = ClientEvent()
self._bad_frame: bool = False
def __enter__(self): def __enter__(self):
self.start_tracking() self.start_tracking()
return super().__enter__() return super().__enter__()
@ -79,6 +82,20 @@ class FrameStream(io.BytesIO):
3. Store the new frame image 3. Store the new frame image
4. Set the new_frame event 4. Set the new_frame event
""" """
# If we get a bad frame, and the last frame was good
if s[-2:] != JPEG_END_BYTES and not self._bad_frame:
# TODO: Handle this more cleverly. Automatically lower bitrate to compensate?
# Log error
logging.error(
"Incomplete frame data recieved. Camera bandwidth may have been exceeded. Consider lowing resolution, framerate, or target bitrate."
)
# Record that last frame was bad
self._bad_frame = True
# If the last frame was bad, but this frame was good
elif self._bad_frame and s[-2:] == JPEG_END_BYTES:
# Clear the bad frame record
self._bad_frame = False
# If we're tracking frame size
if self.tracking: if self.tracking:
frame = TrackerFrame(size=len(s), time=time.time()) frame = TrackerFrame(size=len(s), time=time.time())
self.frames.append(frame) self.frames.append(frame)