I have been working on creating a video editing software with Tkinter and have been developing the video player. I created a class to handle playing the video, but it does not quite run fast enough for a smooth fps. So I implemented cython compiling to speed it up, but one of the functions does not work when using the 'cdef' declaration. However, declaring with just 'def' works fine. The code compiles without a problem.
The error thrown is: Exception code=0xc0000005 flags=0x0 at 0x00007FF972B54E76. Access violation - attempting to read data at address 0x0000000000000008 Fatal Python error: (pygame parachute) Segmentation Fault Python runtime state: initialized
It is thrown on the commented line in file:
#cyVideoViewer.pyx
from tkinter import Tk, Label, Button
from PIL import ImageTk, Image
import cv2
import moviepy.editor as mpy
from time import time
cdef class viewer:
cdef object video, canvas, label, stringvar, slider, last_frame
cdef int delay
cdef bint pause
cdef tuple dimensions
cdef list tempTime
def __init__(self, object video, object canvas, object label, tuple dimensions, object sv, object slider):
self.video = video
self.canvas = canvas
self.label = label
self.delay = int((1000 / int(video.fps)))
self.pause = True
self.dimensions = dimensions
self.tempTime = [0, 0]
self.setPreviewFrame()
self.stringvar = sv
self.slider = slider
try:
self.last_frame = video.get_frame(video.end)
except Exception as e:
self.last_frame = video.get_frame(0)
cpdef void setPreviewFrame(self, int t=0):
cdef object image
try:
image = self.video.get_frame(t)
except:
image = self.last_frame
cdef object res = cv2.resize(image, dsize=self.dimensions, interpolation=cv2.INTER_CUBIC)
cdef object frame_image = ImageTk.PhotoImage(Image.fromarray(res))
self.label.config(image=frame_image)
self.label.image = frame_image
cpdef void pausePlay(self):
if self.pause:
self.setPause(False)
self.dostream(self.tempTime)
else:
self.setPause(True)
cpdef void dostream(self, prev_time=[0,0], skip=False):
self.stream(prev_time, skip)
cdef stream(self, prev_time=[0, 0], bint skip=False):
time1 = time()
cdef double frame
##
frame = prev_time[0] # Error
##
frame += prev_time[1]/1000
frame += self.delay/1000
#
if frame >= self.video.duration:
self.stringvar.set(str(self.video.duration))
return
cdef object image
try:
image = self.video.get_frame(frame)
except Exception as e:
print(e)
self.video.close()
return
prev_time[1] += self.delay if skip==False else self.delay*2
if prev_time[1] >= 1000:
prev_time[0] += 1
prev_time[1] = 0
cdef object res = cv2.resize(image, dsize=self.dimensions, interpolation=cv2.INTER_CUBIC)
cdef object frame_image = ImageTk.PhotoImage(Image.fromarray(res))
self.label.config(image=frame_image)
self.label.image = frame_image
time2 = time()
exTime = (time2 - time1) * 1000
self.tempTime = prev_time
self.stringvar.set("0:"+str(prev_time[0])+"."+str(prev_time[1]))
cdef double timePerc = (prev_time[0]+prev_time[1]/1000)/self.video.duration
cdef double loc = timePerc*798+51
cdef int x = self.canvas.coords(self.slider)[0]
self.canvas.move(self.slider, loc-x, 0)
if self.pause:
return
if exTime >= self.delay*2:
self.label.after(0, lambda: self.dostream(prev_time=prev_time, skip=True))
else:
self.label.after(int(self.delay-exTime) if self.delay>exTime else 0, lambda: self.dostream(prev_time=prev_time))
cpdef void setPause(self, pause):
self.pause = pause
cpdef void setTime(self, time):
self.tempTime = time
cpdef void setStringVar(self, sv):
self.stringvar = sv
cpdef void setVideo(self, video):
self.video = video
cpdef object getVideo(self):
return self.video
cpdef object getPause(self):
return self.pause
cpdef object getTime(self):
return self.prevTime
I created the "dostream()" function to prevent errors about closures when calling from lambdas.
Why does the error get thrown when assigning "frame" to a parameter, and how could I fix this while continuing to use cython ? Any help would be greatly appreciated.
User contributions licensed under CC BY-SA 3.0