如何为视频播放器选择文件

Posted

技术标签:

【中文标题】如何为视频播放器选择文件【英文标题】:How to choose file for video player 【发布时间】:2019-02-08 15:48:35 【问题描述】:

我是类和 PyQt5 的新手,正在尝试使用 PyQt5 和 Opencv 构建视频播放器。使用OpenCV Video Capture with PyQt4 中的代码并进行更改以将 PyQt4 中的命令转换为 PyQt5 并添加一个暂停按钮,我现在有了一个带有暂停、播放、结束和退出按钮的视频播放器。这是运行良好的代码:

import cv2
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication, QPushButton, 
QVBoxLayout, QFileDialog

fileName = 'C:/Users/Art/Downloads/testVideo.mp4'


class Capture():
    def __init__(self):
        self.capturing = False
        self.c = cv2.VideoCapture(fileName)

    def startCapture(self):
        self.capturing = True
        cap = self.c
        while(self.capturing):
            ret, frame = cap.read()
            cv2.imshow("Capture", frame)
            cv2.waitKey(5)
        cv2.destroyAllWindows()

    def endCapture(self):
        self.capturing = False

    def pauseCapture(self): 
        if cv2.waitKey(0) & 0xFF == ord('p'):  # Pause
            self.capturing = False

    def quitCapture(self):
        cap = self.c
        cv2.destroyAllWindows()
        cap.release()
        QtCore.QCoreApplication.quit()

class Window(QtWidgets.QWidget):
    def __init__(self):

    QtWidgets.QWidget.__init__(self)
    self.setWindowTitle('Control Panel')

    self.capture = Capture()
    self.start_button = QPushButton('Start', self)
    self.start_button.clicked.connect(self.capture.startCapture)

    self.end_button = QPushButton('End', self)
    self.end_button.clicked.connect(self.capture.endCapture)

    self.pause_button = QPushButton('Pause', self)
    self.pause_button.clicked.connect(self.capture.pauseCapture)

    self.quit_button = QPushButton('Quit', self)
    self.quit_button.clicked.connect(self.capture.quitCapture)

    vbox = QVBoxLayout(self)
    vbox.addWidget(self.start_button)
    vbox.addWidget(self.end_button)
    vbox.addWidget(self.pause_button)
    vbox.addWidget(self.quit_button)

    self.setLayout(vbox)
    self.setGeometry(100, 100, 200, 200)
    self.show()

    if __name__== '__main__':
        import sys
        app = QApplication(sys.argv)
        window = Window()
        sys.exit(app.exec())

到目前为止,我将视频文件名及其路径硬编码到代码 (fileName) 中。现在,我想添加一个加载按钮,让用户选择视频。像这样的:

 self.load_button = QPushButton('Load', self)
 self.load_button.clicked.connect(self.pick_video)

 def pick_video():
     dialog = QtGui.QFileDialog()
     fileName = dialog.getExistingDirectory(None, 
      "Select Folder")
     return fileName

并将加载按钮添加到现有按钮列表中,如下所示:

vbox.addWidget(self.load_button)

我的问题是我不知道如何将其合并到现有代码中。如果我把它放在 Window 类中,它会给我一个错误。我的问题是如何将这样的内容添加到现有代码中,以便用户可以在按下加载按钮后选择视频文件。

编辑:根据@ekhumoro 更改代码后,我得到了这样的结果:

import cv2
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication, QPushButton, 
QVBoxLayout, QFileDialog


class Capture():
    def __init__(self):
        self.capturing = False

    def startCapture(self, path):
        self.capturing = True
        self.c = cv2.VideoCapture(path)
        while self.capturing:
            ret, frame = self.c.read()
            cv2.imshow("Capture", frame)
            cv2.waitKey(5)
        cv2.destroyAllWindows()

    def endCapture(self):
        self.capturing = False

    def pauseCapture(self): 
        if cv2.waitKey(0) & 0xFF == ord('p'):  # Pause
            self.capturing = False

    def quitCapture(self):
        cap = self.c
        cv2.destroyAllWindows()
        cap.release()
        QtCore.QCoreApplication.quit()

class Window(QtWidgets.QWidget):
    def __init__(self):

        QtWidgets.QWidget.__init__(self)
        self.setWindowTitle('Control Panel')

        self.capture = Capture()
        self.start_button = QPushButton('Start', self)
        self.start_button.clicked.connect(self.start)

        self.end_button = QPushButton('End', self)
        self.end_button.clicked.connect(self.capture.endCapture)

        self.pause_button = QPushButton('Pause', self)
        self.pause_button.clicked.connect(self.capture.pauseCapture)

        self.quit_button = QPushButton('Quit', self)
        self.quit_button.clicked.connect(self.capture.quitCapture)

        vbox = QVBoxLayout(self)
        vbox.addWidget(self.start_button)
        vbox.addWidget(self.end_button)
        vbox.addWidget(self.pause_button)
        vbox.addWidget(self.quit_button)

        self.setLayout(vbox)
        self.setGeometry(100, 100, 200, 200)
        self.show()

    def start(self):
        path = QtWidgets.QFileDialog.getOpenFileName(self)[0]
        if path:
            self.capture.startCapture(path)

