2016-12-14 142 views
1

我見過很多其他問題,例如浮動,但它似乎很多都沒有解決或與我的情況無關,所以在這裏。PyQt5 - 無法播放流中的視頻

我試圖在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的進入和「二元視頻」是醃製視頻條目字典鍵。 這還假定MediaPlayer正在正確地創建和我的用戶界面,即

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

我也試過用「QMediaPlayer.StreamPlayback」標誌初始化媒體播放器,但同樣,沒有中被初始化。

當我在Windows上嘗試它時它崩潰,當我在Mac上嘗試它時,它只是一個黑屏。沒有錯誤日誌或任何東西(沒有任何啓發)。

有沒有人得到這個成功地爲他們工作,如果是的話,你是怎麼做到的?

謝謝! -Mark

回答

3

您需要保持對緩衝區和底層數據的引用,否則它們將在玩家啓動後被垃圾回收。

並注意在你的例子中,視頻數據是完全無意義的,因爲它只是字節,所以沒有什麼值得序列化的。泡菜只適用於結構化的Python對象,例如listdict

以下是帶有完整視頻播放器的演示腳本。它initally從文件系統中的視頻資源,但如果從數據庫中來,將工作一樣的:

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

上述解決方案將只工作在Windows和Linux,因爲目前流媒體OSX上不支持:

+0

就是這樣。完美的作品。在我看來,爲了簡潔起見,我沒有做出足夠的解釋。我仍然需要取消數據才能使其工作。 Unpickling基本上代替了'open(path,'rb')作爲流:'etc的代碼行。再次感謝!! – huitlacoche

+0

所以我遇到了這個方法的一個問題。它在Windows機器上工作正常,但去OSX我只是得到一個黑屏。沒有明顯的錯誤。這可能是某種特定於mac的錯誤嗎? – huitlacoche

+0

@huitlacoche。我只嘗試過Linux,而我無法在OSX上自己測試它。這可能是媒體本身導致的問題,所以我建議你嘗試一些不同的視頻格式。你有沒有嘗試直接使用文件url加載相同的媒體?我不知道Qt多媒體的可靠程度如何,因爲我從來沒有真正使用它在一個嚴肅的項目。 (PS:我只是在Linux上嘗試了幾個文件,一兩個文件沒有成功加載 - 不知道爲什麼)。 – ekhumoro