quick fix 2
This commit is contained in:
309
Lib/site-packages/bvPlayer/VideoPlayer.py
Normal file
309
Lib/site-packages/bvPlayer/VideoPlayer.py
Normal file
@ -0,0 +1,309 @@
|
||||
import cv2
|
||||
import random
|
||||
import time
|
||||
from decimal import Decimal
|
||||
from tkinter import *
|
||||
from ffpyplayer.player import MediaPlayer
|
||||
from PIL import Image, ImageTk
|
||||
import tempfile
|
||||
import threading
|
||||
import queue
|
||||
import os
|
||||
import sys
|
||||
import contextlib
|
||||
|
||||
class VideoPlayer:
|
||||
def __init__(self, root, file, **kwargs):
|
||||
|
||||
self.dest = file
|
||||
self.cap = cv2.VideoCapture(self.dest)
|
||||
|
||||
self.frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
||||
self.fps = self.cap.get(cv2.CAP_PROP_FPS)
|
||||
self.newfps = self.fps
|
||||
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
||||
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
||||
|
||||
self.root = root
|
||||
self.root.overrideredirect(1)
|
||||
self.root.geometry('+0+0')
|
||||
self.resize = False
|
||||
self.root.withdraw()
|
||||
|
||||
for k, val in kwargs.items():
|
||||
if k == "fps":
|
||||
if val > self.fps:
|
||||
print("Error: requested FPS is higher than file FPS")
|
||||
self.root.destroy()
|
||||
return
|
||||
self.newfps = val
|
||||
elif k == "pos":
|
||||
self.root.geometry("+%d+%d" %val)
|
||||
elif k == "draggable" and val == True:
|
||||
self.root.bind('<Button-1>',self.clickPos)
|
||||
self.root.bind('<B1-Motion>', self.dragWin)
|
||||
self.clickx = None
|
||||
self.clicky = None
|
||||
elif k == "dim":
|
||||
if (val[0] == self.width and val[1] == self.height):
|
||||
continue
|
||||
self.width = val[0]
|
||||
self.height = val[1]
|
||||
self.resize = True
|
||||
elif k == "videoOptions" and val == True:
|
||||
self.root.bind('<Button-3>', self.options)
|
||||
|
||||
def play(self):
|
||||
self.root.deiconify()
|
||||
|
||||
self.canvas = Canvas(self.root, width = self.width, height = self.height)
|
||||
self.canvas.pack()
|
||||
|
||||
self.fr_lock = threading.Lock()
|
||||
self.frames_read = queue.Queue()
|
||||
self.frame_files = queue.Queue() # list of temp files
|
||||
self.frame_times = []
|
||||
self.kill_threads = False
|
||||
|
||||
self.player = MediaPlayer(self.dest)
|
||||
self.player.set_pause(True)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
self.t1 = threading.Thread(target=self.readFrames)
|
||||
self.t2 = threading.Thread(target=self.writeFrames)
|
||||
self.t3 = threading.Thread(target=self.writeFrames)
|
||||
|
||||
self.t1.start()
|
||||
time.sleep(2)
|
||||
self.t2.start()
|
||||
self.t3.start()
|
||||
time.sleep(1)
|
||||
|
||||
self.playVideo()
|
||||
|
||||
self.t1.join()
|
||||
self.t2.join()
|
||||
self.t3.join()
|
||||
|
||||
def clickPos(self, event):
|
||||
time.sleep(.2)
|
||||
self.clickx = event.x
|
||||
self.clicky = event.y
|
||||
|
||||
def dragWin(self,event):
|
||||
winx = self.root.winfo_x()
|
||||
winy = self.root.winfo_y()
|
||||
|
||||
x = event.x - self.clickx + winx
|
||||
y = event.y - self.clicky + winy
|
||||
self.root.geometry("+%d+%d" %(x,y))
|
||||
|
||||
def kill(self):
|
||||
self.kill_threads = True
|
||||
time.sleep(1)
|
||||
self.player.set_pause(True)
|
||||
self.root.destroy()
|
||||
os._exit(1)
|
||||
|
||||
def options(self,event):
|
||||
|
||||
def restart():
|
||||
os.execl(sys.executable, sys.executable, *sys.argv)
|
||||
|
||||
m = Menu(self.root, tearoff = 0)
|
||||
m.add_command(label = "restart", command = restart)
|
||||
m.add_command(label = "quit", command=self.kill)
|
||||
m.tk_popup(event.x_root, event.y_root)
|
||||
|
||||
def randSelect(self):
|
||||
frameList = []
|
||||
accuracy = 2
|
||||
|
||||
ratio = round(self.newfps/self.fps,accuracy)
|
||||
dec_ratio = Decimal(str(ratio))
|
||||
self.newfps = ratio*self.fps
|
||||
b = (dec_ratio).as_integer_ratio()
|
||||
|
||||
frame_guarantee = b[0]
|
||||
frame_chunk = b[1]
|
||||
|
||||
for i in range(1, self.frames, frame_chunk):
|
||||
select = range(i,i+frame_chunk-1)
|
||||
samp = random.sample(select,frame_guarantee)
|
||||
samp.sort()
|
||||
frameList.extend(samp)
|
||||
|
||||
return frameList
|
||||
|
||||
def generateFrameTimes(self):
|
||||
newFrames = int(self.frames * self.newfps/self.fps)
|
||||
|
||||
targetTime = 1/self.newfps
|
||||
times = 0
|
||||
|
||||
for i in range(newFrames):
|
||||
self.frame_times.append(times)
|
||||
times += targetTime
|
||||
|
||||
def readFrames(self):
|
||||
if(self.fps == self.newfps):
|
||||
self.generateFrameTimes()
|
||||
while(self.cap.isOpened()):
|
||||
if(self.kill_threads == True):
|
||||
return
|
||||
|
||||
if(self.frames_read.qsize() > 10):
|
||||
time.sleep(.01)
|
||||
continue
|
||||
|
||||
ret, frame = self.cap.read()
|
||||
if ret == True:
|
||||
self.frames_read.put(frame)
|
||||
else:
|
||||
break
|
||||
else:
|
||||
|
||||
select_list = self.randSelect()
|
||||
self.generateFrameTimes()
|
||||
|
||||
counter = 0
|
||||
walker = 0
|
||||
|
||||
while(self.cap.isOpened()):
|
||||
if(self.kill_threads == True):
|
||||
return
|
||||
|
||||
if(self.frames_read.qsize() > 10):
|
||||
time.sleep(.01)
|
||||
continue
|
||||
|
||||
counter += 1
|
||||
ret, frame = self.cap.read()
|
||||
if ret == False:
|
||||
break
|
||||
|
||||
if(select_list[walker] == counter):
|
||||
self.frames_read.put(frame)
|
||||
|
||||
walker += 1
|
||||
|
||||
# https://stackoverflow.com/questions/13379742/
|
||||
# right-way-to-clean-up-a-temporary-folder-in-python-class
|
||||
@contextlib.contextmanager
|
||||
def make_temp_directory(self):
|
||||
temp_dir = tempfile.TemporaryDirectory()
|
||||
try:
|
||||
yield temp_dir
|
||||
finally:
|
||||
temp_dir.cleanup()
|
||||
|
||||
def writeFrames(self):
|
||||
|
||||
with self.make_temp_directory() as temp_dir:
|
||||
while True:
|
||||
|
||||
if(self.kill_threads == True):
|
||||
temp_dir.cleanup()
|
||||
return
|
||||
|
||||
if self.frame_files.qsize() > 20:
|
||||
time.sleep(.1)
|
||||
continue
|
||||
|
||||
p = tempfile.NamedTemporaryFile('wb', suffix = '.jpg',
|
||||
dir = temp_dir.name,
|
||||
delete = False)
|
||||
|
||||
with self.fr_lock:
|
||||
if self.frames_read.empty():
|
||||
break
|
||||
|
||||
frame = self.frames_read.get()
|
||||
self.frame_files.put(p)
|
||||
|
||||
if self.resize == True:
|
||||
frame = cv2.resize(frame, (self.width,self.height),
|
||||
interpolation = cv2.INTER_AREA)
|
||||
|
||||
cv2.imwrite(p.name,frame)
|
||||
p.close()
|
||||
|
||||
def playVideo(self):
|
||||
counter = 0
|
||||
|
||||
fps = self.newfps # for testing max frame rate
|
||||
print(fps)
|
||||
targetTime = 1/fps
|
||||
|
||||
img = None
|
||||
pop = None
|
||||
self.player.set_pause(False)
|
||||
|
||||
# load up the audio
|
||||
audio_frame, val = self.player.get_frame()
|
||||
while audio_frame == None:
|
||||
audio_frame, val = self.player.get_frame()
|
||||
|
||||
running_time = time.time()
|
||||
while(not self.frame_files.empty()):
|
||||
|
||||
if(self.kill_threads == True):
|
||||
return
|
||||
|
||||
audio_frame, val = self.player.get_frame()
|
||||
|
||||
if(val == 'eof' or len(self.frame_times) == 0):
|
||||
break
|
||||
|
||||
if(audio_frame == None):
|
||||
continue
|
||||
|
||||
# for any lag due to cpu, especially for dragging
|
||||
if(self.frame_files.qsize() < 5):
|
||||
time.sleep(.08)
|
||||
|
||||
t = self.frame_times.pop(0)
|
||||
pop = self.frame_files.get()
|
||||
|
||||
cur_time = time.time() - running_time
|
||||
delay = t - cur_time
|
||||
|
||||
# frame skipping
|
||||
if (delay < -targetTime):
|
||||
os.remove(pop.name)
|
||||
continue
|
||||
|
||||
prevIm = img
|
||||
|
||||
# diplay image
|
||||
self.canvas.delete("all")
|
||||
|
||||
try:
|
||||
load = Image.open(pop.name)
|
||||
except:
|
||||
os.remove(pop.name)
|
||||
continue
|
||||
|
||||
#load.draft("RGB",(2560,1080)) # doesn't do anything?
|
||||
render = ImageTk.PhotoImage(load)
|
||||
img = Label(image=render)
|
||||
img.image = render
|
||||
img.place(x=0, y=0)
|
||||
load.close()
|
||||
pop.close()
|
||||
|
||||
os.remove(pop.name)
|
||||
|
||||
self.root.update()
|
||||
|
||||
if prevIm != None:
|
||||
prevIm.destroy()
|
||||
|
||||
cur_time = time.time() - running_time
|
||||
delay = t - cur_time
|
||||
|
||||
if (delay > targetTime):
|
||||
time.sleep(targetTime)
|
||||
|
||||
self.kill()
|
||||
1
Lib/site-packages/bvPlayer/__init__.py
Normal file
1
Lib/site-packages/bvPlayer/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .bvPlayer import bvPlayer
|
||||
14
Lib/site-packages/bvPlayer/bvPlayer.py
Normal file
14
Lib/site-packages/bvPlayer/bvPlayer.py
Normal file
@ -0,0 +1,14 @@
|
||||
from tkinter import *
|
||||
from . import VideoPlayer
|
||||
|
||||
class bvPlayer:
|
||||
def __init__(self, file, **kwargs):
|
||||
root = Tk()
|
||||
player = VideoPlayer.VideoPlayer(root, file, **kwargs)
|
||||
|
||||
try:
|
||||
player.play()
|
||||
except KeyboardInterrupt:
|
||||
player.kill()
|
||||
|
||||
root.mainloop()
|
||||
Reference in New Issue
Block a user