class Player(QWidget): fullScreenChanged = pyqtSignal(bool) def __init__(self, playlist, parent=None): super(Player, self).__init__(parent) self.colorDialog = None self.trackInfo = "" self.statusInfo = "" self.duration = 0 self.player = QMediaPlayer() self.playlist = QMediaPlaylist() self.player.setPlaylist(self.playlist) self.player.durationChanged.connect(self.durationChanged) self.player.positionChanged.connect(self.positionChanged) self.player.metaDataChanged.connect(self.metaDataChanged) self.playlist.currentIndexChanged.connect(self.playlistPositionChanged) self.player.mediaStatusChanged.connect(self.statusChanged) self.player.bufferStatusChanged.connect(self.bufferingProgress) self.player.videoAvailableChanged.connect(self.videoAvailableChanged) self.player.error.connect(self.displayErrorMessage) self.videoWidget = VideoWidget() self.player.setVideoOutput(self.videoWidget) self.playlistModel = PlaylistModel() self.playlistModel.setPlaylist(self.playlist) self.playlistView = QListView() self.playlistView.setModel(self.playlistModel) self.playlistView.setCurrentIndex( self.playlistModel.index(self.playlist.currentIndex(), 0)) self.playlistView.activated.connect(self.jump) self.slider = QSlider(Qt.Horizontal) self.slider.setRange(0, self.player.duration() / 1000) self.labelDuration = QLabel() self.slider.sliderMoved.connect(self.seek) # self.labelHistogram = QLabel() # self.labelHistogram.setText("Histogram:") # self.histogram = HistogramWidget() # histogramLayout = QHBoxLayout() # histogramLayout.addWidget(self.labelHistogram) # histogramLayout.addWidget(self.histogram, 1) self.probe = QVideoProbe() # self.probe.videoFrameProbed.connect(self.histogram.processFrame) self.probe.setSource(self.player) openButton = QPushButton("打开", clicked=self.open) controls = PlayerControls() controls.setState(self.player.state()) controls.setVolume(self.player.volume()) controls.setMuted(controls.isMuted()) controls.play.connect(self.player.play) controls.pause.connect(self.player.pause) controls.stop.connect(self.player.stop) controls.next.connect(self.playlist.next) controls.previous.connect(self.previousClicked) controls.changeVolume.connect(self.player.setVolume) controls.changeMuting.connect(self.player.setMuted) controls.changeRate.connect(self.player.setPlaybackRate) controls.stop.connect(self.videoWidget.update) self.player.stateChanged.connect(controls.setState) self.player.volumeChanged.connect(controls.setVolume) self.player.mutedChanged.connect(controls.setMuted) self.fullScreenButton = QPushButton("全屏") self.fullScreenButton.setCheckable(True) self.colorButton = QPushButton("颜色选项") self.colorButton.setEnabled(False) self.colorButton.clicked.connect(self.showColorDialog) displayLayout = QHBoxLayout() displayLayout.addWidget(self.videoWidget, 2) displayLayout.addWidget(self.playlistView) controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) controlLayout.addWidget(openButton) controlLayout.addStretch(1) controlLayout.addWidget(controls) controlLayout.addStretch(1) controlLayout.addWidget(self.fullScreenButton) controlLayout.addWidget(self.colorButton) layout = QVBoxLayout() layout.addLayout(displayLayout) hLayout = QHBoxLayout() hLayout.addWidget(self.slider) hLayout.addWidget(self.labelDuration) layout.addLayout(hLayout) layout.addLayout(controlLayout) # layout.addLayout(histogramLayout) self.setLayout(layout) if not self.player.isAvailable(): QMessageBox.warning( self, "Service not available", "The QMediaPlayer object does not have a valid service.\n" "Please check the media service plugins are installed.") controls.setEnabled(False) self.playlistView.setEnabled(False) openButton.setEnabled(False) self.colorButton.setEnabled(False) self.fullScreenButton.setEnabled(False) self.metaDataChanged() self.addToPlaylist(playlist) def open(self): fileNames, _ = QFileDialog.getOpenFileNames(self, "Open Files") self.addToPlaylist(fileNames) def addToPlaylist(self, fileNames): for name in fileNames: fileInfo = QFileInfo(name) if fileInfo.exists(): url = QUrl.fromLocalFile(fileInfo.absoluteFilePath()) if fileInfo.suffix().lower() == 'm3u': self.playlist.load(url) else: self.playlist.addMedia(QMediaContent(url)) else: url = QUrl(name) if url.isValid(): self.playlist.addMedia(QMediaContent(url)) def durationChanged(self, duration): duration /= 1000 self.duration = duration self.slider.setMaximum(duration) def positionChanged(self, progress): progress /= 1000 if not self.slider.isSliderDown(): self.slider.setValue(progress) self.updateDurationInfo(progress) def metaDataChanged(self): if self.player.isMetaDataAvailable(): self.setTrackInfo( "%s - %s" % (self.player.metaData(QMediaMetaData.AlbumArtist), self.player.metaData(QMediaMetaData.Title))) def previousClicked(self): # Go to the previous track if we are within the first 5 seconds of # playback. Otherwise, seek to the beginning. if self.player.position() <= 5000: self.playlist.previous() else: self.player.setPosition(0) def jump(self, index): if index.isValid(): self.playlist.setCurrentIndex(index.row()) self.player.play() def playlistPositionChanged(self, position): self.playlistView.setCurrentIndex(self.playlistModel.index( position, 0)) def seek(self, seconds): self.player.setPosition(seconds * 1000) def statusChanged(self, status): self.handleCursor(status) if status == QMediaPlayer.LoadingMedia: self.setStatusInfo("Loading...") elif status == QMediaPlayer.StalledMedia: self.setStatusInfo("Media Stalled") elif status == QMediaPlayer.EndOfMedia: QApplication.alert(self) elif status == QMediaPlayer.InvalidMedia: self.displayErrorMessage() else: self.setStatusInfo("") def handleCursor(self, status): if status in (QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia, QMediaPlayer.StalledMedia): self.setCursor(Qt.BusyCursor) else: self.unsetCursor() def bufferingProgress(self, progress): self.setStatusInfo("Buffering %d%" % progress) def videoAvailableChanged(self, available): if available: self.fullScreenButton.clicked.connect( self.videoWidget.setFullScreen) self.videoWidget.fullScreenChanged.connect( self.fullScreenButton.setChecked) if self.fullScreenButton.isChecked(): self.videoWidget.setFullScreen(True) else: self.fullScreenButton.clicked.disconnect( self.videoWidget.setFullScreen) self.videoWidget.fullScreenChanged.disconnect( self.fullScreenButton.setChecked) self.videoWidget.setFullScreen(False) self.colorButton.setEnabled(available) def setTrackInfo(self, info): self.trackInfo = info if self.statusInfo != "": self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo)) else: self.setWindowTitle(self.trackInfo) def setStatusInfo(self, info): self.statusInfo = info if self.statusInfo != "": self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo)) else: self.setWindowTitle(self.trackInfo) def displayErrorMessage(self): self.setStatusInfo(self.player.errorString()) def updateDurationInfo(self, currentInfo): duration = self.duration if currentInfo or duration: currentTime = QTime((currentInfo / 3600) % 60, (currentInfo / 60) % 60, currentInfo % 60, (currentInfo * 1000) % 1000) totalTime = QTime((duration / 3600) % 60, (duration / 60) % 60, duration % 60, (duration * 1000) % 1000) format = 'hh:mm:ss' if duration > 3600 else 'mm:ss' tStr = currentTime.toString(format) + " / " + totalTime.toString( format) else: tStr = "" self.labelDuration.setText(tStr) def showColorDialog(self): if self.colorDialog is None: brightnessSlider = QSlider(Qt.Horizontal) brightnessSlider.setRange(-100, 100) brightnessSlider.setValue(self.videoWidget.brightness()) brightnessSlider.sliderMoved.connect( self.videoWidget.setBrightness) self.videoWidget.brightnessChanged.connect( brightnessSlider.setValue) contrastSlider = QSlider(Qt.Horizontal) contrastSlider.setRange(-100, 100) contrastSlider.setValue(self.videoWidget.contrast()) contrastSlider.sliderMoved.connect(self.videoWidget.setContrast) self.videoWidget.contrastChanged.connect(contrastSlider.setValue) hueSlider = QSlider(Qt.Horizontal) hueSlider.setRange(-100, 100) hueSlider.setValue(self.videoWidget.hue()) hueSlider.sliderMoved.connect(self.videoWidget.setHue) self.videoWidget.hueChanged.connect(hueSlider.setValue) saturationSlider = QSlider(Qt.Horizontal) saturationSlider.setRange(-100, 100) saturationSlider.setValue(self.videoWidget.saturation()) saturationSlider.sliderMoved.connect( self.videoWidget.setSaturation) self.videoWidget.saturationChanged.connect( saturationSlider.setValue) layout = QFormLayout() layout.addRow("亮度", brightnessSlider) layout.addRow("对比度", contrastSlider) layout.addRow("色调", hueSlider) layout.addRow("饱和度", saturationSlider) button = QPushButton("关闭") layout.addRow(button) self.colorDialog = QDialog(self) self.colorDialog.setWindowTitle("颜色选项") self.colorDialog.setLayout(layout) button.clicked.connect(self.colorDialog.close) self.colorDialog.show()
class WebinterfaceService(QObject): cameraChanged = pyqtSignal(QObject) def __init__(self, parent=None): super().__init__(parent) self._camera = None self._converter = None self._latestImage = None self.app = Quart(__name__) self.app.add_url_rule('/camera.mjpeg', 'camerastream', self.getCameraStream) loop = asyncio.get_event_loop() create_server = loop.create_server( lambda: Server(self.app, loop, logger, "%(h)s %(r)s %(s)s %(b)s %(D)s", 5), '0.0.0.0', '9000', ssl=None, ) server = loop.create_task(create_server) @pyqtProperty(QObject, notify=cameraChanged) def camera(self): return self._hostname @camera.setter def camera(self, camera): self._camera = camera print("camera is now", self._camera) print("dir", dir(self._camera)) print("media", self._camera.property("mediaObject")) self.cameraChanged.emit(self._camera) self.start() def start(self): self._tasks = AioJoinableQueue(maxsize=1) self._results = AioQueue() self._exit = AioEvent() self._converter = ConverterWorker(self._tasks, self._results, self._exit) self._converter.start() camera = self._camera.property("mediaObject") self._probe = QVideoProbe(self) self._probe.setSource(camera) self._probe.videoFrameProbed.connect(self.handleFrame) def handleFrame(self, frame): if not self._tasks.full(): asyncio.ensure_future(self._handleFrame(frame)) async def _handleFrame(self, frame): frame.map(QAbstractVideoBuffer.ReadOnly) ptr = frame.bits() ptr.setsize(frame.mappedBytes()) assert frame.pixelFormat() == QVideoFrame.Format_YUV420P w = frame.width() h = frame.height() w2 = w // 2 h2 = h // 2 s = w * h s2 = w2 * h2 y = np.frombuffer(ptr, dtype=np.ubyte, count=s, offset=0) u = np.frombuffer(ptr, dtype=np.ubyte, count=s2, offset=s) v = np.frombuffer(ptr, dtype=np.ubyte, count=s2, offset=s + s2) frame.unmap() await self._tasks.coro_put((y, u, v, h, w, h2, w2)) self._latestImage = await self._results.coro_get() async def getCameraStream(self): async def camera_generator(): while True: if self._latestImage: yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + self._latestImage + b'\r\n') await asyncio.sleep(0.1) return Response(camera_generator(), mimetype='multipart/x-mixed-replace; boundary=frame')
class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.setupUi(self) self.threadpool = QThreadPool() print('Multithreading with maximum %d threads' % self.threadpool.maxThreadCount()) self.player = QMediaPlayer() # Setup the playlist. self.playlist = QMediaPlaylist() self.player.setPlaylist(self.playlist) # Setup the player self.player.durationChanged.connect(self.update_duration) self.player.positionChanged.connect(self.update_position) self.playlist.currentIndexChanged.connect( self.playlist_position_changed) self.player.error.connect(self.erroralert) self.videoWidget = QVideoWidget() self.player.setVideoOutput(self.videoWidget) self.model = PlaylistModel(self.playlist) self.playListView.setModel(self.model) selection_model = self.playListView.selectionModel() selection_model.selectionChanged.connect( self.playlist_selection_changed) self.currentFrame = QVideoFrame() # Connect control buttons/slides for media player. self.playButton.pressed.connect(self.player.play) self.pauseButton.pressed.connect(self.player.pause) self.stopButton.pressed.connect(self.player.stop) layout = QVBoxLayout() layout.addWidget(self.videoWidget) self.viewWidget.setLayout(layout) self.probe = QVideoProbe() self.probe.videoFrameProbed.connect(self.on_videoFrameProbed) self.probe.setSource(self.player) self.timeSlider.valueChanged.connect(self.player.setPosition) self.open_file_action.triggered.connect(self.open_file) # button for save current frame self.saveButton.pressed.connect(self.save_frame) self.setAcceptDrops(True) self.show() def on_videoFrameProbed(self, frame): self.frame = frame def save_frame(self): worker = Worker(self.frame) self.threadpool.start(worker) def dragEnterEvent(self, e): if e.mimeData().hasUrls(): e.acceptProposedAction() def dropEvent(self, e): for url in e.mimeData().urls(): self.playlist.addMedia(QMediaContent(url)) self.model.layoutChanged.emit() # If not playing, seeking to first of newly added + play. if self.player.state() != QMediaPlayer.PlayingState: i = self.playlist.mediaCount() - len(e.mimeData().urls()) self.playlist.setCurrentIndex(i) self.player.play() def open_file(self): path, _ = QFileDialog.getOpenFileName( self, "Open file", "", "mp3 Audio (*.mp3);mp4 Video (*.mp4);Movie files (*.mov);All files (*.*)" ) if path: self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(path))) self.model.layoutChanged.emit() def update_duration(self, duration): print("!", duration) print("?", self.player.duration()) self.timeSlider.setMaximum(duration) if duration >= 0: self.totalTimeLabel.setText(hhmmss(duration)) def update_position(self, position): if position >= 0: self.currentTimeLabel.setText(hhmmss(position)) # Disable the events to prevent updating triggering a setPosition event (can cause stuttering). self.timeSlider.blockSignals(True) self.timeSlider.setValue(position) self.timeSlider.blockSignals(False) def playlist_selection_changed(self, ix): # We receive a QItemSelection from selectionChanged. i = ix.indexes()[0].row() self.playlist.setCurrentIndex(i) def playlist_position_changed(self, i): if i > -1: ix = self.model.index(i) self.playListView.setCurrentIndex(ix) # self.playlistView.setCurrentIndex(ix) def erroralert(self, *args): print(args)
class Player(QWidget): fullScreenChanged = pyqtSignal(bool) def __init__(self, playlist, parent=None): super(Player, self).__init__(parent) self.colorDialog = None self.trackInfo = "" self.statusInfo = "" self.duration = 0 self.player = QMediaPlayer() self.playlist = QMediaPlaylist() self.player.setPlaylist(self.playlist) self.player.durationChanged.connect(self.durationChanged) self.player.positionChanged.connect(self.positionChanged) self.player.metaDataChanged.connect(self.metaDataChanged) self.playlist.currentIndexChanged.connect(self.playlistPositionChanged) self.player.mediaStatusChanged.connect(self.statusChanged) self.player.bufferStatusChanged.connect(self.bufferingProgress) self.player.videoAvailableChanged.connect(self.videoAvailableChanged) self.player.error.connect(self.displayErrorMessage) self.videoWidget = VideoWidget() self.player.setVideoOutput(self.videoWidget) self.playlistModel = PlaylistModel() self.playlistModel.setPlaylist(self.playlist) self.playlistView = QListView() self.playlistView.setModel(self.playlistModel) self.playlistView.setCurrentIndex( self.playlistModel.index(self.playlist.currentIndex(), 0)) self.playlistView.activated.connect(self.jump) self.script_box = QPlainTextEdit() self.segmentList = QTreeWidget() self.segmentList.setSortingEnabled(True) #self.segmentList.setColumnCount(5) self.segmentList.setColumnCount(4) #self.segmentList.setHeaderLabels(['Product','Start','Label','Tool','Behavior']) self.segmentList.setHeaderLabels(['Start segment', 'End segment', 'Label', 'Event']) ''' self.productTextInput = QLineEdit() self.startTextInput = QLineEdit() self.labelTextInput = QLineEdit() self.toolTextInput = QLineEdit() self.behaviorTextInput = QLineEdit() ''' self.startTextInput = QLineEdit() self.endTextInput = QLineEdit() self.labelTextInput = QLineEdit() self.contentTextInput = QLineEdit() self.addBtn = QPushButton("Add") self.addBtn.clicked.connect(self.addSegment) self.saveBtn = QPushButton("Save") self.saveBtn.clicked.connect(self.saveSegments) self.slider = QSlider(Qt.Horizontal) self.slider.setRange(0, self.player.duration() / 1000) self.labelDuration = QLabel() self.slider.sliderMoved.connect(self.seek) self.labelHistogram = QLabel() self.labelHistogram.setText("Histogram:") self.histogram = HistogramWidget() histogramLayout = QHBoxLayout() histogramLayout.addWidget(self.labelHistogram) histogramLayout.addWidget(self.histogram, 1) self.probe = QVideoProbe() self.probe.videoFrameProbed.connect(self.histogram.processFrame) self.probe.setSource(self.player) openButton = QPushButton("Open", clicked=self.open) if os.path.isdir(VIDEO_DIR): self.open_folder(VIDEO_DIR) controls = PlayerControls() controls.setState(self.player.state()) controls.setVolume(self.player.volume()) controls.setMuted(controls.isMuted()) controls.play.connect(self.player.play) controls.pause.connect(self.player.pause) controls.stop.connect(self.player.stop) controls.next.connect(self.playlist.next) controls.previous.connect(self.previousClicked) controls.changeVolume.connect(self.player.setVolume) controls.changeMuting.connect(self.player.setMuted) controls.changeRate.connect(self.player.setPlaybackRate) controls.stop.connect(self.videoWidget.update) self.player.stateChanged.connect(controls.setState) self.player.volumeChanged.connect(controls.setVolume) self.player.mutedChanged.connect(controls.setMuted) #self.segmentButton = QPushButton("Segment") #self.segmentButton.clicked.connect(self.createNewSegment) self.startSegmentButton = QPushButton("Start Segment") self.startSegmentButton.clicked.connect(self.createNewStartSegment) # self.segmentButton.setCheckable(True) self.endSegmentButton = QPushButton("End Segment") self.endSegmentButton.clicked.connect(self.createNewEndSegment) #self.fullScreenButton = QPushButton("FullScreen") #self.fullScreenButton.setCheckable(True) self.colorButton = QPushButton("Color Options...") self.colorButton.setEnabled(False) self.colorButton.clicked.connect(self.showColorDialog) displayLayout = QHBoxLayout() # videoLayout = QVBoxLayout() # videoLayout.addWidget(self.videoWidget) # videoLayout.addWidget(self.script_box) displayLayout.addWidget(self.videoWidget, 3) editLayout = QVBoxLayout() editLayout.addWidget(self.playlistView, 2) #editLayout.addWidget(self.script_box, 4) editLayout.addWidget(self.segmentList, 3) segmentInputLayout = QHBoxLayout() ''' segmentInputLayout.addWidget(self.productTextInput) segmentInputLayout.addWidget(self.startTextInput) segmentInputLayout.addWidget(self.labelTextInput) segmentInputLayout.addWidget(self.toolTextInput) segmentInputLayout.addWidget(self.behaviorTextInput) ''' segmentInputLayout.addWidget(self.startTextInput) segmentInputLayout.addWidget(self.endTextInput) segmentInputLayout.addWidget(self.labelTextInput) segmentInputLayout.addWidget(self.contentTextInput) editLayout.addLayout(segmentInputLayout,1) displayLayout.addLayout(editLayout, 2) controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) controlLayout.addWidget(openButton) controlLayout.addStretch(1) controlLayout.addWidget(controls) controlLayout.addStretch(1) #controlLayout.addWidget(self.segmentButton) controlLayout.addWidget(self.startSegmentButton) controlLayout.addWidget(self.endSegmentButton) controlLayout.addWidget(self.addBtn) controlLayout.addWidget(self.saveBtn) #controlLayout.addWidget(self.fullScreenButton) # controlLayout.addWidget(self.colorButton) layout = QVBoxLayout() layout.addLayout(displayLayout, 2) hLayout = QHBoxLayout() hLayout.addWidget(self.slider) hLayout.addWidget(self.labelDuration) layout.addLayout(hLayout) layout.addLayout(controlLayout) # layout.addLayout(histogramLayout) self.setLayout(layout) if not self.player.isAvailable(): QMessageBox.warning(self, "Service not available", "The QMediaPlayer object does not have a valid service.\n" "Please check the media service plugins are installed.") controls.setEnabled(False) self.playlistView.setEnabled(False) openButton.setEnabled(False) self.colorButton.setEnabled(False) #self.fullScreenButton.setEnabled(False) self.metaDataChanged() self.addToPlaylist(playlist) def open(self): fileNames, _ = QFileDialog.getOpenFileNames(self, "Open Files") self.addToPlaylist(fileNames) def open_folder(self, folder_path): fileNames = [folder_path+x for x in os.listdir(folder_path) if x.endswith('.mp4')] self.addToPlaylist(fileNames) def addToPlaylist(self, fileNames): for name in fileNames: fileInfo = QFileInfo(name) if fileInfo.exists(): url = QUrl.fromLocalFile(fileInfo.absoluteFilePath()) if fileInfo.suffix().lower() == 'm3u': self.playlist.load(url) else: self.playlist.addMedia(QMediaContent(url)) else: url = QUrl(name) if url.isValid(): self.playlist.addMedia(QMediaContent(url)) def addSegment(self): item = TreeWidgetItem(self.segmentList) ''' item.setText(0, self.productTextInput.text()) item.setText(1, self.startTextInput.text()) item.setText(2, self.labelTextInput.text()) item.setText(3, self.toolTextInput.text()) item.setText(4, self.behaviorTextInput.text()) ''' item.setText(0, self.startTextInput.text()) item.setText(1, self.endTextInput.text()) item.setText(2, self.labelTextInput.text()) item.setText(3, self.contentTextInput.text()) item.setFlags(item.flags() | Qt.ItemIsEditable) self.segmentList.addTopLevelItem(item) self.segmentList.sortByColumn(0, Qt.AscendingOrder) self.clear_input_boxes() self.player.play() def saveSegments(self): itemCnt = self.segmentList.topLevelItemCount() colCnt = self.segmentList.columnCount() save_dict = {'segments':[]} for i in range(itemCnt): item = self.segmentList.topLevelItem(i) temp_data = [] for j in range(colCnt): temp_data.append(item.text(j)) #temp_dict = {'product': temp_data[0], 'start': temp_data[1], 'label': temp_data[2], 'tool': temp_data[3], 'behavior': temp_data[4]} if len(temp_data[0]) > 0 and len(temp_data[1]) > 0 and (':' in temp_data[0]) and (':' in temp_data[1]): start_interval_seconds = 0 j = 0 while j < len(temp_data[0].split(':')): start_interval_seconds += (int(temp_data[0].split(':')[- 1 - j]) * (60 ** j)) j += 1 end_interval_seconds = 0 j = 0 while j < len(temp_data[1].split(':')): end_interval_seconds += (int(temp_data[1].split(':')[- 1 - j]) * (60 ** j)) j += 1 else: start_interval_seconds = '' end_interval_seconds = '' temp_dict = {'start_segment': start_interval_seconds, 'end_segment': end_interval_seconds, 'label': temp_data[2], 'event': temp_data[3]} save_dict['segments'].append(temp_dict) import json file_name = self.playlist.currentMedia().canonicalUrl().fileName() with open(SEGMENT_DIR+file_name.replace('.mp4','.json'),'w') as file: json.dump(save_dict, file) def durationChanged(self, duration): duration /= 1000 self.duration = duration self.slider.setMaximum(duration) def positionChanged(self, progress): progress /= 1000 if not self.slider.isSliderDown(): self.slider.setValue(progress) self.updateDurationInfo(progress) def metaDataChanged(self): if self.player.isMetaDataAvailable(): self.setTrackInfo("%s - %s" % ( self.player.metaData(QMediaMetaData.AlbumArtist), self.player.metaData(QMediaMetaData.Title))) def previousClicked(self): # Go to the previous track if we are within the first 5 seconds of # playback. Otherwise, seek to the beginning. if self.player.position() <= 5000: self.playlist.previous() else: self.player.setPosition(0) def clear_input_boxes(self): ''' self.productTextInput.clear() self.startTextInput.clear() self.labelTextInput.clear() self.toolTextInput.clear() self.behaviorTextInput.clear() ''' self.startTextInput.clear() self.endTextInput.clear() self.labelTextInput.clear() self.contentTextInput.clear() def jump(self, index): if index.isValid(): self.playlist.setCurrentIndex(index.row()) self.player.play() file_name = self.playlist.currentMedia().canonicalUrl().fileName() ''' script_file_name = file_name.replace('.mp4','.txt') if os.path.isfile(SCRIPT_DIR+script_file_name): text=open(SCRIPT_DIR+script_file_name).read() self.script_box.setPlainText(text) ''' segment_file_path = SEGMENT_DIR + file_name.replace('.mp4','.json') json_dict = self.open_json(segment_file_path) self.clear_input_boxes() self.segmentList.clear() for segment in json_dict["segments"]: item = TreeWidgetItem(self.segmentList) ''' item.setText(0, segment['product']) item.setText(1, str(segment['start'])) item.setText(2, segment['label']) item.setText(3, segment['tool']) item.setText(4, segment['behavior']) ''' item.setText(0, segment['start_segment']) item.setText(1, segment['end_segment']) item.setText(2, segment['label']) item.setText(3, segment['content']) item.setFlags(item.flags() | Qt.ItemIsEditable) self.segmentList.addTopLevelItem(item) # print([str(x.text()) for x in self.segmentList.currentItem()]) def open_json(self, file_path): import json try: with open(file_path, 'r') as file: json_dict = json.loads(file.read()) except: json_dict = {"segments":[]} # json_dict = {"segments":[{"product":"Sorry","start":"File not found.","label":"","tool":"","behavior":""}]} return json_dict def playlistPositionChanged(self, position): self.playlistView.setCurrentIndex( self.playlistModel.index(position, 0)) def seek(self, seconds): self.player.setPosition(seconds * 1000) def statusChanged(self, status): self.handleCursor(status) if status == QMediaPlayer.LoadingMedia: self.setStatusInfo("Loading...") elif status == QMediaPlayer.StalledMedia: self.setStatusInfo("Media Stalled") elif status == QMediaPlayer.EndOfMedia: QApplication.alert(self) elif status == QMediaPlayer.InvalidMedia: self.displayErrorMessage() else: self.setStatusInfo("") def handleCursor(self, status): if status in (QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia, QMediaPlayer.StalledMedia): self.setCursor(Qt.BusyCursor) else: self.unsetCursor() def bufferingProgress(self, progress): self.setStatusInfo("Buffering %d%" % progress) def videoAvailableChanged(self, available): ''' if available: self.fullScreenButton.clicked.connect( self.videoWidget.setFullScreen) self.videoWidget.fullScreenChanged.connect( self.fullScreenButton.setChecked) if self.fullScreenButton.isChecked(): self.videoWidget.setFullScreen(True) else: self.fullScreenButton.clicked.disconnect( self.videoWidget.setFullScreen) self.videoWidget.fullScreenChanged.disconnect( self.fullScreenButton.setChecked) self.videoWidget.setFullScreen(False) ''' self.colorButton.setEnabled(available) def setTrackInfo(self, info): self.trackInfo = info if self.statusInfo != "": self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo)) else: self.setWindowTitle(self.trackInfo) def setStatusInfo(self, info): self.statusInfo = info if self.statusInfo != "": self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo)) else: self.setWindowTitle(self.trackInfo) def displayErrorMessage(self): self.setStatusInfo(self.player.errorString()) def updateDurationInfo(self, currentInfo): duration = self.duration if currentInfo or duration: currentTime = QTime((currentInfo/3600)%60, (currentInfo/60)%60, currentInfo%60, (currentInfo*1000)%1000) totalTime = QTime((duration/3600)%60, (duration/60)%60, duration%60, (duration*1000)%1000); format = 'hh:mm:ss' if duration > 3600 else 'mm:ss' tStr = currentTime.toString(format) + " / " + totalTime.toString(format) else: tStr = "" self.labelDuration.setText(tStr) ''' def createNewSegment(self): self.startTextInput.setText(str(int(self.player.position()/1000))) ''' def createNewStartSegment(self): seconds = int(self.player.position()/1000) self.startTextInput.setText("{:02d}".format(math.floor(seconds / 3600)) + ':' + "{:02d}".format( math.floor((seconds / 60)) - math.floor(seconds / 3600) * 60) + ':' + "{:02d}".format(seconds % 60)) def createNewEndSegment(self): seconds = int(self.player.position() / 1000) self.endTextInput.setText("{:02d}".format(math.floor(seconds / 3600)) + ':' + "{:02d}".format( math.floor((seconds / 60)) - math.floor(seconds / 3600) * 60) + ':' + "{:02d}".format(seconds % 60)) self.player.pause() def showColorDialog(self): if self.colorDialog is None: brightnessSlider = QSlider(Qt.Horizontal) brightnessSlider.setRange(-100, 100) brightnessSlider.setValue(self.videoWidget.brightness()) brightnessSlider.sliderMoved.connect( self.videoWidget.setBrightness) self.videoWidget.brightnessChanged.connect( brightnessSlider.setValue) contrastSlider = QSlider(Qt.Horizontal) contrastSlider.setRange(-100, 100) contrastSlider.setValue(self.videoWidget.contrast()) contrastSlider.sliderMoved.connect(self.videoWidget.setContrast) self.videoWidget.contrastChanged.connect(contrastSlider.setValue) hueSlider = QSlider(Qt.Horizontal) hueSlider.setRange(-100, 100) hueSlider.setValue(self.videoWidget.hue()) hueSlider.sliderMoved.connect(self.videoWidget.setHue) self.videoWidget.hueChanged.connect(hueSlider.setValue) saturationSlider = QSlider(Qt.Horizontal) saturationSlider.setRange(-100, 100) saturationSlider.setValue(self.videoWidget.saturation()) saturationSlider.sliderMoved.connect( self.videoWidget.setSaturation) self.videoWidget.saturationChanged.connect( saturationSlider.setValue) layout = QFormLayout() layout.addRow("Brightness", brightnessSlider) layout.addRow("Contrast", contrastSlider) layout.addRow("Hue", hueSlider) layout.addRow("Saturation", saturationSlider) button = QPushButton("Close") layout.addRow(button) self.colorDialog = QDialog(self) self.colorDialog.setWindowTitle("Color Options") self.colorDialog.setLayout(layout) button.clicked.connect(self.colorDialog.close) self.colorDialog.show()
class Player(QWidget): fullScreenChanged = pyqtSignal(bool) videoWidget = None colorDialog = None videoWidget = None trackInfo = "" statusInfo = "" duration = 0 def __init__(self, playlist, parent=None): """ :param playlist: :param parent: """ super(Player, self).__init__(parent) self._init_audio_player() self._init_video_player() self._init_addtional_controls() control_layout, controls, open_button = self._init_player_controls_layout( ) self._init_playlist_view() self._init_layout(control_layout=control_layout) self.check_for_player_service(controls=controls, open_button=open_button) self.meta_data_changed() self.add_to_playlist(playlist) def check_for_player_service(self, controls, open_button): """ :param controls: :param open_button: :return: """ if not self.player.isAvailable(): QMessageBox.warning( self, "Service not available", "The QMediaPlayer object does not have a valid service.\n" "Please check the media service plugins are installed.") controls.setEnabled(False) self.playlistView.setEnabled(False) open_button.setEnabled(False) self.colorButton.setEnabled(False) self.fullScreenButton.setEnabled(False) def _init_layout(self, control_layout): """ :param control_layout: :return: """ display_layout = QHBoxLayout() if self.videoWidget: display_layout.addWidget(self.videoWidget, 2) if self.playlistView: display_layout.addWidget(self.playlistView) layout = QVBoxLayout() layout.addLayout(display_layout) if self.slider or self.labelDuration: h_layout = QHBoxLayout() if self.slider: h_layout.addWidget(self.slider) if self.labelDuration: h_layout.addWidget(self.labelDuration) layout.addLayout(h_layout) if control_layout: layout.addLayout(control_layout) layout.addLayout(self._get_histogram_layout()) self.setLayout(layout) def _init_playlist_view(self): """ :return: """ self.playlistView = QListView() self.playlistView.setModel(self.playlistModel) self.playlistView.setCurrentIndex( self.playlistModel.index(self.playlist.currentIndex(), 0)) self.playlistView.activated.connect(self.jump) def _init_addtional_controls(self): """ :return: """ self.slider = QSlider(Qt.Horizontal) self.slider.setRange(0, self.player.duration() / 1000) self.labelDuration = QLabel() self.slider.sliderMoved.connect(self.seek) self.fullScreenButton = QPushButton("FullScreen") self.fullScreenButton.setCheckable(True) self.colorButton = QPushButton("Color Options...") self.colorButton.setEnabled(False) self.colorButton.clicked.connect(self.show_color_dialog) def _init_player_controls_layout(self): """ :return: """ openButton = QPushButton("Open", clicked=self.open) controls = PlayerControls() controls.set_state(self.player.state()) controls.set_volume(self.player.volume()) controls.set_muted(controls.is_muted()) controls.play.connect(self.player.play) controls.pause.connect(self.player.pause) controls.stop.connect(self.player.stop) controls.next.connect(self.playlist.next) controls.previous.connect(self.previous_clicked) controls.changeVolume.connect(self.player.setVolume) controls.changeMuting.connect(self.player.setMuted) controls.changeRate.connect(self.player.setPlaybackRate) if self.videoWidget: controls.stop.connect(self.videoWidget.update) self.player.stateChanged.connect(controls.set_state) self.player.volumeChanged.connect(controls.set_volume) self.player.mutedChanged.connect(controls.set_muted) controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) controlLayout.addWidget(openButton) controlLayout.addStretch(1) controlLayout.addWidget(controls) controlLayout.addStretch(1) if self.fullScreenButton: controlLayout.addWidget(self.fullScreenButton) if self.colorButton: controlLayout.addWidget(self.colorButton) return controlLayout, controls, openButton def _init_audio_player(self): """ :return: """ self.playlist = QMediaPlaylist() self.player = QMediaPlayer() self.player.setPlaylist(self.playlist) self.player.durationChanged.connect(self.duration_changed) self.player.positionChanged.connect(self.position_changed) self.player.metaDataChanged.connect(self.meta_data_changed) self.playlist.currentIndexChanged.connect( self.playlist_position_changed) self.player.mediaStatusChanged.connect(self.status_changed) self.player.bufferStatusChanged.connect(self.buffering_progress) self.player.videoAvailableChanged.connect(self.video_available_changed) self.player.error.connect(self.display_error_message) self.playlistModel = PlaylistModel() self.playlistModel.set_playlist(self.playlist) def _init_video_player(self): """ :return: """ self.histogram = HistogramWidget() self.videoWidget = VideoWidget() self.player.setVideoOutput(self.videoWidget) self.probe = QVideoProbe() self.probe.videoFrameProbed.connect(self.histogram.process_frame) self.probe.setSource(self.player) def _get_histogram_layout(self): """ :return: """ self.labelHistogram = QLabel() self.labelHistogram.setText("Histogram:") histogramLayout = QHBoxLayout() histogramLayout.addWidget(self.labelHistogram) if self.histogram: histogramLayout.addWidget(self.histogram, 1) return histogramLayout def open(self): """ :return: """ file_names, _ = QFileDialog.getOpenFileNames(self, "Open Files") self.add_to_playlist(file_names) def add_to_playlist(self, file_names): """ :param file_names: :return: """ for name in file_names: file_info = QFileInfo(name) if file_info.exists(): url = QUrl.fromLocalFile(file_info.absoluteFilePath()) if file_info.suffix().lower() == 'm3u': self.playlist.load(url) else: self.playlist.addMedia(QMediaContent(url)) else: url = QUrl(name) if url.isValid(): self.playlist.addMedia(QMediaContent(url)) def duration_changed(self, duration): """ :param duration: :return: """ duration /= 1000 self.duration = duration self.slider.setMaximum(duration) def position_changed(self, progress): """ :param progress: :return: """ progress /= 1000 if not self.slider.isSliderDown(): self.slider.setValue(progress) self.update_duration_info(progress) def meta_data_changed(self): """ :return: """ if self.player.isMetaDataAvailable(): self.set_track_info( "%s - %s" % (self.player.metaData(QMediaMetaData.AlbumArtist), self.player.metaData(QMediaMetaData.Title))) def previous_clicked(self): """ :return: """ if self.player.position() <= 5000: self.playlist.previous() else: self.player.setPosition(0) def jump(self, index): """ :param index: :return: """ if index.isValid(): self.playlist.setCurrentIndex(index.row()) self.player.play() def playlist_position_changed(self, position): """ :param position: :return: """ self.playlistView.setCurrentIndex(self.playlistModel.index( position, 0)) def seek(self, seconds): """ :param seconds: :return: """ self.player.setPosition(seconds * 1000) def status_changed(self, status): """ :param status: :return: """ self.handle_cursor(status) if status == QMediaPlayer.LoadingMedia: self.set_status_info("Loading...") elif status == QMediaPlayer.StalledMedia: self.set_status_info("Media Stalled") elif status == QMediaPlayer.EndOfMedia: QApplication.alert(self) elif status == QMediaPlayer.InvalidMedia: self.display_error_message() else: self.set_status_info("") def handle_cursor(self, status): """ :param status: :return: """ if status in (QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia, QMediaPlayer.StalledMedia): self.setCursor(Qt.BusyCursor) else: self.unsetCursor() def buffering_progress(self, progress): """ :param progress: :return: """ self.set_status_info("Buffering %d%" % progress) def video_available_changed(self, available): """ :param available: :return: """ if available: self.fullScreenButton.clicked.connect( self.videoWidget.setFullScreen) self.videoWidget.fullScreenChanged.connect( self.fullScreenButton.setChecked) if self.fullScreenButton.isChecked(): self.videoWidget.setFullScreen(True) else: self.fullScreenButton.clicked.disconnect( self.videoWidget.setFullScreen) self.videoWidget.fullScreenChanged.disconnect( self.fullScreenButton.setChecked) self.videoWidget.setFullScreen(False) self.colorButton.setEnabled(available) def set_track_info(self, info): """ :param info: :return: """ self.trackInfo = info if self.statusInfo != "": self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo)) else: self.setWindowTitle(self.trackInfo) def set_status_info(self, info): """ :param info: :return: """ self.statusInfo = info if self.statusInfo != "": self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo)) else: self.setWindowTitle(self.trackInfo) def display_error_message(self): """ :return: """ self.set_status_info(self.player.errorString()) def update_duration_info(self, current_info): """ :param current_info: :return: """ result = "" duration = self.duration if current_info or duration: current_time = QTime((current_info / 3600) % 60, (current_info / 60) % 60, current_info % 60, (current_info * 1000) % 1000) total_time = QTime((duration / 3600) % 60, (duration / 60) % 60, duration % 60, (duration * 1000) % 1000) if duration > 3600: format = 'hh:mm:ss' else: format = 'mm:ss' result = current_time.toString( format) + " / " + total_time.toString(format) self.labelDuration.setText(result) def show_color_dialog(self): """ :return: """ if self.colorDialog is None: brightness_slider = QSlider(Qt.Horizontal) brightness_slider.setRange(-100, 100) brightness_slider.setValue(self.videoWidget.brightness()) brightness_slider.sliderMoved.connect( self.videoWidget.setBrightness) self.videoWidget.brightnessChanged.connect( brightness_slider.setValue) contrast_slider = QSlider(Qt.Horizontal) contrast_slider.setRange(-100, 100) contrast_slider.setValue(self.videoWidget.contrast()) contrast_slider.sliderMoved.connect(self.videoWidget.setContrast) self.videoWidget.contrastChanged.connect(contrast_slider.setValue) hue_slider = QSlider(Qt.Horizontal) hue_slider.setRange(-100, 100) hue_slider.setValue(self.videoWidget.hue()) hue_slider.sliderMoved.connect(self.videoWidget.setHue) self.videoWidget.hueChanged.connect(hue_slider.setValue) saturation_slider = QSlider(Qt.Horizontal) saturation_slider.setRange(-100, 100) saturation_slider.setValue(self.videoWidget.saturation()) saturation_slider.sliderMoved.connect( self.videoWidget.setSaturation) self.videoWidget.saturationChanged.connect( saturation_slider.setValue) layout = QFormLayout() layout.addRow("Brightness", brightness_slider) layout.addRow("Contrast", contrast_slider) layout.addRow("Hue", hue_slider) layout.addRow("Saturation", saturation_slider) button = QPushButton("Close") layout.addRow(button) self.colorDialog = QDialog(self) self.colorDialog.setWindowTitle("Color Options") self.colorDialog.setLayout(layout) button.clicked.connect(self.colorDialog.close) self.colorDialog.show()
class MediaWindow(QWidget): def __init__(self, stimulusWindow): super(MediaWindow, self).__init__() self.setFocusPolicy(Qt.StrongFocus) self.setStyleSheet(''' QWidget{ border-style: none; } ''') #self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint) self.showFullScreen() self.stimulusWindow = stimulusWindow stimulusWindow.showFullScreen() self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.videoProbe = QVideoProbe() self.videoProbe.videoFrameProbed.connect(self.onVideoFrame) self.videoProbe.setSource(self.mediaPlayer) self.graphicsVideoItem = QGraphicsVideoItem() self.graphicsScene = QGraphicsScene() self.graphicsView = QGraphicsView(self.graphicsScene) geom = stimulusWindow.geometry() self.graphicsView.setFixedSize(geom.width(), geom.height()) self.graphicsScene.addItem(self.graphicsVideoItem) self.graphicsView.setViewport(self.stimulusWindow) self.graphicsView.setViewportUpdateMode( QGraphicsView.FullViewportUpdate) print(self.graphicsView.contentsRect()) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.alignmentRect layout.addWidget(self.graphicsView) self.setLayout(layout) self.graphicsView.setFocusPolicy(Qt.NoFocus) self.graphicsView.viewport().installEventFilter(self) self.hide() #self.showFullScreen() self.ticker = None def eventFilter(self, object, event): if event.type() == QEvent.MouseMove: self.mouseMoveEvent(event) return False def playVideo(self, videoPath, duration): self.showFullScreen() url = QUrl.fromLocalFile(videoPath) self.mediaContent = QMediaContent(url) self.mediaPlayer.setVideoOutput(self.graphicsVideoItem) self.mediaPlayer.setMedia(self.mediaContent) self.stimulusWindow.measuredFrameInterval_s = self.stimulusWindow.expectedFrameInterval_s self.stimulusWindow.gracePeriodForFpsMeasurement = 60 print('mediaplayer: video start') print(self.mediaPlayer.mediaStatus()) self.timer.stop() self.mediaPlayer.play() self.framesToGo = duration print('frames to go: ' + str(self.framesToGo)) def stopVideo(self): #self.stimulusWindow.showFullScreen() print('mediaplayer: video stop') self.mediaPlayer.stop() self.timer.start() def onVideoFrame(self, frame): gears.onDisplayHidden() self.framesToGo = self.framesToGo - 1 if self.framesToGo == 0: self.stopVideo() def start(self, launcherWindow): print("Starting media window.") print(datetime.datetime.now().time()) self.launcherWindow = launcherWindow sequence = gears.getSequence().getPythonObject() self.expectedFrameInterval_s = sequence.getFrameInterval_s() self.measuredFrameInterval_s = self.expectedFrameInterval_s self.gracePeriodForFpsMeasurement = 60 if sequence.getUsesBusyWaitingThreadForSingals(): self.ticker = gears.startTicker() else: self.ticker = None self.timer = QTimer(self) self.timer.setInterval(0) self.timer.timeout.connect(self.onTimer) self.stimulusWindow.mediaWindow = self self.timer.start() self.firstFrame = True self.setFocus() print("Showing media window.") print(datetime.datetime.now().time()) self.showFullScreen() def stop(self): self.timer.stop() sequence = gears.getSequence().getPythonObject() if self.ticker: self.ticker.stop() self.launcherWindow.wake() QApplication.instance().processEvents() gears.reset() self.hide() self.lower() def onBufferSwap(self): if self.ticker: self.ticker.onBufferSwap() def onTimer(self): #print("Media window timer tick.") #print(datetime.datetime.now().time()) self.stimulusWindow.updateNative() def keyReleaseEvent(self, event): stimulus = gears.getCurrentStimulus().getPythonObject() try: for cb in stimulus.onKeyUp: cb(event) except AttributeError: pass def keyPressEvent(self, event): sequence = gears.getSequence().getPythonObject() if event.text() == 'q' or event.key() == Qt.Key_Escape: gears.skip(100000000) elif event.text() == 'f': self.showFps = not self.showFps elif event.key() == Qt.Key_Right or event.text() == 's': gears.skip(1) elif event.key() == Qt.Key_Left or event.text() == 'b': gears.skip(-1) elif event.text() == 'p' or event.text() == 'a': gears.pause() elif event.text() == 'y': gears.instantlyClearSignal(sequence.onKeySpikeChannel) gears.instantlyRaiseSignal(sequence.onKeySpikeChannel) elif event.text() == 'h': gears.instantlyRaiseSignal(sequence.onKeySpikeChannel) gears.instantlyClearSignal(sequence.onKeySpikeChannel) else: if event.text() == ' ': gears.setText("_____toggle info", "Press SPACE to hide this text.") gears.showText() stimulus = gears.getCurrentStimulus().getPythonObject() try: for cb in stimulus.onKey: cb(event) except AttributeError: pass def mouseMoveEvent(self, event): stimulus = gears.getCurrentStimulus().getPythonObject() try: for cb in stimulus.onMouse: cb(event) except AttributeError: pass def mousePressEvent(self, event): stimulus = gears.getCurrentStimulus().getPythonObject() try: for cb in stimulus.onMouseClick: cb(event) except AttributeError: pass def wheelEvent(self, event): stimulus = gears.getCurrentStimulus().getPythonObject() try: for cb in stimulus.onWheel: cb(event) except AttributeError: pass
class Player(QWidget): fullScreenChanged = pyqtSignal(bool) def __init__(self, playlist, parent=None): super(Player, self).__init__(parent) self.colorDialog = None self.trackInfo = "" self.statusInfo = "" self.duration = 0 self.player = QMediaPlayer() self.playlist = QMediaPlaylist() self.player.setPlaylist(self.playlist) self.player.durationChanged.connect(self.durationChanged) self.player.positionChanged.connect(self.positionChanged) self.player.metaDataChanged.connect(self.metaDataChanged) self.playlist.currentIndexChanged.connect(self.playlistPositionChanged) self.player.mediaStatusChanged.connect(self.statusChanged) self.player.bufferStatusChanged.connect(self.bufferingProgress) self.player.videoAvailableChanged.connect(self.videoAvailableChanged) self.player.error.connect(self.displayErrorMessage) self.videoWidget = VideoWidget() self.player.setVideoOutput(self.videoWidget) self.playlistModel = PlaylistModel() self.playlistModel.setPlaylist(self.playlist) self.playlistView = QListView() self.playlistView.setModel(self.playlistModel) self.playlistView.setCurrentIndex( self.playlistModel.index(self.playlist.currentIndex(), 0)) self.playlistView.activated.connect(self.jump) self.slider = QSlider(Qt.Horizontal) self.slider.setRange(0, self.player.duration() / 1000) self.labelDuration = QLabel() self.slider.sliderMoved.connect(self.seek) self.labelHistogram = QLabel() self.labelHistogram.setText("Histogram:") self.histogram = HistogramWidget() histogramLayout = QHBoxLayout() histogramLayout.addWidget(self.labelHistogram) histogramLayout.addWidget(self.histogram, 1) self.probe = QVideoProbe() self.probe.videoFrameProbed.connect(self.histogram.processFrame) self.probe.setSource(self.player) openButton = QPushButton("Open", clicked=self.open) controls = PlayerControls() controls.setState(self.player.state()) controls.setVolume(self.player.volume()) controls.setMuted(controls.isMuted()) controls.play.connect(self.player.play) controls.pause.connect(self.player.pause) controls.stop.connect(self.player.stop) controls.next.connect(self.playlist.next) controls.previous.connect(self.previousClicked) controls.changeVolume.connect(self.player.setVolume) controls.changeMuting.connect(self.player.setMuted) controls.changeRate.connect(self.player.setPlaybackRate) controls.stop.connect(self.videoWidget.update) self.player.stateChanged.connect(controls.setState) self.player.volumeChanged.connect(controls.setVolume) self.player.mutedChanged.connect(controls.setMuted) self.fullScreenButton = QPushButton("FullScreen") self.fullScreenButton.setCheckable(True) self.colorButton = QPushButton("Color Options...") self.colorButton.setEnabled(False) self.colorButton.clicked.connect(self.showColorDialog) displayLayout = QHBoxLayout() displayLayout.addWidget(self.videoWidget, 2) displayLayout.addWidget(self.playlistView) controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) controlLayout.addWidget(openButton) controlLayout.addStretch(1) controlLayout.addWidget(controls) controlLayout.addStretch(1) controlLayout.addWidget(self.fullScreenButton) controlLayout.addWidget(self.colorButton) layout = QVBoxLayout() layout.addLayout(displayLayout) hLayout = QHBoxLayout() hLayout.addWidget(self.slider) hLayout.addWidget(self.labelDuration) layout.addLayout(hLayout) layout.addLayout(controlLayout) layout.addLayout(histogramLayout) self.setLayout(layout) if not self.player.isAvailable(): QMessageBox.warning(self, "Service not available", "The QMediaPlayer object does not have a valid service.\n" "Please check the media service plugins are installed.") controls.setEnabled(False) self.playlistView.setEnabled(False) openButton.setEnabled(False) self.colorButton.setEnabled(False) self.fullScreenButton.setEnabled(False) self.metaDataChanged() self.addToPlaylist(playlist) def open(self): fileNames, _ = QFileDialog.getOpenFileNames(self, "Open Files") self.addToPlaylist(fileNames) def addToPlaylist(self, fileNames): for name in fileNames: fileInfo = QFileInfo(name) if fileInfo.exists(): url = QUrl.fromLocalFile(fileInfo.absoluteFilePath()) if fileInfo.suffix().lower() == 'm3u': self.playlist.load(url) else: self.playlist.addMedia(QMediaContent(url)) else: url = QUrl(name) if url.isValid(): self.playlist.addMedia(QMediaContent(url)) def durationChanged(self, duration): duration /= 1000 self.duration = duration self.slider.setMaximum(duration) def positionChanged(self, progress): progress /= 1000 if not self.slider.isSliderDown(): self.slider.setValue(progress) self.updateDurationInfo(progress) def metaDataChanged(self): if self.player.isMetaDataAvailable(): self.setTrackInfo("%s - %s" % ( self.player.metaData(QMediaMetaData.AlbumArtist), self.player.metaData(QMediaMetaData.Title))) def previousClicked(self): # Go to the previous track if we are within the first 5 seconds of # playback. Otherwise, seek to the beginning. if self.player.position() <= 5000: self.playlist.previous() else: self.player.setPosition(0) def jump(self, index): if index.isValid(): self.playlist.setCurrentIndex(index.row()) self.player.play() def playlistPositionChanged(self, position): self.playlistView.setCurrentIndex( self.playlistModel.index(position, 0)) def seek(self, seconds): self.player.setPosition(seconds * 1000) def statusChanged(self, status): self.handleCursor(status) if status == QMediaPlayer.LoadingMedia: self.setStatusInfo("Loading...") elif status == QMediaPlayer.StalledMedia: self.setStatusInfo("Media Stalled") elif status == QMediaPlayer.EndOfMedia: QApplication.alert(self) elif status == QMediaPlayer.InvalidMedia: self.displayErrorMessage() else: self.setStatusInfo("") def handleCursor(self, status): if status in (QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia, QMediaPlayer.StalledMedia): self.setCursor(Qt.BusyCursor) else: self.unsetCursor() def bufferingProgress(self, progress): self.setStatusInfo("Buffering %d%" % progress) def videoAvailableChanged(self, available): if available: self.fullScreenButton.clicked.connect( self.videoWidget.setFullScreen) self.videoWidget.fullScreenChanged.connect( self.fullScreenButton.setChecked) if self.fullScreenButton.isChecked(): self.videoWidget.setFullScreen(True) else: self.fullScreenButton.clicked.disconnect( self.videoWidget.setFullScreen) self.videoWidget.fullScreenChanged.disconnect( self.fullScreenButton.setChecked) self.videoWidget.setFullScreen(False) self.colorButton.setEnabled(available) def setTrackInfo(self, info): self.trackInfo = info if self.statusInfo != "": self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo)) else: self.setWindowTitle(self.trackInfo) def setStatusInfo(self, info): self.statusInfo = info if self.statusInfo != "": self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo)) else: self.setWindowTitle(self.trackInfo) def displayErrorMessage(self): self.setStatusInfo(self.player.errorString()) def updateDurationInfo(self, currentInfo): duration = self.duration if currentInfo or duration: currentTime = QTime((currentInfo/3600)%60, (currentInfo/60)%60, currentInfo%60, (currentInfo*1000)%1000) totalTime = QTime((duration/3600)%60, (duration/60)%60, duration%60, (duration*1000)%1000); format = 'hh:mm:ss' if duration > 3600 else 'mm:ss' tStr = currentTime.toString(format) + " / " + totalTime.toString(format) else: tStr = "" self.labelDuration.setText(tStr) def showColorDialog(self): if self.colorDialog is None: brightnessSlider = QSlider(Qt.Horizontal) brightnessSlider.setRange(-100, 100) brightnessSlider.setValue(self.videoWidget.brightness()) brightnessSlider.sliderMoved.connect( self.videoWidget.setBrightness) self.videoWidget.brightnessChanged.connect( brightnessSlider.setValue) contrastSlider = QSlider(Qt.Horizontal) contrastSlider.setRange(-100, 100) contrastSlider.setValue(self.videoWidget.contrast()) contrastSlider.sliderMoved.connect(self.videoWidget.setContrast) self.videoWidget.contrastChanged.connect(contrastSlider.setValue) hueSlider = QSlider(Qt.Horizontal) hueSlider.setRange(-100, 100) hueSlider.setValue(self.videoWidget.hue()) hueSlider.sliderMoved.connect(self.videoWidget.setHue) self.videoWidget.hueChanged.connect(hueSlider.setValue) saturationSlider = QSlider(Qt.Horizontal) saturationSlider.setRange(-100, 100) saturationSlider.setValue(self.videoWidget.saturation()) saturationSlider.sliderMoved.connect( self.videoWidget.setSaturation) self.videoWidget.saturationChanged.connect( saturationSlider.setValue) layout = QFormLayout() layout.addRow("Brightness", brightnessSlider) layout.addRow("Contrast", contrastSlider) layout.addRow("Hue", hueSlider) layout.addRow("Saturation", saturationSlider) button = QPushButton("Close") layout.addRow(button) self.colorDialog = QDialog(self) self.colorDialog.setWindowTitle("Color Options") self.colorDialog.setLayout(layout) button.clicked.connect(self.colorDialog.close) self.colorDialog.show()