I've seen a number of other questions like this floating around but it seems many of them are unresolved or unrelated to my situation, so here goes.
I'm attempting to play back a video stored as serialized data (through pickle) on a mongodb collection.
Here's the code:
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()
where 'my_database_entry' is the mongoDB entry and 'binary video' is the dictionary key for the pickled video entry.
This also assumes that mediaPlayer is properly created and initialized within my user interface i.e.
mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
videoPlayer = QVideoWidget()
mediaPlayer.setVideoOutput(videoPlayer)
I also tried initializing mediaPlayer with a 'QMediaPlayer.StreamPlayback' flag but again, nothing.
It crashes when I try it on windows and it's just a black screen when I try it on mac. No error logs or anything (nothing enlightening at any rate).
Has anyone gotten this to successfully work for them and if so, how did you do it?
Thanks!
-Mark
You need to keep a reference to both the buffer and the underlying data, otherwise they will just be garbage-collected after the player starts.
And note that in your example, it is utterly pointless pickling the video data, as it is just bytes and so there's nothing worth serializing. Pickle is only useful for structured python objects, such as a list
or dict
.
Below is a demo script with a complete video player. It initally gets the video resource from the file-system, but it would work just the same if it came from a database:
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_())
UPDATE:
The solution above will only work on Windows and Linux, because there is currently no support for streaming on OSX:
- See: Qt Multimedia Backends