I'm trying to play an online video using python-vlc library.
First, I was using a simple version of the player to test it out:
import vlc
#example url
url="https://player.vimeo.com/external/363536021.hd.mp4?s=6f6e87d86a49149479ebdab6c8bc421aa89f327c&profile_id=175&oauth2_token_id=57447761"
player = vlc.Instance().media_player_new()
player.set_media(vlc.Instance().media_new(url))
player.play()
while str(player.get_state()) != "State.Ended":
pass
player.stop()
It plays the while video from URL without any problems!
Now I wanted to use the more complex version with pyqt5 GUI (original source-code here):
import sys
import os.path
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QPalette, QColor
from PyQt5.QtWidgets import QMainWindow, QWidget, QFrame, QSlider, QHBoxLayout, QPushButton, \
QVBoxLayout, QAction, QFileDialog, QApplication
import vlc
class Player(QMainWindow):
def __init__(self, videoUrl, master=None):
QMainWindow.__init__(self, master)
self.setWindowTitle("Media Player")
# creating a basic vlc instance
self.instance = vlc.Instance()
# creating an empty vlc media player
self.mediaplayer = self.instance.media_player_new()
self.playableVideo = videoUrl
self.createUI()
self.isPaused = False
def createUI(self):
"""Set up the user interface, signals & slots
"""
self.widget = QWidget(self)
self.setCentralWidget(self.widget)
# In this widget, the video will be drawn
if sys.platform == "darwin": # for MacOS
from PyQt5.QtWidgets import QMacCocoaViewContainer
self.videoframe = QMacCocoaViewContainer(0)
else:
self.videoframe = QFrame()
self.palette = self.videoframe.palette()
self.palette.setColor (QPalette.Window,
QColor(0,0,0))
self.videoframe.setPalette(self.palette)
self.videoframe.setAutoFillBackground(True)
self.positionslider = QSlider(Qt.Horizontal, self)
self.positionslider.setToolTip("Position")
self.positionslider.setMaximum(5000)
self.positionslider.sliderMoved.connect(self.setPosition)
self.hbuttonbox = QHBoxLayout()
self.playbutton = QPushButton("Play")
self.hbuttonbox.addWidget(self.playbutton)
self.playbutton.clicked.connect(self.PlayPause)
self.stopbutton = QPushButton("Exit")
self.hbuttonbox.addWidget(self.stopbutton)
self.stopbutton.clicked.connect(self.Stop)
self.hbuttonbox.setAlignment(Qt.AlignHCenter)
self.vboxlayout = QVBoxLayout()
self.vboxlayout.addWidget(self.videoframe)
self.vboxlayout.addWidget(self.positionslider)
self.vboxlayout.addLayout(self.hbuttonbox)
self.widget.setLayout(self.vboxlayout)
self.timer = QTimer(self)
self.timer.setInterval(200)
self.timer.timeout.connect(self.updateUI)
def PlayPause(self):
"""Toggle play/pause status
"""
if self.mediaplayer.is_playing():
self.mediaplayer.pause()
self.playbutton.setText("Play")
self.isPaused = True
else:
if self.mediaplayer.play() == -1:
self.OpenFile()
return
self.mediaplayer.play()
self.playbutton.setText("Pause")
self.timer.start()
self.isPaused = False
def Stop(self):
"""Stop player
"""
self.mediaplayer.stop()
self.playbutton.setText("Play")
def OpenFile(self, filename=None):
"""Open a media file in a MediaPlayer
"""
if filename is None:
filename = self.playableVideo
if not filename:
return
# create the media
if sys.version < '3':
filename = unicode(filename)
self.media = self.instance.media_new(filename)
# put the media in the media player
self.mediaplayer.set_media(self.media)
# parse the metadata of the file
self.media.parse()
# set the title of the track as window title
self.setWindowTitle(self.media.get_meta(0))
# the media player has to be 'connected' to the QFrame
# (otherwise a video would be displayed in it's own window)
# this is platform specific!
# you have to give the id of the QFrame (or similar object) to
# vlc, different platforms have different functions for this
if sys.platform.startswith('linux'): # for Linux using the X Server
self.mediaplayer.set_xwindow(self.videoframe.winId())
elif sys.platform == "win32": # for Windows
self.mediaplayer.set_hwnd(self.videoframe.winId())
elif sys.platform == "darwin": # for MacOS
self.mediaplayer.set_nsobject(int(self.videoframe.winId()))
self.PlayPause()
def setPosition(self, position):
self.mediaplayer.set_position(position / 1000.0)
def updateUI(self):
self.positionslider.setValue(self.mediaplayer.get_position() * 1000)
if not self.mediaplayer.is_playing():
self.timer.stop()
if not self.isPaused:
self.Stop()
if __name__ == "__main__":
app = QApplication(sys.argv)
player = Player("https://player.vimeo.com/external/363536021.hd.mp4?s=6f6e87d86a49149479ebdab6c8bc421aa89f327c&profile_id=175&oauth2_token_id=57447761")
player.show()
player.resize(640, 480)
if sys.argv[1:]:
player.OpenFile(sys.argv[1])
sys.exit(app.exec_())
This code keeps returning an access stream error: HTTP connection failure.
The problem is that as soon as you start playing the video it is not available since the download is not immediate but with your code you try to update the position. The solution is to update is to get the position after it started playing:
def updateUI(self):
if not self.mediaplayer.is_playing():
return
self.positionslider.setValue(self.mediaplayer.get_position() * 1000)
if not self.mediaplayer.is_playing():
self.timer.stop()
if not self.isPaused:
self.Stop()
Related
How can I set the audio output of a QMediaPlayer to a specific output in Windows 7 and later?
This was really easy in PySide (using Phonon) but I can't find a way to do it in PySide2.
There are some related questions already, like this old but still not solved one, or this one that asks exactly what I want.
They are both in c++ and its difficult to convert it to PySide2.
The second one is answered with this code:
QMediaService *svc = player->service();
if (svc != nullptr)
{
QAudioOutputSelectorControl *out = qobject_cast<QAudioOutputSelectorControl *>
(svc->requestControl(QAudioOutputSelectorControl_iid));
if (out != nullptr)
{
out->setActiveOutput(this->ui->comboBox->currentText());
svc->releaseControl(out);
}
}
Another one with an attempt to python conversion didn't work also.
I tried to convert them to Python code, but the result was not successful.
Here is my minimal attempt:
import sys
from PySide2 import QtMultimedia
from PySide2.QtCore import QUrl, Qt
from PySide2.QtMultimedia import QMediaPlayer, QMediaContent
from PySide2.QtWidgets import (QPushButton, QSlider, QHBoxLayout, QVBoxLayout,
QFileDialog, QStyle, QApplication, QDialog, QComboBox)
class Window(QDialog):
def __init__(self):
super().__init__()
self.out_combo = QComboBox()
mode = QtMultimedia.QAudio.AudioOutput
devices = QtMultimedia.QAudioDeviceInfo.availableDevices(mode)
for item in [(dev.deviceName(), dev) for dev in devices]:
self.out_combo.addItem(item[0], item[1])
self.out_combo.currentIndexChanged.connect(self.out_device_changed)
openBtn = QPushButton('Open file')
openBtn.clicked.connect(self.open_file)
self.playBtn = QPushButton()
self.playBtn.setEnabled(False)
self.playBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
self.playBtn.clicked.connect(self.play_file)
self.slider = QSlider(Qt.Horizontal)
self.slider.setRange(0, 0)
self.slider.sliderMoved.connect(self.set_position)
hor_layout = QHBoxLayout()
hor_layout.setContentsMargins(0, 0, 0, 0)
hor_layout.addWidget(openBtn)
hor_layout.addWidget(self.playBtn)
hor_layout.addWidget(self.slider)
ver_layout = QVBoxLayout()
ver_layout.addWidget(self.out_combo)
ver_layout.addLayout(hor_layout)
self.setLayout(ver_layout)
self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.player.stateChanged.connect(self.mediastate_changed)
self.player.positionChanged.connect(self.position_changed)
self.player.durationChanged.connect(self.duration_changed)
self.show()
def open_file(self):
file_name, _ = QFileDialog.getOpenFileName(self, "Open file")
if file_name != '':
self.player.setMedia(QMediaContent(QUrl.fromLocalFile(file_name)))
# self.label.setText(basename(file_name))
self.playBtn.setEnabled(True)
def play_file(self):
if self.player.state() == QMediaPlayer.PlayingState:
self.player.pause()
else:
self.player.play()
def mediastate_changed(self, state):
if self.player.state() == QMediaPlayer.PlayingState:
self.playBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaPause))
else:
self.playBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
def position_changed(self, position):
self.slider.setValue(position)
def duration_changed(self, duration):
self.slider.setRange(0, duration)
def set_position(self, position):
self.player.setPosition(position)
def out_device_changed(self, idx):
device = self.out_combo.itemData(idx)
service = self.player.service()
if service:
out = service.requestControl("org.qt-project.qt.mediastreamscontrol/5.0")
if out:
out.setActiveOutput(self.out_combo.currentText())
service.releaseControl(out)
else:
print("No output found!")
app = QApplication(sys.argv)
window = Window()
sys.exit(app.exec_())
I have use VLC Python binding for media Player Gui and I want to add Timer to the Below Slider its like 0.00:0.00 (current video time : total duration of video) how can i add this ??
How to callback the current playing time and display as label below position slider as mention in image ?
Please help for small hint to how to do??
import sys
from PyQt5 import QtCore as qtc
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtGui as qtg
import vlc
import os.path
class MainWindow(qtw.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
##Main framwork
# creating a basic vlc instance
self.instance = vlc.Instance()
# creating an empty vlc media player
self.mediaplayer = self.instance.media_player_new()
self.createUI()
self.isPaused = False
def createUI(self):
base_widget = qtw.QWidget()
base_widget.setLayout(qtw.QHBoxLayout())
notebook = qtw.QVBoxLayout()
base_widget.layout().addLayout(notebook)
self.setCentralWidget(base_widget)
#VideoFrame Loading
self.videoframe = qtw.QFrame()
self.videoframe.setMinimumWidth(950)
self.videoframe.setMinimumHeight(525)
self.palette = self.videoframe.palette()
self.palette.setColor (qtg.QPalette.Window,
qtg.QColor(0,0,0))
self.videoframe.setPalette(self.palette)
self.videoframe.setAutoFillBackground(True)
#Position Slider
self.positionslider = qtw.QSlider(qtc.Qt.Horizontal, self)
self.positionslider.setToolTip("Position")
self.positionslider.setMaximum(100000.0)
self.positionslider.setTickPosition(qtw.QSlider.TicksBelow)
self.positionslider.setTickInterval(2000)
self.positionslider.sliderMoved.connect(self.setPosition)
self.hbuttonbox = qtw.QHBoxLayout()
self.playbutton = qtw.QPushButton("Play")
self.hbuttonbox.addWidget(self.playbutton)
self.playbutton.clicked.connect(self.PlayPause)
#Button Box
self.stopbutton = qtw.QPushButton("Stop")
self.hbuttonbox.addWidget(self.stopbutton)
self.stopbutton.clicked.connect(self.Stop)
#Volume slider
self.hbuttonbox.addStretch(1)
self.volumeslider = qtw.QSlider(qtc.Qt.Horizontal, self)
self.volumeslider.setMaximum(100)
self.volumeslider.setValue(self.mediaplayer.audio_get_volume())
self.volumeslider.setToolTip("Volume")
self.hbuttonbox.addWidget(self.volumeslider)
self.volumeslider.valueChanged.connect(self.setVolume)
notebook.addWidget(self.videoframe)
notebook.addWidget(self.positionslider)
notebook.addLayout(self.hbuttonbox)
#Actions Code
open1 = qtw.QAction("&Open", self)
open1.triggered.connect(self.OpenFile)
exit = qtw.QAction("&Exit", self)
exit.triggered.connect(sys.exit)
menubar = self.menuBar()
filemenu = menubar.addMenu("&File")
filemenu.addAction(open1)
filemenu.addSeparator()
filemenu.addAction(exit)
self.timer = qtc.QTimer(self)
self.timer.setInterval(200)
self.timer.timeout.connect(self.updateUI)
def PlayPause(self):
"""Toggle play/pause status
"""
if self.mediaplayer.is_playing():
self.mediaplayer.pause()
self.playbutton.setText("Play")
self.isPaused = True
else:
if self.mediaplayer.play() == -1:
self.OpenFile()
return
self.mediaplayer.play()
self.playbutton.setText("Pause")
self.timer.start()
self.isPaused = False
def PausePlay(self):
if self.mediaplayer.is_playing():
self.mediaplayer.pause()
self.playbutton.setText("Play")
self.isPaused = True
def Stop(self):
"""Stop player
"""
self.mediaplayer.stop()
self.playbutton.setText("Play")
def OpenFile(self, filename=None):
"""Open a media file in a MediaPlayer
"""
if filename is None or filename is False:
print("Attempt to open up OpenFile")
filenameraw = qtw.QFileDialog.getOpenFileName(self, "Open File", os.path.expanduser('~'))
filename = filenameraw[0]
if not filename:
return
# create the media
if sys.version < '3':
filename = unicode(filename)
self.media = self.instance.media_new(filename)
# put the media in the media player
self.mediaplayer.set_media(self.media)
# parse the metadata of the file
self.media.parse()
# set the title of the track as window title
self.setWindowTitle(self.media.get_meta(0))
# print(vlc.libvlc_media_get_meta(self.media, 6))
# print(vlc.libvlc_media_get_duration(self.media))
# the media player has to be 'connected' to the QFrame
# (otherwise a video would be displayed in it's own window)
# this is platform specific!
# you have to give the id of the QFrame (or similar object) to
# vlc, different platforms have different functions for this
if sys.platform.startswith('linux'): # for Linux using the X Server
self.mediaplayer.set_xwindow(self.videoframe.winId())
elif sys.platform == "win32": # for Windows
self.mediaplayer.set_hwnd(self.videoframe.winId())
elif sys.platform == "darwin": # for MacOS
self.mediaplayer.set_nsobject(int(self.videoframe.winId()))
self.PlayPause()
def setVolume(self, Volume):
"""Set the volume """
self.mediaplayer.audio_set_volume(Volume)
def setPosition(self, position):
"""Set the position
"""
# setting the position to where the slider was dragged
self.mediaplayer.set_position(position / 100000.0)
# the vlc MediaPlayer needs a float value between 0 and 1, Qt
# uses integer variables, so you need a factor; the higher the
# factor, the more precise are the results
# (1000 should be enough)
def updateUI(self):
"""updates the user interface"""
# setting the slider to the desired position
self.positionslider.setValue(self.mediaplayer.get_position() * 100000.0)
if not self.mediaplayer.is_playing():
# no need to call this function if nothing is played
self.timer.stop()
if not self.isPaused:
# after the video finished, the play button stills shows
# "Pause", not the desired behavior of a media player
# this will fix it
self.Stop()
if __name__ == '__main__':
app = qtw.QApplication(sys.argv) #it's required to save a referance to MainWindow
mw = MainWindow()
mw.show()
if sys.argv[1:]:
mw.OpenFile(sys.argv[1])
sys.exit(app.exec_())
#if it goes out of scope ,it will be destroyed
I'm new to PyQt and I'm trying to create a videoplayer that screenshots the current frame it retrieves. I implemented this method for grabbing the videoframes in order to take screenshots and added it to a videoplayer GUI. Here's how the GUI essentially looks like:
I created a trigger for the screenshot action in the VideoWindow class with the following code:
screenshotAction = QAction(QIcon('screenshot.png'), '&Screenshot', self)
screenshotAction.setShortcut('Ctrl+S')
screenshotAction.setStatusTip('Screenshot scenes')
screenshotAction.triggered.connect(self.screenshotCall)
I then took the implementation of the VideoFrameGrabber class and called it in the screenshot function:
def screenshotCall(self):
#Call video frame grabber
self.grabber = VideoFrameGrabber(self.videoWidget, self)
self.mediaPlayer.setVideoOutput(self.grabber)
self.grabber.frameAvailable.connect(self.process_frame)
self.mediaPlayer.setVideoOutput(self.videoWidget)
Complete code:
# PyQt5 Video player
#!/usr/bin/env python
from PyQt5.QtCore import QDir, Qt, QUrl, pyqtSignal, QPoint, QRect, QObject
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer, QVideoFrame, QAbstractVideoSurface, QAbstractVideoBuffer, QVideoSurfaceFormat
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtWidgets import (QApplication, QFileDialog, QHBoxLayout, QLabel,
QPushButton, QSizePolicy, QSlider, QStyle, QVBoxLayout, QWidget)
from PyQt5.QtWidgets import QMainWindow,QWidget, QPushButton, QAction
from PyQt5.QtGui import QIcon, QPainter, QImage
import sys
import os
import os.path as osp
class VideoFrameGrabber(QAbstractVideoSurface):
frameAvailable = pyqtSignal(QImage)
def __init__(self, widget: QWidget, parent: QObject):
super().__init__(parent)
self.widget = widget
def supportedPixelFormats(self, handleType):
return [QVideoFrame.Format_ARGB32, QVideoFrame.Format_ARGB32_Premultiplied,
QVideoFrame.Format_RGB32, QVideoFrame.Format_RGB24, QVideoFrame.Format_RGB565,
QVideoFrame.Format_RGB555, QVideoFrame.Format_ARGB8565_Premultiplied,
QVideoFrame.Format_BGRA32, QVideoFrame.Format_BGRA32_Premultiplied, QVideoFrame.Format_BGR32,
QVideoFrame.Format_BGR24, QVideoFrame.Format_BGR565, QVideoFrame.Format_BGR555,
QVideoFrame.Format_BGRA5658_Premultiplied, QVideoFrame.Format_AYUV444,
QVideoFrame.Format_AYUV444_Premultiplied, QVideoFrame.Format_YUV444,
QVideoFrame.Format_YUV420P, QVideoFrame.Format_YV12, QVideoFrame.Format_UYVY,
QVideoFrame.Format_YUYV, QVideoFrame.Format_NV12, QVideoFrame.Format_NV21,
QVideoFrame.Format_IMC1, QVideoFrame.Format_IMC2, QVideoFrame.Format_IMC3,
QVideoFrame.Format_IMC4, QVideoFrame.Format_Y8, QVideoFrame.Format_Y16,
QVideoFrame.Format_Jpeg, QVideoFrame.Format_CameraRaw, QVideoFrame.Format_AdobeDng]
def isFormatSupported(self, format):
imageFormat = QVideoFrame.imageFormatFromPixelFormat(format.pixelFormat())
size = format.frameSize()
return imageFormat != QImage.Format_Invalid and not size.isEmpty() and \
format.handleType() == QAbstractVideoBuffer.NoHandle
def start(self, format: QVideoSurfaceFormat):
imageFormat = QVideoFrame.imageFormatFromPixelFormat(format.pixelFormat())
size = format.frameSize()
if imageFormat != QImage.Format_Invalid and not size.isEmpty():
self.imageFormat = imageFormat
self.imageSize = size
self.sourceRect = format.viewport()
super().start(format)
self.widget.updateGeometry()
self.updateVideoRect()
return True
else:
return False
def stop(self):
self.currentFrame = QVideoFrame()
self.targetRect = QRect()
super().stop()
self.widget.update()
def present(self, frame):
if frame.isValid():
cloneFrame = QVideoFrame(frame)
cloneFrame.map(QAbstractVideoBuffer.ReadOnly)
image = QImage(cloneFrame.bits(), cloneFrame.width(), cloneFrame.height(),
QVideoFrame.imageFormatFromPixelFormat(cloneFrame.pixelFormat()))
self.frameAvailable.emit(image) # this is very important
cloneFrame.unmap()
if self.surfaceFormat().pixelFormat() != frame.pixelFormat() or \
self.surfaceFormat().frameSize() != frame.size():
self.setError(QAbstractVideoSurface.IncorrectFormatError)
self.stop()
return False
else:
self.currentFrame = frame
self.widget.repaint(self.targetRect)
return True
def updateVideoRect(self):
size = self.surfaceFormat().sizeHint()
size.scale(self.widget.size().boundedTo(size), Qt.KeepAspectRatio)
self.targetRect = QRect(QPoint(0, 0), size)
self.targetRect.moveCenter(self.widget.rect().center())
def paint(self, painter):
if self.currentFrame.map(QAbstractVideoBuffer.ReadOnly):
oldTransform = self.painter.transform()
if self.surfaceFormat().scanLineDirection() == QVideoSurfaceFormat.BottomToTop:
self.painter.scale(1, -1)
self.painter.translate(0, -self.widget.height())
image = QImage(self.currentFrame.bits(), self.currentFrame.width(), self.currentFrame.height(),
self.currentFrame.bytesPerLine(), self.imageFormat)
self.painter.drawImage(self.targetRect, image, self.sourceRect)
self.painter.setTransform(oldTransform)
self.currentFrame.unmap()
class VideoWindow(QMainWindow):
def __init__(self, parent=None):
super(VideoWindow, self).__init__(parent)
self.setWindowTitle("PyQt Video Player Widget")
self.counter = 0
self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.videoWidget = QVideoWidget()
self.videoFrame = QVideoFrame()
self.playButton = QPushButton()
self.playButton.setEnabled(False)
self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
self.playButton.clicked.connect(self.play)
self.positionSlider = QSlider(Qt.Horizontal)
self.positionSlider.setRange(0, 0)
self.positionSlider.sliderMoved.connect(self.setPosition)
self.errorLabel = QLabel()
self.errorLabel.setSizePolicy(QSizePolicy.Preferred,
QSizePolicy.Maximum)
# Create new action
openAction = QAction(QIcon('open.png'), '&Open', self)
openAction.setShortcut('Ctrl+O')
openAction.setStatusTip('Open video')
openAction.triggered.connect(self.openFile)
# Create exit action
exitAction = QAction(QIcon('quit.png'), '&Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.setStatusTip('Exit application')
exitAction.triggered.connect(self.exitCall)
screenshotAction = QAction(QIcon('screenshot.png'), '&Screenshot', self)
screenshotAction.setShortcut('Ctrl+S')
screenshotAction.setStatusTip('Screenshot scenes')
screenshotAction.triggered.connect(self.screenshotCall)
# Create menu bar and add action
menuBar = self.menuBar()
fileMenu = menuBar.addMenu('&File')
#fileMenu.addAction(newAction)
fileMenu.addAction(openAction)
fileMenu.addAction(screenshotAction)
fileMenu.addAction(exitAction)
# Create a widget for window contents
wid = QWidget(self)
self.setCentralWidget(wid)
# Create layouts to place inside widget
controlLayout = QHBoxLayout()
controlLayout.setContentsMargins(0, 0, 0, 0)
controlLayout.addWidget(self.playButton)
controlLayout.addWidget(self.positionSlider)
layout = QVBoxLayout()
layout.addWidget(self.videoWidget)
layout.addLayout(controlLayout)
layout.addWidget(self.errorLabel)
# Set widget to contain window contents
wid.setLayout(layout)
self.mediaPlayer.setVideoOutput(self.videoWidget)
self.mediaPlayer.stateChanged.connect(self.mediaStateChanged)
self.mediaPlayer.positionChanged.connect(self.positionChanged)
self.mediaPlayer.durationChanged.connect(self.durationChanged)
self.mediaPlayer.error.connect(self.handleError)
def openFile(self):
fileName, _ = QFileDialog.getOpenFileName(self, "Open Movie",
QDir.homePath())
self.path = osp.dirname(str(fileName))
if fileName != '':
self.mediaPlayer.setMedia(
QMediaContent(QUrl.fromLocalFile(fileName)))
self.playButton.setEnabled(True)
def exitCall(self):
sys.exit(app.exec_())
def screenshotCall(self):
#Call video frame grabber
self.grabber = VideoFrameGrabber(self.videoWidget, self)
self.mediaPlayer.setVideoOutput(self.grabber)
self.mediaPlayer.pause()
self.grabber.frameAvailable.connect(self.process_frame)
self.errorLabel.setText("Taking a screenshot of image "+str(self.counter)+" ....")
self.mediaPlayer.play()
self.mediaPlayer.setVideoOutput(self.videoWidget)
def play(self):
if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
self.mediaPlayer.pause()
else:
self.mediaPlayer.play()
def mediaStateChanged(self, state):
if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
self.playButton.setIcon(
self.style().standardIcon(QStyle.SP_MediaPause))
else:
self.playButton.setIcon(
self.style().standardIcon(QStyle.SP_MediaPlay))
def positionChanged(self, position):
self.positionSlider.setValue(position)
def durationChanged(self, duration):
self.positionSlider.setRange(0, duration)
def setPosition(self, position):
self.mediaPlayer.setPosition(position)
def handleError(self):
self.playButton.setEnabled(False)
self.errorLabel.setText("Error: " + self.mediaPlayer.errorString())
def process_frame(self, image):
# Save image here
filename = "screenshot" + str(self.counter).zfill(6)
self.path = 'C:/Desktop/temp'
image.save(self.path+'/{}.png'.format(str(filename)))
self.counter = self.counter+1
if __name__ == '__main__':
app = QApplication(sys.argv)
player = VideoWindow()
player.resize(720, 480)
player.show()
sys.exit(app.exec_())
However, whenever I try taking a screenshot, the video display turns black. Based from the audio, the video is still playing, but the current display remains black all throughout the duration of the video from the moment the screenshot is taken. This happens for both when the player is paused and while it is still playing. I think it's because of the line self.mediaPlayer.setVideoOutput(self.grabber), since it overwrites the current display on the screen with the grabber.
I've tried calling the videoWidget back and set it as the video output after the frame was grabbed, but it seems to overwrite the grabber and does not produce any screenshots at all.
Is there a way for me to simultaneously take screenshots and still display the video on the GUI?
solved this by calling the pause function every time the video plays, and then playing the part of the video where it was paused when the play button is pressed.
here's the code:
def screenshotCall(self):
#Call video frame grabber
self.grabber = VideoFrameGrabber(self.videoWidget, self)
self.mediaPlayer.setVideoOutput(self.grabber)
self.grabber.frameAvailable.connect(self.process_frame)
self.errorLabel.setText("Taking a screenshot of image "+str(self.counter)+" ....")
self.mediaPlayer.pause()
def play(self):
if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
self.mediaPlayer.pause()
else:
self.mediaPlayer.play()
self.mediaPlayer.setVideoOutput(self.videoWidget)
I have a program that plays video with LibVLC, and I want to put some circular buttons on top of the VLC Widget for a barrage effect.
This is my test code.
# -*- coding: utf-8 -*-
import sys
import os
import vlc
from PySide2.QtWidgets import *
from PySide2.QtGui import *
from PySide2.QtCore import *
class demo_widget(QWidget):
def __init__(self):
super(demo_widget, self).__init__()
self.__ui__()
def __ui__(self):
self.resize(600, 400)
t_lay_parent = QHBoxLayout()
t_lay_parent.setContentsMargins(0, 0, 0, 0)
self.frame_media = QFrame(self)
t_lay_parent.addWidget(self.frame_media)
self.setLayout(t_lay_parent)
self.pushButton_test = QPushButton("Test", self)
self.pushButton_test.setFixedSize(70, 30)
self.pushButton_test.setStyleSheet("QPushButton{background-color:#36404A;border:1px solid #36404A;border-radius:10px;color:#98A6AD;}")
self.pushButton_test.move(265, 185)
self.pushButton_test.clicked.connect(self.slt_play)
self.instance = vlc.Instance("--network-caching=1000 --http-continuous")
self.player = self.instance.media_player_new()
if sys.platform.startswith('linux'): # for Linux using the X Server
self.player.set_xwindow(self.frame_media.winId())
elif sys.platform == "win32": # for Windows
self.player.set_hwnd(self.frame_media.winId())
elif sys.platform == "darwin": # for MacOS
self.player.set_nsobject(self.frame_media.winId())
def slt_play(self):
media = self.instance.media_new("1111.m4v")
self.player.set_media(media)
self.player.play()
app = QApplication(sys.argv)
demo = demo_widget()
demo.show()
sys.exit(app.exec_())
This is the ideal working screenshot.
But it actually produces white edges.
I tried to add the following Settings to the button, and it successfully worked as expected, but it ran outside the window.
self.pushButton_test.setWindowFlags(Qt.SplashScreen | Qt.FramelessWindowHint)
self.pushButton_test.setAttribute(Qt.WA_TranslucentBackground, True)
Is there a better way to draw a button with a transparent circular Angle?
A possible solution is to use QRegion with setMask():
# -*- coding: utf-8 -*-
import sys
import os
import vlc
from PySide2 import QtCore, QtGui, QtWidgets
class RoundButton(QtWidgets.QPushButton):
def __init__(self, radius, *args, **kwargs):
super(RoundButton, self).__init__(*args, **kwargs)
self._radius = radius
def resizeEvent(self, event):
r = self.rect()
rb = QtCore.QRect(0, 0, 2*self._radius, 2*self._radius)
reg = QtGui.QRegion(rb, QtGui.QRegion.Ellipse)
rb.moveRight(r.right())
reg += QtGui.QRegion(rb, QtGui.QRegion.Ellipse)
rb.moveBottom(r.bottom())
reg += QtGui.QRegion(rb, QtGui.QRegion.Ellipse)
rb.moveLeft(r.left())
reg += QtGui.QRegion(rb, QtGui.QRegion.Ellipse)
reg += QtGui.QRegion(self._radius, 0, r.width() - 2*self._radius, r.height())
reg += QtGui.QRegion(0, self._radius, r.width(), r.height() - 2*self._radius)
self.setMask(reg)
super(RoundButton, self).resizeEvent(event)
class demo_widget(QtWidgets.QWidget):
def __init__(self):
super(demo_widget, self).__init__()
self.__ui__()
def __ui__(self):
self.resize(600, 400)
t_lay_parent = QtWidgets.QHBoxLayout(self)
t_lay_parent.setContentsMargins(0, 0, 0, 0)
self.frame_media = QtWidgets.QFrame()
t_lay_parent.addWidget(self.frame_media)
self.pushButton_test = RoundButton(10, "Test", self)
self.pushButton_test.setFixedSize(70, 30)
self.pushButton_test.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
self.pushButton_test.setStyleSheet("""QPushButton{
background-color:#36404A;
border:1px solid #36404A;
color:#98A6AD;
}""")
self.pushButton_test.move(265, 185)
self.pushButton_test.clicked.connect(self.slt_play)
self.instance = vlc.Instance("--network-caching=1000 --http-continuous")
self.player = self.instance.media_player_new()
if sys.platform.startswith('linux'): # for Linux using the X Server
self.player.set_xwindow(self.frame_media.winId())
elif sys.platform == "win32": # for Windows
self.player.set_hwnd(self.frame_media.winId())
elif sys.platform == "darwin": # for MacOS
self.player.set_nsobject(self.frame_media.winId())
def slt_play(self):
media = self.instance.media_new("1111.m4v")
self.player.set_media(media)
self.player.play()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
demo = demo_widget()
demo.show()
sys.exit(app.exec_())
I am trying to use QMediaPlayer to create a.. media player. I want to have an ability to rewind videos on press of a button.
But setting a negative playbackRate via QMediaPlayer.setPlaybackRate doesn't seem to put video on rewind. It just keeps playing forward.
I don't want to change the position of the video, I want the video to play at negative speed. Through some logic of mine, setting playbackRate to a negative value would make the video play in reverse. But that just doesn't happen. If you can't understand me clearly, here is a video of what the playback should look like.
Here is some barebones code to reproduce the problem:
import sys
from PyQt5.QtCore import Qt, QUrl, QEvent
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtWidgets import QMainWindow, QApplication
class VideoWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
videoWidget = QVideoWidget()
self.setCentralWidget(videoWidget)
self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.mediaPlayer.setVideoOutput(videoWidget)
self.mediaPlayer.setMedia(
QMediaContent(QUrl.fromLocalFile(r"<some video file>.mp4"))
)
self.mediaPlayer.play()
app.installEventFilter(self)
def eventFilter(self, source, event):
if event.type() == QEvent.KeyPress:
key = event.key()
if key == Qt.Key_A:
self.mediaPlayer.setPlaybackRate(1.0)
elif key == Qt.Key_Y:
self.mediaPlayer.setPlaybackRate(-1.0) # This doesn't work! :(
return super().eventFilter(source, event)
def closeEvent(self, event):
self.mediaPlayer.setMedia(QMediaContent())
if __name__ == '__main__':
app = QApplication(sys.argv)
player = VideoWindow()
player.resize(640, 480)
player.show()
exitCode = app.exec_()
sys.exit(exitCode)
I tried searching for a solution, but I got nothing more than what documentation says (emphasis mine):
Values less than zero can be set and indicate the media will rewind at
the multiplier of the standard pace.
However, I am not seeing this effect.
I did notice this:
Not all playback services support change of the playback rate.
Is it possible that I can't rewind an mp4? Perhaps I need to install / change something?
QMediaPlayer.playbackRate property holds the playback rate of the current media.
This value is a multiplier applied to the media's standard play rate.
Press the Key_A, Key_Z, Key_Y keys to see how it works.
If you want to rewind the video, you should use QMediaPlayer.position property, which holds the playback position of the current media.
The value is the current playback position, expressed in milliseconds since the beginning of the media.
Press the Key_M, Key_P keys to see how it works.
import sys
from PyQt5.QtCore import Qt, QUrl, QEvent
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtWidgets import QMainWindow, QApplication
class VideoWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
videoWidget = QVideoWidget()
self.setCentralWidget(videoWidget)
self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.mediaPlayer.setVideoOutput(videoWidget)
self.mediaPlayer.setMedia(
QMediaContent(QUrl.fromLocalFile(r"<some video file>.mp4"))
)
self.mediaPlayer.play()
app.installEventFilter(self)
def eventFilter(self, source, event):
if event.type() == QEvent.KeyPress:
key = event.key()
# It Playback Rate !
if key == Qt.Key_A:
#self.mediaPlayer.setPlaybackRate(1.0)
self.mediaPlayer.setPlaybackRate(1.5)
elif key == Qt.Key_Z:
self.mediaPlayer.setPlaybackRate(0.8)
elif key == Qt.Key_Y:
self.mediaPlayer.setPlaybackRate(1.0)
# setPosition(int), argument is in milliseconds.
elif key == Qt.Key_M:
self.mediaPlayer.setPosition(self.mediaPlayer.position() - 10000)
elif key == Qt.Key_P:
self.mediaPlayer.setPosition(self.mediaPlayer.position() + 10000)
return super().eventFilter(source, event)
def closeEvent(self, event):
self.mediaPlayer.setMedia(QMediaContent())
if __name__ == '__main__':
app = QApplication(sys.argv)
player = VideoWindow()
player.resize(640, 480)
player.show()
exitCode = app.exec_()
sys.exit(exitCode)