Reputation: 447
I have a GUI app that I wrote in Python and I'm trying to display video in Qt app.
It uses a QGraphicsScene and QGraphicsView to display images but now I have to display a video. When I try to display a video here is what I do:
First, I create VideoCapture from cv2 package. After that I run loop and read frame in every iteration which is then casted into QPixmap (this is done correctly, I checked on a single frame). I return that QPixmap object to the Class which holds QGraphicsScene and QGraphicsView and try to add it to the scene.
Thing is, only when the video ends, the last frame is displayed, throughout video playing time I'm welcomed with this sighting
The loop that I mentioned earlier looks like this:
self.imageViewer.start_capturing()
self.timer = QtCore.QTimer()
self.fps = 24
while True:
retVal = self.imageViewer.read_frame()
if not retVal:
self.timer.stop()
break
self.timer.start(1000./self.fps)
self.imageViewer.stop_capturing()
self.ImageViewer is a component which holds the QGraphicsScene and QGraphicsView I also put timer here so that it displays proper ammount of fps but it doesn't help.
The GUI app itself shows QGraphicsView with some buttons
middleLayout.addWidget(self.imageViewer.view)
This is what I mean. So it doesn't show imageViewer
but it shows a subclass of QGraphicsView
Here is the code from read_frame method in ImageViewer class.
def read_frame(self):
"""
Reads a frame from the video, if video ended, then False is returned.
If there is a successful reading then True is returned
:return: True if video is read successfully, False otherwise.
"""
retVal, self.current_frame = self.capture.getFrame()
if not retVal:
return False
else:
self.pixmap = retVal
self.scene.addPixmap(self.pixmap)
return True
The method self.capture.getFrame()
just returns QPixmap item and CV::mat item.
This whole process is done correctly because I tried manually reading frame by frame and everything worked OK, but when I try to display video the app freezed like shown in image above. So I manually tried to do the whole described process by manually clicking a button which loads me frame and puts it onto the QGraphicsScene so I assume that the core of the app works correctly (and I even tried to get roughly 5-7 fps by clicking fast :D )
I hope I made my problem clear and included all code that is needed.
Upvotes: 1
Views: 1547
Reputation: 3932
I think your timing logic is wrong.. you do not use the timer correctly.. you could either use connect or you can use sleep.
I would do something like this:
def grabFrame
retVal = self.imageViewer.read_frame()
if not retVal:
self.timer.stop()
self.imageViewer.stop_capturing()
And somewhere in your main logic or some init function of your class:
yourObject.connect(timer,SIGNAL("timeout()"),yourObject,SLOT("grabFrame()"))
timer.start(1000./self.fps)
Or you can use some kind of sleep of time module after
import time
...
while True:
retVal = self.imageViewer.read_frame()
if not retVal:
break
time.sleep(1./self.fps)//in fraction of second
self.imageViewer.stop_capturing()
Upvotes: 1