1#!/usr/bin/env python
2
3
4#############################################################################
5##
6## Copyright (C) 2013 Riverbank Computing Limited.
7## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
8## All rights reserved.
9##
10## This file is part of the examples of PyQt.
11##
12## $QT_BEGIN_LICENSE:BSD$
13## You may use this file under the terms of the BSD license as follows:
14##
15## "Redistribution and use in source and binary forms, with or without
16## modification, are permitted provided that the following conditions are
17## met:
18##   * Redistributions of source code must retain the above copyright
19##     notice, this list of conditions and the following disclaimer.
20##   * Redistributions in binary form must reproduce the above copyright
21##     notice, this list of conditions and the following disclaimer in
22##     the documentation and/or other materials provided with the
23##     distribution.
24##   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
25##     the names of its contributors may be used to endorse or promote
26##     products derived from this software without specific prior written
27##     permission.
28##
29## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
40## $QT_END_LICENSE$
41##
42#############################################################################
43
44
45from PyQt5.QtCore import QFileInfo, QSize, Qt
46from PyQt5.QtGui import QMovie, QPalette
47from PyQt5.QtWidgets import (QApplication, QCheckBox, QFileDialog, QGridLayout,
48        QHBoxLayout, QLabel, QSizePolicy, QSlider, QSpinBox, QStyle,
49        QToolButton, QVBoxLayout, QWidget)
50
51
52class MoviePlayer(QWidget):
53    def __init__(self, parent=None):
54        super(MoviePlayer, self).__init__(parent)
55
56        self.movie = QMovie(self)
57        self.movie.setCacheMode(QMovie.CacheAll)
58
59        self.movieLabel = QLabel("No movie loaded")
60        self.movieLabel.setAlignment(Qt.AlignCenter)
61        self.movieLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
62        self.movieLabel.setBackgroundRole(QPalette.Dark)
63        self.movieLabel.setAutoFillBackground(True)
64
65        self.currentMovieDirectory = ''
66
67        self.createControls()
68        self.createButtons()
69
70        self.movie.frameChanged.connect(self.updateFrameSlider)
71        self.movie.stateChanged.connect(self.updateButtons)
72        self.fitCheckBox.clicked.connect(self.fitToWindow)
73        self.frameSlider.valueChanged.connect(self.goToFrame)
74        self.speedSpinBox.valueChanged.connect(self.movie.setSpeed)
75
76        mainLayout = QVBoxLayout()
77        mainLayout.addWidget(self.movieLabel)
78        mainLayout.addLayout(self.controlsLayout)
79        mainLayout.addLayout(self.buttonsLayout)
80        self.setLayout(mainLayout)
81
82        self.updateFrameSlider()
83        self.updateButtons()
84
85        self.setWindowTitle("Movie Player")
86        self.resize(400, 400)
87
88    def open(self):
89        fileName, _ = QFileDialog.getOpenFileName(self, "Open a Movie",
90                self.currentMovieDirectory)
91
92        if fileName:
93            self.openFile(fileName)
94
95    def openFile(self, fileName):
96        self.currentMovieDirectory = QFileInfo(fileName).path()
97
98        self.movie.stop()
99        self.movieLabel.setMovie(self.movie)
100        self.movie.setFileName(fileName)
101        self.movie.start()
102
103        self.updateFrameSlider();
104        self.updateButtons();
105
106    def goToFrame(self, frame):
107        self.movie.jumpToFrame(frame)
108
109    def fitToWindow(self):
110        self.movieLabel.setScaledContents(self.fitCheckBox.isChecked())
111
112    def updateFrameSlider(self):
113        hasFrames = (self.movie.currentFrameNumber() >= 0)
114
115        if hasFrames:
116            if self.movie.frameCount() > 0:
117                self.frameSlider.setMaximum(self.movie.frameCount() - 1)
118            elif self.movie.currentFrameNumber() > self.frameSlider.maximum():
119                self.frameSlider.setMaximum(self.movie.currentFrameNumber())
120
121            self.frameSlider.setValue(self.movie.currentFrameNumber())
122        else:
123            self.frameSlider.setMaximum(0)
124
125        self.frameLabel.setEnabled(hasFrames)
126        self.frameSlider.setEnabled(hasFrames)
127
128    def updateButtons(self):
129        state = self.movie.state()
130
131        self.playButton.setEnabled(self.movie.isValid() and
132                self.movie.frameCount() != 1 and state == QMovie.NotRunning)
133        self.pauseButton.setEnabled(state != QMovie.NotRunning)
134        self.pauseButton.setChecked(state == QMovie.Paused)
135        self.stopButton.setEnabled(state != QMovie.NotRunning)
136
137    def createControls(self):
138        self.fitCheckBox = QCheckBox("Fit to Window")
139
140        self.frameLabel = QLabel("Current frame:")
141
142        self.frameSlider = QSlider(Qt.Horizontal)
143        self.frameSlider.setTickPosition(QSlider.TicksBelow)
144        self.frameSlider.setTickInterval(10)
145
146        speedLabel = QLabel("Speed:")
147
148        self.speedSpinBox = QSpinBox()
149        self.speedSpinBox.setRange(1, 9999)
150        self.speedSpinBox.setValue(100)
151        self.speedSpinBox.setSuffix("%")
152
153        self.controlsLayout = QGridLayout()
154        self.controlsLayout.addWidget(self.fitCheckBox, 0, 0, 1, 2)
155        self.controlsLayout.addWidget(self.frameLabel, 1, 0)
156        self.controlsLayout.addWidget(self.frameSlider, 1, 1, 1, 2)
157        self.controlsLayout.addWidget(speedLabel, 2, 0)
158        self.controlsLayout.addWidget(self.speedSpinBox, 2, 1)
159
160    def createButtons(self):
161        iconSize = QSize(36, 36)
162
163        openButton = QToolButton()
164        openButton.setIcon(self.style().standardIcon(QStyle.SP_DialogOpenButton))
165        openButton.setIconSize(iconSize)
166        openButton.setToolTip("Open File")
167        openButton.clicked.connect(self.open)
168
169        self.playButton = QToolButton()
170        self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
171        self.playButton.setIconSize(iconSize)
172        self.playButton.setToolTip("Play")
173        self.playButton.clicked.connect(self.movie.start)
174
175        self.pauseButton = QToolButton()
176        self.pauseButton.setCheckable(True)
177        self.pauseButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPause))
178        self.pauseButton.setIconSize(iconSize)
179        self.pauseButton.setToolTip("Pause")
180        self.pauseButton.clicked.connect(self.movie.setPaused)
181
182        self.stopButton = QToolButton()
183        self.stopButton.setIcon(self.style().standardIcon(QStyle.SP_MediaStop))
184        self.stopButton.setIconSize(iconSize)
185        self.stopButton.setToolTip("Stop")
186        self.stopButton.clicked.connect(self.movie.stop)
187
188        quitButton = QToolButton()
189        quitButton.setIcon(self.style().standardIcon(QStyle.SP_DialogCloseButton))
190        quitButton.setIconSize(iconSize)
191        quitButton.setToolTip("Quit")
192        quitButton.clicked.connect(self.close)
193
194        self.buttonsLayout = QHBoxLayout()
195        self.buttonsLayout.addStretch()
196        self.buttonsLayout.addWidget(openButton)
197        self.buttonsLayout.addWidget(self.playButton)
198        self.buttonsLayout.addWidget(self.pauseButton)
199        self.buttonsLayout.addWidget(self.stopButton)
200        self.buttonsLayout.addWidget(quitButton)
201        self.buttonsLayout.addStretch()
202
203
204if __name__ == '__main__':
205
206    import sys
207
208    app = QApplication(sys.argv)
209    player = MoviePlayer()
210    player.show()
211    sys.exit(app.exec_())
212