Ejemplo n.º 1
0
class NowPlayingWidget(QtWidgets.QGraphicsView):
    def __init__(self, media_player):
        super().__init__()
        self._media_player = media_player
        self._media_player.currentMediaChanged.connect(self.change_title)

        self.setScene(QtWidgets.QGraphicsScene(self))
        self.init_ui()

    def set_opacity(self, value):
        self._opacity = value
        self.overlay.setOpacity(value)

    def init_ui(self):
        self.main_layout = QtWidgets.QVBoxLayout()
        self.main_layout.setContentsMargins(0, 0, 0, 0)
        self.setFixedHeight(200)

        self.now_playing_visual = NowPlayingVisual(self._media_player, self)
        self.main_layout.addWidget(self.now_playing_visual)

        self.setBackgroundBrush(QtGui.QBrush(QtCore.Qt.black))

        self.video_item = QGraphicsVideoItem()
        self.video_item.setGraphicsEffect(QtWidgets.QGraphicsBlurEffect())
        self.video_item.setAspectRatioMode(
            QtCore.Qt.KeepAspectRatioByExpanding)
        self._media_player.setVideoOutput(self.video_item)
        self.scene().addItem(self.video_item)

        self.overlay = QtWidgets.QGraphicsRectItem(0, 0, 0, 0, self.video_item)
        self.overlay.setBrush(QtGui.QBrush(QtCore.Qt.black))
        self.set_opacity(0.8)

        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)

        self.setStyleSheet('border: 0px;')

        self.setLayout(self.main_layout)

    def change_title(self, media):
        data = self._media_player.nowplaying()
        if data:
            self.now_playing_visual.set_title(data)

    def resizeEvent(self, event):
        self.video_item.setSize(QtCore.QSizeF(self.size()))
        rect = QtCore.QRectF(0, 0,
                             self.video_item.size().width(),
                             self.video_item.size().height())
        self.overlay.setRect(rect)
