Unsolved [PyQt5] Allow QMediaPlayer to read from QBuffer()
-
Bumping... any solutions / suggestions?
-
@Elus Hi, don't pass a
QMediaContent()
as in the doc:Setting the media to a null QMediaContent will cause the player to discard all information relating to the current media source and to cease all I/O operations related to that media.
Try pass a
QUrl()
to it.
(I'm not sure if you can do this in python, or you can pass aQMediaContent(QUrl())
) -
@Bonnie said in [PyQt5] Allow QMediaPlayer to read from QBuffer():
Setting the media to a null QMediaContent will cause the player to discard all information relating to the current media source and to cease all I/O operations related to that media.
I tried:
media_file = QUrl(media_file_name)
But that resulted in exception:
setData(self, Union[QByteArray, bytes, bytearray]): argument 1 has unexpected type 'QUrl'
I also tried:
media_file = QMediaContent(QUrl(media_file_name))
But that resulted in exception:
setData(self, Union[QByteArray, bytes, bytearray]): argument 1 has unexpected type 'QMediaContent'
I can't pass QMediaContent to buffer directly.
-
@Elus No, no, I mean in
set_buffer
self.video_player.setMedia(QUrl(), self.buffer)
-
@VaL-Doroshchuk Would you know anything about this?
@Bonnie
One moment let me try -
@Bonnie said in [PyQt5] Allow QMediaPlayer to read from QBuffer():
self.video_player.setMedia(QUrl(), self.buffer)
I tried this and received error:
TypeError: setMedia(self, QMediaContent, stream: QIODevice = None): argument 1 has unexpected type 'QUrl'
-
@Elus Yes, I said I'm not sure if you can do this in python...
Then can this work? I don't know about python...self.video_player.setMedia(QMediaContent(QUrl()), self.buffer)
-
Unfortunately, the screen is still blank if I do that. Do you think this is related to my issue? https://bugreports.qt.io/browse/QTBUG-69101
-
@Elus Not sure, I tested in Windows and C++.
-
@Elus I don't think joining 2 videos is as simple as concatenating raw data since it has a header that indicates the format, image size, metadata, etc.
If you still want to display a video using raw data then you can use the following example based on my SO answer:
import os import sys from PyQt5 import QtCore, QtWidgets, QtMultimedia, QtMultimediaWidgets CURRENT_DIR = os.path.dirname(os.path.realpath(__file__)) class MainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.player = QtMultimedia.QMediaPlayer( flags=QtMultimedia.QMediaPlayer.VideoSurface ) self.buff = QtCore.QBuffer() self.video_widget = QtMultimediaWidgets.QVideoWidget() self.setCentralWidget(self.video_widget) self.player.setVideoOutput(self.video_widget) self.resize(640, 480) def load_from_file(self, filename): f = QtCore.QFile(filename) if f.open(QtCore.QIODevice.ReadOnly): ba = f.readAll() self.load_from_data(ba) def load_from_data(self, data): ba = QtCore.QByteArray(data) self.buff.setData(ba) self.buff.open(QtCore.QIODevice.ReadOnly) self.player.setMedia(QtMultimedia.QMediaContent(), self.buff) self.player.play() def main(): app = QtWidgets.QApplication.instance() if app is None: app = QtWidgets.QApplication(sys.argv) w = MainWindow() w.show() filename = os.path.join(CURRENT_DIR, "video.mp4") w.load_from_file(filename) sys.exit(app.exec_()) if __name__ == "__main__": main()
├── main.py └── video.mp4
My example has been tested on Linux with PyQt5 5.14.2 and python 3.8.3
-
@Bonnie Thanks for giving it a try. I think your experiment, along with @eyllanesc 's code, confirms my suspicions.
@eyllanesc said in [PyQt5] Allow QMediaPlayer to read from QBuffer():
import os
import sysfrom PyQt5 import QtCore, QtWidgets, QtMultimedia, QtMultimediaWidgets
CURRENT_DIR = os.path.dirname(os.path.realpath(file))
class MainWindow(QtWidgets.QMainWindow):
def init(self, parent=None):
super().init(parent)self.player = QtMultimedia.QMediaPlayer( flags=QtMultimedia.QMediaPlayer.VideoSurface ) self.buff = QtCore.QBuffer() self.video_widget = QtMultimediaWidgets.QVideoWidget() self.setCentralWidget(self.video_widget) self.player.setVideoOutput(self.video_widget) self.resize(640, 480) def load_from_file(self, filename): f = QtCore.QFile(filename) if f.open(QtCore.QIODevice.ReadOnly): ba = f.readAll() self.load_from_data(ba) def load_from_data(self, data): ba = QtCore.QByteArray(data) self.buff.setData(ba) self.buff.open(QtCore.QIODevice.ReadOnly) self.player.setMedia(QtMultimedia.QMediaContent(), self.buff) self.player.play()
def main():
app = QtWidgets.QApplication.instance()
if app is None:
app = QtWidgets.QApplication(sys.argv)w = MainWindow() w.show() filename = os.path.join(CURRENT_DIR, "video.mp4") w.load_from_file(filename) sys.exit(app.exec_())
if name == "main":
main()Thanks a bunch. Your code, which you've tested, confirms my suspicions that https://bugreports.qt.io/browse/QTBUG-69101 is the root cause of my issues and that the underlying problem is Mac OS. Running your code against several different videos produces the same result for me every time: a black screen.
Regarding your comment about the header requirement, I think what you're saying is true of certain video formats. For example, certain compression algorithms are able to reduce the file size by looking at the changes between frames. Therefore, if you simply concatenate one set of bytes to another, as I am trying to do, you'd be missing a critical piece of information that can help you decode the next frame.
However, I do not know if all video formats rely on this kind of paradigm. I believe certain formats, like .ts, allow videos to be concatenated, one to another. I have done this successfully in my own application and playback appears to be fine.
I am not sure where to go from here.
Do I Dockerize my application to avoid the issues associated with Mac OS?
Do I move away from QMediaPlayer in favor of VLC? (I made a thread on their forums listing a different problem I was having https://forum.videolan.org/viewtopic.php?f=32&t=153667, maybe someone here can chime in about how to resolve it).
Do I use gstreamer, which I am entirely unfamiliar with?I have to weigh my options. I appreciate everyone's help so far.