@@ -573,31 +573,37 @@ def detect_scenes(
573573 frame_im = None
574574
575575 logger .info ("Detecting scenes..." )
576- while not self ._stop .is_set ():
577- next_frame , position = frame_queue .get ()
578- if next_frame is None and position is None :
579- break
580- if next_frame is not None :
581- frame_im = next_frame
582- assert frame_im is not None
583- new_cuts = self ._process_frame (position , frame_im , callback )
576+ try :
577+ while not self ._stop .is_set ():
578+ next_frame , position = frame_queue .get ()
579+ if next_frame is None and position is None :
580+ break
581+ if next_frame is not None :
582+ frame_im = next_frame
583+ assert frame_im is not None
584+ new_cuts = self ._process_frame (position , frame_im , callback )
585+ if progress_bar is not None :
586+ if new_cuts :
587+ progress_bar .set_description (
588+ PROGRESS_BAR_DESCRIPTION % len (self ._cutting_list ), refresh = False
589+ )
590+ progress_bar .update (1 + frame_skip )
591+ finally :
584592 if progress_bar is not None :
585- if new_cuts :
586- progress_bar .set_description (
587- PROGRESS_BAR_DESCRIPTION % len (self ._cutting_list ), refresh = False
588- )
589- progress_bar .update (1 + frame_skip )
590-
591- if progress_bar is not None :
592- progress_bar .set_description (
593- PROGRESS_BAR_DESCRIPTION % len (self ._cutting_list ), refresh = True
594- )
595- progress_bar .close ()
596- # Unblock any puts in the decode thread before joining. This can happen if the main
597- # processing thread stops before the decode thread.
598- while not frame_queue .empty ():
599- frame_queue .get_nowait ()
600- decode_thread .join ()
593+ progress_bar .set_description (
594+ PROGRESS_BAR_DESCRIPTION % len (self ._cutting_list ), refresh = True
595+ )
596+ progress_bar .close ()
597+ # The decode thread must never be abandoned, even if a detector or callback
598+ # raises above: an orphaned daemon thread keeps the VideoStream alive until
599+ # interpreter shutdown, where finalizing it (or killing the thread mid-decode)
600+ # can crash process exit. Signal it to stop, then keep unblocking any pending
601+ # puts until it exits.
602+ self ._stop .set ()
603+ while decode_thread .is_alive ():
604+ while not frame_queue .empty ():
605+ frame_queue .get_nowait ()
606+ decode_thread .join (timeout = 0.1 )
601607
602608 if self ._exception_info is not None :
603609 exc = self ._exception_info [1 ]
0 commit comments