Pyqt 在给定时间线显示视频缩略图

问题描述 投票:0回答:1

我有一个基本的 pyqt 视频播放器,但我希望视频时间线背景是视频当时发生的情况的图片,我必须使用什么才能有效地做到这一点?这是基本播放器:

import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
from PySide6.QtMultimediaWidgets import QVideoWidget
from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput

class PyVideoPlayer(QWidget):
    def __init__(self, parent=None):
        super(PyVideoPlayer, self).__init__(parent)

        self.mediaPlayer = QMediaPlayer()
        self.audioOutput = QAudioOutput()

        videoWidget = QVideoWidget()

        self.playButton = QPushButton()
        self.playButton.setIcon(QIcon("gui/images/svg_icons/icon_play.svg"))
        self.playButton.setEnabled(False)
        self.playButton.clicked.connect(self.play)

        self.volumeButton = QPushButton()
        self.volumeButton.setIcon(QIcon("gui/images/svg_icons/icon_volume.svg"))
        self.volumeButton.clicked.connect(self.showVolumeSlider)

        self.volumeSlider = QSlider(orientation=Qt.Horizontal)
        self.volumeSlider.setRange(0, 100)
        self.volumeSlider.setValue(self.audioOutput.volume() * 100)
        self.volumeSlider.setMaximumWidth(100)
        self.volumeSlider.sliderMoved.connect(self.setVolume)
        self.volumeSlider.hide()

        self.positionSlider = QSlider(orientation=Qt.Horizontal)
        self.positionSlider.setRange(0, 0)
        self.positionSlider.sliderMoved.connect(self.setPosition)

        self.timeLabel = QLabel()
        self.timeLabel.setStyleSheet("color: #4f5b6e; font-family: 'Roboto'; font-size: 9pt; font-weight: bold;")

        # Set up the layout
        videoLayout = QVBoxLayout()
        videoLayout.addWidget(videoWidget, stretch=1)

        controlLayout = QHBoxLayout()
        controlLayout.addWidget(self.playButton)
        controlLayout.addWidget(self.volumeButton)
        controlLayout.addWidget(self.volumeSlider)
        controlLayout.addWidget(self.timeLabel)

        layout = QVBoxLayout()
        layout.addLayout(videoLayout)
        layout.addWidget(self.positionSlider)
        layout.addLayout(controlLayout)

        layout.setContentsMargins(10, 0, 10, 0)

        self.setLayout(layout)

        self.mediaPlayer.setVideoOutput(videoWidget)
        self.mediaPlayer.playbackStateChanged.connect(self.mediaStateChanged)
        self.mediaPlayer.positionChanged.connect(self.positionChanged)
        self.mediaPlayer.durationChanged.connect(self.durationChanged)
        self.mediaPlayer.errorOccurred.connect(self.handleError)

    def setMedia(self, fileName):
        self.mediaPlayer.setSource(QUrl.fromLocalFile(fileName))
        self.mediaPlayer.setAudioOutput(self.audioOutput)
        self.playButton.setEnabled(True)
        self.play()

    def play(self):
        if self.mediaPlayer.playbackState() == QMediaPlayer.PlaybackState.PlayingState:
            self.mediaPlayer.pause()
        else:
            self.mediaPlayer.play()

    def mediaStateChanged(self, state):
        if state == QMediaPlayer.PlaybackState.PlayingState:
            self.playButton.setIcon(QIcon("gui/images/svg_icons/icon_pause.svg"))
        else:
            self.playButton.setIcon(QIcon("gui/images/svg_icons/icon_play.svg"))

    def positionChanged(self, position):
        self.positionSlider.setValue(position)
        self.timeLabel.setText(f"{position // 60000:02}:{(position // 1000) % 60:02} / {self.mediaPlayer.duration() // 60000:02}:{(self.mediaPlayer.duration() // 1000) % 60:02}")

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

    def setPosition(self, position):
        self.mediaPlayer.setPosition(position)

    def setVolume(self, volume):
        self.audioOutput.setVolume(volume / 100)

    def showVolumeSlider(self):
        if self.volumeSlider.isHidden():
            self.volumeSlider.show()
        else:
            self.volumeSlider.hide()

    def handleError(self):
        self.playButton.setEnabled(False)
        print("Error: " + self.mediaPlayer.errorString())

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = PyVideoPlayer()
    ex.setMedia("your_video.mp4")  # Replace with your video file path
    ex.show()
    sys.exit(app.exec_())

我尝试过不同的方法,例如使用 QVideoFrame,然后使用 QImage 转换为图像,但不确定它是否应该像这样使用。附上我希望时间线看起来如何的示例,任何帮助将不胜感激,谢谢。

Example Image

python video pyqt media-player pyside6
1个回答
0
投票

您可以使用

QVideoSink
https://doc.qt.io/qtforpython-6/PySide6/QtMultimedia/QVideoSink.html
videoFrame()
函数从
QtMultimedia

获取帧数据

示例:


class TimeineWidget(QWidget):
    def __init__(self):
        super(TimeineWidget, self).__init__()
        self.image = QLabel()
        self.vlayout = QVBoxLayout()
        self.resize(200, 150)
        self.setStyleSheet("background: white;")
        self.vlayout.addWidget(self.image)
        self.setLayout(self.vlayout)
        self.show()

    def setImage(self, img):
        pixmap = QPixmap(img)
        self.image.setPixmap(pixmap.scaled(200, 150, Qt.AspectRatioMode.KeepAspectRatio))


class PyVideoPlayer():
    # ...
    def __init__(self, parent=None):
        # ...

        self.timeineWidget = TimeineWidget()

        # ...

        layout = QVBoxLayout()
        layout.addLayout(videoLayout)
        layout.addWidget(self.timeineWidget) # add timeline widget to layout
        layout.addWidget(self.positionSlider)
        layout.addLayout(controlLayout)

    # Triggered in realtime while the video is playing
    def positionChanged(self, position):
        # ...

        # update image timeline
        if self.mediaPlayer.playbackState() == QMediaPlayer.PlaybackState.PlayingState:
            sink = self.mediaPlayer.videoSink()
            self.timeineWidget.setImage(sink.videoFrame().toImage())

    # Triggered by the position
    def setPosition(self, position):
        # ...

        # update image timeline
        if self.mediaPlayer.playbackState() != QMediaPlayer.PlaybackState.PlayingState:
            sink = self.mediaPlayer.videoSink()
            self.timeineWidget.setImage(sink.videoFrame().toImage())
© www.soinside.com 2019 - 2024. All rights reserved.