PyQt5 - 无法从流中播放视频

Posted

技术标签:

【中文标题】PyQt5 - 无法从流中播放视频【英文标题】:PyQt5 -- Unable to playback video from stream 【发布时间】:2016-12-14 19:00:13 【问题描述】:

我看到过很多类似这样的其他问题,但似乎其中许多问题没有解决或与我的情况无关,所以就这样吧。

我正在尝试在 mongodb 集合上播放存储为序列化数据(通过 pickle)的视频。

代码如下:

    binary_file = my_database_entry['binary video']
    unpickle = pickle.dumps(binary_file)

    outByteArray = QByteArray(unpickle)
    mediaStream = QBuffer()
    mediaStream.setBuffer(outByteArray)
    mediaStream.open(QIODevice.ReadWrite)

    mediaPlayer.setMedia(QMediaContent(), mediaStream)
    mediaPlayer.play()

其中 'my_database_entry' 是 mongoDB 条目,而 'binary video' 是腌制视频条目的字典键。 这还假设在我的用户界面中正确创建和初始化了 mediaPlayer,即

    mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
    videoPlayer = QVideoWidget()
    mediaPlayer.setVideoOutput(videoPlayer)

我还尝试使用“QMediaPlayer.StreamPlayback”标志初始化 mediaPlayer,但同样没有。

当我在 windows 上尝试它时它崩溃了,当我在 mac 上尝试它时它只是一个黑屏。没有错误日志或任何东西(无论如何都没有启发性)。

有没有人成功地为他们工作,如果有,你是怎么做到的?

谢谢! -马克

【问题讨论】:

【参考方案1】:

您需要保留对缓冲区和基础数据的引用,否则它们将在播放器启动后被垃圾回收。

请注意,在您的示例中,腌制视频数据完全没有意义,因为它只是字节,因此没有什么值得序列化的。 Pickle 仅对结构化的 Python 对象有用,例如 listdict

下面是一个带有完整视频播放器的演示脚本。它最初从文件系统中获取视频资源,但如果它来自数据库,它的工作方式也一样:

from PyQt5 import QtCore, QtWidgets
from PyQt5 import QtMultimedia, QtMultimediaWidgets

class Window(QtWidgets.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.player = QtMultimedia.QMediaPlayer(self)
        self.viewer = QtMultimediaWidgets.QVideoWidget(self)
        self.player.setVideoOutput(self.viewer)
        self.player.stateChanged.connect(self.handleStateChanged)
        self.button1 = QtWidgets.QPushButton('Play', self)
        self.button2 = QtWidgets.QPushButton('Stop', self)
        self.button1.clicked.connect(self.handleButton)
        self.button2.clicked.connect(self.player.stop)
        self.button2.setEnabled(False)
        layout = QtWidgets.QGridLayout(self)
        layout.addWidget(self.viewer, 0, 0, 1, 2)
        layout.addWidget(self.button1, 1, 0)
        layout.addWidget(self.button2, 1, 1)
        self._buffer = QtCore.QBuffer(self)
        self._data = None

    def handleButton(self):
        path = QtWidgets.QFileDialog.getOpenFileName(self)[0]
        if path:
            self.button1.setEnabled(False)
            self.button2.setEnabled(True)
            with open(path, 'rb') as stream:
                self._data = stream.read()
                self._buffer.setData(self._data)
                self._buffer.open(QtCore.QIODevice.ReadOnly)
                self.player.setMedia(
                    QtMultimedia.QMediaContent(), self._buffer)
                self.player.play()

    def handleStateChanged(self, state):
        if state == QtMultimedia.QMediaPlayer.StoppedState:
            self._buffer.close()
            self._data = None
            self.button1.setEnabled(True)
            self.button2.setEnabled(False)

if __name__ == '__main__':

    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 50, 640, 480)
    window.show()
    sys.exit(app.exec_())

更新

上述解决方案仅适用于 Windows 和 Linux,因为目前在 OSX 上不支持流式传输:

见:Qt Multimedia Backends

【讨论】:

就是这样。完美运行。就我而言,为了简洁起见,我没有很好地解释它。我仍然需要解开数据才能使其正常工作。 Unpickling 基本上取代了代码中的 'with open(path, 'rb') as stream:' 等行。再次感谢!! 所以我遇到了这个方法的一些问题。它在 Windows 机器上运行良好,但转到 OSX 我只是得到一个黑屏。没有明显的错误。这可能是某种特定于 mac 的错误吗? @huitlacoche。我只在 Linux 上试过,不能在 OSX 上自己测试。可能是媒体本身导致了问题,所以我建议您尝试几种不同的视频格式。您是否尝试过使用文件 url 直接加载相同的媒体?我不知道 Qt Multimedia 一般有多可靠,因为我从未在严肃的项目中真正使用过它。 (PS:我只是在Linux上多试了几个文件,一两个没有加载成功——不知道为什么)。 @huitlacoche。 PPS:我尝试使用文件 url 直接加载有问题的文件,但它们仍然没有加载 - 所以它没有从导致问题的缓冲区中读取。并且使用 mplayer 可以正常加载相同的文件,因此似乎存在一些内部 Qt 问题。 我不确定它的来源。我可以从文件 url 加载视频。我会继续玩它的。至少我知道它可以工作。谢谢!

以上是关于PyQt5 - 无法从流中播放视频的主要内容,如果未能解决你的问题,请参考以下文章

从流中播放波形文件

iOS - 如何从流中读取音频并播放音频

基于pyqt5的QMediaPlayer实现视频播放器(拨动进度条,音量,更换播放模式,加入多个播放文件)

PyQt5 视频播放器:转换为面向对象的代码会阻止播放

pyqt5 qwebenginview 不会自动播放 youtube 视频

使用 OpenCV 和 PyQT5 视频播放速度过快