当前视频结束后,在 tkinter 帧中使用 vlc 播放新视频

Playing a new video with vlc in tkinter frame after current one ends

我目前正在处理我的第一个 python 项目,现在正在用 VLC 播放器碰壁。 我想要做的是让它通过 playRandomVideo() 方法(这有效)在文件夹中给定的一组文件的 tkinter 框架中播放随机 video,播放新的随机 video 通过 playRandomVideo() 方法当我按下一个按钮(也有效)并完全完成 video 时,触发相应的事件(也有效)并随机播放 video 通过 playRandomVideo() 方法(这个没有按预期工作)

如果我保留代码,它会在每次事件启动 video 时打开一个新的 window(如果我按下按钮,它将播放一个新的随机video 最近 window).

如果我通过将

修改为

来阻止 playRandomVideo() 方法创建新实例
if not hasattr(Window1, 'player'):
    Window1.player = Instance.media_player_new()

它会在执行 Window1.player.set_media(Media) 时冻结(在此行之前和之后添加了一个 print() 并且只打印了之前)

通过任何这些修改,在同一框架中启动新 video 的所有方法都有效,除了由事件启动它。

我想我需要做一些 pass 目前所在的事情,但我一辈子都想不出是什么。

完整相关代码:

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.: 当涉及到正确的代码格式时,请随时给我建议,我几乎是根据我从互联网上的随机代码片段中看到的,以及什么Atom 的 ide-python 包对我大喊大叫。

所以经过更多的研究,我偶然发现了这个 post: https://forum.videolan.org/viewtopic.php?t=80305

长话短说:VLC 播放器无法通过自己的事件向自己发送命令。 这导致了这段漂亮优雅的 咳咳 修复问题的代码:

# >>> 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()

简而言之:永久守护线程检查 vidOver 是否已更改为 True 并在更改时启动 playRandomVideo() 方法。事件处理程序只是将 vidOver 更改为 True

我对它的效率不是很满意,所以如果有人提出更优雅的解决方案,我仍然会欣赏新的想法。