Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Make MJPEG stream sources actually connect. #92

Merged
merged 7 commits into from
Feb 6, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 11 additions & 14 deletions BabbleApp/camera.py
Original file line number Diff line number Diff line change
@@ -10,10 +10,9 @@
from enum import Enum
import serial.tools.list_ports
from lang_manager import LocaleStringManager as lang

from colorama import Fore
from config import BabbleConfig, BabbleSettingsConfig
from utils.misc_utils import get_camera_index_by_name, list_camera_names
from utils.misc_utils import get_camera_index_by_name, list_camera_names, is_nt

from vivefacialtracker.vivetracker import ViveTracker
from vivefacialtracker.camera_controller import FTCameraController
@@ -95,6 +94,7 @@ def run(self):
self.config.capture_source is not None
and self.config.capture_source != ""
):
self.current_capture_source = self.config.capture_source
isSerial = any(x in str(self.config.capture_source) for x in PORTS)

if isSerial:
@@ -103,7 +103,7 @@ def run(self):
self.cv2_camera = None
if self.vft_camera is not None:
self.vft_camera.close()
self.device_is_vft = False;
self.device_is_vft = False
if (
self.serial_connection is None
or self.camera_status == CameraState.DISCONNECTED
@@ -116,7 +116,7 @@ def run(self):
if self.cv2_camera is not None:
self.cv2_camera.release()
self.cv2_camera = None
self.device_is_vft = True;
self.device_is_vft = True

if self.vft_camera is None:
print(self.error_message.format(self.config.capture_source))
@@ -141,18 +141,18 @@ def run(self):
self.cv2_camera is None
or not self.cv2_camera.isOpened()
or self.camera_status == CameraState.DISCONNECTED
or get_camera_index_by_name(self.config.capture_source) != self.current_capture_source
#or get_camera_index_by_name(self.config.capture_source) != self.current_capture_source
or self.config.capture_source != self.current_capture_source
):
if self.vft_camera is not None:
self.vft_camera.close()
self.device_is_vft = False;
self.device_is_vft = False

print(self.error_message.format(self.config.capture_source))
# This requires a wait, otherwise we can error and possible screw up the camera
# firmware. Fickle things.
if self.cancellation_event.wait(WAIT_TIME):
return

if self.config.capture_source not in self.camera_list:
self.current_capture_source = self.config.capture_source
else:
@@ -163,9 +163,8 @@ def run(self):
self.current_capture_source, cv2.CAP_FFMPEG
)
else:
self.cv2_camera = cv2.VideoCapture(
self.current_capture_source
)
self.cv2_camera = cv2.VideoCapture()
self.cv2_camera.open(self.current_capture_source)

if not self.settings.gui_cam_resolution_x == 0:
self.cv2_camera.set(
@@ -181,7 +180,6 @@ def run(self):
self.cv2_camera.set(
cv2.CAP_PROP_FPS, self.settings.gui_cam_framerate
)

should_push = False
else:
# We don't have a capture source to try yet, wait for one to show up in the GUI.
@@ -215,15 +213,14 @@ def get_camera_picture(self, should_push):
return
self.frame_number = self.frame_number + 1
elif self.cv2_camera is not None and self.cv2_camera.isOpened():
ret, image = self.cv2_camera.read()
ret, image = self.cv2_camera.read() # MJPEG Stream reconnects are currently limited by the hard coded 30 second timeout time on VideoCapture.read(). We can get around this by recompiling OpenCV or using a custom MJPEG stream imp.
if not ret:
self.cv2_camera.set(cv2.CAP_PROP_POS_FRAMES, 0)
raise RuntimeError(lang._instance.get_string("error.frame"))
self.frame_number = self.cv2_camera.get(cv2.CAP_PROP_POS_FRAMES) + 1
else:
# Switching from a Vive Facial Tracker to a CV2 camera
return

self.FRAME_SIZE = image.shape
# Calculate FPS
current_frame_time = time.time() # Should be using "time.perf_counter()", not worth ~3x cycles?
@@ -361,4 +358,4 @@ def push_image_to_queue(self, image, frame_number, fps):
f'{Fore.YELLOW}[{lang._instance.get_string("log.warn")}] {lang._instance.get_string("warn.backpressure1")} {qsize}. {lang._instance.get_string("warn.backpressure2")}{Fore.RESET}'
)
self.camera_output_outgoing.put((self.clamp_max_res(image), frame_number, fps))
self.capture_event.clear()
self.capture_event.clear()