The code below selects and plays in slow motion the last 8 seconds of a video.
Problem:
When the the button clean is pressed, it resets the video path, and allows for selecting a new video (path) by pressing select button again.
However, when the button play slow motion is pressed, it doesn't play anything after the new video is selected. What could be causing this?
import tkinter as tk
from tkinter import filedialog
import cv2
import threading
from PIL import Image, ImageTk
class VideoPlayerApp:
def __init__(self, root):
self.root = root
self.root.title("Multimedia")
self.root.geometry("900x542+200+1")
self.right_frame = tk.Frame(self.root, bg="#2271b3")
self.right_frame.place(relx=0.8333, rely=0, relwidth=0.1667, relheight=1)
button_height = 0.15
button_spacing = 0.08
self.select_button = tk.Button(self.right_frame, text="Select video", command=self.select_video, height=2, width=15)
self.select_button.place(relx=0.5, rely=button_height, anchor=tk.CENTER)
self.play_button = tk.Button(self.right_frame, text="Play Slow Motion", command=self.play_slow, height=2, width=15)
self.play_button.place(relx=0.5, rely=button_height + button_spacing, anchor=tk.CENTER)
self.freeze_button = tk.Button(self.right_frame, text="Freeze", command=self.freeze_video, height=2, width=15)
self.freeze_button.place(relx=0.5, rely=button_height + 2*button_spacing, anchor=tk.CENTER)
self.clean_button = tk.Button(self.right_frame, text="Clean", command=self.clean_video, height=2, width=15)
self.clean_button.place(relx=0.5, rely=button_height + 3*button_spacing, anchor=tk.CENTER) # New clean button
self.left_frame = tk.Frame(self.root)
self.left_frame.place(relx=0, rely=0, relwidth=0.8333, relheight=1)
self.video_label = None # Placeholder for video label
self.paused = False
self.video_path = None # Initialize video path
# Add white frames to right frame
self.white_frame_top_right = tk.Frame(self.right_frame, bg="white")
self.white_frame_top_right.place(relx=0, rely=0, relwidth=1, relheight=0.05)
self.white_frame_bottom_right = tk.Frame(self.right_frame, bg="white")
self.white_frame_bottom_right.place(relx=0, rely=0.95, relwidth=1, relheight=0.05)
def select_video(self):
self.video_path = filedialog.askopenfilename(filetypes=[("Video files", "*.mp4 *.avi *.mov")])
def play_slow(self):
if self.video_path:
threading.Thread(target=self.play_video_slow).start()
def freeze_video(self):
self.paused = not self.paused
def clean_video(self):
self.paused = True
if self.video_label:
self.video_label.destroy() # Eliminate the current video label
self.video_label = None # Reset to None
self.video_path = None # Reset video path
def play_video_slow(self):
if self.video_path:
cap = cv2.VideoCapture(self.video_path)
fps = int(cap.get(cv2.CAP_PROP_FPS))
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
duration = 8
start_frame = total_frames - (duration * fps)
if start_frame < 0:
start_frame = 0
cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
while True:
if self.paused:
continue
ret, frame = cap.read()
if not ret:
break
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img_pil = Image.fromarray(frame)
img_pil = img_pil.resize((self.left_frame.winfo_width(), self.left_frame.winfo_height()), Image.ANTIALIAS)
img = ImageTk.PhotoImage(image=img_pil)
if not self.video_label: # If video label does not exist, create it
self.video_label = tk.Label(self.left_frame, image=img)
self.video_label.image = img # Keep a reference to the image to prevent garbage collection
self.video_label.place(relx=0, rely=0, relwidth=1, relheight=1)
else:
self.video_label.configure(image=img) # Update the existing video label
self.video_label.image = img # Keep a reference to the image to prevent garbage collection
if cv2.waitKey(3900 // fps) & 0xFF == ord('q'):
break
cap.release()
if __name__ == "__main__":
root = tk.Tk()
app = VideoPlayerApp(root)
root.mainloop()