#python #video #tkinter #raspberry-pi3
#python #Видео #tkinter #raspberry-pi3
Вопрос:
Я пытаюсь запустить / остановить видеофайл в tkinter на raspberry pi, используя python 3.
Мне нужно, чтобы видео начиналось с начала каждый раз, когда инфракрасный датчик разряжен (сломан), и останавливалось, как только датчик снова становится высоким. В идеале видео должно находиться внутри tkinter canvas, чтобы я мог одновременно отображать на экране другие элементы (например, панель загрузки).
Мне удалось запустить все, кроме видео, которое запускается сразу после обнаружения датчика, но оно замораживает все остальные процессы (например, панель загрузки) и не останавливается при высоком уровне датчика.
вот упрощенная (и непроверенная) версия кода, позволяющая получить представление об общей структуре (реальный код намного длиннее):
import tkinter as TK
import RPi.GPIO as GPIO
import os
GPIO.setmode(GPIO.BCM)
GPIO.setup(14, GPIO.IN)
class App:
def __init__(self, root):
self.root = root
self.root.config(background = 'black', cursor = 'none')
self.background = TK.Canvas(root, width = 1024, height = 600, bg = 'black')
self.background.pack()
self.ext = 0
self.trial = 0
self.infrared()
def infrared(self):
if (GPIO.input(14) == False):
self.makebar()
if (self.ext == 0):
self.runvideo()
else:
os.system("killall omxplayer.bin")
self.ext = 0
self.root.after(16, self.infrared)
def runvideo(self):
os.system("omxplayer /home/pi/Desktop/testvideo.m4v")
def makebar():
self.stimulus_rect = TK.Canvas(root, width = 1024, height = 50, bg= 'white')
if self.ext < 1000
self.ext = self.ext 10
self.stimulus_rect.create_rectangle(0, 0, self.ext, 50, fill="red")
self.stimulus_rect.place(x=0, y=0, anchor="new")
else:
self.trial = self.trial 1
self.ext = 0
root = TK.Tk()
App(root)
root.mainloop()
Из того, что я смог найти в Интернете:
1) tkinter может быть связан с opencv для достижения этой цели, но не похоже, что установка opencv на raspberry pi является простой операцией;
2) В общем случае параметры, связанные с «os», похоже, обречены на неудачу в том, чего я хочу достичь.
Я не смог найти чистый способ сделать это. Сценарием моей мечты было бы загружать в canvas видеокадры один за другим и делать это с частотой 60 Гц (частота экрана). Затем я бы проверил датчик точно с той же частотой и предотвратил загрузку следующего кадра, если датчик не поврежден. В псевдокоде это выглядело бы так
def infrared(self):
if (GPIO.input(14) == False):
self.makebar()
if (self.ext == 0):
self.runvideo()
else:
self.video.stop
self.ext = 0
self.frame = 0
self.root.after(16, self.infrared)
def runvideo(self):
self.frame = self.frame 1
video.run("testvideo.m4v", self.frame)
Есть идеи о том, как добиться этого в tkinter на raspberry pi?
спасибо ant
Ответ №1:
После недели исследований, проб и ошибок вот как я в настоящее время достигаю того, что мне было нужно (в псевдокоде):
#### PSEUDOCODE ####
from subprocess import Popen # this library is used to open the video file
class App:
def __init__(self, root):
self.moviestart = False
self.movieduration = 130000
self.movie = "/home/pi/Desktop/test.mp4"
def infrared(self):
if (GPIO.input(IR) == False):
if not self.moviestart:
self.makevideo() # Call the function to start the video
self.moviestart = True # Flag that the video has started
self.moviestop = False # Flag that the video is currently playing
self.root.after(self.videoduration,
self.stopvideo) # manually call the stop video function
# to stop the video after 13 seconds (video's length).
# I could not find a more elegant way of doing this, unfortunately.
else:
self.clear_screen()
self.root.after(self.refreshIR, self.infrared)
def makevideo(self):
# popen will open the movie in a window of the size I specified,
# so that other element from tkinter can be placed on top of the movie window
omxc = Popen(['omxplayer', self.movie, '--win', "0 30 800 450"])
def stopvideo(self):
self.moviestart = False # flag that movie has been stopped
if (self.moviestop == False): # check if the movie is currently playing
try: # this is a cheap workaround other problems I had, do not try this at home
os.system('killall omxplayer.bin') # this literally kills any omxplayer instance
# currently open
self.moviestop = True # flag that the movie is not playing at the moment
except:
pass
Я надеюсь, что это может быть полезно кому-либо еще с подобными проблемами. Я обновлю ответ, если найду лучшее решение. На данный момент это работает достаточно хорошо.