if __name__== '__main__':
    import sys
    app = QApplication(sys.argv)
    window = Window()
    sys.exit(app.exec())

但是,当我运行这段代码时,我得到了这个错误:AttributeError: 'Window' object has no attribute 'start'。另一件事是我想为此过程设置一个单独的按钮,这意味着一旦用户运行代码,在打开的窗口中,他/她可以单击该按钮(我们称之为加载按钮),然后选择视频文件,我在这段代码中没有看到。我在某处遗漏了什么吗?或者,重新排列的代码可能不是 @ekhumoro 的意思。

【问题讨论】:

【参考方案1】:

重新排列代码,使startCapture 采用path 参数。然后在开始按钮的插槽中传递文件对话框中的路径:

class Capture():
    def __init__(self):
        self.capturing = False

    def startCapture(self, path):
        self.capturing = True
        self.c = cv2.VideoCapture(path)
        while self.capturing:
            ret, frame = self.c.read()
            cv2.imshow("Capture", frame)
            cv2.waitKey(5)
        cv2.destroyAllWindows()

class Window(QtWidgets.QWidget):
    def __init__(self):
        ...
        self.start_button = QPushButton('Start', self)
        self.start_button.clicked.connect(self.start)
        ...

    def start(self):
        path = QtWidgets.QFileDialog.getOpenFileName(self)[0]
        if path:
            self.capture.startCapture(path)

这是一个完整的替代实现:

import cv2
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication, QPushButton,QVBoxLayout, QFileDialog

class Capture():
    def __init__(self):
        self.capturing = False
        self.c = None

    def setVideoFile(self, path):
        if self.c is not None:
            cv2.destroyAllWindows()
            self.c.release()
        self.c = cv2.VideoCapture(path)
        self.startCapture()

    def startCapture(self):
        self.capturing = True
        cap = self.c
        while(self.capturing):
            ret, frame = cap.read()
            cv2.imshow("Capture", frame)
            cv2.waitKey(5)
        cv2.destroyAllWindows()

    def endCapture(self):
        self.capturing = False

    def pauseCapture(self):
        if cv2.waitKey(0) & 0xFF == ord('p'):  # Pause
            self.capturing = False

    def quitCapture(self):
        cap = self.c
        cv2.destroyAllWindows()
        cap.release()
        QtCore.QCoreApplication.quit()

class Window(QtWidgets.QWidget):
    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        self.setWindowTitle('Control Panel')

        self.capture = Capture()
        self.open_button = QPushButton('Open', self)
        self.open_button.clicked.connect(self.open)

        self.start_button = QPushButton('Start', self)
        self.start_button.clicked.connect(self.capture.startCapture)

        self.end_button = QPushButton('End', self)
        self.end_button.clicked.connect(self.capture.endCapture)

        self.pause_button = QPushButton('Pause', self)
        self.pause_button.clicked.connect(self.capture.pauseCapture)

        self.quit_button = QPushButton('Quit', self)
        self.quit_button.clicked.connect(self.capture.quitCapture)

        vbox = QVBoxLayout(self)
        vbox.addWidget(self.open_button)
        vbox.addWidget(self.start_button)
        vbox.addWidget(self.end_button)
        vbox.addWidget(self.pause_button)
        vbox.addWidget(self.quit_button)

        self.setLayout(vbox)
        self.setGeometry(100, 100, 200, 200)
        self.show()

    def open(self):
        path = QtWidgets.QFileDialog.getOpenFileName(self)[0]
        if path:
            self.capture.setVideoFile(path)

if __name__== '__main__':
    import sys
    app = QApplication(sys.argv)
    window = Window()
    sys.exit(app.exec())

【讨论】:

@Miranda 您的示例中的缩进搞砸了。如果您更正它,我的代码将正常工作。我已经在我的答案中添加了一个更正的版本。 @ekhumoro 感谢您提供完整的脚本!这是工作。不过有一个问题。当我点击暂停按钮时,为了重新开始(从暂停的帧开始),我需要再次点击开始。通过根据您的代码向“开始”按钮添加加载操作,每当我暂停时,当我单击“开始”按钮再次播放时,它会打开视频文件选择对话框。所以,我的问题是,是否可以添加一个单独的加载按钮来避免这个问题? @Miranda 我添加了一个替代实现,应该可以满足您的需求。 @ekhumoro。谢谢!您的脚本完全符合我的要求。

以上是关于如何为视频播放器选择文件的主要内容,如果未能解决你的问题,请参考以下文章

如何为 Flash 视频加载字幕文本?

如何用 VS2015 制作简易视频播放器

如何为角度课程设置播放器?

如何为媒体播放器组件启用自动播放?

如何用vlc播放器的网络串流

Android 视频播放器 mkv 视频支持