Transparent widget problem over a vlc video on

Viewed 272

I am trying to display transparent label over video output using PyQt and vlc library. Although I can put my label on video, the part under the label is not visible as if there is no video underneath. By the way, target platform is Windows. Also, I think the problem is setting media player to video frame window id. However, if I remove the line 'self.mediaplayer.set_hwnd(int(self.videoframe.winId()))', the video would be displayed in it's own window not my player window.

My attempt looks like this:

this.

My code is attached below:

import platform
import sys
import vlc

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont


class Player(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Media Player")

        # Create a basic vlc instance
        self.instance = vlc.Instance()

        self.media = None

        # Create an empty vlc media player
        self.mediaplayer = self.instance.media_player_new()

        self.widget = QtWidgets.QWidget(self)
        self.setCentralWidget(self.widget)

        self.lbl = QtWidgets.QLabel()
        font = QFont('Helvetica', 16, QFont.Bold)
        self.lbl.setFont(font)
        self.lbl.setText("This is my\ntransparent\nlabel.")
        self.lbl.setAlignment(Qt.AlignCenter)
        self.lbl.setFixedSize(200,200)

        self.videoframe = QtWidgets.QFrame(frameShape=QtWidgets.QFrame.Box, frameShadow=QtWidgets.QFrame.Raised)

        self.videoframe.setFixedSize(600,600)

        self.mediaplayer.set_hwnd(int(self.videoframe.winId()))

        fileName = "C:\\Users\\...\\test.mp4" #dir of the video
        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()

        self.vboxlayout = QtWidgets.QGridLayout()
        self.vboxlayout.addWidget(self.videoframe,0,0)
        self.vboxlayout.addWidget(self.lbl,0,0)
        self.widget.setLayout(self.vboxlayout)

        self.mediaplayer.play() 

if __name__ == "__main__":

    app = QtWidgets.QApplication(sys.argv)

    player = Player()
    player.show()

    sys.exit(app.exec_())
1 Answers

I just had the same problem and my solution is: JUST FOUR THICK LABELS THAT DRAW A SQUARE. here is my code:

class MouseTracker(QtCore.QObject):
positionChanged = QtCore.pyqtSignal(QtCore.QEvent)

def __init__(self, widget):
    super().__init__(widget)
    self._widget = widget
    self.widget.setMouseTracking(True)
    self.widget.installEventFilter(self)

@property
def widget(self):
    return self._widget

def eventFilter(self, o, e):
    if e.type() == QtCore.QEvent.MouseButtonPress:
        # print("pressed")
        self.positionChanged.emit(e)
    elif e.type() == QtCore.QEvent.MouseButtonRelease:
        # print("release")
        self.positionChanged.emit(e)
    if o is self.widget and e.type() == QtCore.QEvent.MouseMove:
        self.positionChanged.emit(e)
    return super().eventFilter(o, e)

then the mainclass...

class MainWindow(QMainWindow):
def __init__(self, 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.initUI()
    self.isPaused = False

def initUI(self):
    self.x0 = None
    self.y0 = None
    self.x1 = None
    self.y1 = None
    # Set up the user interface, signals & slots
    self.statusBar().showMessage("Ready")
    self.resize(640, 480)

    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.video_label = QMacCocoaViewContainer(0)
    else:
        self.video_label = QLabel()

    tracker = MouseTracker(self.video_label)
    tracker.positionChanged.connect(self.on_positionChanged)

    self.positionslider = QSlider(Qt.Horizontal, self)
    self.positionslider.setToolTip("Position")
    self.positionslider.setMaximum(1000)
    self.positionslider.sliderMoved.connect(self.setPosition)
    #########Buttons#################
    self.height_of_BTNS = 30
    self.playbutton = QPushButton("Play")
    self.playbutton.clicked.connect(self.PlayPause)

    self.stopbutton = QPushButton("Stop")
    self.stopbutton.clicked.connect(self.Stop)

    self.volumeslider = QSlider(Qt.Horizontal, self)
    self.volumeslider.setMaximum(100)
    self.volumeslider.setValue(self.mediaplayer.audio_get_volume())
    self.volumeslider.setToolTip("Volume")

    self.volumeslider.valueChanged.connect(self.setVolume)
    #################################
    self.marker_label_top = QLabel(self)
    self.marker_label_top.hide()
    self.marker_label_top.raise_()
    #################################
    self.marker_label_btm = QLabel(self)
    self.marker_label_btm.hide()
    self.marker_label_btm.raise_()
    #################################
    self.marker_label_r = QLabel(self)
    self.marker_label_r.hide()
    self.marker_label_r.raise_()
    #################################
    self.marker_label_l = QLabel(self)
    self.marker_label_l.hide()
    self.marker_label_l.raise_()

    self.hbuttonbox = QHBoxLayout()
    self.hbuttonbox.addWidget(self.playbutton)
    self.hbuttonbox.addWidget(self.stopbutton)
    self.hbuttonbox.addWidget(self.volumeslider)
    self.hbuttonbox.addStretch(1)

    self.vboxlayout = QVBoxLayout()
    self.vboxlayout.addWidget(self.video_label)
    self.vboxlayout.addWidget(self.positionslider)
    self.vboxlayout.addLayout(self.hbuttonbox)

    self.widget.setLayout(self.vboxlayout)
    ##############################
    self.label_position = QtWidgets.QLabel(self.video_label, alignment=QtCore.Qt.AlignCenter)
    self.label_position.setStyleSheet('background-color: white; border: 1px solid black')
    ##############################
    open = QAction("&Open", self)
    open.triggered.connect(self.OpenFile)
    exit = QAction("&Exit", self)
    exit.triggered.connect(sys.exit)
    menubar = self.menuBar()
    filemenu = menubar.addMenu("&File")
    filemenu.addAction(open)
    filemenu.addSeparator()
    filemenu.addAction(exit)

    self.timer = QTimer(self)
    self.timer.setInterval(200)
    self.timer.timeout.connect(self.updateUI)

    self.timer_1 = QTimer(self)
    self.timer_1.setInterval(10000)
    self.timer_1.timeout.connect(self.updateUI_info)

    # Below functions must be FALSE in order to work mousetracker
    self.mediaplayer.video_set_mouse_input(False)
    self.mediaplayer.video_set_key_input(False)

    self.show()

then the function that draw the square when the mouse button released. It actually draw 4 thick labels above the video_label. IMPORTANT TO SET FALSE the self.mediaplayer.video_set_mouse_input(False) and self.mediaplayer.video_set_key_input(False)

@QtCore.pyqtSlot(QtCore.QEvent)
def on_positionChanged(self, e):

    if e.type() == QtCore.QEvent.MouseButtonPress:
        self.statusBar().showMessage("Ready")
        self.marker_label_top.hide()
        self.marker_label_r.hide()
        self.marker_label_l.hide()
        self.marker_label_btm.hide()
        print("Mouse press")
        self.x0 = e.x()
        self.y0 = e.y()
    elif e.type() == QtCore.QEvent.MouseButtonRelease and self.x0 is not None and self.y0 is not None:
        self.x1 = e.x()
        self.y1 = e.y()
        print("Mouse release")
        if abs(self.x0 - self.x1) > 30 and abs(self.y0 - self.y1) > 30:

            marker_width = self.x1 - self.x0
            marker_height = self.y1 - self.y0
            self.marker_label_top.setStyleSheet("border: 2px solid black;")
            self.marker_label_top.resize(marker_width, 2)
            self.marker_label_top.move(self.x0, self.y0)
            self.marker_label_top.show()

            self.marker_label_l.setStyleSheet("border: 2px solid black;")
            self.marker_label_l.resize(2, marker_height)
            self.marker_label_l.move(self.x0, self.y0)
            self.marker_label_l.show()

            self.marker_label_r.setStyleSheet("border: 2px solid black;")
            self.marker_label_r.resize(2, marker_height)
            self.marker_label_r.move(self.x1, self.y0)
            self.marker_label_r.show()

            self.marker_label_btm.setStyleSheet("border: 2px solid black;")
            self.marker_label_btm.resize(marker_width, 2)
            self.marker_label_btm.move(self.x0, self.y1)
            self.marker_label_btm.show()

            print(f"Values UI MOUSE TRACKER X: {self.x0} ,Y: {self.y0}, X1: {self.x1}, Y1: {self.y1}")
        else:
            self.statusBar().showMessage("Make it bigger")
            # self.worker1.reset_values()
            self.x0 = None
            self.y0 = None
            self.x1 = None
            self.y1 = None

    self.label_position.move(e.x(), e.y())
    self.label_position.setText("(%d, %d)" % (e.x(), e.y()))
    self.label_position.adjustSize()
    self.label_position.show()

and the rest of the code

 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.timer_1.start()
        self.isPaused = False

def Stop(self):
    self.mediaplayer.stop()
    self.playbutton.setText("Play")

def OpenFile(self, filename=None):
    if filename == False:
        filename = QFileDialog.getOpenFileName(self, "Open File", os.path.expanduser('~'))[0]
    if not filename:
        return
    # # create the media
    if sys.version < '3':
        filename = vlc.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()

    if sys.platform.startswith('linux'):  # for Linux using the X Server
        self.mediaplayer.set_xwindow(self.video_label.winId())
    elif sys.platform == "win32":  # for Windows
        self.mediaplayer.set_hwnd(self.video_label.winId())
        print(self.video_label.winId())
    elif sys.platform == "darwin":  # for MacOS
        self.mediaplayer.set_nsobject(int(self.video_label.winId()))
    self.PlayPause()

def setVolume(self, Volume):
    self.mediaplayer.audio_set_volume(Volume)

def setPosition(self, position):
    # setting the position to where the slider was dragged
    self.mediaplayer.set_position(position / 1000.0)

def updateUI(self):
    # updates the user interface
    # setting the slider to the desired position
    self.positionslider.setValue(int(self.mediaplayer.get_position() * 1000))
    # self.mediaplayer.video_take_snapshot(num=0, psz_filepath='a.png', i_width=1920, i_height=1080)

    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()

def updateUI_info(self):
    fps = self.mediaplayer.get_fps()
    sec = self.mediaplayer.get_time() / 1000
    frame_no = int(round(sec * fps))
    print(
        f" Frame number Now: {frame_no} \n Frame Rate per Second: {fps} \n Current position in seconds {self.mediaplayer.get_time() / 1000} \n -------------------")

if __name__ == "__main__":
    App = QApplication(sys.argv)
    Root = MainWindow()
    if sys.argv[1:]:
        Root.OpenFile(sys.argv[1])
    sys.exit(App.exec_())

enjoy :)

Related