You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm trying to help a user in https://discourse.holoviz.org/t/streaming-local-video/6929. As I've seen questions about using server camera multiple times on discord I think its a good candidate for an Intermediate Streaming Tutorial.
I'm using a worker thread in a seperate module. But I've run into the issue that the --autoreload does not delete the existing worker thread when it reloads the module and starts a new worker thread. This is a big problem when using a camera as a camera can only be instantiated and used once, i.e. lots of exceptions are starting to be raised when two threads are trying to use it at the same time.
Please explain and document how to stop a thread when the module it is in is being autoreloaded.
Please do this by extending the documentation in Setup Manual Threading to include a reference example for setting up a thread outside of the main app.py file. I.e. a thread that is run once and results shared between all sessions.
Reproducible Example
pip install opencv panel pillow
server_video_stream.py
importcv2ascvimportpanelaspnfromPILimportImageimportparamimporttimeimportthreadingimportloggingimportsysFORMAT="%(asctime)s | %(levelname)s | %(name)s | %(message)s"@pn.cachedefget_logger(name, format_=FORMAT, level=logging.INFO):
logger=logging.getLogger(name)
logger.handlers.clear()
handler=logging.StreamHandler()
handler.setStream(sys.stdout)
formatter=logging.Formatter(format_)
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.propagate=Falselogger.setLevel(level)
logger.info("Logger successfully configured")
returnloggerclassAllReadyStarted(Exception):
"""Raised if the camera is already started"""classCannotOpenCamera(Exception):
"""Raised if the camera cannot be opened"""classCannotReadCamera(Exception):
"""Raised if the camera cannot be read"""classServerVideoStream(pn.viewable.Viewer):
value=param.Parameter(doc="String representation of the current snapshot")
paused=param.Boolean(default=False, doc="Whether the video stream is paused")
fps=param.Number(10, doc="Frames per second", inclusive_bounds=(0, None))
camera_index=param.Integer(0, doc="The index of the active camera")
def__init__(self, log_level=logging.INFO, **params):
super().__init__(**params)
self._cameras={}
self._stop_thread=Falseself._thread=threading.Thread(target=self._take_images)
self._thread.daemon=Trueself._logger=get_logger(f"ServerVideoStream {id(self)}", level=log_level)
defstart(self, camera_indicies):
ifcamera_indicies:
forindexincamera_indicies:
self._logger.debug("Getting Camera %s", index)
self.get_camera(index)
ifnotself._thread.is_alive():
self._logger.debug("Starting Camera Thread")
self._thread.start()
def__panel__(self):
settings=pn.Column(
self.param.paused,
self.param.fps,
self.param.camera_index,
width=300,
)
image=pn.pane.Image(self.param.value, sizing_mode="stretch_both")
returnpn.Row(settings, image)
@staticmethoddef_cv2_to_pil(bgr_image):
rgb_image=cv.cvtColor(bgr_image, cv.COLOR_BGR2RGB)
image=Image.fromarray(rgb_image)
returnimagedefget_camera(self, index):
ifindexinself._cameras:
returnself._cameras[index]
self._logger.debug("Camera %s Opening", index)
cap=cv.VideoCapture(index)
ifnotcap.isOpened():
raiseCannotOpenCamera(f"Cannot open the camera {index}")
self._cameras[index]=capself._logger.debug("Camera %s Opened", index)
returncapdef_take_image(self):
self._logger.debug("Taking image with camera %s", self.camera_index)
camera=self.get_camera(self.camera_index)
ret, frame=camera.read()
ifnotret:
raiseCannotReadCamera("Are you sure the camera exists and is not being read by other processes?")
else:
self.value=self._cv2_to_pil(frame)
def_take_images(self):
whilenotself._stop_thread:
start_time=time.time() # Record the start time of the captureifnotself.paused:
try:
self._take_image()
exceptExceptionasex:
self._logger.error("Error. Could not take image", exc_info=ex)
ifself.fps>0:
interval=1/self.fpselapsed_time=time.time() -start_timesleep_time=max(0, interval-elapsed_time)
time.sleep(sleep_time)
def__del__(self):
self._logger.debug("Stopping Camera Thread")
self._stop_thread=Trueifself._thread.is_alive():
self._thread.join()
self._logger.debug("Releasing Cameras")
forcamerainself._cameras.values():
camera.release()
cv.destroyAllWindows()
# some textserver_video_stream=ServerVideoStream(fps=3, log_level=logging.DEBUG)
server_video_stream.start(camera_indicies=[0])
# https://discourse.holoviz.org/t/best-practice-for-displaying-high-resolution-camera-images-captured-on-server/4285/12# https://discourse.holoviz.org/t/streaming-local-video/6929
MarcSkovMadsen
changed the title
Make it possible to use workerthread with --autoreload
Make it possible to use worker thread with --autoreload
Apr 14, 2024
As discussed elsewhere, I'd consider creating a worker thread a singleton in a module as bad practice. If you want to share a worker thread put it in the pn.state.cache.
I'm trying to help a user in https://discourse.holoviz.org/t/streaming-local-video/6929. As I've seen questions about using server camera multiple times on discord I think its a good candidate for an Intermediate Streaming Tutorial.
I'm using a worker thread in a seperate module. But I've run into the issue that the
--autoreload
does not delete the existing worker thread when it reloads the module and starts a new worker thread. This is a big problem when using a camera as a camera can only be instantiated and used once, i.e. lots of exceptions are starting to be raised when two threads are trying to use it at the same time.Please explain and document how to stop a thread when the module it is in is being autoreloaded.
Please do this by extending the documentation in Setup Manual Threading to include a reference example for setting up a thread outside of the main
app.py
file. I.e. a thread that is run once and results shared between all sessions.Reproducible Example
server_video_stream.py
script.py
# some text
in server_video_stream.py to# some texts
.video_stream_issue.mp4
The text was updated successfully, but these errors were encountered: