在tkinter中播放视频播放列表的问题
我正在制作一个程序,当一个人说出某个单词时,程序会播放一个视频。如果说的单词和视频匹配,视频就会在一个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()