Ejemplo n.º 2
0
class CanvasVideo(QWidget):
    """Canvas for comparing videos.

    Now only support comparing two videos
    """
    def __init__(self, parent):
        super(CanvasVideo, self).__init__()
        self.parent = parent

        self.info_text = []
        self.flag_show_info = True

        # initialize widgets and layout
        self.init_widgets_layout()
        self.qview_bg_color = 'white'
        self.show_fingerprint = False

        # for auto zoom ratio
        self.target_zoom_width = 0

    def init_player(self):
        if not hasattr(self, 'player1'):
            # the first video player
            self.videoitem1 = QGraphicsVideoItem()
            self.player1 = QMediaPlayer(self)
            self.player1.setVideoOutput(self.videoitem1)
            # the second video player
            self.videoitem2 = QGraphicsVideoItem()
            self.player2 = QMediaPlayer(self)
            self.player2.setVideoOutput(self.videoitem2)

            # signal-slot
            self.player1.stateChanged.connect(self.mediaStateChanged)
            self.player1.positionChanged.connect(self.positionChanged)
            self.player1.durationChanged.connect(self.durationChanged)

            # add to scene
            self.scene_text = self.qscenes[0].addText('')
            self.qscenes[0].addItem(self.videoitem1)
            self.qscenes[0].addItem(self.videoitem2)

            self.flag_front_player = '1'
            self.pause_pos = 0

    def open_files(self):
        # init players
        self.init_player()
        # open the first video file
        self.video_file = self._open_one_file()
        self.player1.setMedia(
            QMediaContent(QUrl.fromLocalFile(self.video_file)))
        height, width = self.videoitem1.size().height(), self.videoitem1.size(
        ).width()
        self.qscenes[0].set_width_height(width, height)
        # put video always in the center of a QGraphicsView
        self.qscenes[0].setSceneRect(0, 0, width, height)

        # open the second video file
        self.video_file2 = self._open_one_file()
        self.player2.setMedia(
            QMediaContent(QUrl.fromLocalFile(self.video_file2)))

        self.playButton.setEnabled(True)
        self.syncButton.setEnabled(True)
        self.clearButton.setEnabled(True)
        self.infoButton.setEnabled(True)

        self.show_video(init=True)
        self.show_video_info()

    def _open_one_file(self):
        # get open file name
        try:
            with open(os.path.join(ROOT_DIR, 'history.txt'), 'r') as f:
                history = f.readlines()[0]
                history = history.strip()
        except Exception:
            history = '.'
        key, ok = QFileDialog.getOpenFileName(self, 'Open Video', history)
        if ok:
            # save history
            try:
                with open(os.path.join(ROOT_DIR, 'history.txt'), 'r') as f:
                    lines = f.readlines()
                    lines = [line.strip() for line in lines]
                    if len(lines) == 5:
                        del lines[-1]
            except Exception:
                lines = []
            # add the new record to the first line
            if key not in lines:
                lines.insert(0, key)
            with open(os.path.join(ROOT_DIR, 'history.txt'), 'w') as f:
                for line in lines:
                    f.write(f'{line}\n')
            return key

    def init_widgets_layout(self):
        # QGraphicsView - QGraphicsScene - QPixmap
        self.qscenes = []
        self.qviews = []
        show_info = False
        self.qscenes.append(HVScene(self, show_info=show_info))
        self.qviews.append(HVView(self.qscenes[0], self, show_info=show_info))

        # ---------------------------------------
        # layouts
        # ---------------------------------------
        main_layout = QGridLayout(self)
        # QGridLayout:
        # int row, int column, int rowSpan, int columnSpan
        main_layout.addWidget(self.qviews[0], 0, 0, -1, 50)

        self.infoButton = QPushButton()
        self.infoButton.setEnabled(False)
        self.infoButton.setFixedSize(QSize(80, 80))
        self.infoButton.setIcon(self.style().standardIcon(
            QStyle.SP_MessageBoxInformation))
        self.infoButton.clicked.connect(self.show_video_info)

        self.clearButton = QPushButton()
        self.clearButton.setEnabled(False)
        self.clearButton.setFixedSize(QSize(80, 80))
        self.clearButton.setIcon(self.style().standardIcon(
            QStyle.SP_TrashIcon))
        self.clearButton.clicked.connect(self.clear_players)

        self.syncButton = QPushButton()
        self.syncButton.setEnabled(False)
        self.syncButton.setFixedSize(QSize(80, 80))
        self.syncButton.setIcon(self.style().standardIcon(
            QStyle.SP_BrowserReload))
        self.syncButton.clicked.connect(self.sync_two_players)

        self.playButton = QPushButton()
        self.playButton.setFixedSize(QSize(80, 80))
        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)

        # Create layouts to place inside widget
        controlLayout = QHBoxLayout()
        controlLayout.setContentsMargins(0, 0, 0, 0)
        controlLayout.addWidget(self.playButton)
        controlLayout.addWidget(self.syncButton)
        controlLayout.addWidget(self.positionSlider)

        # controlLayout2 = QVBoxLayout()
        # controlLayout2.setContentsMargins(0, 0, 0, 0)

        # controlLayout2.addWidget(self.playButton)
        # controlLayout2.addLayout(controlLayout)
        main_layout.addWidget(self.clearButton, 59, 0, 1, 1)
        main_layout.addWidget(self.infoButton, 58, 0, 1, 1)
        main_layout.addLayout(controlLayout, 60, 0, -1, 49)

        self.qviews[0].set_shown_text(
            ['Click Open to open ·two· videos for comparison!'])

    def keyPressEvent(self, event):
        modifiers = QApplication.keyboardModifiers()
        if event.key() == QtCore.Qt.Key_F9:
            self.toggle_bg_color()
        elif event.key() == QtCore.Qt.Key_R:
            for qview in self.qviews:
                qview.set_zoom(1)
        elif event.key() == QtCore.Qt.Key_C:
            print('Enter C')
            self.compare_folders(1)
        elif event.key() == QtCore.Qt.Key_V:
            self.compare_folders(-1)

        elif event.key() == QtCore.Qt.Key_Space:
            if modifiers == QtCore.Qt.ShiftModifier:
                self.dir_browse(10)
            else:
                self.dir_browse(1)
        elif event.key() == QtCore.Qt.Key_Backspace:
            if modifiers == QtCore.Qt.ShiftModifier:
                self.dir_browse(-10)
            else:
                self.dir_browse(-1)
        elif event.key() == QtCore.Qt.Key_Right:
            if modifiers == QtCore.Qt.ShiftModifier:
                self.dir_browse(10)
            else:
                self.dir_browse(1)
        elif event.key() == QtCore.Qt.Key_Left:
            if modifiers == QtCore.Qt.ShiftModifier:
                self.dir_browse(-10)
            else:
                self.dir_browse(-1)

        elif event.key() == QtCore.Qt.Key_Up:
            if modifiers == QtCore.Qt.ShiftModifier:
                scale = 1.2
            else:
                scale = 1.05
            for qview in self.qviews:
                qview.zoom_in(scale=scale)
        elif event.key() == QtCore.Qt.Key_Down:
            if modifiers == QtCore.Qt.ShiftModifier:
                scale = 1.2
            else:
                scale = 1.05
            for qview in self.qviews:
                qview.zoom_out(scale=scale)

        elif event.key() == QtCore.Qt.Key_F11:
            self.parent.switch_fullscreen()

    def show_video_info(self):
        if self.flag_show_info is True:
            # if not self.info_text:
            if self.player1.metaData('Resolution') is not None:
                resolution_str1 = (
                    f"Resolution : {self.player1.metaData('Resolution').width()} "
                    f"x {self.player1.metaData('Resolution').height()}")
            else:
                resolution_str1 = ('Resolution : None')
            if self.player2.metaData('Resolution') is not None:
                resolution_str2 = (
                    f"Resolution : {self.player2.metaData('Resolution').width()} "
                    f"x {self.player2.metaData('Resolution').height()}")
            else:
                resolution_str2 = ('Resolution : None')

            self.info_text = [
                f'Title      : {os.path.basename(self.video_file)}',
                resolution_str1,
                f"Duration   : {str(self.player1.metaData('Duration'))}",
                f"FrameRate  : {str(self.player1.metaData('VideoFrameRate'))}",
                f"BitRate    : {str(self.player1.metaData('VideoBitRate'))}",
                f"Video Codec: {str(self.player1.metaData('VideoCodec'))}",
                '',
                f'Title      : {os.path.basename(self.video_file2)}',
                resolution_str2,
                f"Duration   : {str(self.player2.metaData('Duration'))}",
                f"FrameRate  : {str(self.player2.metaData('VideoFrameRate'))}",
                f"BitRate    : {str(self.player2.metaData('VideoBitRate'))}",
                f"Video Codec: {str(self.player2.metaData('VideoCodec'))}",
            ]
            self.qviews[0].set_shown_text(self.info_text)
            self.flag_show_info = False
        else:
            self.qviews[0].set_shown_text(
                ['Click InfoButtion to show video information'])
            self.flag_show_info = True

        self.qscenes[0].update()  # update the shown text

    def clear_players(self):
        if hasattr(self, 'player1'):
            self.player1.stop()
            self.player2.stop()
            self.qscenes[0].clear()
            del self.videoitem1
            del self.videoitem2
            del self.player1
            del self.player2
            gc.collect()
            self.playButton.setEnabled(False)
            self.syncButton.setEnabled(False)
            self.clearButton.setEnabled(False)
            self.infoButton.setEnabled(False)
            self.positionSlider.setRange(0, 0)

            # clear the shown text
            self.qviews[0].set_shown_text([])
            self.qscenes[0].update()

    def sync_two_players(self):
        position = self.player1.position()
        self.player1.setPosition(position)
        self.player2.setPosition(position)

    def play(self):
        """only control player 1"""
        if self.player1.state() == QMediaPlayer.PlayingState:
            self.pause_pos = self.player1.position()
            print(self.pause_pos, self.player1.duration(),
                  self.player2.duration())
            self.player1.pause()
            self.player2.pause()
        else:
            self.player1.play()
            self.player2.play()

    def positionChanged(self, position):
        self.positionSlider.setValue(position)

    def durationChanged(self, duration):
        self.positionSlider.setRange(0, duration)

    def setPosition(self, position):
        self.player1.setPosition(position)
        self.player2.setPosition(position)

    def mediaStateChanged(self, state):
        if self.player1.state() == QMediaPlayer.PlayingState:
            self.playButton.setIcon(self.style().standardIcon(
                QStyle.SP_MediaPause))
        else:
            self.playButton.setIcon(self.style().standardIcon(
                QStyle.SP_MediaPlay))

    def compare_folders(self, step):
        self.show_video()

    def show_video(self, init=False):
        if hasattr(self, 'player1'):
            if self.flag_front_player == '1':
                self.scene_text.setPlainText(os.path.basename(self.video_file))
                self.flag_front_player = '2'
                self.qscenes[0].setFocusItem(self.videoitem2)
                self.videoitem2.stackBefore(self.videoitem1)
                # refresh frame in pause state
                # TODO: still have problem
                if self.player1.state() != QMediaPlayer.PlayingState:
                    self.setPosition(self.pause_pos)
            else:
                self.scene_text.setPlainText(os.path.basename(
                    self.video_file2))
                self.flag_front_player = '1'
                self.qscenes[0].setFocusItem(self.videoitem1)
                self.videoitem1.stackBefore(self.videoitem2)
                # refresh frame in pause state
                # TODO: still have problem
                if self.player1.state() != QMediaPlayer.PlayingState:
                    self.setPosition(self.pause_pos)

            self.qviews[0].set_transform()

    def dir_browse(self, step):
        self.show_video()

    def toggle_bg_color(self):
        if self.qview_bg_color == 'white':
            self.qview_bg_color = 'lightgray'
            for qscene in self.qscenes:
                qscene.setBackgroundBrush(QColor(211, 211, 211))
        else:
            self.qview_bg_color = 'white'
            for qscene in self.qscenes:
                qscene.setBackgroundBrush(QtCore.Qt.white)