I have a program that displays video in a tkinter window. When i want to close window i stopping video thread. But it doesn't stop. There are four functions:
def start_video(self):
if self.video is not None:
self.video_thread_stopped = False
try:
if not self.video_thread.is_alive():
self.video_thread = threading.Thread(target=self.video_stream)
self.video_thread.start()
except AttributeError:
if self.video_thread is None:
self.video_thread = threading.Thread(target=self.video_stream)
self.video_thread.start()
start_video function starts video thread
def video_stream(self):
_, frame = self.video.read()
str_time = time.time()
while frame is not None and getattr(self.video_thread, "running", True):
self.current_frame += 1
# resize and set image to label
frame = cv2.resize(frame, self.video_frame_size)
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
imgtk = ImageTk.PhotoImage(image=Image.fromarray(cv2image))
self.video_label.config(image=imgtk)
self.video_label.image = imgtk
# waiting for frame rate
while time.time() - str_time < (1 / self.fps):
pass
str_time = time.time()
# reading next frame
_, frame = self.video.read()
print("exited from loop")
video_stream is the thread function
def pause_video(self):
if self.video_loaded:
self.video_thread_stopped = True
if self.video_thread is not None:
# stop video
self.video_thread.running = False
print('before join')
start_time = time.time()
while self.video_thread.is_alive():
if time.time() - start_time > 1:
break
print("after while")
self.video_thread.join()
print('after join')
pause_video has to kill thread and stop streaming video
def on_window_close(self):
self.pause_video()
print("thread stopped")
self.root.destroy()
on_window_close has to stop thread before closing tk window (I have the following code)
root.protocol("WM_DELETE_WINDOW", w.on_window_close)
So when I start video thread and pressing a close button on the tk window - thread doesn't stop. Here is a terminal output
before join
after while
Can someone help me and tell why it doesn't stop the video_thread. Thanks!
I found the solution. In the start_video method you have to make video_thread daemon:
def start_video(self):
if self.video is not None:
self.video_thread_stopped = False
try:
if not self.video_thread.is_alive():
self.video_thread = threading.Thread(target=self.video_stream)
self.video_thread.daemon = 1
# start audio
self.audio_class.start(self.current_frame, self.total_video_frames)
# start thread
self.video_thread.start()
except AttributeError:
if self.video_thread is None:
self.video_thread = threading.Thread(target=self.video_stream)
self.video_thread.daemon = 1
# start audio
self.audio_class.start(self.current_frame, self.total_video_frames)
# start thread
self.video_thread.start()
And in the pause_video method you need to remove line with video_thread.join()
def pause_video(self):
if self.video_loaded:
self.video_thread_stopped = True
if self.video_thread is not None:
# stop audio
# stop video
self.video_thread.running = False
print("video stopped")
self.audio_class.stop()
print("audio stopped")
# print('before join')
start_time = time.time()
while self.video_thread.is_alive():
# print("waiting for none")
if time.time() - start_time > 1:
# self.video_thread = None
break