I'm currently working on my first python project and am hitting a brick wall with the VLC player right now.
What I want to do is have it play a random video in a tkinter frame from a given set of files in a folder via the playRandomVideo()
method (this works), play a new random video via the playRandomVideo()
method method when I press a button (also works) and upon completely finishing a video, trigger the corresponding event (also works) and play a random video via the playRandomVideo()
method (this one's not working as intended)
If I leave the code as seen, it will open a new window for every time a video is started by the event (if I press the button it will play a new random video in the latest window).
If I stop the playRandomVideo()
method from creating a new instance by modifying it to
if not hasattr(Window1, 'player'):
Window1.player = Instance.media_player_new()
it will freeze when doing Window1.player.set_media(Media) (added a print() before and after this line and only the before was printed)
With any of those modifications every way of starting a new video in the same frame works, except having it started by the event.
I think that I need to do something where the pass
currently is, but I can't for the life of me figure out what.
Full relevant code:
from tkinter import Tk, ttk, Frame, Button
import os
import threading
from threading import Thread
from glob import glob
import random
import vlc
class MainWindow(Thread):
def __init__(self):
Thread.__init__(self)
print(threading.current_thread())
def run(self):
self.mw = Tk()
self.mw.title('Python Guides')
self.mw.geometry('1200x720')
self.display = Frame(self.mw, bd=5)
self.display.place(relwidth=1, relheight=1)
Button(self.mw, text='Next', padx=10,
command=Window1.playRandomVideo).grid(row=1, columnspan=5, pady=5)
self.mw.mainloop()
def playRandomVideo(self):
fl = glob("C:\\BDFR\\downloads\\*\\*.mp4")
videoPath = ""
if len(fl) > 0:
random_index = random.randrange(len(fl))
videoPath = fl[random_index]
if os.path.exists(videoPath) is True:
if hasattr(Window1, 'player'):
if Window1.player.is_playing() == 1:
Window1.player.stop()
if Window1.player.is_playing() == 0:
pass
Instance = vlc.Instance()
Window1.player = Instance.media_player_new()
Media = Instance.media_new(videoPath)
Window1.player.set_hwnd(Window1.display.winfo_id())
Window1.player.set_media(Media)
Window1.player.play()
# Event Manager for end of media
Window1.events = Window1.player.event_manager()
Window1.events.event_attach(vlc.EventType.MediaPlayerEndReached, Window1.EventManager)
def EventManager(self, event):
if event.type == vlc.EventType.MediaPlayerEndReached:
print("Event reports - finished, playing next")
Window1.playRandomVideo()
Window1 = MainWindow()
Window1.start()
Window1.playRandomVideo()
P.S.: Feel free to give me advice when it comes to proper code formating, I'm pretty much winging it based on what I've seen from random code snippets on the internet, and what Atom's ide-python package shouts at me for.
CodePudding user response:
So after a a good bit more research I stumbled upon this post: https://forum.videolan.org/viewtopic.php?t=80305
Long story short: VLC player can't send a comand to itself through it's own event. Which lead to this beautifully elegant cough piece of code that fixes the problem:
# >>> class definition of MainWindow from original question here <<<
# Event Manager for end of media
if not hasattr(self, "events"):
self.events = self.player.event_manager()
self.events.event_attach(vlc.EventType.MediaPlayerEndReached,
EventManager)
vidOver = False
def EventManager(event):
if event.type == vlc.EventType.MediaPlayerEndReached:
# print("Event reports - finished, playing next")
global vidOver
vidOver = True
def newVid(object):
global vidOver
vidOver = False
while 1:
if vidOver is True:
vidOver = False
object.playRandomVideo()
time.sleep(0.2)
Window1 = MainWindow()
Window1.start()
time.sleep(0.2)
threading.Thread(target=newVid, args=(Window1,), daemon=True).start()
Window1.playRandomVideo()
In short: A permanent daemon thread checks whether vidOver
has been changed to True
and starts the playRandomVideo()
method when it is. The event handler does nothing more than changint vidOver
to True
I'm not terribly happy with the efficiency of this, so if someone comes up with a more elegant solution I would still apprechiate new ideas.