class VideoPlayerWithControls( QWidget ): def __init__( self ): super().__init__() self.video_w = QVideoWidget() self.v_player = QMediaPlayer( None, QMediaPlayer.VideoSurface ) self.v_player.setVideoOutput( self.video_w ) self.v_player.setNotifyInterval( 50 ) self.v_player.stateChanged.connect( self.video_ended ) self.controls = VideoControls( self.v_player ) self._layout = QVBoxLayout() self._layout.addWidget( self.video_w ) self._layout.addWidget( self.controls ) self._layout.setSpacing( 0 ) self._layout.setContentsMargins( 0, 0, 0, 0 ) self.setLayout( self._layout ) def video_ended( self, state ): if state == QMediaPlayer.StoppedState: self.v_player.setPosition( self.v_player.duration() - 10 ) self.v_player.play() self.v_player.pause()
class QMediaPlayerAdapter(Player): def __init__(self, interval=1): self.__callback = None self.__player = QMediaPlayer() self.setNotifyInterval(interval) def setNotifyInterval(self, interval): self.__player.setNotifyInterval(interval) def setMusicPath(self, filePath): qUrl = QUrl(filePath) self.__player.setMedia(QMediaContent(qUrl)) def getState(self): return self.__player.state() def getStatus(self): return self.__player.mediaStatus() def getPosition(self): return self.__player.position() def getDuration(self): return self.__player.duration() def start(self): if self.__player.state() != QMediaPlayer.NoMedia: self.__player.play() # self.__player.setPosition(self.__player.duration() - 2000) else: raise ValueError( "The media of the player should be set before the player get started." ) def pause(self): self.__player.pause() def stop(self): self.__player.stop() def setCallback(self, callback): '''if not isinstance(callback, PlayerCallback): raise TypeError("The callback should be instance of PlayerCallback.")''' self.__callback = callback self.__player.mediaStatusChanged.connect( self.__callback.onMediaStatusChanged) self.__player.stateChanged.connect(self.__callback.onStateChanged) self.__player.positionChanged.connect( self.__callback.onPlayerPositionChanged)
class VideoWindow(QMainWindow): def __init__(self, parent=None): super(VideoWindow, self).__init__(parent) self.first = True # -추가 : 양팡관련 self.YangPang_play = False self.YangPang_first = 0 global player global channel_ls # 제목 표시줄 self.setWindowTitle( "PyQt Video Player Widget Example - pythonprogramminglanguage.com") # 비디오 파일 재생 위젯 생성 self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) # 비디오 출력 프레임 부분 위젯 생성 self.videoWidget = QVideoWidget() # 플레이버튼 생성 self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) # 플레이용 수평 슬라이드 바 생성 self.positionSlider = QSlider(Qt.Horizontal) # 0부터 0까지 칸 수 만큼 슬라이드 할 수 있는 바 생성 self.positionSlider.setRange(0, 0) self.positionSlider.sliderMoved.connect(self.setPosition) # - 추가 : 사운드 이미지 라벨 생성 self.soundImage = QPushButton() self.soundImage.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume)) self.soundImage.clicked.connect(self.sound) # - 추가 : 사운드용 수평 슬라이드 바 생성 self.soundpositionSlider = QSlider(Qt.Horizontal) self.soundpositionSlider.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) # - 추가 : 0부터 100까지 칸 수 만큼 슬라이드 할 수 있는 바 생성 self.soundpositionSlider.setRange(0, 100) self.soundpositionSlider.setValue(100) self.soundpositionSlider.sliderMoved.connect(self.setsoundPosition) # - 추가 : 링크기능 self.textLink = QLineEdit() self.buttonLink = QPushButton() self.textLink.setObjectName("link") self.buttonLink.setText("연결") self.buttonLink.clicked.connect(self.connect_video) self.buttonLink.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) # 에러 Label 생성 self.errorLabel = QLabel() # sizepolicy 정리 # http://mitk.org/images/5/5e/BugSquashingSeminars%2414-04-30-bugsquashing-Qt-Size-Policy.pdf # https://stackoverflow.com/questions/4553304/understanding-form-layout-mechanisms-in-qt self.errorLabel.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) # 메뉴의 open 생성 openAction = QAction(QIcon('open.png'), '&Open', self) openAction.setShortcut('Ctrl+O') openAction.setStatusTip('Open movie') openAction.triggered.connect(self.openFile) # 메뉴의 exit 생성 exitAction = QAction(QIcon('exit.png'), '&Exit', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Exit application') exitAction.triggered.connect(self.exitCall) # - 추가 : 메뉴의 channel add 생성 channelAction = QAction(QIcon('exit.png'), '&Channel', self) channelAction.setStatusTip('Youtube channel set') channelAction.triggered.connect(opensetwin) # 메뉴바 및 메뉴 생성 menuBar = self.menuBar() fileMenu = menuBar.addMenu('&File') # 메뉴 목록 추가 fileMenu.addAction(openAction) fileMenu.addAction(exitAction) # - 추가 fileMenu.addAction(channelAction) # centralwidget 부분 추가 wid = QWidget(self) self.setCentralWidget(wid) # -추가 : 양팡관련 self.YB = QPushButton() self.YB.setText("양팡 Start") self.YB.clicked.connect(self.YangPang) # -추가 : 채널관련 self.CL = QPushButton() self.CL.setText("채널 Start") self.CL.clicked.connect(self.ChannelVideo) # 레이아웃을 생성하고 위에서 만들었던 Widget 수평으로 순서대로 추가 controlLayout = QHBoxLayout() controlLayout.addWidget(self.playButton) controlLayout.addWidget(self.positionSlider) controlLayout.addWidget(self.soundImage) controlLayout.addWidget(self.soundpositionSlider) # 링크 부분 레이아웃 생성 linkLayout = QHBoxLayout() linkLayout.addWidget(self.textLink) linkLayout.addWidget(self.buttonLink) # controlLayout 바깥으로 여백 추가 (left, right, up, down) controlLayout.setContentsMargins(0, 0, 0, 0) # 레이아웃을 생성하고 이 래이아웃들을 수직 순서대로 추가 layout = QVBoxLayout() layout.addWidget(self.videoWidget) layout.addLayout(controlLayout) layout.addLayout(linkLayout) # -추가 : 양팡관련 layout.addWidget(self.YB) # -추가 : 채널관련 layout.addWidget(self.CL) layout.addWidget(self.errorLabel) # CentralWidget에 layout 넣기 wid.setLayout(layout) # 미디어 위젯에 비디오를 출력 시킴 self.mediaPlayer.setVideoOutput(self.videoWidget) # 미디어 위젯의 플레이 상태가 바뀔 때 self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) # 미디어 위젯의 슬라이드바의 위치가 바뀔 때 self.mediaPlayer.positionChanged.connect(self.positionChanged) # 미디어 위젯의 영상이 바뀌어 슬라이드바의 총 나눔이 달라질 때 self.mediaPlayer.durationChanged.connect(self.durationChanged) # 미디어 위젯에 오류가 났을 때 self.mediaPlayer.error.connect(self.handleError) # - 추가 : 영상 1/3 나누어서 5초 앞 / 시작 or 정지 / 5초 뒤 투명한 버튼 생성 hide_layout = QHBoxLayout() self.before = QPushButton() self.state_change = QPushButton() self.after = QPushButton() self.before.setEnabled(False) self.state_change.setEnabled(False) self.after.setEnabled(False) self.before.clicked.connect(self.before_f) self.state_change.clicked.connect(self.play) self.after.clicked.connect(self.after_f) self.before.setShortcut('left') self.state_change.setShortcut('space') self.after.setShortcut('right') hide_layout.addWidget(self.before) hide_layout.addWidget(self.state_change) hide_layout.addWidget(self.after) self.before.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.state_change.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.after.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.videoWidget.setLayout(hide_layout) # 파일 불러오기 def openFile(self): # QFileDialog.getOpenFileName(self, "제목 표시줄", QDir.homePath()) # 이 함수를 통해 filename엔 파일의 전체 경로와 어떤 종류로 가져 왔는지 변수로 줌(ex. All Files (*)) fileName, _ = QFileDialog.getOpenFileName(self, "Open Movie", QDir.homePath()) # -추가 : 양팡관련 self.YangPang_play = False self.YangPang_first = 0 # 위에서 받아온 경로의 파일을 미디어위젯에 대입 if fileName != '': self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(fileName))) self.playButton.setEnabled(True) self.check_url = False self.best = None # 윈도우 종료 함수 def exitCall(self): sys.exit(app.exec_()) # - 추가 : 링크로 연결 (유튜브 주소만 호환) def connect_video(self): # -추가 : 양팡관련 if not self.YangPang_play: self.textValueB = self.textLink.text() self.YangPang_first = 0 url = self.textValueB if self.textLink.text() != "": self.YangPang_play = False play_link = pafy.new(url) self.best = play_link.getbest() self.mediaPlayer.setMedia(QMediaContent(QUrl(self.best.url))) self.playButton.setEnabled(True) self.check_url = True self.play() # 플레이 버튼 함수 def play(self): # 현재 미디어 위젯의 플레이 상태가 재생중일 때이거나 다른 경우 # PlayingState는 Q미디어플레이어.play() 인듯 = 1 if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() # - 추가 : 사운드 버튼 함수 def sound(self): if self.mediaPlayer.isMuted(): self.mediaPlayer.setMuted(False) self.soundImage.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume)) else: self.mediaPlayer.setMuted(True) self.soundImage.setIcon(self.style().standardIcon( QStyle.SP_MediaVolumeMuted)) # 플레이 버튼 모양 변경 def mediaStateChanged(self, state): # 현재 미디어 위젯의 플레이 상태가 재생중일 때이거나 다른 경우 if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) # 양팡 및 채널 관련 if self.mediaPlayer.state() == QMediaPlayer.StoppedState: if self.YangPang_play: if self.YangPang_first == 1: self.YangPang() if self.YangPang_first == 2: self.ChannelVideo() # 영상의 진행 정도에 따른 슬라이드 바 위치 변경 def positionChanged(self, position): self.positionSlider.setValue(position) self.position = position # 영상의 길이만큼 슬라이드 바의 최대값 설정 def durationChanged(self, duration): self.positionSlider.setRange(0, duration) # - 추가 : 슬라이드 이동 간격 설정 self.mediaPlayer.setNotifyInterval(1) # - 추가 : 자동으로 영상크기만큼 윈도우 크기 조절 if self.mediaPlayer.metaData("Resolution") != None: if not self.check_url: player.resize(self.mediaPlayer.metaData("Resolution")) else: if self.best != None: x, y = parse("{}x{}", self.best.resolution) player.resize(int(x), int(y)) # - 추가 : 영상 추가시 버튼 활성화 self.before.setEnabled(True) self.state_change.setEnabled(True) self.after.setEnabled(True) # - 추가 : 5초 앞 def before_f(self): self.mediaPlayer.setPosition(self.position - 5000) # - 추가 : 5초 뒤 def after_f(self): self.mediaPlayer.setPosition(self.position + 5000) # 영상 슬라이드 바 위치에 따른 화면 변경 def setPosition(self, position): self.mediaPlayer.setPosition(position) # 에러 출력 함수 def handleError(self): self.playButton.setEnabled(False) self.before.setEnabled(False) self.state_change.setEnabled(False) self.after.setEnabled(False) self.errorLabel.setText("Error: " + self.mediaPlayer.errorString()) # - 추가 : 사운드 슬라이드 바 위치에 따른 소리 크기 변경 def setsoundPosition(self, position): self.mediaPlayer.setVolume(position) # - 추가 : 양팡 유튜브 영상 재생 def YangPang(self): # if not self.YangPang_play: if self.YangPang_first == 1: web_url = self.textValueB with urllib.request.urlopen(web_url) as response: html = response.read() soup = BeautifulSoup(html, 'html.parser') yp_find = soup.find_all("a") self.yp_find_list = list() for info in yp_find: if parse("/watch?v={}", info["href"]) != None: if str(info.find("span", {"class": "stat attribution" })).count('양팡 YangPang') > 0: self.yp_find_list.append(info["href"]) break if self.YangPang_first != 1: web_url = "https://www.youtube.com/channel/UCMVC92EOs9yDJG5JS-CMesQ/videos" self.YangPang_first = 1 with urllib.request.urlopen(web_url) as response: html = response.read() soup = BeautifulSoup(html, 'html.parser') yp_find = soup.find_all("a") self.yp_find_list = list() for info in yp_find: if parse("/watch?v={}", info["href"]) != None: self.yp_find_list.append(info["href"]) self.YangPang_play = True cnt = len(self.yp_find_list) - 1 self.textValueB = "https://www.youtube.com/" + str( self.yp_find_list[random.randint(0, cnt)]) self.setWindowTitle("양팡플레이어") self.connect_video() def ChannelVideo(self): if self.YangPang_first == 2: web_url = self.textValueB with urllib.request.urlopen(web_url) as response: html = response.read() soup = BeautifulSoup(html, 'html.parser') yp_find = soup.find_all("a") self.yp_find_list = list() for info in yp_find: if parse("/watch?v={}", info["href"]) != None: if str(info.find("span", {"class": "stat attribution" })).count(self.name) > 0: self.yp_find_list.append(info["href"]) break k = random.randint(0, 1) if k == 0: self.YangPang_first = 0 if self.YangPang_first != 2: web_url = channel_ls[random.randint(0, len(channel_ls) - 1)] self.YangPang_first = 2 with urllib.request.urlopen(web_url) as response: html = response.read() soup = BeautifulSoup(html, 'html.parser') yp_find = soup.find_all("a") self.name_ls = soup.find_all("img") for info in self.name_ls: if info["alt"] != None: self.name = info["alt"] break self.yp_find_list = list() for info in yp_find: if parse("/watch?v={}", info["href"]) != None: self.yp_find_list.append(info["href"]) self.YangPang_play = True cnt = len(self.yp_find_list) - 1 self.textValueB = "https://www.youtube.com/" + str( self.yp_find_list[random.randint(0, cnt)]) self.setWindowTitle("랜덤플레이어") self.connect_video()
class QgsFmvPlayer(QMainWindow, Ui_PlayerWindow): """ Video Player Class """ def __init__(self, iface, path, parent=None, meta_reader=None, pass_time=None, initialPt=None, isStreaming=False): """ Constructor """ super(QgsFmvPlayer, self).__init__(parent) self.setupUi(self) self.parent = parent self.iface = iface self.fileName = path self.initialPt = initialPt self.meta_reader = meta_reader self.isStreaming = isStreaming self.createingMosaic = False self.currentInfo = 0.0 self.data = None # Create Draw Toolbar self.DrawToolBar.addAction(self.actionMagnifying_glass) self.DrawToolBar.addSeparator() # Draw Polygon QToolButton self.toolBtn_DPolygon.setDefaultAction(self.actionDraw_Polygon) self.DrawToolBar.addWidget(self.toolBtn_DPolygon) # Draw Point QToolButton self.toolBtn_DPoint.setDefaultAction(self.actionDraw_Pinpoint) self.DrawToolBar.addWidget(self.toolBtn_DPoint) # Draw Point QToolButton self.toolBtn_DLine.setDefaultAction(self.actionDraw_Line) self.DrawToolBar.addWidget(self.toolBtn_DLine) self.DrawToolBar.addAction(self.actionRuler) self.DrawToolBar.addSeparator() # # Censure QToolButton # self.toolBtn_Cesure.setDefaultAction(self.actionCensure) # self.DrawToolBar.addWidget(self.toolBtn_Cesure) # self.DrawToolBar.addSeparator() # # # Object Tracking # self.DrawToolBar.addAction(self.actionObject_Tracking) self.toolBtn_Cesure.setVisible(False) # Hide Color Button self.btn_Color.hide() self.RecGIF = QMovie(":/imgFMV/images/record.gif") self.videoWidget.customContextMenuRequested[QPoint].connect( self.contextMenuRequested) self.menubarwidget.customContextMenuRequested[QPoint].connect( self.contextMenuBarRequested) self.duration = 0 self.playerMuted = False self.HasFileAudio = False self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.pass_time = pass_time self.player.setNotifyInterval(700) # Metadata Callback Interval self.playlist = QMediaPlaylist() self.player.setVideoOutput( self.videoWidget.videoSurface()) # Abstract Surface self.player.durationChanged.connect(self.durationChanged) self.player.positionChanged.connect(self.positionChanged) self.player.mediaStatusChanged.connect(self.statusChanged) self.player.stateChanged.connect(self.setCurrentState) self.playerState = QMediaPlayer.LoadingMedia self.playFile(path) self.sliderDuration.setRange(0, self.player.duration() / 1000) self.volumeSlider.setValue(self.player.volume()) self.volumeSlider.enterEvent = self.showVolumeTip self.metadataDlg = QgsFmvMetadata(parent=self, player=self) self.addDockWidget(Qt.RightDockWidgetArea, self.metadataDlg) self.metadataDlg.setMinimumWidth(500) self.metadataDlg.hide() self.converter = Converter() self.BitratePlot = CreatePlotsBitrate() def HasAudio(self, videoPath): """ Check if video have Metadata or not """ try: p = _spawn([ '-i', videoPath, '-show_streams', '-select_streams', 'a', '-preset', 'ultrafast', '-loglevel', 'error' ], t="probe") stdout_data, _ = p.communicate() if stdout_data == b'': qgsu.showUserAndLogMessage( QCoreApplication.translate( "QgsFmvPlayer", "This video doesn't have Audio ! ")) self.actionAudio.setEnabled(False) self.actionSave_Audio.setEnabled(False) return False return True except Exception as e: qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Audio check Failed! : "), str(e)) self.actionAudio.setEnabled(False) self.actionSave_Audio.setEnabled(False) def get_metadata_from_buffer(self, currentTime): """ Metadata CallBack """ try: # There is no way to spawn a thread and call after join() without blocking the video UI thread. # callBackMetadata can be as fast as possible, it will always create a small video lag every time meta are read. # To get rid of this, we fill a buffer (BufferedMetaReader) in the QManager with some Metadata in advance, # and hope they'll be ready to read here in a totaly non-blocking # way (increase the buffer size if needed in QManager). stdout_data = self.meta_reader.get(currentTime) # qgsu.showUserAndLogMessage( # "", "stdout_data: " + str(stdout_data) + " currentTime: " + str(currentTime), onlyLog=True) if stdout_data == 'NOT_READY': self.metadataDlg.menuSave.setEnabled(False) qgsu.showUserAndLogMessage( "", "Buffer value read but is not ready, increase buffer size. : ", onlyLog=True) return #Values need to be read, pause the video a short while elif stdout_data == 'BUFFERING': qgsu.showUserAndLogMessage("Buffering metadata...", "", duration=4, level=QGis.Info) self.player.pause() QTimer.singleShot(2500, lambda: self.player.play()) return elif stdout_data == b'' or len(stdout_data) == 0: self.metadataDlg.menuSave.setEnabled(False) qgsu.showUserAndLogMessage( "", "Buffer returned empty metadata, check pass_time. : ", onlyLog=True) return self.packetStreamParser(stdout_data) except Exception as inst: qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Metadata Buffer Failed! : "), str(inst)) def packetStreamParser(self, stdout_data): ''' Common packet process''' for packet in StreamParser(stdout_data): try: if isinstance(packet, UnknownElement): qgsu.showUserAndLogMessage( "Error interpreting klv data, metadata cannot be read.", "the parser did not recognize KLV data", level=QGis.Warning, onlyLog=True) continue data = packet.MetadataList() self.data = data if self.metadataDlg.isVisible( ): # Only add metada to table if this QDockWidget is visible (speed plugin) self.metadataDlg.menuSave.setEnabled(True) self.addMetadata(data) UpdateLayers(packet, parent=self, mosaic=self.createingMosaic) QApplication.processEvents() return except Exception: None # qgsu.showUserAndLogMessage(QCoreApplication.translate( # "QgsFmvPlayer", "Meta update failed! "), " Packet:" + str(packet) + ", error:" + str(inst), level=QGis.Warning) def callBackMetadata(self, currentTime, nextTime): """ Metadata CallBack """ try: port = int(self.fileName.split(':')[2]) t = callBackMetadataThread(cmds=[ '-i', self.fileName.replace(str(port), str( port + 1)), '-ss', currentTime, '-to', nextTime, '-map', 'data-re', '-preset', 'ultrafast', '-f', 'data', '-' ]) t.start() t.join(1) if t.is_alive(): t.p.terminate() t.join() qgsu.showUserAndLogMessage("", "callBackMetadataThread self.stdout: " + str(t.stdout), onlyLog=True) if t.stdout == b'': return self.packetStreamParser(t.stdout) except Exception as e: qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Metadata Callback Failed! : "), str(e)) def GetPacketData(self): ''' Return Current Packet data ''' return self.data def addMetadata(self, packet): ''' Add Metadata to List ''' self.clearMetadata() row = 0 for key in sorted(packet.keys()): self.metadataDlg.VManager.insertRow(row) self.metadataDlg.VManager.setItem(row, 0, QTableWidgetItem(str(key))) self.metadataDlg.VManager.setItem( row, 1, QTableWidgetItem(str(packet[key][0]))) self.metadataDlg.VManager.setItem( row, 2, QTableWidgetItem(str(packet[key][1]))) row += 1 self.metadataDlg.VManager.setVisible(False) self.metadataDlg.VManager.resizeColumnsToContents() self.metadataDlg.VManager.setVisible(True) self.metadataDlg.VManager.verticalScrollBar().setSliderPosition( self.sliderPosition) def clearMetadata(self): ''' Clear Metadata List ''' try: self.sliderPosition = self.metadataDlg.VManager.verticalScrollBar( ).sliderPosition() self.metadataDlg.VManager.setRowCount(0) except Exception: None def saveInfoToJson(self): """ Save video Info to json """ out_json, _ = askForFiles(self, QCoreApplication.translate( "QgsFmvPlayer", "Save Json"), isSave=True, exts="json") if not out_json: return taskSaveInfoToJson = QgsTask.fromFunction( 'Save Video Info to Json Task', self.converter.probeToJson, fname=self.fileName, output=out_json, on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskSaveInfoToJson) return def showVideoInfo(self): ''' Show default probe info ''' taskSaveInfoToJson = QgsTask.fromFunction( 'Show Video Info Task', self.converter.probeShow, fname=self.fileName, on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskSaveInfoToJson) return def state(self): ''' Return Current State ''' return self.playerState def setCurrentState(self, state): ''' Set Current State ''' if state != self.playerState: self.playerState = state if state == QMediaPlayer.StoppedState: self.btn_play.setIcon(QIcon(":/imgFMV/images/play-arrow.png")) return def showColorDialog(self): ''' Show Color dialog ''' self.ColorDialog = ColorDialog(parent=self) self.ColorDialog.setWindowFlags(Qt.Window | Qt.WindowCloseButtonHint) # Fail if not uncheked self.actionMagnifying_glass.setChecked(False) self.ColorDialog.exec_() QApplication.processEvents() self.ColorDialog.contrastSlider.setValue(80) self.ColorDialog.contrastSlider.triggerAction( QAbstractSlider.SliderMove) return def createMosaic(self, value): ''' Function for create Video Mosaic ''' home = os.path.expanduser("~") qgsu.createFolderByName(home, "QGIS_FMV") homefmv = os.path.join(home, "QGIS_FMV") root, _ = os.path.splitext(os.path.basename(self.fileName)) qgsu.createFolderByName(homefmv, root) self.createingMosaic = value # Create Group CreateGroupByName() return def contextMenuBarRequested(self, point): ''' Context Menu Menu Bar ''' menu = QMenu('ToolBars') toolbars = self.findChildren(QToolBar) for toolbar in toolbars: action = menu.addAction(toolbar.windowTitle()) action.setCheckable(True) action.setChecked(toolbar.isVisible()) action.setObjectName(toolbar.windowTitle()) action.triggered.connect(lambda _: self.ToggleQToolBar()) menu.exec_(self.mapToGlobal(point)) return def ToggleQToolBar(self): ''' Toggle ToolBar ''' toolbars = self.findChildren(QToolBar) for toolbar in toolbars: if self.sender().objectName() == toolbar.windowTitle(): toolbar.toggleViewAction().trigger() def contextMenuRequested(self, point): ''' Context Menu Video ''' menu = QMenu('Video') # actionColors = menu.addAction( # QCoreApplication.translate("QgsFmvPlayer", "Color Options")) # actionColors.setShortcut("Ctrl+May+C") # actionColors.triggered.connect(self.showColorDialog) actionMute = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Mute/Unmute")) actionMute.setShortcut("Ctrl+Shift+U") actionMute.triggered.connect(self.setMuted) menu.addSeparator() actionAllFrames = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Extract All Frames")) actionAllFrames.setShortcut("Ctrl+Shift+A") actionAllFrames.triggered.connect(self.ExtractAllFrames) actionCurrentFrames = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Extract Current Frame")) actionCurrentFrames.setShortcut("Ctrl+Shift+Q") actionCurrentFrames.triggered.connect(self.ExtractCurrentFrame) menu.addSeparator() actionShowMetadata = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Show Metadata")) actionShowMetadata.setShortcut("Ctrl+Shift+M") actionShowMetadata.triggered.connect(self.OpenQgsFmvMetadata) menu.exec_(self.mapToGlobal(point)) # Start Snnipet FILTERS def grayFilter(self, value): ''' Gray Video Filter ''' self.UncheckFilters(self.sender(), value) self.videoWidget.SetGray(value) self.videoWidget.UpdateSurface() return def MirrorHorizontalFilter(self, value): ''' Mirror Horizontal Video Filter ''' self.UncheckFilters(self.sender(), value) self.videoWidget.SetMirrorH(value) self.videoWidget.UpdateSurface() return def edgeFilter(self, value): ''' Edge Detection Video Filter ''' self.UncheckFilters(self.sender(), value) self.videoWidget.SetEdgeDetection(value) self.videoWidget.UpdateSurface() return def invertColorFilter(self, value): ''' Invert Color Video Filter ''' self.UncheckFilters(self.sender(), value) self.videoWidget.SetInvertColor(value) self.videoWidget.UpdateSurface() return def autoContrastFilter(self, value): ''' Auto Contrast Video Filter ''' self.UncheckFilters(self.sender(), value) self.videoWidget.SetAutoContrastFilter(value) self.videoWidget.UpdateSurface() return def monoFilter(self, value): ''' Filter Mono Video ''' self.UncheckFilters(self.sender(), value) self.videoWidget.SetMonoFilter(value) self.videoWidget.UpdateSurface() return def magnifier(self, value): ''' Magnifier Glass Utils ''' self.UncheckUtils(self.sender(), value) self.videoWidget.SetMagnifier(value) self.videoWidget.UpdateSurface() return def pointDrawer(self, value): ''' Draw Point ''' self.UncheckUtils(self.sender(), value) self.videoWidget.SetPointDrawer(value) self.videoWidget.UpdateSurface() def lineDrawer(self, value): ''' Draw Line ''' self.UncheckUtils(self.sender(), value) self.videoWidget.SetLineDrawer(value) self.videoWidget.UpdateSurface() def polygonDrawer(self, value): ''' Draw Polygon ''' self.UncheckUtils(self.sender(), value) self.videoWidget.SetPolygonDrawer(value) self.videoWidget.UpdateSurface() def ojectTracking(self, value): ''' Object Tracking ''' self.UncheckUtils(self.sender(), value) self.videoWidget.SetObjectTracking(value) self.videoWidget.UpdateSurface() def VideoRuler(self, value): ''' Video Ruler ''' self.UncheckUtils(self.sender(), value) self.videoWidget.SetRuler(value) if value: self.player.pause() self.btn_play.setIcon(QIcon(":/imgFMV/images/play-arrow.png")) else: self.videoWidget.ResetDrawRuler() self.player.play() self.btn_play.setIcon(QIcon(":/imgFMV/images/pause.png")) self.videoWidget.UpdateSurface() def VideoCensure(self, value): ''' Censure Video Parts''' self.UncheckUtils(self.sender(), value) self.videoWidget.SetCensure(value) self.videoWidget.UpdateSurface() return def UncheckUtils(self, sender, value): ''' Uncheck Utils Video ''' self.actionMagnifying_glass.setChecked(False) self.actionDraw_Pinpoint.setChecked(False) self.actionDraw_Line.setChecked(False) self.actionDraw_Polygon.setChecked(False) self.actionObject_Tracking.setChecked(False) self.actionRuler.setChecked(False) self.actionCensure.setChecked(False) self.videoWidget.RestoreDrawer() sender.setChecked(value) return def UncheckFilters(self, sender, value): ''' Uncheck Filters Video ''' self.actionGray.setChecked(False) self.actionInvert_Color.setChecked(False) self.actionMono_Filter.setChecked(False) self.actionCanny_edge_detection.setChecked(False) self.actionAuto_Contrast_Filter.setChecked(False) self.actionMirroredH.setChecked(False) self.videoWidget.RestoreFilters() sender.setChecked(value) return # End Snnipet FILTERS def isMuted(self): ''' Is muted video property''' return self.playerMuted def setMuted(self): ''' Muted video ''' if self.player.isMuted(): self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_up.png")) self.player.setMuted(False) self.volumeSlider.setEnabled(True) else: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_off.png")) self.player.setMuted(True) self.volumeSlider.setEnabled(False) return def stop(self): ''' Stop video''' # Prevent Error in a Video Utils.Disable Magnifier if self.actionMagnifying_glass.isChecked(): self.actionMagnifying_glass.trigger() # Stop Video self.fakeStop() return def volume(self): ''' Volume Slider ''' return self.volumeSlider.value() def setVolume(self, volume): ''' Tooltip and set Volume value and icon ''' self.player.setVolume(volume) self.showVolumeTip(volume) if 0 < volume <= 30: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_30.png")) elif 30 < volume <= 60: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_60.png")) elif 60 < volume <= 100: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_up.png")) elif volume == 0: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_off.png")) def EndMedia(self): ''' Button end video position ''' if self.player.isVideoAvailable(): self.player.setPosition(self.player.duration()) self.videoWidget.update() return def StartMedia(self): ''' Button start video position ''' if self.player.isVideoAvailable(): self.player.setPosition(0) self.videoWidget.update() return def forwardMedia(self): ''' Button forward Video ''' forwardTime = int(self.player.position()) + 10 * 1000 if forwardTime > int(self.player.duration()): forwardTime = int(self.player.duration()) self.player.setPosition(forwardTime) def rewindMedia(self): ''' Button rewind Video ''' rewindTime = int(self.player.position()) - 10 * 1000 if rewindTime < 0: rewindTime = 0 self.player.setPosition(rewindTime) def AutoRepeat(self, checked): ''' Button AutoRepeat Video ''' if checked: self.playlist.setPlaybackMode(QMediaPlaylist.Loop) else: self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) return def showVolumeTip(self, _): ''' Volume Slider Tooltip Trick ''' self.style = self.volumeSlider.style() self.opt = QStyleOptionSlider() self.volumeSlider.initStyleOption(self.opt) rectHandle = self.style.subControlRect(self.style.CC_Slider, self.opt, self.style.SC_SliderHandle) self.tip_offset = QPoint(5, 15) pos_local = rectHandle.topLeft() + self.tip_offset pos_global = self.volumeSlider.mapToGlobal(pos_local) QToolTip.showText(pos_global, str(self.volumeSlider.value()) + " %", self) def showMoveTip(self, currentInfo): ''' Player Silder Move Tooptip Trick ''' self.style = self.sliderDuration.style() self.opt = QStyleOptionSlider() self.sliderDuration.initStyleOption(self.opt) rectHandle = self.style.subControlRect(self.style.CC_Slider, self.opt, self.style.SC_SliderHandle) self.tip_offset = QPoint(5, 15) pos_local = rectHandle.topLeft() + self.tip_offset pos_global = self.sliderDuration.mapToGlobal(pos_local) tStr = _seconds_to_time(currentInfo) QToolTip.showText(pos_global, tStr, self) def durationChanged(self, duration): ''' Duration video change signal ''' duration /= 1000 self.duration = duration self.sliderDuration.setMaximum(duration) def positionChanged(self, progress): ''' Current Video position change ''' progress /= 1000 if not self.sliderDuration.isSliderDown(): self.sliderDuration.setValue(progress) self.updateDurationInfo(progress) def updateDurationInfo(self, currentInfo): ''' Update labels duration Info and CallBack Metadata ''' duration = self.duration self.currentInfo = currentInfo if currentInfo or duration: totalTime = _seconds_to_time(duration) currentTime = _seconds_to_time(currentInfo) tStr = currentTime + " / " + totalTime currentTimeInfo = _seconds_to_time_frac(currentInfo) # Get Metadata from buffer if not self.isStreaming: self.get_metadata_from_buffer(currentTimeInfo) else: qgsu.showUserAndLogMessage("", "Streaming on ", onlyLog=True) nextTime = currentInfo + self.pass_time / 1000 nextTimeInfo = _seconds_to_time_frac(nextTime) self.callBackMetadata(currentTimeInfo, nextTimeInfo) else: tStr = "" self.labelDuration.setText(tStr) def handleCursor(self, status): ''' Change cursor ''' if status in (QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia, QMediaPlayer.StalledMedia): self.setCursor(Qt.BusyCursor) else: self.unsetCursor() def statusChanged(self, status): ''' Signal Status video change ''' self.handleCursor(status) if status is QMediaPlayer.LoadingMedia or status is QMediaPlayer.StalledMedia or status is QMediaPlayer.InvalidMedia: self.videoAvailableChanged(False) elif status == QMediaPlayer.InvalidMedia: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", self.player.errorString()), level=QGis.Warning) self.videoAvailableChanged(False) else: self.videoAvailableChanged(True) def playFile(self, videoPath): ''' Play file from path ''' try: RemoveVideoLayers() RemoveGroupByName() # if "udp://" in videoPath: # host, port = videoPath.split("://")[1].split(":") # receiver = UDPClient(host, int(port), type="udp") # receiver.show() # self.close() # return # if "tcp://" in videoPath: # host, port = videoPath.split("://")[1].split(":") # receiver = UDPClient(host, port, type="tcp") # receiver.show() # self.close() # return self.fileName = videoPath self.playlist = QMediaPlaylist() if self.isStreaming: url = QUrl(videoPath) else: url = QUrl.fromLocalFile(videoPath) qgsu.showUserAndLogMessage("", "Added: " + str(url), onlyLog=True) self.playlist.addMedia(QMediaContent(url)) self.player.setPlaylist(self.playlist) self.setWindowTitle( QCoreApplication.translate("QgsFmvPlayer", 'Playing : ') + os.path.basename(os.path.normpath(videoPath))) CreateVideoLayers() self.clearMetadata() self.HasFileAudio = True if not self.HasAudio(videoPath): self.actionAudio.setEnabled(False) self.actionSave_Audio.setEnabled(False) self.HasFileAudio = False # Recenter map on video initial point if self.initialPt: rect = QgsRectangle(self.initialPt[1], self.initialPt[0], self.initialPt[1], self.initialPt[0]) self.iface.mapCanvas().setExtent(rect) self.iface.mapCanvas().refresh() self.playClicked(True) except Exception as e: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", 'Open Video File : '), str(e), level=QGis.Warning) def ReciconUpdate(self, _): ''' Record Button Icon Effect ''' self.btn_Rec.setIcon(QIcon(self.RecGIF.currentPixmap())) def StopRecordAnimation(self): '''Stop record gif animation''' self.RecGIF.frameChanged.disconnect(self.ReciconUpdate) self.RecGIF.stop() self.btn_Rec.setIcon(QIcon(":/imgFMV/images/record.png")) # TODO: Make in other thread def RecordVideo(self, value): ''' Cut Video ''' currentTime = _seconds_to_time(self.currentInfo) if value is False: self.endRecord = currentTime _, file_extension = os.path.splitext(self.fileName) out, _ = askForFiles(self, QCoreApplication.translate( "QgsFmvPlayer", "Save video record"), isSave=True, exts=file_extension[1:]) if not out: self.StopRecordAnimation() return p = _spawn([ '-i', self.fileName, '-ss', self.startRecord, '-to', self.endRecord, '-preset', 'ultrafast', '-c', 'copy', out ]) p.communicate() qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Save file succesfully!")) self.StopRecordAnimation() else: self.startRecord = currentTime self.RecGIF.frameChanged.connect(self.ReciconUpdate) self.RecGIF.start() return def videoAvailableChanged(self, available): ''' Buttons for video available ''' # self.btn_Color.setEnabled(available) self.btn_CaptureFrame.setEnabled(available) self.gb_PlayerControls.setEnabled(available) return def toggleGroup(self, state): ''' Toggle GroupBox ''' sender = self.sender() if state: sender.setFixedHeight(sender.sizeHint().height()) else: sender.setFixedHeight(15) def fakeStop(self): '''self.player.stop() make a black screen and not reproduce it again''' self.player.pause() self.StartMedia() self.btn_play.setIcon(QIcon(":/imgFMV/images/play-arrow.png")) def playClicked(self, _): ''' Stop and Play video ''' if self.playerState in (QMediaPlayer.StoppedState, QMediaPlayer.PausedState): self.btn_play.setIcon(QIcon(":/imgFMV/images/pause.png")) # Uncheck Ruler self.videoWidget.ResetDrawRuler() self.actionRuler.setChecked(False) self.videoWidget.SetRuler(False) # Play Video self.player.play() elif self.playerState == QMediaPlayer.PlayingState: self.btn_play.setIcon(QIcon(":/imgFMV/images/play-arrow.png")) self.player.pause() def seek(self, seconds): '''Slider Move''' self.player.setPosition(seconds * 1000) self.showMoveTip(seconds) def convertVideo(self): '''Convert Video To Other Format ''' out, _ = askForFiles(self, QCoreApplication.translate( "QgsFmvPlayer", "Save Video as..."), isSave=True, exts=[ "mp4", "ogg", "avi", "mkv", "webm", "flv", "mov", "mpg", "mp3" ]) if not out: return # TODO : Make Correct format Conversion and embebed metadata info = self.converter.probeInfo(self.fileName) if info is not None: if self.HasFileAudio: audio_codec = info.audio.codec audio_samplerate = info.audio.audio_samplerate audio_channels = info.audio.audio_channels video_codec = info.video.codec video_width = info.video.video_width video_height = info.video.video_height video_fps = info.video.video_fps _, out_ext = os.path.splitext(out) if self.HasFileAudio: options = { 'format': out_ext[1:], 'audio': { 'codec': audio_codec, 'samplerate': audio_samplerate, 'channels': audio_channels }, 'video': { 'codec': video_codec, 'width': video_width, 'height': video_height, 'fps': video_fps } } else: options = { 'format': out_ext[1:], 'video': { 'codec': video_codec, 'width': video_width, 'height': video_height, 'fps': video_fps } } taskConvertVideo = QgsTask.fromFunction('Converting Video Task', self.converter.convert, infile=self.fileName, outfile=out, options=options, twopass=False, on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskConvertVideo) def CreateBitratePlot(self): ''' Create video Plot Bitrate Thread ''' sender = self.sender().objectName() if sender == "actionAudio": taskactionAudio = QgsTask.fromFunction( 'Show Audio Bitrate', self.BitratePlot.CreatePlot, fileName=self.fileName, output=None, t='audio', on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskactionAudio) elif sender == "actionVideo": taskactionVideo = QgsTask.fromFunction( 'Show Video Bitrate', self.BitratePlot.CreatePlot, fileName=self.fileName, output=None, t='video', on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskactionVideo) elif sender == "actionSave_Audio": fileaudio, _ = askForFiles(self, QCoreApplication.translate( "QgsFmvPlayer", "Save Audio Bitrate Plot"), isSave=True, exts=[ "png", "pdf", "pgf", "eps", "ps", "raw", "rgba", "svg", "svgz" ]) if not fileaudio: return taskactionSave_Audio = QgsTask.fromFunction( 'Save Action Audio Bitrate', self.BitratePlot.CreatePlot, fileName=self.fileName, output=fileaudio, t='audio', on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskactionSave_Audio) elif sender == "actionSave_Video": filevideo, _ = askForFiles(self, QCoreApplication.translate( "QgsFmvPlayer", "Save Video Bitrate Plot"), isSave=True, exts=[ "png", "pdf", "pgf", "eps", "ps", "raw", "rgba", "svg", "svgz" ]) if not filevideo: return taskactionSave_Video = QgsTask.fromFunction( 'Save Action Video Bitrate', self.BitratePlot.CreatePlot, fileName=self.fileName, output=filevideo, t='video', on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskactionSave_Video) def finishedTask(self, e, result=None): """ Common finish task function """ if e is None: if result is None: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", 'Completed with no exception and no result '\ '(probably manually canceled by the user)'), level=QGis.Warning) else: if "Georeferencing" in result['task']: return qgsu.showUserAndLogMessage( QCoreApplication.translate( "QgsFmvPlayer", "Succesfully " + result['task'] + "!")) if "Bitrate" in result['task']: self.matplot = ShowPlot(self.BitratePlot.bitrate_data, self.BitratePlot.frame_count, self.fileName, self.BitratePlot.output) if result['task'] == 'Show Video Info Task': self.showVideoInfoDialog(self.converter.bytes_value) else: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", "Failed " + result['task'] + "!"), level=QGis.Warning) raise e def ExtractAllFrames(self): """ Extract All Video Frames Task """ directory = askForFolder( self, QCoreApplication.translate("QgsFmvPlayer", "Save all Frames"), options=QFileDialog.DontResolveSymlinks | QFileDialog.ShowDirsOnly) if directory: taskExtractAllFrames = QgsTask.fromFunction( 'Save All Frames Task', self.SaveAllFrames, fileName=self.fileName, directory=directory, on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskExtractAllFrames) return def SaveAllFrames(self, task, fileName, directory): vidcap = cv2.VideoCapture(fileName) length = int(vidcap.get(cv2.CAP_PROP_FRAME_COUNT)) count = 0 while not task.isCanceled(): _, image = vidcap.read() cv2.imwrite(directory + "\\frame_%d.jpg" % count, image) # save frame as JPEG file task.setProgress(count * 100 / length) count += 1 vidcap.release() cv2.destroyAllWindows() if task.isCanceled(): return None return {'task': task.description()} def ExtractCurrentFrame(self): """ Extract Current Frame Task """ image = self.videoWidget.GetCurrentFrame() output, _ = askForFiles(self, QCoreApplication.translate( "QgsFmvPlayer", "Save Current Frame"), isSave=True, exts=["png", "jpg", "bmp", "tiff"]) if not output: return taskCurrentFrame = QgsTask.fromFunction('Save Current Frame Task', self.SaveCapture, image=image, output=output, on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskCurrentFrame) return def SaveCapture(self, task, image, output): ''' Save Current Frame ''' image.save(output) if task.isCanceled(): return None return {'task': task.description()} def OpenQgsFmvMetadata(self): """ Open Metadata Dock """ if self.metadataDlg is None: self.metadataDlg = QgsFmvMetadata(parent=self, player=self) self.addDockWidget(Qt.RightDockWidgetArea, self.metadataDlg) self.metadataDlg.show() else: self.metadataDlg.show() return def showVideoInfoDialog(self, outjson): """ Show Video Information Dialog """ view = QTreeView() model = QJsonModel() view.setModel(model) model.loadJsonFromConsole(outjson) self.VideoInfoDialog = QDialog(self) self.VideoInfoDialog.setWindowTitle( QCoreApplication.translate("QgsFmvPlayer", "Video Information : ") + self.fileName) self.VideoInfoDialog.setWindowIcon( QIcon(":/imgFMV/images/video-info.png")) self.verticalLayout = QVBoxLayout(self.VideoInfoDialog) self.verticalLayout.addWidget(view) view.expandAll() view.header().setSectionResizeMode(QHeaderView.ResizeToContents) self.VideoInfoDialog.setWindowFlags(Qt.Window | Qt.WindowCloseButtonHint) self.VideoInfoDialog.setObjectName("VideoInfoDialog") self.VideoInfoDialog.resize(500, 400) self.VideoInfoDialog.show() def closeEvent(self, _): """ Close Event """ self.stop() self.parent._PlayerDlg = None self.parent.ToggleActiveFromTitle() RemoveVideoLayers() RemoveGroupByName() ResetData() try: self.metadataDlg.hide() except Exception: None try: self.matplot.close() except Exception: None # Restore Filters State self.videoWidget.RestoreFilters()
class VideoPlayer(QWidget): def __init__(self, parent=None): global gantChart global Topics super(VideoPlayer, self).__init__(parent) self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.mediaPlayer.setVolume(0) #Parse json file videoGlobals.classLabels, videoGlobals.highLabels, videoGlobals.annotationColors, videoGlobals.eventColors = self.parseJson() Topics = None self.time_ = 0 self.time_dif = 0 self.duration = 0 self.message_count = 0 self.videobox = [] self.box_buffer = [] self.metric_buffer = [] #Audio variables self.player = QMediaPlayer() self.playlist = QMediaPlaylist(self) self.playFlag = False self.topic_window = topicBox.TopicBox() # >> DEFINE WIDGETS OCJECTS # >> VIDEO - AUDIO - GANTT CHART #---------------------- self.videoWidget = VideoWidget() self.videoWidget.setFixedSize(640, 480) #Video buttons videoLayout = self.createVideoButtons() #Video Gantt Chart self.gantt = gantChart.gantShow() gantChart = self.gantt gantChart.axes.get_xaxis().set_visible(False) gantChart.setFixedSize(1300, 90) #Create Slider self.createSlider() self.controlEnabled = False #Specify video layout align laserAndVideoLayout = QHBoxLayout() laserAndVideoLayout.addLayout(videoLayout) #Audio Player buttons buttonLayoutAudio = self.createAudioButtons() waveLayout = self.createAudio() self.mainLayout = QVBoxLayout() self.mainLayout.addLayout(laserAndVideoLayout) self.mainLayout.addWidget(self.positionSlider) self.mainLayout.addWidget(self.gantt) self.mainLayout.addLayout(waveLayout) self.mainLayout.addLayout(buttonLayoutAudio) self.setLayout(self.mainLayout) self.mediaPlayer.setVideoOutput(self.videoWidget.videoSurface()) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) def createSlider(self): self.positionSlider = QSlider(Qt.Horizontal) self.positionSlider.setMinimum(0) self.positionSlider.setMaximum(self.duration) self.positionSlider.setTickInterval(1) self.positionSlider.sliderMoved.connect(self.setPosition) def createVideoButtons(self): verticalLine = QFrame() verticalLine.setFrameStyle(QFrame.VLine) verticalLine.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Expanding) self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setShortcut(QKeySequence(Qt.Key_Space)) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.previousButton = QPushButton() self.previousButton.setIcon(self.style().standardIcon(QStyle.SP_MediaSeekBackward)) self.previousButton.setShortcut(QKeySequence(Qt.ALT + Qt.Key_A)) self.previousButton.clicked.connect(self.previousFrame) self.nextButton = QPushButton() self.nextButton.setIcon(self.style().standardIcon(QStyle.SP_MediaSeekForward)) self.nextButton.setShortcut(QKeySequence(Qt.ALT + Qt.Key_D)) self.nextButton.clicked.connect(self.nextFrame) #add label to slider about elapsed time self.label_tmp = '<b><FONT SIZE=3>{}</b>' self.timelabel = QLabel(self.label_tmp.format('Time: ' + str(self.duration))) self.label = QHBoxLayout() self.label.addWidget(self.timelabel) self.label.setAlignment(Qt.AlignRight) self.controlLayout = QHBoxLayout() self.controlLayout.addWidget(self.playButton) self.controlLayout.addWidget(self.previousButton) self.controlLayout.addWidget(self.nextButton) self.controlLayout.setAlignment(Qt.AlignLeft) self.newLayout = QHBoxLayout() self.newLayout.addLayout(self.controlLayout) self.newLayout.addLayout(self.label) videoLayout = QVBoxLayout() videoLayout.addWidget(self.videoWidget) videoLayout.addLayout(self.newLayout) return videoLayout def pauseMedia(self): self.mediaPlayer.pause() self.Pause() def previousFrame(self): global frameCounter if frameCounter > 0: frameCounter -= 2 pos = round(((frameCounter ) * (self.duration * 1000)) / self.message_count) self.mediaPlayer.setPosition(pos) def nextFrame(self): global frameCounter if frameCounter < self.message_count: pos = round(((frameCounter ) * (self.duration * 1000)) / self.message_count) self.mediaPlayer.setPosition(pos) # AUDIO PLAYER BUTTON FUNCTIONS def createAudio(self): #Define Audio annotations and gantt chart self.wave = vA.Waveform() audioGlobals.fig = self.wave self.wave.axes.get_xaxis().set_visible(False) self.wave.draw() self.wave.setFixedSize(1300, 175) self.audioChart = gA.Chart() audioGlobals.chartFig = self.audioChart self.audioChart.setFixedSize(1300, 90) #Audio layouts waveLayout = QVBoxLayout() waveLayout.addWidget(self.wave) waveLayout.addWidget(self.audioChart) return waveLayout def createAudioButtons(self): self.playButtonAudio = QPushButton() self.stopButtonAudio = QPushButton() self.playButtonAudio.clicked.connect(self.audioPlay) self.playButtonAudio.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) buttonLayoutAudio = QHBoxLayout() buttonLayoutAudio.addWidget(self.playButtonAudio) buttonLayoutAudio.setAlignment(Qt.AlignLeft) return buttonLayoutAudio #Play audio (whole signal or segment) def audioPlay(self): #GET CLICKS FROM WAVEFORM #Initialize connection-position ONCE if not audioGlobals.playerStarted: #10ms for changePosition -> Not Delaying self.player.positionChanged.connect(self.checkPositionToStop) self.player.setNotifyInterval(10) audioGlobals.playerStarted = True if audioGlobals.durationFlag in [0, 1]: self.end = audioGlobals.duration*1000 - 10 audioGlobals.endTimeToPlay = self.end else: self.end = audioGlobals.endTimeToPlay self.start = audioGlobals.startTimeToPlay self.player.setPosition(self.start) if self.playFlag: self.playFlag = False audioGlobals.playerStarted = True self.player.setPosition(self.time_) self.player.pause() self.playButtonAudio.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) else: self.playFlag = True self.playButtonAudio.setIcon(self.style().standardIcon(QStyle.SP_MediaPause)) self.player.play() #Stop audio playing def audioStop(self): self.player.stop() #Begin again segment self.start = audioGlobals.startTimeToPlay self.player.setPosition(self.start) #Check ms in audio to stop play def checkPositionToStop(self): self.time_ = self.player.position() if not video_player: audioGlobals.fig.drawNew(float(self.time_)/1000) audioGlobals.fig.draw() if self.time_ >= self.end: self.audioStop() self.player.setPosition(self.start) def videoPosition(self): self.videoTime = self.mediaPlayer.position() def openFile(self): global framerate global bagFile global rgbFileName global Topics global audio_player global video_player framerate = 0 fileName, _ = QFileDialog.getOpenFileName(self, "Open Bag", QDir.currentPath(),"(*.bag *.avi *.mp4 *.mkv *.mp3 *.wav)") # create a messsage box for get or load data info if fileName: name, extension = os.path.splitext(fileName) self.videobox = [] if extension == '.bag': bagFile = fileName try: bag = rosbag.Bag(fileName) Topics, self.duration = get_bag_metadata(bag) #Show window to select topics self.topic_window.show_topics(Topics) except: self.errorMessages(0) #Audio Handling if self.topic_window.temp_topics[0][1] != 'Choose Topic': try: audio_player = True audioGlobals.annotations = [] rosbagAudio.runMain(bag, str(fileName)) except: self.errorMessages(6) #DEFINE PLAYER-PLAYLIST #---------------------- self.source = QUrl.fromLocalFile(os.path.abspath(audioGlobals.wavFileName)) self.content = QMediaContent(self.source) self.playlist.addMedia(self.content) self.player.setPlaylist(self.playlist) self.wave.drawWave() self.wave.drawAnnotations() self.wave.draw() self.audioChart.drawChart() self.audioChart.draw() #RGB Handling if self.topic_window.temp_topics[2][1] != 'Choose Topic': try: video_player = True rgbFileName = fileName.replace(".bag","_RGB.avi") if not os.path.isfile(rgbFileName): self.message_count, compressed, framerate = rosbagVideo.buffer_bag_metadata(bag, self.topic_window.temp_topics[2][1]) #Get bag video metadata print('Getting rgb data from ROS', 'green') image_buffer = rosbagRGB.buffer_rgb_data(bag, self.topic_window.temp_topics[2][1], compressed) if not image_buffer: raise Exception(8) result = rosbagRGB.write_rgb_video(rgbFileName, image_buffer, framerate) if not result: raise Exception(2) self.duration, framerate, self.message_count = rosbagRGB.get_metadata(rgbFileName) # just fill time buffer in case that video exists start_time = None for topic, msg, t in bag.read_messages(topics=[self.topic_window.temp_topics[2][1]]): if not start_time: start_time = t.to_sec() time = t.to_sec() - start_time self.videobox.append(boundBox(time)) self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(os.path.abspath(rgbFileName)))) self.playButton.setEnabled(True) except Exception as e: print(e) self.errorMessages(e[0]) else: if extension in video_extensions: video_player = True self.duration, framerate, self.message_count = rosbagRGB.get_metadata(fileName) self.videobox = [boundBox(count/framerate) for count in xrange(int(self.message_count))] self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(os.path.abspath(fileName)))) self.playButton.setEnabled(True) rgbFileName = fileName try: audioGlobals.annotations = [] rosbagAudio.runMain(None, str(fileName)) #DEFINE PLAYER-PLAYLIST #---------------------- print audioGlobals.wavFileName self.source = QUrl.fromLocalFile(os.path.abspath(audioGlobals.wavFileName)) self.content = QMediaContent(self.source) self.playlist.addMedia(self.content) self.player.setPlaylist(self.playlist) self.wave.drawWave() self.wave.drawAnnotations() self.wave.draw() self.audioChart.drawChart() self.audioChart.draw() audio_player = True except: print "No audio found" mainWindow.repaint(player.videobox, framerate) mainWindow.setWindowTitle(fileName) self.setWindowTitle(fileName + ' -> Annotation') #Open CSV file def openCsv(self): global framerate global rgbFileName global bagFile global videoCSV global headlines self.box_buffer = [] if rgbFileName is not None: # OPEN VIDEO - AUDIO fileName,_ = QFileDialog.getOpenFileName(self, "Open Csv ", os.path.dirname(os.path.abspath(rgbFileName)),"(*.csv)") if fileName: videoCSV = fileName self.videobox = [boundBox(count) for count in xrange(int(self.message_count))] headlines, box_buff, box_action, features = rosbagRGB.buffer_video_csv(fileName) if not (box_buff): self.errorMessages(1) else: self.box_buffer = [list(elem) for elem in box_buff] #Frame counter initialize timestamp = None counter = 0 self.box_actionBuffer = [key for key in box_action] self.features = [key for key in features] for i, key in enumerate(self.box_buffer): if timestamp is not None: if timestamp != key[0]: counter += 1 self.videobox[counter].addBox(key[0], key[1], key[2:], self.box_actionBuffer[i], features[i]) timestamp = key[0] mainWindow.repaint(player.videobox, framerate) else: self.errorMessages(10) #Writes the boxes to csv def writeCSV(self): global headlines global rgbFileName global video_player if video_player: name, extension = os.path.splitext(rgbFileName) csvFileName = rgbFileName.replace(extension,"_video.csv") with open(csvFileName, 'w') as file: csv_writer = csv.writer(file, delimiter='\t') csv_writer.writerow(headlines) for i in xrange(0, len(self.videobox)): box = self.videobox[i] if len(box.box_id) > 0: for j in xrange(0, len(box.box_id)): master = [] append = master.append if box.box_id[j] != -1: append(box.timestamp) append(box.box_id[j]) for param in box.box_Param[j][::]: append(param) for param in box.features[j][::]: append(param) append(box.annotation[j]) csv_writer.writerow(master) else: csv_writer.writerow([box.timestamp]) else: csv_writer.writerow([box.timestamp]) print ("Video csv written at: ", csvFileName) def errorMessages(self, index): msgBox = QMessageBox() msgBox.setIcon(msgBox.Warning) if index == 0: msgBox.setWindowTitle("Open rosbag") msgBox.setText("Could not open rosbag") elif index == 1: msgBox.setWindowTitle("Open CSV") msgBox.setText("Could not process CSV file") elif index == 2: msgBox.setWindowTitle("Open rosbag") msgBox.setIcon(msgBox.Critical) msgBox.setText("Could not write video") elif index == 3: msgBox.setText("Error: Json file path error") elif index == 4: msgBox.setText("Not integer type") elif index == 5: msgBox.setText("Box id already given") elif index == 6: msgBox.setWindowTitle("Open rosbag") msgBox.setText("Incorrect Audio Topic") elif index == 8: msgBox.setWindowTitle("Open rosbag") msgBox.setText("Incorrect RGB Topic") elif index == 10: msgBox.setWindowTitle("Open CSV") msgBox.setText("You must select a rosbag first") msgBox.resize(100,40) msgBox.exec_() def play(self): global frameCounter global audio_player global video_player if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.videoPosition() self.mediaPlayer.pause() if audio_player: self.audioPlay() self.time_ = self.positionSlider else: self.time_ = self.mediaPlayer.position() if audio_player: self.player.setPosition(self.time_) self.end = audioGlobals.duration*1000 - 10 self.audioPlay() if video_player: self.mediaPlayer.play() # >> Get slider position for bound box posSlider = self.positionSlider.value() #self.tickLabel.setAlignment(posSlider) frameCounter = int(round((self.message_count * posSlider)/(self.duration * 1000))) def mediaStateChanged(self, state): if state == QMediaPlayer.PlayingState: self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPause)) else: self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) def positionChanged(self, position): time = "{0:.2f}".format(float(position)/1000) self.positionSlider.setValue(position) self.positionSlider.setToolTip(str(time) + ' sec') self.timelabel.setText(self.label_tmp.format('Time: ' + str(time) + '/ ' + str("{0:.2f}".format(self.duration)) + ' sec')) if audioGlobals.duration > 0 and self.mediaPlayer.state() != 0: audioGlobals.fig.drawNew(time) audioGlobals.fig.draw() def keyPressEvent(self,event): if event.key() == Qt.Key_Control: self.controlEnabled = True def keyReleaseEvent(self,event): if event.key() == Qt.Key_Control: self.controlEnabled = False def durationChanged(self, duration): self.positionSlider.setRange(0, duration) def setPosition(self, position): global frameCounter global audio_player global video_player frameCounter = int(round(self.message_count * position/(self.duration * 1000))) if frameCounter >= self.message_count: frameCounter = self.message_count - 1 if video_player: self.mediaPlayer.setPosition(position) if audio_player: self.player.setPosition(position) def closeEvent(self, event): self.writeCSV() eA.writeCSV() def parseJson(self): json_basicLabel = [] json_highLabel = [] json_annotationColors = [] json_eventColors = [] with open("labels.json") as json_file: json_data = json.load(json_file) for i in json_data['basiclabels'] : json_basicLabel.append(i) for i in json_data['highlevellabels']: json_highLabel.append(i) for i in json_data['annotationColors'] : json_annotationColors.append(i) for i in json_data['eventColors']: json_eventColors.append(i) return json_basicLabel,json_highLabel, json_annotationColors, json_eventColors
class MainWindow(qtw.QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.show() self.samples = None self.sampling_rate = None self.samples_after = None self.first_turn = True # This Prevents the Spectrogram range variables from being overwritten self.PLOT_DIR = 'Plots' self.PDF_DIR = 'PDFs' self.ui.save_session_data.clicked.connect(lambda: self.save_session()) self.ui.actionSave.triggered.connect(lambda: self.save_session()) self.audio_player_before = QMediaPlayer() self.audio_player_after = QMediaPlayer() self.audio_player_before.setNotifyInterval(1) self.audio_player_after.setNotifyInterval(1) self.bands_powers = [0.0, 0.25, 0.50, 0.75, 1.0, 2.0, 3.0, 4.0, 5.0] self.spectrogram_power_range = { 'min': np.array([]), 'max': np.array([]) } self.ui.min_pixel_intensity.sliderReleased.connect( lambda: self.spectrogram_pixels_intensity('min')) self.ui.max_pixel_intensity.sliderReleased.connect( lambda: self.spectrogram_pixels_intensity('max')) self.spectrogram_time_min, self.spectrogram_time_max = 0, 0 # Sync With Play self.band_slider = {} self.band_label = {} for index in range(10): self.band_slider[index] = getattr(self.ui, 'band_{}'.format(index + 1)) self.band_label[index] = getattr(self.ui, 'band_{}_label'.format(index + 1)) for slider in self.band_slider.values(): slider.setDisabled(True) slider.setStyleSheet('selection-background-color: grey') for index, slider in self.band_slider.items(): slider.sliderReleased.connect( lambda index=index: self.slider_gain_updated(index)) self.available_palettes = [ 'twilight', 'Blues', 'Greys', 'ocean', 'nipy_spectral' ] self.current_color_palette = self.available_palettes[0] self.modified_signal = np.array([]) self.current_slider_gain = [1.0] * 10 self.controlers = {'before': [], 'after': []} for button, function in zip( ['zoom_in', 'zoom_out', 'jump_forward', 'jump_back'], [self.zoomin, self.zoomout, self.forward, self.back]): self.controlers['before'].append( (getattr(self.ui, '{}_btn_before'.format(button)), function)) self.controlers['after'].append( (getattr(self.ui, '{}_btn_after'.format(button)), function)) for channel in self.controlers.values(): for signal in channel: signal[0].clicked.connect(signal[1]) self.plot_widget = { 'before': self.ui.graph_before, 'after': self.ui.graph_after } self.spectrogram_widget = { 'before': self.ui.spectrogram_before, 'after': self.ui.spectrogram_after } self.data_line = {'before': None, 'after': None} self.playback_position = {'before': None, 'after': None} self.time_seeker = { 'before': self.ui.time_seeker_before, 'after': self.ui.time_seeker_after } self.total_time = { 'before': self.ui.total_time_before, 'after': self.ui.total_time_after } self.ui.actionExit.triggered.connect(self.close) self.ui.actionNew.triggered.connect(self.new_instance) self.ui.actionOpen.triggered.connect(self.open_audio_file) self.ui.play_btn_before.clicked.connect(self.audio_player_before.play) self.ui.pause_btn_before.clicked.connect( self.audio_player_before.pause) self.ui.stop_btn_before.clicked.connect(self.audio_player_before.stop) self.ui.play_btn_after.clicked.connect(self.audio_player_after.play) self.ui.pause_btn_after.clicked.connect(self.audio_player_after.pause) self.ui.stop_btn_after.clicked.connect(self.audio_player_after.stop) self.ui.palettes_box.currentTextChanged.connect(self.change_palette) self.ui.playback_speed_before.currentIndexChanged.connect( lambda: self.audio_player_before.setPlaybackRate( float(self.ui.playback_speed_before.currentText()[1:]))) self.audio_player_before.durationChanged.connect( lambda duration: self.update_duration(duration, 'before')) self.ui.playback_speed_after.currentIndexChanged.connect( lambda: self.audio_player_after.setPlaybackRate( float(self.ui.playback_speed_after.currentText()[1:]))) self.audio_player_after.durationChanged.connect( lambda duration: self.update_duration(duration, 'after')) def new_instance(self): self.new_instance = MainWindow() self.new_instance.show() def open_audio_file(self): path = qtw.QFileDialog.getOpenFileName(None, 'Load Audio', './', "Audio File(*.wav)")[0] for slider in self.band_slider.values(): slider.setDisabled(False) slider.setStyleSheet('selection-background-color: blue') self.ui.max_pixel_intensity.setDisabled(False) self.ui.max_pixel_intensity.setStyleSheet( 'selection-background-color: blue') self.ui.min_pixel_intensity.setDisabled(False) self.ui.min_pixel_intensity.setStyleSheet( 'selection-background-color: blue') self.audio_player_before.setMedia( QMediaContent(qtc.QUrl.fromLocalFile(path))) self.audio_player_before.positionChanged.connect( lambda position: self.update_timestamp( position, self.ui.current_time_before, self.ui. time_seeker_before, 'before')) self.ui.time_seeker_before.valueChanged.connect( self.audio_player_before.setPosition) self.sampling_rate, self.samples = scipy.io.wavfile.read(path) self.plot_graph(self.samples, self.sampling_rate, 'before') self.plot_spectrogram(self.samples, self.sampling_rate, 'before') self.modify_signal() def plot_graph(self, samples, sampling_rate, widget): peak_value = np.amax(samples) normalized_data = samples / peak_value length = samples.shape[0] / sampling_rate time = list(np.linspace(0, length, samples.shape[0])) drawing_pen = pg.mkPen(color=(255, 0, 0), width=0.5) self.plot_widget[widget].removeItem(self.data_line[widget]) self.data_line[widget] = self.plot_widget[widget].plot(time, normalized_data, pen=drawing_pen) self.plot_widget[widget].plotItem.setLabel(axis='left', text='Normalized Amplitude') self.plot_widget[widget].plotItem.setLabel(axis='bottom', text='time [s]') self.plot_widget[widget].plotItem.getViewBox().setLimits( xMin=0, xMax=np.max(time), yMin=-1.1, yMax=1.1) self.spectrogram_time_min, self.spectrogram_time_max = self.plot_widget[ widget].plotItem.getAxis('bottom').range self.playback_position[widget] = pyqtgraph.LinearRegionItem(values=(0, 0)) self.plot_widget[widget].plotItem.getViewBox().addItem( self.playback_position[widget]) def plot_spectrogram(self, samples, sampling_rate, widget): self.spectrogram_widget[widget].getFigure().clear() spectrogram_axes = self.spectrogram_widget[widget].getFigure( ).add_subplot(111) data = samples.astype('float32') frequency_magnitude = np.abs(librosa.stft(data))**2 mel_spectrogram = librosa.feature.melspectrogram(S=frequency_magnitude, y=data, sr=sampling_rate, n_mels=128) decibel_spectrogram = librosa.power_to_db(mel_spectrogram, ref=np.max) if self.first_turn: min_intensity = np.ceil(np.amin(decibel_spectrogram)) max_intensity = np.ceil(np.amax(decibel_spectrogram)) self.spectrogram_power_range['min'] = np.linspace( min_intensity, min_intensity / 2, 10).astype('int') self.spectrogram_power_range['min'] = np.append( self.spectrogram_power_range['min'], np.array([self.spectrogram_power_range['min'][0]])) self.spectrogram_power_range['max'] = np.linspace( (min_intensity + 1) / 2, max_intensity, 10).astype('int') self.spectrogram_power_range['max'] = np.append( self.spectrogram_power_range['max'], np.array([self.spectrogram_power_range['max'][-1]])) self.ui.min_pixel_intensity_lab.setText( str(self.spectrogram_power_range['min'][-1])) self.ui.max_pixel_intensity_lab.setText( str(self.spectrogram_power_range['max'][-1])) self.first_turn = False spectrogram_image = librosa.display.specshow( decibel_spectrogram, x_axis='time', y_axis='mel', sr=sampling_rate, ax=spectrogram_axes, cmap=self.current_color_palette, vmin=self.spectrogram_power_range['min'][-1], vmax=self.spectrogram_power_range['max'][-1]) self.spectrogram_widget[widget].getFigure().colorbar( spectrogram_image, ax=spectrogram_axes, format='%+2.0f dB') spectrogram_axes.set( xlim=[self.spectrogram_time_min, self.spectrogram_time_max]) self.spectrogram_widget[widget].draw() def modify_signal(self): frequency_content = np.fft.rfftfreq(len(self.samples), d=1 / self.sampling_rate) modified_signal = np.fft.rfft(self.samples) for index, slider_gain in enumerate(self.current_slider_gain): frequency_range_min = (index + 0) * self.sampling_rate / (2 * 10) frequency_range_max = (index + 1) * self.sampling_rate / (2 * 10) range_min_frequency = frequency_content > frequency_range_min range_max_frequency = frequency_content <= frequency_range_max slider_min_max = [] for is_in_min_frequency, is_in_max_frequency in zip( range_min_frequency, range_max_frequency): slider_min_max.append(is_in_min_frequency and is_in_max_frequency) modified_signal[slider_min_max] *= slider_gain self.samples_after = np.fft.irfft(modified_signal) self.save_output_wav() self.plot_graph(self.samples_after, self.sampling_rate, 'after') self.plot_spectrogram(self.samples_after, self.sampling_rate, 'after') def spectrogram_pixels_intensity(self, widget): slider = getattr(self.ui, '{}_pixel_intensity'.format(widget)) self.spectrogram_power_range[widget][ -1] = self.spectrogram_power_range[widget][int(slider.value())] label = getattr(self.ui, '{}_pixel_intensity_lab'.format(widget)) label.setText(str(self.spectrogram_power_range[widget][-1])) self.plot_spectrogram(self.samples, self.sampling_rate, 'before') self.plot_spectrogram(self.samples_after, self.sampling_rate, 'after') def change_palette(self): self.current_color_palette = self.available_palettes[ self.ui.palettes_box.currentIndex()] self.plot_spectrogram(self.samples, self.sampling_rate, 'before') self.plot_spectrogram(self.samples_after, self.sampling_rate, 'after') def slider_gain_updated(self, index): slider_gain = self.bands_powers[self.band_slider[index].value()] self.band_label[index].setText(f'{slider_gain}') self.current_slider_gain[index] = slider_gain self.modify_signal() def update_duration(self, duration, widget): self.time_seeker[widget].setMaximum(duration) if duration >= 0: self.total_time[widget].setText(time_stamp(duration)) def update_timestamp(self, position, currentTimeLabel, timeSlider, widget): if position >= 0: currentTimeLabel.setText(time_stamp(position)) timeSlider.blockSignals(True) timeSlider.setValue(position) timeSlider.blockSignals(False) self.playback_position[widget].setRegion( (position / 1000, position / 1000)) minRange, maxRange = self.plot_widget[widget].plotItem.getAxis( 'bottom').range if (position >= maxRange * 1000): self.plot_widget[widget].plotItem.getViewBox().translateBy( (maxRange - minRange), 0) self.synchronize() if (position <= minRange * 1000): self.plot_widget[widget].plotItem.getViewBox().translateBy( -minRange) self.synchronize() def zoomin(self) -> None: self.ui.graph_before.plotItem.getViewBox().scaleBy((0.75, 1.0)) self.synchronize() def zoomout(self) -> None: self.ui.graph_before.plotItem.getViewBox().scaleBy((1.25, 1.0)) self.synchronize() def back(self): self.ui.graph_before.plotItem.getViewBox().translateBy((-0.5, 0.0)) self.synchronize() def forward(self): self.ui.graph_before.plotItem.getViewBox().translateBy((0.5, 0.0)) self.synchronize() def synchronize(self): self.ui.graph_before.plotItem.getViewBox().setXLink( self.ui.graph_after.plotItem) self.spectrogram_time_min, self.spectrogram_time_max = self.ui.graph_before.plotItem.getAxis( 'bottom').range self.plot_spectrogram(self.samples, self.sampling_rate, 'before') self.plot_spectrogram(self.samples_after, self.sampling_rate, 'after') def save_output_wav(self): try: shutil.rmtree('wav') os.mkdir('wav') except: os.mkdir('wav') self.now = datetime.now() self.now = f'{self.now:%Y-%m-%d %H-%M-%S.%f %p}' scipy.io.wavfile.write(f"wav/SBME{self.now}.wav", self.sampling_rate, self.samples_after.astype(np.int16)) path = os.listdir('wav') self.audio_player_after.setMedia( QMediaContent(qtc.QUrl.fromLocalFile(f'wav/{path[0]}'))) self.audio_player_after.positionChanged.connect( lambda position: self.update_timestamp(position, self.ui. current_time_after, self.ui. time_seeker_after, 'after')) self.ui.time_seeker_after.valueChanged.connect( self.audio_player_after.setPosition) def save_session(self): if not self.sampling_rate: qtw.QMessageBox.information(self, 'failed', 'You have to plot a signal first') return try: shutil.rmtree(self.PLOT_DIR) os.mkdir(self.PLOT_DIR) except FileNotFoundError: os.mkdir(self.PLOT_DIR) for index, channel in enumerate(['before', 'after']): exporter = pg.exporters.ImageExporter( self.plot_widget[channel].scene()) exporter.export(f'{self.PLOT_DIR}/plot-{index}.png') self.spectrogram_widget[channel].fig.savefig( f'{self.PLOT_DIR}/spec-{index}.png') pdf = PDF() plots_per_page = pdf.construct(self.PLOT_DIR) for page_images in plots_per_page: pdf.print_page(page_images, self.PLOT_DIR) outFile = qtw.QFileDialog.getSaveFileName(None, 'Save Session', './', "PDF File(*.pdf)") pdf.output(outFile[0], 'F') try: shutil.rmtree(self.PLOT_DIR) except: pass qtw.QMessageBox.information(self, 'success', 'PDF has been created') sampling_rate, samples = scipy.io.wavfile.read( f"wav/SBME{self.now}.wav") outFile = qtw.QFileDialog.getSaveFileName(None, 'Save Session', './', "Wav File(*.wav)") scipy.io.wavfile.write(outFile[0], sampling_rate, samples.astype(np.int16)) qtw.QMessageBox.information(self, 'success', 'Wav has been saved')
class Visard(QWidget, UI): def __init__(self): super().__init__() self.player_window() self.UI = False self.player = QMediaPlayer() self.player.setNotifyInterval(1) self.player.mediaStatusChanged.connect(self.media_status_changed) self.state = 0 self.player.stateChanged.connect(self.state_changed) self.player.durationChanged.connect(self.duration_changed) self.player.positionChanged.connect(self.position_changed) self.player.metaDataChanged.connect(self.change_metadata) self.open_button.clicked.connect(self.open_dialog) self.volume_slider.valueChanged.connect(self.player.setVolume) self.position_slider.sliderPressed.connect(self.change_position_freeze) self.position_slider.sliderReleased.connect( self.change_position_unfreeze) self.play_pause_button.clicked.connect(self.play_pause) self.stop_button.clicked.connect(self.stop) def media_status_changed(self, media_status): self.media_status = media_status if media_status == 7: self.player.setPosition(0) self.play_pause_button.setText('Play') print(f'MS: {media_status}!') def state_changed(self, state): self.state = state print(f'S: {state}!') def duration_changed(self, duration): self.duration_label.setText(ms_to_time(duration)) self.position_slider.setMaximum(duration) print('DC!') def position_changed(self, position): self.position_label.setText(ms_to_time(position)) self.position_slider.setSliderPosition(position) def change_metadata(self): artist = self.player.metaData(QMediaMetaData.ContributingArtist) title = self.player.metaData(QMediaMetaData.Title) image = self.player.metaData(QMediaMetaData.CoverArtImage) if artist: if type(artist) == list: artist = ', '.join(artist) self.artist_label.setText(artist) else: self.artist_label.setText('None') if title: self.title_label.setText(title) else: self.title_label.setText('None') if image: self.image_label.setPixmap(QPixmap.fromImage(image)) else: self.image_label.setText('None') def open_dialog(self): track_directory = QFileDialog.getOpenFileName(self, 'Choose track', '', 'Music (*.flac *.ogg *.mp3 *.wav *.webm)')[0] if track_directory: if self.state != 0: if self.state == 1: self.play_pause_button.setText('Play') self.stop_button.setEnabled(False) self.player.setMedia( QMediaContent(QUrl.fromLocalFile(track_directory))) if not self.UI: self.artist_label.setEnabled(True) self.title_label.setEnabled(True) self.volume_slider.setEnabled(True) self.position_label.setEnabled(True) self.duration_label.setEnabled(True) self.position_slider.setEnabled(True) self.play_pause_button.setEnabled(True) self.UI = True def change_position_freeze(self): self.player.positionChanged.disconnect(self.position_changed) self.position_slider.sliderMoved.connect(self.change_position_label) def change_position_label(self, position): self.position_label.setText(ms_to_time(position)) def change_position_unfreeze(self): self.player.setPosition(self.position_slider.sliderPosition()) self.position_slider.sliderMoved.disconnect(self.change_position_label) self.player.positionChanged.connect(self.position_changed) def play_pause(self): if self.state == 1: self.player.pause() self.play_pause_button.setText('Play') else: if self.state == 0: self.stop_button.setEnabled(True) self.player.play() self.play_pause_button.setText('Pause') def stop(self): if self.state == 1: self.play_pause_button.setText('Play') self.player.stop() self.stop_button.setEnabled(False)
class PlaybackPanel(SpecialLabel): desktop_lyric_state_changed_signal = pyqtSignal(bool) playmode_changed_signal = pyqtSignal(int, int) media_player_notify_signal = pyqtSignal(int) muted_changed_signal = pyqtSignal(int) mark_favorite_completed_signal = pyqtSignal() current_media_changed_signal = pyqtSignal() music_ended_signal = pyqtSignal() update_window_lyric_signal = pyqtSignal(str, str) show_artist_info_signal = pyqtSignal(str) dont_hide_main_window_signal = pyqtSignal() def __init__(self, parent=None): super(PlaybackPanel, self).__init__(parent) self.initial_mediaplayer() self.create_actions() self.setup_ui() self.create_connections() self.initial_params() def create_connections(self): self.artistHeadLabel.clicked.connect(self.show_artist_info) self.desktopLyric.hide_desktop_lyric_signal.connect(self.desktop_lyric_closed) self.seekSlider.valueChanged.connect(self.slider_value_changed) self.seekSlider.sliderPressed.connect(self.slider_pressed) self.seekSlider.sliderReleased.connect(self.seek) self.mediaPlayer.positionChanged.connect(self.tick) self.mediaPlayer.mutedChanged.connect(self.muted_changed_signal.emit) self.mediaPlayer.stateChanged.connect(self.state_changed) self.mediaPlayer.durationChanged.connect(self.duration_changed) self.mediaPlayer.mediaStatusChanged.connect(self.media_status_changed) self.mediaPlayer.currentMediaChanged.connect(self.current_media_changed) def initial_mediaplayer(self): self.mediaPlayer = QMediaPlayer() self.mediaPlayer.setNotifyInterval(500) self.set_volume(globalSettings.Volume) def initial_params(self): self.playlist = None self.artistName = "Zheng-Yejian" self.clickPlayFlag = False # 用来标志一首歌是否是主动点击选中的 self.timerFlag = False self.timeStart = 0 self.timeSpan = 0 self.sourcePath = "" self.errorType = Configures.NoError self.currentSourceRow = -1 self.nearPlayedSongs = [] self.downloadDir = globalSettings.DownloadfilesPath self.songinfosManager = SonginfosManager() self.totalTime = Configures.ZeroTime self.playmode = Configures.PlaymodeRandom # 播放模式指示器 playlistTemp = Playlist() playlistTemp.fill_list(Configures.PlaylistFavorite) self.lovedSongs = playlistTemp.get_titles() def set_playlist(self, playlist): self.playlist = playlist self.currentSourceRow = self.playlist.get_current_row() def create_actions(self): self.nextAction = QAction(QIcon(IconsHub.ControlNext), "下一首", self, enabled=True, triggered=self.next_song) self.playAction = QAction(QIcon(IconsHub.ControlPlay), "播放/暂停", self, enabled=True, triggered=self.play_music) self.previousAction = QAction( QIcon(IconsHub.ControlPrevious), "上一首", self, enabled=True, triggered=self.previous_song ) self.stopAction = QAction( QIcon(IconsHub.ControlStop), "停止", self, enabled=True, triggered=self.stop_music_but_timing ) def get_play_button_action(self): return self.playAction def get_previous_button_action(self): return self.previousAction def get_next_button_action(self): return self.nextAction def get_stop_button_action(self): return self.stopAction def set_download_dir(self, dir): self.downloadDir = dir def get_loved_songs(self): return self.lovedSongs def get_songinfos_manager(self): return self.songinfosManager def setup_ui(self): self.setFixedHeight(50) # 桌面歌词标签 self.desktopLyric = desktop_lyric.DesktopLyric() self.desktopLyric.set_color(globalSettings.DesktoplyricColors) # 3个标签 self.artistHeadLabel = LabelButton() self.artistHeadLabel.setToolTip(self.tr("查看歌手信息")) self.artistHeadLabel.setFixedSize(QSize(42, 42)) self.artistHeadLabel.setScaledContents(True) self.artistHeadLabel.setPixmap(QPixmap(IconsHub.Anonymous)) self.musicTitleLabel = NewLabel() self.musicTitleLabel.setObjectName("musicTitleLabel") self.musicTitleLabel.setFixedSize(QSize(370, 20)) self.musicTitleLabel.setText("Zheng-Yejian._.XYPLAYER") self.timeLabel = QLabel("00:00/00:00") self.timeLabel.setObjectName("timeLabel") self.timeLabel.setFixedHeight(20) self.timeLabel.setAlignment(Qt.AlignRight and Qt.AlignVCenter) # 五个基本按键 self.playmodeButton = QToolButton(clicked=self.change_playmode) self.playmodeButton.setFocusPolicy(Qt.NoFocus) self.playmodeButton.setIcon(QIcon(IconsHub.PlaymodeRandom)) self.playmodeButton.setIconSize(QSize(25, 25)) self.playmodeButton.setToolTip("随机播放") self.favoriteButton = QToolButton(clicked=self.mark_as_favorite) self.favoriteButton.setFocusPolicy(Qt.NoFocus) self.favoriteButton.setToolTip("收藏") self.favoriteButton.setIcon(QIcon(IconsHub.Favorites)) self.favoriteButton.setIconSize(QSize(20, 20)) self.previousButton = QToolButton() self.previousButton.setFocusPolicy(Qt.NoFocus) self.previousButton.setIconSize(QSize(40, 40)) self.previousButton.setShortcut(QKeySequence("Ctrl + Left")) self.previousButton.setDefaultAction(self.previousAction) self.playButton = QToolButton() self.playButton.setFocusPolicy(Qt.NoFocus) self.playButton.setIconSize(QSize(40, 40)) self.playButton.setShortcut(QKeySequence("Ctrl + Down")) self.playButton.setDefaultAction(self.playAction) self.nextButton = QToolButton() self.nextButton.setFocusPolicy(Qt.NoFocus) self.nextButton.setIconSize(QSize(40, 40)) self.nextButton.setFocusPolicy(Qt.NoFocus) self.nextButton.setShortcut(QKeySequence("Ctrl + Right")) self.nextButton.setDefaultAction(self.nextAction) self.desktopLyricButton = QToolButton(clicked=self.show_desktop_lyric) self.desktopLyricButton.setToolTip(self.tr("桌面歌词")) self.desktopLyricButton.setFocusPolicy(Qt.NoFocus) self.desktopLyricButton.setIcon(QIcon(IconsHub.DesktopLyric)) self.desktopLyricButton.setIconSize(QSize(25, 25)) self.seekSlider = QSlider(Qt.Horizontal) self.seekSlider.setObjectName("seekSlider") self.seekSlider.setFixedHeight(20) self.seekSlider.setFocusPolicy(Qt.NoFocus) self.seekSlider.setRange(0, 0) hbox1 = QHBoxLayout() hbox1.addWidget(self.favoriteButton) hbox1.addWidget(self.musicTitleLabel) hbox1.addStretch() hbox1.addWidget(self.timeLabel) vbox1 = QVBoxLayout() vbox1.addLayout(hbox1) vbox1.setSpacing(5) vbox1.addWidget(self.seekSlider) mainLayout = QHBoxLayout(self) mainLayout.setContentsMargins(2, 0, 0, 0) mainLayout.addWidget(self.artistHeadLabel) mainLayout.addWidget(self.previousButton) mainLayout.addWidget(self.playButton) mainLayout.addWidget(self.nextButton) mainLayout.addLayout(vbox1) mainLayout.addWidget(self.playmodeButton) mainLayout.addWidget(self.desktopLyricButton) def show_desktop_lyric(self): if self.desktopLyric.isHidden(): beToOff = True self.desktopLyric.show() self.desktopLyric.original_place() else: beToOff = False self.desktopLyric.hide() self.desktop_lyric_state_changed_signal.emit(beToOff) def desktop_lyric_closed(self): self.desktop_lyric_state_changed_signal.emit(False) def change_playmode(self): oldPlaymode = self.playmode if self.playmode == Configures.PlaymodeRandom: self.set_new_playmode(Configures.PlaymodeOrder) elif self.playmode == Configures.PlaymodeOrder: self.set_new_playmode(Configures.PlaymodeSingle) elif self.playmode == Configures.PlaymodeSingle: self.set_new_playmode(Configures.PlaymodeRandom) self.playmode_changed_signal.emit(oldPlaymode, self.playmode) def set_new_playmode(self, playmode): self.playmode = playmode if playmode == Configures.PlaymodeRandom: iconPath = IconsHub.PlaymodeRandom toolTip = Configures.PlaymodeRandomText elif playmode == Configures.PlaymodeOrder: iconPath = IconsHub.PlaymodeOrder toolTip = Configures.PlaymodeOrderText else: iconPath = IconsHub.PlaymodeSingle toolTip = Configures.PlaymodeSingleText self.playmodeButton.setIcon(QIcon(iconPath)) self.playmodeButton.setToolTip(toolTip) def ui_initial(self): self.mediaPlayer.stop() self.totalTime = "00:00" self.playAction.setIcon(QIcon(IconsHub.ControlPlay)) self.musicTitleLabel.setText("Zheng-Yejian._.XYPLAYER") self.artistName = "Zheng-Yejian" self.artistHeadLabel.setPixmap(QPixmap(IconsHub.Anonymous)) self.seekSlider.setRange(0, 0) self.favoriteButton.setIcon(QIcon(IconsHub.Favorites)) self.favoriteButton.setToolTip("收藏") self.timeLabel.setText("00:00/00:00") def set_volume(self, volume): self.mediaPlayer.setVolume(volume) def set_muted(self, muted): self.mediaPlayer.setMuted(muted) def tick(self): currentTime = self.mediaPlayer.position() self.seekSlider.setValue(currentTime) cTime = format_position_to_mmss(currentTime // 1000) self.timeLabel.setText(cTime + "/" + self.totalTime) self.media_player_notify_signal.emit(currentTime) def slider_value_changed(self, value): cTime = format_position_to_mmss(value // 1000) self.timeLabel.setText("%s/%s" % (cTime, self.totalTime)) self.media_player_notify_signal.emit(value) def slider_pressed(self): self.mediaPlayer.positionChanged.disconnect(self.tick) def seek(self): if self.mediaPlayer.state() == QMediaPlayer.StoppedState: self.mediaPlayer.play() self.mediaPlayer.setPosition(self.seekSlider.value()) else: self.mediaPlayer.setPosition(self.seekSlider.value()) self.mediaPlayer.play() self.mediaPlayer.positionChanged.connect(self.tick) def duration_changed(self, duration): self.seekSlider.setMaximum(duration) exactTotalTime = format_position_to_mmss(self.mediaPlayer.duration() // 1000) self.timeLabel.setText("%s/%s" % (Configures.ZeroTime, exactTotalTime)) if self.totalTime != exactTotalTime: self.totalTime = exactTotalTime self.playlist.set_music_time_at(self.currentSourceRow, exactTotalTime) def check_favorite(self): if self.currentSourceRow >= 0: if self.playlist.get_music_title_at(self.currentSourceRow) in self.lovedSongs: self.favoriteButton.setIcon(QIcon(IconsHub.Favorites)) self.favoriteButton.setToolTip("取消收藏") else: self.favoriteButton.setIcon(QIcon(IconsHub.FavoritesNo)) self.favoriteButton.setToolTip("收藏") if self.playlist.get_name() == Configures.PlaylistFavorite: self.favoriteButton.setToolTip("收藏") def mark_as_favorite(self): if ( self.playlist.get_name() == Configures.PlaylistFavorite or not self.playlist.length() or self.currentSourceRow < 0 ): return path = self.playlist.get_music_path_at(self.currentSourceRow) title = self.playlist.get_music_title_at(self.currentSourceRow) if self.playlist.get_name() == Configures.PlaylistOnline: musicName = get_full_music_name_from_title(title) musicPath = os.path.join(self.downloadDir, musicName) musicPathO = os.path.join(Configures.MusicsDir, musicName) if not os.path.exists(musicPath) and not os.path.exists(musicPathO): QMessageBox.information(self, "提示", "请先下载该歌曲再添加喜欢!") return if os.path.exists(musicPath): path = musicPath else: path = musicPathO elif not os.path.exists(path): QMessageBox.information(self, "提示", "路径'" + "%s" % path + "'无效,无法标记喜欢!") return playlistTemp = Playlist() playlistTemp.fill_list(Configures.PlaylistFavorite) if title in self.lovedSongs: playlistTemp.remove_item_at(self.lovedSongs.index(title)) playlistTemp.commit_records() self.lovedSongs.remove(title) self.favoriteButton.setIcon(QIcon(IconsHub.FavoritesNo)) self.favoriteButton.setToolTip("收藏") else: playlistTemp.add_item_from_path(path) playlistTemp.commit_records() self.lovedSongs.append(title) self.favoriteButton.setIcon(QIcon(IconsHub.Favorites)) self.favoriteButton.setToolTip("取消收藏") self.mark_favorite_completed_signal.emit() def show_artist_info(self): if self.artistName: self.show_artist_info_signal.emit(self.artistName) def decide_to_play_or_pause(self, row): if row != self.currentSourceRow: self.set_media_source_at_row(row, clickPlayFlag=True) elif self.mediaPlayer.state() in (QMediaPlayer.PausedState, QMediaPlayer.StoppedState): self.mediaPlayer.play() elif self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() def set_media_source_at_row(self, row, clickPlayFlag=False): if not self.playlist.length() or row < 0: return self.stop_music() self.clickPlayFlag = clickPlayFlag self.playlist.set_current_row(row) sourcePath = self.playlist.get_music_path_at(row) self.title = self.playlist.get_music_title_at(row) self.sourceTrace = "local" if self.playlist.get_music_id_at(row) == Configures.LocalMusicId else "online" self.artistName, self.musicName = get_artist_and_musicname_from_title(self.title) self.playlistName = self.playlist.get_name() self.totalTime = self.playlist.get_music_time_at(row) self.album = self.playlist.get_music_album_at(row) self.errorType = Configures.NoError isAnUrl = False if not os.path.exists(sourcePath): if self.playlist.get_name() == Configures.PlaylistOnline: if sourcePath == Configures.NoLink: musicId = self.playlist.get_music_id_at(row) sourcePath = SearchOnline.get_song_link(musicId) if sourcePath: self.playlist.set_music_path_at(row, sourcePath) else: self.errorType = Configures.UrlError isAnUrl = True else: self.errorType = Configures.PathError sourcePath = "/usr/share/sounds/error_happened.ogg" if self.errorType == Configures.NoError: self.sourcePath = sourcePath self.musicFileName = get_base_name_from_path(sourcePath) self.playedDate = get_time_of_now() self.songinfosManager.update_datas_of_item( self.musicFileName, self.playedDate, self.musicName, self.artistName, self.totalTime, self.album, self.playlistName, ) if not self.timerFlag: self.timerFlag = True self.timeSpan = 0 if isAnUrl: url = QUrl(sourcePath) else: url = QUrl.fromLocalFile(sourcePath) self.play_from_url(url) else: self.timerFlag = False self.dont_hide_main_window_signal.emit() if self.errorType == Configures.DisnetError: QMessageBox.critical( self, "错误", "联网出错!\n无法联网播放歌曲'%s'!\n您最好在网络畅通时下载该曲目!" % self.playlist.get_music_title_at(row) ) elif self.errorType == Configures.PathError: QMessageBox.information(self, "提示", "路径'%s'无效,请尝试重新下载并添加对应歌曲!" % self.playlist.get_music_path_at(row)) def play_from_url(self, url): mediaContent = QMediaContent(url) self.mediaPlayer.setMedia(mediaContent) self.mediaPlayer.play() def state_changed(self, newState): if self and newState in [QMediaPlayer.PlayingState, QMediaPlayer.PausedState, QMediaPlayer.StoppedState]: if not self.playlist.length(): return iconPath = IconsHub.ControlPause if newState in [QMediaPlayer.StoppedState, QMediaPlayer.PausedState]: iconPath = IconsHub.ControlPlay icon = QIcon(iconPath) self.playAction.setIcon(icon) if self.timerFlag: if newState == QMediaPlayer.PlayingState: self.timeStart = time.time() else: self.timeSpan += time.time() - self.timeStart def media_status_changed(self, status): if status == QMediaPlayer.EndOfMedia: self.music_finished() def music_finished(self): if self.errorType == Configures.NoError: self.next_song() def play_music(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def stop_music_but_timing(self): self.mediaPlayer.stop() self.seekSlider.setValue(0) self.media_player_notify_signal.emit(-0.5) def stop_music(self): self.stop_music_but_timing() if self.timerFlag: self.timerFlag = False InfosList = [ self.playedDate, self.musicFileName, self.musicName, self.artistName, self.album, "%i" % change_mmss_to_seconds(self.totalTime), "%.1f" % self.timeSpan, self.playlistName, self.sourcePath, "%i" % (self.title in self.lovedSongs), self.sourceTrace, Configures.Playmodes[self.playmode], "%i" % self.clickPlayFlag, ] log_playback_history(organized_list_as_str(InfosList)) self.songinfosManager.update_time_span_relate_of_item(self.musicFileName, self.timeSpan, self.clickPlayFlag) self.clickPlayFlag = False def get_next_random_row(self): listTemp = list(self.playlist.get_ids() - set(self.nearPlayedSongs)) ran = random.randint(0, len(listTemp) - 1) return self.playlist.get_items_queue().index(listTemp[ran]) def get_next_single_row(self): nextRow = self.currentSourceRow if nextRow < 0: nextRow = 0 return nextRow def get_next_order_row(self, reverse=False): if reverse: if self.currentSourceRow < 0: self.currentSourceRow = 0 return (self.currentSourceRow - 1) % self.playlist.length() return (self.currentSourceRow + 1) % self.playlist.length() def previous_song(self): self.play_source_on_next_row(reverse=True) def next_song(self): self.play_source_on_next_row() def play_source_on_next_row(self, reverse=False): if not self.playlist.length(): return if self.mediaPlayer.position() > 20: self.music_ended_signal.emit() nextRow = 0 if self.playmode == Configures.PlaymodeRandom: nextRow = self.get_next_random_row() elif self.playmode == Configures.PlaymodeOrder: nextRow = self.get_next_order_row(reverse) elif self.playmode == Configures.PlaymodeSingle: nextRow = self.get_next_single_row() self.set_media_source_at_row(nextRow) def current_media_changed(self): if not self.playlist.length(): return self.current_media_changed_signal.emit() self.update_parameters() self.update_near_played_queue() self.check_favorite() def update_parameters(self): self.currentSourceRow = self.playlist.get_current_row() self.musicTitleLabel.setText(self.title) self.playAction.setText(self.musicName) imagePath = SearchOnline.get_artist_image_path(self.artistName) if imagePath: pixmap = QPixmap(imagePath) else: pixmap = QPixmap(IconsHub.Anonymous) self.artistHeadLabel.setPixmap(pixmap) musicId = self.playlist.get_music_id_at(self.currentSourceRow) self.update_window_lyric_signal.emit(self.title, musicId) def update_near_played_queue(self): self.currentSourceId = self.playlist.get_music_path_at(self.currentSourceRow) if self.playlist.get_name() == Configures.PlaylistOnline: self.currentSourceId = self.playlist.get_music_id_at(self.currentSourceRow) if self.currentSourceId not in self.nearPlayedSongs: self.nearPlayedSongs.append(self.currentSourceId) while len(self.nearPlayedSongs) >= self.playlist.length() * 4 / 5: del self.nearPlayedSongs[0] def add_title_into_loved_songs(self, title): self.lovedSongs.append(title)
class PlaybackPanel(SpecialLabel): desktop_lyric_state_changed_signal = pyqtSignal(bool) playmode_changed_signal = pyqtSignal(int, int) media_player_notify_signal = pyqtSignal(int) muted_changed_signal = pyqtSignal(int) mark_favorite_completed_signal = pyqtSignal() current_media_changed_signal = pyqtSignal() music_ended_signal = pyqtSignal() update_window_lyric_signal = pyqtSignal(str, str) show_artist_info_signal = pyqtSignal(str) dont_hide_main_window_signal = pyqtSignal() def __init__(self, parent=None): super(PlaybackPanel, self).__init__(parent) self.initial_mediaplayer() self.create_actions() self.setup_ui() self.create_connections() self.initial_params() def create_connections(self): self.artistHeadLabel.clicked.connect(self.show_artist_info) self.desktopLyric.hide_desktop_lyric_signal.connect( self.desktop_lyric_closed) self.seekSlider.valueChanged.connect(self.slider_value_changed) self.seekSlider.sliderPressed.connect(self.slider_pressed) self.seekSlider.sliderReleased.connect(self.seek) self.mediaPlayer.positionChanged.connect(self.tick) self.mediaPlayer.mutedChanged.connect(self.muted_changed_signal.emit) self.mediaPlayer.stateChanged.connect(self.state_changed) self.mediaPlayer.durationChanged.connect(self.duration_changed) self.mediaPlayer.mediaStatusChanged.connect(self.media_status_changed) self.mediaPlayer.currentMediaChanged.connect( self.current_media_changed) def initial_mediaplayer(self): self.mediaPlayer = QMediaPlayer() self.mediaPlayer.setNotifyInterval(500) self.set_volume(globalSettings.Volume) def initial_params(self): self.playlist = None self.artistName = 'Zheng-Yejian' self.clickPlayFlag = False #用来标志一首歌是否是主动点击选中的 self.timerFlag = False self.timeStart = 0 self.timeSpan = 0 self.sourcePath = '' self.errorType = Configures.NoError self.currentSourceRow = -1 self.nearPlayedSongs = [] self.downloadDir = globalSettings.DownloadfilesPath self.songinfosManager = SonginfosManager() self.totalTime = Configures.ZeroTime self.playmode = Configures.PlaymodeRandom #播放模式指示器 playlistTemp = Playlist() playlistTemp.fill_list(Configures.PlaylistFavorite) self.lovedSongs = playlistTemp.get_titles() def set_playlist(self, playlist): self.playlist = playlist self.currentSourceRow = self.playlist.get_current_row() def create_actions(self): self.nextAction = QAction(QIcon(IconsHub.ControlNext), "下一首", self, enabled=True, triggered=self.next_song) self.playAction = QAction(QIcon(IconsHub.ControlPlay), "播放/暂停", self, enabled=True, triggered=self.play_music) self.previousAction = QAction(QIcon(IconsHub.ControlPrevious), "上一首", self, enabled=True, triggered=self.previous_song) self.stopAction = QAction(QIcon(IconsHub.ControlStop), "停止", self, enabled=True, triggered=self.stop_music_but_timing) def get_play_button_action(self): return self.playAction def get_previous_button_action(self): return self.previousAction def get_next_button_action(self): return self.nextAction def get_stop_button_action(self): return self.stopAction def set_download_dir(self, dir): self.downloadDir = dir def get_loved_songs(self): return self.lovedSongs def get_songinfos_manager(self): return self.songinfosManager def setup_ui(self): self.setFixedHeight(50) #桌面歌词标签 self.desktopLyric = desktop_lyric.DesktopLyric() self.desktopLyric.set_color(globalSettings.DesktoplyricColors) #3个标签 self.artistHeadLabel = LabelButton() self.artistHeadLabel.setToolTip(self.tr('查看歌手信息')) self.artistHeadLabel.setFixedSize(QSize(42, 42)) self.artistHeadLabel.setScaledContents(True) self.artistHeadLabel.setPixmap(QPixmap(IconsHub.Anonymous)) self.musicTitleLabel = NewLabel() self.musicTitleLabel.setObjectName('musicTitleLabel') self.musicTitleLabel.setFixedSize(QSize(370, 20)) self.musicTitleLabel.setText("Zheng-Yejian._.XYPLAYER") self.timeLabel = QLabel("00:00/00:00") self.timeLabel.setObjectName('timeLabel') self.timeLabel.setFixedHeight(20) self.timeLabel.setAlignment(Qt.AlignRight and Qt.AlignVCenter) #五个基本按键 self.playmodeButton = QToolButton(clicked=self.change_playmode) self.playmodeButton.setFocusPolicy(Qt.NoFocus) self.playmodeButton.setIcon(QIcon(IconsHub.PlaymodeRandom)) self.playmodeButton.setIconSize(QSize(25, 25)) self.playmodeButton.setToolTip('随机播放') self.favoriteButton = QToolButton(clicked=self.mark_as_favorite) self.favoriteButton.setFocusPolicy(Qt.NoFocus) self.favoriteButton.setToolTip('收藏') self.favoriteButton.setIcon(QIcon(IconsHub.Favorites)) self.favoriteButton.setIconSize(QSize(20, 20)) self.previousButton = QToolButton() self.previousButton.setFocusPolicy(Qt.NoFocus) self.previousButton.setIconSize(QSize(40, 40)) self.previousButton.setShortcut(QKeySequence("Ctrl + Left")) self.previousButton.setDefaultAction(self.previousAction) self.playButton = QToolButton() self.playButton.setFocusPolicy(Qt.NoFocus) self.playButton.setIconSize(QSize(40, 40)) self.playButton.setShortcut(QKeySequence("Ctrl + Down")) self.playButton.setDefaultAction(self.playAction) self.nextButton = QToolButton() self.nextButton.setFocusPolicy(Qt.NoFocus) self.nextButton.setIconSize(QSize(40, 40)) self.nextButton.setFocusPolicy(Qt.NoFocus) self.nextButton.setShortcut(QKeySequence("Ctrl + Right")) self.nextButton.setDefaultAction(self.nextAction) self.desktopLyricButton = QToolButton(clicked=self.show_desktop_lyric) self.desktopLyricButton.setToolTip(self.tr("桌面歌词")) self.desktopLyricButton.setFocusPolicy(Qt.NoFocus) self.desktopLyricButton.setIcon(QIcon(IconsHub.DesktopLyric)) self.desktopLyricButton.setIconSize(QSize(25, 25)) self.seekSlider = QSlider(Qt.Horizontal) self.seekSlider.setObjectName('seekSlider') self.seekSlider.setFixedHeight(20) self.seekSlider.setFocusPolicy(Qt.NoFocus) self.seekSlider.setRange(0, 0) hbox1 = QHBoxLayout() hbox1.addWidget(self.favoriteButton) hbox1.addWidget(self.musicTitleLabel) hbox1.addStretch() hbox1.addWidget(self.timeLabel) vbox1 = QVBoxLayout() vbox1.addLayout(hbox1) vbox1.setSpacing(5) vbox1.addWidget(self.seekSlider) mainLayout = QHBoxLayout(self) mainLayout.setContentsMargins(2, 0, 0, 0) mainLayout.addWidget(self.artistHeadLabel) mainLayout.addWidget(self.previousButton) mainLayout.addWidget(self.playButton) mainLayout.addWidget(self.nextButton) mainLayout.addLayout(vbox1) mainLayout.addWidget(self.playmodeButton) mainLayout.addWidget(self.desktopLyricButton) def show_desktop_lyric(self): if self.desktopLyric.isHidden(): beToOff = True self.desktopLyric.show() self.desktopLyric.original_place() else: beToOff = False self.desktopLyric.hide() self.desktop_lyric_state_changed_signal.emit(beToOff) def desktop_lyric_closed(self): self.desktop_lyric_state_changed_signal.emit(False) def change_playmode(self): oldPlaymode = self.playmode if self.playmode == Configures.PlaymodeRandom: self.set_new_playmode(Configures.PlaymodeOrder) elif self.playmode == Configures.PlaymodeOrder: self.set_new_playmode(Configures.PlaymodeSingle) elif self.playmode == Configures.PlaymodeSingle: self.set_new_playmode(Configures.PlaymodeRandom) self.playmode_changed_signal.emit(oldPlaymode, self.playmode) def set_new_playmode(self, playmode): self.playmode = playmode if playmode == Configures.PlaymodeRandom: iconPath = IconsHub.PlaymodeRandom toolTip = Configures.PlaymodeRandomText elif playmode == Configures.PlaymodeOrder: iconPath = IconsHub.PlaymodeOrder toolTip = Configures.PlaymodeOrderText else: iconPath = IconsHub.PlaymodeSingle toolTip = Configures.PlaymodeSingleText self.playmodeButton.setIcon(QIcon(iconPath)) self.playmodeButton.setToolTip(toolTip) def ui_initial(self): self.mediaPlayer.stop() self.totalTime = '00:00' self.playAction.setIcon(QIcon(IconsHub.ControlPlay)) self.musicTitleLabel.setText("Zheng-Yejian._.XYPLAYER") self.artistName = 'Zheng-Yejian' self.artistHeadLabel.setPixmap(QPixmap(IconsHub.Anonymous)) self.seekSlider.setRange(0, 0) self.favoriteButton.setIcon(QIcon(IconsHub.Favorites)) self.favoriteButton.setToolTip('收藏') self.timeLabel.setText("00:00/00:00") def set_volume(self, volume): self.mediaPlayer.setVolume(volume) def set_muted(self, muted): self.mediaPlayer.setMuted(muted) def tick(self): currentTime = self.mediaPlayer.position() self.seekSlider.setValue(currentTime) cTime = format_position_to_mmss(currentTime // 1000) self.timeLabel.setText(cTime + '/' + self.totalTime) self.media_player_notify_signal.emit(currentTime) def slider_value_changed(self, value): cTime = format_position_to_mmss(value // 1000) self.timeLabel.setText('%s/%s' % (cTime, self.totalTime)) self.media_player_notify_signal.emit(value) def slider_pressed(self): self.mediaPlayer.positionChanged.disconnect(self.tick) def seek(self): if self.mediaPlayer.state() == QMediaPlayer.StoppedState: self.mediaPlayer.play() self.mediaPlayer.setPosition(self.seekSlider.value()) else: self.mediaPlayer.setPosition(self.seekSlider.value()) self.mediaPlayer.play() self.mediaPlayer.positionChanged.connect(self.tick) def duration_changed(self, duration): self.seekSlider.setMaximum(duration) exactTotalTime = format_position_to_mmss(self.mediaPlayer.duration() // 1000) self.timeLabel.setText('%s/%s' % (Configures.ZeroTime, exactTotalTime)) if self.totalTime != exactTotalTime: self.totalTime = exactTotalTime self.playlist.set_music_time_at(self.currentSourceRow, exactTotalTime) def check_favorite(self): if self.currentSourceRow >= 0: if self.playlist.get_music_title_at( self.currentSourceRow) in self.lovedSongs: self.favoriteButton.setIcon(QIcon(IconsHub.Favorites)) self.favoriteButton.setToolTip('取消收藏') else: self.favoriteButton.setIcon(QIcon(IconsHub.FavoritesNo)) self.favoriteButton.setToolTip('收藏') if self.playlist.get_name() == Configures.PlaylistFavorite: self.favoriteButton.setToolTip('收藏') def mark_as_favorite(self): if self.playlist.get_name( ) == Configures.PlaylistFavorite or not self.playlist.length( ) or self.currentSourceRow < 0: return path = self.playlist.get_music_path_at(self.currentSourceRow) title = self.playlist.get_music_title_at(self.currentSourceRow) if self.playlist.get_name() == Configures.PlaylistOnline: musicName = get_full_music_name_from_title(title) musicPath = os.path.join(self.downloadDir, musicName) musicPathO = os.path.join(Configures.MusicsDir, musicName) if not os.path.exists(musicPath) and not os.path.exists( musicPathO): QMessageBox.information(self, '提示', '请先下载该歌曲再添加喜欢!') return if os.path.exists(musicPath): path = musicPath else: path = musicPathO elif not os.path.exists(path): QMessageBox.information(self, "提示", "路径'" + "%s" % path + "'无效,无法标记喜欢!") return playlistTemp = Playlist() playlistTemp.fill_list(Configures.PlaylistFavorite) if title in self.lovedSongs: playlistTemp.remove_item_at(self.lovedSongs.index(title)) playlistTemp.commit_records() self.lovedSongs.remove(title) self.favoriteButton.setIcon(QIcon(IconsHub.FavoritesNo)) self.favoriteButton.setToolTip("收藏") else: playlistTemp.add_item_from_path(path) playlistTemp.commit_records() self.lovedSongs.append(title) self.favoriteButton.setIcon(QIcon(IconsHub.Favorites)) self.favoriteButton.setToolTip("取消收藏") self.mark_favorite_completed_signal.emit() def show_artist_info(self): if self.artistName: self.show_artist_info_signal.emit(self.artistName) def decide_to_play_or_pause(self, row): if row != self.currentSourceRow: self.set_media_source_at_row(row, clickPlayFlag=True) elif self.mediaPlayer.state() in (QMediaPlayer.PausedState, QMediaPlayer.StoppedState): self.mediaPlayer.play() elif self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() def set_media_source_at_row(self, row, clickPlayFlag=False): if not self.playlist.length() or row < 0: return self.stop_music() self.clickPlayFlag = clickPlayFlag self.playlist.set_current_row(row) sourcePath = self.playlist.get_music_path_at(row) self.title = self.playlist.get_music_title_at(row) self.sourceTrace = 'local' if self.playlist.get_music_id_at( row) == Configures.LocalMusicId else 'online' self.artistName, self.musicName = get_artist_and_musicname_from_title( self.title) self.playlistName = self.playlist.get_name() self.totalTime = self.playlist.get_music_time_at(row) self.album = self.playlist.get_music_album_at(row) self.errorType = Configures.NoError isAnUrl = False if not os.path.exists(sourcePath): if self.playlist.get_name() == Configures.PlaylistOnline: if sourcePath == Configures.NoLink: musicId = self.playlist.get_music_id_at(row) sourcePath = SearchOnline.get_song_link(musicId) if sourcePath: self.playlist.set_music_path_at(row, sourcePath) else: self.errorType = Configures.UrlError isAnUrl = True else: self.errorType = Configures.PathError sourcePath = "/usr/share/sounds/error_happened.ogg" if self.errorType == Configures.NoError: self.sourcePath = sourcePath self.musicFileName = get_base_name_from_path(sourcePath) self.playedDate = get_time_of_now() self.songinfosManager.update_datas_of_item( self.musicFileName, self.playedDate, self.musicName, self.artistName, self.totalTime, self.album, self.playlistName) if not self.timerFlag: self.timerFlag = True self.timeSpan = 0 if isAnUrl: url = QUrl(sourcePath) else: url = QUrl.fromLocalFile(sourcePath) self.play_from_url(url) else: self.timerFlag = False self.dont_hide_main_window_signal.emit() if self.errorType == Configures.DisnetError: QMessageBox.critical( self, "错误", "联网出错!\n无法联网播放歌曲'%s'!\n您最好在网络畅通时下载该曲目!" % self.playlist.get_music_title_at(row)) elif self.errorType == Configures.PathError: QMessageBox.information( self, "提示", "路径'%s'无效,请尝试重新下载并添加对应歌曲!" % self.playlist.get_music_path_at(row)) def play_from_url(self, url): mediaContent = QMediaContent(url) self.mediaPlayer.setMedia(mediaContent) self.mediaPlayer.play() def state_changed(self, newState): if self and newState in [ QMediaPlayer.PlayingState, QMediaPlayer.PausedState, QMediaPlayer.StoppedState ]: if not self.playlist.length(): return iconPath = IconsHub.ControlPause if newState in [ QMediaPlayer.StoppedState, QMediaPlayer.PausedState ]: iconPath = IconsHub.ControlPlay icon = QIcon(iconPath) self.playAction.setIcon(icon) if self.timerFlag: if newState == QMediaPlayer.PlayingState: self.timeStart = time.time() else: self.timeSpan += (time.time() - self.timeStart) def media_status_changed(self, status): if status == QMediaPlayer.EndOfMedia: self.music_finished() def music_finished(self): if self.errorType == Configures.NoError: self.next_song() def play_music(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def stop_music_but_timing(self): self.mediaPlayer.stop() self.seekSlider.setValue(0) self.media_player_notify_signal.emit(-0.5) def stop_music(self): self.stop_music_but_timing() if self.timerFlag: self.timerFlag = False InfosList = [ self.playedDate, self.musicFileName, self.musicName, self.artistName, self.album, '%i' % change_mmss_to_seconds(self.totalTime), '%.1f' % self.timeSpan, self.playlistName, self.sourcePath, '%i' % (self.title in self.lovedSongs), self.sourceTrace, Configures.Playmodes[self.playmode], '%i' % self.clickPlayFlag ] log_playback_history(organized_list_as_str(InfosList)) self.songinfosManager.update_time_span_relate_of_item( self.musicFileName, self.timeSpan, self.clickPlayFlag) self.clickPlayFlag = False def get_next_random_row(self): listTemp = list(self.playlist.get_ids() - set(self.nearPlayedSongs)) ran = random.randint(0, len(listTemp) - 1) return self.playlist.get_items_queue().index(listTemp[ran]) def get_next_single_row(self): nextRow = self.currentSourceRow if nextRow < 0: nextRow = 0 return nextRow def get_next_order_row(self, reverse=False): if reverse: if self.currentSourceRow < 0: self.currentSourceRow = 0 return (self.currentSourceRow - 1) % self.playlist.length() return (self.currentSourceRow + 1) % self.playlist.length() def previous_song(self): self.play_source_on_next_row(reverse=True) def next_song(self): self.play_source_on_next_row() def play_source_on_next_row(self, reverse=False): if not self.playlist.length(): return if self.mediaPlayer.position() > 20: self.music_ended_signal.emit() nextRow = 0 if self.playmode == Configures.PlaymodeRandom: nextRow = self.get_next_random_row() elif self.playmode == Configures.PlaymodeOrder: nextRow = self.get_next_order_row(reverse) elif self.playmode == Configures.PlaymodeSingle: nextRow = self.get_next_single_row() self.set_media_source_at_row(nextRow) def current_media_changed(self): if not self.playlist.length(): return self.current_media_changed_signal.emit() self.update_parameters() self.update_near_played_queue() self.check_favorite() def update_parameters(self): self.currentSourceRow = self.playlist.get_current_row() self.musicTitleLabel.setText(self.title) self.playAction.setText(self.musicName) imagePath = SearchOnline.get_artist_image_path(self.artistName) if imagePath: pixmap = QPixmap(imagePath) else: pixmap = QPixmap(IconsHub.Anonymous) self.artistHeadLabel.setPixmap(pixmap) musicId = self.playlist.get_music_id_at(self.currentSourceRow) self.update_window_lyric_signal.emit(self.title, musicId) def update_near_played_queue(self): self.currentSourceId = self.playlist.get_music_path_at( self.currentSourceRow) if self.playlist.get_name() == Configures.PlaylistOnline: self.currentSourceId = self.playlist.get_music_id_at( self.currentSourceRow) if self.currentSourceId not in self.nearPlayedSongs: self.nearPlayedSongs.append(self.currentSourceId) while len(self.nearPlayedSongs) >= self.playlist.length() * 4 / 5: del self.nearPlayedSongs[0] def add_title_into_loved_songs(self, title): self.lovedSongs.append(title)
class ApplicationWindow(QtWidgets.QMainWindow): # >> QtMultimedia Signals #---------------------- play = pyqtSignal() pause = pyqtSignal() stop = pyqtSignal() def __init__(self): QtWidgets.QMainWindow.__init__(self) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.main_widget = QtWidgets.QWidget(self) audioGlobals.playerStarted = False #DEFINE PLAYER-PLAYLIST #---------------------- self.source = QtCore.QUrl.fromLocalFile(os.path.abspath(audioGlobals.wavFileName)) self.content = QMediaContent(self.source) self.player = QMediaPlayer() self.playlist = QMediaPlaylist(self) self.playlist.addMedia(self.content) self.player.setPlaylist(self.playlist) # >> Define annotations and gantt chart #---------------------- self.wave = vA.Waveform() audioGlobals.fig = self.wave self.chart = gA.Chart() audioGlobals.chartFig = self.chart # >> Define player buttons #---------------------- playButton = QPushButton("Play") pauseButton = QPushButton("Pause") stopButton = QPushButton("Stop") # >> Define layouts #---------------------- waveLayout = QVBoxLayout() waveLayout.addWidget(self.wave) waveLayout.addWidget(self.chart) line = QFrame() line.setFrameShape(QFrame.VLine) line.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Expanding) waveLayout.addWidget(line) #Buttons layout buttonLayout = QVBoxLayout() buttonLayout.addWidget(playButton) buttonLayout.addWidget(pauseButton) buttonLayout.addWidget(stopButton) buttonLayout.setAlignment(Qt.AlignTop) # >> Specify final layout align #---------------------- layout = QHBoxLayout(self.main_widget) layout.addLayout(waveLayout) layout.addLayout(buttonLayout) # >> Define buttons connections #---------------------- playButton.clicked.connect(self.Play) pauseButton.clicked.connect(self.Pause) stopButton.clicked.connect(self.Stop) self.main_widget.setFocus() self.setCentralWidget(self.main_widget) # PLAYER BUTTON FUNCTIONS # >> Play audio (whole signal or segment) #---------------------- def Play(self): #GET CLICKS FROM WAVEFORM #---------------------- #Initialize connection-position ONCE if not audioGlobals.playerStarted: #10ms for changePosition -> Not Delaying self.player.positionChanged.connect(self.checkPositionToStop) self.player.setNotifyInterval(10) if audioGlobals.durationFlag==0: audioGlobals.playerStarted = True audioGlobals.startTimeToPlay = 0 self.start = audioGlobals.startTimeToPlay self.end = audioGlobals.duration*1000 - 10 audioGlobals.endTimeToPlay = self.end audioGlobals.counterClick = 3 elif audioGlobals.durationFlag==1: audioGlobals.playerStarted = True self.start = audioGlobals.startTimeToPlay self.end = audioGlobals.duration*1000 - 10 audioGlobals.endTimeToPlay = self.end audioGlobals.counterClick = 3 elif audioGlobals.durationFlag==2: audioGlobals.playerStarted = True self.start = audioGlobals.startTimeToPlay self.end = audioGlobals.endTimeToPlay self.player.setPosition(self.start) playFlag = True self.player.play() # >> Pause audio playing #---------------------- def Pause(self): #Not begging from self.start audioGlobals.playerStarted = True self.player.setPosition(self.time_) self.player.pause() # >> Stop audio playing #---------------------- def Stop(self): self.player.stop() #Begin again segment self.start = audioGlobals.startTimeToPlay self.player.setPosition(self.start) # >> Check ms in audio to stop play #---------------------- def checkPositionToStop(self): self.time_ = self.player.position() tStart = float(self.time)/1000.0 iS = np.argmin(np.abs(audioGlobals.timeArrayToPlot - tStart)) audioGlobals.fig.axes.plot(audioGlobals.timeArrayToPlot[iS],self.signalToPlot[iS], color = 'black', alpha=0.65) print self.time_ if self.time_ >= self.end: self.Stop() self.player.setPosition(self.start) def fileQuit(self): self.close() def closeEvent(self, ce): self.fileQuit()
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui = Ui_MainWindow() #创建UI对象 self.ui.setupUi(self) #构造UI界面 self.player = QMediaPlayer(self) #创建视频播放器 self.player.setNotifyInterval(1000) #信息更新周期, ms scene = QGraphicsScene(self) self.ui.graphicsView.setScene(scene) self.videoItem = QGraphicsVideoItem() #视频显示画面 self.videoItem.setSize(QSizeF(320, 220)) self.videoItem.setFlag(QGraphicsItem.ItemIsMovable) self.videoItem.setFlag(QGraphicsItem.ItemIsSelectable) self.videoItem.setFlag(QGraphicsItem.ItemIsFocusable) scene.addItem(self.videoItem) self.player.setVideoOutput(self.videoItem) #设置视频显示图形项 self.textItem = QGraphicsTextItem("面朝大海,春暖花开") #弹幕文字 font = self.textItem.font() font.setPointSize(20) self.textItem.setFont(font) self.textItem.setDefaultTextColor(Qt.red) self.textItem.setPos(100, 220) self.textItem.setFlag(QGraphicsItem.ItemIsMovable) self.textItem.setFlag(QGraphicsItem.ItemIsSelectable) self.textItem.setFlag(QGraphicsItem.ItemIsFocusable) scene.addItem(self.textItem) self.ui.btnText.setCheckable(True) #弹幕文字按钮 self.ui.btnText.setChecked(True) self.__duration = "" self.__curPos = "" self.player.stateChanged.connect(self.do_stateChanged) self.player.positionChanged.connect(self.do_positionChanged) self.player.durationChanged.connect(self.do_durationChanged) ## ==============自定义功能函数======================== ## ==============event处理函数========================== def closeEvent(self, event): #窗体关闭时 # 窗口关闭时不能自动停止播放,需手动停止 if (self.player.state() == QMediaPlayer.PlayingState): self.player.stop() ## ==========由connectSlotsByName()自动连接的槽函数============ @pyqtSlot() ##打开文件 def on_btnOpen_clicked(self): curPath = QDir.currentPath() #获取系统当前目录 ## curPath=os.getcwd() title = "选择视频文件" filt = "视频文件(*.wmv *.avi);;所有文件(*.*)" fileName, flt = QFileDialog.getOpenFileName(self, title, curPath, filt) if (fileName == ""): return fileInfo = QFileInfo(fileName) baseName = fileInfo.fileName() ## baseName=os.path.basename(fileName) self.ui.LabCurMedia.setText(baseName) curPath = fileInfo.absolutePath() QDir.setCurrent(curPath) #重设当前目录 media = QMediaContent(QUrl.fromLocalFile(fileName)) self.player.setMedia(media) #设置播放文件 self.player.play() @pyqtSlot() ##播放 def on_btnPlay_clicked(self): self.player.play() @pyqtSlot() ##暂停 def on_btnPause_clicked(self): self.player.pause() @pyqtSlot() ##停止 def on_btnStop_clicked(self): self.player.stop() @pyqtSlot() ##全屏 def on_btnFullScreen_clicked(self): self.videoWidget.setFullScreen(True) @pyqtSlot() ##静音按钮 def on_btnSound_clicked(self): mute = self.player.isMuted() self.player.setMuted(not mute) if mute: self.ui.btnSound.setIcon(QIcon(":/icons/images/volumn.bmp")) else: self.ui.btnSound.setIcon(QIcon(":/icons/images/mute.bmp")) @pyqtSlot(int) ##音量调节 def on_sliderVolumn_valueChanged(self, value): self.player.setVolume(value) @pyqtSlot(int) ##播放进度调节 def on_sliderPosition_valueChanged(self, value): self.player.setPosition(value) @pyqtSlot() ##放大 def on_btnZoomIn_clicked(self): sc = self.videoItem.scale() self.videoItem.setScale(sc + 0.1) @pyqtSlot() ##缩小 def on_btnZoomOut_clicked(self): sc = self.videoItem.scale() self.videoItem.setScale(sc - 0.1) @pyqtSlot(bool) ##弹幕 def on_btnText_clicked(self, checked): self.textItem.setVisible(checked) ## =============自定义槽函数=============================== def do_stateChanged(self, state): isPlaying = (state == QMediaPlayer.PlayingState) self.ui.btnPlay.setEnabled(not isPlaying) self.ui.btnPause.setEnabled(isPlaying) self.ui.btnStop.setEnabled(isPlaying) def do_durationChanged(self, duration): self.ui.sliderPosition.setMaximum(duration) secs = duration / 1000 #秒 mins = secs / 60 #分钟 secs = secs % 60 #余数秒 self.__duration = "%d:%d" % (mins, secs) self.ui.LabRatio.setText(self.__curPos + "/" + self.__duration) def do_positionChanged(self, position): if (self.ui.sliderPosition.isSliderDown()): return #如果正在拖动滑条,退出 self.ui.sliderPosition.setSliderPosition(position) secs = position / 1000 #秒 mins = secs / 60 #分钟 secs = secs % 60 #余数秒 self.__curPos = "%d:%d" % (mins, secs) self.ui.LabRatio.setText(self.__curPos + "/" + self.__duration)
class VideoEditor(QFrame): """ This widget allows to load a video file and zoom onto a specific ROI (region of interest) """ meta_data_loaded = pyqtSignal(dict) @property def is_playing(self): """ True if the video is currently being played. """ return self._media_player.state() == QMediaPlayer.PlayingState @property def duration(self): """ Duration in seconds of the video clip currently loaded. """ return self._duration @property def start_trim(self): """ Gets the duration of the trimmed footage at the beginning of the video clip in seconds. """ return self._start_trim @start_trim.setter def start_trim(self, value): """ Sets how much of the beginning of the clip should be trimmed. :param value: Footage to cut in seconds """ if not self.video_file_open: return if value > self.end_trim: value = self.end_trim if value < 0: value = 0 self._start_trim = value self._start_frame = int(value * self.fps) self._timeline.setMinimum(value * 1000) self._current_time.setText('{:10.3f}'.format( round(self._timeline.value() / self.fps / 1000 - self._start_trim, 3))) self._total_time.setText('{:10.3f}'.format(self._end_trim - self._start_trim)) @property def end_trim(self): """ Gets the time in seconds until which the video clip is shown. The rest is trimmed. """ return self._end_trim @end_trim.setter def end_trim(self, value): """ Sets the time in seconds until which the video clip is displayed. Everything beyond is trimmed. :param value: Time code in seconds until which the video clip shoud be shown """ if not self.video_file_open: return if value > self._duration_time_code / 1000: value = self._duration_time_code / 1000 if value < self._start_trim: value = self._start_trim self._end_trim = value self._end_frame = int(value * self.fps) self._timeline.setMaximum(value * 1000) self._current_time.setText('{:10.3f}'.format( round(self._timeline.value() / self.fps / 1000 - self._start_trim, 3))) self._total_time.setText('{:10.3f}'.format(self._end_trim - self._start_trim)) @property def fps(self): """ Frames per second of the currently loaded video clip. """ return self._fps @property def frame_count(self): """ Total amount of frames of the currently loaded video clip. """ return self._frame_count @property def current_frame(self): """ Gets the current frame """ return self._current_frame @current_frame.setter def current_frame(self, value): """ Sets the current frame :param value: frame number """ self._current_frame = value self._allow_frame_counter_update = False self._media_player.setPosition(self._frame_number_to_time_code(value)) self._allow_frame_counter_update = True @property def start_frame(self): """ Gets the start frame. (Depends on the trimming of the video clip) """ return self._start_frame @property def end_frame(self): """ Gets the end frame. (Depends on the trimming of the video clip) """ return self._end_frame @property def video_width(self): """ Horizontal resolution of the currently loaded video clip. """ return self._video_width @property def video_height(self): """ Vertical resolution of the currently loaded video clip. """ return self._video_height @property def video_path(self): """ Path of the currently loaded video file. """ return self._video_path @property def video_file_open(self): """ True if a video file is currently opened in the editor. """ return self._video_file_open @property def roi(self): """ Returns a QRect representing the current region of interest. (If None, the entire image is the ROI) """ return self._roi @property def overlay_layers(self): return self._image_control.overlay_layers def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.installEventFilter( self) # start listening for mouse events to capture ROI changes self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored ) # make the editor use as much space as possible self._media_player = QMediaPlayer(self, QMediaPlayer.VideoSurface) self._media_player.positionChanged.connect(self._player_time_changed_) self._media_player.metaDataAvailableChanged.connect( self._meta_data_changed_) self._grabber = VideoFrameGrabber(self) self._allow_frame_counter_update = True self._result_frame = None self._media_player.setVideoOutput(self._grabber) self._grabber.frameAvailable.connect(self._frame_ready_) self._video_file_open = False self._video_path = None self._display_image = dict( ) # cache for images that are displayed from the video self._frame_count = 0 self._duration_time_code = 0 self._duration = 0 self._fps = 1 self._current_frame = 0 self._video_width = 0 self._video_height = 0 self._file_path = None self._is_playing = False self._roi = None self._start_trim = 0 self._end_trim = 0 self._start_frame = 0 self._end_frame = 0 self._layers = list( ) # layers for visualizations on top of the video footage self._selection_layer = ImageLayer( enabled=False) # layer for selection indicators self._selection_rectangle = ImageRectangle( 0, 0, filled=False, border_color=Qt.yellow) # selection rectangle self._selection_layer.shapes.append(self._selection_rectangle) self._selection_start = None # start point for selection rectangle self.time_code_changed = list() self._layout = QGridLayout() self._timeline = None self._current_time = None self._total_time = None self._frame_box = None self._play_button = None self._stop_button = None self._next_frame_button = None self._previous_frame_button = None self._box_roi_x = None self._box_roi_y = None self._box_roi_width = None self._box_roi_height = None self._accept_roi_updates_from_boxes = True self._wait = False self.setLayout(self._layout) self._setup_() def _time_code_to_frame_number_(self, time_code): """ Convert time code to frame number :param time_code: time code (in ms) :return: frame number """ return int(time_code / 1000 * self.fps) def _frame_number_to_time_code(self, f_number): """ Convert frame number to time code :param f_number: frame number :return: time code (in ms) """ return int(f_number / self.fps * 1000) def _to_image_space_(self, point: QPoint): """ Convert a point on the editor widget in to a point in the video footage. :param point: point in coordinates of the widget :return: point in the coordinates of the video footage """ control_position = self._image_control.pos( ) # get the position of the video image on the editor control_size = self._image_control.size( ) # get the size of the video image dx = (control_size.width() - self._image_control.image_width ) / 2 # get the x offset of the footage in the image dy = (control_size.height() - self._image_control.image_height ) / 2 # get the y offset of the footage in the image x = (point.x() - dx - control_position.x()) / self._image_control.image_scale_x y = (point.y() - dy - control_position.y()) / self._image_control.image_scale_y return QPoint(x, y) def eventFilter(self, obj, event): """ Check for mouse events to edit the ROI :param obj: object that caused the event :param event: event parameters (i.e. mouse position on the widget) """ if event.type( ) == QEvent.MouseMove: # if the mouse was moved, update the selection size target = self._to_image_space_(event.pos()) self._selection_rectangle.position = self._selection_start self._selection_rectangle.width = target.x( ) - self._selection_start.x() self._selection_rectangle.height = target.y( ) - self._selection_start.y() self._image_control.update() elif event.type( ) == QEvent.MouseButtonPress: # if the left mouse button was pressed designate the point as start of the selection self._selection_layer.enabled = True target = self._to_image_space_(event.pos()) self._selection_start = target elif event.type( ) == QEvent.MouseButtonRelease and self._selection_start is not None: # if the button was release the the ROI self._selection_layer.enabled = False end_point = self._to_image_space_(event.pos()) # get all possible corner points x1 = self._selection_start.x() x2 = end_point.x() y1 = self._selection_start.y() y2 = end_point.y() # find upper left corner of the ROI roi_x = x1 if x1 < x2 else x2 roi_y = y1 if y1 < y2 else y2 # find extent of the ROI roi_width = abs(x1 - x2) roi_height = abs(y1 - y2) # set the ROI if it was not just a click with no extent if roi_width > 0 and roi_height > 0: # take into account if the footage was already focused onto a previous ROI if self._roi is not None: roi_x += self._roi.x() roi_y += self._roi.y() # update spin box values self._accept_roi_updates_from_boxes = False # disable ROI changes from the spin boxes self._box_roi_x.setValue(roi_x) self._box_roi_y.setValue(roi_y) self._box_roi_width.setValue(roi_width) self._box_roi_height.setValue(roi_height) self._accept_roi_updates_from_boxes = True # enable ROI changes from the spin boxes self.set_roi(QRect(roi_x, roi_y, roi_width, roi_height)) # set ROI self._selection_start = None # remove selection start return False def sizeHint(self): """ Needed for widget to expand properly on the UI (Should be improved) """ return QSize(1200, 1200) def load(self, path): """ Load a video file from the given path :param path: path of the file """ if self.video_file_open: # close current video file if one was open self.close() self._media_player.setMedia(QMediaContent(QUrl.fromLocalFile(path))) self._video_file_open = True self._media_player.pause() def _player_time_changed_(self, position): self._timeline.setValueSilent(position) if self._allow_frame_counter_update: self._current_frame = self._time_code_to_frame_number_(position) # used for updating keyframes self._image_control.current_frame = self._current_frame # update the UI self._current_time.setText('{:10.3f}'.format( round(position / 1000 - self._start_trim, 3))) self._frame_box.setText('(frame: {:04})'.format(self.current_frame)) # send event about frame change for callback in self.time_code_changed: callback(position / 1000 - self._start_trim) def _meta_data_changed_(self, available): if self._media_player.isMetaDataAvailable(): resolution = self._media_player.metaData('Resolution') self._duration_time_code = self._media_player.metaData( 'Duration') # get duration in ms self._fps = self._media_player.metaData( 'VideoFrameRate') # get frames per second of the video self._media_player.setNotifyInterval(1000 / self._fps) self._frame_count = self._time_code_to_frame_number_( self._duration_time_code) # get total video frames self._video_width = resolution.width() # get width of the image self._video_height = resolution.height() # get height of the image self.start_trim = 0 # no trimming when video is loaded self._start_frame = 0 # first frame is also the first frame of the video self._duration = self._duration_time_code / 1000 self._end_frame = self._frame_count - 1 # don't trim the end of the video self.end_trim = self.duration # use the duration of the video as trim mark (no trimming) # set maximum values of the ROI spin boxes self._box_roi_x.setMaximum(self._video_width) self._box_roi_width.setMaximum(self._video_width) self._box_roi_y.setMaximum(self._video_height) self._box_roi_height.setMaximum(self._video_height) # update the data on the UI elements self._total_time.setText('{:10.3f}'.format(self._end_trim - self._start_trim)) self._frame_box.setText('(Frame: 0000)') self._timeline.setValue(0) self._timeline.setMaximum(self._duration_time_code) self._timeline.setEnabled(True) self._play_button.setEnabled(True) self._stop_button.setEnabled(True) self._next_frame_button.setEnabled(True) self._previous_frame_button.setEnabled(True) self.reset_roi() meta_data = dict() for key in self._media_player.availableMetaData(): meta_data[key] = self._media_player.metaData(key) self.meta_data_loaded.emit(meta_data) def _frame_ready_(self, frame): if self._roi is not None: # crop the frame to the ROI if one has been specified self._result_frame = frame.copy(self._roi) else: self._result_frame = frame self._image_control.set_image(self._result_frame) self._wait = False if self._media_player.position() > self.end_trim * 1000: self.pause() self._media_player.setPosition(self.end_trim * 1000) elif self._media_player.position() < self.start_trim * 1000: self.pause() self._media_player.setPosition(self.start_trim * 1000) def set_time(self, seconds): """ Display the frame that is the closest to the given time :param seconds: time at which to display the frame in seconds """ if not self.video_file_open: return self._media_player.setPosition(seconds * 1000) def get_time(self, frame_number): """ Return the time code at the specified frame :param frame_number: frame number :return: time code in seconds """ if not self.video_file_open: # return zero if no file is opened return 0 frame_number = self._clamp_frame_number_(frame_number) return frame_number / self.fps - self._start_trim @staticmethod def _to_numpy_array_(frame): channels = int(frame.byteCount() / frame.width() / frame.height()) bits = frame.bits() bits.setsize(frame.byteCount()) return np.frombuffer(bits, np.uint8).reshape(frame.height(), frame.width(), channels) def get_frame(self, frame_number, wait_for_new_frame=False): """ Returns a numpy array containing the video frame at the given frame number :param frame_number: frame number :param wait_for_new_frame: Makes sure that a new frame is retrieved before it is returned (otherwise most recent is returned) :return: numpy array """ if not self.video_file_open: # return None if no video file is opened return None frame_number = self._clamp_frame_number_(frame_number) if wait_for_new_frame: self._wait = True old_interval = self._media_player.notifyInterval() self._media_player.setNotifyInterval(1) self._media_player.setPosition( self._frame_number_to_time_code(frame_number)) while self._wait: sleep(0.001) self._media_player.setNotifyInterval(old_interval) result_frame = self._result_frame data = self._to_numpy_array_(result_frame) return data def _clamp_frame_number_(self, frame_number): """ Clamps the given frame number to an allowed range :param frame_number: frame number :return: frame number between 0 and frame_count - 1 """ if frame_number < self._start_frame: frame_number = self._start_frame elif frame_number > self._end_frame: frame_number = self._end_frame return int(frame_number) def _clamp_time_code_(self, time_code): """ Clamps the given time code to an allowed range :param time_code: time code (in ms) :return: time code (in ms) """ if time_code < self._start_trim * 1000: time_code = self._start_trim * 1000 elif time_code > self._end_trim * 1000: time_code = self._end_trim * 1000 return time_code def set_roi(self, rect: QRect): """ Sets the region of interest on the video footage. :param rect: rectangle representing the region of interest """ self._roi = rect self._box_roi_x.setValue(rect.x()) self._box_roi_y.setValue(rect.y()) self._box_roi_width.setValue(rect.width()) self._box_roi_height.setValue(rect.height()) if self._frame_count > 0: self._display_time_code_( self._timeline.value()) # update the display def reset_roi(self): """ Reset the region of interest """ self._roi = None # set the full image as ROI on the spin boxes self._accept_roi_updates_from_boxes = False # stop the spin boxes from updating the ROI self._box_roi_x.setValue(0) self._box_roi_y.setValue(0) self._box_roi_width.setValue(self._video_width) self._box_roi_height.setValue(self._video_height) self._accept_roi_updates_from_boxes = True # re-enable the spin boxes to update the ROI if self._frame_count > 0: self._display_time_code_(self._timeline.value()) def play(self): """ Start playing the video that is currently loaded. """ if self.is_playing: # do nothing if the video is already playing return self._media_player.play() self._play_button.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) # set pause button icon to pause def pause(self): """ Pauses the video. """ self._media_player.pause() self._play_button.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) # set pause button icon to play def stop(self): """ Stop the video and rewind. """ self.pause() # stop the video from playing self._media_player.setPosition(self.start_trim * 1000) # return to the first frame def next_frame(self): """ Skip one frame ahead. """ if self.current_frame < self.end_frame: self.current_frame += 1 def previous_frame(self): """ Skip to the previous frame. """ if self.current_frame > self.start_frame: self.current_frame -= 1 def _play_pause_(self): """ Play if the video is paused or pause if the video is currently playing. """ if self.is_playing: self.pause() else: self.play() def _display_time_code_(self, time_code): """ Displays the requested time code on the widget. :param time_code: time code (in ms) """ if not self.video_file_open: # do nothing if no video file is open return time_code = self._clamp_time_code_(time_code) # get proper time code self._media_player.setPosition(time_code) def _roi_box_value_changed_(self, *args): """ Callback for changes made in the ROI spin boxes. Adjust the ROI accordingly. """ if self._accept_roi_updates_from_boxes: roi_x = self._box_roi_x.value() roi_y = self._box_roi_y.value() roi_width = self._box_roi_width.value() roi_height = self._box_roi_height.value() self.set_roi(QRect(roi_x, roi_y, roi_width, roi_height)) def close(self): """ Closes the video file which is currently opened. """ if self._video_file_open: self._media_player.stop() self._frame_count = 0 # set the frame count to zero self._fps = 1 # set the frames per second to zero self._media_player.setPosition(0) # set the timeline to zero self._timeline.setEnabled(False) # disable the timeline self._play_button.setEnabled(False) # disable the play button self._stop_button.setEnabled(False) # disable the stop button self._next_frame_button.setEnabled( True) # disable the skip frame button self._previous_frame_button.setEnabled( True) # disable the previous frame button self._current_time.setText( '0.000') # set the current time code to zero self._total_time.setText('0.000') # set the total time to zero self._frame_box.setText( '(frame: 0000)') # set the current frame to zero self._box_roi_x.setMaximum(0) # set the ROI maximum to zero self._box_roi_width.setMaximum(0) # set the ROI maximum to zero self._box_roi_y.setMaximum(0) # set the ROI maximum to zero self._box_roi_height.setMaximum(0) # set the ROI maximum to zero self.reset_roi() # reset the ROI def _setup_(self): self._image_control = ImageRenderWidget() self._image_control.overlay_layers.append(self._selection_layer) self._layout.addWidget(self._image_control, 0, 0, 1, 10, Qt.AlignCenter) self._timeline = QJumpSlider(Qt.Horizontal) self._timeline.setEnabled(False) self._timeline.valueChangedSmart.connect(self._display_time_code_) self._layout.addWidget(self._timeline, 1, 4) self._current_time = QLabel('0.000') self._total_time = QLabel('0.000') self._frame_box = QLabel('(Frame: 0000)') self._layout.addWidget(self._current_time, 1, 5) self._layout.addWidget(QLabel('/'), 1, 6) self._layout.addWidget(self._total_time, 1, 7) self._layout.addWidget(QLabel(' s'), 1, 8) self._layout.addWidget(self._frame_box, 1, 9) self._play_button = QPushButton() self._play_button.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) self._play_button.setEnabled(False) self._play_button.clicked.connect(self._play_pause_) self._layout.addWidget(self._play_button, 1, 0) self._stop_button = QPushButton() self._stop_button.setIcon(self.style().standardIcon( QStyle.SP_MediaStop)) self._stop_button.setEnabled(False) self._stop_button.clicked.connect(self.stop) self._layout.addWidget(self._stop_button, 1, 1) self._next_frame_button = QPushButton() self._next_frame_button.setIcon(self.style().standardIcon( QStyle.SP_MediaSkipForward)) self._next_frame_button.setEnabled(False) self._next_frame_button.clicked.connect(self.next_frame) self._layout.addWidget(self._next_frame_button, 1, 3) self._previous_frame_button = QPushButton() self._previous_frame_button.setIcon(self.style().standardIcon( QStyle.SP_MediaSkipBackward)) self._previous_frame_button.setEnabled(False) self._previous_frame_button.clicked.connect(self.previous_frame) self._layout.addWidget(self._previous_frame_button, 1, 2) roi_frame = QFrame() roi_layout = QHBoxLayout() roi_frame.setLayout(roi_layout) roi_frame.setFixedHeight(38) roi_layout.addWidget(QLabel('ROI: [')) roi_layout.addWidget(QLabel('x:')) self._box_roi_x = QSpinBox() roi_layout.addWidget(self._box_roi_x) roi_layout.addWidget(QLabel('y:')) self._box_roi_y = QSpinBox() roi_layout.addWidget(self._box_roi_y) roi_layout.addWidget(QLabel('width:')) self._box_roi_width = QSpinBox() roi_layout.addWidget(self._box_roi_width) roi_layout.addWidget(QLabel('height:')) self._box_roi_height = QSpinBox() roi_layout.addWidget(self._box_roi_height) roi_layout.addWidget(QLabel(']')) roi_reset_button = QPushButton('Reset') roi_reset_button.clicked.connect(self.reset_roi) roi_layout.addWidget(roi_reset_button) self._box_roi_x.valueChanged.connect(self._roi_box_value_changed_) self._box_roi_y.valueChanged.connect(self._roi_box_value_changed_) self._box_roi_width.valueChanged.connect(self._roi_box_value_changed_) self._box_roi_height.valueChanged.connect(self._roi_box_value_changed_) self._layout.addWidget(roi_frame, 2, 0, 1, 9, Qt.AlignLeft)
class Window(QWidget, Ui_Window): def __init__(self): super().__init__() self.setupUi(self) self.status = False self.player = QMediaPlayer() self.player.setNotifyInterval(100) self.open_button.clicked.connect(self.open_dialog) self.play_pause_button.clicked.connect(self.play_pause) self.stop_button.clicked.connect(self.stop) self.player.durationChanged.connect(self.track_duration) self.player.positionChanged.connect(self.track_position) self.player.mediaStatusChanged.connect(self.track_status) self.position_slider.sliderPressed.connect( self.change_track_position_block) self.position_slider.sliderReleased.connect( self.change_track_position_unblock) self.volume_slider.valueChanged.connect(self.player.setVolume) self.mute_button.clicked.connect(self.mute) self.playback_spinbox.valueChanged.connect(self.change_playback) def play_pause(self): if self.status: self.play_pause_button.setText('Play') self.player.pause() self.status = False else: self.play_pause_button.setText('Pause') self.stop_button.setEnabled(True) self.player.play() self.status = True def stop(self): if self.status: self.play_pause_button.setText('Play') self.stop_button.setEnabled(False) self.player.stop() self.status = False def track_duration(self, duration): self.track_duration_label.setText(ms_to_time(duration)) self.position_slider.setMaximum(duration) def track_position(self, position): self.track_position_label.setText(ms_to_time(position)) self.position_slider.setValue(position) def change_track_position_block(self): self.player.positionChanged.disconnect(self.track_position) self.position_slider.valueChanged.connect( self.change_track_position_label) def change_track_position_label(self, value): self.track_position_label.setText(ms_to_time(value)) def change_track_position_unblock(self): self.player.setPosition(self.position_slider.value()) self.position_slider.valueChanged.disconnect( self.change_track_position_label) self.player.positionChanged.connect(self.track_position) def track_status(self, status): if status == 7: self.stop() self.player.setPosition(0) def change_playback(self, value): self.player.positionChanged.disconnect(self.track_position) position = self.player.position() self.player.stop() self.player.setPlaybackRate(value) self.player.play() self.player.setPosition(position) self.player.positionChanged.connect(self.track_position) def mute(self): if self.player.isMuted(): self.player.setMuted(False) self.volume_slider.setEnabled(True) self.mute_button.setText('🔊') else: self.volume_slider.setEnabled(False) self.player.setMuted(True) self.mute_button.setText('🔈') def open_dialog(self): track = QFileDialog.getOpenFileName( self, dialog, '', 'Music (*.flac *.ogg *.mp3 *.wav *.webm)')[0] if track: self.play_pause_button.setEnabled(True) self.position_slider.setEnabled(True) self.volume_slider.setEnabled(True) self.mute_button.setEnabled(True) self.playback_spinbox.setEnabled(True) self.player.setMedia(QMediaContent(QUrl.fromLocalFile(track))) self.stop()
class Main(QMainWindow, Ui_MainWindow): lyricList = [] lyricCount = 0 videoPath = "" videoName = "" darkMode = False redMode = False blueMode = False latestStartTime = QtCore.QTime(0, 0, 0) latestEndTime = QtCore.QTime(0, 0, 0) def __init__(self): super(Main, self).__init__() self.setupUi(self) self.removeButton.clicked.connect(self.OnRemove) self.addButton.clicked.connect(lambda: self.OnAddButton()) self.createSRTButton.clicked.connect(self.CreateSRT) self.actionOpen_Video.triggered.connect(self.OpenVideoFile) #Modes self.actionDark_Mode_2.triggered.connect( lambda: self.ToggleDarkMode(self.darkMode)) self.actionLight_Mode.triggered.connect(self.ToggleLightMode) self.actionRed_Palette.triggered.connect( lambda: self.ToggleRedMode(self.redMode)) self.actionBlue_Palette.triggered.connect( lambda: self.ToggleBlueMode(self.blueMode)) #Video self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) btnSize = QSize(16, 16) videoWidget = QVideoWidget() openButton = QPushButton("Abrir Video") openButton.setToolTip("Abrir Video") openButton.setStatusTip("Abrir Video") openButton.setFixedHeight(40) openButton.setIconSize(btnSize) openButton.setFont(QFont("Noto Sans", 15)) openButton.setIcon( QIcon.fromTheme("document-open", QIcon("D:/_Qt/img/open.png"))) openButton.clicked.connect(self.open) self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setFixedHeight(65) self.playButton.setFixedWidth(60) self.playButton.setIconSize(btnSize) 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) self.statusBar = QStatusBar() self.statusBar.setFont(QFont("Noto Sans", 7)) self.statusBar.setFixedHeight(14) controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) controlLayout.addWidget(openButton) controlLayout.addWidget(self.playButton) controlLayout.addWidget(self.positionSlider) #self.QVideoBoxVLayout = QVBoxLayout() self.QVideoBoxVLayout.addWidget(videoWidget) self.QVideoBoxVLayout.addLayout(controlLayout) self.QVideoBoxVLayout.addWidget(self.statusBar) self.setLayout(self.QVideoBoxVLayout) self.mediaPlayer.setVideoOutput(videoWidget) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.error.connect(self.handleError) # Every 200 ms self.mediaPlayer.setNotifyInterval(200) self.translator = google_translator() self.statusBar.showMessage("Listo") # connect buttons playback self.fiveBack.clicked.connect(lambda: self.TimeSkip(5, False)) self.tenBack.clicked.connect(lambda: self.TimeSkip(10, False)) self.oneMBack.clicked.connect(lambda: self.TimeSkip(.1, False)) self.fiveForward.clicked.connect(lambda: self.TimeSkip(5, True)) self.tenForward.clicked.connect(lambda: self.TimeSkip(10, True)) self.oneMForward.clicked.connect(lambda: self.TimeSkip(.1, True)) #Import srt self.actionInportar_Subtitulos_srt.triggered.connect(self.ImportSRT) def ToggleLightMode(self): light_palette = QPalette() appctxt.app.setPalette(light_palette) def ToggleRedMode(self, dark): if not dark: red_palette = QPalette() red_palette.setColor(QPalette.Window, QColor(100, 53, 53)) red_palette.setColor(QPalette.WindowText, Qt.white) red_palette.setColor(QPalette.Base, QColor(25, 25, 25)) red_palette.setColor(QPalette.AlternateBase, QColor(53, 53, 53)) red_palette.setColor(QPalette.ToolTipBase, Qt.white) red_palette.setColor(QPalette.ToolTipText, Qt.white) red_palette.setColor(QPalette.Text, Qt.white) red_palette.setColor(QPalette.Button, QColor(53, 53, 53)) red_palette.setColor(QPalette.ButtonText, Qt.white) red_palette.setColor(QPalette.BrightText, Qt.red) red_palette.setColor(QPalette.Link, QColor(42, 130, 218)) red_palette.setColor(QPalette.Highlight, QColor(42, 130, 218)) red_palette.setColor(QPalette.HighlightedText, Qt.black) appctxt.app.setPalette(red_palette) #appctxt.app.setStyleSheet( # "QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }") self.redMode = True else: light_palette = QPalette() appctxt.app.setPalette(light_palette) self.redMode = False def ToggleBlueMode(self, dark): if not dark: blue_palette = QPalette() blue_palette.setColor(QPalette.Window, QColor(53, 53, 100)) blue_palette.setColor(QPalette.WindowText, Qt.white) blue_palette.setColor(QPalette.Base, QColor(25, 25, 25)) blue_palette.setColor(QPalette.AlternateBase, QColor(53, 53, 53)) blue_palette.setColor(QPalette.ToolTipBase, Qt.white) blue_palette.setColor(QPalette.ToolTipText, Qt.white) blue_palette.setColor(QPalette.Text, Qt.white) blue_palette.setColor(QPalette.Button, QColor(53, 53, 53)) blue_palette.setColor(QPalette.ButtonText, Qt.white) blue_palette.setColor(QPalette.BrightText, Qt.red) blue_palette.setColor(QPalette.Link, QColor(42, 130, 218)) blue_palette.setColor(QPalette.Highlight, QColor(42, 130, 218)) blue_palette.setColor(QPalette.HighlightedText, Qt.black) appctxt.app.setPalette(blue_palette) #appctxt.app.setStyleSheet( # "QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }") self.blueMode = True else: light_palette = QPalette() appctxt.app.setPalette(light_palette) self.blueMode = False def ToggleDarkMode(self, dark): if not dark: dark_palette = QPalette() dark_palette.setColor(QPalette.Window, QColor(53, 53, 53)) dark_palette.setColor(QPalette.WindowText, Qt.white) dark_palette.setColor(QPalette.Base, QColor(25, 25, 25)) dark_palette.setColor(QPalette.AlternateBase, QColor(53, 53, 53)) dark_palette.setColor(QPalette.ToolTipBase, Qt.white) dark_palette.setColor(QPalette.ToolTipText, Qt.white) dark_palette.setColor(QPalette.Text, Qt.white) dark_palette.setColor(QPalette.Button, QColor(53, 53, 53)) dark_palette.setColor(QPalette.ButtonText, Qt.white) dark_palette.setColor(QPalette.BrightText, Qt.red) dark_palette.setColor(QPalette.Link, QColor(42, 130, 218)) dark_palette.setColor(QPalette.Highlight, QColor(42, 130, 218)) dark_palette.setColor(QPalette.HighlightedText, Qt.black) appctxt.app.setPalette(dark_palette) #appctxt.app.setStyleSheet( # "QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }") self.darkMode = True else: light_palette = QPalette() appctxt.app.setPalette(light_palette) self.darkMode = False # Currently only supports mp4 def ImportSRT(self): fileName, _ = QFileDialog.getOpenFileName(self, "Selecciona los mediose", ".", "SRT Files (*.srt)") videoFilePath = (fileName.split(".")[0]) + ".mp4" print(videoFilePath) if fileName != '': self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(videoFilePath))) self.playButton.setEnabled(True) self.statusBar.showMessage(videoFilePath) self.play() self.videoPath = videoFilePath self.videoName = self.videoPath.split("/")[-1] # Delete existing objects count = self.lyricCount for i in range(count): self.OnRemove() # Create video objects self.CreateLyricObjectsFromSRT(fileName) def CreateLyricObjectsFromSRT(self, path): srtFile = open(path, "r", encoding="utf-8") # General srt format is # index # start time --> end time # lyrics # empty line #--- Temp variables index = 1 foundStart = False foundEnd = False foundLyrics = False lyricsString = "" subStringTime = "-->" startString = "" endString = "" # iterate through srt file for line in srtFile: # after times is lyrics if foundStart and foundEnd and not foundLyrics: # until we find empty if line == "\n": foundLyrics = True if lyricsString != "": lyricsString = lyricsString + line.strip('\n').rstrip() else: lyricsString = line # times if subStringTime in line: startString = line.split(" --> ")[0].rstrip() endString = line.split(" --> ")[-1].rstrip() if startString != "": foundStart = True else: print("No start time for item", index) if endString != "": foundEnd = True else: print("No end time for item ", index) index = index + 1 if foundLyrics and startString != "" and endString != "": #Create lyrics object here startQTime = self.ReturnQTimeObject(startString) endQtime = self.ReturnQTimeObject(endString) self.OnAdd(start=startQTime, end=endQtime, lyrics=lyricsString) lyricsString = "" foundLyrics = False foundStart = False foundEnd = False srtFile.close() def ReturnQTimeObject(self, timeString): hours = timeString.split(":")[0] minutes = timeString.split(":")[1] secondsAndMsec = timeString.split(":")[2] seconds = secondsAndMsec.split(",")[0] mSeconds = secondsAndMsec.split(",")[1] return QtCore.QTime(int(hours), int(minutes), int(seconds), int(mSeconds)) def TimeSkip(self, amount, forward): if forward: tempPosition = self.mediaPlayer.position() self.setPosition(tempPosition + int(amount * 1000)) else: tempPosition = self.mediaPlayer.position() self.setPosition(tempPosition - int(amount * 1000)) def SetCurrentTimeText(self, millis): millis = int(millis) seconds = (millis / 1000) % 60 seconds = int(seconds) minutes = (millis / (1000 * 60)) % 60 minutes = int(minutes) sMillis = self.ThreeCharSyntax(str(millis)) sSeconds = self.TwoCharSyntax(str(seconds)) sMinutes = self.TwoCharSyntax(str(minutes)) self.currentTime.setText("Tiempo Actual " + sMinutes + ":" + sSeconds + ":" + sMillis) def open(self): fileName, _ = QFileDialog.getOpenFileName( self, "Selecciona los mediose", ".", "Video Files (*.mp4 *.flv *.ts *.mts *.avi)") if fileName != '': self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(fileName))) self.playButton.setEnabled(True) self.statusBar.showMessage(fileName) self.play() self.videoPath = fileName self.videoName = self.videoPath.split("/")[-1] def OpenVideoFile(self): #self.videoPath, _ = QFileDialog.getOpenFileName(self, 'Open File', options=QFileDialog.DontUseNativeDialog) options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog self.videoPath, _ = QFileDialog.getOpenFileName( self, "Select Video File", "", "Video File (*.mp4 *.avi *.ogv)", options=options) self.videoName = self.videoPath.split("/")[-1] def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) # Show exact time when paused self.SetCurrentTimeText(self.mediaPlayer.position()) self.SetCurrentLyrics(self.mediaPlayer.position()) else: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) def positionChanged(self, position): self.positionSlider.setValue(position) self.SetCurrentTimeText(self.mediaPlayer.position()) self.SetCurrentLyrics(position) def durationChanged(self, duration): self.positionSlider.setRange(0, duration) def setPosition(self, position): self.mediaPlayer.setPosition(position) def handleError(self): self.playButton.setEnabled(False) self.statusBar.showMessage("Error: " + self.mediaPlayer.errorString()) def OnRemove(self): if len(self.lyricList) > 0: self.verticalLayout.removeWidget(self.lyricList[-1]) sip.delete(self.lyricList[-1]) self.lyricCount -= 1 del (self.lyricList[-1]) self.progressBar.setProperty("value", 0) def OnAddButton(self): if self.lyricCount > 0: endTimeObject = self.lyricList[self.lyricCount - 1].findChild( QtWidgets.QTimeEdit, "endTime").time() newTime = QtCore.QTime(0, endTimeObject.minute(), endTimeObject.second(), endTimeObject.msec() + 1) self.OnAdd(start=newTime, end=newTime) self.scrollArea.ensureWidgetVisible(self.lyricGroup) max = self.scrollArea.verticalScrollBar().maximum() self.scrollArea.verticalScrollBar().setValue(999999) else: self.OnAdd() max = self.scrollArea.verticalScrollBar().maximum() self.scrollArea.verticalScrollBar().setValue(max) def OnAdd(self, start=QtCore.QTime(0, 0, 0), end=QtCore.QTime(0, 0, 0), lyrics=""): self.lyricGroup = QtWidgets.QWidget(self.scrollAreaWidgetContents) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.lyricGroup.sizePolicy().hasHeightForWidth()) self.lyricGroup.setSizePolicy(sizePolicy) self.lyricGroup.setMinimumSize(QtCore.QSize(0, 150)) self.lyricGroup.setMaximumSize(QtCore.QSize(600, 100)) self.lyricGroup.setLayoutDirection(QtCore.Qt.LeftToRight) self.lyricGroup.setObjectName("lyricGroup") self.gridLayout = QtWidgets.QGridLayout(self.lyricGroup) self.gridLayout.setObjectName("gridLayout") self.startLabel = QtWidgets.QLabel(self.lyricGroup) font = QtGui.QFont() font.setPointSize(10) self.startLabel.setFont(font) self.startLabel.setObjectName("startLabel") self.startLabel.setText("Inicio:") self.gridLayout.addWidget(self.startLabel, 0, 0, 1, 1) font = QtGui.QFont() font.setPointSize(12) self.lyricsText = QtWidgets.QPlainTextEdit(self.lyricGroup) self.lyricsText.setObjectName("lyricsText") self.lyricsText.setFont(font) self.lyricsText.setPlainText(lyrics) self.gridLayout.addWidget(self.lyricsText, 0, 2, 2, 1) self.endLabel = QtWidgets.QLabel(self.lyricGroup) font = QtGui.QFont() font.setPointSize(10) self.endLabel.setFont(font) self.endLabel.setObjectName("endLabel") self.endLabel.setText("Final:") self.gridLayout.addWidget(self.endLabel, 1, 0, 1, 1) self.endTime = QtWidgets.QTimeEdit(self.lyricGroup) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.endTime.sizePolicy().hasHeightForWidth()) self.endTime.setSizePolicy(sizePolicy) self.endTime.setMinimumSize(QtCore.QSize(100, 30)) self.endTime.setMaximumSize(QtCore.QSize(75, 16777215)) font = QtGui.QFont() font.setPointSize(11) self.endTime.setFont(font) self.endTime.setObjectName("endTime") self.endTime.setDisplayFormat("mm:ss:zzz") self.gridLayout.addWidget(self.endTime, 1, 1, 1, 1) self.endTime.setCurrentSectionIndex(0) self.endTime.setTime(end) self.startTime = QtWidgets.QTimeEdit(self.lyricGroup) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.startTime.sizePolicy().hasHeightForWidth()) self.startTime.setSizePolicy(sizePolicy) self.startTime.setMinimumSize(QtCore.QSize(100, 30)) self.startTime.setMaximumSize(QtCore.QSize(75, 16777215)) font = QtGui.QFont() font.setPointSize(11) self.startTime.setFont(font) self.startTime.setCurrentSection(QtWidgets.QDateTimeEdit.MSecSection) self.startTime.setCurrentSection(2) self.startTime.setCurrentSectionIndex(2) self.startTime.setTime(start) self.startTime.setObjectName("startTime") self.startTime.setDisplayFormat("mm:ss:zzz") #self.startTime.timeChanged.connect(lambda:self.IncreaseTime(self.endTime)) self.gridLayout.addWidget(self.startTime, 0, 1, 1, 1) self.verticalLayout.addWidget(self.lyricGroup, 0, QtCore.Qt.AlignTop) # add to list self.lyricList.append(self.lyricGroup) self.lyricCount += 1 self.progressBar.setProperty("value", 0) def IncreaseTime(self, endTime): if endTime.time().currentTime() <= self.startTime.time().currentTime(): startTimeObject = self.startTime.time() newTime = QtCore.QTime(0, startTimeObject.minute(), startTimeObject.second(), startTimeObject.msec()) endTime.setTime(newTime) def CreateSRT(self): # For progress bar self.progressCount = 1 itemSelected = self.textAppendList.currentText() # Check to see if file has been open if self.videoPath: self.newVideoPath = self.videoPath.split( ".")[0] + " - NoTranslation" + ".srt" srtFile = open(self.newVideoPath, "w", encoding="utf-8") if self.translateEnglish.isChecked( ) and self.translateSpanish.isChecked(): self.newVideoPath = self.videoPath.split(".")[0] + ".srt" srtFile = open(self.newVideoPath, "w", encoding="utf-8") elif self.translateEnglish.isChecked(): self.newVideoPath = self.videoPath.split( ".")[0] + " - English" + ".srt" srtFile = open(self.newVideoPath, "w", encoding="utf-8") elif self.translateSpanish.isChecked(): self.newVideoPath = self.videoPath.split( ".")[0] + " - Spanish" + ".srt" srtFile = open(self.newVideoPath, "w", encoding="utf-8") for i in range(len(self.lyricList)): # lyrics childLyricsText = self.lyricList[i].findChild( QtWidgets.QPlainTextEdit, "lyricsText") # start Time ## Format: hh:mm:ss:zzz childStartTime = self.lyricList[i].findChild( QtWidgets.QTimeEdit, "startTime").time() # end Time childEndTime = self.lyricList[i].findChild( QtWidgets.QTimeEdit, "endTime").time() #print("Start time : " + str(childStartTime.minute()) + str(childStartTime.second()) + str( # childStartTime.msec())) # Number of iteration srtFile.write(str(self.progressCount) + "\n") # start time minuteTime = self.TwoCharSyntax(str(childStartTime.minute())) secondTime = self.TwoCharSyntax(str(childStartTime.second())) mSecTime = self.ThreeCharSyntax(str(childStartTime.msec())) srtFile.write("00:" + minuteTime + ":" + secondTime + "," + mSecTime + " --> ") # end time minuteTime = self.TwoCharSyntax(str(childEndTime.minute())) secondTime = self.TwoCharSyntax(str(childEndTime.second())) mSecTime = self.ThreeCharSyntax(str(childEndTime.msec())) srtFile.write("00:" + minuteTime + ":" + secondTime + "," + mSecTime) # Lyrics if self.translateEnglish.isChecked( ) and self.translateSpanish.isChecked(): result = self.translator.translate( childLyricsText.toPlainText(), lang_tgt='en') srtFile.write("\n" + result.rstrip().replace("\n", " ") + "\n") result = self.translator.translate( childLyricsText.toPlainText(), lang_tgt='es') srtFile.write(itemSelected + result.rstrip().replace("\n", " ") + itemSelected + "\n\n") elif self.translateEnglish.isChecked(): result = self.translator.translate( childLyricsText.toPlainText(), lang_tgt='en') srtFile.write("\n" + result.rstrip().replace("\n", " ") + "\n\n") elif self.translateSpanish.isChecked(): result = self.translator.translate( childLyricsText.toPlainText(), lang_tgt='es') srtFile.write("\n" + itemSelected + result.rstrip().replace("\n", " ") + itemSelected + "\n\n") else: srtFile.write( "\n" + childLyricsText.toPlainText().replace("\n", " ") + "\n\n") progress = self.progressCount / self.lyricCount print(int(progress * 100)) self.progressBar.setProperty("value", int(progress * 100)) self.progressCount += 1 if progress == 1: print(self.newVideoPath) openPath = self.newVideoPath.replace('/', '\\') subprocess.Popen(r'explorer /select,"' + openPath + '"') else: self.ShowPopUpMessage() # check if string is only 1 character def TwoCharSyntax(self, str): if len(str) != 2: return "0" + str else: return str #Make into 3 char def ThreeCharSyntax(self, str): if len(str) == 1: return "00" + str elif len(str) == 2: return "0" + str elif len(str) >= 4: return str[-3:] else: return str def SetCurrentLyrics(self, currentTime): showingLyrics = False for i in range(len(self.lyricList)): # start Time ## Format: hh:mm:ss:zzz childStartTime = self.lyricList[i].findChild( QtWidgets.QTimeEdit, "startTime").time() # convert to msecs minuteTime = childStartTime.minute() secondTime = childStartTime.second() mSecTime = childStartTime.msec() startTotal = (minuteTime * 60000) + (secondTime * 1000) + mSecTime # end Time childEndTime = self.lyricList[i].findChild(QtWidgets.QTimeEdit, "endTime").time() # convert to msecs minuteTime = childEndTime.minute() secondTime = childEndTime.second() mSecTime = childEndTime.msec() endTotal = (minuteTime * 60000) + (secondTime * 1000) + mSecTime if currentTime >= startTotal and currentTime <= endTotal: childLyricsText = self.lyricList[i].findChild( QtWidgets.QPlainTextEdit, "lyricsText") self.currentLyrics.setText(childLyricsText.toPlainText()) showingLyrics = True if showingLyrics == False: self.currentLyrics.setText("") def ShowPopUpMessage(self): errorMsg = QMessageBox() errorMsg.setWindowTitle("Error") errorMsg.setText("Por favor selecciona un video primero") x = errorMsg.exec_()
class jaabaGUI(QMainWindow): """ controller for the blob labeling GUI""" def __init__(self,parent=None): self.debugMode = True self.debugVideoPath = '/Users/071cht/Desktop/Lab/jaabagui/testt.mjpeg.avi' QMainWindow.__init__(self,parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.installEventFilter(self) self.setFocusPolicy(Qt.StrongFocus) #add new slider # self.positionSlider=QSlider(Qt.Horizontal) # self.positionSlider.setGeometry (800,800,100,30) # self.positionSlider.setRange(0, 0) # self.positionSlider.sliderMoved.connect(self.setPosition) #setup Video #video player self.mediaPlayer1 = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.mediaPlayer2 = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.mediaPlayer2.setNotifyInterval(10) #self.mediaPlayer.metaDataChanged.connect(self.metaDataChanged) self.mediaPlayer1.durationChanged.connect(self.durationChanged) self.mediaPlayer1.positionChanged.connect(self.positionChanged) self.mediaPlayer2.positionChanged.connect(self.positionChanged) #self.mediaPlayer2.positionChanged.connect(self.paintEvent) #visualizetion self.scene = QGraphicsScene() self.ui.graphicsView.setScene(self.scene) #self.scene.setBackgroundBrush(Qt.black) self.videoItem1 = QGraphicsVideoItem() self.videoItem2 = Video() self.scene.addItem(self.videoItem1) self.scene.addItem(self.videoItem2) self.mediaPlayer1.setVideoOutput(self.videoItem1) self.mediaPlayer2.setVideoOutput(self.videoItem2) #slider bar self.ui.horizontalSlider.setRange(0, 0) self.ui.horizontalSlider.sliderMoved.connect(self.setPosition) # self.ui.horizontalSlider.sliderPressed.connect(self.sliderPressed) #draw on video self.flyCanvas= TargetView() self.scene.addItem(self.flyCanvas) #give reference to target view self.flyCanvas.setWindowReference(self) #lineEdit signals: self.ui.lineEdit.returnPressed.connect(self.lineEditChanged) #callbacks self.ui.actionQuit.triggered.connect(self.quit) self.ui.actionLoad_Project.triggered.connect(self.loadVideo) self.ui.actionImport_Labels.triggered.connect(self.loadLabels) #self.ui.buttonPlay.clicked[bool].connect(self.setToggleText) self.ui.buttonPlay.clicked.connect(self.play) self.ui.actionSave.triggered.connect(self.saveLabels) ## print self.ui.graphicsView.sizeHint() #behavior Button self.ui.buttonBehavior.clicked.connect(self.behaviorButtonClick) self.ui.buttonNone.clicked.connect(self.noneButtonClick) #initialization self.loaded = False self.videoFilename = None self.frame_count=None self.width=None self.height=None self.frame_trans=None self.previous_frame=0 self.current_frame=0 self.behaviorButtonStart = False self.noneButtonStart = False self.currentFly=1 #initialize flyInfo #self.setCurrentFly(self.currentFly) # register flyid changed callback self.flyCanvas.onCurrentFlyIdChanged(self.currentFlyIdChangedCallback) self.flyCanvas.setCurrentFlyId(self.currentFly) # when double click on video, change fly id in target view self.videoItem2.onDoubleClick(self.flyCanvas.setCurrentFlyIdByXY) ######################## # DEBUG PART HERE!!!!! # ######################## if (self.debugMode): self.debugLoadVideo() # add label UI related when load video def showEvent(self, evt): super(jaabaGUI, self).showEvent(evt) ##### HERE THE WINDOW IS LOADED!!!!!!!! # self.loadLabelUI() def loadLabelUI(self): #labels self.labelScene = QGraphicsScene() self.ui.graphLabels.setScene(self.labelScene) # the size is only accurate after the window fully displayed labelUIWidth = self.ui.graphLabels.width() labelUIHeight = self.ui.graphLabels.height()-1 self.labelScene.setSceneRect(0,0,labelUIWidth,labelUIHeight) self.labelUI = LabelUI() # visiableWidth = 850 # height = 30 # visiableFrameNum = 850 self.labelUI.setWidthPerFrame(850.0/850.0) # print '850/500',850.0/850.0b # print 'length_perframe is ', self.labelUI.widthPerFrame # 850 is the original length of graphLabel total_length= self.labelUI.widthPerFrame * self.frame_count self.labelUI.setVisiableSize(total_length,30) # set start position self.labelUI.setPos(labelUIWidth/2,0) print 'frame_count is ', self.frame_count print 'total length is', total_length self.labelScene.addItem(self.labelUI) # middle line ui self.labelUIMiddleLine = LabelUIMiddleLine() self.labelScene.addItem(self.labelUIMiddleLine) self.labelUIMiddleLine.setPos(labelUIWidth/2,0) # self.labelUI.setPos(QPointF(-100,0)) self.writeLog('Label UI loaded') def eventFilter(self, obj, event): if (event.type() == PyQt5.QtCore.QEvent.KeyPress): # http://qt-project.org/doc/qt-4.8/qt.html#Key-enum key = event.key() if (key == Qt.Key_Up) : curr_frame= int(float(self.ui.lineEdit.text())) curr_frame= curr_frame-30 media_position= int(round(curr_frame*self.frame_trans)) # print curr_frame, media_position self.mediaPlayer1.setPosition(media_position) self.mediaPlayer2.setPosition(media_position) # print 'down -30' elif (key == Qt.Key_Right): curr_frame= int(float(self.ui.lineEdit.text())) # print 'right +1' # print curr_frame curr_frame= curr_frame+1 media_position= int(round(curr_frame*self.frame_trans)) # print 'curr_frame',curr_frame # print 'frame_trans',self.frame_trans # print ' curr_frame*self.frame_trans',curr_frame*self.frame_trans # print 'media_position',media_position # print curr_frame, media_position self.mediaPlayer1.setPosition(media_position) self.mediaPlayer2.setPosition(media_position) # self.mediaPlayerPositionChanged(media_position) elif (key == Qt.Key_Left): curr_frame= int(float(self.ui.lineEdit.text())) curr_frame= curr_frame-1 media_position= int(round(curr_frame*self.frame_trans)) self.mediaPlayer1.setPosition(media_position) self.mediaPlayer2.setPosition(media_position) # print 'left -1' elif (key == Qt.Key_Down): curr_frame= int(float(self.ui.lineEdit.text())) curr_frame= curr_frame+30 media_position= int(round(curr_frame*self.frame_trans)) self.mediaPlayer1.setPosition(media_position) self.mediaPlayer2.setPosition(media_position) # print 'up +30' return True return False # ###actions starts from here### def quit(self): QApplication.quit() def loadVideo(self): # print QMediaPlayer.supportedMimeTypes() self.writeLog("Loading video...") self.videoFilename = QFileDialog.getOpenFileName(self, 'Open File', '.')[0] if not self.videoFilename: self.writeLog("User cancelled - no video loaded") return else: cap=cv2.VideoCapture(self.videoFilename) self.frame_count=cap.get(cv2.CAP_PROP_FRAME_COUNT) self.width=cap.get(3) self.height=cap.get(4) self.mediaPlayer2.setMedia(QMediaContent(QUrl.fromLocalFile(self.videoFilename ))) self.mediaPlayer1.setMedia(QMediaContent(QUrl.fromLocalFile(self.videoFilename ))) self.ui.buttonPlay.setEnabled(True) # self.mediaPlayer2.setVideoOutput(self.videoItem2) # self.mediaPlayer1.setVideoOutput(self.videoItem1) # size= self.videoItem2.nativeSize() # # print size ## print self.mediaPlayer.duration() ## print self.mediaPlayer.metaData() self.writeLog("Video loaded!") # init label related ui self.loadLabelUI() def debugLoadVideo(self): self.videoFilename = self.debugVideoPath cap=cv2.VideoCapture(self.videoFilename) self.frame_count=cap.get(cv2.CAP_PROP_FRAME_COUNT) self.width=cap.get(3) self.height=cap.get(4) self.mediaPlayer2.setMedia(QMediaContent(QUrl.fromLocalFile(self.videoFilename ))) self.mediaPlayer1.setMedia(QMediaContent(QUrl.fromLocalFile(self.videoFilename ))) self.ui.buttonPlay.setEnabled(True) self.writeLog("Video loaded!") QTimer.singleShot(1000, self.loadLabelUI) def play(self): self.videoItem1.setAspectRatioMode(0) self.videoItem2.setAspectRatioMode(0) self.scene.setSceneRect(0,0,self.ui.graphicsView.width(),self.ui.graphicsView.height()) self.videoItem1.setSize(QSizeF(self.ui.graphicsView.width()/2,self.ui.graphicsView.height())) self.videoItem2.setSize(QSizeF(self.ui.graphicsView.width()/2,self.ui.graphicsView.height())) self.videoItem1.setPos(QPointF(0,0)) self.videoItem2.setPos(QPointF(self.ui.graphicsView.width()/2,0)) self.flyCanvas.setPos(QPointF(self.ui.graphicsView.width()/2,0)) # custom function setXYScale self.videoItem2.setXYScale(self.width,self.height,self.ui.graphicsView.width()/2,self.ui.graphicsView.height()) self.flyCanvas.setXYScale(self.width,self.height,self.ui.graphicsView.width()/2,self.ui.graphicsView.height()) if self.mediaPlayer1.state() == QMediaPlayer.PlayingState: self.ui.buttonPlay.setIcon(self.ui.style().standardIcon(PyQt5.QtWidgets.QStyle.SP_MediaPlay)) self.ui.buttonPlay.setText("Play") self.mediaPlayer1.pause() self.writeLog("Video paused") else: self.ui.buttonPlay.setIcon(self.ui.style().standardIcon(PyQt5.QtWidgets.QStyle.SP_MediaPause)) self.ui.buttonPlay.setText("Stop") self.mediaPlayer1.play() self.writeLog("Playing video") if self.mediaPlayer2.state() == QMediaPlayer.PlayingState: self.mediaPlayer2.pause() else: self.mediaPlayer2.play() def loadLabels(self): self.writeLog("Loading labels from file...") self.labelFilename = QFileDialog.getOpenFileName(self, 'Open File', '.')[0] self.labelUI.labelData = pickle.load(open(self.labelFilename,"rb")) self.writeLog("Label loaded from file:" + self.labelFilename) def saveLabels(self): # Now it can only save to current file. Will add an poput window to choose path later pickle.dump( self.labelUI.labelData, open( "newLabels.p", "wb" ) ) def setPosition(self, position): self.mediaPlayer1.setPosition(position) self.mediaPlayer2.setPosition(position) # when position of media changed, set slider and text box accordingly. def positionChanged(self, position): #test change labelui position # self.labelUI.startLabel(); # self.labelUI.update() previous_frame= self.previous_frame curr_frame= int(round(position/self.frame_trans)) self.current_frame=curr_frame frame_change= previous_frame-curr_frame move_width= frame_change * self.labelUI.widthPerFrame self.previous_frame= curr_frame self.labelUI.moveBy(move_width,0) self.labelUI.setCurrentFrame(curr_frame) # enforce labelUI paint once self.labelUI.update() # self.labelUI.setPos(self.labelUI.mapToParent(1,0)); # self.labelUI.update() # # print 'triggered position' # # print position # # print 'cur position' # # print self.mediaPlayer2.position() self.updateLineEdit(position) self.updateSliderAndGraph(position) # self.ui.horizontalSlider.setValue(position) # if isinstance(self.frame_trans,float): # # # print type(position),position # # # print type(self.frame_trans),self.frame_trans # # # print position/self.frame_trans # self.ui.lineEdit.setText(str(int(round(position/self.frame_trans)))) # self.flyCanvas.getFrame(int(round(position/self.frame_trans))) # self.flyCanvas.isManualCalled = True; # self.flyCanvas.update() # self.writeLog(str(position)) # # self.updateMediaControlUI(position) # # self.flyCanvas.update() def updateSliderAndGraph(self, position): self.ui.horizontalSlider.setValue(position) if isinstance(self.frame_trans,float): self.flyCanvas.getFrame(int(round(position/self.frame_trans))) self.flyCanvas.isManualCalled = True self.flyCanvas.update() #self.writeLog(str(position)) def updateLineEdit(self, position): # # print self.width # # print self.height if isinstance(self.frame_trans,float): # # print type(position),position # # print type(self.frame_trans),self.frame_trans # # print position/self.frame_trans self.ui.lineEdit.setText(str(int(round(position/self.frame_trans)))) def durationChanged(self, duration): self.ui.horizontalSlider.setRange(0, duration) self.frame_trans=self.mediaPlayer1.duration()/self.frame_count ## print self.frame_trans #def eventFilter(self,source,event): #if (event.type()==PyQt5.QtCore.QEvent.MousePress and source is self.videoItem2): # pos=event.pos() # # print('mouse position: (%d,%d)' % (pos.x(),pos.y())) # return PyQt5.QtGui.QWidget.eventFilter(self, source, event) def writeLog(self,text): self.ui.log.setText(text) # def eventFilter (self.ui.lineEdit,event): # if event.type()==PyQt5.QtCore.QEvent def lineEditChanged(self): #set position of media curr_frame= int(float(self.ui.lineEdit.text())) media_position= int(round(curr_frame*self.frame_trans)) self.mediaPlayer1.setPosition(media_position) self.mediaPlayer2.setPosition(media_position) # print 'setPosition' # print media_position # print 'after set' # print self.mediaPlayer2.position() # self.updateSliderAndGraph(media_position) def behaviorButtonClick(self): # flip flag self.behaviorButtonStart = not self.behaviorButtonStart # check click to start or stop if (self.behaviorButtonStart): # start labeling self.labelUI.startLabel(self.ui.comboBox.currentIndex(),'',self.current_frame) self.writeLog('start labeling') else: # stop lableing self.labelUI.stopLabel() self.writeLog('stop labeling') def noneButtonClick(self): # flip flag self.noneButtonStart = not self.noneButtonStart # check click to start or stop if (self.noneButtonStart): # start labeling self.labelUI.startLabel(self.ui.comboBox.currentIndex(),'_none',self.current_frame) self.writeLog('start labeling') else: # stop lableing self.labelUI.stopLabel() self.writeLog('stop labeling') # set CurrentFly when fly changed! def setCurrentFly(self,fly): self.currentFly = fly self.ui.flyInfo.setPlainText('FlyID:' + str(self.currentFly)) self.flyCanvas.currentFly=fly def currentFlyIdChangedCallback(self,fly): print 'callback!!!!!'; self.currentFly = fly self.ui.flyInfo.setPlainText('FlyID:' + str(self.currentFly))
class ReplayWindow(QWidget): def __init__(self, stylesheet, **kwargs): super().__init__(**kwargs) self.setStyleSheet(stylesheet) self.offset_defined = None self.time_result = None self.layout = QVBoxLayout() self.timer_label = self.make_label() self.video_w = QVideoWidget() self.v_player = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.v_player.setVideoOutput(self.video_w) self.v_player.setNotifyInterval(7) self.v_player.positionChanged.connect(self.update_time_label) self.v_player.stateChanged.connect(self.video_ended) self.music_player = QMediaPlayer(None, QMediaPlayer.LowLatency) self.recording_player = QMediaPlayer(None, QMediaPlayer.LowLatency) self.controls = ReplayWindowControls(self.v_player, self.recording_player, self.music_player) self.layout.addWidget(self.timer_label) self.layout.addWidget(self.video_w) self.layout.addWidget(self.controls) self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.layout) @staticmethod def format_millis(millis: int) -> str: if millis >= 0: minutes = int(millis / (60 * 1000)) seconds = int((millis % (60 * 1000)) / 1000) ms = millis % 1000 return f"{minutes:02}:{seconds:02}:{ms:03}" else: millis = -millis minutes = int(millis / (60 * 1000)) seconds = int((millis % (60 * 1000)) / 1000) ms = millis % 1000 return f"-{minutes:02}:{seconds:02}:{ms:03}" def update_time_label(self): if self.time_result is None: return position = self.v_player.position() if position > self.time_result: text = self.format_millis(self.time_result - self.offset_defined) else: text = self.format_millis(position - self.offset_defined) self.timer_label.setText(text) def make_label(self): timer_label = QLabel() timer_label.setText(self.format_millis(0)) timer_label.setAlignment(QtCore.Qt.AlignRight) timer_label.setStyleSheet(""" color: #CCCCCC; font-size:32px; padding: 16px; position: absolute; """) return timer_label def replay(self, file: str): self.music_player.stop() self.v_player.stop() self.recording_player.stop() v_path = QFileInfo(f"recordings/{file}2.avi").absoluteFilePath() a_path = QFileInfo(f"recordings/{file}.wav").absoluteFilePath() self.v_player.setMedia(QMediaContent(QUrl.fromLocalFile(v_path))) self.recording_player.setMedia( QMediaContent(QUrl.fromLocalFile(a_path))) self.music_player.play() time.sleep(recording_latency / 1000) # Latency guessed empirically self.v_player.play() self.recording_player.play() def end_replay(self): self.music_player.stop() self.v_player.stop() self.recording_player.stop() def video_ended(self): if self.v_player.state() == QMediaPlayer.StoppedState: self.music_player.stop() self.v_player.setPosition(self.v_player.duration() - 10) self.v_player.play() self.v_player.pause()
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.my_state = _STATE_PLAY # Controles principales para organizar la ventana. self.widget = QWidget(self) self.layout = QVBoxLayout() self.bottom_layout = QHBoxLayout() # Control de reproducción de video de Qt. self.video_widget = QVideoWidget(self) self.media_player = QMediaPlayer() self.media_player.setMedia( QMediaContent(QUrl.fromLocalFile(MY_PATH + VIDEO_PATH))) self.media_player.setVideoOutput(self.video_widget) # Botones de reproducción y pausa. self.play_button = QPushButton("Pausa", self) self.stop_button = QPushButton("Detener", self) # Deslizadores para el volumen y transición del video. self.seek_slider = QSlider(Qt.Horizontal) self.volume_slider = QSlider(Qt.Horizontal) self.volume_slider.setRange(0, 100) self.volume_slider.setValue(self.media_player.volume()) #self.volume_slider.sliderMoved.connect(self.media_player.setVolume) # actualizar la posicion #self.seek_slider.sliderMoved.connect(self.change_media_player) #self.media_player.durationChanged.connect(self.change_duration) # Acomodar controles en la pantalla. self.layout.addWidget(self.video_widget) self.layout.addLayout(self.bottom_layout) self.layout.addWidget(self.seek_slider) self.bottom_layout.addWidget(self.play_button) self.bottom_layout.addWidget(self.stop_button) self.bottom_layout.addWidget(self.volume_slider) # Conectar los eventos con sus correspondientes funciones. self.play_button.clicked.connect(self.play_clicked) #self.stop_button.clicked.connect(self.stop_clicked) self.media_player.stateChanged.connect(self.state_changed) # Personalizar la ventana. self.setWindowTitle("Reproductor de video") self.resize(800, 600) self.layout.setContentsMargins(0, 0, 0, 0) self.bottom_layout.setContentsMargins(0, 0, 0, 0) self.widget.setLayout(self.layout) self.setCentralWidget(self.widget) self.media_player.positionChanged.connect(self.pos_changed) # Reproducir el video. self.my_signal = mi_senal() self.my_signal.sig.connect(self.saySomeWords) self.timer = QTimer() self.timer.timeout.connect(self.tick) self.timer.start(500) self.parar = False self.media_player.setNotifyInterval(1000) self.media_player.play() def tick(self): #print ("este es mi timer") if self.parar == True: self.media_player.pause() self.timer.stop() # senales relacionadas a eventos @pyqtSlot(str) def saySomeWords(self, words): print(words) self.media_player.pause() def hand_my_signal(self): print("Esta es mi senal") def play_clicked(self): """ Comenzar o resumir la reproducción. """ self.my_signal.sig.emit("hola a todo mundo") #if (self.media_player.state() in # (QMediaPlayer.PausedState, QMediaPlayer.StoppedState)): # self.media_player.play() #else: # self.media_player.pause() def pos_changed(self, value): print("la posicion es:%d" % (value)) if value >= 4000: self.parar = True # self.media_player.positionChanged.disconnect(self.pos_changed) #self.media_player.pause() def state_changed(self, newstate): print("cambio de estado")
class WorkSpace(QMainWindow): def __init__(self): super().__init__() self.widget = QWidget(self) self.positionVideo = 0 self.createVideo() self.createPlayButton() self.createPositionSlider() self.createTimelineSlider() self.createLayout() def createVideo(self): self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.mediaPlayer.setNotifyInterval(10) self.videoWidget = QVideoWidget() self.mediaPlayer.setVideoOutput(self.videoWidget) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) def createPlayButton(self): self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) def createPositionSlider(self): self.positionSlider = QSlider(Qt.Horizontal, self.widget) self.positionSlider.sliderMoved.connect(self.setPosition) def createTimelineSlider(self): self.timelineSlider = QSlider(Qt.Horizontal, self.widget) self.timelineSlider.setTickInterval(100) self.timelineSlider.setTickPosition(QSlider.TicksBelow) self.timelineSlider.sliderMoved.connect(self.setPosition) def createLayout(self): self.timelineWidget = QGraphicsView() screenSize = QDesktopWidget().availableGeometry() self.timelineWidget.setFixedSize(screenSize.width() - 20, screenSize.height() // 8) historyBox = QVBoxLayout() text = QLabel('<font size=5> History </font>') self.undoView = QUndoView() historyBox.addWidget(text) historyBox.addWidget(self.undoView) history = QWidget() history.setLayout(historyBox) sliderBox = QHBoxLayout() sliderBox.addWidget(self.playButton) sliderBox.addWidget(self.positionSlider) videoBox = QVBoxLayout() videoBox.addWidget(self.videoWidget) videoBox.addLayout(sliderBox) video = QWidget() video.setLayout(videoBox) splitter = QSplitter(Qt.Horizontal) splitter.setStyleSheet("QSplitter::handle { background-color: #d3d3d3 }") splitter.addWidget(history) splitter.addWidget(video) vbox = QVBoxLayout() vbox.addWidget(splitter) vbox.addWidget(self.timelineSlider) vbox.addWidget(self.timelineWidget) self.widget.setLayout(vbox) def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPause)) else: self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) def positionChanged(self, position): self.positionVideo = position self.positionSlider.setValue(position) self.timelineSlider.setValue(position) def durationChanged(self, duration): self.durationVideo = duration self.positionSlider.setRange(0, duration) self.timelineSlider.setRange(0, duration) self.timelineLogic = TimelineLogic(duration) self.timelineWidget.setScene(self.timelineLogic.scene) self.undoView.setStack(self.timelineLogic.undoStack) def setPosition(self, position): self.mediaPlayer.setPosition(position)
class VideoWindow(QWidget): def __init__(self, vidPath): super().__init__() self.fullPath = vidPath self.startTime = 0 self.endTime = 0 self.init_ui() def init_ui(self): layout = QVBoxLayout() self.setLayout(layout) self.setWindowTitle(self.fullPath) self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.videoWidget = QVideoWidget() self.playButton = QPushButton() self.playButton.setEnabled(True) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.setFixedWidth(100) self.playButton.setFixedHeight(50) self.playButton.clicked.connect(self.play) self.trimButton = QPushButton("Trim") self.trimButton.setFixedWidth(150) self.trimButton.setFixedHeight(50) self.trimButton.clicked.connect(self.trimVid) self.positionSlider = QSlider(QtCore.Qt.Horizontal) self.positionSlider.setRange(0, 0) self.positionSlider.sliderMoved.connect(self.setPosition) self.rangeSlider = qrangeslider.QRangeSlider() self.rangeSlider.setRange(0, 0) self.rangeSlider.endValueChanged.connect(self.adjustForEnd) self.rangeSlider.startValueChanged.connect(self.adjustForStart) self.rangeSlider.setFixedHeight(15) self.startTimeInput = QTimeEdit() self.endTimeInput = QTimeEdit() self.startTimeInput.setDisplayFormat('hh:mm:ss.zzz') self.endTimeInput.setDisplayFormat('hh:mm:ss.zzz') self.startTimeInput.timeChanged.connect(self.startInputChanged) self.endTimeInput.timeChanged.connect(self.endInputChanged) self.mediaPlayer.setMedia( QMediaContent(QtCore.QUrl.fromLocalFile(self.fullPath))) layout.addWidget(self.videoWidget) self.mediaPlayer.setVideoOutput(self.videoWidget) self.mediaPlayer.setNotifyInterval(10) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) controlLayout = QVBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) controlLayout.addWidget(self.rangeSlider) controlLayout.addWidget(self.positionSlider) timeInputLayout = QHBoxLayout() timeInputLayout.addWidget(self.playButton) timeInputLayout.addWidget(self.startTimeInput) timeInputLayout.addWidget(self.endTimeInput) timeInputLayout.addWidget(self.trimButton) controlLayout.addLayout(timeInputLayout) layout.addLayout(controlLayout) self.mediaPlayer.play() self.resize(1024, 700) self.show() def closeEvent(self, event): self.mediaPlayer.stop() self.videoWidget.setParent(None) self.mediaPlayer.setParent(None) self.mediaPlayer.deleteLater() self.videoWidget.deleteLater() def trimVid(self): self.trimButton.setEnabled(False) outName = mytools.getAvailableName(self.fullPath, 'Trim') print(outName) trimStartTime = self.startTimeInput.time().toString('hh:mm:ss.zzz') trimEndTime = self.endTimeInput.time().toString('hh:mm:ss.zzz') try: ff = FFmpeg(inputs={self.fullPath: None}, outputs={ outName: [ '-ss', trimStartTime, '-to', trimEndTime, '-c:v', 'copy', '-c:a', 'copy', ] }) ff.run() except Exception as e: msg = QMessageBox() msg.setWindowTitle("Trim Failed") msg.setText(str(e)) msg.setIcon(QMessageBox.Critical) showMsg = msg.exec_() self.trimButton.setEnabled(True) def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) def positionChanged(self, position): self.positionSlider.setValue(position) if position > self.endTime: self.mediaPlayer.setPosition(self.startTime) def adjustForStart(self, startPos): self.startTime = startPos self.mediaPlayer.setPosition(startPos) self.startTimeInput.setTime(QtCore.QTime(0, 0).addMSecs(startPos)) self.endTimeInput.setMinimumTime(QtCore.QTime(0, 0).addMSecs(startPos)) def adjustForEnd(self, endPos): self.endTime = endPos if self.positionSlider.value() > endPos: self.mediaPlayer.setPosition(endPos) self.endTimeInput.setTime(QtCore.QTime(0, 0).addMSecs(endPos)) self.startTimeInput.setMaximumTime(QtCore.QTime(0, 0).addMSecs(endPos)) def startInputChanged(self, inputTime): self.rangeSlider.setStart(QtCore.QTime(0, 0, 0, 0).msecsTo(inputTime)) def endInputChanged(self, inputTime): self.rangeSlider.setEnd(QtCore.QTime(0, 0, 0, 0).msecsTo(inputTime)) def durationChanged(self, duration): self.positionSlider.setRange(0, duration) self.rangeSlider.setMax(duration) self.rangeSlider.setEnd(duration) self.startTimeInput.setMinimumTime(QtCore.QTime(0, 0)) self.endTimeInput.setMinimumTime(QtCore.QTime(0, 0)) self.endTimeInput.setTime(QtCore.QTime(0, 0).addMSecs(duration)) self.startTimeInput.setMaximumTime( QtCore.QTime(0, 0).addMSecs(duration)) self.endTimeInput.setMaximumTime(QtCore.QTime(0, 0).addMSecs(duration)) def setPosition(self, position): self.mediaPlayer.setPosition(position)
class SongList(QWidget): def __init__(self, parent=None): super(SongList, self).__init__(parent) os.chdir(os.path.dirname(os.path.abspath(__file__))) resourcesPath = os.getcwd() resourcesPath = os.path.join(resourcesPath, "resources") self.PLAY_ICON = QIcon(QPixmap(os.path.join(resourcesPath, "play.png"))) self.PAUSE_ICON = QIcon(QPixmap(os.path.join(resourcesPath, "pause.png"))) self.STOP_ICON = QIcon(QPixmap(os.path.join(resourcesPath, "stop.png"))) self.DELETE_ICON = QIcon(QPixmap(os.path.join(resourcesPath, "delete.png"))) self.setupMediaPlayer() self.setupUi() def setupMediaPlayer(self): self.mediaPlayer = QMediaPlayer() self.mediaPlayer.setNotifyInterval(1) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) def setupUi(self): self.setWindowTitle("List of songs") mainLayout = QHBoxLayout(self) verticalListLayout = QVBoxLayout() self.songsListWidget = QListWidget() self.songsListWidget.setContextMenuPolicy(Qt.CustomContextMenu) self.songsListWidget.customContextMenuRequested.connect(self.listWidgetRightClick) verticalListLayout.addWidget(self.songsListWidget) miniHorizontalLayout = QHBoxLayout() locatorLine = QLineEdit() locatorLine.setPlaceholderText("Locator") locatorBox = QComboBox() items = ["Title", "Status", "Description", "Style", "All"] locatorBox.addItems(items) locatorBox.setCurrentIndex(len(items)-1) miniHorizontalLayout.addWidget(locatorLine) miniHorizontalLayout.addWidget(locatorBox) locatorLine.textChanged.connect(lambda:self.populateList(locatorLine.text(), locatorBox.currentText())) verticalListLayout.addLayout(miniHorizontalLayout) self.mainForm = QGroupBox() self.mainForm.setTitle("Details") mainLayout.addLayout(verticalListLayout) mainLayout.addWidget(self.mainForm) self.populateList() self.mainFormSetupUi() #self.show() self.songsListWidget.currentRowChanged.connect(self.changePage) def mainFormSetupUi(self): """title, status style, duration, descriptin, location, project, variation_another_song, timestamp""" mainLayout = QVBoxLayout(self.mainForm) #Horizontal Layout 1 horizontalLayout1 = QHBoxLayout() titleLabel = QLabel("Song name:") self.titleEdit = QLineEdit() self.titleEdit.editingFinished.connect(self.checkSong) self.titleEdit.textChanged.connect(self.validateSong) horizontalLayout1.addWidget(titleLabel) horizontalLayout1.addWidget(self.titleEdit) #Horizontal Layout 2 horizontalLayout2 = QHBoxLayout() statusLabel = QLabel("Status:") self.statusBox = QComboBox() dateLabel = QLabel("Date:") self.dateEdit = QDateTimeEdit() self.dateEdit.setCalendarPopup(True) horizontalLayout2.addWidget(statusLabel) horizontalLayout2.addWidget(self.statusBox) horizontalLayout2.addStretch(1) horizontalLayout2.addWidget(dateLabel) horizontalLayout2.addWidget(self.dateEdit) #Style Groupbox, widgets added automatically self.styleGroupBox = QGroupBox() self.styleGroupBox.setTitle("Style:") self.styleLayout = QGridLayout(self.styleGroupBox) horizontalLayout3 = QHBoxLayout() durationLabel = QLabel("Duration:") self.durationLine = QTimeEdit() self.durationLine.setDisplayFormat("mm:ss") projectLabel = QLabel("Project") self.projectComboBox = QComboBox() self.projectComboBox.setEditable(True) horizontalLayout3.addWidget(durationLabel) horizontalLayout3.addWidget(self.durationLine) horizontalLayout3.addWidget(projectLabel) horizontalLayout3.addWidget(self.projectComboBox) horizontalLayout4 = QHBoxLayout() descriptionLabel = QLabel("Description:") variationLabel = QLabel("Variation from another song: ") self.variationLine = QLineEdit() horizontalLayout4.addWidget(descriptionLabel) horizontalLayout4.addStretch(1) horizontalLayout4.addWidget(variationLabel) horizontalLayout4.addWidget(self.variationLine) self.descriptionTextEdit = QTextEdit() horizontalLayout5 = QHBoxLayout() locationLabel = QLabel("Location:") self.locationLine = QLineEdit() self.locationButton = QPushButton("...") self.locationButton.clicked.connect(self.locateFile) horizontalLayout5.addWidget(locationLabel) horizontalLayout5.addWidget(self.locationLine) horizontalLayout5.addWidget(self.locationButton) horizontalLayout6 = QHBoxLayout() self.slider = QSlider(Qt.Horizontal) self.slider.sliderReleased.connect(self.playSlider) self.slider.setStyleSheet("QSlider::handle:horizontal { border: 1px solid #777; background:#b55858;}") horizontalLayout6.addWidget(self.slider) horizontalLayout7 = QHBoxLayout() self.playButton = QPushButton() self.stopButton = QPushButton() self.playButton.setIcon(self.PLAY_ICON) self.stopButton.setIcon(self.STOP_ICON) self.playButton.clicked.connect(self.playSong) self.stopButton.clicked.connect(self.stopSong) horizontalLayout7.addStretch(1) horizontalLayout7.addWidget(self.playButton) horizontalLayout7.addWidget(self.stopButton) horizontalLayout7.addStretch(1) horizontalLayout8 = QHBoxLayout() self.saveButton = QPushButton() self.saveButton.setText("Save") self.saveButton.clicked.connect(self.saveSong) horizontalLayout8.addStretch(1) horizontalLayout8.addWidget(self.saveButton) mainLayout.addLayout(horizontalLayout1) mainLayout.addLayout(horizontalLayout2) mainLayout.addWidget(self.styleGroupBox) mainLayout.addLayout(horizontalLayout3) mainLayout.addLayout(horizontalLayout4) mainLayout.addWidget(self.descriptionTextEdit) mainLayout.addLayout(horizontalLayout5) mainLayout.addLayout(horizontalLayout6) mainLayout.addLayout(horizontalLayout7) mainLayout.addLayout(horizontalLayout8) def clearForm(self): self.titleEdit.clear() self.statusBox.clear() for widget in self.styleGroupBox.children(): if not isinstance(widget, QGridLayout): widget.deleteLater() self.durationLine.clear() self.projectComboBox.clear() self.variationLine.clear() self.descriptionTextEdit.clear() self.locationLine.clear() def changePage(self, index): title = self.songsListWidget.item(index).data(Qt.UserRole) self.clearForm() self.populateForm(title) self.slider.setValue(0) def populateForm(self, title): #title is the primary key listArray = queries("""SELECT title, status, style, duration, description, location, project, variation_another_song, timestamp from songs WHERE title = ?""", (title,)) print(listArray) if len(listArray) != 0: title = listArray[0][0] status = listArray[0][1] styles = [] styleArray = listArray[0][2] if styleArray != None: if "," in styleArray: styles = styleArray.split(",") else: styles.append(styleArray) duration = listArray[0][3] description = listArray[0][4] location = listArray[0][5] project = listArray[0][6] variation_another_song = listArray[0][7] timestamp = listArray[0][8] else: title = None status = None styles = None duration = None description = None location = None project = None variation_another_song = None timestamp = None if title != None: self.titleEdit.setText(title) self.statusBox.addItems(["Select...", "Demo", "WIP", "Idea", "Unfinished song", "EQ", "Master", "Finished"]) if status != None: self.statusBox.setCurrentText(status) if timestamp != None: self.dateEdit.setDateTime(datetime.strptime(timestamp, '%d/%m/%Y %H:%M')) else: self.dateEdit.setDateTime(datetime.now())#default styleArray = queries("select style from songs where style is not null") """ print(styleArray) if styleArray != None: styleArray = styleArray[0][0] if "," in styleArray: styles = styleArray.split(",") else: styles.append(styleArray)""" stylesArray = [] query = queries("select style from songs where style is not null") if len(query) != 0: for style in query: stylesMiniArray = style[0].split(",") stylesMiniArray = list(filter(None, stylesMiniArray)) for item in stylesMiniArray: if item not in stylesArray: if item != '': stylesArray.append(item) self.x = 0 self.y = 0 if len(stylesArray) != 0: for style in stylesArray: print("style", style) checkBox = QCheckBox(style) self.styleLayout.addWidget(checkBox, self.x, self.y) self.checkBoxPositionAsignment() self.addStyle() if styles!= None: if len(styles) != 0: for style in styles: for checkbox in self.styleGroupBox.children(): if isinstance(checkbox, QCheckBox): if checkbox.text() == style: checkbox.setChecked(True) if duration != None: time = QTime(0,0,0) self.durationLine.setTime(time.addSecs(duration)) projectsArray = ["Select..."] projectsArrayQuery = queries("SELECT project from songs") if len(projectsArrayQuery) != 0: for project in projectsArrayQuery[0]: if project not in projectsArray: projectsArray.append(project) if project != None: self.projectComboBox.setCurrentText(project) if variation_another_song != None: self.variationLine.setText(variation_another_song) if description != None: self.descriptionTextEdit.setText(description) available = False if location != None: self.locationLine.setText(location) if len(self.locationLine.text()) != 0: try: self.playlist = QMediaPlaylist() self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(location))) self.mediaPlayer.setPlaylist(self.playlist) except: pass available = True#I know this is stupid but just in case self.slider.setVisible(available) self.playButton.setVisible(available) self.stopButton.setVisible(available) def populateList(self, locatorItem=None, locatorColumn=None): print(locatorItem, locatorColumn) self.songsListWidget.blockSignals(True) self.songsListWidget.clear() if locatorItem == None or locatorItem == "": listArray = queries("""SELECT title, status, timestamp from songs """) print(listArray) else: if locatorColumn != "All": #No strings concatenation, no security holes if locatorColumn == "Title": sql = """SELECT title, status, timestamp from songs where title LIKE ?""" elif locatorColumn == "Status": sql = """SELECT title, status, timestamp from songs where status LIKE ?""" elif locatorColumn == "Description": sql = """SELECT title, status, timestamp from songs where description LIKE ?""" elif locatorColumn == "Style": sql = """SELECT title, status, timestamp from songs where style LIKE ?""" locatorItem = "%" + locatorItem + "%" listArray = queries(sql, (locatorItem,)) else: locatorItem = "%" + locatorItem + "%" variables = [locatorItem, locatorItem, locatorItem, locatorItem, locatorItem] listArray = queries("""SELECT title, status, timestamp from songs where title LIKE ? OR type LIKE ? OR original_song LIKE ? OR link LIKE ? OR description LIKE ?""", variables) for item in listArray: title = item[0] status = item[1] timestamp = item[2] try: timestamp = datetime.strptime(timestamp, "%d/%m/%Y %H:%M") timestamp = timestamp.strftime("%d/%m/%Y") except: timestamp = "" text = "%s %s %s" % (title, status, timestamp) qItem = QListWidgetItem(text) qItem.setData(Qt.UserRole, title) self.songsListWidget.addItem(qItem) #new idea qItem = QListWidgetItem("New song...") qItem.setData(Qt.UserRole, "New song...") #otherwise that would be an error self.songsListWidget.addItem(qItem) self.songsListWidget.blockSignals(False) def listWidgetRightClick(self, position): widgetItem = self.songsListWidget.itemAt(position) if widgetItem != None: #quick lazy text fix if widgetItem.text() != "New song...": print(widgetItem.text()) menu = QMenu() deleteAction = QAction(self.DELETE_ICON, "Delete song") menu.addAction(deleteAction) action = menu.exec(self.mapToGlobal(position)) if action == deleteAction: msg = QMessageBox.question(None, "Delete?", "Are you sure you want to delete this entry?") if msg == QMessageBox.Yes: title = widgetItem.data(Qt.UserRole) queries("DELETE from songs where title = ?", (title,)) self.populateList() self.songsListWidget.setCurrentRow(0) def songVariations(self): sql = "SELECT title from songs" songArray = [] for song in queries(sql)[0]: songArray.append(song) return songArray def checkBoxPositionAsignment(self): self.y += 1 if self.y == 4: self.y = 0 self.x += 1 def addStyle(self, text=""): "text = "" if comes from outside" self.styleEdit = QLineEdit() self.styleEdit.setPlaceholderText("Style") self.styleEdit.textChanged.connect(self.validateStyle) self.styleEdit.returnPressed.connect(lambda: self.addStyle(self.styleEdit.text())) if text != "": self.styleLayout.takeAt(self.styleLayout.count()-1).widget().deleteLater() styleCheckBox = QCheckBox() styleCheckBox.setText(text) print(text) self.styleLayout.addWidget(styleCheckBox, self.x, self.y) self.checkBoxPositionAsignment() print(self.durationLine.text()) self.styleLayout.addWidget(self.styleEdit) def checkSong(self): text = self.titleEdit.text() sql = "SELECT title from songs where title = ?" if len(queries(sql, (text,))) != 0: self.titleEdit.setText("") def validateSong(self): pass #VALIDATE REG EXP def validateStyle(self, text): if "," in text: self.styleEdit.undo() def playSong(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon(self.PAUSE_ICON) else: self.playButton.setIcon(self.PLAY_ICON) def positionChanged(self, position): if position != self.mediaPlayer.duration(): self.slider.setValue(position) def durationChanged(self, duration): if duration != self.mediaPlayer.position(): print("duration chagned") self.slider.setRange(0, duration) def playSlider(self): self.mediaPlayer.setPosition(self.slider.value()) def stopSong(self): self.mediaPlayer.stop() def locateFile(self): self.fileSystem = QFileDialog(filter="Sound files (*.wav *.mp3 *.flac)") self.fileSystem.show() self.fileSystem.fileSelected.connect(self.fileLoaded) def fileLoaded(self, path): self.locationLine.setText(path) try: self.playlist = QMediaPlaylist() self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(path))) self.mediaPlayer.setPlaylist(self.playlist) except: print("fail") self.slider.setVisible(True) self.playButton.setVisible(True) self.stopButton.setVisible(True) def saveSong(self): title = self.titleEdit.text() status = self.statusBox.currentText() date = self.dateEdit.text() style = "" print(status, style) x = 0 for checkBox in self.styleGroupBox.children(): if isinstance(checkBox, QCheckBox): if checkBox.isChecked(): style += (checkBox.text()) + "," x+=1 if x != 0: style = style.rstrip(",") else: style = None duration = self.durationLine.time() duration = QTime(0, 0).secsTo(duration) project = self.projectComboBox.currentText() variation = self.variationLine.text() description = self.descriptionTextEdit.toPlainText() location = self.locationLine.text() variables = [title, status, description, location, project,\ variation, date, style, duration] print("---------", variables) sql = """INSERT OR REPLACE into songs (title, status, description, location, project, variation_another_song, timestamp, style, duration) values (?, ?, ?, ?, ?, ?, ?, ?, ?)""" queries(sql, variables) self.populateList()
class QgsFmvPlayer(QMainWindow, Ui_PlayerWindow): """ Video Player Class """ def __init__(self, iface, path=None, parent=None): """ Constructor """ super(QgsFmvPlayer, self).__init__(parent) self.setupUi(self) self.parent = parent self.iface = iface self.fileName = None self.metadataDlg = None self.createingMosaic = False self.currentInfo = 0.0 self.RecGIF = QMovie(":/imgFMV/images/record.gif") self.videoWidget.customContextMenuRequested[QPoint].connect( self.contextMenuRequested) self.duration = 0 self.playerMuted = False self.HasFileAudio = False self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.player.setNotifyInterval(1000) # One second self.pass_time = 0.1 self.playlist = QMediaPlaylist() # self.player.setVideoOutput( # self.videoWidget) # Standar Surface self.player.setVideoOutput( self.videoWidget.videoSurface()) # Custom Surface self.player.durationChanged.connect(self.durationChanged) self.player.positionChanged.connect(self.positionChanged) self.player.mediaStatusChanged.connect(self.statusChanged) self.player.stateChanged.connect(self.setCurrentState) self.playerState = QMediaPlayer.StoppedState self.playFile(path) self.sliderDuration.setRange(0, self.player.duration() / 1000) self.volumeSlider.setValue(self.player.volume()) self.volumeSlider.enterEvent = self.showVolumeTip if self.metadataDlg is None: self.metadataDlg = QgsFmvMetadata(parent=self, player=self) self.addDockWidget(Qt.RightDockWidgetArea, self.metadataDlg) self.metadataDlg.setMinimumWidth(500) self.metadataDlg.hide() def HasMetadata(self, videoPath): """ Check if video have Metadata or not """ try: p = _spawn([ '-i', videoPath, '-map', 'data-re', '-codec', 'copy', '-f', 'data', '-' ]) stdout_data, _ = p.communicate() if stdout_data == b'': qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", "This video don't have Metadata ! : "), level=QGis.Info) return False return True except Exception as e: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", "Metadata Callback Failed! : "), str(e), level=QGis.Info) def HasAudio(self, videoPath): """ Check if video have Metadata or not """ try: p = _spawn([ '-i', videoPath, '-show_streams', '-select_streams', 'a', '-loglevel', 'error' ], type="ffprobe") stdout_data, _ = p.communicate() if stdout_data == b'': qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", "This video don't have Audio ! : "), level=QGis.Info) return False return True except Exception as e: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", "Audio check Failed! : "), str(e), level=QGis.Info) def callBackMetadata(self, currentTime, nextTime): """ Metadata CallBack """ try: # TODO : Speed this function # stdout_data = _check_output(['-i', self.fileName, # '-ss', currentTime, # '-to', nextTime, # '-f', 'data', '-']) t = callBackMetadataThread(cmds=[ '-i', self.fileName, '-ss', currentTime, '-to', nextTime, '-map', 'data-re', '-f', 'data', '-' ]) t.start() t.join(1) if t.is_alive(): t.p.terminate() t.join() if t.stdout == b'': return for packet in StreamParser(t.stdout): try: self.addMetadata(packet.MetadataList()) UpdateLayers(packet, parent=self, mosaic=self.createingMosaic) self.iface.mapCanvas().refresh() QApplication.processEvents() return except Exception as e: None except Exception as e: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", "Metadata Callback Failed! : "), str(e), level=QGis.Info) def addMetadata(self, packet): ''' Add Metadata to List ''' self.clearMetadata() row = 0 for key in sorted(packet.keys()): self.metadataDlg.VManager.insertRow(row) self.metadataDlg.VManager.setItem(row, 0, QTableWidgetItem(str(key))) self.metadataDlg.VManager.setItem( row, 1, QTableWidgetItem(str(packet[key][0]))) self.metadataDlg.VManager.setItem( row, 2, QTableWidgetItem(str(packet[key][1]))) row += 1 self.metadataDlg.VManager.setVisible(False) self.metadataDlg.VManager.resizeColumnsToContents() self.metadataDlg.VManager.setVisible(True) self.metadataDlg.VManager.verticalScrollBar().setSliderPosition( self.sliderPosition) def clearMetadata(self): ''' Clear Metadata List ''' try: self.sliderPosition = self.metadataDlg.VManager.verticalScrollBar( ).sliderPosition() self.metadataDlg.VManager.setRowCount(0) except: None def saveInfoToJson(self): """ Save video Info to json """ if not self.KillAllProcessors(): return out_json, _ = QFileDialog.getSaveFileName(self, "Save File", "", "Json Files (*.json)") if out_json == "": return try: self.VPProbeToJson = Converter() self.VPTProbeToJson = QThread() self.VPProbeToJson.moveToThread(self.VPTProbeToJson) self.VPProbeToJson.finished.connect(self.QThreadFinished) self.VPProbeToJson.error.connect(self.QThreadError) self.VPProbeToJson.progress.connect( self.progressBarProcessor.setValue) self.VPTProbeToJson.start(QThread.LowPriority) QMetaObject.invokeMethod(self.VPProbeToJson, 'probeToJson', Qt.QueuedConnection, Q_ARG(str, self.fileName), Q_ARG(str, out_json)) except Exception as e: qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Error saving Json")) self.QThreadFinished("probeToJson", "Closing ProbeToJson") def showVideoInfo(self): ''' Show default probe info ''' try: self.VPProbe = Converter() self.VPTProbe = QThread() self.VPProbe.moveToThread(self.VPTProbe) self.VPProbe.finishedJson.connect(self.QThreadFinished) self.VPProbe.error.connect(self.QThreadError) self.VPProbe.progress.connect(self.progressBarProcessor.setValue) self.VPTProbe.start(QThread.LowPriority) QMetaObject.invokeMethod(self.VPProbe, 'probeShow', Qt.QueuedConnection, Q_ARG(str, self.fileName)) except Exception as e: qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Error Info Show")) self.QThreadFinished("probeShow", "Closing Probe") return def state(self): ''' Return Current State ''' return self.playerState def setCurrentState(self, state): ''' Set Current State ''' if state != self.playerState: self.playerState = state if state == QMediaPlayer.StoppedState: self.btn_play.setIcon(QIcon(":/imgFMV/images/play-arrow.png")) return def showColorDialog(self): ''' Show Color dialog ''' self.ColorDialog = ColorDialog(parent=self) self.ColorDialog.setWindowFlags(Qt.Window | Qt.WindowCloseButtonHint) # Fail if not uncheked self.actionMagnifying_glass.setChecked(False) self.actionZoom_Rectangle.setChecked(False) self.ColorDialog.exec_() return def createMosaic(self, value): ''' Function for create Video Mosaic ''' home = os.path.expanduser("~") qgsu.createFolderByName(home, "QGIS_FMV") homefmv = os.path.join(home, "QGIS_FMV") root, ext = os.path.splitext(os.path.basename(self.fileName)) qgsu.createFolderByName(homefmv, root) self.createingMosaic = value # Create Group CreateGroupByName() return def contextMenuRequested(self, point): ''' Context Menu Video ''' menu = QMenu() # actionColors = menu.addAction( # QCoreApplication.translate("QgsFmvPlayer", "Color Options")) # actionColors.setShortcut("Ctrl+May+C") # actionColors.triggered.connect(self.showColorDialog) actionMute = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Mute/Unmute")) actionMute.setShortcut("Ctrl+May+U") actionMute.triggered.connect(self.setMuted) menu.addSeparator() actionAllFrames = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Extract All Frames")) actionAllFrames.setShortcut("Ctrl+May+A") actionAllFrames.triggered.connect(self.ExtractAllFrames) actionCurrentFrames = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Extract Current Frame")) actionCurrentFrames.setShortcut("Ctrl+May+Q") actionCurrentFrames.triggered.connect(self.ExtractCurrentFrame) menu.addSeparator() actionShowMetadata = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Show Metadata")) actionShowMetadata.setShortcut("Ctrl+May+M") actionShowMetadata.triggered.connect(self.OpenQgsFmvMetadata) menu.exec_(self.mapToGlobal(point)) # Start Snnipet FILTERS def grayFilter(self, value): self.UncheckFilters(self.sender(), value) self.videoWidget.SetGray(value) self.videoWidget.UpdateSurface() return def edgeFilter(self, value): self.UncheckFilters(self.sender(), value) self.videoWidget.SetEdgeDetection(value) self.videoWidget.UpdateSurface() return def invertColorFilter(self, value): self.UncheckFilters(self.sender(), value) self.videoWidget.SetInvertColor(value) self.videoWidget.UpdateSurface() return def autoContrastFilter(self, value): self.UncheckFilters(self.sender(), value) self.videoWidget.SetAutoContrastFilter(value) self.videoWidget.UpdateSurface() return def monoFilter(self, value): self.UncheckFilters(self.sender(), value) self.videoWidget.SetMonoFilter(value) self.videoWidget.UpdateSurface() return def magnifier(self, value): self.UncheckUtils(self.sender(), value) self.videoWidget.SetMagnifier(value) self.videoWidget.UpdateSurface() return def zoomRect(self, value): self.UncheckUtils(self.sender(), value) self.videoWidget.SetZoomRect(value) self.videoWidget.UpdateSurface() return def UncheckUtils(self, sender, value): # p = self.player.position() # self.player.setVideoOutput( # self.videoWidget.videoSurface()) # Custom surface # self.player.setPosition(p) QApplication.processEvents() name = sender.objectName() self.actionMagnifying_glass.setChecked( True if name == "actionMagnifying_glass" else False) self.actionZoom_Rectangle.setChecked(True if name == "actionZoom_Rectangle" else False) sender.setChecked(value) return def UncheckFilters(self, sender, value): # p = self.player.position() # self.player.setVideoOutput( # self.videoWidget.videoSurface()) # Custom surface # self.player.setPosition(p) # QApplication.processEvents() name = sender.objectName() self.actionGray.setChecked(True if name == "actionGray" else False) self.actionInvert_Color.setChecked(True if name == "actionInvert_Color" else False) self.actionMono_Filter.setChecked(True if name == "actionMono_Filter" else False) self.actionCanny_edge_detection.setChecked( True if name == "actionCanny_edge_detection" else False) self.actionAuto_Contrast_Filter.setChecked( True if name == "actionAuto_Contrast_Filter" else False) self.videoWidget.SetGray(True if name == "actionGray" else False) self.videoWidget.SetEdgeDetection( True if name == "actionCanny_edge_detection" else False) self.videoWidget.SetInvertColor(True if name == "actionInvert_Color" else False) self.videoWidget.SetMonoFilter(True if name == "actionMono_Filter" else False) self.videoWidget.SetAutoContrastFilter( True if name == "actionAuto_Contrast_Filter" else False) sender.setChecked(value) return # End Snnipet FILTERS def isMuted(self): ''' Is muted video property''' return self.playerMuted def setMuted(self): ''' Muted video ''' if self.player.isMuted(): self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_up.png")) self.player.setMuted(False) self.volumeSlider.setEnabled(True) else: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_off.png")) self.player.setMuted(True) self.volumeSlider.setEnabled(False) return def stop(self): ''' Stop video''' self.player.stop() self.videoWidget.update() return def volume(self): ''' Volume Slider ''' return self.volumeSlider.value() def setVolume(self, volume): ''' Tooltip and set value''' self.player.setVolume(volume) self.showVolumeTip(volume) if 0 < volume <= 30: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_30.png")) elif 30 < volume <= 60: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_60.png")) elif 60 < volume <= 100: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_up.png")) elif volume == 0: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_off.png")) def EndMedia(self): ''' Button end video position ''' if self.player.isVideoAvailable(): self.player.setPosition(self.player.duration()) self.videoWidget.update() return def StartMedia(self): ''' Button start video position ''' if self.player.isVideoAvailable(): self.player.setPosition(0) self.videoWidget.update() return def forwardMedia(self): ''' Button forward Video ''' forwardTime = int(self.player.position()) + 10 * 1000 if forwardTime > int(self.player.duration()): forwardTime = int(self.player.duration()) self.player.setPosition(forwardTime) def rewindMedia(self): ''' Button rewind Video ''' rewindTime = int(self.player.position()) - 10 * 1000 if rewindTime < 0: rewindTime = 0 self.player.setPosition(rewindTime) def AutoRepeat(self, checked): ''' Button AutoRepeat Video ''' if checked: self.playlist.setPlaybackMode(QMediaPlaylist.Loop) else: self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) return def showVolumeTip(self, _): ''' Volume Slider Tooltip Trick ''' self.style = self.volumeSlider.style() self.opt = QStyleOptionSlider() self.volumeSlider.initStyleOption(self.opt) rectHandle = self.style.subControlRect(self.style.CC_Slider, self.opt, self.style.SC_SliderHandle) self.tip_offset = QPoint(5, 15) pos_local = rectHandle.topLeft() + self.tip_offset pos_global = self.volumeSlider.mapToGlobal(pos_local) QToolTip.showText(pos_global, str(self.volumeSlider.value()) + " %", self) def showMoveTip(self, currentInfo): ''' Player Silder Move Tooptip Trick ''' self.style = self.sliderDuration.style() self.opt = QStyleOptionSlider() self.sliderDuration.initStyleOption(self.opt) rectHandle = self.style.subControlRect(self.style.CC_Slider, self.opt, self.style.SC_SliderHandle) self.tip_offset = QPoint(5, 15) pos_local = rectHandle.topLeft() + self.tip_offset pos_global = self.sliderDuration.mapToGlobal(pos_local) tStr = _seconds_to_time(currentInfo) QToolTip.showText(pos_global, tStr, self) def durationChanged(self, duration): ''' Duration video change signal ''' duration /= 1000 self.duration = duration self.sliderDuration.setMaximum(duration) def positionChanged(self, progress): ''' Current Video position change ''' progress /= 1000 if not self.sliderDuration.isSliderDown(): self.sliderDuration.setValue(progress) self.updateDurationInfo(progress) def updateDurationInfo(self, currentInfo): ''' Update labels duration Info and CallBack Metadata ''' duration = self.duration self.currentInfo = currentInfo if currentInfo or duration: totalTime = _seconds_to_time(duration) currentTime = _seconds_to_time(currentInfo) tStr = currentTime + " / " + totalTime nextTime = currentInfo + self.pass_time currentTimeInfo = _seconds_to_time_frac(currentInfo) nextTimeInfo = _seconds_to_time_frac(nextTime) # Metadata CallBack self.callBackMetadata(currentTimeInfo, nextTimeInfo) else: tStr = "" self.labelDuration.setText(tStr) def handleCursor(self, status): ''' Change cursor ''' if status in (QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia, QMediaPlayer.StalledMedia): self.setCursor(Qt.BusyCursor) else: self.unsetCursor() def statusChanged(self, status): ''' Signal Status video change ''' self.handleCursor(status) if status == QMediaPlayer.LoadingMedia: self.videoAvailableChanged(False) elif status == QMediaPlayer.StalledMedia: self.videoAvailableChanged(False) if status == QMediaPlayer.EndOfMedia: self.videoAvailableChanged(True) elif status == QMediaPlayer.InvalidMedia: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", self.player.errorString()), level=QGis.Warning) self.videoAvailableChanged(False) else: self.videoAvailableChanged(True) def playFile(self, videoPath): ''' Play file from path ''' try: RemoveVideoLayers() RemoveGroupByName() self.fileName = videoPath self.playlist = QMediaPlaylist() url = QUrl.fromLocalFile(videoPath) self.playlist.addMedia(QMediaContent(url)) self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) self.player.setPlaylist(self.playlist) self.setWindowTitle("Playing : " + os.path.basename(os.path.normpath(videoPath))) if self.HasMetadata(videoPath): CreateVideoLayers() self.clearMetadata() self.lb_cursor_coord.setText( "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>" + "<span style='font-size:9pt; font-weight:normal;'>Null</span>" + "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>" + "<span style='font-size:9pt; font-weight:normal;'>Null</span>" ) else: self.btn_GeoReferencing.setEnabled(False) self.HasFileAudio = True if not self.HasAudio(videoPath): self.actionAudio.setEnabled(False) self.actionSave_Audio.setEnabled(False) self.HasFileAudio = False self.playClicked(True) except Exception as e: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", 'Open Video File : '), str(e), level=QGis.Warning) def ReciconUpdate(self, frame): self.btn_Rec.setIcon(QIcon(self.RecGIF.currentPixmap())) def RecordVideo(self, value): ''' Cut Video ''' currentTime = _seconds_to_time(self.currentInfo) if value is False: self.endRecord = currentTime _, file_extension = os.path.splitext(self.fileName) out, _ = QFileDialog.getSaveFileName(self, "Save As", "", file_extension) if not out: self.RecGIF.frameChanged.disconnect(self.ReciconUpdate) self.RecGIF.stop() self.btn_Rec.setIcon(QIcon(":/imgFMV/images/record.png")) return False lfn = out.lower() if not lfn.endswith((file_extension)): out += file_extension p = _spawn([ '-i', self.fileName, '-ss', self.startRecord, '-to', self.endRecord, '-c', 'copy', out ]) p.communicate() qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Save file succesfully!")) self.RecGIF.frameChanged.disconnect(self.ReciconUpdate) self.RecGIF.stop() self.btn_Rec.setIcon(QIcon(":/imgFMV/images/record.png")) else: self.startRecord = currentTime self.RecGIF.frameChanged.connect(self.ReciconUpdate) self.RecGIF.start() return def videoAvailableChanged(self, available): ''' Buttons for video available ''' # self.btn_Color.setEnabled(available) self.btn_CaptureFrame.setEnabled(available) self.gb_PlayerControls.setEnabled(available) return def toggleGroup(self, state): ''' Toggle GroupBox ''' sender = self.sender() if state: sender.setFixedHeight(sender.sizeHint().height()) else: sender.setFixedHeight(15) def playClicked(self, state): ''' Stop and Play video ''' if self.playerState in (QMediaPlayer.StoppedState, QMediaPlayer.PausedState): self.btn_play.setIcon(QIcon(":/imgFMV/images/pause.png")) self.player.play() elif self.playerState == QMediaPlayer.PlayingState: self.btn_play.setIcon(QIcon(":/imgFMV/images/play-arrow.png")) self.player.pause() def seek(self, seconds): '''Slider Move''' self.player.setPosition(seconds * 1000) self.showMoveTip(seconds) def convertVideo(self): '''Convert Video To Other Format ''' if not self.KillAllProcessors(): return sel = "mp4 Files (*.mp4)" out, _ = QFileDialog.getSaveFileName( self, "Save Video as...", None, "ogg files (*.ogg);;avi Files (*.avi);;mkv Files (*.mkv);;webm Files (*.webm);;flv Files (*.flv);;mov Files (*.mov);;mp4 Files (*.mp4);;mpg Files (*.mpg);;mp3 Files (*.mp3)", sel) if not out: return False lfn = out.lower() if not lfn.endswith(('.ogg', '.avi', '.mkv', '.webm', '.flv', '.mov', '.mp4', '.mp3', '.mpg')): # The default. out += '.mp4' try: self.VPConverter = Converter() self.VPTConverter = QThread() self.VPConverter.moveToThread(self.VPTConverter) self.VPConverter.finished.connect(self.QThreadFinished) self.VPConverter.error.connect(self.QThreadError) self.VPConverter.progress.connect( self.progressBarProcessor.setValue) self.VPTConverter.start(QThread.LowPriority) # TODO : Make Correct format Conversion and embebed metadata info = self.VPConverter.probeInfo(self.fileName) if info is not None: if self.HasFileAudio: audio_codec = info.audio.codec audio_samplerate = info.audio.audio_samplerate audio_channels = info.audio.audio_channels video_codec = info.video.codec video_width = info.video.video_width video_height = info.video.video_height video_fps = info.video.video_fps _, out_ext = os.path.splitext(out) if self.HasFileAudio: options = { 'format': out_ext[1:], 'audio': { 'codec': audio_codec, 'samplerate': audio_samplerate, 'channels': audio_channels }, 'video': { 'codec': video_codec, 'width': video_width, 'height': video_height, 'fps': video_fps } } else: options = { 'format': out_ext[1:], 'video': { 'codec': video_codec, 'width': video_width, 'height': video_height, 'fps': video_fps } } QMetaObject.invokeMethod(self.VPConverter, 'convert', Qt.QueuedConnection, Q_ARG(str, self.fileName), Q_ARG(str, out), Q_ARG(dict, options), Q_ARG(bool, False)) except Exception as e: qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Error converting video ")) self.QThreadFinished("convert", "Closing convert") def ShowPlot(self, bitrate_data, frame_count, output=None): ''' Show plot,because show not work using threading ''' matplot.figure().canvas.set_window_title(self.fileName) matplot.title("Stream Bitrate vs Time") matplot.xlabel("Time (sec)") matplot.ylabel("Frame Bitrate (kbit/s)") matplot.grid(True) # map frame type to color frame_type_color = { # audio 'A': 'yellow', # video 'I': 'red', 'P': 'green', 'B': 'blue' } global_peak_bitrate = 0.0 global_mean_bitrate = 0.0 # render charts in order of expected decreasing size for frame_type in ['I', 'P', 'B', 'A']: # skip frame type if missing if frame_type not in bitrate_data: continue # convert list of tuples to numpy 2d array frame_list = bitrate_data[frame_type] frame_array = numpy.array(frame_list) # update global peak bitrate peak_bitrate = frame_array.max(0)[1] if peak_bitrate > global_peak_bitrate: global_peak_bitrate = peak_bitrate # update global mean bitrate (using piecewise mean) mean_bitrate = frame_array.mean(0)[1] global_mean_bitrate += mean_bitrate * \ (len(frame_list) / frame_count) # plot chart using gnuplot-like impulses matplot.vlines(frame_array[:, 0], [0], frame_array[:, 1], color=frame_type_color[frame_type], label="{} Frames".format(frame_type)) self.progressBarProcessor.setValue(90) # calculate peak line position (left 15%, above line) peak_text_x = matplot.xlim()[1] * 0.15 peak_text_y = global_peak_bitrate + \ ((matplot.ylim()[1] - matplot.ylim()[0]) * 0.015) peak_text = "peak ({:.0f})".format(global_peak_bitrate) # draw peak as think black line w/ text matplot.axhline(global_peak_bitrate, linewidth=2, color='black') matplot.text(peak_text_x, peak_text_y, peak_text, horizontalalignment='center', fontweight='bold', color='black') # calculate mean line position (right 85%, above line) mean_text_x = matplot.xlim()[1] * 0.85 mean_text_y = global_mean_bitrate + \ ((matplot.ylim()[1] - matplot.ylim()[0]) * 0.015) mean_text = "mean ({:.0f})".format(global_mean_bitrate) # draw mean as think black line w/ text matplot.axhline(global_mean_bitrate, linewidth=2, color='black') matplot.text(mean_text_x, mean_text_y, mean_text, horizontalalignment='center', fontweight='bold', color='black') matplot.legend() if output != "": matplot.savefig(output) else: matplot.show() self.progressBarProcessor.setValue(100) def CreateBitratePlot(self): ''' Create video Plot Bitrate Thread ''' if not self.KillAllProcessors(): return try: self.VPBitratePlot = CreatePlotsBitrate() self.VPTBitratePlot = QThread() self.VPBitratePlot.moveToThread(self.VPTBitratePlot) self.VPBitratePlot.finished.connect(self.QThreadFinished) self.VPBitratePlot.return_fig.connect(self.ShowPlot) self.VPBitratePlot.error.connect(self.QThreadError) self.VPBitratePlot.progress.connect( self.progressBarProcessor.setValue) self.VPTBitratePlot.start(QThread.LowPriority) sender = self.sender().objectName() if sender == "actionAudio": QMetaObject.invokeMethod(self.VPBitratePlot, 'CreatePlot', Qt.QueuedConnection, Q_ARG(str, self.fileName), Q_ARG(str, None), Q_ARG(str, 'audio')) elif sender == "actionVideo": QMetaObject.invokeMethod(self.VPBitratePlot, 'CreatePlot', Qt.QueuedConnection, Q_ARG(str, self.fileName), Q_ARG(str, None), Q_ARG(str, 'video')) elif sender == "actionSave_Audio": selfilter = "Portable Network Graphics (*.png)" fileaudio, _ = QFileDialog.getSaveFileName( self, "Save Audio Bitrate Plot", "", "EPS Encapsulated Postscript (*.eps);;" "PGF code for LaTex (*.pgf);;" "Portable document format(*pdf);;" "Portable Network Graphics (*.png);;" "Postscript (*.ps);;" "Raw RGBA bitmap (*.raw*.rgba);;" "Scalable vector graphics (*.svg*.svgz)", selfilter) if fileaudio == "": return QMetaObject.invokeMethod(self.VPBitratePlot, 'CreatePlot', Qt.QueuedConnection, Q_ARG(str, self.fileName), Q_ARG(str, fileaudio), Q_ARG(str, 'audio')) elif sender == "actionSave_Video": selfilter = "Portable Network Graphics (*.png)" filevideo, _ = QFileDialog.getSaveFileName( self, "Save Video Bitrate Plot", "", "EPS Encapsulated Postscript (*.eps);;" "PGF code for LaTex (*.pgf);;" "Portable document format(*pdf);;" "Portable Network Graphics (*.png);;" "Postscript (*.ps);;" "Raw RGBA bitmap (*.raw*.rgba);;" "Scalable vector graphics (*.svg*.svgz)", selfilter) if filevideo == "": return QMetaObject.invokeMethod(self.VPBitratePlot, 'CreatePlot', Qt.QueuedConnection, Q_ARG(str, self.fileName), Q_ARG(str, filevideo), Q_ARG(str, 'video')) except Exception as e: qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Failed creating Plot Bitrate")) def ExtractAllFrames(self): """ Extract All Video Frames Thread """ if not self.KillAllProcessors(): return options = QFileDialog.DontResolveSymlinks | QFileDialog.ShowDirsOnly directory = QFileDialog.getExistingDirectory( self, QCoreApplication.translate("QgsFmvPlayer", "Save images"), '', options=options) if directory: self.VPExtractFrames = ExtractFramesProcessor() self.VPTExtractAllFrames = QThread() self.VPExtractFrames.moveToThread(self.VPTExtractAllFrames) self.VPExtractFrames.finished.connect(self.QThreadFinished) self.VPExtractFrames.error.connect(self.QThreadError) self.VPExtractFrames.progress.connect( self.progressBarProcessor.setValue) self.VPTExtractAllFrames.start(QThread.LowPriority) QMetaObject.invokeMethod(self.VPExtractFrames, 'ExtractFrames', Qt.QueuedConnection, Q_ARG(str, directory), Q_ARG(str, self.fileName)) return def ExtractCurrentFrame(self): """ Extract Current Frame Thread """ image = self.videoWidget.GetCurrentFrame() out_image, _ = QFileDialog.getSaveFileName( self, "Save Current Frame", "", "Image File (*.png *.jpg *.bmp *.tiff)") if out_image == "": return if out_image: t = threading.Thread(target=self.SaveCapture, args=( image, out_image, )) t.start() return def SaveCapture(self, image, output): ''' Save Current Image ''' image.save(output) QApplication.processEvents() return def QThreadFinished(self, process, msg, outjson=None): ''' Finish Threads ''' if process == "ExtractFramesProcessor": self.VPExtractFrames.deleteLater() self.VPTExtractAllFrames.terminate() self.VPTExtractAllFrames.deleteLater() elif process == "CreatePlotsBitrate": self.VPBitratePlot.deleteLater() self.VPTBitratePlot.terminate() self.VPTBitratePlot.deleteLater() elif process == "convert": self.VPConverter.deleteLater() self.VPTConverter.terminate() self.VPTConverter.deleteLater() elif process == "probeToJson": self.VPProbeToJson.deleteLater() self.VPTProbeToJson.terminate() self.VPTProbeToJson.deleteLater() elif process == "probeShow": self.VPProbe.deleteLater() self.VPTProbe.terminate() self.VPTProbe.deleteLater() self.showVideoInfoDialog(outjson) QApplication.processEvents() self.progressBarProcessor.setValue(0) return def QThreadError(self, processor, e, exception_string): """ Threads Errors""" qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", processor), 'Failed!\n'.format(exception_string), level=QGis.Warning) self.QThreadFinished(processor, "Closing Processor") return def OpenQgsFmvMetadata(self): """ Open Metadata Dock """ if self.metadataDlg is None: self.metadataDlg = QgsFmvMetadata(parent=self, player=self) self.addDockWidget(Qt.RightDockWidgetArea, self.metadataDlg) self.metadataDlg.show() else: self.metadataDlg.show() return def KillAllProcessors(self): """Kill All Processors""" """ Extract all frames Processors """ try: if self.VPTExtractAllFrames.isRunning(): ret = qgsu.CustomMessage( QCoreApplication.translate( "QgsFmvPlayer", "HEY...Active background process!"), QCoreApplication.translate("QgsFmvPlayer", "Do you really want close?")) if ret == QMessageBox.Yes: self.QThreadFinished("ExtractFramesProcessor", "Closing Extract Frames Processor") else: return False except: None """ Bitrates Processors""" try: if self.VPTBitratePlot.isRunning(): ret = qgsu.CustomMessage( QCoreApplication.translate( "QgsFmvPlayer", "HEY...Active background process!"), QCoreApplication.translate("QgsFmvPlayer", "Do you really want close?")) if ret == QMessageBox.Yes: self.QThreadFinished("CreatePlotsBitrate", "Closing Plot Bitrate") else: return False except: None """ Converter Processors """ try: if self.VPTConverter.isRunning(): ret = qgsu.CustomMessage( QCoreApplication.translate( "QgsFmvPlayer", "HEY...Active background process!"), QCoreApplication.translate("QgsFmvPlayer", "Do you really want close?")) if ret == QMessageBox.Yes: self.QThreadFinished("convert", "Closing convert") else: return False except: None """ probeToJson Processors """ try: if self.VPTProbeToJson.isRunning(): ret = qgsu.CustomMessage( QCoreApplication.translate( "QgsFmvPlayer", "HEY...Active background process!"), QCoreApplication.translate("QgsFmvPlayer", "Do you really want close?")) if ret == QMessageBox.Yes: self.QThreadFinished("probeToJson", "Closing Info to Json") else: return False except: None """ probeShow Processors """ try: if self.VPTProbe.isRunning(): ret = qgsu.CustomMessage( QCoreApplication.translate( "QgsFmvPlayer", "HEY...Active background process!"), QCoreApplication.translate("QgsFmvPlayer", "Do you really want close?")) if ret == QMessageBox.Yes: self.QThreadFinished("probeShow", "Closing Show Video Info") else: return False except: None return True def showVideoInfoDialog(self, outjson): """ Show Video Information Dialog """ view = QTreeView() model = QJsonModel() view.setModel(model) model.loadJsonFromConsole(outjson) self.VideoInfoDialog = QDialog(self) self.VideoInfoDialog.setWindowTitle("Video Information : " + self.fileName) self.VideoInfoDialog.setWindowIcon( QIcon(":/imgFMV/images/video_information.png")) self.verticalLayout = QVBoxLayout(self.VideoInfoDialog) self.verticalLayout.addWidget(view) view.expandAll() view.header().setSectionResizeMode(QHeaderView.ResizeToContents) self.VideoInfoDialog.setWindowFlags(Qt.Window | Qt.WindowCloseButtonHint) self.VideoInfoDialog.setObjectName("VideoInfoDialog") self.VideoInfoDialog.resize(500, 400) self.VideoInfoDialog.show() def closeEvent(self, evt): """ Close Event """ if self.KillAllProcessors() is False: evt.ignore() return self.player.stop() self.parent._PlayerDlg = None self.parent.ToggleActiveFromTitle() RemoveVideoLayers() RemoveGroupByName() # Restore Filters State self.videoWidget.RestoreFilters() # QApplication.processEvents() del self.player
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui = Ui_MainWindow() #创建UI对象 self.ui.setupUi(self) #构造UI界面 self.player = QMediaPlayer(self) #创建视频播放器 self.player.setNotifyInterval(1000) #信息更新周期, ms self.player.setVideoOutput(self.ui.videoWidget) #视频显示组件 self.ui.videoWidget.installEventFilter(self) #事件过滤器 self.__duration = "" self.__curPos = "" self.player.stateChanged.connect(self.do_stateChanged) self.player.positionChanged.connect(self.do_positionChanged) self.player.durationChanged.connect(self.do_durationChanged) ## ==============自定义功能函数======================== ## ==============event处理函数========================== def closeEvent(self, event): #窗体关闭时 # 窗口关闭时不能自动停止播放,需手动停止 if (self.player.state() == QMediaPlayer.PlayingState): self.player.stop() def eventFilter(self, watched, event): ##事件过滤器 if (watched != self.ui.videoWidget): return super().eventFilter(watched, event) #鼠标左键按下时,暂停或继续播放 if event.type() == QEvent.MouseButtonPress: if event.button() == Qt.LeftButton: if self.player.state() == QMediaPlayer.PlayingState: self.player.pause() else: self.player.play() #全屏状态时,按ESC键退出全屏 if event.type() == QEvent.KeyPress: if event.key() == Qt.Key_Escape: if self.ui.videoWidget.isFullScreen(): self.ui.videoWidget.setFullScreen(False) return super().eventFilter(watched, event) ## ==========由connectSlotsByName()自动连接的槽函数============ @pyqtSlot() ##打开文件 def on_btnOpen_clicked(self): ## curPath=os.getcwd() #获取系统当前目录 curPath = QDir.currentPath() #获取系统当前目录 title = "选择视频文件" filt = "视频文件(*.wmv *.avi);;所有文件(*.*)" fileName, flt = QFileDialog.getOpenFileName(self, title, curPath, filt) if (fileName == ""): return fileInfo = QFileInfo(fileName) baseName = fileInfo.fileName() ## baseName=os.path.basename(fileName) self.ui.LabCurMedia.setText(baseName) curPath = fileInfo.absolutePath() QDir.setCurrent(curPath) #重设当前目录 media = QMediaContent(QUrl.fromLocalFile(fileName)) self.player.setMedia(media) #设置播放文件 self.player.play() @pyqtSlot() ##播放 def on_btnPlay_clicked(self): self.player.play() @pyqtSlot() ##暂停 def on_btnPause_clicked(self): self.player.pause() @pyqtSlot() ##停止 def on_btnStop_clicked(self): self.player.stop() @pyqtSlot() ##全屏 def on_btnFullScreen_clicked(self): self.ui.videoWidget.setFullScreen(True) @pyqtSlot() ##静音按钮 def on_btnSound_clicked(self): mute = self.player.isMuted() self.player.setMuted(not mute) if mute: self.ui.btnSound.setIcon(QIcon(":/icons/images/volumn.bmp")) else: self.ui.btnSound.setIcon(QIcon(":/icons/images/mute.bmp")) @pyqtSlot(int) ##音量调节 def on_sliderVolumn_valueChanged(self, value): self.player.setVolume(value) @pyqtSlot(int) ##播放进度调节 def on_sliderPosition_valueChanged(self, value): self.player.setPosition(value) ## =============自定义槽函数=============================== def do_stateChanged(self, state): ##状态变化 isPlaying = (state == QMediaPlayer.PlayingState) self.ui.btnPlay.setEnabled(not isPlaying) self.ui.btnPause.setEnabled(isPlaying) self.ui.btnStop.setEnabled(isPlaying) def do_durationChanged(self, duration): ##文件长度变化 self.ui.sliderPosition.setMaximum(duration) secs = duration / 1000 #秒 mins = secs / 60 #分钟 secs = secs % 60 #余数秒 self.__duration = "%d:%d" % (mins, secs) self.ui.LabRatio.setText(self.__curPos + "/" + self.__duration) def do_positionChanged(self, position): ##当前播放位置变化 if (self.ui.sliderPosition.isSliderDown()): return #如果正在拖动滑条,退出 self.ui.sliderPosition.setSliderPosition(position) secs = position / 1000 #秒 mins = secs / 60 #分钟 secs = secs % 60 #余数秒 self.__curPos = "%d:%d" % (mins, secs) self.ui.LabRatio.setText(self.__curPos + "/" + self.__duration)
class ApplicationWindow(QtWidgets.QMainWindow): global wavFileName global fig,chartFig global duration, counterClick global colorName, text_ global startAnnotation, endTimeToPlay # >> QtMultimedia Signals #---------------------- play = pyqtSignal() pause = pyqtSignal() stop = pyqtSignal() def __init__(self): global playerStarted global wavFileName, fig, chartFig global playerStarted, durationFlag, duration global colorName, text_, counterClick global startAnnotation, endTimeToPlay QtWidgets.QMainWindow.__init__(self) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.main_widget = QtWidgets.QWidget(self) playerStarted = False #DEFINE PLAYER-PLAYLIST #---------------------- self.source = QtCore.QUrl.fromLocalFile(os.path.abspath(wavFileName)) self.content = QMediaContent(self.source) self.player = QMediaPlayer() self.playlist = QMediaPlaylist(self) self.playlist.addMedia(self.content) self.player.setPlaylist(self.playlist) # >> Define annotations and gantt chart #---------------------- self.wave = Waveform() fig = self.wave self.chart = Chart() chartFig = self.chart # >> Define player buttons #---------------------- playButton = QPushButton("Play") pauseButton = QPushButton("Pause") stopButton = QPushButton("Stop") # >> Define layouts #---------------------- waveLayout = QVBoxLayout() waveLayout.addWidget(self.wave) waveLayout.addWidget(self.chart) line = QFrame() line.setFrameShape(QFrame.VLine) line.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Expanding) waveLayout.addWidget(line) #Buttons layout buttonLayout = QVBoxLayout() buttonLayout.addWidget(playButton) buttonLayout.addWidget(pauseButton) buttonLayout.addWidget(stopButton) buttonLayout.setAlignment(Qt.AlignTop) # >> Specify final layout align #---------------------- layout = QHBoxLayout(self.main_widget) layout.addLayout(waveLayout) layout.addLayout(buttonLayout) # >> Define buttons connections #---------------------- playButton.clicked.connect(self.Play) pauseButton.clicked.connect(self.Pause) stopButton.clicked.connect(self.Stop) self.main_widget.setFocus() self.setCentralWidget(self.main_widget) # PLAYER BUTTON FUNCTIONS # >> Play audio (whole signal or segment) #---------------------- def Play(self): global playerStarted global durationFlag global duration, counterClick global startTimeToPlay, endTimeToPlay, first #GET CLICKS FROM WAVEFORM #---------------------- #Initialize connection-position ONCE if not playerStarted: #10ms for changePosition -> Not Delaying self.player.positionChanged.connect(self.checkPositionToStop) self.player.setNotifyInterval(10) if durationFlag==0: playerStarted = True startTimeToPlay = 0 self.start = startTimeToPlay self.end = duration*1000 - 10 endTimeToPlay = self.end counterClick = 3 elif durationFlag==1: playerStarted = True self.start = startTimeToPlay self.end = duration*1000 - 10 endTimeToPlay = self.end counterClick = 3 elif durationFlag==2: playerStarted = True self.start = startTimeToPlay self.end = endTimeToPlay self.player.setPosition(self.start) playFlag = True self.player.play() # >> Pause audio playing #---------------------- def Pause(self): #Not begging from self.start playerStarted = True self.player.setPosition(self.time_) self.player.pause() # >> Stop audio playing #---------------------- def Stop(self): self.player.stop() #Begin again segment self.start = startTimeToPlay self.player.setPosition(self.start) # >> Check ms in audio to stop play #---------------------- def checkPositionToStop(self): self.time_ = self.player.position() print self.time_ if self.time_ >= self.end: self.Stop() self.player.setPosition(self.start) def fileQuit(self): self.close() def closeEvent(self, ce): self.fileQuit()
class MainWindow(QMainWindow): def __init__(self): super().__init__() # iniciando conexio con google self.translate_client = translate.Client() self.my_state = _STATE_PLAY # Controles principales para organizar la ventana. self.widget = QWidget(self) self.layout = QVBoxLayout() self.bottom_layout = QHBoxLayout() # status layout self.statusLayout = StatusLayout() # Sutitles layout self.subLayout = SubtitleLayout() # time stuff self.time_layout = QHBoxLayout() self.label_time = QLabel() self.label_mi = QLabel() self.label_end = QLabel() # inicializar subtitulos self.list_frames = sub.frames(MY_PATH + SUB_PATH) self.text_frame = self.list_frames.pop() # Control de reproducción de video de Qt. self.video_widget = QVideoWidget(self) self.media_player = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.media_player.setMedia( QMediaContent(QUrl.fromLocalFile(MY_PATH + VIDEO_PATH))) self.media_player.setVideoOutput(self.video_widget) # Botones de reproducción y pausa. # Deslizadores para el volumen y transición del video. self.seek_slider = QSlider(Qt.Horizontal) self.volume_slider = QSlider(Qt.Horizontal) self.volume_slider.setRange(0, 100) self.volume_slider.setValue(self.media_player.volume()) self.volume_slider.sliderMoved.connect(self.media_player.setVolume) # actualizar la posicion self.seek_slider.sliderMoved.connect(self.change_media_player) self.media_player.positionChanged.connect(self.change_seek_bar) self.media_player.durationChanged.connect(self.change_duration) # Acomodar controles en la pantalla. self.layout.addLayout(self.statusLayout) self.layout.addWidget(self.video_widget) self.layout.addLayout(self.bottom_layout) self.layout.addLayout(self.time_layout) self.layout.addWidget(self.seek_slider) # andir layout self.layout.addLayout(self.subLayout) #conections self.subLayout.prev_button.clicked.connect(self.click_prev) self.subLayout.next_button.clicked.connect(self.click_next) self.bottom_layout.addWidget(self.volume_slider) # time stuff self.time_layout.addWidget(self.label_time) self.time_layout.addWidget(self.label_mi) self.time_layout.addWidget(self.label_end) #self.set_sub_text(self.labels_sub2, self.frame.txt) self.subLayout.set_sub_text( self.subLayout.labelSub1, self.text_frame.f1.get_txt_conver_asteric()) self.subLayout.set_sub_text( self.subLayout.labelSub2, self.text_frame.f2.get_txt_conver_asteric()) # Conectar los eventos con sus correspondientes funciones. self.statusLayout.play_button.clicked.connect(self.play_clicked) self.statusLayout.stop_button.clicked.connect(self.stop_clicked) self.media_player.stateChanged.connect(self.state_changed) # conectando labels self.connect_labels() # Personalizar la ventana. self.setWindowTitle("Reproductor de video") self.resize(800, 600) self.layout.setContentsMargins(0, 0, 0, 0) self.bottom_layout.setContentsMargins(0, 0, 0, 0) self.widget.setLayout(self.layout) self.setCentralWidget(self.widget) # setear Timer self.timer = QTimer() self.timer.timeout.connect(self.timer_change_status) self.timer.start(_TIMER_TICK) # Reproducir el video. self.media_player.setNotifyInterval(_NOTIFY_INTERVAL) self.media_player.play() def connect_labels(self): for element in self.subLayout.labelSub1: element.clicked.connect(self.label_cliked) for element in self.subLayout.labelSub2: element.clicked.connect(self.label_cliked) def miles_minutes(self, value): s, ms = divmod(value, 1000) m, s = divmod(s, 60) h, m = divmod(m, 60) return h, m, s, ms # modificar el valor del seek def change_media_player(self, value): self.media_player.setPosition(value) def timer_change_status(self): #print ("timer") if self.my_state == _STATE_PAUSE: self.media_player.pause() self.timer.stop() def change_seek_bar(self, value): if self.my_state == _STATE_PLAY: # detiene la ejecusion del video si el frame ya acabo if value > self.text_frame.end: self.my_state = _STATE_PAUSE #if (value > self.text_frame.end and self.my_state == _STATE_PLAY): # print ("pasa") # self.media_player.pause() # self.my_state = _STATE_PAUSE #self.text_frame = self.list_frames.pop() #if self.text_frame != None: # self.sub_text_lab1 = self.text_frame.txt1 # self.sub_text_lab2 = self.text_frame.txt2 #else : # self.sub_text_lab1 = "" # self.sub_text_lab2 = "" # self.text_frame.end = 0 #print ("casa") (h, m, s, ms) = self.miles_minutes(value) time = "%d:%d:%d.%d" % (h, m, s, ms) self.label_time.setText(time) self.label_mi.setText(str(value)) self.label_end.setText(str(self.text_frame.end)) #self.label_sub1.setText(self.frame.txt) #self.set_sub_text(self.labels_sub1, self.sub_text_lab1) #self.set_sub_text(self.labels_sub2, self.sub_text_lab2) self.seek_slider.setValue(value) return True # se modifico la duracion def change_duration(self, value): self.seek_slider.setRange(0, value) # senales relacionadas a eventos def play_clicked(self): """ Comenzar o resumir la reproducción. """ if (self.media_player.state() in (QMediaPlayer.PausedState, QMediaPlayer.StoppedState)): self.media_player.play() else: self.media_player.pause() def click_prev(self): if self.my_state == _STATE_PLAY: self.media_player.pause() self.timer.stop() self.media_player.setPosition(self.text_frame.start) self.timer.start(_TIMER_TICK) self.media_player.play() self.my_state = _STATE_PLAY def click_next(self): if self.my_state == _STATE_PLAY: self.media_player.pause() self.timer.stop() self.text_frame = self.list_frames.pop() self.media_player.setPosition(self.text_frame.start) self.timer.start(_TIMER_TICK) self.media_player.play() self.my_state = _STATE_PLAY self.subLayout.set_sub_text( self.subLayout.labelSub1, self.text_frame.f1.get_txt_conver_asteric()) self.subLayout.set_sub_text( self.subLayout.labelSub2, self.text_frame.f2.get_txt_conver_asteric()) def stop_clicked(self): """ Detener la reproducción. """ self.media_player.stop() def state_changed(self, newstate): """ Actualizar el texto de los botones de reproducción y pausa. """ states = { QMediaPlayer.PausedState: "Resumir", QMediaPlayer.PlayingState: "Pausa", QMediaPlayer.StoppedState: "Reproducir" } self.statusLayout.play_button.setText(states[newstate]) self.statusLayout.stop_button.setEnabled( newstate != QMediaPlayer.StoppedState) def eventFilter(self, obj, event): """ Establecer o remover pantalla completa al obtener el evento MouseButtonDblClick. """ if event.type() == QEvent.MouseButtonDblClick: obj.setFullScreen(not obj.isFullScreen()) return False def keyPressEvent(self, event): if type(event) == QtGui.QKeyEvent: if event.key() == Qt.Key_Space: print("tecla space") else: #print (event.key()) if self.text_frame.new_key(event.key()) == True: #print("cambiar al siguiente Frame") self.text_frame = self.list_frames.pop() if self.my_state == _STATE_PLAY: self.media_player.pause() self.media_player.setPosition(self.text_frame.start) self.timer.start(_TIMER_TICK) self.media_player.play() self.my_state = _STATE_PLAY self.subLayout.set_sub_text( self.subLayout.labelSub1, self.text_frame.f1.get_txt_conver_asteric()) self.subLayout.set_sub_text( self.subLayout.labelSub2, self.text_frame.f2.get_txt_conver_asteric()) event.accept() else: event.ignore() def label_cliked(self, word): #print(word) result = self.translate_client.translate( word, target_language=_TARGET_LANGUAGE) txt = "%s = %s" % (result['input'], result['translatedText']) print(txt)
class ApplicationWindow(QMainWindow): ## Accessing files in Processed Stuff ## QDir.setCurrent(QCoreApplication.applicationDirPath()) processedVideoPath = QDir.currentPath() + "/ProcessedStuff/horses_1_predicted.mp4"; textFilePath = QDir.currentPath() + "/ProcessedStuff/labels_example.txt"; # Environmental Variable # os.environ['PYTHONPATH'] = "$(pwd)/detection:$(pwd)/detection/slim" # subprocess.check_call(['sqsub', '-np', sys.argv[1], 'application.py'], # env=dict(os.environ, SQSUB_VAR="visible in this subprocess")) ## Important variables ## videoLoaded = False fileReceived = False playing = False fileName = None labels = [] nextLine = 0 def __init__(self): # Create the Qt5 application backend super(ApplicationWindow, self).__init__() # Load in and display the UI self.ui = Ui_MainWindow() self.ui.setupUi(self) ## CONNECT EVENTS (like button presses) to functions ## self.ui.button_play_pause.clicked.connect(self.playPauseButtonClicked) self.ui.button_load.clicked.connect(self.loadButtonClicked) self.ui.button_track.clicked.connect(self.trackButtonClicked) # Configure the original video widget self.original_video_player = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.original_video_player.durationChanged.connect(self.durationChanged) self.original_video_player.setVideoOutput(self.ui.original_video_widget) # Configure the processed video widget self.video_player = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.video_player.setNotifyInterval(30) self.video_player.durationChanged.connect(self.durationChanged) self.video_player.positionChanged.connect(self.positionChanged) self.video_player.stateChanged.connect(self.stopped) self.video_player.setVideoOutput(self.ui.video_widget) # Configure the video slider self.ui.video_slider.sliderPressed.connect(self.sliderPressed) self.ui.video_slider.sliderReleased.connect(self.sliderReleased) # Update states self.updateStates() ## CALLBACK FUNCTIONS ## def playPauseButtonClicked(self): if self.playing: print("Pause!") self.pause() else: print("Play!") self.play() def saveButtonClicked(self): print("Save!") def loadButtonClicked(self): print("Load!") # fileName, _ = QFileDialog.getOpenFileName( # self, # "Choose a video", # QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation), # "Vide files (*mp4 *mp3)") # file = open("ProcessedStuff/labels_example.txt","w") # file.write("labels = []\n") # file.close() fileName, _ = QFileDialog.getOpenFileName(self, "Open Files") if fileName != "": self.ui.file_info.setText(fileName) print("Video filepath: " + fileName) self.fileName = fileName self.fileReceived = True self.nextLine = 0 self.updateStates() def trackButtonClicked(self): print("Track!") # Do processing and call following method when completed # detection.detection_code(self.fileName) self.processingFinished() def sliderReleased(self): newPosition = self.ui.video_slider.value() self.setPosition(newPosition) def sliderPressed(self): self.pause() def durationChanged(self): self.videoLoaded = True self.updateStates() self.ui.video_slider.setMaximum(self.video_player.duration()) def positionChanged(self): if not self.playing: return position = self.video_player.position() # Update video progress bar self.ui.video_slider.setValue(position) # Update information label self.updateLabel(position) def stopped(self): if self.video_player.state() == QMediaPlayer.StoppedState: self.playing = False self.ui.label_info.setText("") ## Helper Functions ## def play(self): self.original_video_player.play() self.video_player.play() self.playing = True def pause(self): self.playing = False self.original_video_player.pause() self.video_player.pause() def setPosition(self, position): self.resetNextLine(position) self.updateLabel(position) self.original_video_player.setPosition(position) self.video_player.setPosition(position) self.play() def updateStates(self): self.ui.button_play_pause.setEnabled(self.videoLoaded) self.ui.video_slider.setEnabled(self.videoLoaded) self.ui.button_track.setEnabled(self.fileReceived and not self.playing) def processingFinished(self): print("Text file location: " + self.textFilePath) file = open(self.textFilePath, "r") self.labels = [line.split(',') for line in file] file.close() print(self.processedVideoPath) self.video_player.setMedia(QMediaContent(QUrl.fromLocalFile(self.processedVideoPath))) self.original_video_player.setMedia(QMediaContent(QUrl.fromLocalFile(self.fileName))) self.play() # When the user changes the slider the next line changes def resetNextLine(self, position): while (position < int(self.labels[self.nextLine][0])): self.nextLine -= 1 if (self.nextLine <= 0): break if self.nextLine+1<=len(self.labels)-1: while (position >= int(self.labels[self.nextLine+1][0])): self.nextLine += 1 if (self.nextLine >= len(self.labels)-1): break def updateLabel(self, position): if position >= int(self.labels[self.nextLine][0]): label = self.labels[self.nextLine] messageStr = "Count: " + label[1] for i in range(2,len(label),2): messageStr += ("\n%s. %s %s" % (i-int(i/2),label[i],label[i+1])) self.ui.label_info.setText(messageStr) if self.nextLine < len(self.labels)-1: self.nextLine += 1
class MyMainForm(QMainWindow, Ui_MainWindow): signal_close_popup = pyqtSignal() def __init__(self, parent=None): QMainWindow.__init__(self, parent) Ui_MainWindow.__init__(self) self.setupUi(self) self.setWindowTitle(' ') self.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowCloseButtonHint | Qt.MSWindowsFixedSizeDialogHint) self.songs_data_manager = SongsDataManager() self.songs_data = self.songs_data_manager.read_songs_data() self.column_num = 2 self.row_num = math.ceil(globals.style_num / self.column_num) self._generate_colors(globals.style_num) self.action = QAction('导入') self.main_menu.addAction(self.action) self.action.triggered.connect(self._import_files) self.styles_widget.load_styles_images() self.style_table_widget.setVisible(False) self.style_table_widget.setShowGrid(False) self.style_table_widget.setFrameShape(QFrame.NoFrame) self.style_table_widget.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.style_table_widget.horizontalHeader().setVisible(False) self.style_table_widget.verticalHeader().setVisible(False) self.style_table_widget.verticalHeader().setSectionResizeMode( QHeaderView.Stretch) self.style_table_widget.setColumnCount(self.column_num) self.style_table_widget.setRowCount(self.row_num) self.table_items = [] self.playlist_items = [] self.selected_style_index = -1 self.selected_song_name = '' self.location_root = os.getcwd() for i in range(self.row_num * self.column_num): row = math.floor(i / self.column_num) column = math.floor(i % self.column_num) if i < globals.style_num: table_item = QTableWidgetItem(globals.styles_chinese[i]) table_item.setData(Qt.FontRole, QFont("", 20)) table_item.setBackground(self.qcolors[i]) else: table_item = QTableWidgetItem('') self.table_items.append(table_item) table_item.setTextAlignment(Qt.AlignCenter) self.style_table_widget.setItem(row, column, table_item) self.style_table_widget.cellClicked.connect( self._on_table_item_clicked) self.video_widget = QVideoWidget() self.player_layout.addWidget(self.video_widget) control_layout = QHBoxLayout() control_layout.setContentsMargins(0, 0, 0, 0) self.play_button = QPushButton() self.play_button.setEnabled(False) self.play_button.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) self.play_button.clicked.connect(self.play) control_layout.addWidget(self.play_button) self.position_slider = QSlider(Qt.Horizontal) self.position_slider.setRange(0, 0) self.position_slider.sliderMoved.connect(self.set_position) control_layout.addWidget(self.position_slider) self.player_layout.addLayout(control_layout) self.back_btn.clicked.connect(self._on_back_to_style_view) self.delete_btn.clicked.connect(self._on_delete_item) self.playlist.itemClicked.connect(self._on_playlist_item_clicked) self.playlist.itemDoubleClicked.connect( self._on_playlist_item_double_clicked) self.playlist_widget.setVisible(False) self.media_player = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.notify_interval = 100 self.media_player.setVideoOutput(self.video_widget) self.media_player.setNotifyInterval(self.notify_interval) self.media_player.stateChanged.connect(self.media_state_changed) self.media_player.positionChanged.connect(self.play_time_changed) self.media_player.durationChanged.connect(self.duration_changed) self.media_player.error.connect(self.handle_error) self.styles_widget.signal_style_clicked.connect(self.on_style_selected) self.detected_result_str = '' with open('music_model.pkl', 'rb') as fp: self.model = pickle.load(fp) def closeEvent(self, event): self.media_player.pause() self.wave_widget.stop_audio() def _change_to_playlist_view(self, style_index): self.styles_widget.setVisible(False) self.playlist_widget.setVisible(True) self.selected_style_index = style_index self._refresh_playlist() def _refresh_playlist(self): files = self.songs_data.get(globals.styles[self.selected_style_index], []) self.playlist_items = [] self.playlist.clear() flip_count = False for file in files: flip_count = False if flip_count else True list_item = QListWidgetItem(os.path.basename(file)) setattr(list_item, 'full_file_name', file) list_item.setBackground(Qt.lightGray if flip_count else Qt.white) self.playlist_items.append(list_item) self.playlist.addItem(list_item) def _on_back_to_style_view(self): self.styles_widget.setVisible(True) self.playlist_widget.setVisible(False) self.selected_song_name = '' self.delete_btn.setEnabled(False) def _get_cur_style_dir(self): return os.path.join(self.location_root, 'playlists', globals.styles[self.selected_style_index]) @staticmethod def _pop_message_box(alert_text): result_window = MyPopup(has_close=True) result_window.label.setText(alert_text) result_window.exec() def on_style_selected(self, style_selected): self._change_to_playlist_view(globals.styles.index(style_selected)) def _print_media_state(self): if self.media_player.state() == QMediaPlayer.PlayingState: print('playing state') elif self.media_player.state() == QMediaPlayer.PausedState: print('paused state') elif self.media_player.state() == QMediaPlayer.StoppedState: print('stopped state') def _on_table_item_clicked(self, row, col): style_index = row * self.column_num + col if style_index >= globals.style_num: return self._change_to_playlist_view(style_index) def _on_playlist_item_clicked(self, item): self.selected_song_name = getattr(item, 'full_file_name') self.delete_btn.setEnabled(True) def _on_playlist_item_double_clicked(self, item): if self.selected_style_index == -1: return filename = getattr(item, 'full_file_name') if os.path.isfile(filename): self.current_song_label.setText(os.path.basename(filename)) self.media_player.setMedia( QMediaContent(QUrl.fromLocalFile(filename))) self.wave_widget.load_file(filename) self.play() else: self._pop_message_box('找不到文件:%s' % filename) def _on_delete_item(self): if not self.selected_song_name: return if self.selected_style_index == -1: return self.songs_data[globals.styles[self.selected_style_index]].pop( self.selected_song_name, None) self.songs_data_manager.write_songs_data(self.songs_data) self._refresh_playlist() def _import_files(self): file_dialog = QFileDialog() file_dialog.setFileMode(QFileDialog.ExistingFiles) names = file_dialog.getOpenFileNames(None, 'open wav file', '.', 'AUDIO(*.wav *.mp3)') if not names[0]: return if not isinstance(names[0], list): audio_names = [names[0]] else: audio_names = names[0] self.processing_files_thread = ProcessingFilesThread(main_widget=self, names=audio_names) self.processing_files_thread.start() main_window_geometry = self.geometry() self.progress_window = MyPopup(main_widget=self) self.progress_window.exec() self.processing_files_thread.wait() self._pop_message_box(self.detected_result_str) self._refresh_playlist() def play(self): self.play_button.setEnabled(True) if self.media_player.state() == QMediaPlayer.PlayingState: self.media_player.pause() self.wave_widget.pause_audio() else: self.media_player.play() self.wave_widget.start_audio() def media_state_changed(self, state): if state == QMediaPlayer.PlayingState: self.play_button.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.play_button.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) if state == QMediaPlayer.StoppedState: self.wave_widget.stop_audio() def play_time_changed(self, play_time): self.wave_widget.set_cur_play_time(play_time) self.position_slider.setValue(play_time) def duration_changed(self, duration): self.position_slider.setRange(0, duration) def set_position(self, position): self.media_player.setPosition(position) def handle_error(self): self.play_button.setEnabled(False) def _generate_colors(self, num): colors = [] for r_value in range(0, 256, 20): for g_value in range(0, 256, 20): for b_value in range(0, 256, 20): colors.append((r_value, g_value, b_value)) colors_choosen = random.sample(colors, num) self.qcolors = [] for color in colors_choosen: self.qcolors.append(QColor(color[0], color[1], color[2], 127))
class VideoWindow(QWidget): sigTimeChanged = pyqtSignal(object) def __init__(self, project=None, parent=None): super(VideoWindow, self).__init__(parent) self.project = project self.setWindowTitle("Video") self.mediaPlayer = QMediaPlayer() #None, QMediaPlayer.VideoSurface) self.last_position = 0 self.position_on_new_file = 0 self.duration = -1 self.waiting_for_file = False self.media_state_before_file_transition = self.mediaPlayer.state() self.video_time_offset = 0.0 self.play_icon = QIcon(play_icon_file) self.clock_icon = QIcon(clock_icon_file) self.pause_icon = QIcon(pause_icon_file) videoWidget = QVideoWidget() self.videoWidget = videoWidget self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setIcon(self.play_icon) self.playButton.clicked.connect(self.play) self.timeOffsetButton = QPushButton() self.timeOffsetButton.setIcon(self.clock_icon) self.timeOffsetButton.clicked.connect(self.setTimeOffset) self.positionSlider = QSlider(Qt.Horizontal) self.positionSlider.setRange(0, 0) self.positionSlider.sliderMoved.connect(self.setPosition) self.errorLabel = QLabel() self.errorLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Maximum) # Create layouts to place inside widget controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) controlLayout.addWidget(self.timeOffsetButton) controlLayout.addWidget(self.playButton) controlLayout.addWidget(self.positionSlider) layout = QVBoxLayout() layout.addWidget(videoWidget) layout.addLayout(controlLayout) layout.addWidget(self.errorLabel) # Hide error Label # Set widget to contain window contents self.setLayout(layout) self.mediaPlayer.setVideoOutput(videoWidget) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.mediaStatusChanged.connect(self.mediaStatusChanged) self.mediaPlayer.error.connect(self.handleError) self.mediaPlayer.setNotifyInterval(40) # 25 fps if self.project is None: self.current_time_range = [0, 0] self.current_file = '' # self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(self.current_file))) # self.playButton.setEnabled(True) # self.mediaPlayer.play() elif self.project.current_animal.video_files: self.current_file = self.project.current_animal.video_files[0] self.current_time_range = [ self.project.current_animal.video_init_time[0], self.project.current_animal.video_init_time[0] + self.project.current_animal.video_duration[0] ] self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(self.current_file))) self.playButton.setEnabled(True) else: self.current_file = '' self.current_time_range = [0, 0] def setTimeOffset(self): offset, okpressed = QInputDialog.getDouble( self, 'Video time offset', 'Offset video time position (seconds)', value=self.video_time_offset) if okpressed: self.video_time_offset = offset current_position = self.current_time_range[ 0] + self.last_position / 1000 self.setGlobalPosition(0) self.setGlobalPosition(current_position) def openFile(self): fileName, _ = QFileDialog.getOpenFileName(self, "Open Movie", QDir.homePath()) if fileName != '': self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(fileName))) self.playButton.setEnabled(True) def exitCall(self): sys.exit(app.exec_()) def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon(self.pause_icon) else: self.playButton.setIcon(self.play_icon) def positionChanged(self, position): # Connected to video player # print('positionChanged',position,self.last_position,self.waiting_for_file,self.duration,self.current_time_range) # if self.duration == -1: # print('positionChanged: no file - duration ==-1') # return # if self.waiting_for_file: # print('positionChanged: Waiting to load file') # return # if position == 0: # print('positionChanged: avoiding setting positions to 0') # return if position == 0 or self.waiting_for_file or self.duration == -1 or position == self.last_position: # avoid position changes on file transitions or repeated signals on same position return if position < self.duration - 40: # avoid time changes when switching files self.last_position = position self.positionSlider.setValue(position) self.sigTimeChanged.emit(position / 1000 + self.current_time_range[0]) else: # position is at the end of file - try to switch to next file pos = self.current_time_range[1] + .04 print('Trying to jump to next file', self.current_time_range[1], self.duration, pos) self.setGlobalPosition(pos) def durationChanged(self, duration): # print('duration changed',duration) self.duration = duration self.positionSlider.setRange(0, duration) self.mediaPlayer.setPosition( self.position_on_new_file ) # if duration changes avoid the position going back to 0 def setPosition(self, position): # connected to slider # print('setPosition',position) self.mediaPlayer.setPosition( position) # milliseconds since the beginning of the media def setGlobalPosition(self, pos): # Connected to project main model sigTimeChanged # open the right media if self.current_time_range[0] <= pos <= self.current_time_range[ 1]: # correct file opened position = int((pos - self.current_time_range[0]) * 1000) if self.mediaPlayer.state() == QMediaPlayer.PlayingState and abs( position - self.last_position) < 200: # skip position setting by signal of main model to ensure smooth video plaback return # go to correct relative position self.mediaPlayer.setPosition(position) # UNIX time return else: for i, file in enumerate(self.project.current_animal.video_files ): # search for file to open arange = [ self.project.current_animal.video_init_time[i] + self.video_time_offset, self.project.current_animal.video_init_time[i] + self.project.current_animal.video_duration[i] + self.video_time_offset ] if (arange[0] <= pos <= arange[1]): print('Changing video file: ', file) self.current_file = file self.errorLabel.setText("File: " + self.current_file) self.current_time_range = arange self.waiting_for_file = True self.media_state_before_file_transition = self.mediaPlayer.state( ) self.mediaPlayer.stop() position = (pos - self.current_time_range[0]) * 1000 self.position_on_new_file = int(position) # print('Changing position_on_new_file: ', self.position_on_new_file,pos) self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(file))) self.playButton.setEnabled(True) # self.duration = (arange[1]-arange[0])*1000 return print('no video file found for current position') self.errorLabel.setText("No video file found for current position") self.mediaPlayer.stop() self.mediaPlayer.setMedia(QMediaContent()) self.current_file = '' self.current_time_range = [0, 0] # self.duration = 0 self.playButton.setEnabled(False) self.positionSlider.setRange(0, 0) self.positionSlider.setValue(0) def mediaStatusChanged(self, status): if self.waiting_for_file: if self.mediaPlayer.mediaStatus() == QMediaPlayer.LoadedMedia: self.waiting_for_file = False # print('finished loading file') # self.mediaPlayer.stop() self.mediaPlayer.setPosition(self.position_on_new_file) self.mediaPlayer.play() time.sleep(.05) self.mediaPlayer.pause() if self.media_state_before_file_transition == QMediaPlayer.PlayingState: self.mediaPlayer.play() # print('finished setting position on new file') def handleError(self): self.playButton.setEnabled(False) self.errorLabel.setText("Error: " + self.mediaPlayer.errorString()) print("Video - Error: " + self.mediaPlayer.errorString())
class jaabaGUI(QMainWindow): """ controller for the blob labeling GUI""" def __init__(self, parent=None): self.debugMode = True self.debugVideoPath = '/Users/071cht/Desktop/Lab/jaabagui/testt.mjpeg.avi' QMainWindow.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.installEventFilter(self) self.setFocusPolicy(Qt.StrongFocus) #add new slider # self.positionSlider=QSlider(Qt.Horizontal) # self.positionSlider.setGeometry (800,800,100,30) # self.positionSlider.setRange(0, 0) # self.positionSlider.sliderMoved.connect(self.setPosition) #setup Video #video player self.mediaPlayer1 = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.mediaPlayer2 = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.mediaPlayer2.setNotifyInterval(10) #self.mediaPlayer.metaDataChanged.connect(self.metaDataChanged) self.mediaPlayer1.durationChanged.connect(self.durationChanged) self.mediaPlayer1.positionChanged.connect(self.positionChanged) self.mediaPlayer2.positionChanged.connect(self.positionChanged) #self.mediaPlayer2.positionChanged.connect(self.paintEvent) #visualizetion self.scene = QGraphicsScene() self.ui.graphicsView.setScene(self.scene) #self.scene.setBackgroundBrush(Qt.black) self.videoItem1 = QGraphicsVideoItem() self.videoItem2 = Video() self.scene.addItem(self.videoItem1) self.scene.addItem(self.videoItem2) self.mediaPlayer1.setVideoOutput(self.videoItem1) self.mediaPlayer2.setVideoOutput(self.videoItem2) #slider bar self.ui.horizontalSlider.setRange(0, 0) self.ui.horizontalSlider.sliderMoved.connect(self.setPosition) # self.ui.horizontalSlider.sliderPressed.connect(self.sliderPressed) #draw on video self.flyCanvas = TargetView() self.scene.addItem(self.flyCanvas) #give reference to target view self.flyCanvas.setWindowReference(self) #lineEdit signals: self.ui.lineEdit.returnPressed.connect(self.lineEditChanged) #callbacks self.ui.actionQuit.triggered.connect(self.quit) self.ui.actionLoad_Project.triggered.connect(self.loadVideo) self.ui.actionImport_Labels.triggered.connect(self.loadLabels) #self.ui.buttonPlay.clicked[bool].connect(self.setToggleText) self.ui.buttonPlay.clicked.connect(self.play) self.ui.actionSave.triggered.connect(self.saveLabels) ## print self.ui.graphicsView.sizeHint() #behavior Button self.ui.buttonBehavior.clicked.connect(self.behaviorButtonClick) self.ui.buttonNone.clicked.connect(self.noneButtonClick) #initialization self.loaded = False self.videoFilename = None self.frame_count = None self.width = None self.height = None self.frame_trans = None self.previous_frame = 0 self.current_frame = 0 self.behaviorButtonStart = False self.noneButtonStart = False self.currentFly = 1 #initialize flyInfo #self.setCurrentFly(self.currentFly) # register flyid changed callback self.flyCanvas.onCurrentFlyIdChanged(self.currentFlyIdChangedCallback) self.flyCanvas.setCurrentFlyId(self.currentFly) # when double click on video, change fly id in target view self.videoItem2.onDoubleClick(self.flyCanvas.setCurrentFlyIdByXY) ######################## # DEBUG PART HERE!!!!! # ######################## if (self.debugMode): self.debugLoadVideo() # add label UI related when load video def showEvent(self, evt): super(jaabaGUI, self).showEvent(evt) ##### HERE THE WINDOW IS LOADED!!!!!!!! # self.loadLabelUI() def loadLabelUI(self): #labels self.labelScene = QGraphicsScene() self.ui.graphLabels.setScene(self.labelScene) # the size is only accurate after the window fully displayed labelUIWidth = self.ui.graphLabels.width() labelUIHeight = self.ui.graphLabels.height() - 1 self.labelScene.setSceneRect(0, 0, labelUIWidth, labelUIHeight) self.labelUI = LabelUI() # visiableWidth = 850 # height = 30 # visiableFrameNum = 850 self.labelUI.setWidthPerFrame(850.0 / 850.0) # print '850/500',850.0/850.0b # print 'length_perframe is ', self.labelUI.widthPerFrame # 850 is the original length of graphLabel total_length = self.labelUI.widthPerFrame * self.frame_count self.labelUI.setVisiableSize(total_length, 30) # set start position self.labelUI.setPos(labelUIWidth / 2, 0) print 'frame_count is ', self.frame_count print 'total length is', total_length self.labelScene.addItem(self.labelUI) # middle line ui self.labelUIMiddleLine = LabelUIMiddleLine() self.labelScene.addItem(self.labelUIMiddleLine) self.labelUIMiddleLine.setPos(labelUIWidth / 2, 0) # self.labelUI.setPos(QPointF(-100,0)) self.writeLog('Label UI loaded') def eventFilter(self, obj, event): if (event.type() == PyQt5.QtCore.QEvent.KeyPress): # http://qt-project.org/doc/qt-4.8/qt.html#Key-enum key = event.key() if (key == Qt.Key_Up): curr_frame = int(float(self.ui.lineEdit.text())) curr_frame = curr_frame - 30 media_position = int(round(curr_frame * self.frame_trans)) # print curr_frame, media_position self.mediaPlayer1.setPosition(media_position) self.mediaPlayer2.setPosition(media_position) # print 'down -30' elif (key == Qt.Key_Right): curr_frame = int(float(self.ui.lineEdit.text())) # print 'right +1' # print curr_frame curr_frame = curr_frame + 1 media_position = int(round(curr_frame * self.frame_trans)) # print 'curr_frame',curr_frame # print 'frame_trans',self.frame_trans # print ' curr_frame*self.frame_trans',curr_frame*self.frame_trans # print 'media_position',media_position # print curr_frame, media_position self.mediaPlayer1.setPosition(media_position) self.mediaPlayer2.setPosition(media_position) # self.mediaPlayerPositionChanged(media_position) elif (key == Qt.Key_Left): curr_frame = int(float(self.ui.lineEdit.text())) curr_frame = curr_frame - 1 media_position = int(round(curr_frame * self.frame_trans)) self.mediaPlayer1.setPosition(media_position) self.mediaPlayer2.setPosition(media_position) # print 'left -1' elif (key == Qt.Key_Down): curr_frame = int(float(self.ui.lineEdit.text())) curr_frame = curr_frame + 30 media_position = int(round(curr_frame * self.frame_trans)) self.mediaPlayer1.setPosition(media_position) self.mediaPlayer2.setPosition(media_position) # print 'up +30' return True return False # ###actions starts from here### def quit(self): QApplication.quit() def loadVideo(self): # print QMediaPlayer.supportedMimeTypes() self.writeLog("Loading video...") self.videoFilename = QFileDialog.getOpenFileName( self, 'Open File', '.')[0] if not self.videoFilename: self.writeLog("User cancelled - no video loaded") return else: cap = cv2.VideoCapture(self.videoFilename) self.frame_count = cap.get(cv2.CAP_PROP_FRAME_COUNT) self.width = cap.get(3) self.height = cap.get(4) self.mediaPlayer2.setMedia( QMediaContent(QUrl.fromLocalFile(self.videoFilename))) self.mediaPlayer1.setMedia( QMediaContent(QUrl.fromLocalFile(self.videoFilename))) self.ui.buttonPlay.setEnabled(True) # self.mediaPlayer2.setVideoOutput(self.videoItem2) # self.mediaPlayer1.setVideoOutput(self.videoItem1) # size= self.videoItem2.nativeSize() # # print size ## print self.mediaPlayer.duration() ## print self.mediaPlayer.metaData() self.writeLog("Video loaded!") # init label related ui self.loadLabelUI() def debugLoadVideo(self): self.videoFilename = self.debugVideoPath cap = cv2.VideoCapture(self.videoFilename) self.frame_count = cap.get(cv2.CAP_PROP_FRAME_COUNT) self.width = cap.get(3) self.height = cap.get(4) self.mediaPlayer2.setMedia( QMediaContent(QUrl.fromLocalFile(self.videoFilename))) self.mediaPlayer1.setMedia( QMediaContent(QUrl.fromLocalFile(self.videoFilename))) self.ui.buttonPlay.setEnabled(True) self.writeLog("Video loaded!") QTimer.singleShot(1000, self.loadLabelUI) def play(self): self.videoItem1.setAspectRatioMode(0) self.videoItem2.setAspectRatioMode(0) self.scene.setSceneRect(0, 0, self.ui.graphicsView.width(), self.ui.graphicsView.height()) self.videoItem1.setSize( QSizeF(self.ui.graphicsView.width() / 2, self.ui.graphicsView.height())) self.videoItem2.setSize( QSizeF(self.ui.graphicsView.width() / 2, self.ui.graphicsView.height())) self.videoItem1.setPos(QPointF(0, 0)) self.videoItem2.setPos(QPointF(self.ui.graphicsView.width() / 2, 0)) self.flyCanvas.setPos(QPointF(self.ui.graphicsView.width() / 2, 0)) # custom function setXYScale self.videoItem2.setXYScale(self.width, self.height, self.ui.graphicsView.width() / 2, self.ui.graphicsView.height()) self.flyCanvas.setXYScale(self.width, self.height, self.ui.graphicsView.width() / 2, self.ui.graphicsView.height()) if self.mediaPlayer1.state() == QMediaPlayer.PlayingState: self.ui.buttonPlay.setIcon(self.ui.style().standardIcon( PyQt5.QtWidgets.QStyle.SP_MediaPlay)) self.ui.buttonPlay.setText("Play") self.mediaPlayer1.pause() self.writeLog("Video paused") else: self.ui.buttonPlay.setIcon(self.ui.style().standardIcon( PyQt5.QtWidgets.QStyle.SP_MediaPause)) self.ui.buttonPlay.setText("Stop") self.mediaPlayer1.play() self.writeLog("Playing video") if self.mediaPlayer2.state() == QMediaPlayer.PlayingState: self.mediaPlayer2.pause() else: self.mediaPlayer2.play() def loadLabels(self): self.writeLog("Loading labels from file...") self.labelFilename = QFileDialog.getOpenFileName( self, 'Open File', '.')[0] self.labelUI.labelData = pickle.load(open(self.labelFilename, "rb")) self.writeLog("Label loaded from file:" + self.labelFilename) def saveLabels(self): # Now it can only save to current file. Will add an poput window to choose path later pickle.dump(self.labelUI.labelData, open("newLabels.p", "wb")) def setPosition(self, position): self.mediaPlayer1.setPosition(position) self.mediaPlayer2.setPosition(position) # when position of media changed, set slider and text box accordingly. def positionChanged(self, position): #test change labelui position # self.labelUI.startLabel(); # self.labelUI.update() previous_frame = self.previous_frame curr_frame = int(round(position / self.frame_trans)) self.current_frame = curr_frame frame_change = previous_frame - curr_frame move_width = frame_change * self.labelUI.widthPerFrame self.previous_frame = curr_frame self.labelUI.moveBy(move_width, 0) self.labelUI.setCurrentFrame(curr_frame) # enforce labelUI paint once self.labelUI.update() # self.labelUI.setPos(self.labelUI.mapToParent(1,0)); # self.labelUI.update() # # print 'triggered position' # # print position # # print 'cur position' # # print self.mediaPlayer2.position() self.updateLineEdit(position) self.updateSliderAndGraph(position) # self.ui.horizontalSlider.setValue(position) # if isinstance(self.frame_trans,float): # # # print type(position),position # # # print type(self.frame_trans),self.frame_trans # # # print position/self.frame_trans # self.ui.lineEdit.setText(str(int(round(position/self.frame_trans)))) # self.flyCanvas.getFrame(int(round(position/self.frame_trans))) # self.flyCanvas.isManualCalled = True; # self.flyCanvas.update() # self.writeLog(str(position)) # # self.updateMediaControlUI(position) # # self.flyCanvas.update() def updateSliderAndGraph(self, position): self.ui.horizontalSlider.setValue(position) if isinstance(self.frame_trans, float): self.flyCanvas.getFrame(int(round(position / self.frame_trans))) self.flyCanvas.isManualCalled = True self.flyCanvas.update() #self.writeLog(str(position)) def updateLineEdit(self, position): # # print self.width # # print self.height if isinstance(self.frame_trans, float): # # print type(position),position # # print type(self.frame_trans),self.frame_trans # # print position/self.frame_trans self.ui.lineEdit.setText( str(int(round(position / self.frame_trans)))) def durationChanged(self, duration): self.ui.horizontalSlider.setRange(0, duration) self.frame_trans = self.mediaPlayer1.duration() / self.frame_count ## print self.frame_trans #def eventFilter(self,source,event): #if (event.type()==PyQt5.QtCore.QEvent.MousePress and source is self.videoItem2): # pos=event.pos() # # print('mouse position: (%d,%d)' % (pos.x(),pos.y())) # return PyQt5.QtGui.QWidget.eventFilter(self, source, event) def writeLog(self, text): self.ui.log.setText(text) # def eventFilter (self.ui.lineEdit,event): # if event.type()==PyQt5.QtCore.QEvent def lineEditChanged(self): #set position of media curr_frame = int(float(self.ui.lineEdit.text())) media_position = int(round(curr_frame * self.frame_trans)) self.mediaPlayer1.setPosition(media_position) self.mediaPlayer2.setPosition(media_position) # print 'setPosition' # print media_position # print 'after set' # print self.mediaPlayer2.position() # self.updateSliderAndGraph(media_position) def behaviorButtonClick(self): # flip flag self.behaviorButtonStart = not self.behaviorButtonStart # check click to start or stop if (self.behaviorButtonStart): # start labeling self.labelUI.startLabel(self.ui.comboBox.currentIndex(), '', self.current_frame) self.writeLog('start labeling') else: # stop lableing self.labelUI.stopLabel() self.writeLog('stop labeling') def noneButtonClick(self): # flip flag self.noneButtonStart = not self.noneButtonStart # check click to start or stop if (self.noneButtonStart): # start labeling self.labelUI.startLabel(self.ui.comboBox.currentIndex(), '_none', self.current_frame) self.writeLog('start labeling') else: # stop lableing self.labelUI.stopLabel() self.writeLog('stop labeling') # set CurrentFly when fly changed! def setCurrentFly(self, fly): self.currentFly = fly self.ui.flyInfo.setPlainText('FlyID:' + str(self.currentFly)) self.flyCanvas.currentFly = fly def currentFlyIdChangedCallback(self, fly): print 'callback!!!!!' self.currentFly = fly self.ui.flyInfo.setPlainText('FlyID:' + str(self.currentFly))