如何将可变视频呈现到PyQt小部件



我正在使用PyQt开发python中的视频编辑应用程序。我希望能够制作";剪辑";从视频文件中提取,并能够连接这些片段以渲染新视频。我使用了带有VideoSurface的QMediaPlayer类来播放一个用.mp4文件实例化了QVideoWidget的视频,但我想使用numpy数组(首选(或一些可变对象来播放视频。我浏览了一些开源视频编辑器(OpenShot、Vidcutter、Pitivi(,但似乎找不到我需要的东西。许多人使用C++框架,我对此并不熟悉。

我使用了多线程和for循环,试图通过使用QImage对象破解解决方案,这意味着我逐帧循环视频,提取每帧的numpy数组表示,并将其转换为QImage对象,然后调用repaint((。不幸的是,即使在新线程上调用此函数,也无法以所需的速度呈现。这是受到moviepy用pygame渲染剪辑的方法的启发。我还查阅了PyQt文档,但这些类似乎不能满足我的需求,或者我不理解它们。图形用户界面编程对我来说是新的。

我知道fps不是问题所在,如果你用更新的VideoFileCLip参数运行下面的代码,视频将以原始帧速率的75%左右显示(没有声音(。并且,窗口将";不响应";如果没有多线程。我尝试过30和60的fps,但我的for循环方法仍然不理想,因为其他任务将在其他地方执行,计算复杂性只会增加。

以下是一个简化版本,将揭示问题:

import numpy as np                                                     
import sys
import time
from PyQt5.QtGui import QImage, QPainter
from PyQt5.QtWidgets import QApplication, QWidget
import threading
from moviepy.editor import VideoFileClip
class Demo(QWidget):
def __init__(self):
super().__init__()
self.video = VideoFileClip(r'C:UsersjklewVideosMusicFractalia.MP4') # I am using a real video
im_np = self.video.get_frame(0)
self.image = QImage(im_np, im_np.shape[1], im_np.shape[0],                                                                                                                                                 
QImage.Format_RGB888)
self.stopEvent = threading.Event()
self.thread = threading.Thread(target=self.display_clip, args=())
self.thread.start()
def paintEvent(self, event):
painter = QPainter(self)
painter.drawImage(self.rect(), self.image)
def display_clip(self, fps=60):
clip = self.video
img = clip.get_frame(0) # returns numpy array of frame at time 0
t0 = time.time()
for t in np.arange(1.0 / fps, clip.duration-.001, 1.0 / fps):

img = clip.get_frame(t) # returns numpy array of frame at time t
# print(img.shape)
t1 = time.time()
time.sleep(max(0, t - (t1-t0))) # loop at framerate specified
self.imdisplay(img) #, screen)

def imdisplay(self, img_array):
# fill the widget with the image array
# TODO: Qt widget
self.image = QImage(img_array, img_array.shape[1], img_array.shape[0], QImage.Format_RGB888)
self.repaint()
def main():
app = QApplication(sys.argv)
demo = Demo()
demo.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

这个问题也扩展到可变音频数据。

尝试使用QPixmaps。在显示帧之前,请将它们保存到列表中:

self.frames = []
for file in files:
pixmap = QPixmap(file)
self.frames.append(pixmap)

然后,当你播放图像序列时:

for frame in self.frames:
self.<LABELNAME>.setPixmap(frame)
time.sleep(1/FPS)

最新更新