Exact Position of video in QVideoWidget

702 views Asked by At

I have a custom Media Player, that can display images and videos with the help of PyQt. Media player is implemented by the following code in python:

from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout, QVBoxLayout, 
QLabel, \
QSlider, QStyle, QSizePolicy, QFileDialog
import sys
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtGui import QIcon, QPalette
from PyQt5.QtCore import Qt, QUrl



class Window(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("PyQt5 Media Player")
        self.setGeometry(350, 100, 700, 500)
        self.setWindowIcon(QIcon('player.png'))

        p =self.palette()
        p.setColor(QPalette.Window, Qt.black)
        self.setPalette(p)

        self.init_ui()


        self.show()


     def init_ui(self):

        #create media player object
        self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)


        #create videowidget object

        videowidget = QVideoWidget()


        #create open button
        openBtn = QPushButton('Open Video')
        openBtn.clicked.connect(self.open_file)



        #create button for playing
        self.playBtn = QPushButton()
        self.playBtn.setEnabled(False)
        self.playBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
        self.playBtn.clicked.connect(self.play_video)



        #create slider
        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0,0)
        self.slider.sliderMoved.connect(self.set_position)



        #create label
        self.label = QLabel()
        self.label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)


        #create hbox layout
        hboxLayout = QHBoxLayout()
        hboxLayout.setContentsMargins(0,0,0,0)

        #set widgets to the hbox layout
        hboxLayout.addWidget(openBtn)
        hboxLayout.addWidget(self.playBtn)
        hboxLayout.addWidget(self.slider)



        #create vbox layout
        vboxLayout = QVBoxLayout()
        vboxLayout.addWidget(videowidget)
        vboxLayout.addLayout(hboxLayout)
        vboxLayout.addWidget(self.label)


        self.setLayout(vboxLayout)

        self.mediaPlayer.setVideoOutput(videowidget)


        #media player signals

        self.mediaPlayer.stateChanged.connect(self.mediastate_changed)
        self.mediaPlayer.positionChanged.connect(self.position_changed)
        self.mediaPlayer.durationChanged.connect(self.duration_changed)


    def open_file(self):
        filename, _ = QFileDialog.getOpenFileName(self, "Open Video")

        if filename != '':
            self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(filename)))
            self.playBtn.setEnabled(True)


    def play_video(self):
         if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.mediaPlayer.pause()

        else:
            self.mediaPlayer.play()


    def mediastate_changed(self, state):
        if self.mediaPlayer.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.mediaPlayer.setPosition(position)


    def handle_errors(self):
        self.playBtn.setEnabled(False)
        self.label.setText("Error: " + self.mediaPlayer.errorString())                          
        app = QApplication(sys.argv)                                                         
        window = Window()                                                     
        sys.exit(app.exec_())    

What I am trying to do is get the x and y coordinates of the edges of the video/image played each time and while it feels like it should be easy I really can't figure out how to do this. As displayed in the images every video/image may have different corner positions. The only thing I could think of was getting videowidgets dimensions but it wasn't right.

    print(videowidget.height())
    print(videowidget.width())                                 
    print(videowidget.x())
    print(videowidget.y())

enter image description here

enter image description here

1

There are 1 answers

0
Michal Lange On

I'm not sure if this exactly answers your question but I found a sort of solution by comparing aspect ratios of the video and the widget:

class VideoClickWidget(QVideoWidget):

    def __init__(self):
        QVideoWidget.__init__(self)
    
    def mouseReleaseEvent(self, event):
        widget_width = self.frameGeometry().width()
        widget_height = self.frameGeometry().height()
        widget_ratio = widget_width / widget_height

        video_width = self.mediaObject().metaData("Resolution").width()
        video_height = self.mediaObject().metaData("Resolution").height()
        video_ratio = video_width / video_height

        x, y  = event.pos().x(), event.pos().y()

        # It's wider
        if widget_ratio > video_ratio:
            percentage = video_ratio / widget_ratio
            # we know that video occupies $percentage$ of the widget
            dead_zone = int(np.round(widget_width * ((1 - percentage) / 2)))

            new_x = np.clip(x - dead_zone, 0, widget_width - 2 * dead_zone)

            print(new_x, y)



        else:
            percentage = widget_ratio / video_ratio

            dead_zone = int(np.round(widget_height * ((1 - percentage) / 2)))
            new_y = np.clip(y - dead_zone, 0, widget_height - 2 * dead_zone)

            print(x, new_y)

        
        
        super(QVideoWidget, self).mouseReleaseEvent(event)