在tkinter中播放视频播放列表的问题

0 投票
2 回答
43 浏览
提问于 2025-04-14 15:42

我正在制作一个程序,当一个人说出某个单词时,程序会播放一个视频。如果说的单词和视频匹配,视频就会在一个tkinter标签中显示出来。我的问题是,当匹配到多个单词时,程序会同时播放所有匹配的视频。我想要的是让程序一个接一个地播放所有匹配的单词对应的视频。我正在使用tkinter和tkvideo。希望你能帮我解决这个问题。

dir = 'C:\\Users\\Usuario\\Desktop\\Prototipo\\palabras'
listaVid = []
with os.scandir(dir) as ficheros:
     for fichero in ficheros:
            listaVid.append(fichero.name.replace('.mp4',''))


def audioTexto():
    listener = sr.Recognizer()
    with sr.Microphone(device_index=0) as source:
        print("Escuchando...")
        audio = listener.listen(source)
        rec = listener.recognize_whisper(audio, language="spanish")
        trans_tab = dict.fromkeys(map(ord, u'\u0301\u0308'), None)
        rec = normalize('NFKC', normalize('NFKD', rec).translate(trans_tab))
        rec = re.sub(r'[.]', '', rec)
        palabras = rec.split(',')
    try:
        for palabra in palabras:
            for vid in listaVid:
                if vid in palabra:
                    player = tkvideo.tkvideo('C:\\Users\\Usuario\\Desktop\\Reconocimiento de voz\\palabras\\'+vid+'.mp4', lblVid,loop=0, size = (640,360))
                    player.play()
                                     
    except sr.UnknownValueError:
        print("No se entiende")
    except sr.RequestError as e:
        print("error")

root =Tk()
btnHablar = Button(root,text='Hablar..',command= audioTexto)
btnHablar.grid(column=0, row=0 , padx=5 ,pady=5)
lblVid = Label(root)
lblVid.grid(column=0,row=2,columnspan=2)
root.mainloop()

2 个回答

0

下面的代码会让每个匹配的视频立即播放。只需要把循环中的play去掉就行了。

for palabra in palabras:
    for vid in listaVid:
        if vid in palabra:
            # you are doing this on every iteration of the loops
            player = tkvideo.tkvideo('C:\\Users\\Usuario\\Desktop\\Reconocimiento de voz\\palabras\\'+vid+'.mp4', lblVid, loop=0, size = (640,360))
            player.play()

可以试试这样做:

VIDEO_PATH = 'C:\\Users\\Usuario\\Desktop\\Reconocimiento de voz\\palabras\\{}.mp4'

# create a queue of video paths for word
queue = [VIDEO_PATH.format(vid) for palabra in palabras for vid in listaVid if vid in palabra]

# get first path
video = queue[0] # or queue.pop(0)

# init player
player = tkvideo.tkvideo(video, lblVid, loop=0, size = (640,360))

# play
player.play()

我觉得这样找视频更合理,但只有你知道这些东西实际是怎么格式化的。

queue = [VIDEO_PATH.format(palabra) for palabra in palabras if palabra in listaVid]


为下一个播放列表项目创建触发器

为了把queue当作播放列表来播放,最简单的方法就是修改tkvideo。首先,修改__init__方法,让它可以接受一个回调函数。

def __init__(self, path, label, loop = 0, size = (640,360), hz = 0, callback = None):
    #... everything that is already in this method
    self.callback = callback

然后在load的最后调用这个callback。这样,当视频播放完毕时,你就会收到通知,可以播放下一个视频。

def load(self, path, label, loop, hz):
    #... everything that is already in this method
              
    if callable(self.callback):              
        self.callback()

使用方法

from tkvideo import tkvideo
import tkinter as tk


class App(tk.Tk):
    def __init__(self, **kwargs):
        tk.Tk.__init__(self)
        self.config(**kwargs)
        self.geometry('800x600')
        
        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)
        
        self.viewer = tk.Label(self)
        self.viewer.grid(sticky='nswe')

        self.playlist = ['one.mp4', 'two.mp4', 'three.mp4']
        self.next_vid() # start playing the playlist
        
    def next_vid(self):
        if self.playlist:
            player = tkvideo(self.playlist.pop(0), self.viewer, loop=0, size=(800,600), callback=self.next_vid)
            player.play()
        else:
            print('playlist consumed')
        
        
if __name__ == "__main__":
    App().mainloop()

如果你打算深入研究并修改tkvideo,我建议你添加一个可以处理整个播放列表的方法。所有需要的部分都在这篇文章里。你只需要调整一下位置,改变一下引用方式。

你可能还要考虑到tkvideo不播放声音,所以你基本上是把mp4当成gif来处理。由于视频之间加载的延迟,把mp4转换成gif可能更合适,并学习如何播放gif。

0

你需要把需要播放的视频放在一个列表里,然后一个一个地播放。

为了一个接一个地播放这些视频,你可以重写 tkvideo 类里的 load() 方法,这样当当前播放的视频结束时,就可以通过一个叫做 虚拟事件 的方式通知应用程序。应用程序收到这个虚拟事件后,就可以开始播放下一个视频。

下面是一个例子:

import tkinter as tk
import tkvideo

# create custom class based on tkvideo
class Player(tkvideo.tkvideo):
    # overload load()
    def load(self, path, label, loop):
        # call the original load()
        super().load(path, label, loop)
        # video ended, signal the application via virtual event
        label.event_generate("<<End>>")

# function to play a video in the playlist
def play():
    try:
        # get next video from the playlist
        video = next(playlist)
        print(f"{video=}")
        # play the video
        player = Player(video, playbox)
        player.play()
    except Exception as ex:
        # no more video to play
        print(f"{ex=}")

# create the playlist
playlist = iter(["1.mp4", "2.mp4", "3.mp4"])

root = tk.Tk()
playbox = tk.Label(root)
playbox.pack()
# call play() upon receiving virtual event "<<End>>"
playbox.bind("<<End>>", lambda e: play())
# play the first video
play()
tk.mainloop()

撰写回答