class Player(QGraphicsVideoItem): def __init__(self, parent=None): super().__init__() self.parent = parent self.player = QMediaPlayer() self.player.setVideoOutput(self) def playerPlayOrOpen(self, arg=None): if type(arg) == list and len(arg) > 1: content = QMediaContent(QUrl.fromLocalFile(arg[1])) self.player.setMedia(content) self.play() def addVideo(self, video): content = QMediaContent(QUrl.fromLocalFile(video)) self.player.setMedia(content) self.play() def sliderChanged(self, pos): self.player.setPosition(pos) def mouseDoubleClickEvent(self, event): if not self.parent.isFullScreen(): self.parent.showFullScreen() else: self.parent.showNormal() def play(self): self.player.play() def stop(self): self.player.stop() def pause(self): self.player.pause() def setMuted(self, mute): self.player.setMuted(mute) def mutedState(self): if self.player.isMuted(): self.setMuted(False) else: self.setMuted(True) def isMuted(self): return self.player.isMuted() def setVolume(self, value): self.player.setVolume(value) def volume(self): return self.player.volume()
class Player(QGraphicsVideoItem): def __init__(self, parent=None): super().__init__() self.parent = parent self.player = QMediaPlayer() self.player.setVideoOutput(self) def playerPlayOrOpen(self, arg=None): if type(arg) == list and len(arg) > 1: content = QMediaContent(QUrl.fromLocalFile(arg[1])) self.player.setMedia(content) self.play() def addVideo(self, video): content = QMediaContent(QUrl.fromLocalFile(video)) self.player.setMedia(content) self.play() def sliderChanged(self, pos): self.player.setPosition(pos) def mouseDoubleClickEvent(self, event): if not self.parent.isFullScreen(): self.parent.showFullScreen() else: self.parent.showNormal() def play(self): self.player.play() def stop(self): self.player.stop() def pause(self): self.player.pause() def setMuted(self, mute): self.player.setMuted(mute) def mutedState(self): if self.player.isMuted(): self.setMuted(False) else: self.setMuted(True) def isMuted(self): return self.player.isMuted() def setVolume(self, value): self.player.setVolume(value) def volume(self): return self.player.volume()
class Reproductor(Genesis, QMainWindow): """ Instalar MatroskaSplitter y LAVFilters(Codecs), para que pueda reproducir videos y audio LAVFilters https://github.com/Nevcairiel/LAVFilters/releases MatroskaSplitter https://haali.su/mkv/ """ def __init__(self, *args, **kwargs): super(Reproductor, self).__init__() self.transcurso = 0 # Centramos la ventana principal self.centrar() # Inicializamos el modulo QMediaPlayer self.media = QMediaPlayer() self.media.setVolume(5) self.reproducir.setEnabled(False) # Setup the playlist. self.lista_repro = QMediaPlaylist() self.media.setPlaylist(self.lista_repro) self.modelo = ListaModelo(self.lista_repro) self.lista.setModel(self.modelo) self.lista_repro.currentIndexChanged.connect(self.cambio_lista_repro) modelo_seleccion = self.lista.selectionModel() modelo_seleccion.selectionChanged.connect(self.seleccion_lista_repro) # ********** Inicializamos el modulo QVideoWidget ******* self.video = QVideoWidget() # Agregamos el modulo QVideoWidget al grid donde se mostrara el video self.reproductor.addWidget(self.video) # Tambien lo agregamos al modulo QMediaPlayer self.media.setVideoOutput(self.video) # Conectamos el boton de reproducir con su metodo correspondiente self.reproducir.clicked.connect(self.play_video) # Conectamos el Skider del tiempo con su metodo correspondiente self.tiempo.sliderMoved.connect(self.posicion_establecida) # ****** Conectamos los estados del modulo QMediaPlayer con sus correspondientes metodos ***** self.media.stateChanged.connect(self.cambios_video) self.media.positionChanged.connect(self.posicion_video) self.media.durationChanged.connect(self.duracion_video) self.total_duracion = 0 self.cargar.clicked.connect(self.abrir_archivo) #self.marco.origen.connect(self.arrastrar_soltar) self.parar.pressed.connect(self.media.stop) self.atras.pressed.connect(self.lista_repro.previous) self.adelante.pressed.connect(self.lista_repro.next) self.volumen.valueChanged.connect(self.media.setVolume) self.logo_volumen.clicked.connect(self.silenciar) self.lista.doubleClicked.connect(self.play_video) self.video.keyPressEvent = self.keyPressEvent # ****** Boton de menu ****** self.lista.setMinimumSize(QSize(0, 0)) self.lista_visible = True self.menu.clicked.connect(self.boton_menu) self.setAcceptDrops(True) self.primera_reproduccion = True self.show() # ---------------- Inicio de Metodos --------------------------- # # Detectamos una tecla presionada def keyPressEvent(self, event): if event.key() == Qt.Key_F11 or event.key() == Qt.Key_Escape and self.video.isFullScreen(): self.fullscreen_change() elif event.key() == Qt.Key_Space: self.play_video() #Pantalla completa def fullscreen_change(self): if self.video.isFullScreen(): self.video.setFullScreen(False) self.lista.setMinimumSize(QSize(300, 16777215)) else: self.video.setFullScreen(True) # Ocultar y mostrar la lista de reproduccion def boton_menu(self): if self.lista_visible: self.lista.setVisible(False) size_policy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.marco.setSizePolicy(size_policy) self.lista_visible = False else: self.lista.setVisible(True) self.lista_visible = True # Metodos para arrastrar y soltar en la lista de reproduccion def dragEnterEvent(self, e): if e.mimeData().hasUrls(): e.acceptProposedAction() # Metodos para arrastrar y soltar en la lista de reproduccion def dropEvent(self, e): for url in e.mimeData().urls(): self.lista_repro.addMedia(QMediaContent(url)) self.lista_repro.setPlaybackMode(QMediaPlaylist.Loop) self.media.setPlaylist(self.lista_repro) self.reproducir.setEnabled(True) self.reproductor.removeWidget(self.logo) self.media.play() self.modelo.layoutChanged.emit() """ # If not playing, seeking to first of newly added + play. if self.media.state() != QMediaPlayer.PlayingState: #i = self.lista_repro.mediaCount() - len(e.mimeData().urls()) #print(i) #self.lista_repro.setCurrentIndex(i) self.reproducir.setEnabled(True) self.reproductor.removeWidget(self.logo) #self.media.setPlaylist(playlist) self.media.play() """ # Metodo para cargar el video en cuestion def abrir_archivo(self): archivo, _ = QFileDialog.getOpenFileName(self, ' Abrir Archivo !!!', 'C:/Users/Duque/Videos', 'Solo Video (*.mp4 *.mov *.flv *.mkv *.ts *.mts *.avi);; Solo Audio (*.mp3 *.flac *.m4a *.wav)') if archivo != '': self.reproductor.removeWidget(self.logo) self.primera_reproduccion = False self.lista_repro.addMedia(QMediaContent(QUrl.fromLocalFile(archivo))) self.reproducir.setEnabled(True) self.modelo.layoutChanged.emit() # Metodo para el cambio en la lista de reproduccion def cambio_lista_repro(self, i): if i > -1: ix = self.modelo.index(i) self.lista.setCurrentIndex(ix) # Metodo para la seleccion en la lista de reproduccion def seleccion_lista_repro(self, ix): i = ix.indexes()[0].row() self.lista_repro.setCurrentIndex(i) # Metodo para silenciar el audio o video def silenciar(self): if self.media.isMuted(): self.media.setMuted(False) icon = QIcon() icon.addPixmap(QPixmap(":/img/altavoz3.png"), QIcon.Normal, QIcon.Off) self.logo_volumen.setIcon(icon) self.logo_volumen.setToolTip(' Silenciar ') else: self.media.setMuted(True) icon = QIcon() icon.addPixmap(QPixmap(":/img/altavoz4.png"), QIcon.Normal, QIcon.Off) self.logo_volumen.setIcon(icon) self.logo_volumen.setToolTip(' Restablecer Sonido ') @pyqtSlot(str) def arrastrar_soltar(self, archivo): if archivo != '': self.media.setMedia(QMediaContent(QUrl.fromLocalFile(archivo))) self.reproducir.setEnabled(True) self.lista_repro.addMedia(QMediaContent(QUrl.fromLocalFile(archivo))) self.modelo.layoutChanged.emit() # Metodo para reproducir el video en cuestion def play_video(self): if self.primera_reproduccion: self.reproductor.removeWidget(self.logo) self.primera_reproduccion = False if self.media.state() == QMediaPlayer.PlayingState: self.media.pause() else: self.media.play() # Metodo que detecta el estado de cambio del boton reproducir de play a pausa y viceversa def cambios_video(self, state): if self.media.state() == QMediaPlayer.PlayingState: icon = QIcon() icon.addPixmap(QPixmap(":/img/pausa.png"), QIcon.Normal, QIcon.Off) self.reproducir.setIcon(icon) self.reproducir.setToolTip(' Pausar Video o Audio ') QToolTip.setFont(QFont('Cascadia Code PL', 18)) else: icon = QIcon() icon.addPixmap(QPixmap(":/img/play.svg"), QIcon.Normal, QIcon.Off) self.reproducir.setIcon(icon) self.reproducir.setToolTip(' Reproducir Video o Audio ') QToolTip.setFont(QFont('Cascadia Code PL', 18)) def duracion_video(self, duracion): """ # Detecta la duración del vídeo en el slider. """ self.tiempo.setMaximum(duracion) self.total_duracion = duracion # Metodo que detecta la posiscion del video en el slider def posicion_video(self, posicion): if posicion >= 0: reproduccion = f'{detalle_tiempo(posicion)} || {detalle_tiempo(self.total_duracion)}' self.datos.setText(reproduccion) self.tiempo.blockSignals(True) self.tiempo.setValue(posicion) self.tiempo.blockSignals(False) # Metodo que detecta la posiscion establecida del modulo QMediaPlayer def posicion_establecida(self, position): self.media.setPosition(position) def errores(self): self.reproducir.setEnabled(False) # self.lbl.setText("Error: " + self.media.errorString()) # Metodo para centrar la ventana principal def centrar(self): ventana = self.frameGeometry() centro = QDesktopWidget().availableGeometry().center() # print(centro) ventana.moveCenter(centro) self.move(ventana.topLeft())
class videoPlayer(QWidget): # 视频播放类 def __init__(self, parent=None): # 构造函数 super(videoPlayer, self).__init__(parent=parent) # 类的继承 self.mainwindow = parent self.length = 0 # 视频总时长 self.position = 0 # 视频当前时长 self.count = 0 self.player_status = -1 # 设置窗口 self.setGeometry(300, 50, 800, 600) #大小,与桌面放置位置 # self.setWindowIcon(QIcon(':/images/video_player_icon.png')) # 程序图标 # self.setWindowTitle(titleName) # 窗口名称 # self.setWindowFlags(Qt.WindowCloseButtonHint | Qt.WindowMinimizeButtonHint) # 设置窗口背景 self.palette = QPalette() self.palette.setColor(QPalette.Background, Qt.black) self.setPalette(self.palette) self.now_position = QLabel("/ 00:00") # 目前时间进度 self.all_duration = QLabel('00:00') # 总的时间进度 self.all_duration.setStyleSheet('''QLabel{color:#000000}''') self.now_position.setStyleSheet('''QLabel{color:#000000}''') #视频插件 self.video_widget = QVideoWidget(self) self.video_widget.setGeometry(QRect(0, 0, 1200, 700)) #大小,与桌面放置位置 #self.video_widget.resize(1200, 700) # 设置插件宽度与高度 #self.video_widget.move(0, 30) # 设置插件放置位置 self.video_palette = QPalette() self.video_palette.setColor(QPalette.Background, Qt.black) # 设置播放器背景 self.video_widget.setPalette(self.video_palette) video_widget_color = "background-color:#000000" self.video_widget.setStyleSheet(video_widget_color) #布局容器 self.verticalLayout = QVBoxLayout() self.verticalLayout.setSpacing(0) #self.verticalLayout.setContentsMargins(0, 5, 0, 10) self.layout = QHBoxLayout() self.layout.setSpacing(15) # 各个插件的间距 # 设置播放器 self.player = QMediaPlayer(self) self.player.setVideoOutput(self.video_widget) #设置播放按钮事件 self.player.durationChanged.connect(self.get_duration_func) # self.player.positionChanged.connect(self.progress) # 媒体播放时发出信号 self.player.mediaStatusChanged.connect(self.playerStatusChanged) self.player.error.connect(self.player_error) # 播放按钮 self.play_btn = QPushButton(self) self.play_btn.setIcon(QIcon(':/images/play_btn_icon.png')) # 设置按钮图标,下同 self.play_btn.setIconSize(QSize(35, 35)) self.play_btn.setStyleSheet( '''QPushButton{border:none;}QPushButton:hover{border:none;border-radius:35px;}''' ) self.play_btn.setCursor(QCursor(Qt.PointingHandCursor)) self.play_btn.setToolTip("播放") self.play_btn.setFlat(True) #self.play_btn.hide() #isHidden() #判定控件是否隐藏 #isVisible() 判定控件是否显示 self.play_btn.clicked.connect(self.start_button) #音量条 self.volume_slider = QSlider(Qt.Horizontal) # 声音设置 self.volume_slider.setMinimum(0) # 音量0到100 self.volume_slider.setMaximum(100) self.volume_slider.valueChanged.connect(self.volumes_change) self.volume_slider.setStyleSheet('''QSlider{} QSlider::sub-page:horizontal:disabled{background: #00009C; border-color: #999; } QSlider::add-page:horizontal:disabled{background: #eee; border-color: #999; } QSlider::handle:horizontal:disabled{background: #eee; border: 1px solid #aaa; border-radius: 4px; } QSlider::add-page:horizontal{background: #575757; border: 0px solid #777; height: 10px;border-radius: 2px; } QSlider::handle:horizontal:hover{background:qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0.6 #2A8BDA, stop:0.778409 rgba(255, 255, 255, 255)); width: 11px; margin-top: -3px; margin-bottom: -3px; border-radius: 5px; } QSlider::sub-page:horizontal{background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c4c4); background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,stop: 0 #5DCCFF, stop: 1 #1874CD); border: 1px solid #4A708B; height: 10px; border-radius: 2px; } QSlider::groove:horizontal{border: 1px solid #4A708B; background: #C0C0C0; height: 5px; border-radius: 1px; padding-left:-1px; padding-right:-1px;} QSlider::handle:horizontal{background: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0.6 #45ADED, stop:0.778409 rgba(255, 255, 255, 255)); width: 11px; margin-top: -3px; margin-bottom: -3px; border-radius: 5px; }''' ) #视频播放进度条 self.video_slider = QSlider(Qt.Horizontal, self) # 视频进度拖拖动 self.video_slider.setMinimum(0) # 视频进度0到100% #self.video_slider.setMaximum(100) self.video_slider.setSingleStep(1) self.video_slider.setGeometry(QRect(0, 0, 200, 10)) self.video_slider.sliderReleased.connect(self.video_silder_released) self.video_slider.sliderPressed.connect(self.video_silder_pressed) self.video_slider.setStyleSheet('''QSlider{} QSlider::sub-page:horizontal:disabled{background: #00009C; border-color: #999; } QSlider::add-page:horizontal:disabled{background: #eee; border-color: #999; } QSlider::handle:horizontal:disabled{background: #eee; border: 1px solid #aaa; border-radius: 4px; } QSlider::add-page:horizontal{background: #575757; border: 0px solid #777; height: 10px;border-radius: 2px; } QSlider::handle:horizontal:hover{background:qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0.6 #2A8BDA, stop:0.778409 rgba(255, 255, 255, 255)); width: 11px; margin-top: -3px; margin-bottom: -3px; border-radius: 5px; } QSlider::sub-page:horizontal{background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c4c4); background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,stop: 0 #5DCCFF, stop: 1 #1874CD); border: 1px solid #4A708B; height: 10px; border-radius: 2px; } QSlider::groove:horizontal{border: 1px solid #4A708B; background: #C0C0C0; height: 5px; border-radius: 1px; padding-left:-1px; padding-right:-1px;} QSlider::handle:horizontal{background: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0.6 #45ADED, stop:0.778409 rgba(255, 255, 255, 255)); width: 11px; margin-top: -3px; margin-bottom: -3px; border-radius: 5px; }''' ) #静音按钮 self.mute_button = QPushButton('') self.mute_button.clicked.connect(self.mute) self.mute_button.setIconSize(QSize(30, 30)) self.mute_button.setStyleSheet( '''QPushButton{border:none;}QPushButton:hover{border:none;}''') self.mute_button.setCursor(QCursor(Qt.PointingHandCursor)) self.mute_button.setToolTip("播放") self.mute_button.setFlat(True) self.mute_button.setIcon(QIcon(':/images/sound_btn_icon.png')) #暂停按钮 self.pause_btn = QPushButton('') self.pause_btn.setIcon(QIcon(':/images/stop_btn_icon.png')) self.pause_btn.clicked.connect(self.stop_button) self.pause_btn.setIconSize(QSize(35, 35)) self.pause_btn.setStyleSheet( '''QPushButton{border:none;}QPushButton:hover{border:none;}''') self.pause_btn.setCursor(QCursor(Qt.PointingHandCursor)) self.pause_btn.setToolTip("播放") self.pause_btn.setFlat(True) self.pause_btn.hide() #音量值和音量显示标签 self.volume_value = QLabel() self.volume_value.setText(' ' * 5) self.volume_value.setStyleSheet('''QLabel{color:#000000;}''') self.volume_t = QLabel() self.volume_t.setStyleSheet('''QLabel{color:#000000;}''') #视频文件打开按钮 self.open_btn = QPushButton('Open') self.open_btn.clicked.connect(self.getfile) #全屏按钮 self.screen_btn = QPushButton('') self.screen_btn.setIcon( QIcon(QPixmap(':/images/fullsrceen_btn_icon.png'))) self.screen_btn.setIconSize(QSize(38, 38)) self.screen_btn.setStyleSheet( '''QPushButton{border:none;}QPushButton:hover{border:1px solid #F3F3F5;border-radius:35px;}''' ) self.screen_btn.setCursor(QCursor(Qt.PointingHandCursor)) self.screen_btn.setToolTip("播放") self.screen_btn.setFlat(True) self.screen_btn.clicked.connect(self.fullscreen) #添加按钮组件 self.verticalLayout.addStretch() self.layout.addWidget(self.play_btn, 0, Qt.AlignCenter | Qt.AlignVCenter) self.layout.addWidget(self.pause_btn, 0, Qt.AlignCenter | Qt.AlignVCenter) # 插件,与前一个模块的距离,位置 self.layout.addWidget(self.all_duration, 0, Qt.AlignCenter | Qt.AlignVCenter) self.layout.addWidget(self.now_position, 0, Qt.AlignCenter | Qt.AlignVCenter) self.layout.addWidget(self.video_slider, 15, Qt.AlignVCenter | Qt.AlignVCenter) self.layout.addWidget(self.mute_button, 0, Qt.AlignCenter | Qt.AlignVCenter) self.layout.addWidget(self.volume_slider, 0, Qt.AlignCenter | Qt.AlignVCenter) self.layout.addWidget(self.volume_value, 0, Qt.AlignCenter | Qt.AlignVCenter) #self.layout.addWidget(self.screen_btn) #self.layout.addWidget(self.open_btn) self.verticalLayout.addLayout(self.layout) #self.verticalLayout.addLayout(self.layout) self.setLayout(self.verticalLayout) def player_error(self, errorCode): print('error = ' + str(errorCode)) try: if errorCode == 0: pass elif errorCode == 1: self.showAlertWindow('errorCode:1 \n\n无效视频源。') elif errorCode == 2: self.showAlertWindow('errorCode:2 \n\n不支持的媒体格式') elif errorCode == 3: self.showAlertWindow('errorCode:3 \n\n网络错误') elif errorCode == 4: self.showAlertWindow('errorCode:4 \n\n没有权限播放该视频') elif errorCode == 5: self.showAlertWindow('errorCode:5 \n\n视频服务不存在,无法继续播放。') else: self.showAlertWindow('未知错误') except: self.showAlertWindow('视频加载异常') def video_silder_pressed(self): if self.player.state != 0: self.player.pause() def playerStatusChanged(self, status): self.player_status = status if status == 7: self.play_btn.show() self.pause_btn.hide() #print('playerStatusChanged =' + str(status) + '...............') def resizeEvent(self, e): #print(e.size().width(), e.size().height()) newSize = e.size() self.video_widget.setGeometry(0, 0, newSize.width(), newSize.height() - 50) #self.video_widget.setGeometry(0, 0, 0, 0) def closeEvent(self, e): self.player.stop() def get_duration_func(self, d): try: end_number = int(d / 1000 / 10) + 1 #print('end_number = ' + str(end_number)) sum = 0 for n in range(1, end_number): sum = sum + n vv = int((100 / (d / 1000)) * (d / 1000)) self.video_slider.setMaximum(d) #self.video_slider.setMaximum(vv + sum) #print(100 + sum) all_second = int(d / 1000 % 60) # 视频播放时间 all_minute = int(d / 1000 / 60) if all_minute < 10: if all_second < 10: self.all_duration.setText('0' + str(all_minute) + ':0' + str(all_second)) else: self.all_duration.setText('0' + str(all_minute) + ':' + str(all_second)) else: if all_second < 10: self.all_duration.setText( str(all_minute) + ':0' + str(all_second)) else: self.all_duration.setText( str(all_minute) + ':' + str(all_second)) except Exception as e: pass def mouseDoubleClickEvent(self, e): try: #print('mouseDoubleClickEvent................... = ' + str(self.player.state())) if self.player.state() == 2: #视频暂停 self.player.play() self.play_btn.hide() self.pause_btn.show() elif self.player.state() == 1: # 正在播放 self.player.pause() self.play_btn.show() self.pause_btn.hide() else: #视频停止 self.play_btn.hide() self.pause_btn.show() self.player.setPosition(0) self.video_slider.setValue(0) self.player.play() except Exception as e: pass def start_button(self): # 视频播放按钮 try: self.play_btn.hide() self.pause_btn.show() if self.player_status == 7: self.video_slider.setValue(0) self.player.setPosition(0) self.player.play() except Exception as e: pass def stop_button(self): # 视频暂停按钮 self.play_btn.show() self.pause_btn.hide() self.player.pause() def getfile(self, filepath): # 打开视频文件 try: #print(str(filepath)) url = QUrl.fromLocalFile(filepath) if url.isValid(): self.player.setMedia(QMediaContent(url)) # 返回该文件地址,并把地址放入播放内容中 self.player.setVolume(50) # 设置默认打开音量即为音量条大小 self.volume_value.setText(str(50)) self.volume_slider.setValue(50) else: self.showAlertWindow('视频地址无效') except Exception as e: self.showAlertWindow() def clearVolumeValue(): self.volume_value.setText(' ' * 5) def volumes_change(self): # 拖动进度条设置声音 try: size = self.volume_slider.value() if size: # 但进度条的值不为0时,此时音量不为静音,音量值即为进度条值 self.player.setMuted(False) self.player.setVolume(size) volume_value = str(size) + ' ' * 4 self.volume_value.setText(volume_value) #print(size) self.mute_button.setIcon(QIcon(':/images/sound_btn_icon.png')) else: self.player.setMuted(True) self.mute_button.setIcon(QIcon(':/images/mute_btn_icon.png')) self.player.setVolume(0) volume_value = '0' + ' ' * 4 self.volume_value.setText(volume_value) if len(str(size)) == 1: volume_value = str(size) + ' ' * 4 elif len(str(size)) == 2: volume_value = str(size) + ' ' * 3 else: volume_value = str(size) + ' ' * 2 self.volume_value.setText(volume_value) except Exception as e: pass def mute(self): try: if self.player.isMuted(): self.mute_button.setIcon(QIcon(':/images/sound_btn_icon.png')) self.player.setMuted(False) self.volume_slider.setValue(50) volume_value = '50' + ' ' * 4 self.volume_value.setText(volume_value) else: self.mute_button.setIcon(QIcon(':/images/mute_btn_icon.png')) self.player.setMuted(True) # 若不为静音,则设置为静音,音量置为0 self.volume_slider.setValue(0) volume_value = '0' + ' ' * 4 self.volume_value.setText(volume_value) except Exception as e: pass def progress(self): # 视频进度条自动释放与播放时间 try: self.length = self.player.duration() + 1 self.position = self.player.position() #print(str(self.length) + ':' + str(self.position)) self.count += 1 video_silder_maximum = self.video_slider.maximum() #video_silder_value = int(((video_silder_maximum / (self.length / 1000)) * (self.position / 1000))) #self.video_slider.setValue(video_silder_value + self.count) self.video_slider.setValue(self.position) #print('video_slider_value = ' + str(video_silder_value + self.count)) now_second = int(self.position / 1000 % 60) now_minute = int(self.position / 1000 / 60) self.mainwindow.resultlist2.addItem("{0:02d} : {1:02d}".format( now_minute, now_second)) #print(str(now_minute) + ':' + str(now_second)) if now_minute < 10: if now_second < 10: self.now_position.setText('/ 0' + str(now_minute) + ':0' + str(now_second)) else: self.now_position.setText('/ 0' + str(now_minute) + ':' + str(now_second)) else: #print('now_minute < 10' + str(now_minute) + ':' + str(now_second)) if now_second < 10: #print('now_second < 10' + str(now_minute) + ':' + str(now_second)) #self.now_position.setText(str(now_minute) + ':0' + str(now_second)) self.now_position.setText('/ ' + str(now_minute) + ':0' + str(now_second)) else: #print('now_second > 10' + str(now_minute) + ':' + str(now_second)) self.now_position.setText('/ ' + str(now_minute) + ':' + str(now_second)) except Exception as e: pass def video_silder_released(self): # 释放滑条时,改变视频播放进度 try: #print('video_silder_released......') if self.player.state() != 0: self.player.setPosition(self.video_slider.value()) self.player.play() else: #如果视频是停止状态,则拖动进度条无效 self.video_slider.setValue(0) except Exception as e: pass def fullscreen(self): self.showFullScreen() def keyPressEvent(self, event): # 重新改写按键 if event.key() == Qt.Key_Escape: self.winquit() def winquit(self): # 退出窗口 self.showNormal() def showAlertWindow(self, msg='视频加载出错!'): reply = QMessageBox.information(self, "消息框标题", msg, QMessageBox.Yes) def setWindowTitleName(self, titleName): self.setWindowTitle(titleName) # 窗口名称
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 Demo(QWidget): def __init__(self): super(Demo, self).__init__() self.time_label = QLabel(self) self.volume_slider = QSlider(self) self.progress_slider = QSlider(self) self.sound_btn = QPushButton(self) self.previous_btn = QPushButton(self) self.play_pause_btn = QPushButton(self) self.next_btn = QPushButton(self) self.mode_btn = QPushButton(self) self.list_btn = QPushButton(self) self.list_widget = QListWidget(self) self.h1_layout = QHBoxLayout() self.h2_layout = QHBoxLayout() self.all_v_layout = QVBoxLayout() self.playlist = QMediaPlaylist(self) self.player = QMediaPlayer(self) self.widget_init() self.layout_init() self.signal_init() def widget_init(self): self.time_label.setText('--/--') self.volume_slider.setRange(0, 100) self.volume_slider.setValue(100) self.volume_slider.setOrientation(Qt.Horizontal) self.progress_slider.setEnabled(False) self.progress_slider.setOrientation(Qt.Horizontal) self.sound_btn.setIcon(QIcon('images/sound_on.png')) self.previous_btn.setIcon(QIcon('images/previous.png')) self.play_pause_btn.setIcon(QIcon('images/play.png')) self.next_btn.setIcon(QIcon('images/next.png')) self.mode_btn.setIcon(QIcon('images/list_loop.png')) self.list_btn.setIcon(QIcon('images/show.png')) self.player.setPlaylist(self.playlist) self.media_list = ['/Users/louis/Downloads/music1.mp3', '/Users/louis/Downloads/music2.mp4', '/Users/louis/Downloads/music3.mp3'] for m in self.media_list: self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(m))) self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) self.list_widget.addItems([m.split('/')[-1] for m in self.media_list]) def layout_init(self): self.h1_layout.addWidget(self.progress_slider) self.h1_layout.addWidget(self.time_label) self.h2_layout.addWidget(self.volume_slider) self.h2_layout.addWidget(self.sound_btn) self.h2_layout.addWidget(self.previous_btn) self.h2_layout.addWidget(self.play_pause_btn) self.h2_layout.addWidget(self.next_btn) self.h2_layout.addWidget(self.mode_btn) self.h2_layout.addWidget(self.list_btn) self.all_v_layout.addLayout(self.h1_layout) self.all_v_layout.addLayout(self.h2_layout) self.all_v_layout.addWidget(self.list_widget) self.all_v_layout.setSizeConstraint(QVBoxLayout.SetFixedSize) self.setLayout(self.all_v_layout) def signal_init(self): self.sound_btn.clicked.connect(lambda: self.btn_func(self.sound_btn)) self.previous_btn.clicked.connect(lambda: self.btn_func(self.previous_btn)) self.play_pause_btn.clicked.connect(lambda: self.btn_func(self.play_pause_btn)) self.next_btn.clicked.connect(lambda: self.btn_func(self.next_btn)) self.mode_btn.clicked.connect(lambda: self.btn_func(self.mode_btn)) self.list_btn.clicked.connect(lambda: self.btn_func(self.list_btn)) self.volume_slider.valueChanged.connect(self.volume_slider_func) self.list_widget.doubleClicked.connect(self.list_play_func) self.player.durationChanged.connect(self.get_duration_func) self.player.positionChanged.connect(self.get_position_func) self.progress_slider.sliderMoved.connect(self.update_position_func) def btn_func(self, btn): if btn == self.sound_btn: if self.player.isMuted(): self.player.setMuted(False) self.sound_btn.setIcon(QIcon('images/sound_on')) else: self.player.setMuted(True) self.sound_btn.setIcon(QIcon('images/sound_off')) elif btn == self.previous_btn: if self.playlist.currentIndex() == 0: self.playlist.setCurrentIndex(self.playlist.mediaCount() - 1) else: self.playlist.previous() elif btn == self.play_pause_btn: if self.player.state() == 1: self.player.pause() self.play_pause_btn.setIcon(QIcon('images/play.png')) else: self.player.play() self.play_pause_btn.setIcon(QIcon('images/pause.png')) elif btn == self.next_btn: if self.playlist.currentIndex() == self.playlist.mediaCount() - 1: self.playlist.setCurrentIndex(0) else: self.playlist.next() elif btn == self.mode_btn: if self.playlist.playbackMode() == 2: self.playlist.setPlaybackMode(QMediaPlaylist.Loop) self.mode_btn.setIcon(QIcon('images/item_loop.png')) elif self.playlist.playbackMode() == 3: self.playlist.setPlaybackMode(QMediaPlaylist.Random) self.mode_btn.setIcon(QIcon('images/random.png')) elif self.playlist.playbackMode() == 4: self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) self.mode_btn.setIcon(QIcon('images/list_loop.png')) elif btn == self.list_btn: if self.list_widget.isHidden(): self.list_widget.show() self.list_btn.setIcon(QIcon('images/show.png')) else: self.list_widget.hide() self.list_btn.setIcon(QIcon('images/hide.png')) def volume_slider_func(self, value): self.player.setVolume(value) if value == 0: self.sound_btn.setIcon(QIcon('images/sound_off.png')) else: self.sound_btn.setIcon(QIcon('images/sound_on.png')) def list_play_func(self): self.playlist.setCurrentIndex(self.list_widget.currentRow()) self.player.play() self.play_pause_btn.setIcon(QIcon('images/pause.png')) def get_duration_func(self, d): self.progress_slider.setRange(0, d) self.progress_slider.setEnabled(True) self.get_time_func(d) def get_time_func(self, d): seconds = int(d / 1000) minutes = int(seconds / 60) seconds -= minutes * 60 if minutes == 0 and seconds == 0: self.time_label.setText('--/--') self.play_pause_btn.setIcon(QIcon('images/play.png')) else: self.time_label.setText('{}:{}'.format(minutes, seconds)) def get_position_func(self, p): self.progress_slider.setValue(p) def update_position_func(self, v): self.player.setPosition(v) d = self.progress_slider.maximum() - v self.get_time_func(d)
class Control: """A class that handles the logic behind the program by manipulating the GUI classes and calling their methods in response to received signals.""" MAGIC = b"\x01\xff" def __init__(self, screens: list) -> None: self.player = QMediaPlayer() self.player.setAudioRole(QAudio.MusicRole) self.playlist = QMediaPlaylist() self.player.setPlaylist(self.playlist) self.mainWindow = MainWindow(self, screens) self.mainArea = self.mainWindow.centralWidget().upperBox.mainArea self.songList = self.mainWindow.centralWidget().upperBox.songList self.mediaControlArea = self.mainWindow.centralWidget( ).mediaControlArea self.mainWindow.show() self.library = None self.currentSong = None self.playing = False self.random = False self.repeat = 0 self.volume = 50 self.volumeChange(self.volume) self.mediaControlArea.volumeControl.setValue(self.volume) self.mainTimer = QTimer() self.mainTimer.setInterval(100) self.mainTimer.timeout.connect(self.updateSongProgress) self.mainTimer.start() self.libraryUpdateTimer = QTimer() self.libraryUpdateTimer.setInterval(15_000) self.libraryUpdateTimer.timeout.connect(self.updateLibrary) self.libraryUpdateTimer.start() self._connection = None self.connections() self.displayedType = None self.displayedName = None self.types = None self.songListWidth = None values = self.load() if values: self.mainWindow.setGeometry(*values) self.volumeChange(self.volume) self.mediaControlArea.volumeControl.setValue(self.volume) self.setUpTimer = QTimer() self.setUpTimer.setInterval(20) self.setUpTimer.setSingleShot(True) self.setUpTimer.timeout.connect(self.setAreas) self.setUpTimer.start() def connections(self): self.player.currentMediaChanged.connect(self.updateCurrentSong) self.player.durationChanged.connect(self.updateSongProgressRange) self.player.stateChanged.connect(self.playerStatusChanged) self.mediaControlArea.previousButton.click.connect( self.playlist.previous) self.mediaControlArea.repeatButton.click.connect( self.repeatButtonClick) self.mediaControlArea.stopButton.click.connect(self.stopButtonClick) self.mediaControlArea.playButton.click.connect(self.playButtonClick) self.mediaControlArea.randomButton.click.connect( self.randomButtonClick) self.mediaControlArea.nextButton.click.connect(self.playlist.next) self.mediaControlArea.muteButton.click.connect(self.mute) self.mediaControlArea.songProgress.sliderMoved.connect( self.songProgressMove) self.mediaControlArea.volumeControl.sliderMoved.connect( self.volumeChange) def setAreas(self) -> None: """Called after the GUI is created to provide user with a feedback that the program is running in case a larger amount of songs will be added when the Library class is initialized.""" # TODO add a tooltip that will notify the user larger amount of songs is being loaded # (freezes the program as the execution moves to the Library class.) self.library = library.Library() self.types = { "artist": self.library.getSongsForArtist, "album": self.library.getSongsForAlbum, "playlist": self.library.getSongsForPlaylist } self.mainArea.setAreas(self.library) self.setUpTimer.deleteLater() self.setUpTimer = None self.getSongs(self.displayedType, self.displayedName) if self.songListWidth is not None: songListGeometry = self.songList.geometry() self.songList.preferredWidth = songListGeometry.width( ) - self.songListWidth self.mainWindow.centralWidget().upperBox.line.resizeWidgets( songListGeometry.width() - self.songListWidth) def updateLibrary(self) -> None: self.library.update() self.mainArea.updateView(self.library) def updateCurrentSong(self) -> None: """Update all areas that may display information about the currently playing song - SongList, Now Playing tab, BottomBox""" media = self.player.currentMedia() self.currentSong = media.request().url().toLocalFile().replace( "/", "\\") if self.currentSong in self.library.library: self.songList.updateActiveSong(self.currentSong) self.mainArea.updateActiveSong(self.playlist.currentIndex()) songEntry = self.library.library[self.currentSong] self.mediaControlArea.updateSongInfo( f"{songEntry[ARTIST]} - {songEntry[NAME]}") def updateSongProgressRange(self) -> None: """Updates the range of the slider that represents the song position.""" self.mediaControlArea.updateSongProgressRange(self.player.duration()) def playerStatusChanged(self) -> None: """Used to properly update the player look after the current playlist has finished.""" index = self.playlist.currentIndex() if index == -1: self.stopButtonClick() def getSongs(self, isType: str, name: str) -> None: """Retrieves the songs for a given artist, album or playlist based on type and passes the resulting list to the SongList class.""" if isType is None: isType = self.displayedType if name is None: name = self.displayedName orderBy = self.songList.buttonOrderBy.text() reverse = True if self.songList.buttonOrderReverse.text() == chr( 0x25bc) else False listForType = self.types[isType](name, orderBy, reverse) playlist = None if isType == "playlist": playlist = name if len(listForType) == 0: artists = self.library.artists if len(artists): listForType = self.library.getSongsForArtist(artists[0]) self.songList.updateSongList(listForType, self.library.library, self.currentSong, playlist, isType) self.displayedType = isType self.displayedName = name def playSongList(self, song: str = None) -> None: """Called when user double-clicks on an artist/album/playlist widget or a song in right-hand side panel.""" self.playlist.clear() index = 0 loopIndex = 0 for songPath in self.songList.garbageProtector: if song == songPath: index = loopIndex self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(songPath))) loopIndex += 1 if self.playlist.isEmpty(): return self.player.play() if index > 0: self.playlist.setCurrentIndex(index) self.playing = True self.mediaControlArea.playButton.updatePictures( bottom.pausePixmap, bottom.pauseHoverPixmap, False) self.mainArea.setNowPlayingArea(self.library) self.mainArea.updateActiveSong(self.playlist.currentIndex()) def playSongWidget(self, songPath: str, afterCurrent: bool = False) -> None: if afterCurrent: index = self.playlist.currentIndex() + 1 self.playlist.insertMedia( index, QMediaContent(QUrl.fromLocalFile(songPath))) else: self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(songPath))) self.mainArea.setNowPlayingArea(self.library) self.mainArea.updateActiveSong(self.playlist.currentIndex()) self.playing = True def removeFromNowPlaying(self, widget) -> None: if self.playlist.mediaCount() > 1: for row in range(self.mainArea.nowPlayingLayout.rowCount()): for column in range( self.mainArea.nowPlayingLayout.columnCount()): if self.mainArea.nowPlayingLayout.itemAtPosition( row, column).widget() is widget: self.playlist.removeMedia(row - 1) break else: continue break else: self.stopButtonClick() self.playlist.clear() self.mainArea.setNowPlayingArea(self.library) if self.playing: self.mainArea.updateActiveSong(self.playlist.currentIndex()) def playMediaWidget(self, isType: str, target: str, startOver: bool, afterCurrent: bool) -> None: """Called from MediaWidget - plays all songs for MediaWidget's type and name.""" if startOver: self.playlist.clear() if afterCurrent: index = self.playlist.currentIndex() + 1 for songPath in self.types[isType](target): self.playlist.insertMedia( index, QMediaContent(QUrl.fromLocalFile(songPath))) index += 1 else: for songPath in self.types[isType](target): self.playlist.addMedia( QMediaContent(QUrl.fromLocalFile(songPath))) if startOver: self.player.play() self.playing = True self.mediaControlArea.playButton.updatePictures( bottom.pausePixmap, bottom.pauseHoverPixmap, False) self.mainArea.setNowPlayingArea(self.library) self.mainArea.updateActiveSong(self.playlist.currentIndex()) def playFromNowPlaying(self, song: str) -> None: """Called when user double-clicks on a song in the Now Playing tab.""" for n in range(self.playlist.mediaCount()): media = self.playlist.media(n) if song == media.request().url().toLocalFile().replace("/", "\\"): self.playlist.setCurrentIndex(n) if not self.playing: self.player.play() self.playing = True return def createPlaylist(self, playlistName: str) -> None: self.library.createPlaylist(playlistName) self.mainArea.setMainAreaPlaylists(self.library) def addToExistingPlaylist(self, playlist: str, songOrWidget: str, isType: str) -> None: if isType in self.types: for song in self.types[isType](songOrWidget): self.library.addToPlaylist(playlist, song) else: self.library.addToPlaylist(playlist, songOrWidget) self.library.update() def removeFromPlaylist(self, playlist: str, song: str) -> None: self.library.deleteFromPlaylist(playlist, song) self.mainArea.setMainAreaPlaylists(self.library) self.library.update() self.getSongs("playlist", playlist) def renamePlaylist(self, playlistName: str, newPlaylistName: str) -> None: self.library.renamePlaylist(playlistName, newPlaylistName) self.mainArea.setMainAreaPlaylists(self.library) self.library.update() def deletePlaylist(self, playlistName: str) -> None: self.library.deletePlaylist(playlistName) self.mainArea.setMainAreaPlaylists(self.library) self.library.update() def addWatchedFolder(self, folder: str) -> None: """Adds a folder to the Library class. all mp3 files within the folder and its sub-folders will be added to the library and accessible to the player.""" self.library.addFolder(folder.replace("/", "\\")) self.mainArea.updateView(self.library) def removeWatchedFolder(self, folder: str) -> None: """Removes folder from the library, updates view and stops playback if the current song was in the now-removed folder.""" self.library.deleteFolder(folder) self.mainArea.updateView(self.library) if self.currentSong not in self.library.library: self.songList.updateSongList([], [], "", "") self.player.stop() self.playlist.clear() self.mediaControlArea.updateSongInfo("") self.songList.nowPlayingSong = None self.mainArea.nowPlayingSong = None self.playing = False self.mediaControlArea.updatePlayButton(self.playing, False) def playButtonClick(self, passMove: bool = True) -> None: if not self.playing: if self.playlist.isEmpty(): self.playSongList() return self.playing = True self.player.play() self.mainArea.updateActiveSong(self.playlist.currentIndex()) self.songList.updateActiveSong(self.currentSong) else: self.playing = False self.player.pause() self.mediaControlArea.updatePlayButton(self.playing, passMove) def repeatButtonClick(self) -> None: if self.repeat == 0: self.repeat = 1 self.playlist.setPlaybackMode(QMediaPlaylist.Loop) elif self.repeat == 1: self.repeat = 2 self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop) elif self.repeat == 2: self.repeat = 0 self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) self.mediaControlArea.updateRepeatButton(self.repeat) def randomButtonClick(self) -> None: if not self.random: self.random = True self.playlist.setPlaybackMode(QMediaPlaylist.Random) else: self.random = False self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) self.mediaControlArea.updateRandomButton(self.random) def stopButtonClick(self) -> None: self.playing = False self.player.stop() if self.songList.nowPlayingSong is not None: self.songList.nowPlayingSong.clear() if self.mainArea.nowPlayingSong is not None: self.mainArea.nowPlayingSong.clear() self.mediaControlArea.updatePlayButton(self.playing, False) def mute(self) -> None: if not self.player.isMuted(): self.player.setMuted(True) self.mediaControlArea.showMute() else: self.player.setMuted(False) self.volumeChange(self.volume) def volumeChange(self, volume: int) -> None: logVolume = QAudio.convertVolume(volume / 100, QAudio.LogarithmicVolumeScale, QAudio.LinearVolumeScale) * 100 self.player.setVolume(logVolume) self.volume = volume self.mediaControlArea.updateVolumeBar(volume) def songProgressMove(self, position: int) -> None: self.player.setPosition(position) def updateSongProgress(self) -> None: position = self.player.position() if 0 <= position < 2_000_000_000: if self.player.state() > 0: self.mediaControlArea.updateSongProgress(position) if self.playing: self.songList.activeSongPixmap() self.mainArea.activeSongPixmap() else: self.mediaControlArea.updateSongProgress(0) def disconnect(self): self.player.currentMediaChanged.disconnect() self.player.durationChanged.disconnect() self.player.stateChanged.disconnect() self.mediaControlArea.previousButton.click.disconnect() self.mediaControlArea.repeatButton.click.disconnect() self.mediaControlArea.stopButton.click.disconnect() self.mediaControlArea.playButton.click.disconnect() self.mediaControlArea.randomButton.click.disconnect() self.mediaControlArea.nextButton.click.disconnect() self.mediaControlArea.muteButton.click.disconnect() self.mediaControlArea.songProgress.sliderMoved.disconnect() self.mediaControlArea.volumeControl.sliderMoved.disconnect() def close(self) -> None: self.disconnect() self.player.stop() self.mainTimer.stop() self.save() def save(self) -> None: """Called on exit, saves current view, geometry and volume.""" with gzip.open(r"musicplayer\mpdata", "wb") as fh: fh.write(self.MAGIC) toBeWritten = struct.pack(f"<h{len(self.displayedType.encode())}s", len(self.displayedType.encode()), self.displayedType.encode()) fh.write(toBeWritten) fh.write(self.MAGIC) toBeWritten = struct.pack(f"<h{len(self.displayedName.encode())}s", len(self.displayedName.encode()), self.displayedName.encode()) fh.write(toBeWritten) fh.write(self.MAGIC) geo = self.mainWindow.geometry() toBeWritten = struct.pack("<4h", geo.x(), geo.y(), geo.width(), geo.height()) fh.write(toBeWritten) toBeWritten = struct.pack("<h", self.volume) fh.write(toBeWritten) toBeWritten = struct.pack("<h", self.songList.width()) fh.write(toBeWritten) def load(self) -> [bool, tuple]: """Called on startup, loads view, geometry and volume saved on previous run.""" try: with gzip.open(r"musicplayer\mpdata", "rb") as fh: if not fh.read(2) == self.MAGIC: return False length = fh.read(2) length = struct.unpack("<h", length)[0] displayedType = fh.read(length) displayedType = struct.unpack(f"<{length}s", displayedType)[0].decode("utf8") if displayedType in ["artist", "album", "playlist"]: self.displayedType = displayedType if not fh.read(2) == self.MAGIC: return False length = fh.read(2) length = struct.unpack("<h", length)[0] displayedName = fh.read(length) displayedName = struct.unpack(f"<{length}s", displayedName)[0].decode("utf8") if not fh.read(2) == self.MAGIC: return False self.displayedName = displayedName variables = [] for n in range(6): var = fh.read(2) var = struct.unpack("<h", var)[0] variables.append(var) x, y, width, height, volume, songListWidth = variables self.volume = volume self.songListWidth = songListWidth return x, y, width, height except Exception: return False
class Ui_Form(object): def setupUi(self, Form): Form.setObjectName("Form") Form.resize(1200, 720) Form.setMinimumSize(QtCore.QSize(200, 199)) Form.setStyleSheet("background-color:black;") self.isOnline = False self.isMini = False self.isOnTop = True self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.verticalLayout_2 = QtWidgets.QVBoxLayout(Form) self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setSpacing(0) self.verticalLayout_2.setObjectName("verticalLayout_2") self.mainFrame = QtWidgets.QFrame(Form) self.mainFrame.setMinimumSize(QtCore.QSize(200, 82)) self.mainFrame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.mainFrame.setFrameShadow(QtWidgets.QFrame.Raised) self.mainFrame.setObjectName("mainFrame") self.verticalLayout = QtWidgets.QVBoxLayout(self.mainFrame) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setSpacing(0) self.verticalLayout.setObjectName("verticalLayout") self.frame_3 = QtWidgets.QFrame(self.mainFrame) sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.frame_3.sizePolicy().hasHeightForWidth()) self.frame_3.setSizePolicy(sizePolicy) self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised) self.frame_3.setObjectName("frame_3") self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.frame_3) self.horizontalLayout_6.setContentsMargins(0, 0, 0, 0) self.horizontalLayout_6.setObjectName("horizontalLayout_6") self.Player_name = QtWidgets.QLabel(self.frame_3) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.Player_name.sizePolicy().hasHeightForWidth()) self.Player_name.setSizePolicy(sizePolicy) self.Player_name.setStyleSheet("QLabel\n" " {\n" " font: 12pt \"Helvetica\";\n" " color: white;\n" " border: 0px solid #076100;\n" " }") self.Player_name.setObjectName("status_label") self.horizontalLayout_6.addWidget(self.Player_name) spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_6.addItem(spacerItem) self.minimize_button = QtWidgets.QPushButton(self.frame_3) self.minimize_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.minimize_button.setText("") icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap("icon_sets/minimize.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.minimize_button.setIconSize(QSize(25, 17)) self.minimize_button.setMaximumSize(QSize(25, 17)) self.minimize_button.setIcon(icon) self.minimize_button.setIconSize(QtCore.QSize(27, 20)) # self.minimize_button.setFlat(True) self.minimize_button.setObjectName("minimize_button") self.horizontalLayout_6.addWidget(self.minimize_button) self.maximize_button = QtWidgets.QPushButton(self.frame_3) self.maximize_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.maximize_button.setText("") icon1 = QtGui.QIcon() icon1.addPixmap(QtGui.QPixmap("icon_sets/maximize.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.maximize_button.setIcon(icon1) self.maximize_button.setIconSize(QSize(25, 17)) self.maximize_button.setMaximumSize(QSize(25, 17)) self.maximize_button.setIconSize(QtCore.QSize(27, 20)) # self.maximize_button.setFlat(True) self.maximize_button.setObjectName("maximize_button") self.horizontalLayout_6.addWidget(self.maximize_button) self.cross_button = QtWidgets.QPushButton(self.frame_3) self.cross_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.cross_button.setText("") self.cross_button.setIconSize(QSize(25, 17)) self.cross_button.setMaximumSize(QSize(25, 17)) icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap("icon_sets/cross.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.cross_button.setIcon(icon2) self.cross_button.setIconSize(QtCore.QSize(27, 20)) # self.cross_button.setFlat(True) self.cross_button.setObjectName("cross_button") self.horizontalLayout_6.addWidget(self.cross_button) self.verticalLayout.addWidget(self.frame_3) self.video_playback = Videowidget(self.frame_3) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(200) sizePolicy.setHeightForWidth( self.video_playback.sizePolicy().hasHeightForWidth()) self.video_playback.setSizePolicy(sizePolicy) self.video_playback.setMinimumSize(QtCore.QSize(200, 100)) self.video_playback.setMouseTracking(False) self.video_playback.setTabletTracking(False) self.video_playback.setAcceptDrops(False) self.video_playback.setAutoFillBackground(False) self.video_playback.setObjectName("video_playback") self.video_playback.setStyleSheet("background-color:grey") self.verticalLayout.addWidget(self.video_playback) self.pos_frame = QtWidgets.QFrame(self.mainFrame) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(10) sizePolicy.setHeightForWidth( self.pos_frame.sizePolicy().hasHeightForWidth()) self.pos_frame.setSizePolicy(sizePolicy) self.pos_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.pos_frame.setFrameShadow(QtWidgets.QFrame.Raised) self.pos_frame.setObjectName("pos_frame") self.horizontalLayout = QtWidgets.QHBoxLayout(self.pos_frame) self.horizontalLayout.setObjectName("horizontalLayout") self.position_slider = PosSlider(self.pos_frame) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(100) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.position_slider.sizePolicy().hasHeightForWidth()) self.position_slider.setSizePolicy(sizePolicy) self.position_slider.setMouseTracking(True) self.position_slider.setAutoFillBackground(False) self.position_slider.setStyleSheet( "QSlider::handle:horizontal \n" " {\n" " background: transparent;\n" " width: 8px;\n" " }\n" "QSlider::groove:horizontal {\n" " border: 1px solid white;\n" " height: 8px;\n" " background: qlineargradient(y1: 0, y2: 1,stop: 0 #2e3436, stop: 1.0 #000000);\n" "}\n" " QSlider::sub-page:horizontal {\n" " background:qlineargradient( y1: 0, y2: 1,\n" " stop: 0 #42a6db, stop: 1 #0074e0); \n" " border: 1px solid white;\n" " height: 8px;\n" "}\n" "QSlider::handle:horizontal:hover {\n" " background: black;\n" " height: 8px;\n" " width: 8px;\n" " border: 1px solid white;\n" " }\n" "") self.position_slider.setOrientation(QtCore.Qt.Horizontal) self.position_slider.setInvertedAppearance(False) self.position_slider.setInvertedControls(False) self.position_slider.setObjectName("position_slider") self.horizontalLayout.addWidget(self.position_slider) self.time_status = QtWidgets.QLabel(self.pos_frame) font = QtGui.QFont() font.setFamily("Arial Rounded MT Bold") font.setPointSize(8) font.setBold(False) font.setItalic(False) font.setWeight(50) self.time_status.setFont(font) self.time_status.setStyleSheet( "QLabel\n" " {\n" " \n" " font: 8pt \"Arial Rounded MT Bold\";\n" " color: white;\n" " border: 0px solid #076100;\n" "\n" " }") self.time_status.setObjectName("time_status") self.horizontalLayout.addWidget(self.time_status) self.backslash = QtWidgets.QLabel(self.pos_frame) font = QtGui.QFont() font.setFamily("Arial Rounded MT Bold") font.setPointSize(8) font.setBold(False) font.setItalic(False) font.setWeight(50) self.backslash.setFont(font) self.backslash.setStyleSheet( "QLabel\n" " {\n" " \n" " font: 8pt \"Arial Rounded MT Bold\";\n" " color: white;\n" " border: 0px solid #076100;\n" "\n" " }") self.backslash.setObjectName("backslash") self.horizontalLayout.addWidget(self.backslash) self.duration_status = QtWidgets.QLabel(self.pos_frame) font = QtGui.QFont() font.setFamily("Arial Rounded MT Bold") font.setPointSize(8) font.setBold(False) font.setItalic(False) font.setWeight(50) self.duration_status.setFont(font) self.duration_status.setStyleSheet( "QLabel\n" " {\n" " \n" " font: 8pt \"Arial Rounded MT Bold\";\n" " color: white;\n" " border: 0px solid #076100;\n" "\n" " }") self.duration_status.setObjectName("duration_status") self.horizontalLayout.addWidget(self.duration_status) self.verticalLayout.addWidget(self.pos_frame) self.frame_2 = QtWidgets.QFrame(self.mainFrame) sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(22) # sizePolicy.setHeightForWidth(self.frame_2.sizePolicy().hasHeightForWidth()) self.frame_2.setSizePolicy(sizePolicy) self.frame_2.setContentsMargins(0, 0, 0, 0) self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised) self.frame_2.setObjectName("frame_2") self.frame_2.setStyleSheet("") self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.frame_2) self.horizontalLayout_4.setObjectName("horizontalLayout_4") self.play_button = QtWidgets.QPushButton(self.frame_2) self.play_button.setEnabled(False) self.play_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.play_button.setStyleSheet( "QPushButton[play=true]{image:url(icon_sets/play/play.png);width:22px;height:22px}\n" "QPushButton[play=false]{image:url(icon_sets/pause/pause.png);width:22px;height:22px }\n" ) self.play_button.setProperty("play", True) self.play_button.setText("") self.play_button.setObjectName("play_button") self.horizontalLayout_4.addWidget(self.play_button) self.playback_button = QtWidgets.QPushButton(self.frame_2) self.playback_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.playback_button.setStyleSheet( "QPushButton{image:url(icon_sets/playback/playback.png);width:22px;height:22px }\n" ) self.playback_button.setText("") self.playback_button.setObjectName("playback_button") self.horizontalLayout_4.addWidget(self.playback_button) self.always_on_top_button = QtWidgets.QPushButton(self.frame_2) self.always_on_top_button.setCursor( QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.always_on_top_button.setStyleSheet( "QPushButton[top=false]{image : url(icon_sets/always_on_top/top_off.png) }\n" "QPushButton[top=true]{image : url(icon_sets/always_on_top/top_on.png) }\n" ) self.always_on_top_button.setProperty("top", True) self.always_on_top_button.setText("") self.always_on_top_button.setObjectName("always_on_top_button") self.horizontalLayout_4.addWidget(self.always_on_top_button) self.miniplayer_button = QtWidgets.QPushButton(self.frame_2) self.miniplayer_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.miniplayer_button.setStyleSheet( "QPushButton[mini=false]{image : url(icon_sets/standard_player/standard.png) }\n" # "QPushButton[mini=false]:hover{ image:url(icon_sets/standard_player/.png) }\n" "QPushButton[mini=true]{image : url(icon_sets/mini_player/mini.png) }\n" # "QPushButton[mini=true]:hover{ image:url(icon_sets/mini_player/.png) }\n" ) self.miniplayer_button.setProperty("mini", False) self.miniplayer_button.setContentsMargins(0, 0, 0, 0) self.miniplayer_button.setText("") self.miniplayer_button.setObjectName("miniplayer_button") self.horizontalLayout_4.addWidget(self.miniplayer_button) self.open_File_button = QtWidgets.QPushButton(self.frame_2) self.open_File_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.open_File_button.setStyleSheet( "QPushButton{image:url(icon_sets/new_file/new_file.png);width:22px;height:22px }\n" ) self.open_File_button.setText("") self.open_File_button.setObjectName("playback_button") self.horizontalLayout_4.addWidget(self.open_File_button) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_4.addItem(spacerItem1) self.screenshot_button = QtWidgets.QPushButton(self.frame_2) self.screenshot_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.screenshot_button.setStyleSheet( "QPushButton{image : url(icon_sets/snapshot/snapshot.png);width:22px;height:22px} \n" ) self.screenshot_button.setText("") self.screenshot_button.setObjectName("screenshot_button") self.horizontalLayout_4.addWidget(self.screenshot_button) ''' Video Setting button for Video subs and dubs''' # self.video_setting_button = QtWidgets.QPushButton(self.frame_2) # self.video_setting_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) # self.video_setting_button.setText("") # self.video_setting_button.setIconSize(QtCore.QSize(22, 22)) # self.video_setting_button.setStyleSheet("QPushButton{image : url(icon_sets/video_setting/video_settings.png) }\n" # ) # self.video_setting_button.setObjectName("video_setting_button") # self.horizontalLayout_4.addWidget(self.video_setting_button) self.setting_button = QtWidgets.QPushButton(self.frame_2) self.setting_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.setting_button.setStyleSheet( "QPushButton{image : url(icon_sets/settings/settings.png) }\n") self.setting_button.setText("") self.setting_button.setObjectName("setting_button") self.horizontalLayout_4.addWidget(self.setting_button) self.Quality_box = QtWidgets.QComboBox(self.frame_2) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.Quality_box.sizePolicy().hasHeightForWidth()) self.Quality_box.setSizePolicy(sizePolicy) self.Quality_box.setStyleSheet( "QComboBox\n" " {\n" " border-image :url(icon_sets/quality/border.png);\n" " color: #fcffff;\n" " font-size: 8pt;\n" " font-weight: bold;\n" # " width: 41px;\n" " background-color: #000000;\n" " }\n" " QComboBox QAbstractItemView \n" " {\n" " background: #fcffff;\n" " border: 2px solid darkgray;\n" " selection-background-color: #000000;\n" " }\n" "QComboBox::drop-down {\n" " border: 0px;\n" " subcontrol-origin: padding;\n" " subcontrol-position: top right;\n" "\n" " border-top-right-radius: 3px;\n" " border-bottom-right-radius: 3px;\n" "}\n") self.Quality_box.setIconSize(QtCore.QSize(0, 0)) self.Quality_box.setDuplicatesEnabled(False) self.Quality_box.setObjectName("comboBox") self.Quality_box.addItem(" -") self.horizontalLayout_4.addWidget(self.Quality_box) self.volume_button = QtWidgets.QPushButton(self.frame_2) self.volume_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.volume_button.setText("") icon9 = QtGui.QIcon() icon9.addPixmap(QtGui.QPixmap("icon_sets/volume/volume1.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.volume_button.setIcon(icon9) self.volume_button.setIconSize(QtCore.QSize(22, 22)) self.volume_button.setCheckable(True) # self.volume_button.setFlat(True) self.volume_button.setObjectName("volume_button") self.horizontalLayout_4.addWidget(self.volume_button) self.volumeslider = VolSlider(self.frame_2) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.volumeslider.sizePolicy().hasHeightForWidth()) self.volumeslider.setSizePolicy(sizePolicy) self.volumeslider.setAutoFillBackground(False) self.volumeslider.setStyleSheet( "QSlider::handle:horizontal \n" " {\n" " background: transparent;\n" " width: 5px;\n" " }\n" "QSlider::groove:horizontal {\n" " border: 1px solid #444444;\n" " height: 5px;\n" " background: qlineargradient(y1: 0, y2: 1,stop: 0 grey, stop: 1.0 grey);\n" "}\n" " QSlider::sub-page:horizontal {\n" " background:qlineargradient( y1: 0, y2: 1,\n" " stop: 0 #42a6db, stop: 1 #0074e0); \n" " border: 1px solid #777;\n" " height: 5px;\n" "}\n" "QSlider::handle:horizontal:hover {\n" " background: black;\n" " height: 5px;\n" " width: 5px;\n" " border: 1px solid #0074e0;\n" " }\n" "QSlider::sub-page:horizontal:disabled{background:qlineargradient( y1: 0, y2: 1,\n" " stop: 0 #909090, stop: 1 #A8A8A8 );}\n" "") self.volumeslider.setOrientation(QtCore.Qt.Horizontal) self.volumeslider.setObjectName("volume_slider") self.horizontalLayout_4.addWidget(self.volumeslider) self.volume_percentage = QtWidgets.QLabel(self.frame_2) self.volume_percentage.setStyleSheet( "QLabel\n" " {\n" " font: 7pt \"Arial Rounded MT Bold\";\n" " color: white;\n" " border: 0px solid #076100;\n" " }") self.volume_percentage.setObjectName("volume_status") self.volume_percentage.setMinimumWidth(35) self.volume_percentage.setText(" 75 %") self.horizontalLayout_4.addWidget(self.volume_percentage) self.verticalLayout.addWidget(self.frame_2) self.frame = QtWidgets.QFrame(self.mainFrame) font = QtGui.QFont() font.setFamily("Lucida Console") self.frame.setFont(font) self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame.setFrameShadow(QtWidgets.QFrame.Raised) self.frame.setObjectName("frame") self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.frame) self.horizontalLayout_5.setObjectName("horizontalLayout_5") sizegrip_2 = QtWidgets.QSizeGrip(Form) sizegrip_2.setStyleSheet("image:url(icon_sets/.png)") self.horizontalLayout_5.addWidget( sizegrip_2, 0, QtCore.Qt.AlignBottom | QtCore.Qt.AlignLeft) # self.enter_url_label = QtWidgets.QLabel(self.frame) # font = QtGui.QFont() # font.setFamily("Arial Rounded MT Bold") # font.setPointSize(8) # font.setBold(False) # font.setItalic(False) # font.setWeight(50) # self.enter_url_label.setFont(font) # self.enter_url_label.setStyleSheet("QLabel\n" # " {\n" # " \n" # " font: 8pt \"Arial Rounded MT Bold\";\n" # " color: white;\n" # " border: 0px solid #076100;\n" # " }") # self.enter_url_label.setObjectName("enter_url_label") # self.horizontalLayout_5.addWidget(self.enter_url_label) self.url_box = QtWidgets.QComboBox(self.frame) sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(200) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.url_box.sizePolicy().hasHeightForWidth()) self.url_box.setSizePolicy(sizePolicy) self.url_box.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.url_box.setMouseTracking(False) self.url_box.setAcceptDrops(False) self.url_box.setWhatsThis("") self.url_box.setAccessibleDescription("") self.url_box.setAutoFillBackground(True) self.url_box.setStyleSheet("QComboBox\n" " {\n" " border: 2px solid #0074e0;\n" " color: #fcffff;\n" " font-size: 8pt;\n" " font-weight: bold;\n" " background-color: #000000;\n" " border-radius: 6px;\n" " }\n" " QComboBox QAbstractItemView \n" " {\n" " background: #fcffff;\n" " border: 2px solid darkgray;\n" " selection-background-color: #000000;\n" " }\n" "QComboBox::down-arrow {\n" " image: url(icon_sets/url/url4.png)\n" "}\n" "QComboBox::drop-down {\n" " subcontrol-origin: padding;\n" " subcontrol-position: top right;\n" " width: 20px;\n" " \n" " border-top-right-radius: 3px;\n" " border-bottom-right-radius: 3px;\n" "}") self.url_box.setInputMethodHints(QtCore.Qt.ImhUrlCharactersOnly) self.url_box.setEditable(True) self.url_box.setCurrentText("") self.url_box.setMaxVisibleItems(100) self.url_box.setMaxCount(100) self.url_box.setInsertPolicy(QtWidgets.QComboBox.InsertAtCurrent) self.url_box.setSizeAdjustPolicy( QtWidgets.QComboBox.AdjustToContentsOnFirstShow) self.url_box.setMinimumContentsLength(2) self.url_box.setIconSize(QtCore.QSize(20, 20)) self.url_box.setDuplicatesEnabled(False) self.url_box.setFrame(True) self.url_box.setObjectName("url_box") self.horizontalLayout_5.addWidget(self.url_box) self.verticalLayout.addWidget(self.frame) sizegrip_1 = QtWidgets.QSizeGrip(Form) sizegrip_1.setStyleSheet( "image:url(icon_sets/size.png);width:15; height:18;") self.horizontalLayout_5.addWidget( sizegrip_1, 0, QtCore.Qt.AlignBottom | QtCore.Qt.AlignRight) self.verticalLayout_2.addWidget(self.mainFrame) self.retranslateUi(Form) self.url_box.setCurrentIndex(-1) QtCore.QMetaObject.connectSlotsByName(Form) def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "Q-Stream Player")) self.Player_name.setText(_translate("Form", "Q-Stream Player")) self.time_status.setText(_translate("Form", "00:00:00")) self.backslash.setText(_translate("Form", "/")) self.duration_status.setText(_translate("Form", "00:00:00")) # self.enter_url_label.setText(_translate("Form", statusList[4])) # Set intial Volume self.volumeslider.setRange(0, 100) self.volumeslider.setValue(75) self.mediaPlayer.setVolume(75) self.position_slider.setRange(0, 100) # connecting buttons self.miniplayer_button.clicked.connect(self.setupMiniPlayer) self.position_slider.sliderMoved.connect(self.setPosition) self.position_slider.sliderMoved.connect(self.handleLabel) self.volume_button.clicked.connect(self.mute) self.volumeslider.valueChanged.connect(self.setVolume) self.screenshot_button.clicked.connect(self.screenshot) self.playback_button.clicked.connect(self.stopplayback) self.always_on_top_button.clicked.connect(self.checkOnTop) self.play_button.clicked.connect(self.play) self.open_File_button.clicked.connect(self.openFile) # self.video_setting_button.clicked.connect(self.handleQuality) self.setting_button.clicked.connect(self.handleSetting) self.Quality_box.currentTextChanged.connect(self.handleQuality) self.cross_button.clicked.connect(self.exit) self.maximize_button.clicked.connect(self.max) self.minimize_button.clicked.connect(self.min) # Shortcuts shortcut = QShortcut(QKeySequence('Esc'), self.video_playback) shortcut.activated.connect(self.EscFun) shortcut = QShortcut(QKeySequence('Space'), self.video_playback) shortcut.activated.connect(self.play) shortcut = QShortcut(QKeySequence('f'), self.video_playback) shortcut.activated.connect(self.fullscreen_video) shortcut = QShortcut(QKeySequence('c'), self.video_playback) shortcut.activated.connect(self.setupMiniPlayer) shortcut = QShortcut(QKeySequence('o'), self.video_playback) shortcut.activated.connect(self.openFile) shortcut = QShortcut(QKeySequence('a'), self.video_playback) shortcut.activated.connect(self.checkOnTop) shortcut = QShortcut(QKeySequence("Return"), self.video_playback) shortcut.activated.connect(self.playOnline) shortcut = QShortcut(QKeySequence('m'), self.video_playback) shortcut.activated.connect(self.mute) shortcut = QShortcut(QKeySequence(Qt.Key_Right), self.video_playback) shortcut.activated.connect(self.forwardSlider) shortcut = QShortcut(QKeySequence(Qt.Key_Left), self.video_playback) shortcut.activated.connect(self.backSlider) self.volupshortcut = QShortcut(QKeySequence(Qt.Key_Up), self.video_playback) self.volupshortcut.activated.connect(self.volumeUp) self.voldownshortcut = QShortcut(QKeySequence(Qt.Key_Down), self.video_playback) self.voldownshortcut.activated.connect(self.volumeDown) shortcut = QShortcut(QKeySequence(Qt.ControlModifier + Qt.Key_Right), self.video_playback) shortcut.activated.connect(self.forwardSlider10) shortcut = QShortcut(QKeySequence(Qt.ControlModifier + Qt.Key_Left), self.video_playback) shortcut.activated.connect(self.backSlider10) shortcut = QShortcut(QKeySequence(Qt.AltModifier + Qt.Key_Left), self.video_playback) shortcut.activated.connect(self.backSlider5) shortcut = QShortcut(QKeySequence(Qt.AltModifier + Qt.Key_Right), self.video_playback) shortcut.activated.connect(self.forwardSlider5) # loading history to Url Box items = self.load() self.url_box.addItems(items) self.url_box.setCurrentIndex(-1) # icon size # iconSize = QSize(5,5) # self.play_button.setIconSize(iconSize) # self.playback_button.setIconSize(iconSize) # self.screenshot_button.setIconSize(iconSize) # self.always_on_top_button.setIconSize(iconSize) # self.miniplayer_button.setIconSize(iconSize) # self.setting_button.setIconSize(iconSize) # self.volume_button.setIconSize(iconSize) # button size btnSize = QSize(22, 22) self.play_button.setMaximumSize(btnSize) self.playback_button.setMaximumSize(btnSize) self.screenshot_button.setMaximumSize(btnSize) self.always_on_top_button.setMaximumSize(btnSize) self.miniplayer_button.setMaximumSize(btnSize) # self.video_setting_button.setMaximumSize(btnSize) self.setting_button.setMaximumSize(btnSize) self.volume_button.setMaximumSize(btnSize) # set margin self.horizontalLayout.setContentsMargins(10, 5, 9, 0) self.horizontalLayout_4.setContentsMargins(9, 0, 9, 0) self.horizontalLayout_4.setSpacing(4) self.horizontalLayout_5.setContentsMargins(0, 5, 5, 5) self.horizontalLayout_6.setContentsMargins(9, 0, 9, 0) # Media player settings self.mediaPlayer.setVideoOutput(self.video_playback) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.positionChanged.connect(self.handleLabel) self.mediaPlayer.durationChanged.connect(self.durationChanged) def handleLabel(self): self.time_status.clear() mtime = QtCore.QTime(0, 0, 0, 0) self.time = mtime.addMSecs(self.mediaPlayer.position()) self.time_status.setText(self.time.toString()) def hide_all(self): self.frame_3.close() # self.frame.close() self.url_box.close() self.playback_button.close() self.screenshot_button.close() self.Quality_box.close() self.volume_button.close() # self.video_setting_button.close() # self.setting_button.close() def show_all(self): self.frame_3.show() # self.frame.show() self.url_box.show() self.playback_button.show() self.screenshot_button.show() self.Quality_box.show() self.volume_button.show() # self.video_setting_button.show() self.setting_button.show() def checkOnTop(self): self.isOnTop = not self.isOnTop if self.isOnTop: self.always_on_top_button.setProperty("top", True) self.always_on_top_button.setStyle( self.always_on_top_button.style()) Form.setWindowFlags(Form.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) else: self.always_on_top_button.setProperty("top", False) self.always_on_top_button.setStyle( self.always_on_top_button.style()) Form.setWindowFlags(Form.windowFlags() & ~QtCore.Qt.WindowStaysOnTopHint) Form.show() def miniProperty(self): self.video_playback.setMinimumSize(QSize(200, 100)) self.video_playback.resize(QSize(550, 270)) Form.resize(QSize(550, 270)) Form.setMinimumSize(QSize(200, 175)) self.mainFrame.setMinimumSize(QSize(200, 60)) self.mainFrame.resize(QSize(200, 53)) def standardProperty(self): self.video_playback.setMinimumSize(QSize(200, 100)) self.mainFrame.setMinimumSize(QSize(200, 82)) Form.setMinimumSize(QSize(200, 202)) Form.resize(550, 369) def setupMiniPlayer(self): self.isMini = not self.isMini if self.isMini: self.miniplayer_button.setProperty("mini", True) self.miniplayer_button.setStyle(self.miniplayer_button.style()) self.hide_all() self.miniProperty() else: self.miniplayer_button.setProperty("mini", False) self.miniplayer_button.setStyle(self.miniplayer_button.style()) self.standardProperty() self.show_all() def load(self): scorefile = "db.bat" if os.path.exists(scorefile): with open(scorefile, 'rb') as sf: scores = pickle.load(sf) else: scores = [] with open(scorefile, "wb") as sf: pickle.dump(scores, sf) return scores def scor_func(self, url): scorefile = "db.bat" if os.path.exists(scorefile): with open(scorefile, 'rb') as sf: scores = pickle.load(sf) else: scores = [] scores.append(url) with open(scorefile, "wb") as sf: if len(scores) > 100: print("here", scores) scores = scores[1:] pickle.dump(scores, sf) return scores def mute(self): if self.mediaPlayer.isMuted(): print('[ ! Full Volume]') self.mediaPlayer.setMuted(False) icon9 = QtGui.QIcon() icon9.addPixmap(QtGui.QPixmap("icon_sets/volume/volume1.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.volume_button.setIcon(icon9) self.volume_button.setIconSize(QSize(22, 22)) self.volumeslider.setEnabled(True) # shortcut Enable self.volupshortcut.setEnabled(True) self.voldownshortcut.setEnabled(True) else: print('[ ! Mute Volume]') self.mediaPlayer.setMuted(True) icon9 = QtGui.QIcon() icon9.addPixmap(QtGui.QPixmap("icon_sets/volume/volume2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.volume_button.setIcon(icon9) self.volume_button.setIconSize(QSize(22, 22)) self.volumeslider.setEnabled(False) # shrotcut disable self.volupshortcut.setEnabled(False) self.voldownshortcut.setEnabled(False) def play(self): if self.mediaPlayer.isVideoAvailable(): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: print("[ ! PAUSE PRESSED ]") self.mediaPlayer.pause() else: print("[ ! PLAY PRESSED ]") self.mediaPlayer.play() def playOnline(self): if self.url_box.currentText() != '': print('[ ! GETTING VIDEO ONLINE ]') fileName = self.url_box.currentText() res = requests.get('https://mediaplayerserver.herokuapp.com/', params={"key": fileName}) try: self.streams = json.loads(res.text) try: self.mediaPlayer.setMedia( QMediaContent(QUrl(self.streams['best']))) self.play_video() self.isOnline = True self.addQuality() if self.url_box.findText(fileName, Qt.MatchExactly) < 0: self.url_box.addItem(fileName) self.scor_func(fileName) except KeyError: print("[ ! Error Video Not Supported By platform]") except json.JSONDecodeError: print("[ ! Error NoPluginError]") finally: self.url_box.setCurrentText("") def openFile(self): print('[ ! OPEN FILE ]') username = getpass.getuser() if sys.platform == 'win32': path = 'C:/Users/' + username + '/Videos/' elif sys.platform == 'linux' or sys.platform == 'Darwin': path = '/home/' + username + '/Videos/' formats = str.join(' ', [ '*.%s' % str(fmt).strip('b').strip("'") for fmt in QtGui.QMovie.supportedFormats() ]) fileName, _ = QFileDialog.getOpenFileName( self.video_playback, "Select media file", path, "Video Files (*.mp4 *.flv *.ts *.mts *.avi *.mkv)") if fileName != '': self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(fileName))) self.play_video() # def decodeLink(self,url): # try: # streams = streamlink.streams(url) # keys = [k for k in streams.keys()] # data = dict() # for k in keys: # data[k] = streams[k].url # return data # except streamlink.NoPluginError: # return None # def playOnline(self): # if self.url_box.currentText() != '': # print('[ ! GETTING VIDEO ONLINE ]') # fileName = self.url_box.currentText() # self.streams = self.decodeLink(fileName) # try: # self.mediaPlayer.setMedia(QMediaContent(QUrl(self.streams['best']))) # self.play_video() # self.isOnline = True # self.addQuality() # if self.url_box.findText(fileName, Qt.MatchExactly) < 0: # self.url_box.addItem(fileName) # self.scor_func(fileName) # except KeyError: # print("[ ! Error Video Not Supported By platform]") # finally: # self.url_box.setCurrentText("") def play_video(self): print('[ ! PLAYING VIDEO ]') self.play_button.setEnabled(True) if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): print('[ ! CHANGING MEDIA STATE ]') if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.play_button.setProperty('play', False) self.play_button.setStyle(self.play_button.style()) else: self.play_button.setProperty('play', True) self.play_button.setStyle(self.play_button.style()) def stopplayback(self): print('[ ! STOP PLAYBACK VIDEO ]') self.mediaPlayer.stop() self.play_video() def positionChanged(self, position): print('[ ! POSITION CHANGED ]') self.position_slider.setValue(position) def durationChanged(self, duration): print('[ ! DURATION CHANGED ]') self.position_slider.setRange(0, duration) self.duration_status.clear() mtime = QtCore.QTime(0, 0, 0, 0) time = mtime.addMSecs(self.mediaPlayer.duration()) self.duration_status.setText(time.toString()) def setPosition(self, position): print('[ ! POSITION SET ]') self.mediaPlayer.setPosition(position) def setVolumePos(self, remain): print('[ ! REMANING VOLUME ]') print(remain) self.volumeslider.setRange(remain, 100) def setVolume(self, vol): print('[ ! SET VOLUME ]') print("set volume = " + str(vol)) if vol >= 0 and vol <= 100: self.volume_percentage.setText(" " + str(vol) + " %") if vol <= 0: icon9 = QtGui.QIcon() icon9.addPixmap(QtGui.QPixmap("icon_sets/volume/volume2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.volume_button.setIcon(icon9) else: icon9 = QtGui.QIcon() icon9.addPixmap(QtGui.QPixmap("icon_sets/volume/volume1.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.volume_button.setIcon(icon9) self.volumeslider.setValue(vol) self.mediaPlayer.setVolume(vol) def screenshot(self): print('[ ! SCREENSHOT ]') wincen = Form.geometry() topX = wincen.topLeft().x() topY = wincen.topLeft().y() geo = self.video_playback.geometry() image = pyautogui.screenshot(region=(topX, topY + 38, geo.width(), geo.height() - 35)) filename = "screenshot" + str(uuid.uuid4()) + ".png" username = getpass.getuser() if sys.platform == 'win32': path = 'C:/Users/' + username + '/Pictures/' + filename elif sys.platform == 'linux' or sys.platform == 'Darwin': path = '/home/' + username + '/Pictures/' + filename image.save(path) def EscFun(self): if self.video_playback.isFullScreen(): Form.show() self.video_playback.setFullScreen(False) def fullscreen_video(self): if self.mediaPlayer.isVideoAvailable(): if self.video_playback.isFullScreen(): self.video_playback.setFullScreen(False) print('[ ! Normal Screen ]') Form.show() else: print('[ ! Full Screen ]') self.video_playback.setFullScreen(True) Form.hide() def getFormat(self): li = [k for k in self.streams.keys()] for q in li: if q.startswith('audio'): li.remove(q) try: li.remove('audio_opus') except ValueError: pass return li def changeQuality(self, quality): pos = self.mediaPlayer.position() try: self.mediaPlayer.setMedia( QMediaContent(QUrl(self.streams[quality]))) except KeyError: pass self.setPosition(pos) self.mediaPlayer.play() def handleSetting(self): from setting import SettingDialog dlg = SettingDialog() dlg.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) dlg.exec_() def addQuality(self): self.Quality_box.clear() self.Quality_box.addItems(self.getFormat()) def handleQuality(self): if self.isOnline: self.changeQuality(self.Quality_box.currentText()) def forwardSlider(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() + 1000) def forwardSlider10(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() + 10000) def forwardSlider5(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() + 5000) def backSlider(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() - 1000) def backSlider10(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() - 10000) def backSlider5(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() - 5000) def volumeUp(self): self.setVolume(self.mediaPlayer.volume() + 10) print("Volume: " + str(self.mediaPlayer.volume())) def volumeDown(self): self.setVolume(self.mediaPlayer.volume() - 10) print("Volume: " + str(self.mediaPlayer.volume())) def max(self): if not Form.isMaximized(): print("[! Window is Maximized]") Form.showMaximized() else: print("[! Window is Normal]") Form.showNormal() def min(self): if not Form.isMinimized(): print("[! Window is Minimized]") Form.showMinimized() else: print("[! Window is Normal]") Form.showNormal() def exit(self): self.mediaPlayer.stop() sys.exit()
class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.setupUi(self) self.player = QMediaPlayer() self.player.error.connect(self.erroralert) self.player.play() self.player.stateChanged.connect(self.Set_Icons) # self.player.volumeChanged.connect(self.prev_volume) # Connect control buttons/slides for media player. self.playButton.pressed.connect(self.play_pause) self.stopButton.pressed.connect(self.player.stop) self.showButton.pressed.connect(self.playlist_toggle) self.equalizerButton.pressed.connect(self.ShowEqualizer) self.volumeButton.pressed.connect(self.mute) self.volumeSlider.valueChanged.connect(self.volumeChanged) self.currentVolume = self.volumeSlider.value() self.timeSlider.valueChanged.connect(self.player.setPosition) # Setup the playlist. self.playlist = QMediaPlaylist() self.player.setPlaylist(self.playlist) self.model = PlaylistModel(self.playlist) self.listWidget.setModel(self.model) self.playlist.currentIndexChanged.connect( self.playlist_position_changed) selection_model = self.listWidget.selectionModel() selection_model.selectionChanged.connect( self.playlist_selection_changed) self.player.durationChanged.connect(self.update_duration) self.player.positionChanged.connect(self.update_position) self.actionOpen_File.triggered.connect(self.open_file) self.files = [] self.setAcceptDrops(True) self.graphWidget.setBackground((60, 60, 60)) self.graphWidget.GetViewBox().setMenuEnabled(False) self.graphWidget.GetViewBox().setMouseEnabled(x=False, y=False) self.graphWidget.setPlotEQ((42, 130, 218)) self.Visualizer = FFTAnalyser(self.player) self.Visualizer.calculated_visual.connect(self.draw) self.Visualizer.start() self.Equalizer = QWidget() self.visdata = np.array([]) self.show() def draw(self, visdata): self.visdata = np.array(visdata) self.graphWidget.UpdatePlotEQ(self.visdata) def dragEnterEvent(self, e): if e.mimeData().hasUrls(): e.acceptProposedAction() def play_pause(self): if self.player.state() == QMediaPlayer.PlayingState: self.player.pause() else: self.player.play() def Set_Icons(self, state): if state == QMediaPlayer.StoppedState: self.stopButton.setIcon( qta.icon('fa5s.stop-circle', active='fa5s.stop-circle', color='white', color_active='grey')) self.playButton.setIcon(qta.icon('fa5s.play-circle', color='white')) self.playButton.setToolTip('Play') elif state == QMediaPlayer.PlayingState: self.playButton.setIcon( qta.icon('fa5s.pause-circle', color='white')) self.playButton.setToolTip('Pause') elif state == QMediaPlayer.PausedState: self.playButton.setIcon(qta.icon('fa5s.play-circle', color='white')) self.playButton.setToolTip('Play') def playlist_toggle(self): if self.listWidget.isHidden(): self.listWidget.setHidden(False) self.listWidget.setProperty("showDropIndicator", True) self.showButton.setIcon(qta.icon('fa5s.eye-slash', color='white')) self.showButton.setToolTip('Hide Playlist') else: self.listWidget.setHidden(True) self.listWidget.setProperty("showDropIndicator", False) self.showButton.setIcon(qta.icon('fa5s.list-ul', color='white')) self.showButton.setToolTip('Show Playlist') def dropEvent(self, e): for url in e.mimeData().urls(): self.playlist.addMedia(QMediaContent(url)) self.model.layoutChanged.emit() # If not playing, seeking to first of newly added + play. if self.player.state() != QMediaPlayer.PlayingState: i = self.playlist.mediaCount() - len(e.mimeData().urls()) self.playlist.setCurrentIndex(i) self.player.play() def open_file(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog path, _ = QFileDialog.getOpenFileName(self, "Open file", "", "Music Files (*.mp3 *.wav)", options=options) if path: self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(path))) self.files.append(QMediaContent(QUrl.fromLocalFile(path))) self.model.layoutChanged.emit() # def contextMenuEvent(self, event): # contextMenu = QMenu(self) # graph = contextMenu.addAction("Show Graph") def update_duration(self, duration): print("!", duration) print("?", self.player.duration()) self.timeSlider.setMaximum(duration) if duration >= 0: self.totalTimeLabel.setText(hhmmss(duration)) def update_position(self, position): if position >= 0: self.currentTimeLabel.setText(hhmmss(position)) self.timeSlider.blockSignals(True) self.timeSlider.setValue(position) self.timeSlider.blockSignals(False) def playlist_selection_changed(self, ix): i = ix.indexes()[0].row() self.playlist.setCurrentIndex(i) def playlist_position_changed(self, i): if i > -1: ix = self.model.index(i) self.listWidget.setCurrentIndex(ix) def erroralert(self, *args): print(args) def ShowEqualizer(self): if self.player.currentMedia().canonicalUrl().path() != "": self.Equalizer = WindowingWidget( self.player.currentMedia().canonicalUrl().path()) self.Equalizer.SendPath.connect(self.AddPathToPlaylist) self.Equalizer.show() def AddPathToPlaylist(self, path): if path: self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(path))) self.files.append(path) self.model.layoutChanged.emit() def volumeChanged(self): self.currentVolume = self.volumeSlider.value() self.player.setVolume(self.volumeSlider.value()) def mute(self): if self.player.isMuted(): self.player.setMuted(False) self.volumeButton.setIcon(qta.icon('fa5s.volume-up', color='white')) self.volumeButton.setToolTip('Mute') self.volumeSlider.setEnabled(True) else: self.player.setMuted(True) self.volumeButton.setIcon( qta.icon('fa5s.volume-mute', color='white')) self.volumeButton.setToolTip('Unmute') self.volumeSlider.setEnabled(False) def closeEvent(self, event): self.Visualizer.terminate() if self.Equalizer.isVisible(): self.Equalizer.close()
class Player(QGraphicsVideoItem): isSubtitle = pyqtSignal(bool) subtitlePos = pyqtSignal(int) def __init__(self, parent=None): super().__init__() self.parent = parent self.player = QMediaPlayer() self.player.setVolume(int(settings().value("Player/volume") or 100)) self.player.setVideoOutput(self) self.timer = QTimer(self) self.timer.timeout.connect(self.timerPos) self.player.currentMediaChanged.connect(self.signalStart) self.player.currentMediaChanged.connect( self.parent.subtitleitem.subtitleControl) self.player.currentMediaChanged.connect(self.videoConfigure) """self.player.mediaStatusChanged.connect(self.metadata) def metadata(self, data): if data and self.player.isMetaDataAvailable(): print(self.player.metaData("VideoCodec"))""" def videoConfigure(self, media): video_name = os.path.basename(media.canonicalUrl().toLocalFile()) videos = settings().value("Player/video_names") or [] videos_time = settings().value("Player/videos_time") or [] try: self.player.setPosition(int(videos_time[videos.index(video_name)])) except ValueError: pass def timerStart(self): self.timer.start(200) def signalStart(self, content): srt = content.canonicalUrl().toLocalFile().split(".") srt.pop(-1) srt.append("srt") srt = ".".join(srt) if QFile.exists(srt): self.isSubtitle.emit(True) self.timer.start(100) else: self.isSubtitle.emit(False) self.timer.stop() def timerPos(self): self.subtitlePos.emit(self.player.position()) def playerPlayOrOpen(self, arg=None): if type(arg) == list and len(arg) > 1: content = QMediaContent(QUrl.fromLocalFile(arg[1])) self.player.setMedia(content) self.play() def addVideo(self, video): content = QMediaContent(QUrl.fromLocalFile(video)) self.player.setMedia(content) self.play() def addYoutubeVideo(self, video): dm = DownloadManager(self) content = QMediaContent(dm.addUrl(video)) self.player.setMedia(content) self.play() def sliderChanged(self, pos): self.player.setPosition(pos) def play(self): self.player.play() def stop(self): self.player.stop() def pause(self): self.player.pause() def setMuted(self, mute): self.player.setMuted(mute) def mutedState(self): if self.player.isMuted(): self.setMuted(False) else: self.setMuted(True) def isMuted(self): return self.player.isMuted() def setVolume(self, value): self.player.setVolume(value) def volume(self): return self.player.volume()
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 Player(QGraphicsVideoItem): isSubtitle = pyqtSignal(bool) subtitlePos = pyqtSignal(int) def __init__(self, parent=None): super().__init__() self.parent = parent self.player = QMediaPlayer() self.player.setVolume(int(settings().value("Player/volume") or 100)) self.player.setVideoOutput(self) self.timer = QTimer(self) self.timer.timeout.connect(self.timerPos) self.player.currentMediaChanged.connect(self.signalStart) self.player.currentMediaChanged.connect(self.parent.subtitleitem.subtitleControl) self.player.currentMediaChanged.connect(self.videoConfigure) """self.player.mediaStatusChanged.connect(self.metadata) def metadata(self, data): if data and self.player.isMetaDataAvailable(): print(self.player.metaData("VideoCodec"))""" def videoConfigure(self, media): video_name = os.path.basename(media.canonicalUrl().toLocalFile()) videos = settings().value("Player/video_names") or [] videos_time = settings().value("Player/videos_time") or [] try: self.player.setPosition(int(videos_time[videos.index(video_name)])) except ValueError: pass def timerStart(self): self.timer.start(200) def signalStart(self, content): srt = content.canonicalUrl().toLocalFile().split(".") srt.pop(-1) srt.append("srt") srt = ".".join(srt) if QFile.exists(srt): self.isSubtitle.emit(True) self.timer.start(100) else: self.isSubtitle.emit(False) self.timer.stop() def timerPos(self): self.subtitlePos.emit(self.player.position()) def playerPlayOrOpen(self, arg=None): if type(arg) == list and len(arg) > 1: content = QMediaContent(QUrl.fromLocalFile(arg[1])) self.player.setMedia(content) self.play() def addVideo(self, video): content = QMediaContent(QUrl.fromLocalFile(video)) self.player.setMedia(content) self.play() def addYoutubeVideo(self, video): dm = DownloadManager(self) content = QMediaContent(dm.addUrl(video)) self.player.setMedia(content) self.play() def sliderChanged(self, pos): self.player.setPosition(pos) def play(self): self.player.play() def stop(self): self.player.stop() def pause(self): self.player.pause() def setMuted(self, mute): self.player.setMuted(mute) def mutedState(self): if self.player.isMuted(): self.setMuted(False) else: self.setMuted(True) def isMuted(self): return self.player.isMuted() def setVolume(self, value): self.player.setVolume(value) def volume(self): return self.player.volume()
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 VidCutter(QWidget): def __init__(self, parent): super(VidCutter, self).__init__(parent) self.novideoWidget = QWidget(self, autoFillBackground=True) self.parent = parent self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.videoWidget = VideoWidget(self) self.videoService = VideoService(self) QFontDatabase.addApplicationFont( MainWindow.get_path('fonts/DroidSansMono.ttf')) QFontDatabase.addApplicationFont( MainWindow.get_path('fonts/OpenSans.ttf')) fontSize = 12 if sys.platform == 'darwin' else 10 appFont = QFont('Open Sans', fontSize, 300) qApp.setFont(appFont) self.clipTimes = [] self.inCut = False self.movieFilename = '' self.movieLoaded = False self.timeformat = 'hh:mm:ss' self.finalFilename = '' self.totalRuntime = 0 self.initIcons() self.initActions() self.toolbar = QToolBar(floatable=False, movable=False, iconSize=QSize(40, 36)) self.toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.toolbar.setStyleSheet('''QToolBar { spacing:10px; } QToolBar QToolButton { border:1px solid transparent; min-width:95px; font-size:11pt; font-weight:400; border-radius:5px; padding:1px 2px; color:#444; } QToolBar QToolButton:hover { border:1px inset #6A4572; color:#6A4572; background-color:rgba(255, 255, 255, 0.85); } QToolBar QToolButton:pressed { border:1px inset #6A4572; color:#6A4572; background-color:rgba(255, 255, 255, 0.25); } QToolBar QToolButton:disabled { color:#999; }''') self.initToolbar() self.appMenu, self.cliplistMenu = QMenu(), QMenu() self.initMenus() self.seekSlider = VideoSlider(parent=self, sliderMoved=self.setPosition) self.initNoVideo() self.cliplist = QListWidget( sizePolicy=QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding), contextMenuPolicy=Qt.CustomContextMenu, uniformItemSizes=True, iconSize=QSize(100, 700), dragDropMode=QAbstractItemView.InternalMove, alternatingRowColors=True, customContextMenuRequested=self.itemMenu, dragEnabled=True) self.cliplist.setStyleSheet( 'QListView { border-radius:0; border:none; border-left:1px solid #B9B9B9; ' + 'border-right:1px solid #B9B9B9; } QListView::item { padding:10px 0; }' ) self.cliplist.setFixedWidth(185) self.cliplist.model().rowsMoved.connect(self.syncClipList) listHeader = QLabel(pixmap=QPixmap( MainWindow.get_path('images/clipindex.png'), 'PNG'), alignment=Qt.AlignCenter) listHeader.setStyleSheet( '''padding:5px; padding-top:8px; border:1px solid #b9b9b9; background-color:qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFF, stop: 0.5 #EAEAEA, stop: 0.6 #EAEAEA stop:1 #FFF);''' ) self.runtimeLabel = QLabel('<div align="right">00:00:00</div>', textFormat=Qt.RichText) self.runtimeLabel.setStyleSheet( '''font-family:Droid Sans Mono; font-size:10pt; color:#FFF; background:rgb(106, 69, 114) url(:images/runtime.png) no-repeat left center; padding:2px; padding-right:8px; border:1px solid #B9B9B9;''') self.clipindexLayout = QVBoxLayout(spacing=0) self.clipindexLayout.setContentsMargins(0, 0, 0, 0) self.clipindexLayout.addWidget(listHeader) self.clipindexLayout.addWidget(self.cliplist) self.clipindexLayout.addWidget(self.runtimeLabel) self.videoLayout = QHBoxLayout() self.videoLayout.setContentsMargins(0, 0, 0, 0) self.videoLayout.addWidget(self.novideoWidget) self.videoLayout.addLayout(self.clipindexLayout) self.timeCounter = QLabel('00:00:00 / 00:00:00', autoFillBackground=True, alignment=Qt.AlignCenter, sizePolicy=QSizePolicy( QSizePolicy.Expanding, QSizePolicy.Fixed)) self.timeCounter.setStyleSheet( 'color:#FFF; background:#000; font-family:Droid Sans Mono; font-size:10.5pt; padding:4px;' ) videoplayerLayout = QVBoxLayout(spacing=0) videoplayerLayout.setContentsMargins(0, 0, 0, 0) videoplayerLayout.addWidget(self.videoWidget) videoplayerLayout.addWidget(self.timeCounter) self.videoplayerWidget = QWidget(self, visible=False) self.videoplayerWidget.setLayout(videoplayerLayout) self.muteButton = QPushButton(icon=self.unmuteIcon, flat=True, toolTip='Mute', statusTip='Toggle audio mute', iconSize=QSize(16, 16), cursor=Qt.PointingHandCursor, clicked=self.muteAudio) self.volumeSlider = QSlider(Qt.Horizontal, toolTip='Volume', statusTip='Adjust volume level', cursor=Qt.PointingHandCursor, value=50, minimum=0, maximum=100, sliderMoved=self.setVolume) self.menuButton = QPushButton( icon=self.menuIcon, flat=True, toolTip='Menu', statusTip='Media + application information', iconSize=QSize(24, 24), cursor=Qt.PointingHandCursor) self.menuButton.setMenu(self.appMenu) toolbarLayout = QHBoxLayout() toolbarLayout.addWidget(self.toolbar) toolbarLayout.setContentsMargins(2, 2, 2, 2) toolbarGroup = QGroupBox() toolbarGroup.setFlat(False) toolbarGroup.setCursor(Qt.PointingHandCursor) toolbarGroup.setLayout(toolbarLayout) toolbarGroup.setStyleSheet( '''QGroupBox { background-color:rgba(0, 0, 0, 0.1); border:1px inset #888; border-radius:5px; }''') controlsLayout = QHBoxLayout(spacing=0) controlsLayout.addStretch(1) controlsLayout.addWidget(toolbarGroup) controlsLayout.addStretch(1) controlsLayout.addWidget(self.muteButton) controlsLayout.addWidget(self.volumeSlider) controlsLayout.addSpacing(1) controlsLayout.addWidget(self.menuButton) layout = QVBoxLayout() layout.setContentsMargins(10, 10, 10, 4) layout.addLayout(self.videoLayout) layout.addWidget(self.seekSlider) layout.addSpacing(5) layout.addLayout(controlsLayout) layout.addSpacing(2) self.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) def initNoVideo(self) -> None: novideoImage = QLabel( alignment=Qt.AlignCenter, autoFillBackground=False, pixmap=QPixmap(MainWindow.get_path('images/novideo.png'), 'PNG'), sizePolicy=QSizePolicy(QSizePolicy.Expanding, QSizePolicy.MinimumExpanding)) novideoImage.setBackgroundRole(QPalette.Dark) novideoImage.setContentsMargins(0, 20, 0, 20) self.novideoLabel = QLabel(alignment=Qt.AlignCenter, autoFillBackground=True, sizePolicy=QSizePolicy( QSizePolicy.Expanding, QSizePolicy.Minimum)) self.novideoLabel.setBackgroundRole(QPalette.Dark) self.novideoLabel.setContentsMargins(0, 20, 15, 60) novideoLayout = QVBoxLayout(spacing=0) novideoLayout.addWidget(novideoImage) novideoLayout.addWidget(self.novideoLabel, alignment=Qt.AlignTop) self.novideoMovie = QMovie( MainWindow.get_path('images/novideotext.gif')) self.novideoMovie.frameChanged.connect(self.setNoVideoText) self.novideoMovie.start() self.novideoWidget.setBackgroundRole(QPalette.Dark) self.novideoWidget.setLayout(novideoLayout) def initIcons(self) -> None: self.appIcon = QIcon(MainWindow.get_path('images/vidcutter.png')) self.openIcon = icon('fa.film', color='#444', color_active='#6A4572', scale_factor=0.9) self.playIcon = icon('fa.play-circle-o', color='#444', color_active='#6A4572', scale_factor=1.1) self.pauseIcon = icon('fa.pause-circle-o', color='#444', color_active='#6A4572', scale_factor=1.1) self.cutStartIcon = icon('fa.scissors', scale_factor=1.15, color='#444', color_active='#6A4572') endicon_normal = icon('fa.scissors', scale_factor=1.15, color='#444').pixmap(QSize(36, 36)).toImage() endicon_active = icon('fa.scissors', scale_factor=1.15, color='#6A4572').pixmap(QSize(36, 36)).toImage() self.cutEndIcon = QIcon() self.cutEndIcon.addPixmap( QPixmap.fromImage( endicon_normal.mirrored(horizontal=True, vertical=False)), QIcon.Normal, QIcon.Off) self.cutEndIcon.addPixmap( QPixmap.fromImage( endicon_active.mirrored(horizontal=True, vertical=False)), QIcon.Active, QIcon.Off) self.saveIcon = icon('fa.video-camera', color='#6A4572', color_active='#6A4572') self.muteIcon = QIcon(MainWindow.get_path('images/muted.png')) self.unmuteIcon = QIcon(MainWindow.get_path('images/unmuted.png')) self.upIcon = icon('ei.caret-up', color='#444') self.downIcon = icon('ei.caret-down', color='#444') self.removeIcon = icon('ei.remove', color='#B41D1D') self.removeAllIcon = icon('ei.trash', color='#B41D1D') self.successIcon = QIcon(MainWindow.get_path('images/success.png')) self.menuIcon = icon('fa.cog', color='#444', scale_factor=1.15) self.completePlayIcon = icon('fa.play', color='#444') self.completeOpenIcon = icon('fa.folder-open', color='#444') self.completeRestartIcon = icon('fa.retweet', color='#444') self.completeExitIcon = icon('fa.sign-out', color='#444') self.mediaInfoIcon = icon('fa.info-circle', color='#444') self.updateCheckIcon = icon('fa.cloud-download', color='#444') def initActions(self) -> None: self.openAction = QAction(self.openIcon, 'Open', self, statusTip='Open media file', triggered=self.openMedia) self.playAction = QAction(self.playIcon, 'Play', self, statusTip='Play media file', triggered=self.playMedia, enabled=False) self.cutStartAction = QAction(self.cutStartIcon, ' Start', self, toolTip='Start', statusTip='Set clip start marker', triggered=self.setCutStart, enabled=False) self.cutEndAction = QAction(self.cutEndIcon, ' End', self, toolTip='End', statusTip='Set clip end marker', triggered=self.setCutEnd, enabled=False) self.saveAction = QAction(self.saveIcon, 'Save', self, statusTip='Save clips to a new video file', triggered=self.cutVideo, enabled=False) self.moveItemUpAction = QAction( self.upIcon, 'Move up', self, statusTip='Move clip position up in list', triggered=self.moveItemUp, enabled=False) self.moveItemDownAction = QAction( self.downIcon, 'Move down', self, statusTip='Move clip position down in list', triggered=self.moveItemDown, enabled=False) self.removeItemAction = QAction( self.removeIcon, 'Remove clip', self, statusTip='Remove selected clip from list', triggered=self.removeItem, enabled=False) self.removeAllAction = QAction(self.removeAllIcon, 'Clear list', self, statusTip='Clear all clips from list', triggered=self.clearList, enabled=False) self.mediaInfoAction = QAction( self.mediaInfoIcon, 'Media information', self, statusTip='View current media file information', triggered=self.mediaInfo, enabled=False) self.updateCheckAction = QAction( self.updateCheckIcon, 'Check for updates...', self, statusTip='Check for application updates', triggered=self.updateCheck) self.aboutQtAction = QAction('About Qt', self, statusTip='About Qt', triggered=qApp.aboutQt) self.aboutAction = QAction('About %s' % qApp.applicationName(), self, statusTip='Credits and licensing', triggered=self.aboutInfo) def initToolbar(self) -> None: self.toolbar.addAction(self.openAction) self.toolbar.addAction(self.playAction) self.toolbar.addAction(self.cutStartAction) self.toolbar.addAction(self.cutEndAction) self.toolbar.addAction(self.saveAction) def initMenus(self) -> None: self.appMenu.addAction(self.mediaInfoAction) self.appMenu.addAction(self.updateCheckAction) self.appMenu.addSeparator() self.appMenu.addAction(self.aboutQtAction) self.appMenu.addAction(self.aboutAction) self.cliplistMenu.addAction(self.moveItemUpAction) self.cliplistMenu.addAction(self.moveItemDownAction) self.cliplistMenu.addSeparator() self.cliplistMenu.addAction(self.removeItemAction) self.cliplistMenu.addAction(self.removeAllAction) @staticmethod def getSpacer() -> QWidget: spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) return spacer def setRunningTime(self, runtime: str) -> None: self.runtimeLabel.setText('<div align="right">%s</div>' % runtime) @pyqtSlot(int) def setNoVideoText(self) -> None: self.novideoLabel.setPixmap(self.novideoMovie.currentPixmap()) def itemMenu(self, pos: QPoint) -> None: globalPos = self.cliplist.mapToGlobal(pos) self.moveItemUpAction.setEnabled(False) self.moveItemDownAction.setEnabled(False) self.removeItemAction.setEnabled(False) self.removeAllAction.setEnabled(False) index = self.cliplist.currentRow() if index != -1: if not self.inCut: if index > 0: self.moveItemUpAction.setEnabled(True) if index < self.cliplist.count() - 1: self.moveItemDownAction.setEnabled(True) if self.cliplist.count() > 0: self.removeItemAction.setEnabled(True) if self.cliplist.count() > 0: self.removeAllAction.setEnabled(True) self.cliplistMenu.exec_(globalPos) def moveItemUp(self) -> None: index = self.cliplist.currentRow() tmpItem = self.clipTimes[index] del self.clipTimes[index] self.clipTimes.insert(index - 1, tmpItem) self.renderTimes() def moveItemDown(self) -> None: index = self.cliplist.currentRow() tmpItem = self.clipTimes[index] del self.clipTimes[index] self.clipTimes.insert(index + 1, tmpItem) self.renderTimes() def removeItem(self) -> None: index = self.cliplist.currentRow() del self.clipTimes[index] if self.inCut and index == self.cliplist.count() - 1: self.inCut = False self.initMediaControls() self.renderTimes() def clearList(self) -> None: self.clipTimes.clear() self.cliplist.clear() self.inCut = False self.renderTimes() self.initMediaControls() def mediaInfo(self) -> None: if self.mediaPlayer.isMetaDataAvailable(): content = '<table cellpadding="4">' for key in self.mediaPlayer.availableMetaData(): val = self.mediaPlayer.metaData(key) if type(val) is QSize: val = '%s x %s' % (val.width(), val.height()) content += '<tr><td align="right"><b>%s:</b></td><td>%s</td></tr>\n' % ( key, val) content += '</table>' mbox = QMessageBox(windowTitle='Media Information', windowIcon=self.parent.windowIcon(), textFormat=Qt.RichText) mbox.setText('<b>%s</b>' % os.path.basename( self.mediaPlayer.currentMedia().canonicalUrl().toLocalFile())) mbox.setInformativeText(content) mbox.exec_() else: QMessageBox.critical( self.parent, 'MEDIA ERROR', '<h3>Could not probe media file.</h3>' + '<p>An error occurred while analyzing the media file for its metadata details.' + '<br/><br/><b>This DOES NOT mean there is a problem with the file and you should ' + 'be able to continue using it.</b></p>') def aboutInfo(self) -> None: about_html = '''<style> a { color:#441d4e; text-decoration:none; font-weight:bold; } a:hover { text-decoration:underline; } </style> <div style="min-width:650px;"> <p style="font-size:26pt; font-weight:bold; color:#6A4572;">%s</p> <p> <span style="font-size:13pt;"><b>Version: %s</b></span> <span style="font-size:10pt;position:relative;left:5px;">( %s )</span> </p> <p style="font-size:13px;"> Copyright © 2016 <a href="mailto:[email protected]">Pete Alexandrou</a> <br/> Website: <a href="%s">%s</a> </p> <p style="font-size:13px;"> Thanks to the folks behind the <b>Qt</b>, <b>PyQt</b> and <b>FFmpeg</b> projects for all their hard and much appreciated work. </p> <p style="font-size:11px;"> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. </p> <p style="font-size:11px;"> This software uses libraries from the <a href="https://www.ffmpeg.org">FFmpeg</a> project under the <a href="https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html">LGPLv2.1</a> </p></div>''' % (qApp.applicationName(), qApp.applicationVersion(), platform.architecture()[0], qApp.organizationDomain(), qApp.organizationDomain()) QMessageBox.about(self.parent, 'About %s' % qApp.applicationName(), about_html) def openMedia(self) -> None: filename, _ = QFileDialog.getOpenFileName(self.parent, caption='Select video', directory=QDir.homePath()) if filename != '': self.loadFile(filename) def loadFile(self, filename: str) -> None: self.movieFilename = filename if not os.path.exists(filename): return self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(filename))) self.initMediaControls(True) self.cliplist.clear() self.clipTimes = [] self.parent.setWindowTitle( '%s - %s' % (qApp.applicationName(), os.path.basename(filename))) if not self.movieLoaded: self.videoLayout.replaceWidget(self.novideoWidget, self.videoplayerWidget) self.novideoMovie.stop() self.novideoMovie.deleteLater() self.novideoWidget.deleteLater() self.videoplayerWidget.show() self.videoWidget.show() self.movieLoaded = True if self.mediaPlayer.isVideoAvailable(): self.mediaPlayer.setPosition(1) self.mediaPlayer.play() self.mediaPlayer.pause() def playMedia(self) -> None: if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() self.playAction.setText('Play') else: self.mediaPlayer.play() self.playAction.setText('Pause') def initMediaControls(self, flag: bool = True) -> None: self.playAction.setEnabled(flag) self.saveAction.setEnabled(False) self.cutStartAction.setEnabled(flag) self.cutEndAction.setEnabled(False) self.mediaInfoAction.setEnabled(flag) if flag: self.seekSlider.setRestrictValue(0) def setPosition(self, position: int) -> None: self.mediaPlayer.setPosition(position) def positionChanged(self, progress: int) -> None: self.seekSlider.setValue(progress) currentTime = self.deltaToQTime(progress) totalTime = self.deltaToQTime(self.mediaPlayer.duration()) self.timeCounter.setText('%s / %s' % (currentTime.toString( self.timeformat), totalTime.toString(self.timeformat))) @pyqtSlot() def mediaStateChanged(self) -> None: if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playAction.setIcon(self.pauseIcon) else: self.playAction.setIcon(self.playIcon) def durationChanged(self, duration: int) -> None: self.seekSlider.setRange(0, duration) def muteAudio(self) -> None: if self.mediaPlayer.isMuted(): self.muteButton.setIcon(self.unmuteIcon) self.muteButton.setToolTip('Mute') else: self.muteButton.setIcon(self.muteIcon) self.muteButton.setToolTip('Unmute') self.mediaPlayer.setMuted(not self.mediaPlayer.isMuted()) def setVolume(self, volume: int) -> None: self.mediaPlayer.setVolume(volume) def toggleFullscreen(self) -> None: self.videoWidget.setFullScreen(not self.videoWidget.isFullScreen()) def setCutStart(self) -> None: self.clipTimes.append([ self.deltaToQTime(self.mediaPlayer.position()), '', self.captureImage() ]) self.cutStartAction.setDisabled(True) self.cutEndAction.setEnabled(True) self.seekSlider.setRestrictValue(self.seekSlider.value(), True) self.inCut = True self.renderTimes() def setCutEnd(self) -> None: item = self.clipTimes[len(self.clipTimes) - 1] selected = self.deltaToQTime(self.mediaPlayer.position()) if selected.__lt__(item[0]): QMessageBox.critical( self.parent, 'Invalid END Time', 'The clip end time must come AFTER it\'s start time. Please try again.' ) return item[1] = selected self.cutStartAction.setEnabled(True) self.cutEndAction.setDisabled(True) self.seekSlider.setRestrictValue(0, False) self.inCut = False self.renderTimes() @pyqtSlot(QModelIndex, int, int, QModelIndex, int) def syncClipList(self, parent: QModelIndex, start: int, end: int, destination: QModelIndex, row: int) -> None: if start < row: index = row - 1 else: index = row clip = self.clipTimes.pop(start) self.clipTimes.insert(index, clip) def renderTimes(self) -> None: self.cliplist.clear() if len(self.clipTimes) > 4: self.cliplist.setFixedWidth(200) else: self.cliplist.setFixedWidth(185) self.totalRuntime = 0 for item in self.clipTimes: endItem = '' if type(item[1]) is QTime: endItem = item[1].toString(self.timeformat) self.totalRuntime += item[0].msecsTo(item[1]) listitem = QListWidgetItem() listitem.setTextAlignment(Qt.AlignVCenter) if type(item[2]) is QPixmap: listitem.setIcon(QIcon(item[2])) self.cliplist.addItem(listitem) marker = QLabel( '''<style>b { font-size:7pt; } p { margin:2px 5px; }</style> <p><b>START</b><br/>%s<br/><b>END</b><br/>%s</p>''' % (item[0].toString(self.timeformat), endItem)) marker.setStyleSheet('border:none;') self.cliplist.setItemWidget(listitem, marker) listitem.setFlags(Qt.ItemIsSelectable | Qt.ItemIsDragEnabled | Qt.ItemIsEnabled) if len(self.clipTimes) and not self.inCut: self.saveAction.setEnabled(True) if self.inCut or len(self.clipTimes) == 0 or not type( self.clipTimes[0][1]) is QTime: self.saveAction.setEnabled(False) self.setRunningTime( self.deltaToQTime(self.totalRuntime).toString(self.timeformat)) @staticmethod def deltaToQTime(millisecs: int) -> QTime: secs = millisecs / 1000 return QTime((secs / 3600) % 60, (secs / 60) % 60, secs % 60, (secs * 1000) % 1000) def captureImage(self) -> QPixmap: frametime = self.deltaToQTime(self.mediaPlayer.position()).toString( self.timeformat) inputfile = self.mediaPlayer.currentMedia().canonicalUrl().toLocalFile( ) imagecap = self.videoService.capture(inputfile, frametime) if type(imagecap) is QPixmap: return imagecap def cutVideo(self) -> bool: clips = len(self.clipTimes) filename, filelist = '', [] source = self.mediaPlayer.currentMedia().canonicalUrl().toLocalFile() _, sourceext = os.path.splitext(source) if clips > 0: self.finalFilename, _ = QFileDialog.getSaveFileName( self.parent, 'Save video', source, 'Video files (*%s)' % sourceext) if self.finalFilename == '': return False qApp.setOverrideCursor(Qt.BusyCursor) self.saveAction.setDisabled(True) self.showProgress(clips) file, ext = os.path.splitext(self.finalFilename) index = 1 self.progress.setLabelText('Cutting media files...') qApp.processEvents() for clip in self.clipTimes: duration = self.deltaToQTime(clip[0].msecsTo( clip[1])).toString(self.timeformat) filename = '%s_%s%s' % (file, '{0:0>2}'.format(index), ext) filelist.append(filename) self.videoService.cut(source, filename, clip[0].toString(self.timeformat), duration) index += 1 if len(filelist) > 1: self.joinVideos(filelist, self.finalFilename) else: QFile.remove(self.finalFilename) QFile.rename(filename, self.finalFilename) self.progress.setLabelText('Complete...') self.progress.setValue(100) qApp.processEvents() self.progress.close() self.progress.deleteLater() qApp.restoreOverrideCursor() self.complete() return True return False def joinVideos(self, joinlist: list, filename: str) -> None: listfile = os.path.normpath( os.path.join(os.path.dirname(joinlist[0]), '.vidcutter.list')) fobj = open(listfile, 'w') for file in joinlist: fobj.write('file \'%s\'\n' % file.replace("'", "\\'")) fobj.close() self.videoService.join(listfile, filename) QFile.remove(listfile) for file in joinlist: if os.path.isfile(file): QFile.remove(file) def updateCheck(self) -> None: self.updater = Updater() self.updater.updateAvailable.connect(self.updateHandler) self.updater.start() def updateHandler(self, updateExists: bool, version: str = None): if updateExists: if Updater.notify_update(self, version) == QMessageBox.AcceptRole: self.updater.install_update(self) else: Updater.notify_no_update(self) def showProgress(self, steps: int, label: str = 'Analyzing media...') -> None: self.progress = QProgressDialog(label, None, 0, steps, self.parent, windowModality=Qt.ApplicationModal, windowIcon=self.parent.windowIcon(), minimumDuration=0, minimumWidth=500) self.progress.show() for i in range(steps): self.progress.setValue(i) qApp.processEvents() time.sleep(1) def complete(self) -> None: info = QFileInfo(self.finalFilename) mbox = QMessageBox(windowTitle='VIDEO PROCESSING COMPLETE', minimumWidth=500, textFormat=Qt.RichText) mbox.setText( ''' <style> table.info { margin:6px; padding:4px 15px; } td.label { font-weight:bold; font-size:10.5pt; text-align:right; } td.value { font-size:10.5pt; } </style> <table class="info" cellpadding="4" cellspacing="0"> <tr> <td class="label"><b>File:</b></td> <td class="value" nowrap>%s</td> </tr> <tr> <td class="label"><b>Size:</b></td> <td class="value">%s</td> </tr> <tr> <td class="label"><b>Length:</b></td> <td class="value">%s</td> </tr> </table><br/>''' % (QDir.toNativeSeparators( self.finalFilename), self.sizeof_fmt(int(info.size())), self.deltaToQTime(self.totalRuntime).toString(self.timeformat))) play = mbox.addButton('Play', QMessageBox.AcceptRole) play.setIcon(self.completePlayIcon) play.clicked.connect(self.openResult) fileman = mbox.addButton('Open', QMessageBox.AcceptRole) fileman.setIcon(self.completeOpenIcon) fileman.clicked.connect(self.openFolder) end = mbox.addButton('Exit', QMessageBox.AcceptRole) end.setIcon(self.completeExitIcon) end.clicked.connect(self.close) new = mbox.addButton('Restart', QMessageBox.AcceptRole) new.setIcon(self.completeRestartIcon) new.clicked.connect(self.parent.restart) mbox.setDefaultButton(new) mbox.setEscapeButton(new) mbox.adjustSize() mbox.exec_() def sizeof_fmt(self, num: float, suffix: chr = 'B') -> str: for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']: if abs(num) < 1024.0: return "%3.1f%s%s" % (num, unit, suffix) num /= 1024.0 return "%.1f%s%s" % (num, 'Y', suffix) @pyqtSlot() def openFolder(self) -> None: self.openResult(pathonly=True) @pyqtSlot(bool) def openResult(self, pathonly: bool = False) -> None: self.parent.restart() if len(self.finalFilename) and os.path.exists(self.finalFilename): target = self.finalFilename if not pathonly else os.path.dirname( self.finalFilename) QDesktopServices.openUrl(QUrl.fromLocalFile(target)) @pyqtSlot() def startNew(self) -> None: qApp.restoreOverrideCursor() self.clearList() self.seekSlider.setValue(0) self.seekSlider.setRange(0, 0) self.mediaPlayer.setMedia(QMediaContent()) self.initNoVideo() self.videoLayout.replaceWidget(self.videoplayerWidget, self.novideoWidget) self.initMediaControls(False) self.parent.setWindowTitle('%s' % qApp.applicationName()) def wheelEvent(self, event: QWheelEvent) -> None: if self.mediaPlayer.isVideoAvailable( ) or self.mediaPlayer.isAudioAvailable(): if event.angleDelta().y() > 0: newval = self.seekSlider.value() - 1000 else: newval = self.seekSlider.value() + 1000 self.seekSlider.setValue(newval) self.seekSlider.setSliderPosition(newval) self.mediaPlayer.setPosition(newval) event.accept() def keyPressEvent(self, event: QKeyEvent) -> None: if self.mediaPlayer.isVideoAvailable( ) or self.mediaPlayer.isAudioAvailable(): addtime = 0 if event.key() == Qt.Key_Left: addtime = -1000 elif event.key() == Qt.Key_PageUp or event.key() == Qt.Key_Up: addtime = -10000 elif event.key() == Qt.Key_Right: addtime = 1000 elif event.key() == Qt.Key_PageDown or event.key() == Qt.Key_Down: addtime = 10000 elif event.key() == Qt.Key_Enter: self.toggleFullscreen() elif event.key( ) == Qt.Key_Escape and self.videoWidget.isFullScreen(): self.videoWidget.setFullScreen(False) if addtime != 0: newval = self.seekSlider.value() + addtime self.seekSlider.setValue(newval) self.seekSlider.setSliderPosition(newval) self.mediaPlayer.setPosition(newval) event.accept() def mousePressEvent(self, event: QMouseEvent) -> None: if event.button() == Qt.BackButton and self.cutStartAction.isEnabled(): self.setCutStart() event.accept() elif event.button( ) == Qt.ForwardButton and self.cutEndAction.isEnabled(): self.setCutEnd() event.accept() else: super(VidCutter, self).mousePressEvent(event) @pyqtSlot(QMediaPlayer.Error) def handleError(self, error: QMediaPlayer.Error) -> None: qApp.restoreOverrideCursor() self.startNew() if error == QMediaPlayer.ResourceError: QMessageBox.critical( self.parent, 'INVALID MEDIA', 'Invalid media file detected at:<br/><br/><b>%s</b><br/><br/>%s' % (self.movieFilename, self.mediaPlayer.errorString())) else: QMessageBox.critical(self.parent, 'ERROR NOTIFICATION', self.mediaPlayer.errorString()) def closeEvent(self, event: QCloseEvent) -> None: self.parent.closeEvent(event)
class PlayerSound(QWidget): ''' represente le lecteur de musique, permettant de mettre pause/play, changer de musique, etc. :param board: le tableau de bord du lecteur :type board: model.Board ''' def __init__(self, board, parent=None): QWidget.__init__(self, parent) # hauteur du lecteur heightWindow = 125 self.setMinimumHeight(heightWindow) self.setMaximumHeight(heightWindow) # images des bouttons self.iconPlay = QIcon(QPixmap("assets/play.png")) self.iconPause = QIcon(QPixmap("assets/pause.png")) iconNext = QIcon(QPixmap("assets/next.png")) iconPrecedent = QIcon(QPixmap("assets/precedent.png")) iconShuffle = QIcon(QPixmap("assets/shuffle.png")) iconReplay = QIcon(QPixmap("assets/replay.png")) self.iconSoundOn = QIcon(QPixmap("assets/soundOn.png")) self.iconSoundOff = QIcon(QPixmap("assets/soundOff.png")) iconConfig = QIcon(QPixmap("assets/config.png")) # taille des bouttons iconSize = QSize(50, 50) self.board = board self.isPlaying = False # lecteur Qt et musique en cours currentSong = self.board.getCurrentSong() self.player = QMediaPlayer() nameSong = "" nameAuthor = "" if currentSong: nameSong = currentSong.getName() nameAuthor = currentSong.getAuthor() self.songName = QLabel(nameSong) self.songAuthor = QLabel(nameAuthor) self.songName.setWordWrap(True) self.songName.setFixedWidth(310) self.songName.setProperty("class", "songName") self.songAuthor.setProperty("class", "author") self.player.mediaStatusChanged.connect(self.mediaFinished) self.player.positionChanged.connect(self.changeSliderPosition) # bouttons au dessus de la barre de progression de la lecture de la musique bShuffle = QPushButton() bShuffle.setToolTip("Melanger la liste d'attente") bShuffle.setFixedSize(iconSize) bShuffle.setIcon(iconShuffle) bShuffle.setIconSize(iconSize) bShuffle.clicked.connect(self.shuffle) bPrecedent = QPushButton() bPrecedent.setFixedSize(iconSize) bPrecedent.setIcon(iconPrecedent) bPrecedent.setIconSize(iconSize) bPrecedent.clicked.connect(self.precedentSong) self.bPlay = QPushButton() self.bPlay.setFixedSize(iconSize) self.bPlay.setIcon(self.iconPlay) self.bPlay.setIconSize(iconSize) self.bPlay.clicked.connect(self.play) bNext = QPushButton() bNext.setFixedSize(iconSize) bNext.setIcon(iconNext) bNext.setIconSize(iconSize) bNext.clicked.connect(self.nextSong) bReplay = QPushButton() bReplay.setToolTip("Rejouer") bReplay.setFixedSize(iconSize) bReplay.setIcon(iconReplay) bReplay.setIconSize(iconSize) bReplay.clicked.connect(self.replay) # barre de progression de la lecture de la musique en cours self.sliderSong = QSlider(Qt.Horizontal) self.sliderSong.setMinimumWidth(600) self.sliderSong.setMaximumWidth(600) self.labCurrentDuration = QLabel("0:00") self.labCurrentDuration.setProperty("class", "duration") self.volumeSlider = QSlider(Qt.Horizontal) self.labMaxDuration = QLabel("0:00") self.labMaxDuration.setProperty("class", "duration") # controles sur le son de la musique self.bMute = QPushButton() self.bMute.setIcon(self.iconSoundOn) self.bMute.setFixedSize(iconSize) self.bMute.setIconSize(iconSize) self.bMute.clicked.connect(self.mute) self.labelVolume = QLabel("100") self.labelVolume.setAlignment(Qt.AlignCenter) self.volumeSlider.setFixedWidth(250) self.volumeSlider.setValue(100) self.volumeSlider.valueChanged.connect(self.changeVolume) # boutton pour ouvrir la fenetre de parametres bParams = QPushButton() bParams.setToolTip("Parametres") bParams.setFixedSize(iconSize) bParams.setIcon(iconConfig) bParams.setIconSize(iconSize) bParams.clicked.connect(self.openParams) # position elements leftInfoSong = QVBoxLayout() leftInfoSong.addWidget(self.songName) leftInfoSong.addWidget(self.songAuthor) centerPlayer = QVBoxLayout() buttonsPlayer = QHBoxLayout() buttonsPlayer.addStretch() buttonsPlayer.addWidget(bShuffle) buttonsPlayer.addSpacing(8) buttonsPlayer.addWidget(bPrecedent) buttonsPlayer.addSpacing(8) buttonsPlayer.addWidget(self.bPlay) buttonsPlayer.addSpacing(8) buttonsPlayer.addWidget(bNext) buttonsPlayer.addSpacing(8) buttonsPlayer.addWidget(bReplay) buttonsPlayer.addStretch() centerPlayer.addLayout(buttonsPlayer) sliderWithTime = QHBoxLayout() sliderWithTime.addWidget(self.labCurrentDuration) sliderWithTime.addWidget(self.sliderSong) sliderWithTime.addWidget(self.labMaxDuration) centerPlayer.addLayout(sliderWithTime) rightVolumeParam = QVBoxLayout() sliderAndMuteLayout = QHBoxLayout() sliderAndMuteLayout.addWidget(self.bMute) sliderAndMuteLayout.addWidget(self.volumeSlider) rightVolumeParam.addLayout(sliderAndMuteLayout) otherButtonsZone = QHBoxLayout() otherButtonsZone.addStretch() otherButtonsZone.addWidget(bParams) otherButtonsZone.addStretch() rightVolumeParam.addLayout(otherButtonsZone) # positionnement global layout = QHBoxLayout() self.setLayout(layout) layout.addLayout(leftInfoSong) layout.addStretch() layout.addLayout(centerPlayer) layout.addStretch() layout.addLayout(rightVolumeParam) def mediaFinished(self, status): if status == QMediaPlayer.EndOfMedia: self.nextSong() def shuffle(self): self.board.shuffle(5) def replay(self): self.player.setPosition(0) self.sliderSong.setValue(0) self.update() def play(self): state = self.player.state() currentSong = self.board.getCurrentSong() if currentSong: if state == QMediaPlayer.PausedState or state == QMediaPlayer.StoppedState: if state == QMediaPlayer.StoppedState: self.setSongInPlayer() self.player.play() self.bPlay.setIcon(self.iconPause) self.isPlaying = True else: self.player.pause() self.bPlay.setIcon(self.iconPlay) self.isPlaying = False def mute(self): isMuted = self.player.isMuted() self.player.setMuted(not isMuted) if isMuted: self.bMute.setIcon(self.iconSoundOn) else: self.bMute.setIcon(self.iconSoundOff) def nextSong(self): self.board.nextSong() self.player.stop() self.setSongInPlayer() if self.isPlaying: self.play() def precedentSong(self): state = self.player.state() stateStop = QMediaPlayer.StoppedState statePause = QMediaPlayer.PausedState playerStoped = state == stateStop or state == statePause if not playerStoped: self.player.stop() self.board.precedentSong() self.setSongInPlayer() if not playerStoped: self.player.play() def setSongInPlayer(self): ''' set la musique courante dans le lecteur Qt ''' song = self.board.getCurrentSong() url = QUrl.fromLocalFile(song.getFullFilename()) self.player.setMedia(QMediaContent(url)) # set du temps maximum pour la barre de progression self.sliderSong.setMaximum(song.getDuration()) self.labMaxDuration.setText(getStrDuration(song.getDuration())) def changeSliderPosition(self, position): self.sliderSong.setValue(position) self.update() def changeVolume(self): valueVolume = self.volumeSlider.value() self.player.setVolume(valueVolume) def openParams(self): w = QMainWindow(self) w.setCentralWidget(ConfigWindow(self.board, w)) w.setGeometry(650, 500, 600, 150) w.setStyleSheet(open("src/gui/styleSheet/styleParam.qss", "r").read()) w.setWindowTitle("Parametres") w.show() def update(self): song = self.board.getCurrentSong() if song: self.songName.setText(song.getName()) self.songAuthor.setText(song.getAuthor()) else: self.songName.setText("") self.songAuthor.setText("") self.player.stop() self.bPlay.setIcon(self.iconPlay) self.isPlaying = False self.labCurrentDuration.setText(getStrDuration(self.player.position()))
class NewProject(QtWidgets.QWidget, Ui_NewProject): def __init__(self, projectfile, MainWidget): QtWidgets.QWidget.__init__(self) self.setupUi(self) self.setWindowFlags(Qt.WindowStaysOnTopHint) self.Main = MainWidget self.iface = self.Main.iface self.muteButton.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume)) self.replayPlay_pushButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) if projectfile.split('.')[-1] == "vgp": self.projectfile = projectfile else: self.projectfile = projectfile + '.vgp' self.videofile = None self.GPXfile = None self.GPXList = None self.fps = None self.RealFps = None self.DB = None self.player = QMediaPlayer() self.player.setVideoOutput(self.video_frame_2) self.player.durationChanged.connect(self.durationChanged) self.player.positionChanged.connect(self.positionChanged) self.player.stateChanged.connect(self.mediaStateChanged) self.toolButton_3.clicked.connect(self.ManageDB) self.pushButton_2.clicked.connect(self.Synchronize) self.pushButton.clicked.connect(self.SelectVideoGPX) self.replayPlay_pushButton.clicked.connect(self.PlayPause) self.muteButton.clicked.connect(self.MuteUnmute) self.horizontalSlider.sliderMoved.connect(self.setPosition) self.toolButton.clicked.connect(self.SkipBackward) self.toolButton_2.clicked.connect(self.SkipForward) self.SkipBacktoolButton_7.clicked.connect(self.BackwardFrame) self.SkipFortoolButton_8.clicked.connect(self.ForwardFrame) def closeEvent(self, *args, **kwargs): self.player.stop() return QtWidgets.QWidget.closeEvent(self, *args, **kwargs) def mediaStateChanged(self, state): if self.player.state() == QMediaPlayer.PlayingState: self.replayPlay_pushButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.replayPlay_pushButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) def Synchronize(self): TimeItem = self.comboBox.currentIndex() duration = self.player.duration() position = self.player.position() VideoPartLen = round((duration - position) / 1000) GpxPartition = self.GPXList[TimeItem:VideoPartLen + TimeItem] outputFile = open(self.projectfile, 'w') if self.DB == None: outputFile.write( 'VideoGis Project v0.1 DO NOT MODIFY' + '\nVideo file location = ' + self.videofile + '\nVideo start at msecond: ' + str(self.player.position()) + ' #fps = ' + str(self.RealFps) + '\nDB = None' + '\n' + 'Latitude # Longitude # Ele # Speed (m/s) # Course # Time \n') else: outputFile.write( 'Video file location = ' + self.videofile + '\nVideo start at msecond: ' + str(self.player.position()) + ' #fps = ' + str(self.RealFps) + '\nDB = ' + str(self.DB.dataProvider().dataSourceUri().split('|')[0]) + '\n' + 'Latitude # Longitude # Ele # Speed (m/s) # Course # Time \n') Counter = 0 for x in GpxPartition: if Counter != 0: ActualLatitude = x[1][0] ActualLongitude = x[1][1] PreviousLatitude = GpxPartition[Counter - 1][1][0] PreviousLongitude = GpxPartition[Counter - 1][1][1] GeodesicCalcolus = Geodesic.WGS84.Inverse( PreviousLatitude, PreviousLongitude, ActualLatitude, ActualLongitude) Speed = GeodesicCalcolus['s12'] / 1 Course = GeodesicCalcolus['azi2'] if Course < 0: Course += 360 Ele = x[1][2] Time = x[1][3] Counter = Counter + 1 else: ActualLatitude = x[1][0] ActualLongitude = x[1][1] PreviousLatitude = GpxPartition[Counter + 1][1][0] PreviousLongitude = GpxPartition[Counter + 1][1][1] GeodesicCalcolus = Geodesic.WGS84.Inverse( ActualLatitude, ActualLongitude, PreviousLatitude, PreviousLongitude) Speed = GeodesicCalcolus['s12'] * 1 Course = GeodesicCalcolus['azi2'] if Course < 0: Course += 360 Ele = x[1][2] Time = x[1][3] Counter = Counter + 1 outputFile.write( str(ActualLatitude) + ' ' + str(ActualLongitude) + ' ' + str(Ele) + ' ' + str(Speed) + ' ' + str(Course) + ' ' + str(Time) + '\n') outputFile.close() self.Main.LoadProjFromNew(self.projectfile) if os.name == 'nt': os.remove(self.tmp) self.close() def SelectVideoGPX(self): if os.name == 'nt': ffmpeg = os.path.dirname(__file__) + '/FFMPEG/ffmpeg.exe' versione = 'ffmpeg.exe' else: ffmpeg = os.path.dirname(__file__) + '/FFMPEG/./ffmpeg' versione = 'ffmpeg' if os.path.exists(ffmpeg) == True: self.comboBox.clear() if self.player.state() == QMediaPlayer.PlayingState: self.player.pause() self.videofile = None self.GPXfile = None options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog self.videofile, _ = QFileDialog.getOpenFileName( self, "Select Video File", "", "All Files (*);;Video File (*.mp4 *.avi *.ogv)", options=options) if self.videofile: self.GPXfile, _ = QFileDialog.getOpenFileName( self, "Select GPX file", "", "All Files (*);;Video File (*.gpx)", options=options) if self.GPXfile: self.ParseGpx(self.GPXfile) self.LoadVideo(self.videofile) self.replayPosition_label.setText("-:- / -:-") else: ret = QMessageBox.warning( self, "Warning", 'missing ffmpeg binaries, please download it from https://github.com/sagost/VideoUavTracker/blob/master/FFMPEG/' + versione + ' and paste it in /.qgis3/python/plugins/Video_UAV_Tracker/FFMPEG/ ', QMessageBox.Ok) self.close() def ParseGpx(self, GPXfile): gpx = parse(GPXfile) track = gpx.getElementsByTagName("trkpt") GPXList = [] Error = 0 GpxProgressiveNumber = 0 Timestamp = 'Segnaposto' for name in track: dict = {'Lat': 0, 'Lon': 0, 'Ele': 0, 'Time': 0} a = (name.toprettyxml(indent='')).split() for x in a: if x.find('lat') == 0: lat = float(x.split('"')[1]) dict['Lat'] = float(x.split('"')[1]) elif x.find('lon') == 0: lon = float(x.split('"')[1]) dict['Lon'] = float(x.split('"')[1]) elif x.find('<ele>') == 0: dict['Ele'] = float(x[5:-6]) elif x.find('<time>') == 0: try: gpxtime = time.strftime( '%Y-%m-%dT%H:%M:%S.%fZ', time.strptime(x[6:-7], '%Y-%m-%dT%H:%M:%S.%fZ')) dict['Time'] = x[6:-7] except ValueError: try: gpxtime = time.strftime( '%Y-%m-%dT%H:%M:%SZ', time.strptime(x[6:-7], '%Y-%m-%dT%H:%M:%SZ')) dict['Time'] = x[6:-7] except ValueError: try: gpxtime = time.strftime( '%Y-%m-%dT%H:%M:%S', time.strptime(x[6:-7], '%Y-%m-%dT%H:%M:%S')) dict['Time'] = x[6:-7] except ValueError: try: gpxtime = time.strftime( '%Y-%m-%dT%H.%M.%S', time.strptime(x[6:-7], '%Y-%m-%dT%H.%M.%S')) dict['Time'] = x[6:-7] except ValueError: try: gpxtime = time.strftime( '%Y-%m-%dT%H.%M.%S', time.strptime( x[6:-13], '%Y-%m-%dT%H.%M.%S')) dict['Time'] = x[6:-13] except ValueError: try: gpxtime = time.strftime( '%Y-%m-%dT%H.%M.%S', time.strptime( x[6:-13], '%Y-%m-%dT%H:%M:%S')) dict['Time'] = x[6:-13] except ValueError: Error = 1 FormatoErrore = str(x) if dict['Time'] != Timestamp: Point = [dict['Lat'], dict['Lon'], dict['Ele'], dict['Time']] self.comboBox.addItem( str(GpxProgressiveNumber) + '-' + gpxtime) GPXList.append([GpxProgressiveNumber, Point]) GpxProgressiveNumber = GpxProgressiveNumber + 1 Timestamp = dict['Time'] else: Timestamp = dict['Time'] if Error == 0: self.GPXList = GPXList else: ret = QMessageBox.warning( self, "Warning", FormatoErrore + ' UNKOWN GPX TIME FORMAT - ABORTED', QMessageBox.Ok) self.close def LoadVideo(self, videofile): fps = self.getVideoDetails(str(videofile)) self.RealFps = float(fps) self.fps = (1 / self.RealFps) * 1000 url = QUrl.fromLocalFile(str(self.videofile)) mc = QMediaContent(url) self.player.setMedia(mc) self.player.play() def setPosition(self, position): self.player.setPosition(position * 1000) def durationChanged(self, duration): duration /= 1000 self.horizontalSlider.setMaximum(duration) def secTotime(self, seconds): m, s = divmod(seconds, 60) h, m = divmod(m, 60) return "%d:%02d:%02d" % (h, m, s) def positionChanged(self, progress): duration = self.player.duration() totalTime = self.secTotime(duration / 1000) actualTime = self.secTotime(progress / 1000) self.replayPosition_label.setText(actualTime + ' / ' + totalTime) progress /= 1000 if not self.horizontalSlider.isSliderDown(): self.horizontalSlider.setValue(progress) def MuteUnmute(self): if self.player.mediaStatus() == 6: if self.player.isMuted() == 1: self.player.setMuted(0) self.muteButton.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume)) elif self.player.isMuted() == 0: self.player.setMuted(1) self.muteButton.setIcon(self.style().standardIcon( QStyle.SP_MediaVolumeMuted)) def PlayPause(self): if self.player.state() == QMediaPlayer.PlayingState: self.player.pause() else: self.player.play() def getVideoDetails(self, filepath): if os.name == 'nt': tmp = os.path.dirname(__file__)[0:-18] + '/Video_UAV_Tracker/tmp' tmp2 = '"' + tmp + '"' filepath2 = '"' + filepath + '"' a = open(tmp, 'w') a.close() ffmpeg = '"' + os.path.dirname( __file__)[0:-18] + '/Video_UAV_Tracker/FFMPEG/ffmpeg.exe' + '"' a = os.popen(str(ffmpeg + ' -i ' + filepath2 + ' 2> ' + tmp2)) while os.stat(tmp).st_size < 1500: pass a = open(tmp, 'r') lines = a.readlines() a.close() for l in lines: l = l.strip() if str(l).startswith("Stream #0:0"): linea = str(l).split(',')[-4] dopo = linea.find('fps') fps = float(linea[0:dopo]) self.tmp = tmp return fps else: tmpf = tempfile.NamedTemporaryFile() ffmpeg = os.path.dirname(__file__) + '/FFMPEG/./ffmpeg' os.system(str(ffmpeg) + " -i \"%s\" 2> %s" % (filepath, tmpf.name)) lines = tmpf.readlines() tmpf.close() for l in lines: l = l.strip() if str(l).startswith("b'Stream #0:0"): linea = str(l).split(',')[-4] dopo = linea.find('fps') fps = float(linea[0:dopo]) return fps def SkipForward(self): position = self.player.position() self.player.setPosition(position + 1000) def SkipBackward(self): position = self.player.position() self.player.setPosition(position - 1000) def ForwardFrame(self): position = self.player.position() self.player.setPosition(position + int(self.fps)) def BackwardFrame(self): position = self.player.position() self.player.setPosition(position - int(self.fps)) def ManageDB(self): self.player.pause() shapeFileFirst, _ = QFileDialog.getSaveFileName( caption='Save shape file', filter="Esri shp (*.shp)") if shapeFileFirst: if shapeFileFirst.split('.')[-1] == 'shp': shapeFile = shapeFileFirst else: shapeFile = shapeFileFirst + '.shp' try: os.remove(shapeFile) os.remove(shapeFileFirst.split('.')[0] + '.qpg') os.remove(shapeFileFirst.split('.')[0] + '.prj') os.remove(shapeFileFirst.split('.')[0] + '.cpg') os.remove(shapeFileFirst.split('.')[0] + '.shx') os.remove(shapeFileFirst.split('.')[0] + '.dbf') except OSError: pass crs = QgsCoordinateReferenceSystem( 4326, QgsCoordinateReferenceSystem.EpsgCrsId) fields = QgsFields() QgsVectorFileWriter(shapeFile, "CP1250", fields, QgsWkbTypes.Point, crs, "ESRI Shapefile") EmptyLayer = QgsVectorLayer(shapeFile, shapeFile.split('.')[0].split('/')[-1], 'ogr') self.dialoga = TableManager(self.iface, EmptyLayer, self) self.dialoga.exec_() def AcceptNewDB(self, DB): self.DB = DB
class NewProject(QtWidgets.QWidget, Ui_NewProject): def __init__(self,projectfile,MainWidget): QtWidgets.QWidget.__init__(self) self.setupUi(self) self.setWindowFlags(Qt.WindowStaysOnTopHint) self.Main = MainWidget self.iface = self.Main.iface self.muteButton.setIcon( self.style().standardIcon(QStyle.SP_MediaVolume)) self.replayPlay_pushButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPlay)) if projectfile.split('.')[-1] =="vut": self.projectfile = projectfile else: self.projectfile = projectfile +'.vut' self.videofile = None self.GPXfile = None self.GPXList = None self.fps = None self.RealFps = None self.DB = None self.DEM = None self.Image = None self.HFilmSize = None self.VFilmSize = None self.FocalLenght = None self.GPXMode = 2 self.Course = 0 self.player = QMediaPlayer() self.player.setVideoOutput(self.video_frame_2) self.player.durationChanged.connect(self.durationChanged) self.player.positionChanged.connect(self.positionChanged) self.player.stateChanged.connect(self.mediaStateChanged) self.toolButton_3.clicked.connect(self.ManageDB) self.pushButton_2.clicked.connect(self.Synchronize) self.pushButton.clicked.connect(self.SelectVideoGPX) self.replayPlay_pushButton.clicked.connect(self.PlayPause) self.muteButton.clicked.connect(self.MuteUnmute) self.horizontalSlider.sliderMoved.connect(self.setPosition) self.toolButton.clicked.connect(self.SkipBackward) self.toolButton_2.clicked.connect(self.SkipForward) self.SkipBacktoolButton_7.clicked.connect(self.BackwardFrame) self.SkipFortoolButton_8.clicked.connect(self.ForwardFrame) self.toolButton_4.clicked.connect(self.Setup3DParameterer) if os.name == 'nt': self.toolButton_4.setEnabled(False) def Setup3DParameterer(self): treDOptions = Setup3D(QgsProject) a = treDOptions.exec_() if a == 1: self.DEM = treDOptions.DEM self.Image = treDOptions.Image self.HFilmSize = treDOptions.HFilmSize self.VFilmSize = treDOptions.VFilmSize self.FocalLenght = treDOptions.FocalLenght self.GPXMode = treDOptions.GPXMODE if self.GPXMode == 1: self.HeadingOffset = treDOptions.HeadingOffset self.PitchOffset = treDOptions.PitchOffset self.RollOffset = treDOptions.RollOffset def closeEvent(self, *args, **kwargs): self.player.stop() return QtWidgets.QWidget.closeEvent(self, *args, **kwargs) def mediaStateChanged(self, state): if self.player.state() == QMediaPlayer.PlayingState: self.replayPlay_pushButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPause)) else: self.replayPlay_pushButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPlay)) def Synchronize(self): TimeItem = self.comboBox.currentIndex() duration = self.player.duration() position = self.player.position() VideoPartLen = round((duration-position) / 1000) GpxPartition = self.GPXList[TimeItem:VideoPartLen+TimeItem] outputFile = open(self.projectfile ,'w') if self.checkBox.isChecked(): PixelConversion = str(1) else: PixelConversion = str(0) if self.DB == None: outputFile.write('Video UAV Tracker Project v0.2 DO NOT MODIFY'+ '\nVideo file location = ' +self.videofile+ '\nVideo start at msecond: '+ str(self.player.position())+ ' #fps = '+str(self.RealFps)+' '+str(self.VideoWidth)+' '+str(self.VideoHeight)+' '+PixelConversion+ '\nDB = None'+ '\n3D = ' + str(self.DEM) + ',' + str(self.Image) + ',' + str(self.HFilmSize) + ',' + str(self.VFilmSize) + ',' + str(self.FocalLenght) +','+str(self.Course)+ '\n'+'Latitude # Longitude # Ele # Speed (m/s) # Course # Time \n') else: outputFile.write('Video UAV Tracker Project v0.2 DO NOT MODIFY'+ '\nVideo file location = ' +self.videofile+ '\nVideo start at msecond: '+ str(self.player.position())+ ' #fps = '+str(self.RealFps)+' '+str(self.VideoWidth)+' '+str(self.VideoHeight)+' '+PixelConversion+ '\nDB = '+str(self.DB.dataProvider().dataSourceUri().split('|')[0])+ '\n3D = '+str(self.DEM)+','+str(self.Image)+','+str(self.HFilmSize)+','+str(self.VFilmSize)+','+str(self.FocalLenght)+','+str(self.Course)+ '\n'+'Latitude # Longitude # Ele # Speed (m/s) # Course # Time \n') Counter = 0 for x in GpxPartition: if Counter != 0: ActualLatitude = x[1][0] ActualLongitude = x[1][1] PreviousLatitude = GpxPartition[Counter-1][1][0] PreviousLongitude = GpxPartition[Counter-1][1][1] GeodesicCalcolus = Geodesic.WGS84.Inverse(PreviousLatitude, PreviousLongitude, ActualLatitude, ActualLongitude) Speed = GeodesicCalcolus['s12'] /1 if self.Course == 1: Course = float(x[1][4]) Pitch = float(x[1][5]) Roll = float(x[1][6]) else: Course = GeodesicCalcolus['azi2'] if Course < 0: Course += 360 Pitch = 0 Roll = 0 if self.GPXMode == 1: # correct value with fixed offset Course = Course + self.HeadingOffset if Course > 360: Course = Course -360 elif Course < 0: Course += 360 Pitch = Pitch + self.PitchOffset if Pitch < -180: Pitch = 360 - abs(Pitch) elif Pitch > 180: Pitch = -(360-Pitch) Roll = Roll + self.RollOffset if Roll < -180: Roll = 360 - abs(Roll) elif Roll > 180: Roll = -(360-Roll) Ele = x[1][2] Time = x[1][3] Counter = Counter + 1 else: ActualLatitude = x[1][0] ActualLongitude = x[1][1] PreviousLatitude = GpxPartition[Counter+1][1][0] PreviousLongitude = GpxPartition[Counter+1][1][1] GeodesicCalcolus = Geodesic.WGS84.Inverse(ActualLatitude, ActualLongitude, PreviousLatitude, PreviousLongitude) Speed = GeodesicCalcolus['s12'] * 1 if self.Course == 1: Course = float(x[1][4]) Pitch = float(x[1][5]) Roll = float(x[1][6]) else: Course = GeodesicCalcolus['azi2'] if Course < 0: Course += 360 Pitch = 0 Roll = 0 if self.GPXMode == 1: # correct value with fixed offset Course = Course + self.HeadingOffset if Course > 360: Course = Course -360 elif Course < 0: Course += 360 Pitch = Pitch + self.PitchOffset if Pitch < -180: Pitch = 360 - abs(Pitch) elif Pitch > 180: Pitch = -(360-Pitch) Roll = Roll + self.RollOffset if Roll < -180: Roll = 360 - abs(Roll) elif Roll > 180: Roll = -(360-Roll) Ele = x[1][2] Time = x[1][3] Counter = Counter + 1 outputFile.write(str(ActualLatitude)+' '+str(ActualLongitude)+ ' '+str(Ele)+' '+str(Speed)+' '+str(Course)+ ' '+str(Pitch)+' '+str(Roll)+' '+str(Time)+'\n') outputFile.close() self.Main.LoadProjFromNew(self.projectfile) self.close() def SelectVideoGPX(self): if os.name == 'nt': ffmpeg = os.path.dirname(__file__)+'/FFMPEG/ffprobe.exe' versione = 'ffprobe.exe' else: ffmpeg = os.path.dirname(__file__)+'/FFMPEG/./ffprobe' versione = 'ffprobe' if os.path.exists(ffmpeg): self.comboBox.clear() if self.player.state() == QMediaPlayer.PlayingState: self.player.pause() self.videofile = None self.GPXfile = None options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog self.videofile, _ = QFileDialog.getOpenFileName(self,"Select Video File", "","All Files (*);;Video File (*.mp4 *.avi *.ogv)", options=options) if self.videofile: self.GPXfile, _ = QFileDialog.getOpenFileName(self,"Select GPX file", "","All Files (*);;Video File (*.gpx)", options=options) if self.GPXfile: self.Course = 0 self.ParseGpx(self.GPXfile) self.LoadVideo(self.videofile) self.replayPosition_label.setText( "-:- / -:-") else: ret = QMessageBox.warning(self, "Warning", 'missing ffprobe binaries, please download it from https://github.com/sagost/Video_UAV_Tracker-3D/tree/master/Video_UAV_Tracker/FFMPEG'+versione+' and paste it in /.qgis3/python/plugins/Video_UAV_Tracker/FFMPEG/ ', QMessageBox.Ok) self.close() def ParseGpx(self,GPXfile): gpx = parse(GPXfile) track = gpx.getElementsByTagName("trkpt") GPXList = [] Error = 0 GpxProgressiveNumber = 0 Timestamp = 'Segnaposto' for name in track: dict = {'Lat': 0, 'Lon': 0, 'Ele': 0, 'Time':0,'Course':0,'Pitch':0,'Roll':0} a = (name.toprettyxml(indent = '') ).split() for x in a: if x.find('lat') == 0: lat = float(x.split('"')[1]) dict['Lat'] = float(x.split('"')[1]) elif x.find('lon') == 0: lon = float(x.split('"')[1]) dict['Lon'] = float(x.split('"')[1]) elif x.find('<ele>') == 0: dict['Ele'] = float(x[5:-6]) elif x.find('<time>') == 0: try: gpxtime = time.strftime('%Y-%m-%dT%H:%M:%S.%fZ',time.strptime(x[6:-7], '%Y-%m-%dT%H:%M:%S.%fZ')) dict['Time']= x[6:-7] except ValueError: try: gpxtime = time.strftime('%Y-%m-%dT%H:%M:%SZ',time.strptime(x[6:-7],'%Y-%m-%dT%H:%M:%SZ')) dict['Time']= x[6:-7] except ValueError: try: gpxtime = time.strftime('%Y-%m-%dT%H.%M.%S',time.strptime(x[6:-7],'%Y-%m-%dT%H.%M.%S')) dict['Time']= x[6:-7] except ValueError: try: gpxtime = time.strftime('%Y-%m-%dT%H.%M.%S',time.strptime(x[6:-13],'%Y-%m-%dT%H.%M.%S')) dict['Time']= x[6:-13] except ValueError: try: gpxtime = time.strftime('%Y-%m-%dT%H.%M.%S',time.strptime(x[6:-13],'%Y-%m-%dT%H:%M:%S')) dict['Time']= x[6:-13] except ValueError: try: gpxtime = time.strftime('%Y-%m-%dT%H.%M.%S', time.strptime(x[6:-7], '%Y-%m-%dT%H:%M:%S')) dict['Time'] = x[6:-7] except ValueError: Error = 1 FormatoErrore = str(x) elif x.find('<course>')==0: dict['Course'] = float(x[8:-9]) self.Course = 1 elif x.find('<yaw>') == 0: dict['Course'] = float(x[5:-6]) self.Course = 1 elif x.find('<pitch>') == 0: dict['Pitch'] = float(x[7:-8]) elif x.find('<roll>') == 0: dict['Roll'] = float(x[6:-7]) if dict['Time'] != Timestamp: if self.Course == 1: Point = [dict['Lat'], dict['Lon'], dict['Ele'], dict['Time'],dict['Course'],dict['Pitch'],dict['Roll']] else: Point = [dict['Lat'],dict['Lon'],dict['Ele'],dict['Time']] self.comboBox.addItem(str(GpxProgressiveNumber) + '-'+ gpxtime ) GPXList.append([GpxProgressiveNumber,Point]) GpxProgressiveNumber = GpxProgressiveNumber + 1 Timestamp = dict['Time'] else: Timestamp = dict['Time'] if Error == 0: self.GPXList = GPXList else: ret = QMessageBox.warning(self, "Warning", FormatoErrore +' UNKOWN GPX TIME FORMAT - ABORTED', QMessageBox.Ok) self.close() def LoadVideo(self,videofile): fps = self.getVideoDetails(str(videofile)) self.RealFps = float(fps) self.fps = (1 / self.RealFps )*1000 url = QUrl.fromLocalFile(str(self.videofile)) mc = QMediaContent(url) self.player.setMedia(mc) self.player.play() def setPosition(self, position): self.player.setPosition(position*1000) def durationChanged(self, duration): duration /= 1000 self.horizontalSlider.setMaximum(duration) def secTotime(self,seconds): m, s = divmod(seconds, 60) h, m = divmod(m, 60) return "%d:%02d:%02d" % (h, m, s) def positionChanged(self, progress): duration = self.player.duration() totalTime = self.secTotime(duration/1000) actualTime = self.secTotime(progress/1000) self.replayPosition_label.setText(actualTime + ' / '+totalTime) progress /= 1000 if not self.horizontalSlider.isSliderDown(): self.horizontalSlider.setValue(progress) def MuteUnmute(self): if self.player.mediaStatus() == 6 : if self.player.isMuted() == 1: self.player.setMuted(0) self.muteButton.setIcon( self.style().standardIcon(QStyle.SP_MediaVolume)) elif self.player.isMuted() == 0: self.player.setMuted(1) self.muteButton.setIcon( self.style().standardIcon(QStyle.SP_MediaVolumeMuted)) def PlayPause(self): if self.player.state() == QMediaPlayer.PlayingState: self.player.pause() else: self.player.play() def getVideoDetails(self,filepath): filepath2 = '"'+filepath+'"' if os.name == 'nt': ffmpeg = '"'+os.path.dirname(__file__)[0:-18]+'/Video_UAV_Tracker/FFMPEG/ffprobe.exe'+'"' else: ffmpeg = os.path.dirname(__file__)+'/FFMPEG/./ffprobe' p = os.popen(ffmpeg + ' -v error -show_format -show_streams '+filepath2) lines = p.readlines() for l in lines: l = l.strip() if str(l).startswith("width"): self.VideoWidth = str(l).split('=')[1] elif str(l).startswith("height"): self.VideoHeight = str(l).split('=')[1] elif str(l).startswith("r_frame_rate"): if str(l).split('=')[1] != '0/0' fps = float(str(l).split('=')[1].split('/')[0] ) / float(str(l).split('=')[1].split('/')[1] ) return fps def SkipForward(self): position = self.player.position() self.player.setPosition(position+1000) def SkipBackward(self): position = self.player.position() self.player.setPosition(position-1000) def ForwardFrame(self): position = self.player.position() self.player.setPosition(position+round(self.fps)) def BackwardFrame(self): position = self.player.position() self.player.setPosition(position-round(self.fps)) def ManageDB(self): self.player.pause() shapeFileFirst,_ = QFileDialog.getSaveFileName(caption = 'Save shape file', filter = "Esri shp (*.shp)") if shapeFileFirst: if shapeFileFirst.split('.')[-1] == 'shp': shapeFile = shapeFileFirst else: shapeFile = shapeFileFirst + '.shp' try: os.remove(shapeFile) os.remove(shapeFileFirst.split('.')[0]+'.qpg') os.remove(shapeFileFirst.split('.')[0]+'.prj') os.remove(shapeFileFirst.split('.')[0]+'.cpg') os.remove(shapeFileFirst.split('.')[0]+'.shx') os.remove(shapeFileFirst.split('.')[0]+'.dbf') except OSError: pass crs = QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId) fields = QgsFields() QgsVectorFileWriter(shapeFile, "CP1250", fields, QgsWkbTypes.Point, crs, "ESRI Shapefile") EmptyLayer = QgsVectorLayer(shapeFile, shapeFile.split('.')[0].split('/')[-1], 'ogr') self.dialoga = TableManager(self.iface, EmptyLayer,self) self.dialoga.exec_() def AcceptNewDB(self,DB): self.DB = DB
class MediaPlayer(QWidget): # 初始化 def __init__(self): super(MediaPlayer, self).__init__() self.setWindowTitle('播放器') # 先注册一个媒体播放器 self.player = QMediaPlayer(self) # 注册其他控件 self.volume_slider = QSlider(self) self.volume_save = 0 self.player.setVolume(36) # 进度条 self.progress_slider = QSlider(self) self.time_stamp = QLabel(self) # 按钮(PushButton)有,播放(暂停) 上一首,下一首 ,播放模式 self.preview_btn = QPushButton(self) # 播放按钮要切换播放与暂停 self.play_pause_btn = QPushButton(self) self.next_btn = QPushButton(self) self.play_mode = QPushButton() self.get_music = QPushButton('云音乐') self.sound_btn = QPushButton(self) # 播放列表 self.mediaList = QMediaPlaylist(self) self.play_list = QListWidget(self) self.songs_list = [] self.songs_formats = ['mp3', 'm4a', 'flac', 'wav', 'ogg'] # 布局注册 self.h1_layout = QHBoxLayout() self.h2_layout = QHBoxLayout() self.all_v_layout = QVBoxLayout() self.widget_init() self.layout_init() self.signal_init() self.center() '''控件初始化''' def widget_init(self): self.time_stamp.setText('--/--') self.volume_slider.setRange(0, 100) self.volume_slider.setValue(36) self.volume_slider.setOrientation(Qt.Horizontal) self.progress_slider.setEnabled(False) self.progress_slider.setOrientation(Qt.Horizontal) self.sound_btn.setIcon(QIcon('../icon_font/sound_on.png')) self.next_btn.setIcon(QIcon(r'..\icon\next.png')) self.play_pause_btn.setIcon(QIcon(r'..\icon\play.png')) self.preview_btn.setIcon(QIcon(r'..\icon\prev.png')) self.play_mode.setIcon(QIcon('../icon_font/list_down.png')) self.sound_btn.setIcon(QIcon(r'..\icon_font\sound_on.png')) self.player.setPlaylist(self.mediaList) self.mediaList.setPlaybackMode(QMediaPlaylist.Sequential) # 布局初始化 def layout_init(self): self.h1_layout.addWidget(self.progress_slider) # 5 self.h1_layout.addWidget(self.time_stamp) self.h2_layout.addWidget(self.preview_btn) self.h2_layout.addWidget(self.play_pause_btn) self.h2_layout.addWidget(self.next_btn) self.h2_layout.addWidget(self.sound_btn) self.h2_layout.addWidget(self.volume_slider) self.h2_layout.addWidget(self.play_mode) self.h2_layout.addWidget(self.get_music) self.all_v_layout.addLayout(self.h1_layout) self.all_v_layout.addWidget(self.play_list) self.all_v_layout.addLayout(self.h2_layout) self.all_v_layout.setSizeConstraint(QVBoxLayout.SetFixedSize) # 6 self.setLayout(self.all_v_layout) # 创建信号函数,连接槽函数 def signal_init(self): # self.preview_btn.clicked.connect(lambda: self.slot_func(self.preview_btn)) self.play_pause_btn.clicked.connect(lambda: self.slot_func(self.play_pause_btn)) self.next_btn.clicked.connect(lambda: self.slot_func(self.next_btn)) self.play_mode.clicked.connect(lambda: self.slot_func(self.play_mode)) self.sound_btn.clicked.connect(lambda: self.slot_func(self.sound_btn)) # 获取云音乐函数 self.get_music.clicked.connect(self.get_music_func) # 播放器音量控制 self.volume_slider.valueChanged.connect(self.volume_slider_func) self.play_list.doubleClicked.connect(self.play_list_func) self.player.durationChanged.connect(self.get_progress_func) self.player.positionChanged.connect(self.get_position_func) self.progress_slider.sliderMoved.connect(self.update_position_func) # 建立槽函数 def slot_func(self, btn): if btn == self.play_pause_btn: if self.player.state() == 1: self.player.pause() self.play_pause_btn.setIcon(QIcon(r'G:\python3\PyQt_Study\icon\play.png')) else: self.player.play() self.play_pause_btn.setIcon(QIcon(r'G:\python3\PyQt_Study\icon\pause.png')) #下一首 elif btn == self.next_btn: # 如果点击下一个按钮时为最后一首歌 if self.mediaList.currentIndex() == self.mediaList.mediaCount() - 1: self.mediaList.setCurrentIndex(0) self.play_list.setCurrentRow(0) else: # print(self.player.state()) if self.player.state() == 1: self.play_list.setCurrentRow(self.mediaList.currentIndex() + 1) self.mediaList.next() self.play_pause_btn.setIcon(QIcon(r'G:\python3\PyQt_Study\icon\pause.png')) # 上一首 elif btn == self.preview_btn: if self.mediaList.currentIndex() == 0: self.mediaList.setCurrentIndex(self.mediaList.mediaCount() -1) else: if self.player.state() == 1: self.mediaList.previous() self.play_pause_btn.setIcon(QIcon(r'G:\python3\PyQt_Study\icon\pause.png')) # 播放模式 elif btn == self.play_mode: # 根据播放模式切换 if self.mediaList.playbackMode() == 2: self.mediaList.setPlaybackMode(QMediaPlaylist.Loop) self.play_mode.setIcon(QIcon(r'G:\python3\PyQt_Study\icon_font\loop.png')) elif self.mediaList.playbackMode() == 3: self.mediaList.setPlaybackMode(QMediaPlaylist.Random) self.play_mode.setIcon(QIcon(r'..\icon_font\random.png')) elif self.mediaList.playbackMode() == 4: self.mediaList.setPlaybackMode(QMediaPlaylist.Sequential) self.play_mode.setIcon(QIcon(r'..\icon_font\list_loop.png')) # 声音按钮控制 elif btn == self.sound_btn: if self.player.isMuted(): # self.sound_btn.setIcon('') print("1", self.player.isMuted()) self.volume_slider.setValue(self.volume_save) self.player.setMuted(False) self.sound_btn.setIcon(QIcon(r'G:\python3\PyQt_Study\icon_font\sound_on.png')) else: print("2", self.player.isMuted()) self.player.setMuted(True) self.volume_save = self.volume_slider.value() self.volume_slider.setValue(0) self.sound_btn.setIcon(QIcon(r'G:\python3\PyQt_Study\icon_font\sound_off.png')) # 窗口居中 def center(self): qr = self.frameGeometry() # 获得主窗口的一个矩形特定几何图形。这包含了窗口的框架。 cp = QDesktopWidget().availableGeometry().center() # 算出相对于显示器的绝对值。 # 并且从这个绝对值中,我们获得了屏幕中心点。 qr.moveCenter(cp) # 矩形已经设置好了它的宽和高。现在我们把矩形的中心设置到屏幕的中间去。 # 矩形的大小并不会改变。 self.move(qr.topLeft()) # 移动了应用窗口的左上方的点到qr矩形的左上方的点,因此居中显示在我们的屏幕上。 # 获取音乐槽函数 def get_music_func(self): self.mediaList.clear() url = 'http://47.108.93.231:8000/cloudMusic' response = request.urlopen(url).read() # print(json.loads(response), type(json.loads(response))) # 读取数据库信息 # print(json.loads(response)) msg = json.loads(response)['msg'] for song in msg: if song['url'].split('.')[-1] in self.songs_formats: # self.songs_list.append([song, song['url']]) self.mediaList.addMedia(QMediaContent(QUrl(song['url']))) self.play_list.addItem(song['name']) self.play_list.setCurrentRow(0) # print(self.mediaList.mediaCount()) if self.songs_list: self.cur_playing_song = self.songs_list[self.play_list.currentRow()][-1] def volume_slider_func(self, val): self.player.setVolume(val) # if val == 0: # self.sound_btn.setICon(QIcon(r'G:\python3\PyQt_Study\icon\sound.png')) # else: # self.sound_btn.setIcon(QIcon(r'G:\python3\PyQt_Study\icon\sound.png')) # 播放列表双击函数 def play_list_func(self): self.mediaList.setCurrentIndex(self.play_list.currentRow()) self.player.play() self.play_pause_btn.setIcon(QIcon(r'G:\python3\PyQt_Study\icon\pause.png')) def get_progress_func(self, d): # 连接的函数,传入参数的d为毫秒。所以做一个时间变换 self.progress_slider.setRange(0, d) self.progress_slider.setEnabled(True) self.get_time_func(d) # 时间控制函数,每次调用改变滑条位置,以及时间减少 def get_time_func(self, d): seconds = int(d / 1000) minutes = int(seconds / 60) seconds -= minutes * 60 # print("%s分" %minutes, "%s秒" %seconds) if minutes == 0 and seconds == 0: self.time_stamp.setText("--/--") self.play_pause_btn.setIcon(QIcon(r'G:\python3\PyQt_Study\icon\play.png')) else: self.time_stamp.setText("{}:{}".format(minutes, seconds)) def get_position_func(self, p): self.progress_slider.setValue(p) self.get_time_func(self.progress_slider.maximum() - self.progress_slider.value()) # 当且仅当用户手动改变滑条位置时 def update_position_func(self, v): self.player.setPosition(v) d = self.progress_slider.maximum() - v self.get_time_func(d)
class NewProject(QtWidgets.QWidget, Ui_NewProject): def __init__(self,projectfile,MainWidget): QtWidgets.QWidget.__init__(self) self.setupUi(self) self.setWindowFlags(Qt.WindowStaysOnTopHint) self.Main = MainWidget self.iface = self.Main.iface self.muteButton.setIcon( self.style().standardIcon(QStyle.SP_MediaVolume)) self.replayPlay_pushButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPlay)) if projectfile.split('.')[-1] =="vgp": self.projectfile = projectfile else: self.projectfile = projectfile +'.vgp' self.videofile = None self.GPXfile = None self.GPXList = None self.fps = None self.RealFps = None self.DB = None self.player = QMediaPlayer() self.player.setVideoOutput(self.video_frame_2) self.player.durationChanged.connect(self.durationChanged) self.player.positionChanged.connect(self.positionChanged) self.player.stateChanged.connect(self.mediaStateChanged) self.toolButton_3.clicked.connect(self.ManageDB) self.pushButton_2.clicked.connect(self.Synchronize) self.pushButton.clicked.connect(self.SelectVideoGPX) self.replayPlay_pushButton.clicked.connect(self.PlayPause) self.muteButton.clicked.connect(self.MuteUnmute) self.horizontalSlider.sliderMoved.connect(self.setPosition) self.toolButton.clicked.connect(self.SkipBackward) self.toolButton_2.clicked.connect(self.SkipForward) self.SkipBacktoolButton_7.clicked.connect(self.BackwardFrame) self.SkipFortoolButton_8.clicked.connect(self.ForwardFrame) def closeEvent(self, *args, **kwargs): self.player.stop() return QtWidgets.QWidget.closeEvent(self, *args, **kwargs) def mediaStateChanged(self, state): if self.player.state() == QMediaPlayer.PlayingState: self.replayPlay_pushButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPause)) else: self.replayPlay_pushButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPlay)) def Synchronize(self): TimeItem = self.comboBox.currentIndex() duration = self.player.duration() position = self.player.position() VideoPartLen = round((duration-position) / 1000) GpxPartition = self.GPXList[TimeItem:VideoPartLen+TimeItem] outputFile = open(self.projectfile ,'w') if self.DB == None: outputFile.write('VideoGis Project v0.1 DO NOT MODIFY'+ '\nVideo file location = ' +self.videofile+ '\nVideo start at msecond: '+ str(self.player.position())+ ' #fps = '+str(self.RealFps)+ '\nDB = None'+ '\n'+'Latitude # Longitude # Ele # Speed (m/s) # Course # Time \n') else: outputFile.write('Video file location = ' +self.videofile+ '\nVideo start at msecond: '+ str(self.player.position())+ ' #fps = '+str(self.RealFps)+ '\nDB = '+str(self.DB.dataProvider().dataSourceUri().split('|')[0])+ '\n'+'Latitude # Longitude # Ele # Speed (m/s) # Course # Time \n') Counter = 0 for x in GpxPartition: if Counter != 0: ActualLatitude = x[1][0] ActualLongitude = x[1][1] PreviousLatitude = GpxPartition[Counter-1][1][0] PreviousLongitude = GpxPartition[Counter-1][1][1] GeodesicCalcolus = Geodesic.WGS84.Inverse(PreviousLatitude, PreviousLongitude, ActualLatitude, ActualLongitude) Speed = GeodesicCalcolus['s12'] /1 Course = GeodesicCalcolus['azi2'] if Course < 0: Course += 360 Ele = x[1][2] Time = x[1][3] Counter = Counter + 1 else: ActualLatitude = x[1][0] ActualLongitude = x[1][1] PreviousLatitude = GpxPartition[Counter+1][1][0] PreviousLongitude = GpxPartition[Counter+1][1][1] GeodesicCalcolus = Geodesic.WGS84.Inverse(ActualLatitude, ActualLongitude, PreviousLatitude, PreviousLongitude) Speed = GeodesicCalcolus['s12'] * 1 Course = GeodesicCalcolus['azi2'] if Course < 0: Course += 360 Ele = x[1][2] Time = x[1][3] Counter = Counter + 1 outputFile.write(str(ActualLatitude)+' '+str(ActualLongitude)+' '+str(Ele)+' '+str(Speed)+' '+str(Course)+' '+str(Time)+'\n') outputFile.close() self.Main.LoadProjFromNew(self.projectfile) if os.name == 'nt': os.remove (self.tmp) self.close() def SelectVideoGPX(self): if os.name == 'nt': ffmpeg = os.path.dirname(__file__)+'/FFMPEG/ffmpeg.exe' versione = 'ffmpeg.exe' else: ffmpeg = os.path.dirname(__file__)+'/FFMPEG/./ffmpeg' versione = 'ffmpeg' if os.path.exists(ffmpeg) == True: self.comboBox.clear() if self.player.state() == QMediaPlayer.PlayingState: self.player.pause() self.videofile = None self.GPXfile = None options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog self.videofile, _ = QFileDialog.getOpenFileName(self,"Select Video File", "","All Files (*);;Video File (*.mp4 *.avi *.ogv)", options=options) if self.videofile: self.GPXfile, _ = QFileDialog.getOpenFileName(self,"Select GPX file", "","All Files (*);;Video File (*.gpx)", options=options) if self.GPXfile: self.ParseGpx(self.GPXfile) self.LoadVideo(self.videofile) self.replayPosition_label.setText( "-:- / -:-") else: ret = QMessageBox.warning(self, "Warning", 'missing ffmpeg binaries, please download it from https://github.com/sagost/VideoUavTracker/blob/master/FFMPEG/'+versione+' and paste it in /.qgis3/python/plugins/Video_UAV_Tracker/FFMPEG/ ', QMessageBox.Ok) self.close() def ParseGpx(self,GPXfile): gpx = parse(GPXfile) track = gpx.getElementsByTagName("trkpt") GPXList = [] Error = 0 GpxProgressiveNumber = 0 Timestamp = 'Segnaposto' for name in track: dict = {'Lat': 0, 'Lon': 0, 'Ele': 0, 'Time':0} a = (name.toprettyxml(indent = '') ).split() for x in a: if x.find('lat') == 0: lat = float(x.split('"')[1]) dict['Lat'] = float(x.split('"')[1]) elif x.find('lon') == 0: lon = float(x.split('"')[1]) dict['Lon'] = float(x.split('"')[1]) elif x.find('<ele>') == 0: dict['Ele'] = float(x[5:-6]) elif x.find('<time>') == 0: try: gpxtime = time.strftime('%Y-%m-%dT%H:%M:%S.%fZ',time.strptime(x[6:-7], '%Y-%m-%dT%H:%M:%S.%fZ')) dict['Time']= x[6:-7] except ValueError: try: gpxtime = time.strftime('%Y-%m-%dT%H:%M:%SZ',time.strptime(x[6:-7],'%Y-%m-%dT%H:%M:%SZ')) dict['Time']= x[6:-7] except ValueError: try: gpxtime = time.strftime('%Y-%m-%dT%H:%M:%S',time.strptime(x[6:-7],'%Y-%m-%dT%H:%M:%S')) dict['Time']= x[6:-7] except ValueError: try: gpxtime = time.strftime('%Y-%m-%dT%H.%M.%S',time.strptime(x[6:-7],'%Y-%m-%dT%H.%M.%S')) dict['Time']= x[6:-7] except ValueError: try: gpxtime = time.strftime('%Y-%m-%dT%H.%M.%S',time.strptime(x[6:-13],'%Y-%m-%dT%H.%M.%S')) dict['Time']= x[6:-13] except ValueError: try: gpxtime = time.strftime('%Y-%m-%dT%H.%M.%S',time.strptime(x[6:-13],'%Y-%m-%dT%H:%M:%S')) dict['Time']= x[6:-13] except ValueError: Error = 1 FormatoErrore = str(x) if dict['Time'] != Timestamp: Point = [dict['Lat'],dict['Lon'],dict['Ele'],dict['Time']] self.comboBox.addItem(str(GpxProgressiveNumber) + '-'+gpxtime ) GPXList.append([GpxProgressiveNumber,Point]) GpxProgressiveNumber = GpxProgressiveNumber + 1 Timestamp = dict['Time'] else: Timestamp = dict['Time'] if Error == 0: self.GPXList = GPXList else: ret = QMessageBox.warning(self, "Warning", FormatoErrore +' UNKOWN GPX TIME FORMAT - ABORTED', QMessageBox.Ok) self.close def LoadVideo(self,videofile): fps = self.getVideoDetails(str(videofile)) self.RealFps = float(fps) self.fps = (1 / self.RealFps )*1000 url = QUrl.fromLocalFile(str(self.videofile)) mc = QMediaContent(url) self.player.setMedia(mc) self.player.play() def setPosition(self, position): self.player.setPosition(position*1000) def durationChanged(self, duration): duration /= 1000 self.horizontalSlider.setMaximum(duration) def secTotime(self,seconds): m, s = divmod(seconds, 60) h, m = divmod(m, 60) return "%d:%02d:%02d" % (h, m, s) def positionChanged(self, progress): duration = self.player.duration() totalTime = self.secTotime(duration/1000) actualTime = self.secTotime(progress/1000) self.replayPosition_label.setText(actualTime + ' / '+totalTime) progress /= 1000 if not self.horizontalSlider.isSliderDown(): self.horizontalSlider.setValue(progress) def MuteUnmute(self): if self.player.mediaStatus() == 6 : if self.player.isMuted() == 1: self.player.setMuted(0) self.muteButton.setIcon( self.style().standardIcon(QStyle.SP_MediaVolume)) elif self.player.isMuted() == 0: self.player.setMuted(1) self.muteButton.setIcon( self.style().standardIcon(QStyle.SP_MediaVolumeMuted)) def PlayPause(self): if self.player.state() == QMediaPlayer.PlayingState: self.player.pause() else: self.player.play() def getVideoDetails(self,filepath): if os.name == 'nt': tmp = os.path.dirname(__file__)[0:-18]+'/Video_UAV_Tracker/tmp' tmp2 = '"'+tmp+'"' filepath2 = '"'+filepath+'"' a = open(tmp,'w') a.close() ffmpeg = '"'+os.path.dirname(__file__)[0:-18]+'/Video_UAV_Tracker/FFMPEG/ffmpeg.exe'+'"' a = os.popen(str(ffmpeg + ' -i '+filepath2+' 2> '+tmp2)) while os.stat(tmp).st_size < 1500: pass a = open(tmp,'r') lines = a.readlines() a.close() for l in lines: l = l.strip() if str(l).startswith("Stream #0:0"): linea = str(l).split(',')[-4] dopo = linea.find('fps') fps = float(linea[0:dopo]) self.tmp = tmp return fps else: tmpf = tempfile.NamedTemporaryFile() ffmpeg = os.path.dirname(__file__)+'/FFMPEG/./ffmpeg' os.system(str(ffmpeg)+" -i \"%s\" 2> %s" % (filepath, tmpf.name)) lines = tmpf.readlines() tmpf.close() for l in lines: l = l.strip() if str(l).startswith("b'Stream #0:0"): linea = str(l).split(',')[-4] dopo = linea.find('fps') fps = float(linea[0:dopo]) return fps def SkipForward(self): position = self.player.position() self.player.setPosition(position+1000) def SkipBackward(self): position = self.player.position() self.player.setPosition(position-1000) def ForwardFrame(self): position = self.player.position() self.player.setPosition(position+int(self.fps)) def BackwardFrame(self): position = self.player.position() self.player.setPosition(position-int(self.fps)) def ManageDB(self): self.player.pause() shapeFileFirst,_ = QFileDialog.getSaveFileName(caption = 'Save shape file', filter = "Esri shp (*.shp)") if shapeFileFirst: if shapeFileFirst.split('.')[-1] == 'shp': shapeFile = shapeFileFirst else: shapeFile = shapeFileFirst + '.shp' try: os.remove(shapeFile) os.remove(shapeFileFirst.split('.')[0]+'.qpg') os.remove(shapeFileFirst.split('.')[0]+'.prj') os.remove(shapeFileFirst.split('.')[0]+'.cpg') os.remove(shapeFileFirst.split('.')[0]+'.shx') os.remove(shapeFileFirst.split('.')[0]+'.dbf') except OSError: pass crs = QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId) fields = QgsFields() QgsVectorFileWriter(shapeFile, "CP1250", fields, QgsWkbTypes.Point, crs, "ESRI Shapefile") EmptyLayer = QgsVectorLayer(shapeFile, shapeFile.split('.')[0].split('/')[-1], 'ogr') self.dialoga = TableManager(self.iface, EmptyLayer,self) self.dialoga.exec_() def AcceptNewDB(self,DB): self.DB = DB
class MusicPlayer(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.options = self.parent().options self.ffmpeg = self.options['paths']['ffmpeg_bin'] self.thumbnails = self.options['paths']['thumbnails'] self.thumb_width = self.options['thumbnail']['width'] self.thumb_height = self.options['thumbnail']['height'] self.jumping = False self.blocked = False self.durations = {} self.playback_value = 0 self.text = ["None", "Repeat", "Random"] self.playlist_list = [] self.values = [ QMediaPlaylist.Loop, QMediaPlaylist.CurrentItemInLoop, QMediaPlaylist.Random ] # Thumbnail widget self.image_label = QLabel() # Control widgets self.playButton = QToolButton(clicked=self.play) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.stopButton = QToolButton(clicked=self.stop) self.stopButton.setIcon(self.style().standardIcon(QStyle.SP_MediaStop)) self.stopButton.setEnabled(False) self.playbackButton = QToolButton(clicked=self.playback_mode) self.playbackButton.setText(self.text[0]) self.nextButton = QToolButton(clicked=self.next_song) self.nextButton.setIcon(self.style().standardIcon( QStyle.SP_MediaSkipForward)) self.previousButton = QToolButton(clicked=self.previous_song) self.previousButton.setIcon(self.style().standardIcon( QStyle.SP_MediaSkipBackward)) self.muteButton = QToolButton(clicked=self.mute_clicked) self.muteButton.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume)) self.volumeSlider = QSlider(Qt.Horizontal, sliderMoved=self.change_volume) self.volumeSlider.setRange(0, 100) self.volumeSlider.setPageStep(1) self.volumeSlider.setValue(50) # Player and playlist setup self.player = QMediaPlayer() self.player.setVolume(50) self.player.stateChanged.connect(self.waveform) self.playlist = QMediaPlaylist() self.playlist.setPlaybackMode(self.values[0]) self.playlist.setCurrentIndex(1) self.player.setPlaylist(self.playlist) self.playlistModel = PlaylistModel() self.playlistModel.setPlaylist(self.playlist) self.playlistView = QListView() self.playlistView.setModel(self.playlistModel) self.playlistView.setCurrentIndex( self.playlistModel.index(self.playlist.currentIndex(), 0)) self.playlistView.activated.connect(self.jump) self.playlistView.setContextMenuPolicy(Qt.CustomContextMenu) self.playlistView.customContextMenuRequested.connect( self.list_view_menu) self.playlist.currentIndexChanged.connect( lambda position: self.change_thumbnail(position)) song_search = QLineEdit() song_search.textChanged.connect(self.search) song_search.setClearButtonEnabled(True) # Playlist self.playlist_name = QComboBox() self.playlist_name.currentTextChanged.connect(self.switch_playlist) self.refresh_lists() self.up_button = QToolButton(clicked=self.move_up) self.up_button.setIcon(self.style().standardIcon(QStyle.SP_ArrowUp)) self.down_button = QToolButton(clicked=self.move_down) self.down_button.setIcon(self.style().standardIcon( QStyle.SP_ArrowDown)) # Sound wave widget self.wave_graphic = WaveGraphic(self) #self.wave_graphic.hide() # Testing slider again self.slider = QSlider(Qt.Horizontal) self.slider.setRange(0, self.player.duration() / 1000) self.slider.sliderMoved.connect(self.seek) self.player.durationChanged.connect(self.durationChanged) self.player.positionChanged.connect(self.positionChanged) # Shortcuts QShortcut(QKeySequence(Qt.CTRL + Qt.Key_F), self, song_search.setFocus) # Layouts setup playlist_layout = QHBoxLayout() playlist_layout.addWidget(self.playlist_name) playlist_layout.addWidget(self.up_button) playlist_layout.addWidget(self.down_button) control_layout = QHBoxLayout() control_layout.setContentsMargins(0, 0, 0, 0) control_layout.addWidget(self.stopButton) control_layout.addWidget(self.previousButton) control_layout.addWidget(self.playButton) control_layout.addWidget(self.nextButton) control_layout.addWidget(self.muteButton) control_layout.addWidget(self.volumeSlider) control_layout.addWidget(self.playbackButton) display_layout = QVBoxLayout() display_layout.addWidget(song_search) display_layout.addWidget(self.playlistView) display_layout.addLayout(playlist_layout) music_layout = QVBoxLayout() music_layout.addWidget(self.image_label) music_layout.addWidget(self.slider) music_layout.addLayout(control_layout) main_layout = QHBoxLayout() main_layout.addLayout(music_layout) main_layout.addLayout(display_layout) main_2_layout = QVBoxLayout() main_2_layout.addLayout(main_layout) main_2_layout.addWidget(self.wave_graphic) self.setLayout(main_2_layout) def waveform(self, status): if status == QMediaPlayer.PlayingState: self.wave_graphic.start() elif status == QMediaPlayer.PausedState: self.wave_graphic.pause() else: self.wave_graphic.stop() def list_view_menu(self, point): menu = QMenu("Menu", self) recommend_action = QAction('&Recommend Songs', self) menu.addAction(recommend_action) # TODO: [FEATURE] add rename song recommend_action.triggered.connect( lambda: self.parent().call_download_manager(self.get_links())) rename_action = QAction('&Rename', self) menu.addAction(rename_action) # TODO: [FEATURE] add rename song rename_action.triggered.connect(lambda: print("rename")) # Show the context menu. menu.exec_(self.playlistView.mapToGlobal(point)) def get_links(self): title = self.playlistView.selectedIndexes()[0].data() link = getYoutubeURLFromSearch(title) if len(link) > 1: return youtube_recommendations(link) def move_up(self): index = self.playlistView.currentIndex().row() if index - 1 >= 0: item, above = self.playlist.media(index), self.playlist.media( index - 1) self.playlist.removeMedia(index) self.playlist.removeMedia(index - 1) self.playlist.insertMedia(index - 1, item) self.playlist.insertMedia(index, above) self.blocked = True self.playlistView.setCurrentIndex( self.playlistModel.index(index - 1, 0)) self.blocked = False self.stop() def move_down(self): index = self.playlistView.currentIndex().row() if index + 1 <= self.playlistModel.rowCount(): item, below = self.playlist.media(index), self.playlist.media( index + 1) self.playlist.removeMedia(index + 1) self.playlist.removeMedia(index) self.playlist.insertMedia(index, below) self.playlist.insertMedia(index + 1, item) self.blocked = True self.playlistView.setCurrentIndex( self.playlistModel.index(index + 1, 0)) self.blocked = False self.stop() def search(self, part_of_song): for index in range(self.playlistModel.rowCount()): item = self.playlistModel.data(self.playlistModel.index( index, 0)).lower() self.playlistView.setRowHidden(index, part_of_song.lower() not in item) def change_thumbnail(self, position=0): self.playlistView.setCurrentIndex(self.playlistModel.index( position, 0)) song = self.playlistView.selectedIndexes()[0].data() if self.wave_graphic.is_song_cached(song): self.wave_graphic.load_waves(song) else: wc_ = WaveConverter(song, self.wave_graphic.set_wav) wc_.convert() if self.playlistView.currentIndex().data() is None or self.blocked: return max_ratio = 0 img = None for item in listdir(self.thumbnails): if item.endswith('.jpg'): ratio = similar( item, self.playlistView.currentIndex().data().replace( '.mp3', '.jpg')) if ratio > max_ratio: max_ratio = ratio img = item if img: p = QPixmap(self.thumbnails + img) self.image_label.setPixmap( p.scaled(self.thumb_width, self.thumb_height, Qt.KeepAspectRatio)) def switch_playlist(self, current_text): self.playlist.clear() if current_text == "No Playlist": self.refresh() else: if read_playlist(current_text): songs = read_playlist(current_text).split('\n') for song in songs: self.playlist.addMedia( QMediaContent(QUrl.fromLocalFile(song))) def refresh(self): # Change it so it will go to same song. if self.playlist_name.currentText() != "No Playlist": return paths = fetch_options()['paths']['music_path'].split(';') current_songs = [ self.playlistModel.data(self.playlistModel.index(row, 0)) for row in range(self.playlistModel.rowCount()) ] for path in paths: if not path: continue for item in listdir(path): if isfile(join(path, item)) and item.endswith(".mp3") and ( item not in current_songs): self.playlist.addMedia( QMediaContent(QUrl.fromLocalFile(join(path, item)))) def refresh_lists(self): path = fetch_options()['paths']['playlist'] self.playlist_name.clear() self.playlist_list = ["No Playlist"] self.playlist_name.addItem("No Playlist") for item in listdir(path): if isfile(join(path, item)) and item.endswith(".lst"): self.playlist_list.append(item.split('.')[0]) self.playlist_name.addItem(item.split('.')[0]) def playback_mode(self): # Normal -> Loop -> Random def up_value(value, max_value=3): if value + 1 == max_value: return 0 return value + 1 self.playback_value = up_value(self.playback_value) self.playlist.setPlaybackMode(self.values[self.playback_value]) self.playbackButton.setText(self.text[self.playback_value]) def jump(self, index): if index.isValid() and not self.blocked: self.playlist.setCurrentIndex(index.row()) self.jumping = True self.play() def play(self): if self.blocked: return if self.player.state() != QMediaPlayer.PlayingState or self.jumping: self.player.play() self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) self.jumping = False else: self.player.pause() self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) self.stopButton.setEnabled(True) def change_volume(self, value): self.player.setVolume(value) def stop(self): if self.player.state() != QMediaPlayer.StoppedState: self.player.stop() self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.stopButton.setEnabled(False) def next_song(self): self.playlist.next() self.playlistView.setCurrentIndex( self.playlistModel.index(self.playlist.currentIndex(), 0)) def previous_song(self): self.playlist.previous() self.playlistView.setCurrentIndex( self.playlistModel.index(self.playlist.currentIndex(), 0)) def mute_clicked(self): self.player.setMuted(not self.player.isMuted()) self.muteButton.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume if not self.player.isMuted() else QStyle. SP_MediaVolumeMuted)) def durationChanged(self, duration): duration /= 1000 self.slider.setMaximum(duration) def positionChanged(self, progress): progress /= 1000 if not self.slider.isSliderDown(): self.slider.setValue(progress) def seek(self, seconds): self.player.setPosition(seconds * 1000)
class EventAction(): def __init__(self): #self.parent = parent self.isLoop = 0 #0循环列表,1单曲循环 self.isRandom = 0 #0不随机,1随机 self.fileList = [] #曲目名称列表 self.randomList =[] #播放列表 self.soundID = 0 #当前歌曲ID self.playStat = False #当前播放状态 (0未播放,1播放) self.openPath = "F:/mp3/" #歌曲目录 self.isPreview = 0 #试用开关,0正常播放,1列表中的歌曲每首歌曲放10秒 self.currentVolume = 0.1#默认的起始音量 self.isInitPlay = 1 #是否是初始播放 #==>>打开目录 self.config=configparser.ConfigParser() self.config.read('config.ini') self.openDir() #打开目录<<== self.playObj = QMediaPlayer() self.currentImg = "" #当前图片 self.songText = {} #歌词 self.songTextKey=[] #歌词KEY #打开歌曲目录 def openDir(self): self.openPath = self.config.get('Save','musicPath') isMusicDir = os.path.isdir(self.openPath)#检查是否为目录 if isMusicDir: dirFile = os.listdir(self.openPath)#目录中的所有文件 #遍历有效音乐文件 i=0; for file in dirFile: fileName,fileType=os.path.splitext(file) if fileType==".mp3" or fileType==".wav": self.fileList.append(file) self.randomList.append(i) i+=1 if self.isRandom==1: self.shuffleMusic(1) #随机(打乱播放顺序) def shuffleMusic(self,isshuffle): if isshuffle: random.shuffle(self.randomList)#乱序 else: self.randomList.sort()#排序 #初始化播放 def initPlay(self): self.soundID = int(self.config.get('Save','soundID')) self.playStat = self.config.get('Save','playStat') self.pastTime = self.config.getint('Save','pastTime') self.currentVolume = self.config.getint('Save','volume') self.isRandom = self.config.getint('Save','isRandom') self.isLoop = self.config.getint('Save','isLoop') if self.soundID!="": self.play(self.soundID) if self.isRandom:#打乱列表 self.shuffleMusic(1) self.playObj.setVolume(self.currentVolume) #播放 def play(self,i): source = self.openPath + self.fileList[i] self.playObj.setMedia(QMediaContent(QUrl.fromLocalFile(source))) #解析文件中的ID3V2 self.currentImg = "" f = QFile(source) if f.open(QIODevice.ReadOnly): #读取标签 headData = f.read(10) data = headData[:0] if self.id3v2(headData):#检测是否有ID3 #标签的大小计算 tag = headData[6:10] tagSize = (tag[0]&0x7f)*0x200000+(tag[1]&0x7f)*0x4000+(tag[2]&0x7f)*0x80+(tag[3]&0x7f) data =f.read(tagSize) while len(data)>10: data = self.resolve(data) f.close() self.playObj.play() def testPlay(self): #ps =QMediaMetaData() #print("QMediaMetaData",ps) #print("metaData",self.playObj.metaData(QMediaMetaData.Title)) #print("position",self.playObj.position()) #print("playlist",self.playObj.playlist) #print("availability",self.playObj.availability()) #print("bufferStatus",self.playObj.bufferStatus()) #print("currentMedia",self.playObj.currentMedia()) #print("currentNetworkConfiguration",self.playObj.currentNetworkConfiguration()) #print("duration",self.playObj.duration()) #print("error",self.playObj.error()) #print("errorString",self.playObj.errorString()) #print("isAudioAvailable",self.playObj.isAudioAvailable()) #print("isMuted",self.playObj.isMuted()) #print("isSeekable",self.playObj.isSeekable()) #print("media",self.playObj.media()) #print("media:::::::A",self.playObj.media().canonicalResource().audioBitRate()) #print("media:::::::B",self.playObj.media().canonicalResource().audioCodec()) #print("media:::::::C",self.playObj.media().canonicalResource().channelCount()) #print("media:::::::D",self.playObj.media().canonicalResource().dataSize()) #print("media:::::::e",self.playObj.media().canonicalResource().isNull()) #print("media:::::::f",self.playObj.media().canonicalResource().language()) #print("media:::::::g",self.playObj.media().canonicalResource().mimeType()) #print("media:::::::h",self.playObj.media().canonicalResource().request()) #print("isVideoAvailable",self.playObj.isVideoAvailable()) #print("mediaStatus",self.playObj.mediaStatus()) #print("mediaStream",self.playObj.mediaStream()) #print("playbackRate",self.playObj.playbackRate()) #print("state",self.playObj.state()) #print("volume",self.playObj.volume()) # print("volume",self.playObj.filename) pass #换歌之前先停止,释放内存 def stopPlay(self): self.playObj.pause() #上一首 def prevPlay(self): self.stopPlay() if self.isRandom: key = self.searchID(self.soundID)-1 if key<0: key=0 self.soundID = self.randomList[key] else: self.soundID-=1 if self.soundID< 0: self.soundID = len(self.randomList)-1 self.play(self.soundID) #下一首 def nextPlay(self): self.stopPlay() if self.isRandom: key = self.searchID(self.soundID)+1 if key>(len(self.randomList)-1): key=len(self.randomList)-1 self.soundID = self.randomList[key] else: self.soundID+=1 if self.soundID > (len(self.randomList)-1): self.soundID = 0 #print("next:::",self.soundID) self.play(self.soundID) #快退 def rewindPlay(self): #print("<<") rewindTime = int(self.playObj.position()) - 10*1000 if rewindTime < 0: rewindTime = 0 self.playObj.setPosition(rewindTime) #快进 def forwardPlay(self): #print(">>") forwardTime = int(self.playObj.position()) + 10*1000 if forwardTime > int(self.playObj.duration()): forwardTime = int(self.playObj.duration()) self.playObj.setPosition(forwardTime) #播放/暂停 def playORpause(self): if self.playObj.state()==1: self.playObj.pause() else: self.playObj.play() #音量加 def raisevolPlay(self): self.playObj.setVolume(self.playObj.volume()+10) self.currentVolume = self.playObj.volume() #音量减 def lowervolPlay(self): self.playObj.setVolume(self.playObj.volume()-10) self.currentVolume = self.playObj.volume() #静音 def mutePlay(self): if self.playObj.isMuted(): self.playObj.setMuted(False) else: self.playObj.setMuted(True) #volume #跟据v找K def searchID(self,v): for index, item in enumerate(self.randomList): if item ==v: return index return 0 #解析文件中是否有id3v2 def id3v2(self,headData): if str(headData[:3],encoding=("utf-8")) != "ID3": return False return True #解析文件中的歌词与图片 def resolve(self,data): tagName = str(data[:4],encoding=("utf-8")) size = data[4:8] #sizeS = size[0]*0x1000000 + size[1]*0x10000 + size[2]*0x100 + size[3] sizeS=int.from_bytes(size, byteorder='big') flags = data[8:10] tagContent = data[10:sizeS+10] if tagName=="TEXT":#歌词 #print("歌词") condingType=int.from_bytes(tagContent[:1], byteorder='big') if condingType == 0:#0代表字符使用ISO-8859-1编码方式; try: content = str(tagContent[1:],encoding="gbk") except: content ="" elif condingType == 1:#1代表字符使用UTF-16编码方式; try: content = str(tagContent[1:],encoding="UTF-16") except: content ="" elif condingType == 2:#2代表字符使用 UTF-16BE编码方式; content ="" elif condingType == 3:#3代表字符使用UTF-8编码方式。 try: content = str(tagContent[1:],encoding="UTF-8") except: content ="" if content!="": temp={} self.songTextKey=[] contentSplit = content.splitlines() for k in range(len(contentSplit)): if contentSplit[k][1].isdigit(): xxx = contentSplit[k].split("]") tempKey = "%d" %(int(xxx[0][1:3])*60 +int(xxx[0][4:6]) ) temp[str(tempKey)] = xxx[1] self.songTextKey.append(tempKey) else: endKey = contentSplit[k].find("]",0) self.songTextKey.append(k) temp[str(k)] = contentSplit[k][1:endKey] self.songText = temp else: self.songText = {} elif tagName=="APIC":#图片 #print("图片") self.currentImg = tagContent[17:] return data[10+sizeS:]
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui = Ui_MainWindow() #创建UI对象 self.ui.setupUi(self) #构造UI界面 ## self.setWindowTitle("Demo10_1,音乐播放器") self.player = QMediaPlayer(self) self.playlist = QMediaPlaylist(self) self.player.setPlaylist(self.playlist) self.playlist.setPlaybackMode(QMediaPlaylist.Loop) #循环模式 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) self.playlist.currentIndexChanged.connect(self.do_currentChanged) ## ==============自定义功能函数============ ## ===============event 处理函数========== def closeEvent(self, event): ##窗体关闭时 ## 窗口关闭时不能自动停止播放,需手动停止 if (self.player.state() == QMediaPlayer.PlayingState): self.player.stop() ## ==========由connectSlotsByName() 自动连接的槽函数================== # 播放列表管理 @pyqtSlot() ##添加文件 def on_btnAdd_clicked(self): ## curPath=os.getcwd() #获取系统当前目录 ## curPath=QDir.homePath() curPath = QDir.currentPath() dlgTitle = "选择音频文件" filt = "音频文件(*.mp3 *.wav *.wma);;所有文件(*.*)" fileList, flt = QFileDialog.getOpenFileNames(self, dlgTitle, curPath, filt) count = len(fileList) if count < 1: return filename = fileList[0] fileInfo = QFileInfo(filename) #文件信息 QDir.setCurrent(fileInfo.absolutePath()) #重设当前路径 for i in range(count): filename = fileList[i] fileInfo.setFile(filename) song = QMediaContent(QUrl.fromLocalFile(filename)) self.playlist.addMedia(song) #添加播放媒体 ## basename=os.path.basename(filename) #文件名和后缀 basename = fileInfo.baseName() self.ui.listWidget.addItem(basename) #添加到界面文件列表 if (self.player.state() != QMediaPlayer.PlayingState): self.playlist.setCurrentIndex(0) self.player.play() @pyqtSlot() ##移除一个文件 def on_btnRemove_clicked(self): pos = self.ui.listWidget.currentRow() item = self.ui.listWidget.takeItem(pos) #python会自动删除 if (self.playlist.currentIndex() == pos): #是当前播放的曲目 nextPos = 0 if pos >= 1: nextPos = pos - 1 self.playlist.removeMedia(pos) #从播放列表里移除 if self.ui.listWidget.count() > 0: #剩余个数 self.playlist.setCurrentIndex(nextPos) self.do_currentChanged(nextPos) #当前曲目变化 else: self.player.stop() self.ui.LabCurMedia.setText("无曲目") else: self.playlist.removeMedia(pos) @pyqtSlot() ##清空播放列表 def on_btnClear_clicked(self): self.playlist.clear() #清空播放列表 self.ui.listWidget.clear() self.player.stop() #停止播放 ## @pyqtSlot() ##双击时切换播放文件 def on_listWidget_doubleClicked(self, index): rowNo = index.row() #行号 self.playlist.setCurrentIndex(rowNo) self.player.play() # 播放控制 @pyqtSlot() ##播放 def on_btnPlay_clicked(self): if (self.playlist.currentIndex() < 0): self.playlist.setCurrentIndex(0) self.player.play() @pyqtSlot() ##暂停 def on_btnPause_clicked(self): self.player.pause() @pyqtSlot() ##停止 def on_btnStop_clicked(self): self.player.stop() @pyqtSlot() ##上一曲目 def on_btnPrevious_clicked(self): self.playlist.previous() @pyqtSlot() ##下一曲目 def on_btnNext_clicked(self): self.playlist.next() @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): ##播放器状态变化 self.ui.btnPlay.setEnabled(state != QMediaPlayer.PlayingState) self.ui.btnPause.setEnabled(state == QMediaPlayer.PlayingState) self.ui.btnStop.setEnabled(state == QMediaPlayer.PlayingState) 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) 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_currentChanged(self, position): ##playlist当前曲目变化 self.ui.listWidget.setCurrentRow(position) item = self.ui.listWidget.currentItem() #QListWidgetItem if (item != None): self.ui.LabCurMedia.setText(item.text())
class VidCutter(QWidget): def __init__(self, parent): super(VidCutter, self).__init__(parent) self.parent = parent self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.videoWidget = VideoWidget() self.videoService = VideoService(self) QFontDatabase.addApplicationFont( os.path.join(self.getAppPath(), 'fonts', 'DroidSansMono.ttf')) QFontDatabase.addApplicationFont( os.path.join(self.getAppPath(), 'fonts', 'HelveticaNeue.ttf')) qApp.setFont(QFont('Helvetica Neue', 10)) self.clipTimes = [] self.inCut = False self.movieFilename = '' self.movieLoaded = False self.timeformat = 'hh:mm:ss' self.finalFilename = '' self.totalRuntime = 0 self.initIcons() self.initActions() self.toolbar = QToolBar( floatable=False, movable=False, iconSize=QSize(28, 28), toolButtonStyle=Qt.ToolButtonTextUnderIcon, styleSheet= 'QToolBar QToolButton { min-width:82px; margin-left:10px; margin-right:10px; font-size:14px; }' ) self.initToolbar() self.aboutMenu, self.cliplistMenu = QMenu(), QMenu() self.initMenus() self.seekSlider = VideoSlider(parent=self, sliderMoved=self.setPosition) self.seekSlider.installEventFilter(self) self.initNoVideo() self.cliplist = QListWidget( sizePolicy=QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding), contextMenuPolicy=Qt.CustomContextMenu, uniformItemSizes=True, iconSize=QSize(100, 700), dragDropMode=QAbstractItemView.InternalMove, alternatingRowColors=True, customContextMenuRequested=self.itemMenu, styleSheet='QListView::item { margin:10px 5px; }') self.cliplist.setFixedWidth(185) self.cliplist.model().rowsMoved.connect(self.syncClipList) listHeader = QLabel(pixmap=QPixmap( os.path.join(self.getAppPath(), 'images', 'clipindex.png'), 'PNG'), alignment=Qt.AlignCenter) listHeader.setStyleSheet( '''padding:5px; padding-top:8px; border:1px solid #b9b9b9; border-bottom:none; background-color:qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFF, stop: 0.5 #EAEAEA, stop: 0.6 #EAEAEA stop:1 #FFF);''' ) self.runtimeLabel = QLabel('<div align="right">00:00:00</div>', textFormat=Qt.RichText) self.runtimeLabel.setStyleSheet( '''font-family:Droid Sans Mono; font-size:10pt; color:#FFF; background:rgb(106, 69, 114) url(:images/runtime.png) no-repeat left center; padding:2px; padding-right:8px; border:1px solid #b9b9b9; border-top:none;''' ) self.clipindexLayout = QVBoxLayout(spacing=0) self.clipindexLayout.setContentsMargins(0, 0, 0, 0) self.clipindexLayout.addWidget(listHeader) self.clipindexLayout.addWidget(self.cliplist) self.clipindexLayout.addWidget(self.runtimeLabel) self.videoLayout = QHBoxLayout() self.videoLayout.setContentsMargins(0, 0, 0, 0) self.videoLayout.addWidget(self.novideoWidget) self.videoLayout.addLayout(self.clipindexLayout) self.timeCounter = QLabel('00:00:00 / 00:00:00', autoFillBackground=True, alignment=Qt.AlignCenter, sizePolicy=QSizePolicy( QSizePolicy.Expanding, QSizePolicy.Fixed)) self.timeCounter.setStyleSheet( 'color:#FFF; background:#000; font-family:Droid Sans Mono; font-size:10.5pt; padding:4px;' ) videoplayerLayout = QVBoxLayout(spacing=0) videoplayerLayout.setContentsMargins(0, 0, 0, 0) videoplayerLayout.addWidget(self.videoWidget) videoplayerLayout.addWidget(self.timeCounter) self.videoplayerWidget = QWidget(self, visible=False) self.videoplayerWidget.setLayout(videoplayerLayout) self.menuButton = QPushButton(icon=self.aboutIcon, flat=True, toolTip='About', statusTip='About', iconSize=QSize(24, 24), cursor=Qt.PointingHandCursor) self.menuButton.setMenu(self.aboutMenu) self.muteButton = QPushButton(icon=self.unmuteIcon, flat=True, toolTip='Mute', statusTip='Toggle audio mute', cursor=Qt.PointingHandCursor, clicked=self.muteAudio) self.volumeSlider = QSlider(Qt.Horizontal, toolTip='Volume', statusTip='Adjust volume level', cursor=Qt.PointingHandCursor, value=50, sizePolicy=QSizePolicy( QSizePolicy.Fixed, QSizePolicy.Minimum), minimum=0, maximum=100, sliderMoved=self.setVolume) self.volumeSlider.setStyleSheet( '''QSlider::groove:horizontal { height:40px; } QSlider::sub-page:horizontal { border:1px outset #6A4572; background:#6A4572; margin:2px; } QSlider::handle:horizontal { image: url(:images/knob.png) no-repeat top left; width:20px; }''' ) self.saveAction = QPushButton( self.parent, icon=self.saveIcon, text='Save Video', flat=True, toolTip='Save Video', clicked=self.cutVideo, cursor=Qt.PointingHandCursor, iconSize=QSize(30, 30), statusTip='Save video clips merged as a new video file', enabled=False) self.saveAction.setStyleSheet( '''QPushButton { color:#FFF; padding:8px; font-size:12pt; border:1px inset #481953; border-radius:4px; background-color:rgb(106, 69, 114); } QPushButton:!enabled { background-color:rgba(0, 0, 0, 0.1); color:rgba(0, 0, 0, 0.3); border:1px inset #CDCDCD; } QPushButton:hover { background-color:rgba(255, 255, 255, 0.8); color:#444; } QPushButton:pressed { background-color:rgba(218, 218, 219, 0.8); color:#444; }''' ) controlsLayout = QHBoxLayout() controlsLayout.addStretch(1) controlsLayout.addWidget(self.toolbar) controlsLayout.addSpacerItem(QSpacerItem(20, 1)) controlsLayout.addWidget(self.saveAction) controlsLayout.addStretch(1) controlsLayout.addWidget(self.muteButton) controlsLayout.addWidget(self.volumeSlider) controlsLayout.addSpacing(1) controlsLayout.addWidget(self.menuButton) layout = QVBoxLayout() layout.setContentsMargins(10, 10, 10, 4) layout.addLayout(self.videoLayout) layout.addWidget(self.seekSlider) layout.addLayout(controlsLayout) self.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) def initNoVideo(self) -> None: novideoImage = QLabel(alignment=Qt.AlignCenter, autoFillBackground=False, pixmap=QPixmap( os.path.join(self.getAppPath(), 'images', 'novideo.png'), 'PNG'), sizePolicy=QSizePolicy( QSizePolicy.Expanding, QSizePolicy.MinimumExpanding)) novideoImage.setBackgroundRole(QPalette.Dark) novideoImage.setContentsMargins(0, 20, 0, 20) self.novideoLabel = QLabel(alignment=Qt.AlignCenter, autoFillBackground=True, sizePolicy=QSizePolicy( QSizePolicy.Expanding, QSizePolicy.Minimum)) self.novideoLabel.setBackgroundRole(QPalette.Dark) self.novideoLabel.setContentsMargins(0, 20, 15, 60) novideoLayout = QVBoxLayout(spacing=0) novideoLayout.addWidget(novideoImage) novideoLayout.addWidget(self.novideoLabel, alignment=Qt.AlignTop) self.novideoMovie = QMovie( os.path.join(self.getAppPath(), 'images', 'novideotext.gif')) self.novideoMovie.frameChanged.connect(self.setNoVideoText) self.novideoMovie.start() self.novideoWidget = QWidget(self, autoFillBackground=True) self.novideoWidget.setBackgroundRole(QPalette.Dark) self.novideoWidget.setLayout(novideoLayout) def initIcons(self) -> None: self.appIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'vidcutter.png')) self.openIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'addmedia.png')) self.playIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'play.png')) self.pauseIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'pause.png')) self.cutStartIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'cut-start.png')) self.cutEndIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'cut-end.png')) self.saveIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'save.png')) self.muteIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'muted.png')) self.unmuteIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'unmuted.png')) self.upIcon = QIcon(os.path.join(self.getAppPath(), 'images', 'up.png')) self.downIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'down.png')) self.removeIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'remove.png')) self.removeAllIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'remove-all.png')) self.successIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'success.png')) self.aboutIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'about.png')) self.completePlayIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'complete-play.png')) self.completeOpenIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'complete-open.png')) self.completeRestartIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'complete-restart.png')) self.completeExitIcon = QIcon( os.path.join(self.getAppPath(), 'images', 'complete-exit.png')) def initActions(self) -> None: self.openAction = QAction(self.openIcon, 'Add Media', self, statusTip='Select media source', triggered=self.openFile) self.playAction = QAction(self.playIcon, 'Play Video', self, statusTip='Play selected media', triggered=self.playVideo, enabled=False) self.cutStartAction = QAction(self.cutStartIcon, 'Set Start', self, toolTip='Set Start', statusTip='Set start marker', triggered=self.cutStart, enabled=False) self.cutEndAction = QAction(self.cutEndIcon, 'Set End', self, statusTip='Set end marker', triggered=self.cutEnd, enabled=False) self.moveItemUpAction = QAction( self.upIcon, 'Move Up', self, statusTip='Move clip position up in list', triggered=self.moveItemUp, enabled=False) self.moveItemDownAction = QAction( self.downIcon, 'Move Down', self, statusTip='Move clip position down in list', triggered=self.moveItemDown, enabled=False) self.removeItemAction = QAction( self.removeIcon, 'Remove clip', self, statusTip='Remove selected clip from list', triggered=self.removeItem, enabled=False) self.removeAllAction = QAction(self.removeAllIcon, 'Clear list', self, statusTip='Clear all clips from list', triggered=self.clearList, enabled=False) self.aboutAction = QAction('About %s' % qApp.applicationName(), self, statusTip='Credits and acknowledgements', triggered=self.aboutInfo) self.aboutQtAction = QAction('About Qt', self, statusTip='About Qt', triggered=qApp.aboutQt) self.mediaInfoAction = QAction( 'Media Information', self, statusTip='Media information from loaded video file', triggered=self.mediaInfo, enabled=False) def initToolbar(self) -> None: self.toolbar.addAction(self.openAction) self.toolbar.addAction(self.playAction) self.toolbar.addSeparator() self.toolbar.addAction(self.cutStartAction) self.toolbar.addAction(self.cutEndAction) self.toolbar.addSeparator() def initMenus(self) -> None: self.aboutMenu.addAction(self.mediaInfoAction) self.aboutMenu.addSeparator() self.aboutMenu.addAction(self.aboutQtAction) self.aboutMenu.addAction(self.aboutAction) self.cliplistMenu.addAction(self.moveItemUpAction) self.cliplistMenu.addAction(self.moveItemDownAction) self.cliplistMenu.addSeparator() self.cliplistMenu.addAction(self.removeItemAction) self.cliplistMenu.addAction(self.removeAllAction) def setRunningTime(self, runtime: str) -> None: self.runtimeLabel.setText('<div align="right">%s</div>' % runtime) @pyqtSlot(int) def setNoVideoText(self, frame: int) -> None: self.novideoLabel.setPixmap(self.novideoMovie.currentPixmap()) def itemMenu(self, pos: QPoint) -> None: globalPos = self.cliplist.mapToGlobal(pos) self.moveItemUpAction.setEnabled(False) self.moveItemDownAction.setEnabled(False) self.removeItemAction.setEnabled(False) self.removeAllAction.setEnabled(False) index = self.cliplist.currentRow() if index != -1: if not self.inCut: if index > 0: self.moveItemUpAction.setEnabled(True) if index < self.cliplist.count() - 1: self.moveItemDownAction.setEnabled(True) if self.cliplist.count() > 0: self.removeItemAction.setEnabled(True) if self.cliplist.count() > 0: self.removeAllAction.setEnabled(True) self.cliplistMenu.exec_(globalPos) def moveItemUp(self) -> None: index = self.cliplist.currentRow() tmpItem = self.clipTimes[index] del self.clipTimes[index] self.clipTimes.insert(index - 1, tmpItem) self.renderTimes() def moveItemDown(self) -> None: index = self.cliplist.currentRow() tmpItem = self.clipTimes[index] del self.clipTimes[index] self.clipTimes.insert(index + 1, tmpItem) self.renderTimes() def removeItem(self) -> None: index = self.cliplist.currentRow() del self.clipTimes[index] if self.inCut and index == self.cliplist.count() - 1: self.inCut = False self.initMediaControls() self.renderTimes() def clearList(self) -> None: self.clipTimes.clear() self.cliplist.clear() self.inCut = False self.renderTimes() self.initMediaControls() def mediaInfo(self) -> None: if self.mediaPlayer.isMetaDataAvailable(): content = '<table cellpadding="4">' for key in self.mediaPlayer.availableMetaData(): val = self.mediaPlayer.metaData(key) if type(val) is QSize: val = '%s x %s' % (val.width(), val.height()) content += '<tr><td align="right"><b>%s:</b></td><td>%s</td></tr>\n' % ( key, val) content += '</table>' mbox = QMessageBox(windowTitle='Media Information', windowIcon=self.parent.windowIcon(), textFormat=Qt.RichText) mbox.setText('<b>%s</b>' % os.path.basename( self.mediaPlayer.currentMedia().canonicalUrl().toLocalFile())) mbox.setInformativeText(content) mbox.exec_() else: QMessageBox.critical( self.parent, 'Could not retrieve media information', '''There was a problem in tring to retrieve media information. This DOES NOT mean there is a problem with the file and you should be able to continue using it.''') def aboutInfo(self) -> None: about_html = '''<style> a { color:#441d4e; text-decoration:none; font-weight:bold; } a:hover { text-decoration:underline; } </style> <p style="font-size:26pt; font-weight:bold;">%s</p> <p> <span style="font-size:13pt;"><b>Version: %s</b></span> <span style="font-size:10pt;position:relative;left:5px;">( %s )</span> </p> <p style="font-size:13px;"> Copyright © 2016 <a href="mailto:[email protected]">Pete Alexandrou</a> <br/> Website: <a href="%s">%s</a> </p> <p style="font-size:13px;"> Thanks to the folks behind the <b>Qt</b>, <b>PyQt</b> and <b>FFmpeg</b> projects for all their hard and much appreciated work. </p> <p style="font-size:11px;"> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. </p> <p style="font-size:11px;"> This software uses libraries from the <a href="https://www.ffmpeg.org">FFmpeg</a> project under the <a href="https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html">LGPLv2.1</a> </p>''' % (qApp.applicationName(), qApp.applicationVersion(), platform.architecture()[0], qApp.organizationDomain(), qApp.organizationDomain()) QMessageBox.about(self.parent, 'About %s' % qApp.applicationName(), about_html) def openFile(self) -> None: filename, _ = QFileDialog.getOpenFileName(self.parent, caption='Select video', directory=QDir.homePath()) if filename != '': self.loadFile(filename) def loadFile(self, filename: str) -> None: self.movieFilename = filename if not os.path.exists(filename): return self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(filename))) self.initMediaControls(True) self.cliplist.clear() self.clipTimes = [] self.parent.setWindowTitle( '%s - %s' % (qApp.applicationName(), os.path.basename(filename))) if not self.movieLoaded: self.videoLayout.replaceWidget(self.novideoWidget, self.videoplayerWidget) self.novideoMovie.stop() self.novideoMovie.deleteLater() self.novideoWidget.deleteLater() self.videoplayerWidget.show() self.videoWidget.show() self.movieLoaded = True if self.mediaPlayer.isVideoAvailable(): self.mediaPlayer.setPosition(1) self.mediaPlayer.play() self.mediaPlayer.pause() def playVideo(self) -> None: if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() self.playAction.setText('Play Video') else: self.mediaPlayer.play() self.playAction.setText('Pause Video') def initMediaControls(self, flag: bool = True) -> None: self.playAction.setEnabled(flag) self.saveAction.setEnabled(False) self.cutStartAction.setEnabled(flag) self.cutEndAction.setEnabled(False) self.mediaInfoAction.setEnabled(flag) if flag: self.seekSlider.setRestrictValue(0) def setPosition(self, position: int) -> None: self.mediaPlayer.setPosition(position) def positionChanged(self, progress: int) -> None: self.seekSlider.setValue(progress) currentTime = self.deltaToQTime(progress) totalTime = self.deltaToQTime(self.mediaPlayer.duration()) self.timeCounter.setText('%s / %s' % (currentTime.toString( self.timeformat), totalTime.toString(self.timeformat))) @pyqtSlot() def mediaStateChanged(self) -> None: if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playAction.setIcon(self.pauseIcon) else: self.playAction.setIcon(self.playIcon) def durationChanged(self, duration: int) -> None: self.seekSlider.setRange(0, duration) def muteAudio(self, muted: bool) -> None: if self.mediaPlayer.isMuted(): self.mediaPlayer.setMuted(not self.mediaPlayer.isMuted()) self.muteButton.setIcon(self.unmuteIcon) self.muteButton.setToolTip('Mute') else: self.mediaPlayer.setMuted(not self.mediaPlayer.isMuted()) self.muteButton.setIcon(self.muteIcon) self.muteButton.setToolTip('Unmute') def setVolume(self, volume: int) -> None: self.mediaPlayer.setVolume(volume) def toggleFullscreen(self) -> None: self.videoWidget.setFullScreen(not self.videoWidget.isFullScreen()) def cutStart(self) -> None: self.clipTimes.append([ self.deltaToQTime(self.mediaPlayer.position()), '', self.captureImage() ]) self.cutStartAction.setDisabled(True) self.cutEndAction.setEnabled(True) self.seekSlider.setRestrictValue(self.seekSlider.value() + 1000) self.mediaPlayer.setPosition(self.seekSlider.restrictValue) self.inCut = True self.renderTimes() def cutEnd(self) -> None: item = self.clipTimes[len(self.clipTimes) - 1] selected = self.deltaToQTime(self.mediaPlayer.position()) if selected.__lt__(item[0]): QMessageBox.critical( self.parent, 'Invalid END Time', 'The clip end time must come AFTER it\'s start time. Please try again.' ) return item[1] = selected self.cutStartAction.setEnabled(True) self.cutEndAction.setDisabled(True) self.seekSlider.setRestrictValue(0) self.inCut = False self.renderTimes() @pyqtSlot(QModelIndex, int, int, QModelIndex, int) def syncClipList(self, parent: QModelIndex, start: int, end: int, destination: QModelIndex, row: int) -> None: if start < row: index = row - 1 else: index = row clip = self.clipTimes.pop(start) self.clipTimes.insert(index, clip) def renderTimes(self) -> None: self.cliplist.clear() self.seekSlider.setCutMode(self.inCut) if len(self.clipTimes) > 4: self.cliplist.setFixedWidth(200) else: self.cliplist.setFixedWidth(185) self.totalRuntime = 0 for item in self.clipTimes: endItem = '' if type(item[1]) is QTime: endItem = item[1].toString(self.timeformat) self.totalRuntime += item[0].msecsTo(item[1]) listitem = QListWidgetItem() listitem.setTextAlignment(Qt.AlignVCenter) if type(item[2]) is QPixmap: listitem.setIcon(QIcon(item[2])) self.cliplist.addItem(listitem) marker = QLabel( '''<style>b { font-size:8pt; } p { margin:5px; }</style> <p><b>START</b><br/>%s</p><p><b>END</b><br/>%s</p>''' % (item[0].toString(self.timeformat), endItem)) self.cliplist.setItemWidget(listitem, marker) listitem.setFlags(Qt.ItemIsSelectable | Qt.ItemIsDragEnabled | Qt.ItemIsEnabled) if len(self.clipTimes) and not self.inCut: self.saveAction.setEnabled(True) if self.inCut or len(self.clipTimes) == 0 or not type( self.clipTimes[0][1]) is QTime: self.saveAction.setEnabled(False) self.setRunningTime( self.deltaToQTime(self.totalRuntime).toString(self.timeformat)) @staticmethod def deltaToQTime(millisecs: int) -> QTime: secs = millisecs / 1000 return QTime((secs / 3600) % 60, (secs / 60) % 60, secs % 60, (secs * 1000) % 1000) def captureImage(self) -> None: frametime = self.deltaToQTime( self.mediaPlayer.position()).addSecs(1).toString(self.timeformat) inputfile = self.mediaPlayer.currentMedia().canonicalUrl().toLocalFile( ) imagecap = self.videoService.capture(inputfile, frametime) if type(imagecap) is QPixmap: return imagecap def cutVideo(self) -> bool: self.setCursor(Qt.BusyCursor) clips = len(self.clipTimes) filename, filelist = '', [] source = self.mediaPlayer.currentMedia().canonicalUrl().toLocalFile() _, sourceext = os.path.splitext(source) if clips > 0: self.finalFilename, _ = QFileDialog.getSaveFileName( self.parent, 'Save video', source, 'Video files (*%s)' % sourceext) if self.finalFilename != '': self.saveAction.setDisabled(True) self.showProgress(clips) file, ext = os.path.splitext(self.finalFilename) index = 1 self.progress.setLabelText('Cutting video clips...') qApp.processEvents() for clip in self.clipTimes: duration = self.deltaToQTime(clip[0].msecsTo( clip[1])).toString(self.timeformat) filename = '%s_%s%s' % (file, '{0:0>2}'.format(index), ext) filelist.append(filename) self.videoService.cut(source, filename, clip[0].toString(self.timeformat), duration) index += 1 if len(filelist) > 1: self.joinVideos(filelist, self.finalFilename) else: QFile.remove(self.finalFilename) QFile.rename(filename, self.finalFilename) self.unsetCursor() self.progress.setLabelText('Complete...') qApp.processEvents() self.saveAction.setEnabled(True) self.progress.close() self.progress.deleteLater() self.complete() self.saveAction.setEnabled(True) self.unsetCursor() self.saveAction.setDisabled(True) return True self.unsetCursor() self.saveAction.setDisabled(True) return False def joinVideos(self, joinlist: list, filename: str) -> None: listfile = os.path.normpath( os.path.join(os.path.dirname(joinlist[0]), '.vidcutter.list')) fobj = open(listfile, 'w') for file in joinlist: fobj.write('file \'%s\'\n' % file.replace("'", "\\'")) fobj.close() self.videoService.join(listfile, filename) try: QFile.remove(listfile) for file in joinlist: if os.path.isfile(file): QFile.remove(file) except: pass def showProgress(self, steps: int, label: str = 'Processing video...') -> None: self.progress = QProgressDialog(label, None, 0, steps, self.parent, windowModality=Qt.ApplicationModal, windowIcon=self.parent.windowIcon(), minimumDuration=0, minimumWidth=500) self.progress.show() for i in range(steps): self.progress.setValue(i) qApp.processEvents() time.sleep(1) def complete(self) -> None: info = QFileInfo(self.finalFilename) mbox = QMessageBox(windowTitle='Success', windowIcon=self.parent.windowIcon(), minimumWidth=500, iconPixmap=self.successIcon.pixmap(48, 49), textFormat=Qt.RichText) mbox.setText( ''' <style> table.info { margin:8px; padding:4px 15px; } td.label { font-weight:bold; font-size:9pt; text-align:right; background-color:#444; color:#FFF; } td.value { background-color:#FFF !important; font-size:10pt; } </style> <p>Your video was successfully created.</p> <p align="center"> <table class="info" cellpadding="6" cellspacing="0"> <tr> <td class="label"><b>Filename</b></td> <td class="value" nowrap>%s</td> </tr> <tr> <td class="label"><b>Size</b></td> <td class="value">%s</td> </tr> <tr> <td class="label"><b>Runtime</b></td> <td class="value">%s</td> </tr> </table> </p> <p>How would you like to proceed?</p>''' % (QDir.toNativeSeparators( self.finalFilename), self.sizeof_fmt(int(info.size())), self.deltaToQTime(self.totalRuntime).toString(self.timeformat))) play = mbox.addButton('Play', QMessageBox.AcceptRole) play.setIcon(self.completePlayIcon) play.clicked.connect(self.openResult) fileman = mbox.addButton('Open', QMessageBox.AcceptRole) fileman.setIcon(self.completeOpenIcon) fileman.clicked.connect(self.openFolder) end = mbox.addButton('Exit', QMessageBox.AcceptRole) end.setIcon(self.completeExitIcon) end.clicked.connect(self.close) new = mbox.addButton('Restart', QMessageBox.AcceptRole) new.setIcon(self.completeRestartIcon) new.clicked.connect(self.startNew) mbox.setDefaultButton(new) mbox.setEscapeButton(new) mbox.exec_() def sizeof_fmt(self, num: float, suffix: chr = 'B') -> str: for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']: if abs(num) < 1024.0: return "%3.1f%s%s" % (num, unit, suffix) num /= 1024.0 return "%.1f%s%s" % (num, 'Y', suffix) @pyqtSlot() def openFolder(self) -> None: self.openResult(pathonly=True) @pyqtSlot(bool) def openResult(self, pathonly: bool = False) -> None: self.startNew() if len(self.finalFilename) and os.path.exists(self.finalFilename): target = self.finalFilename if not pathonly else os.path.dirname( self.finalFilename) QDesktopServices.openUrl(QUrl.fromLocalFile(target)) @pyqtSlot() def startNew(self) -> None: self.unsetCursor() self.clearList() self.seekSlider.setValue(0) self.seekSlider.setRange(0, 0) self.mediaPlayer.setMedia(QMediaContent()) self.initNoVideo() self.videoLayout.replaceWidget(self.videoplayerWidget, self.novideoWidget) self.initMediaControls(False) self.parent.setWindowTitle('%s' % qApp.applicationName()) def wheelEvent(self, event: QWheelEvent) -> None: if self.mediaPlayer.isVideoAvailable( ) or self.mediaPlayer.isAudioAvailable(): if event.angleDelta().y() > 0: newval = self.seekSlider.value() - 1000 else: newval = self.seekSlider.value() + 1000 self.seekSlider.setValue(newval) self.seekSlider.setSliderPosition(newval) self.mediaPlayer.setPosition(newval) event.accept() def keyPressEvent(self, event: QKeyEvent) -> None: if self.mediaPlayer.isVideoAvailable( ) or self.mediaPlayer.isAudioAvailable(): addtime = 0 if event.key() == Qt.Key_Left: addtime = -1000 elif event.key() == Qt.Key_PageUp or event.key() == Qt.Key_Up: addtime = -10000 elif event.key() == Qt.Key_Right: addtime = 1000 elif event.key() == Qt.Key_PageDown or event.key() == Qt.Key_Down: addtime = 10000 elif event.key() == Qt.Key_Enter: self.toggleFullscreen() elif event.key( ) == Qt.Key_Escape and self.videoWidget.isFullScreen(): self.videoWidget.setFullScreen(False) if addtime != 0: newval = self.seekSlider.value() + addtime self.seekSlider.setValue(newval) self.seekSlider.setSliderPosition(newval) self.mediaPlayer.setPosition(newval) event.accept() def mousePressEvent(self, event: QMouseEvent) -> None: if event.button() == Qt.BackButton and self.cutStartAction.isEnabled(): self.cutStart() event.accept() elif event.button( ) == Qt.ForwardButton and self.cutEndAction.isEnabled(): self.cutEnd() event.accept() else: super(VidCutter, self).mousePressEvent(event) def eventFilter(self, obj: QObject, event: QEvent) -> bool: if event.type() == QEvent.MouseButtonRelease and isinstance( obj, VideoSlider): if obj.objectName() == 'VideoSlider' and ( self.mediaPlayer.isVideoAvailable() or self.mediaPlayer.isAudioAvailable()): obj.setValue( QStyle.sliderValueFromPosition(obj.minimum(), obj.maximum(), event.x(), obj.width())) self.mediaPlayer.setPosition(obj.sliderPosition()) return QWidget.eventFilter(self, obj, event) @pyqtSlot(QMediaPlayer.Error) def handleError(self, error: QMediaPlayer.Error) -> None: self.unsetCursor() self.startNew() if error == QMediaPlayer.ResourceError: QMessageBox.critical( self.parent, 'Error', 'Invalid media file detected at:<br/><br/><b>%s</b><br/><br/>%s' % (self.movieFilename, self.mediaPlayer.errorString())) else: QMessageBox.critical(self.parent, 'Error', self.mediaPlayer.errorString()) def getAppPath(self) -> str: return ':' def closeEvent(self, event: QCloseEvent) -> None: self.parent.closeEvent(event)
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 Player(QWidget): """Sub-class of QWidget""" def __init__(self, parent=None, *args, **kwargs): """Initialize class attributes""" super(Player, self).__init__(parent, *args, **kwargs) self.init_ui() def init_ui(self): """Create local components""" # loop self.loop = False # time label text self.time_text = '{:0>2d}:{:0>2d}:{:0>2d}/{:0>2d}:{:0>2d}:{:0>2d}' self.hours = self.minutes = self.seconds = 0 # create media player object self.mediaPlayer = QMediaPlayer(self, QMediaPlayer.VideoSurface) # create videowidget object self.videoWidget = QVideoWidget() # create open button self.btn_size = QSize(16, 16) openButton = Button("Open") openButton.setToolTip("Open Media File") openButton.setStatusTip("Open Media File") openButton.setFixedHeight(24) openButton.setIconSize(self.btn_size) openButton.setIcon( QIcon.fromTheme("document-open", QIcon("Icons/Open.bmp"))) # openButton.setStyleSheet("background-color: #B0C4DE") openButton.clicked.connect(self.abrir) # create play button self.playButton = Button() self.playButton.setEnabled(False) self.playButton.setFixedHeight(24) self.playButton.setIconSize(self.btn_size) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) # self.playButton.setStyleSheet("background-color: #B0C4DE") self.playButton.clicked.connect(self.play) # create slider self.positionSlider = PositionSlider(self.mediaPlayer, Qt.Horizontal) self.positionSlider.setRange(0, 0) self.positionSlider.setObjectName("positionSlider") # create status bar self.statusBar = QStatusBar() self.statusBar.setFont(QFont("Noto sans", 8)) self.statusBar.setFixedHeight(14) self.statusBar.setStyleSheet('color:#ffffff') # create duration time label self.durationLabel = QLabel() self.durationLabel.setStyleSheet( 'background-color:rgba(255, 255, 255, 0)') self.durationLabel.setText('00:00:00/00:00:00') # create hbox layout controlLayoutWidget = QWidget(self) controlLayout = QHBoxLayout(controlLayoutWidget) controlLayoutWidget.setLayout(controlLayout) controlLayout.setContentsMargins(2, 2, 2, 2) # set widgets to the hbox layout controlLayout.addWidget(openButton) controlLayout.addWidget(self.playButton) controlLayout.addWidget(self.positionSlider) controlLayout.addWidget(self.durationLabel) # change hbox color controlLayoutWidget.setStyleSheet( 'background-color:rgba(255, 255, 255, 50)') controlLayoutWidget.setWindowOpacity(0.1) # create vbox layout self.layout = QVBoxLayout() self.layout.setSpacing(0) # set widgets to vbox layout self.layout.addWidget(self.videoWidget) self.layout.addWidget(controlLayoutWidget) self.sub_controls() self.layout.addWidget(self.statusBar) self.setLayout(self.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) self.statusBar.showMessage('{:->33s}{:-<33s}'.format("Have Fun", "")) self.key_bindings() def key_bindings(self): # bind Keys to methods self.onplaypause = self.create_shortcut(Qt.Key_Space, self.videoWidget, self.play) # Space key for self.on_fscreen = self.create_shortcut( Qt.Key_F, self.videoWidget, self.toggle_fullscreen) # F key for fullscreen on self.onforward = self.create_shortcut( Qt.Key_Right, self.videoWidget, self.forward) # Right key for forward self.redvolume = self.create_shortcut( Qt.Key_Down, self.videoWidget, self.red_volume) # Down key reduce volume self.incvolume = self.create_shortcut( Qt.Key_Up, self.videoWidget, self.inc_volume) # Up key increase volume self.onsetloop = self.create_shortcut( "L", self.videoWidget, # L key for repeat on, (lambda self=self: self.repeat.toggle() or self.play_again())) self.onrewind = self.create_shortcut( Qt.Key_Left, self.videoWidget, self.rewind) # Left key for rewind self.volmute = self.create_shortcut(Qt.Key_M, self.videoWidget, self.mute) # M for mute and unmute self.onopen = self.create_shortcut('Ctrl+O', self.videoWidget, self.abrir) # Ctrl+O for open self.onstop = self.create_shortcut(Qt.Key_S, self.videoWidget, self.stop_media) # S key for stop def create_shortcut(self, sequence, widget, obj): """generate key shortcuts""" return QShortcut(QKeySequence(sequence), widget, obj, context=Qt.ApplicationShortcut) def sub_controls(self): """Repeat, volume, and mute controls""" # repeat button self.repeat = Button() self.repeat.setCheckable(True) self.repeat.toggle() self.repeat.setIconSize(self.btn_size) self.repeat.setFixedHeight(24) self.repeat.setFixedWidth(26) self.repeat.setToolTip("repeat") self.repeat.setStatusTip("repeat") # Icons to correspond with button state icon = QIcon() icon.addPixmap(QPixmap(os.path.join(FOLDER, "Icons/repeat(1).png")), QIcon.Normal, QIcon.On) icon.addPixmap(QPixmap(os.path.join(FOLDER, "Icons/repeat(2).png")), QIcon.Active) self.repeat.setIcon(icon) # self.repeat.setStyleSheet("background-color: #B0C4DE; margin: 0px 0px 0px 2px;") self.repeat.clicked.connect(self.play_again) # stop button self.stop = Button() self.stop.setIconSize(self.btn_size) self.stop.setFixedHeight(24) self.stop.setFixedWidth(26) self.stop.setToolTip("Stop playing media") self.stop.setStatusTip("Stop playing media") self.stop.setIcon(self.style().standardIcon(QStyle.SP_MediaStop)) # self.stop.setStyleSheet("background-color: #B0C4DE; margin: 0px 0px 0px 2px;") self.stop.clicked.connect(self.stop_media) # volume slider self.volumeSlider = VolumeSlider(self.mediaPlayer, Qt.Horizontal) self.volumeSlider.setRange(0, 100) self.volumeSlider.setFixedWidth(200) self.mediaPlayer.setVolume(50) self.volumeSlider.sliderMoved.connect(self.set_volume) # volume button self.volume = Button(self) self.volume.setIconSize(self.btn_size) self.volume.setFixedHeight(24) self.volume.setFixedWidth(26) self.volume.setToolTip("Mute or Unmute") self.volume.setStatusTip("Mute or Unmute") self.volume.setIcon(self.style().standardIcon(QStyle.SP_MediaVolume)) # self.volume.setStyleSheet("background-color: #B0C4DE; margin: 0px 0px 0px 2px;") self.volume.clicked.connect(self.mute) # create control widget subControlWidget = QWidget(self) subControlWidget.setStyleSheet( 'background-color:rgba(255, 255, 255, 30)') # create Horizontal Layout subControlLayout = QHBoxLayout(subControlWidget) subControlLayout.setContentsMargins(0, 0, 0, 0) subControlLayout.addWidget(self.repeat, 0, Qt.AlignLeft) subControlLayout.addWidget(self.stop, 1, Qt.AlignLeft) # sub layout for volume control self.sub_layout = QHBoxLayout() self.sub_layout.addWidget(self.volume) self.sub_layout.addWidget(self.volumeSlider) subControlLayout.addLayout(self.sub_layout) subControlLayout.setContentsMargins(2, 2, 2, 2) self.layout.addWidget(subControlWidget) def abrir(self, event=None, url=None): """" Equivalent to open for most GUIs""" fileName = None if self.videoWidget.isFullScreen(): self.toggle_fullscreen() if not url: fileName, _ = QFileDialog.getOpenFileName(self, "Select media") if fileName: self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(fileName))) else: self.mediaPlayer.setMedia(QMediaContent(QUrl(url))) if url or fileName: self.volumeSlider.setValue(self.mediaPlayer.volume()) self.playButton.setEnabled(True) self.statusBar.showMessage((fileName or url)) if not self.loop: self.play() def play(self): """Start media player""" if self.playButton.isEnabled(): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): """Callback for media player state change""" 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 state == QMediaPlayer.StoppedState and self.loop: self.play() def positionChanged(self, position): """Callback for media player position change""" if self.mediaPlayer.state() == QMediaPlayer.StoppedState: position = 0 self.positionSlider.setValue(position) hours, position = position // 3600000, position % 3600000 minutes, position = position // 60000, position % 60000 seconds = position // 1000 self.durationLabel.setText( self.time_text.format(hours, minutes, seconds, self.hours, self.minutes, self.seconds)) def durationChanged(self, duration): """Callback for media player duration of media change""" self.positionSlider.setRange(0, duration) self.hours, duration = duration // 3600000, duration % 3600000 self.minutes, duration = duration // 60000, duration % 60000 self.seconds = duration // 1000 self.durationLabel.setText( self.time_text.format(0, 0, 0, self.hours, self.minutes, self.seconds)) def setPosition(self, position): """set media player play position""" self.mediaPlayer.setPosition(position) def handleError(self): """Callback for multiplayer errors""" self.playButton.setEnabled(False) self.statusBar.showMessage("Error: " + self.mediaPlayer.errorString()) def play_again(self): """Set repeat on or off""" self.loop = not self.loop def stop_media(self): """Callback for stop button""" if self.loop: self.loop = False self.repeat.toggle() self.mediaPlayer.stop() def toggle_fullscreen(self): """Toggle in or out of fullscreen mode""" self.videoWidget.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) if self.videoWidget.isFullScreen(): self.videoWidget.setFullScreen(False) self.videoWidget.setWindowState(Qt.WindowNoState) self.videoWidget.setParent(self) self.layout.insertWidget(0, self.videoWidget) self.videoWidget.showNormal() self.show() else: self.videoWidget.setFullScreen(True) self.hide() def rewind(self, lapse=2500): """Rewind the current media file by 1 second""" new_position = self.mediaPlayer.position() - lapse self.setPosition(new_position) def forward(self, lapse=2500): """Forward media file by 1 second""" new_position = self.mediaPlayer.position() + lapse self.setPosition(new_position) def set_volume(self, vol=0): """Set media player volume volume""" if vol: self.mediaPlayer.setVolume(vol) def red_volume(self, vol=1): """Reduce volume by a factor of 0.01""" volume = self.mediaPlayer.volume() if volume >= 0: new_volume = volume - 1 self.volumeSlider.setValue(new_volume) self.set_volume(new_volume) def inc_volume(self, vol=1): """Increase volume by a factor of 0.01""" volume = self.mediaPlayer.volume() if self.mediaPlayer.isMuted(): self.mediaPlayer.setMuted(False) self.volume.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume)) if volume <= 100: new_volume = volume + 1 self.volumeSlider.setValue(new_volume) self.set_volume(new_volume) def mute(self): """Mute media player""" if self.mediaPlayer.isMuted(): self.mediaPlayer.setMuted(False) self.volume.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume)) else: self.mediaPlayer.setMuted(True) self.volume.setIcon(self.style().standardIcon( QStyle.SP_MediaVolumeMuted))
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 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 QGisMap(QtWidgets.QWidget, Ui_Form): def __init__(self,projectfile,MainWidget): QtWidgets.QMainWindow.__init__(self) if os.name == 'nt': ffmpeg = os.path.dirname(__file__)[0:-18]+'/Video_UAV_Tracker/FFMPEG/ffmpeg.exe' versione = 'ffmpeg.exe' else: ffmpeg = os.path.dirname(__file__)+'/FFMPEG/./ffmpeg' versione = 'ffmpeg' if os.path.exists(ffmpeg) == True: self.setupUi(self) self.setWindowFlags(Qt.WindowStaysOnTopHint) self.Main = MainWidget self.projectfile = projectfile with open(self.projectfile,'r') as File: for line in File: if line[0:19] == 'Video file location': self.videoFile = line.split('=')[-1][1:-1] elif line[0:23] == 'Video start at msecond:': self.fps = (1 / (float(line.split()[7]))) * 1000 self.StartMsecond = int(line.split()[4]) elif line[0:4] == 'DB =': DB = line.split('=')[-1][1:-1] if DB == 'None': self.DB = None else: self.DB = DB break self.pushButton_3.setCheckable(True) self.EnableMapTool = False self.ExtractTool = 0 self.dockWidget_4.hide() self.GPXList = [] self.positionMarker=PositionMarker(self.Main.iface.mapCanvas()) self.muteButton.setIcon( self.style().standardIcon(QStyle.SP_MediaVolume)) self.playButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPause)) self.player = QMediaPlayer() self.player.setVideoOutput(self.video_frame) self.playButton.clicked.connect(self.PlayPause) self.muteButton.clicked.connect(self.MuteUnmute) self.toolButton_11.clicked.connect(self.SkipBackward) self.toolButton_12.clicked.connect(self.SkipForward) self.SkipBacktoolButton_8.clicked.connect(self.BackwardFrame) self.SkipFortoolButton_9.clicked.connect(self.ForwardFrame) self.toolButton_4.clicked.connect(self.ExtractToolbar) self.toolButton_5.clicked.connect(self.close) self.pushButtonCut_2.clicked.connect(self.ExtractCommand) self.pushButtonCutA_6.clicked.connect(self.ExtractFromA) self.pushButtonCutB_6.clicked.connect(self.ExtractToB) self.pushButton_5.clicked.connect(self.CancelVertex) self.progressBar.hide() self.Main.pushButton_2.hide() self.Main.pushButton_8.hide() self.Main.groupBox.show() self.Main.groupBox_4.hide() self.ExtractA = False self.ExtractB = False self.ExtractedDirectory = None self.pushButtonCut_2.setEnabled(False) self.toolButton_6.setEnabled(False) self.LoadGPXVideoFromPrj(self.projectfile) else: ret = QMessageBox.warning(self, "Warning", 'missing ffmpeg binaries, please download it from https://github.com/sagost/VideoUavTracker/blob/master/FFMPEG/'+versione+' and paste it in /.qgis3/python/plugins/Video_UAV_Tracker/FFMPEG/ ', QMessageBox.Ok) self.close() def LoadGPXVideoFromPrj(self,VideoGisPrj): self.Polyline = [] with open(VideoGisPrj,'r') as File: Counter = 0 for line in File: if Counter < 5: pass else: line = line.split() lat = float(line[0]) lon = float(line[1]) ele = float(line[2]) speed = float(line[3]) course = float(line[4]) time = line[5] Point = [lat,lon,ele,speed,course,time] qgsPoint = QgsPoint(lon,lat) self.Polyline.append(qgsPoint) self.GPXList.append(Point) Counter = Counter + 1 self.GpsLayer = QgsVectorLayer("LineString?crs=epsg:4326", self.videoFile.split('.')[-2].split('/')[-1], "memory") self.pr = self.GpsLayer.dataProvider() feat = QgsFeature() feat.setGeometry(QgsGeometry.fromPolyline(self.Polyline)) self.pr.addFeatures([feat]) self.GpsLayer.updateExtents() if self.DB != None: try: self.DBLayer = QgsVectorLayer(self.DB,self.DB.split('.')[-2].split('/')[-1],'ogr') QgsProject.instance().addMapLayers([self.DBLayer,self.GpsLayer]) self.AddPointMapTool = AddPointTool(self.Main.iface.mapCanvas(),self.DBLayer,self) self.toolButton_6.clicked.connect(self.AddPointTool) self.toolButton_6.setEnabled(True) except: ret = QMessageBox.warning(self, "Warning", str(self.DB)+' is not a valid shapefile.', QMessageBox.Ok) return else: QgsProject.instance().addMapLayers([self.GpsLayer]) self.duration = len(self.GPXList) self.ExtractToB = self.duration self.horizontalSlider.setSingleStep(1000) self.horizontalSlider.setMinimum(0) self.horizontalSlider.setMaximum(len(self.GPXList)*1000) url = QUrl.fromLocalFile(str(self.videoFile)) mc = QMediaContent(url) self.player.setMedia(mc) self.player.setPosition(self.StartMsecond) self.player.play() self.horizontalSlider.sliderMoved.connect(self.setPosition) self.player.stateChanged.connect(self.mediaStateChanged) self.player.positionChanged.connect(self.positionChanged) self.pushButton_3.clicked.connect(self.MapTool) self.skiptracktool = SkipTrackTool( self.Main.iface.mapCanvas(),self.GpsLayer , self) def AddPointTool(self): self.Main.iface.mapCanvas().setMapTool(self.AddPointMapTool) def MapTool(self): if self.EnableMapTool == False: self.Main.iface.mapCanvas().setMapTool(self.skiptracktool) self.pushButton_3.setChecked(True) self.EnableMapTool = True else: self.Main.iface.mapCanvas().unsetMapTool(self.skiptracktool) self.pushButton_3.setChecked(False) self.EnableMapTool = False def closeEvent(self, *args, **kwargs): try: self.player.stop() self.Main.iface.mapCanvas().scene().removeItem(self.positionMarker) self.CancelVertex() self.Main.pushButton_2.show() #self.Main.horizontalSpacer_2.show() self.Main.groupBox.hide() self.Main.pushButton_8.show() self.Main.groupBox_4.show() self.dockWidget_2.close() except: pass return QtWidgets.QWidget.closeEvent(self, *args, **kwargs) def mediaStateChanged(self, state): if self.player.state() == QMediaPlayer.PlayingState: self.playButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPause)) else: self.playButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPlay)) def setPosition(self, position): self.player.setPosition(position+self.StartMsecond) def secTotime(self,seconds): m, s = divmod(seconds, 60) h, m = divmod(m, 60) return "%d:%02d:%02d" % (h, m, s) def positionChanged(self, progress): if progress < self.StartMsecond: self.player.setPosition(self.StartMsecond) progress = self.StartMsecond AssociatedGps = round((progress - self.StartMsecond )/1000) self.DisplayPoint(AssociatedGps) totalTime = self.secTotime(self.duration) actualTime = self.secTotime((progress - self.StartMsecond )/1000) self.replayPosition_label.setText(actualTime + ' / '+totalTime) if not self.horizontalSlider.isSliderDown(): self.horizontalSlider.setValue(progress - self.StartMsecond ) def DisplayPoint(self,Point): if Point >= len(self.GPXList): Point = len(self.GPXList) - 1 gpx = self.GPXList[Point] lat = round(gpx[0],7) lon = round(gpx[1],7) ele = gpx[2] speed = gpx[3] course = gpx[4] time = gpx[5] Point = QgsPointXY() Point.set(lon, lat) canvas = self.Main.iface.mapCanvas() crsSrc = QgsCoordinateReferenceSystem(4326) # .gpx is in WGS 84 crsDest = QgsProject.instance().crs() xform = QgsCoordinateTransform(crsSrc, crsDest) self.positionMarker.setHasPosition(True) self.Point = xform.transform(Point) self.positionMarker.newCoords(self.Point) self.positionMarker.angle = float(course) extent = canvas.extent() boundaryExtent=QgsRectangle(extent) boundaryExtent.scale(0.7) if not boundaryExtent.contains(QgsRectangle(Point, self.Point)): extentCenter= self.Point newExtent=QgsRectangle( extentCenter.x()-extent.width()/2, extentCenter.y()-extent.height()/2, extentCenter.x()+extent.width()/2, extentCenter.y()+extent.height()/2 ) self.Main.iface.mapCanvas().setExtent(newExtent) self.Main.iface.mapCanvas().refresh() self.Main.label_14.setText('GPS Time: '+str(time)) self.Main.label_15.setText('Course: '+"%.2f" % (course)) self.Main.label_16.setText('Ele: '+"%.2f" %(ele)) self.Main.label_17.setText('Speed m/s: '+"%.2f" %(speed)) self.Main.label_19.setText('Lat : '+str(lat)) self.Main.label_18.setText('Lon : '+str(lon)) def MuteUnmute(self): if self.player.mediaStatus() == 6 : if self.player.isMuted() == 1: self.player.setMuted(0) self.muteButton.setIcon( self.style().standardIcon(QStyle.SP_MediaVolume)) elif self.player.isMuted() == 0: self.player.setMuted(1) self.muteButton.setIcon( self.style().standardIcon(QStyle.SP_MediaVolumeMuted)) def SkipForward(self): position = self.player.position() self.player.setPosition(position+1000) def SkipBackward(self): position = self.player.position() self.player.setPosition(position-1000) def ForwardFrame(self): position = self.player.position() self.player.setPosition(position+int(self.fps)) def BackwardFrame(self): position = self.player.position() self.player.setPosition(position-int(self.fps)) def PlayPause(self): if self.player.state() == QMediaPlayer.PlayingState: self.player.pause() else: self.player.play() def findNearestPointInRecording(self, x,y): ClickPt = QgsPoint(x,y) Low = ClickPt.distanceSquared(self.Polyline[0]) NearPoint = 0 Counter = 0 for Point in self.Polyline: dist = ClickPt.distanceSquared(Point) if dist < Low: Low = dist NearPoint = Counter Counter = Counter + 1 else: Counter = Counter + 1 self.setPosition(NearPoint*1000) def ExtractSingleFrameOnTime(self, pos, outputfile): if os.name == 'nt': ffmpeg = ('"'+os.path.dirname(__file__)[0:-18]+'/Video_UAV_Tracker/FFMPEG/ffmpeg.exe'+'"') os.popen(str(ffmpeg)+' -ss '+str(pos/1000)+' -i '+str('"' +self.videoFile+ '"')+ ' -t 1 '+str('"'+outputfile+'"')) else: ffmpeg = os.path.dirname(__file__)+'/FFMPEG/./ffmpeg' os.system(str(ffmpeg)+' -ss '+str(pos/1000)+' -i '+str(self.videoFile)+' -t 1 '+str(outputfile)) def AddPoint(self,x,y): self.Main.iface.mapCanvas().unsetMapTool(self.AddPointMapTool) Point = QgsPointXY(x,y) pos = self.player.position() if self.player.state() == QMediaPlayer.PlayingState: self.player.pause() a = self.DBLayer.name() last_desc = '///' LayerName =str(a) last_desc2 = LayerName + ' Point N ' directory = str(self.DB.split('.')[0])+'_Image/' if not os.path.exists(directory): os.makedirs(directory) fc = int(self.DBLayer.featureCount()) self.ExtractSingleFrameOnTime(pos,directory+LayerName+'_'+str(fc)+'_.jpg') fields = self.DBLayer.fields() attributes = [] lat,lon = Point.y(), Point.x() for field in fields: a = str(field.name()) b = str(field.typeName()) if a == 'id': fcnr = fc attributes.append(fcnr) elif a == 'Lon(WGS84)': attributes.append(str(lon)) elif a == 'Lat(WGS84)': attributes.append(str(lat)) elif a == 'Image link': attributes.append(str(directory+LayerName+'_'+str(fc)+'_.jpg')) else: if b == 'String': (a,ok) = QInputDialog.getText( self.Main.iface.mainWindow(), "Attributes", a + ' = String', QLineEdit.Normal) attributes.append(a) elif b == 'Real': (a,ok) = QInputDialog.getDouble( self.Main.iface.mainWindow(), "Attributes", a + ' = Real', decimals = 10) attributes.append(a) elif b == 'Integer64': (a,ok) = QInputDialog.getInt( self.Main.iface.mainWindow(), "Attributes", a + ' = Integer') attributes.append(a) feature = QgsFeature() feature.setGeometry(QgsGeometry.fromPoint(Point)) feature.setAttributes(attributes) self.DBLayer.startEditing() self.DBLayer.addFeature(feature) self.DBLayer.commitChanges() self.DBLayer.triggerRepaint() def ExtractCommand(self): if self.ExtractToB <= self.ExtractFromA: ret = QMessageBox.warning(self, "Warning", '"To B" point must be after "from A" point', QMessageBox.Ok) self.CancelVertex() else: if os.name == 'nt': ffmpeg = '"'+os.path.dirname(__file__)[0:-18]+'/Video_UAV_Tracker/FFMPEG/ffmpeg.exe'+'"' else: ffmpeg = os.path.dirname(__file__)+'/FFMPEG/./ffmpeg' Directory,_ = QFileDialog.getSaveFileName(caption= 'Save georeferenced images') if Directory: self.progressBar.show() self.progressBar.setValue(0) start = self.ExtractFromA if self.comboBox_6.currentText() == 'seconds': finish = self.ExtractToB - self.ExtractFromA fps = self.doubleSpinBox_2.value() if fps < 1.0: fps = 1.0 / fps elif fps > 1: fps = 1.0 / fps if os.name == 'nt': os.popen(str(ffmpeg+ ' -ss ' + str(start) + ' -i '+ str('"'+self.videoFile+'"')+ ' -t ' + str(finish) + ' -vf fps=' + str(fps) + ' ' + '"'+Directory + '_%d.png'+'"')) else: os.system(ffmpeg+' -ss '+ str(start) + ' -i '+ str(self.videoFile) + ' -t ' + str(finish) + ' -vf fps=' + str(fps) + ' ' + Directory + '_%d.png') else: txtGPSFile = open(Directory + 'UTM_Coordinates.txt', 'w') txtGPSFile.close() txtGPSFile = open(Directory+ 'UTM_Coordinates.txt', 'a') txtGPSFile.write('filename # East UTM # North UTM # Ele '+ '\n') finish = self.ExtractToB meters = self.doubleSpinBox_2.value() Timerange = range(start, finish + 1) RemainToUseMeterTotal = 0 if os.name == 'nt': os.popen(ffmpeg+' -ss '+ str(start) + ' -i '+ str('"'+self.videoFile+'"') + ' -frames:v 1 ' + '"'+Directory + '_sec_' + str(start)+'.00.png'+'"') else: os.system(ffmpeg+' -ss '+ str(start) + ' -i '+ str(self.videoFile) + ' -frames:v 1 ' + Directory + '_sec_' + str(start)+'.00.png') lonUTM, latUTM,quotainutile = self.transform_wgs84_to_utm(float(self.GPXList[start][1]) , float(self.GPXList[start][0])) ele = float(self.GPXList[start][2]) txtGPSFile.write(str(Directory.split('/')[-1]) + '_sec_' + str(start)+'.00.png,'+' '+ str(lonUTM) + ', '+ str(latUTM) + ', ' + str(ele) + '\n') for i in Timerange: progessBarValue = ((i-start) * 100) // len(Timerange) self.progressBar.setValue(int(progessBarValue)) latitude1,longitude1 = float(self.GPXList[i][0]) ,float(self.GPXList[i][1]) latitude2,longitude2 = float(self.GPXList[i+1][0]) ,float(self.GPXList[i+1][1]) ele1 = float(self.GPXList[i][2]) ele2 = float(self.GPXList[i+1][2]) Calculus = Geodesic.WGS84.Inverse(latitude1, longitude1, latitude2, longitude2) DistanceBetweenPoint = Calculus['s12'] Azimuth = Calculus['azi2'] SpeedMeterSecond = DistanceBetweenPoint #GPS refresh rate is actually 1, change parameter for different rates # Time = 1 if RemainToUseMeterTotal == 0: if DistanceBetweenPoint >= meters: decimalSecondToAdd = meters / DistanceBetweenPoint RemainToUseMeter = DistanceBetweenPoint - meters if os.name == 'nt': os.popen(ffmpeg+ ' -ss '+ str(i + decimalSecondToAdd) + ' -i '+ str('"'+self.videoFile+'"') + ' -frames:v 1 ' +'"'+ Directory + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4] +'.png'+'"') else: os.system(ffmpeg+ ' -ss '+ str(i + decimalSecondToAdd) + ' -i '+ str(self.videoFile) + ' -frames:v 1 ' + Directory + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4] +'.png') CalculusDirect = Geodesic.WGS84.Direct(latitude1, longitude1, Azimuth,decimalSecondToAdd* SpeedMeterSecond) X,Y,quotainutile = self.transform_wgs84_to_utm(CalculusDirect['lon2'],CalculusDirect['lat2'] ) Z = ele1 + decimalSecondToAdd*(ele2 - ele1) txtGPSFile.write(str(Directory.split('/')[-1]) + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4]+'.png,' + ' ' + str(X) + ', ' + str(Y) + ', ' + str(Z) + '\n') while RemainToUseMeter > meters: decimalSecondToAddMore = meters / SpeedMeterSecond RemainToUseMeter = RemainToUseMeter - meters decimalSecondToAdd = decimalSecondToAdd + decimalSecondToAddMore if os.name == 'nt': os.popen(ffmpeg+ ' -ss '+ str(i + decimalSecondToAdd) + ' -i '+ str('"'+self.videoFile+'"') + ' -frames:v 1 ' +'"'+ Directory + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4] +'.png'+'"') else: os.system(ffmpeg+ ' -ss '+ str(i + decimalSecondToAdd) + ' -i '+ str(self.videoFile) + ' -frames:v 1 ' + Directory + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4] +'.png') CalculusDirect = Geodesic.WGS84.Direct(latitude1, longitude1, Azimuth,decimalSecondToAdd* SpeedMeterSecond) X,Y,quotainutile = self.transform_wgs84_to_utm(CalculusDirect['lon2'],CalculusDirect['lat2'] ) Z = ele1 + decimalSecondToAdd*(ele2 - ele1) txtGPSFile.write(str(Directory.split('/')[-1]) + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4]+'.png,' + ' ' + str(X) + ', ' + str(Y) + ', ' + str(Z) + '\n') if RemainToUseMeter == meters: decimalSecondToAddMore = meters / SpeedMeterSecond RemainToUseMeter = RemainToUseMeter - meters decimalSecondToAdd = decimalSecondToAdd + decimalSecondToAddMore if os.name == 'nt': os.popen(ffmpeg+ ' -ss '+ str(i + decimalSecondToAdd) + ' -i '+ str('"'+self.videoFile+'"') + ' -frames:v 1 ' +'"'+ Directory + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4] +'.png'+'"') else: os.system(ffmpeg+ ' -ss '+ str(i + decimalSecondToAdd) + ' -i '+ str(self.videoFile) + ' -frames:v 1 ' + Directory + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4] +'.png') CalculusDirect = Geodesic.WGS84.Direct(latitude1, longitude1, Azimuth,decimalSecondToAdd* SpeedMeterSecond) X,Y,quotainutile = self.transform_wgs84_to_utm(CalculusDirect['lon2'],CalculusDirect['lat2'] ) Z = ele1 + decimalSecondToAdd*(ele2 - ele1) txtGPSFile.write(str(Directory.split('/')[-1]) + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4]+'.png,' + ' ' +str(X) + ', ' + str(Y) + ', ' + str(Z) + '\n') RemainToUseMeterTotal = 0 elif RemainToUseMeter < meters: RemainToUseMeterTotal = RemainToUseMeter pass else: RemainToUseMeterTotal = meters - DistanceBetweenPoint elif RemainToUseMeterTotal > 0: if DistanceBetweenPoint >= (meters - RemainToUseMeterTotal) : decimalSecondToAdd = (meters - RemainToUseMeterTotal) / DistanceBetweenPoint RemainToUseMeter = DistanceBetweenPoint - (meters - RemainToUseMeterTotal) if os.name == 'nt': os.popen(ffmpeg+ ' -ss '+ str(i + decimalSecondToAdd) + ' -i '+ str('"'+self.videoFile+'"') + ' -frames:v 1 ' +'"'+ Directory + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4] +'.png'+'"') else: os.system(ffmpeg+ ' -ss '+ str(i + decimalSecondToAdd) + ' -i '+ str(self.videoFile) + ' -frames:v 1 ' + Directory + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4] +'.png') CalculusDirect = Geodesic.WGS84.Direct(latitude1, longitude1, Azimuth,decimalSecondToAdd* SpeedMeterSecond) X,Y,quotainutile = self.transform_wgs84_to_utm(CalculusDirect['lon2'],CalculusDirect['lat2'] ) Z = ele1 + decimalSecondToAdd*(ele2 - ele1) txtGPSFile.write(str(Directory.split('/')[-1]) + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4]+'.png,' + ' ' + str(X) + ', ' + str(Y) + ', ' + str(Z) + '\n') while RemainToUseMeter > meters: decimalSecondToAddMore = meters / SpeedMeterSecond RemainToUseMeter = RemainToUseMeter - meters decimalSecondToAdd = decimalSecondToAdd + decimalSecondToAddMore if os.name == 'nt': os.popen(ffmpeg+ ' -ss '+ str(i + decimalSecondToAdd) + ' -i '+ str('"'+self.videoFile+'"') + ' -frames:v 1 ' +'"'+ Directory + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4] +'.png'+'"') else: os.system(ffmpeg+ ' -ss '+ str(i + decimalSecondToAdd) + ' -i '+ str(self.videoFile) + ' -frames:v 1 ' + Directory + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4] +'.png') CalculusDirect = Geodesic.WGS84.Direct(latitude1, longitude1, Azimuth,decimalSecondToAdd* SpeedMeterSecond) X,Y,quotainutile = self.transform_wgs84_to_utm(CalculusDirect['lon2'],CalculusDirect['lat2'] ) Z = ele1 + decimalSecondToAdd*(ele2 - ele1) txtGPSFile.write(str(Directory.split('/')[-1]) + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4]+'.png,' + ' ' + str(X) + ', ' + str(Y) + ', ' + str(Z) + '\n') if RemainToUseMeter == meters: decimalSecondToAddMore = meters / SpeedMeterSecond RemainToUseMeter = RemainToUseMeter - meters decimalSecondToAdd = decimalSecondToAdd + decimalSecondToAddMore if os.name == 'nt': os.popen(ffmpeg+ ' -ss '+ str(i + decimalSecondToAdd) + ' -i '+ str('"'+self.videoFile+'"') + ' -frames:v 1 ' +'"'+ Directory + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4] +'.png'+'"') else: os.system(ffmpeg+ ' -ss '+ str(i + decimalSecondToAdd) + ' -i '+ str(self.videoFile) + ' -frames:v 1 ' + Directory + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4] +'.png') CalculusDirect = Geodesic.WGS84.Direct(latitude1, longitude1, Azimuth,decimalSecondToAdd* SpeedMeterSecond) X,Y,quotainutile = self.transform_wgs84_to_utm(CalculusDirect['lon2'],CalculusDirect['lat2'] ) Z = ele1 + decimalSecondToAdd*(ele2 - ele1) txtGPSFile.write(str(Directory.split('/')[-1]) + '_sec_' + str(i) + str(decimalSecondToAdd)[1:4]+'.png,' + ' ' + str(X) + ', ' + str(Y) + ', ' + str(Z) + '\n') RemainToUseMeterTotal = 0 elif RemainToUseMeter < meters: RemainToUseMeterTotal = RemainToUseMeter else: RemainToUseMeterTotal = (meters - DistanceBetweenPoint) + RemainToUseMeterTotal txtGPSFile.close() self.progressBar.hide() def ExtractFromA(self): if self.ExtractA == True: self.Main.iface.mapCanvas().scene().removeItem(self.ExtractAVertex) self.ExtractA = False self.ExtractFromA = round((self.player.position()- self.StartMsecond )/1000) canvas = self.Main.iface.mapCanvas() crsSrc = QgsCoordinateReferenceSystem(4326) # .gpx is in WGS 84 crsDest = QgsProject.instance().crs() xform = QgsCoordinateTransform(crsSrc, crsDest) latitude,longitude = self.Polyline[self.ExtractFromA].y(), self.Polyline[self.ExtractFromA].x() self.ExtractAVertex = QgsVertexMarker(canvas) self.ExtractAVertex.setCenter(xform.transform(QgsPointXY(longitude, latitude))) self.ExtractAVertex.setColor(QColor(0,255,0)) self.ExtractAVertex.setIconSize(10) self.ExtractAVertex.setIconType(QgsVertexMarker.ICON_X) self.ExtractAVertex.setPenWidth(10) self.ExtractA = True if self.ExtractB == True: self.pushButtonCut_2.setEnabled(True) else: self.pushButtonCut_2.setEnabled(False) def ExtractToB(self): if self.ExtractB == True: self.Main.iface.mapCanvas().scene().removeItem(self.ExtractBVertex) self.ExtractB = False self.ExtractToB = round((self.player.position()- self.StartMsecond )/1000) if self.ExtractA == True: if self.ExtractToB > self.ExtractFromA: canvas = self.Main.iface.mapCanvas() crsSrc = QgsCoordinateReferenceSystem(4326) # .gpx is in WGS 84 crsDest = QgsProject.instance().crs() xform = QgsCoordinateTransform(crsSrc, crsDest) latitude,longitude = self.Polyline[self.ExtractToB].y(), self.Polyline[self.ExtractToB].x() self.ExtractBVertex = QgsVertexMarker(canvas) self.ExtractBVertex.setCenter(xform.transform(QgsPointXY(longitude, latitude))) self.ExtractBVertex.setColor(QColor(255,0,0)) self.ExtractBVertex.setIconSize(10) self.ExtractBVertex.setIconType(QgsVertexMarker.ICON_X) self.ExtractBVertex.setPenWidth(10) self.ExtractB = True self.pushButtonCut_2.setEnabled(True) else: self.pushButtonCut_2.setEnabled(False) def CancelVertex(self): if self.ExtractA == True: self.Main.iface.mapCanvas().scene().removeItem(self.ExtractAVertex) self.ExtractA = False if self.ExtractB == True: self.Main.iface.mapCanvas().scene().removeItem(self.ExtractBVertex) self.ExtractB = False self.pushButtonCut_2.setEnabled(False) def ExtractToolbar(self): if self.ExtractTool == 0: self.dockWidget_4.show() self.ExtractTool = 1 else: self.dockWidget_4.hide() self.ExtractTool = 0 def transform_wgs84_to_utm(self, lon, lat): def get_utm_zone(longitude): return (int(1+(longitude+180.0)/6.0)) def is_northern(latitude): """ Determines if given latitude is a northern for UTM """ if (latitude < 0.0): return 0 else: return 1 utm_coordinate_system = osr.SpatialReference() utm_coordinate_system.SetWellKnownGeogCS("WGS84") # Set geographic coordinate system to handle lat/lon utm_coordinate_system.SetUTM(get_utm_zone(lon), is_northern(lat)) wgs84_coordinate_system = utm_coordinate_system.CloneGeogCS() # Clone ONLY the geographic coordinate system wgs84_to_utm_transform = osr.CoordinateTransformation(wgs84_coordinate_system, utm_coordinate_system) # (<from>, <to>) return wgs84_to_utm_transform.TransformPoint(lon, lat, 0) # returns easting, northing, altitude
class DPlayerCore(QWidget): def __init__(self): """Initialize player and load playlist if any.""" super().__init__() self.player = QMediaPlayer() self.playlist = QMediaPlaylist() self.player.setPlaylist(self.playlist) self.shuffling = False self.repeatingPlaylist = False self.repeatingSong = False self.musicOrder = [] self.loadPlaylist(QUrl( 'file://{}/lastListened.m3u'.format(os.getcwd()))) self.lyricsApi = 'http://api.musixmatch.com/ws/1.1/' self.lyricsApiKey = '4b364f0652e471aa50813a22cdf830ea' self.lastFMapi = 'http://ws.audioscrobbler.com/2.0/' self.lastFMapikey = '052c43a00a4fc294bb3c9e0c38bdf710' self.lastFMsecret = '14c66392fa9c6c142a41ccc2b0674e19' self.username = None self.password = None self.network = None self.error = 'Something went wrong! Try again later.' def play(self): """Start the player.""" self.player.play() def pause(self): """Pause the player.""" self.player.pause() def stop(self): """Stop the player.""" self.player.stop() def previous(self): """Play previous song.""" self.playlist.previous() def next(self): """Play next song.""" self.playlist.next() def mute(self): """Mute the player.""" self.player.setMuted(True) def unmute(self): """Unmute the player.""" self.player.setMuted(False) def setVolume(self, value): """Set player's volume to value.""" self.player.setVolume(value) def add(self, fileNames): """Add fileNames to the playlist.""" for name in fileNames: url = QUrl.fromLocalFile(QFileInfo(name).absoluteFilePath()) self.playlist.addMedia(QMediaContent(url)) self.musicOrder.append([name]) self.added(len(fileNames)) def added(self, added): """Saves music info in musicOrder.""" for name, index in zip( self.musicOrder[self.playlist.mediaCount() - added:], range(self.playlist.mediaCount() - added, len(self.musicOrder))): name = name[0] artist = self.getArtist(name)[0] title = self.getTitle(name)[0] album = self.getAlbum(name)[0] seconds = self.getDuration(name) duration = QTime(0, seconds // 60, seconds % 60) duration = duration.toString('mm:ss') self.musicOrder[index].extend( [artist, title, album, duration]) def remove(self, songIndexes): """Remove songIndexes from the playlist.""" for index in songIndexes: self.songChanged = True del self.musicOrder[index] self.playlist.removeMedia(index) self.songChanged = False def savePlaylist(self, path): """Save playlist to path.""" if path.toString()[len(path.toString()) - 4:] != '.m3u': path = QUrl('{}.m3u'.format(path.toString())) self.playlist.save(path, 'm3u') def loadPlaylist(self, path): """Load playlist form path.""" count = self.playlist.mediaCount() self.playlist.load(path) for index in range(count, self.playlist.mediaCount()): self.musicOrder.append( [self.playlist.media(index).canonicalUrl().path()]) self.added(self.playlist.mediaCount() - count) def clearPlaylist(self): """Delete all songs in the playlist.""" self.playlist.clear() self.musicOrder = [] def shuffle(self, value): """Shuffle playlist if value = True.""" self.shuffling = value if self.repeatingSong: return if self.shuffling: self.playlist.setPlaybackMode(QMediaPlaylist.Random) elif self.repeatingPlaylist: self.playlist.setPlaybackMode(QMediaPlaylist.Loop) else: self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) def repeatPlaylist(self, value): """Repeat playlist after the last song is finished if value = True.""" self.repeatingPlaylist = value if self.repeatingSong or self.shuffling: return if self.repeatingPlaylist: self.playlist.setPlaybackMode(QMediaPlaylist.Loop) else: self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) def repeatSong(self, value): """Repeat current song if value = True.""" self.repeatingSong = value if self.repeatingSong: self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop) elif self.shuffling: self.playlist.setPlaybackMode(QMediaPlaylist.Random) elif self.repeatingPlaylist: self.playlist.setPlaybackMode(QMediaPlaylist.Loop) else: self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) def sort(self, column, order): """Sort playlist by column in order.""" ordered = sorted(self.musicOrder, key=itemgetter(column + 1), reverse=order) self.clearPlaylist() for song in ordered: url = QUrl.fromLocalFile(QFileInfo(song[0]).absoluteFilePath()) self.playlist.addMedia(QMediaContent(url)) self.musicOrder = ordered def findLyrics(self, index): """Returns lyrics for song at index.""" if self.musicOrder[index][2] == 'Unknown': return 'Unknown song.' searchSong = '{}track.search?q_track={}'.format( self.lyricsApi, self.musicOrder[index][2].replace(' ', '%20')) if self.musicOrder[index][1] != 'Unknown': searchSong = '{}&q_artist={}'.format( searchSong, self.musicOrder[index][1].replace(' ', '%20')) searchSong = '{}&f_has_lyrics=1&apikey={}'.format( searchSong, self.lyricsApiKey) try: requestSong = requests.get(searchSong) except requests.ConnectionError: return self.error songJson = requestSong.json() if requestSong.status_code != 200 or \ songJson['message']['header']['available'] == 0: return self.error songId = songJson[ 'message']['body']['track_list'][0]["track"]["track_id"] searchLyrics = '{}track.lyrics.get?track_id={}&apikey={}'.format( self.lyricsApi, songId, self.lyricsApiKey) try: requestLyrics = requests.get(searchLyrics) except requests.ConnectionError: return self.error if requestLyrics.status_code != 200 or \ songJson['message']['header']['available'] == 0: return self.error return requestLyrics.json()[ 'message']['body']['lyrics']['lyrics_body'][:-58] # spam and bacon def findInfo(self, index): """Returns info about artist and album for index if any.""" info = [] if self.musicOrder[index][1] != 'Unknown': artist = self.artistInfo(self.musicOrder[index][1]) if artist != self.error: info += artist if self.musicOrder[index][1] != 'Unknown' and \ self.musicOrder[index][3] != 'Unknown': album = self.albumInfo(self.musicOrder[index][1], self.musicOrder[index][3]) if album != self.error: info += album if info: return info else: return ['Unknown artist and song!'] def artistInfo(self, artist): """Returns info about artist if any.""" try: response = requests.get( ('{}/?method=artist.getinfo&artist={}&api_key={}&' 'format=json&autocorrect=1').format( self.lastFMapi, artist, self.lastFMapikey)) except Exception: return self.error if response.status_code != 200: return self.error artist = 'Artist: {}'.format(response.json()['artist']['name']) bio = 'Bio: {}'.format( response.json()['artist']['bio']['summary'].replace('.', '.\n')) spam = bio.find('<a') bio = bio[:spam] return [artist, bio] def albumInfo(self, artist, album): """Returns info about album if any.""" try: response = requests.get( ('{}/?method=album.getinfo&artist={}&album={}&api_key={}&' 'format=json&autocorrect=1').format( self.lastFMapi, artist, album, self.lastFMapikey)) except Exception: return self.error if response.status_code != 200 or \ 'album' not in response.json().keys(): return self.error album = 'Album: {}'.format(response.json()['album']['name']) tracks = ['Tracks: '] t = response.json()['album']['tracks']['track'] for track, index in zip(t, range(len(t))): tracks.append('{}. {}'.format(index + 1, track['name'])) info = [album, '\n'.join(tracks)] if 'wiki' in response.json()['album'].keys(): wiki = response.json()['album']['wiki'] if 'published' in wiki.keys(): info.append('Published: {}'.format(wiki['published'])) if 'summary' in wiki.keys(): summary = wiki['summary'].replace('.', '.\n') spam = summary.find('<a') info.append('Summary: {}'.format(summary[:spam])) if 'Musical style' in wiki.keys(): info.append('Musical style: {}'.format(wiki['Musical style'])) return info def login(self, username, password): """Creates lastFM network.""" self.username = username self.password = pylast.md5(password) try: self.network = pylast.LastFMNetwork(api_key=self.lastFMapikey, api_secret=self.lastFMsecret, username=self.username, password_hash=self.password) except Exception: self.username = None self.password = None self.network = None return False return True def logout(self): """Destoys lastFM network and current user info.""" self.username = None self.password = None self.network = None def loveTrack(self, index): """Love track at index in lastFM.""" if self.network is None: return False track = self.network.get_track(self.musicOrder[index][1], self.musicOrder[index][2]) try: track.love() except Exception: return False return True def unloveTrack(self, index): """Unlove track at index in lastFM.""" if self.network is None: return False track = self.network.get_track(self.musicOrder[index][1], self.musicOrder[index][2]) try: track.unlove() except Exception: return False return True def isMuted(self): """Returns True if player is muted.""" return self.player.isMuted() def getArtist(self, song): """Returns the artist of song.""" if song[-4:] == '.mp3': obj = EasyID3(song) if 'artist' in obj.keys(): return obj['artist'] elif 'TAG' in mediainfo(song).keys(): obj = mediainfo(song)['TAG'] if 'artist' in obj.keys(): return [obj['artist']] elif 'ARTIST' in obj.keys(): return [obj['ARTIST']] else: return ['Unknown'] else: return ['Unknown'] def getTitle(self, song): """Returns the title of song.""" if song[-4:] == '.mp3': obj = EasyID3(song) if 'title' in obj.keys(): return obj['title'] elif 'TAG' in mediainfo(song).keys(): obj = mediainfo(song)['TAG'] if 'title' in obj.keys(): return [obj['title']] elif 'TITLE' in obj.keys(): return [obj['TITLE']] else: return ['Unknown'] else: return ['Unknown'] def getAlbum(self, song): """Returns the album of song.""" if song[-4:] == '.mp3': obj = EasyID3(song) if 'album' in obj.keys(): return obj['album'] elif 'TAG' in mediainfo(song).keys(): obj = mediainfo(song)['TAG'] if 'album' in obj.keys(): return [obj['album']] elif 'ALBUM' in obj.keys(): return [obj['ALBUM']] else: return ['Unknown'] else: return ['Unknown'] def getDuration(self, song): """Returns the duration of song.""" if song[-4:] == '.mp3': return MP3(song).info.length return int(float(mediainfo(song)['duration']))
class videoPlayer(QVideoWidget): def __init__(self, parent): super(QVideoWidget, self).__init__(parent) self.player = QMediaPlayer(self) self.player.setVolume(50) self.player.setVideoOutput(self) self.player.mediaStatusChanged.connect(self.mediaStatusChanged) def update(self, path): if path: path = QUrl.fromLocalFile(path) self.player.setMedia(QMediaContent(path)) self.player.play() def rotate(self, path, sign): self.update(None) clip = VideoFileClip(path) clip.rotate(90 * sign) if path.endswith(('gif')): clip.write_gif(path) else: clip.write_videofile(path) clip.close() def pause(self): status = self.player.state() if status == QMediaPlayer.PlayingState: self.player.pause() elif status == QMediaPlayer.PausedState: self.player.play() def position(self, delta): self.player.setPosition(self.player.position() + delta) def volume(self, delta): if self.player.isAudioAvailable(): self.player.setVolume(self.player.volume() + delta) def mute(self): if self.player.isAudioAvailable(): self.player.setMuted(not self.player.isMuted()) def stop(self): self.player.stop() def mediaStatusChanged(self, status): if status == QMediaPlayer.EndOfMedia: self.player.play() elif status not in (2, 1): self.parent().setCurrentIndex(1) def wheelEvent(self, event): self.volume(event.angleDelta().y() // 12)
class Ui_MainWindow(QWidget): def __init__(self, feature=feature): super().__init__() self.feature = feature self.points_CAM1 = [] self.points_CAM2 = [] self.points_CAM3 = [] self.numWarning = 0 def setupUi(self, Form): Form.setObjectName("Form") Form.resize(1048, 375) self.verticalLayout_4 = QtWidgets.QVBoxLayout(Form) self.verticalLayout_4.setObjectName("verticalLayout_4") self.tabWidget = QtWidgets.QTabWidget(Form) self.tabWidget.setObjectName("tabWidget") self.tab = QtWidgets.QWidget() self.tab.setObjectName("tab") # View CAM 1 self.gridLayout = QtWidgets.QGridLayout(self.tab) self.gridLayout.setHorizontalSpacing(20) self.gridLayout.setObjectName("gridLayout") self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setSpacing(10) self.verticalLayout_3.setObjectName("verticalLayout_3") self.CAM1 = QtWidgets.QLabel(self.tab) self.CAM1.setMinimumSize(QtCore.QSize(320, 240)) self.CAM1.setMaximumSize(QtCore.QSize(426, 400)) self.CAM1.setFrameShape(QtWidgets.QFrame.Box) self.CAM1.setObjectName("CAM1") self.verticalLayout_3.addWidget(self.CAM1) self.horizontalLayout_6 = QtWidgets.QHBoxLayout() self.horizontalLayout_6.setObjectName("horizontalLayout_6") self.startCAM1 = QtWidgets.QPushButton(self.tab) self.startCAM1.setObjectName("startCAM1") self.horizontalLayout_6.addWidget(self.startCAM1) self.carProtectionCAM1 = QtWidgets.QPushButton(self.tab) self.carProtectionCAM1.setObjectName("carProtectionCAM1") self.horizontalLayout_6.addWidget(self.carProtectionCAM1) self.monitorAreaCAM1 = QtWidgets.QPushButton(self.tab) self.monitorAreaCAM1.setObjectName("monitorAreaCAM1") self.horizontalLayout_6.addWidget(self.monitorAreaCAM1) self.verticalLayout_3.addLayout(self.horizontalLayout_6) self.horizontalLayout_7 = QtWidgets.QHBoxLayout() self.horizontalLayout_7.setObjectName("horizontalLayout_7") self.stopCAM1 = QtWidgets.QPushButton(self.tab) self.stopCAM1.setEnabled(False) self.stopCAM1.setObjectName("stopCAM1") self.horizontalLayout_7.addWidget(self.stopCAM1) self.personSearchingCAM1 = QtWidgets.QPushButton(self.tab) self.personSearchingCAM1.setObjectName("personSearchingCAM1") self.horizontalLayout_7.addWidget(self.personSearchingCAM1) self.illegalCAM1 = QtWidgets.QPushButton(self.tab) self.illegalCAM1.setObjectName("illegalCAM1") self.horizontalLayout_7.addWidget(self.illegalCAM1) self.verticalLayout_3.addLayout(self.horizontalLayout_7) self.gridLayout.addLayout(self.verticalLayout_3, 0, 0, 1, 1) self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setSpacing(10) self.verticalLayout.setObjectName("verticalLayout") # View CAM 2 self.CAM2 = QtWidgets.QLabel(self.tab) self.CAM2.setMinimumSize(QtCore.QSize(320, 240)) self.CAM2.setMaximumSize(QtCore.QSize(426, 400)) self.CAM2.setFrameShape(QtWidgets.QFrame.Box) self.CAM2.setObjectName("CAM2") self.verticalLayout.addWidget(self.CAM2) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.startCAM2 = QtWidgets.QPushButton(self.tab) self.startCAM2.setObjectName("startCAM2") self.horizontalLayout_2.addWidget(self.startCAM2) self.carProtectionCAM2 = QtWidgets.QPushButton(self.tab) self.carProtectionCAM2.setObjectName("carProtectionCAM2") self.horizontalLayout_2.addWidget(self.carProtectionCAM2) self.monitorAreaCAM2 = QtWidgets.QPushButton(self.tab) self.monitorAreaCAM2.setObjectName("monitorAreaCAM2") self.horizontalLayout_2.addWidget(self.monitorAreaCAM2) self.verticalLayout.addLayout(self.horizontalLayout_2) self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.stopCAM2 = QtWidgets.QPushButton(self.tab) self.stopCAM2.setEnabled(False) self.stopCAM2.setObjectName("stopCAM2") self.horizontalLayout_3.addWidget(self.stopCAM2) self.personSearchingCAM2 = QtWidgets.QPushButton(self.tab) self.personSearchingCAM2.setObjectName("personSearchingCAM2") self.horizontalLayout_3.addWidget(self.personSearchingCAM2) self.illegalCAM2 = QtWidgets.QPushButton(self.tab) self.illegalCAM2.setObjectName("illegalCAM2") self.horizontalLayout_3.addWidget(self.illegalCAM2) self.verticalLayout.addLayout(self.horizontalLayout_3) self.gridLayout.addLayout(self.verticalLayout, 0, 1, 1, 1) self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2.setSpacing(10) self.verticalLayout_2.setObjectName("verticalLayout_2") # View CAM 3 self.CAM3 = QtWidgets.QLabel(self.tab) self.CAM3.setMinimumSize(QtCore.QSize(320, 240)) self.CAM3.setMaximumSize(QtCore.QSize(426, 400)) self.CAM3.setFrameShape(QtWidgets.QFrame.Box) self.CAM3.setObjectName("CAM3") self.verticalLayout_2.addWidget(self.CAM3) self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") self.startCAM3 = QtWidgets.QPushButton(self.tab) self.startCAM3.setObjectName("startCAM3") self.horizontalLayout_4.addWidget(self.startCAM3) self.carProtectionCAM3 = QtWidgets.QPushButton(self.tab) self.carProtectionCAM3.setObjectName("carProtectionCAM3") self.horizontalLayout_4.addWidget(self.carProtectionCAM3) self.monitorAreaCAM3 = QtWidgets.QPushButton(self.tab) self.monitorAreaCAM3.setObjectName("monitorAreaCAM3") self.horizontalLayout_4.addWidget(self.monitorAreaCAM3) self.verticalLayout_2.addLayout(self.horizontalLayout_4) self.horizontalLayout_5 = QtWidgets.QHBoxLayout() self.horizontalLayout_5.setObjectName("horizontalLayout_5") self.stopCAM3 = QtWidgets.QPushButton(self.tab) self.stopCAM3.setEnabled(False) self.stopCAM3.setObjectName("stopCAM3") self.horizontalLayout_5.addWidget(self.stopCAM3) self.personSearchingCAM3 = QtWidgets.QPushButton(self.tab) self.personSearchingCAM3.setObjectName("personSearchingCAM3") self.horizontalLayout_5.addWidget(self.personSearchingCAM3) self.illegalCAM3 = QtWidgets.QPushButton(self.tab) self.illegalCAM3.setObjectName("illegalCAM3") self.horizontalLayout_5.addWidget(self.illegalCAM3) self.verticalLayout_2.addLayout(self.horizontalLayout_5) self.gridLayout.addLayout(self.verticalLayout_2, 0, 2, 1, 1) self.tabWidget.addTab(self.tab, "") # Media Tab self.tab_2 = QtWidgets.QWidget() self.tab_2.setObjectName("tab_2") self.tabWidget.addTab(self.tab_2, "") self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) videowidget = QVideoWidget() self.openBtn = QtWidgets.QPushButton('Open Video') self.playBtn = QtWidgets.QPushButton() self.playBtn.setEnabled(False) self.playBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.stopBtn = QtWidgets.QPushButton() self.stopBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaStop)) self.slowBtn = QtWidgets.QPushButton() self.slowBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaSeekBackward)) self.fastBtn = QtWidgets.QPushButton() self.fastBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaSeekForward)) self.volumeBtn = QtWidgets.QPushButton() self.volumeBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume)) self.fullscreenBtn = QPushButton("Full Screen") self.slider = QSlider(Qt.Horizontal) self.slider.setRange(0, 0) self.volume_slider = QSlider(Qt.Horizontal) self.volume_slider.setRange(0, 100) self.volume_slider.setValue(100) self.label_2_1 = QLabel() self.label_2_1.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) self.label_2_2 = QLabel() hboxLayout_2_1 = QHBoxLayout() hboxLayout_2_2 = QHBoxLayout() hboxLayout_2_3 = QHBoxLayout() hboxLayout_2_1.addWidget(self.slider) hboxLayout_2_2.addWidget(self.openBtn) hboxLayout_2_2.addWidget(self.stopBtn) hboxLayout_2_2.addWidget(self.slowBtn) hboxLayout_2_2.addWidget(self.playBtn) hboxLayout_2_2.addWidget(self.fastBtn) hboxLayout_2_2.addWidget(self.volumeBtn) hboxLayout_2_2.addWidget(self.volume_slider) hboxLayout_2_2.addStretch(1) hboxLayout_2_2.addWidget(self.fullscreenBtn) hboxLayout_2_3.addWidget(videowidget) vboxLayout_2_1 = QVBoxLayout() vboxLayout_2_1.addLayout(hboxLayout_2_3) vboxLayout_2_1.addLayout(hboxLayout_2_1) vboxLayout_2_1.addLayout(hboxLayout_2_2) vboxLayout_2_1.addWidget(self.label_2_1) self.tab_2.setLayout(vboxLayout_2_1) # Setting CAM 1 self.tab_3 = QtWidgets.QWidget() self.tab_3.setObjectName("tab_3") self.gridLayout_2 = QtWidgets.QGridLayout(self.tab_3) self.gridLayout_2.setHorizontalSpacing(20) self.gridLayout_2.setObjectName("gridLayout_2") self.verticalLayout_5 = QtWidgets.QVBoxLayout() self.verticalLayout_5.setSpacing(10) self.verticalLayout_5.setObjectName("verticalLayout_5") self.CAM1_draw = QtWidgets.QLabel(self.tab_3) self.CAM1_draw.setMinimumSize(QtCore.QSize(320, 240)) self.CAM1_draw.setMaximumSize(QtCore.QSize(426, 400)) self.CAM1_draw.setFrameShape(QtWidgets.QFrame.Box) self.CAM1_draw.setObjectName("CAM1_draw") self.verticalLayout_5.addWidget(self.CAM1_draw) self.horizontalLayout_8 = QtWidgets.QHBoxLayout() self.horizontalLayout_8.setObjectName("horizontalLayout_8") self.drawCAM1 = QtWidgets.QPushButton(self.tab_3) self.drawCAM1.setObjectName("drawCAM1") self.horizontalLayout_8.addWidget(self.drawCAM1) self.removeCAM1 = QtWidgets.QPushButton(self.tab_3) self.removeCAM1.setObjectName("removeCAM1") self.horizontalLayout_8.addWidget(self.removeCAM1) self.verticalLayout_5.addLayout(self.horizontalLayout_8) self.gridLayout_2.addLayout(self.verticalLayout_5, 0, 0, 1, 1) self.verticalLayout_6 = QtWidgets.QVBoxLayout() self.verticalLayout_6.setSpacing(10) self.verticalLayout_6.setObjectName("verticalLayout_6") # Setting CAM 2 self.CAM2_draw = QtWidgets.QLabel(self.tab_3) self.CAM2_draw.setMinimumSize(QtCore.QSize(320, 240)) self.CAM2_draw.setMaximumSize(QtCore.QSize(426, 400)) self.CAM2_draw.setFrameShape(QtWidgets.QFrame.Box) self.CAM2_draw.setObjectName("CAM2_draw") self.verticalLayout_6.addWidget(self.CAM2_draw) self.horizontalLayout_10 = QtWidgets.QHBoxLayout() self.horizontalLayout_10.setObjectName("horizontalLayout_10") self.drawCAM2 = QtWidgets.QPushButton(self.tab_3) self.drawCAM2.setObjectName("drawCAM2") self.horizontalLayout_10.addWidget(self.drawCAM2) self.removeCAM2 = QtWidgets.QPushButton(self.tab_3) self.removeCAM2.setObjectName("removeCAM2") self.horizontalLayout_10.addWidget(self.removeCAM2) self.verticalLayout_6.addLayout(self.horizontalLayout_10) self.gridLayout_2.addLayout(self.verticalLayout_6, 0, 1, 1, 1) self.verticalLayout_7 = QtWidgets.QVBoxLayout() self.verticalLayout_7.setSpacing(10) self.verticalLayout_7.setObjectName("verticalLayout_7") # Setting CAM 3 self.CAM3_draw = QtWidgets.QLabel(self.tab_3) self.CAM3_draw.setMinimumSize(QtCore.QSize(320, 240)) self.CAM3_draw.setMaximumSize(QtCore.QSize(426, 400)) self.CAM3_draw.setFrameShape(QtWidgets.QFrame.Box) self.CAM3_draw.setObjectName("CAM3_draw") self.verticalLayout_7.addWidget(self.CAM3_draw) self.horizontalLayout_12 = QtWidgets.QHBoxLayout() self.horizontalLayout_12.setObjectName("horizontalLayout_12") self.drawCAM3 = QtWidgets.QPushButton(self.tab_3) self.drawCAM3.setObjectName("drawCAM3") self.horizontalLayout_12.addWidget(self.drawCAM3) self.removeCAM3 = QtWidgets.QPushButton(self.tab_3) self.removeCAM3.setObjectName("removeCAM3") self.horizontalLayout_12.addWidget(self.removeCAM3) self.verticalLayout_7.addLayout(self.horizontalLayout_12) self.gridLayout_2.addLayout(self.verticalLayout_7, 0, 2, 1, 1) self.tabWidget.addTab(self.tab_3, "") self.verticalLayout_4.addWidget(self.tabWidget) # Setup Connect # Setup enable self.removeCAM1.setEnabled(False) self.removeCAM2.setEnabled(False) self.removeCAM3.setEnabled(False) # Setup choosing feature self.carProtectionCAM1.setVisible(self.feature['car1']) self.carProtectionCAM2.setVisible(self.feature['car2']) self.carProtectionCAM3.setVisible(self.feature['car3']) self.illegalCAM1.setVisible(self.feature['illegal1']) self.illegalCAM2.setVisible(self.feature['illegal2']) self.illegalCAM3.setVisible(self.feature['illegal3']) self.monitorAreaCAM1.setVisible(self.feature['mpa1']) self.monitorAreaCAM1.toggle() self.monitorAreaCAM1.setCheckable(True) self.monitorAreaCAM2.setVisible(self.feature['mpa2']) self.monitorAreaCAM3.setVisible(self.feature['mpa3']) self.personSearchingCAM1.setVisible(self.feature['person1']) self.personSearchingCAM2.setVisible(self.feature['person2']) self.personSearchingCAM3.setVisible(self.feature['person3']) # setup media player self.mediaPlayer.setVideoOutput(videowidget) self.openBtn.clicked.connect(self.open_file) self.playBtn.clicked.connect(self.play_video) self.stopBtn.clicked.connect(self.stop_video) self.fastBtn.clicked.connect(self.fast) self.slowBtn.clicked.connect(self.slow) self.volumeBtn.clicked.connect(self.mute) self.fullscreenBtn.clicked.connect(self.fullscreen) self.volume_slider.sliderMoved.connect(self.set_volume) self.slider.sliderMoved.connect(self.set_position) self.mediaPlayer.stateChanged.connect(self.mediastate_changed) self.mediaPlayer.positionChanged.connect(self.position_changed) self.mediaPlayer.durationChanged.connect(self.duration_changed) # setup image processing # create a timer self.timer = QTimer() self.timer2 = QTimer() self.timer3 = QTimer() # set timer timeout callback function self.timer.timeout.connect(self.viewCam1) self.startCAM1.clicked.connect(self.start_view1) self.stopCAM1.clicked.connect(self.stop_view1) self.timer2.timeout.connect(self.viewCam2) self.startCAM2.clicked.connect(self.start_view2) self.stopCAM2.clicked.connect(self.stop_view2) self.timer3.timeout.connect(self.viewCam3) self.startCAM3.clicked.connect(self.start_view3) self.stopCAM3.clicked.connect(self.stop_view3) self.CAM1_draw.mousePressEvent = self.mouseEventCAM1 self.CAM2_draw.mousePressEvent = self.mouseEventCAM2 self.CAM3_draw.mousePressEvent = self.mouseEventCAM3 self.drawCAM1.clicked.connect(self.startDrawAreaCAM1) self.removeCAM1.clicked.connect(self.removeAreaCAM1) self.drawCAM2.clicked.connect(self.startDrawAreaCAM2) self.removeCAM2.clicked.connect(self.removeAreaCAM2) self.drawCAM3.clicked.connect(self.startDrawAreaCAM3) self.removeCAM3.clicked.connect(self.removeAreaCAM3) self.retranslateUi(Form) self.tabWidget.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(Form) # All function # Function retranslateUI def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "Form")) self.CAM1.setText(_translate("Form", "IP CAM 1")) self.startCAM1.setText(_translate("Form", "Start")) self.carProtectionCAM1.setText(_translate("Form", "Car protection")) self.monitorAreaCAM1.setText( _translate("Form", "Monitor prohibited area")) self.stopCAM1.setText(_translate("Form", "Stop")) self.personSearchingCAM1.setText(_translate("Form", "Person searching")) self.illegalCAM1.setText(_translate("Form", "Illegal access action")) self.CAM2.setText(_translate("Form", "IP CAM 2")) self.startCAM2.setText(_translate("Form", "Start")) self.carProtectionCAM2.setText(_translate("Form", "Car protection")) self.monitorAreaCAM2.setText( _translate("Form", "Monitor prohibited area")) self.stopCAM2.setText(_translate("Form", "Stop")) self.personSearchingCAM2.setText(_translate("Form", "Person searching")) self.illegalCAM2.setText(_translate("Form", "Illegal access action")) self.CAM3.setText(_translate("Form", "IP CAM 3")) self.startCAM3.setText(_translate("Form", "Start")) self.carProtectionCAM3.setText(_translate("Form", "Car protection")) self.monitorAreaCAM3.setText( _translate("Form", "Monitor prohibited area")) self.stopCAM3.setText(_translate("Form", "Stop")) self.personSearchingCAM3.setText(_translate("Form", "Person searching")) self.illegalCAM3.setText(_translate("Form", "Illegal access action")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("Form", "3 IP CAMs")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("Form", "PLAY RECORD")) self.CAM1_draw.setText(_translate("Form", "TextLabel")) self.drawCAM1.setText(_translate("Form", "Draw")) self.removeCAM1.setText(_translate("Form", "Clear")) self.CAM2_draw.setText(_translate("Form", "TextLabel")) self.drawCAM2.setText(_translate("Form", "Draw")) self.removeCAM2.setText(_translate("Form", "Clear")) self.CAM3_draw.setText(_translate("Form", "TextLabel")) self.drawCAM3.setText(_translate("Form", "Draw")) self.removeCAM3.setText(_translate("Form", "Clear")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("Form", "SETTING")) # Function for media player def open_file(self): filename, _ = QFileDialog.getOpenFileName(self, "Open Video") if filename != '': self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(filename))) self.playBtn.setEnabled(True) def play_video(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def stop_video(self): self.mediaPlayer.stop() def mediastate_changed(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.playBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) def position_changed(self, position): self.slider.setValue(position) def duration_changed(self, duration): self.slider.setRange(0, duration) def set_position(self, position): self.mediaPlayer.setPosition(position) print(position) def set_volume(self, volume): self.mediaPlayer.setVolume(volume) def mute(self): if not self.mediaPlayer.isMuted(): self.mediaPlayer.setMuted(True) self.volumeBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaVolumeMuted)) else: self.mediaPlayer.setMuted(False) self.volumeBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume)) def handle_errors(self): self.playBtn.setEnabled(False) self.label.setText("Error: " + self.mediaPlayer.errorString()) self.startCAM1.clicked.connect(self.start) self.stopCAM1.clicked.connect(self.stop) def fullscreen(self): if self.windowState() & Qt.WindowFullScreen: QApplication.setOverrideCursor(Qt.ArrowCursor) self.showNormal() print("no Fullscreen") else: Form.showFullScreen() QApplication.setOverrideCursor(Qt.BlankCursor) print("Fullscreen entered") def fast(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() + 10 * 60) def slow(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() - 10 * 60) # Function for image processing def image_to_QImage(self, image, label: QLabel): image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) image = cv2.resize(image, (label.width(), label.height())) height, width, channel = image.shape step = channel * width return QImage(image.data, width, height, step, QImage.Format_RGB888) def start_view1(self): self.stopCAM1.setEnabled(True) self.startCAM1.setEnabled(False) self.vs1 = VideoStream(src=IP_CAM_ADDRESS['CAM1']) self.flag_CAM1 = self.vs1.flag if self.vs1.flag: self.vs1.start() now = datetime.now() self.savePath1 = self.createDir('IP_CAM_1') self.startTime1 = str(now.day) + ' - ' + str(now.hour) + 'h' + str( now.minute) + ' - ' fourcc = cv2.VideoWriter_fourcc(*'XVID') self.outVivdeo = cv2.VideoWriter( self.savePath1 + 'output.avi', fourcc, 30, (int(self.vs1.stream.get(3)), int(self.vs1.stream.get(4)))) self.timer.start(20) else: self.startCAM1.setEnabled(True) self.stopCAM1.setEnabled(False) image = cv2.imread('no-connection.jpg') self.CAM1.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM1))) def viewCam1(self): image = self.vs1.read() self.outVivdeo.write(image) self.CAM1.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM1))) if self.feature['mpa1'] and self.monitorAreaCAM1.isChecked(): image, self.numWarning = detectObject(image, self.points_CAM1, flag_Warning=1, numWarning=self.numWarning) self.CAM1_draw.setPixmap( QPixmap.fromImage( self.image_to_QImage( self.drawArea(image, self.points_CAM1, self.CAM1_draw), self.CAM1_draw))) def stop_view1(self): self.startCAM1.setEnabled(True) self.stopCAM1.setEnabled(False) self.timer.stop() self.vs1.stop() image = cv2.imread('stopVideo.png') self.CAM1.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM1))) now = datetime.now() fileName = self.startTime1 + str(now.hour) + 'h' + str( now.minute) + '.avi' os.rename(self.savePath1 + 'output.avi', self.savePath1 + fileName) def start_view2(self): self.stopCAM2.setEnabled(True) self.startCAM2.setEnabled(False) self.vs2 = VideoStream(src=IP_CAM_ADDRESS['CAM2']) print('ok') if self.vs2.flag: self.vs2.start() now = datetime.now() self.savePath2 = self.createDir('IP_CAM_2') self.startTime2 = str(now.day) + ' - ' + str(now.hour) + 'h' + str( now.minute) + ' - ' fourcc = cv2.VideoWriter_fourcc(*'XVID') self.outVivdeo2 = cv2.VideoWriter( self.savePath2 + 'output2.avi', fourcc, 30, (int(self.vs2.stream.get(3)), int(self.vs2.stream.get(4)))) self.timer2.start(20) else: self.startCAM2.setEnabled(True) self.stopCAM2.setEnabled(False) image = cv2.imread('no-connection.jpg') self.CAM2.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM2))) def viewCam2(self): image = self.vs2.read() self.outVivdeo2.write(image) self.CAM2.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM2))) def stop_view2(self): self.startCAM2.setEnabled(True) self.stopCAM2.setEnabled(False) self.timer2.stop() self.vs2.stop() image = cv2.imread('stopVideo.png') self.CAM2.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM2))) now = datetime.now() fileName = self.startTime2 + str(now.hour) + 'h' + str( now.minute) + '.avi' os.rename(self.savePath2 + 'output2.avi', self.savePath2 + fileName) # def viewCam(self): # # while True: # ret, image = self.cap.read() # self.outVivdeo.write(image) # self.CAM1.setPixmap(QPixmap.fromImage(self.image_to_QImage(image, self.CAM1))) # if self.feature['mpa1'] and self.monitorAreaCAM1.isChecked(): # image, self.numWarning = detectObject(image, self.points_CAM1, flag_Warning=1, numWarning=self.numWarning) # self.CAM1_draw.setPixmap(QPixmap.fromImage(self.image_to_QImage(self.drawArea(image, self.points_CAM1, self.CAM1_draw), self.CAM1_draw))) # def start_view(self): # self.stopCAM1.setEnabled(True) # self.startCAM1.setEnabled(False) # self.cap = cv2.VideoCapture(IP_CAM_ADDRESS['CAM1']) # self.flag_CAM1 = self.cap.isOpened() # if self.cap.isOpened(): # now = datetime.now() # self.savePath1 = self.createDir('IP_CAM_1') # self.startTime1 = str(now.day)+' - '+str(now.hour)+'h'+str(now.minute)+ ' - ' # fourcc = cv2.VideoWriter_fourcc(*'XVID') # self.outVivdeo = cv2.VideoWriter(self.savePath1+'output.avi', fourcc, 30, (int(self.cap.get(3)), int(self.cap.get(4)))) # self.timer.start(0) # else: # self.startCAM1.setEnabled(True) # self.stopCAM1.setEnabled(False) # image = cv2.imread('no-connection.jpg') # self.CAM1.setPixmap(QPixmap.fromImage(self.image_to_QImage(image, self.CAM1))) # def stop_view(self): # self.startCAM1.setEnabled(True) # self.stopCAM1.setEnabled(False) # self.timer.stop() # self.cap.release() # self.outVivdeo.release() # print("ok") # image = cv2.imread('stopVideo.png') # self.CAM1.setPixmap(QPixmap.fromImage(self.image_to_QImage(image, self.CAM1))) # print('ok2') # now = datetime.now() # fileName = self.startTime1+str(now.hour)+'h'+str(now.minute)+'.avi' # os.rename(self.savePath1+'output.avi', self.savePath1+fileName) # def viewCam2(self): # ret, image = self.cap2.read() # self.outVivdeo2.write(image) # self.CAM2_draw.setPixmap(QPixmap.fromImage(self.image_to_QImage(self.drawArea(image, self.points_CAM2, self.CAM2_draw), self.CAM2_draw))) # self.CAM2.setPixmap(QPixmap.fromImage(self.image_to_QImage(image, self.CAM2))) # def start_view2(self): # if not self.timer2.isActive(): # self.stopCAM2.setEnabled(True) # self.startCAM2.setEnabled(False) # self.cap2 = cv2.VideoCapture(IP_CAM_ADDRESS['CAM2']) # self.flag_CAM2 = self.cap2.isOpened() # if self.cap2.isOpened(): # now = datetime.now() # self.savePath2 = self.createDir('IP_CAM_2') # self.startTime2 = str(now.day)+' - '+str(now.hour)+'h'+str(now.minute)+ ' - ' # # fourcc = cv2.VideoWriter_fourcc(*'mp4v') # fourcc = cv2.VideoWriter_fourcc(*'XVID') # self.outVivdeo2 = cv2.VideoWriter(self.savePath2+'output2.avi', fourcc, 30, (int(self.cap2.get(3)), int(self.cap2.get(4)))) # self.timer2.start(0) # else: # self.startCAM2.setEnabled(True) # self.stopCAM2.setEnabled(False) # image = cv2.imread('no-connection.jpg') # self.CAM2.setPixmap(QPixmap.fromImage(self.image_to_QImage(image, self.CAM2))) # def stop_view2(self): # self.startCAM2.setEnabled(True) # self.stopCAM2.setEnabled(False) # self.timer2.stop() # self.outVivdeo2.release() # image = cv2.imread('stopVideo.png') # self.CAM2.setPixmap(QPixmap.fromImage(self.image_to_QImage(image, self.CAM2))) # self.cap2.release() # now = datetime.now() # fileName = self.startTime2+str(now.hour)+'h'+str(now.minute)+'.avi' # os.rename(self.savePath2+'output2.avi', self.savePath2+fileName) def viewCam3(self): ret, image = self.cap3.read() self.outVivdeo3.write(image) self.CAM3_draw.setPixmap( QPixmap.fromImage( self.image_to_QImage( self.drawArea(image, self.points_CAM3, self.CAM3_draw), self.CAM3_draw))) self.CAM3.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM3))) def start_view3(self): if not self.timer3.isActive(): self.stopCAM3.setEnabled(True) self.startCAM3.setEnabled(False) self.cap3 = cv2.VideoCapture(IP_CAM_ADDRESS['CAM3']) self.flag_CAM3 = self.cap3.isOpened() if self.cap3.isOpened(): now = datetime.now() self.savePath3 = self.createDir('IP_CAM_3') self.startTime3 = str(now.day) + ' - ' + str( now.hour) + 'h' + str(now.minute) + ' - ' # fourcc = cv2.VideoWriter_fourcc(*'mp4v') fourcc = cv2.VideoWriter_fourcc(*'XVID') self.outVivdeo3 = cv2.VideoWriter( self.savePath3 + 'output3.avi', fourcc, 30, (int(self.cap3.get(3)), int(self.cap3.get(4)))) self.timer3.start(0) else: self.startCAM3.setEnabled(True) self.stopCAM3.setEnabled(False) image = cv2.imread('no-connection.jpg') self.CAM3.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM3))) def stop_view3(self): self.startCAM3.setEnabled(True) self.stopCAM3.setEnabled(False) self.timer3.stop() self.outVivdeo3.release() image = cv2.imread('stopVideo.png') self.CAM3.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM3))) self.cap3.release() now = datetime.now() fileName = self.startTime3 + str(now.hour) + 'h' + str( now.minute) + '.avi' os.rename(self.savePath3 + 'output3.avi', self.savePath3 + fileName) def createDir(self, IP_CAM_Number: str): now = datetime.now() year = now.year month = MONTH[now.month] curPath = os.getcwd() if not path.exists(curPath + '/IVA'): os.mkdir(curPath + '/IVA') if not path.exists(curPath + '/IVA/' + IP_CAM_Number): os.mkdir(curPath + '/IVA/' + IP_CAM_Number) # check path exists if path.exists(curPath + '/IVA/' + IP_CAM_Number + '/' + str(year)): if path.exists(curPath + '/IVA/' + IP_CAM_Number + '/' + str(year) + '/' + month): return curPath + '/IVA/' + IP_CAM_Number + '/' + str( year) + '/' + month + '/' else: os.mkdir(curPath + '/IVA/' + IP_CAM_Number + '/' + str(year) + '/' + month) return curPath + '/IVA/' + IP_CAM_Number + '/' + str( year) + '/' + month + '/' else: os.mkdir(curPath + '/IVA/' + IP_CAM_Number + '/' + str(year)) if path.exists(curPath + '/IVA/' + IP_CAM_Number + '/' + str(year) + '/' + month): return curPath + '/IVA/' + IP_CAM_Number + '/' + str( year) + '/' + month + '/' else: os.mkdir(curPath + '/IVA/' + IP_CAM_Number + '/' + str(year) + '/' + month) return curPath + '/IVA/' + IP_CAM_Number + '/' + str( year) + '/' + month + '/' # Create Mouse Event for draw protected area def mouseEventCAM1(self, event): if self.removeCAM1.isEnabled() and ( not self.startCAM1.isEnabled()) and self.flag_CAM1 == True: # print(self.CAM1_draw.width(), self.CAM1_draw.height()) x = event.pos().x() y = event.pos().y() print(x, y) x = round((x / self.CAM1_draw.width()), 10) y = round((y / self.CAM1_draw.height()), 10) self.points_CAM1.append([x, y]) print("Position clicked is ({}, {})".format( int(x * self.CAM1_draw.width()), int(y * self.CAM1_draw.height()))) # print(self.points_CAM1) def mouseEventCAM2(self, event): if self.removeCAM2.isEnabled() and ( not self.startCAM2.isEnabled()) and self.flag_CAM2 == True: x = event.pos().x() y = event.pos().y() self.points_CAM2.append([x, y]) print("Position clicked is ({}, {})".format(x, y)) def mouseEventCAM3(self, event): if self.removeCAM3.isEnabled() and ( not self.startCAM3.isEnabled()) and self.flag_CAM3 == True: x = event.pos().x() y = event.pos().y() self.points_CAM3.append([x, y]) print("Position clicked is ({}, {})".format(x, y)) def startDrawAreaCAM1(self): self.drawCAM1.setEnabled(False) self.removeCAM1.setEnabled(True) def removeAreaCAM1(self): while len(self.points_CAM1): self.points_CAM1.pop() self.drawCAM1.setEnabled(True) self.removeCAM1.setEnabled(False) def startDrawAreaCAM2(self): self.drawCAM2.setEnabled(False) self.removeCAM2.setEnabled(True) def removeAreaCAM2(self): while len(self.points_CAM2): self.points_CAM2.pop() self.drawCAM2.setEnabled(True) self.removeCAM2.setEnabled(False) def startDrawAreaCAM3(self): self.drawCAM3.setEnabled(False) self.removeCAM3.setEnabled(True) def removeAreaCAM3(self): while len(self.points_CAM3): self.points_CAM3.pop() self.drawCAM3.setEnabled(True) self.removeCAM3.setEnabled(False) def drawArea(self, image, points: list, qlabel: QtWidgets.QLabel): image_draw = image.copy() (width, height) = image.shape[:2] image_draw = cv2.resize(image_draw, (qlabel.width(), qlabel.height())) if len(points) > 1: point1 = [] for point in points: x = int(point[0] * qlabel.width()) y = int(point[1] * qlabel.height()) point1.append((x, y)) cv2.polylines(image_draw, np.array([point1]), 1, (255, 0, 0), 1) b, g, r = cv2.split(image_draw) cv2.fillPoly(b, np.array([point1]), (0, 255, 0)) cv2.fillPoly(r, np.array([point1]), (0, 255, 0)) image_draw = cv2.merge([b, g, r]) return image_draw # Function for IVA tasks def monitorProhibitedArea(self, frame, points: list, flag_Warning: int): pass
class MainWindow(QMainWindow): def __init__(self, app): super(MainWindow, self).__init__() self.app = app print('window created') self.setWindowIcon(QIcon('img/icon.png')) self.setWindowTitle('Kasino') self.setPalette(QPalette(Qt.darkGreen)) self.setup_music() self.statusbar = QStatusBar(self) self.statusbar.setStyleSheet('background: white') self.setStatusBar(self.statusbar) self.statusbar.showMessage('Welcome to the Cassino game!') self.menubar = QMenuBar(self) self.optionsMenu = self.menubar.addMenu('Options') self.music_toggle = QAction() self.music_toggle.setText('Music') self.music_toggle.setShortcut('Ctrl+m') self.music_toggle.setCheckable(True) self.music_toggle.setChecked(True) self.optionsMenu.addAction(self.music_toggle) self.music_toggle.triggered.connect(self.toggle_music) self.speedGroup = QActionGroup(self) self.speedGroup.triggered.connect(self.set_speed) self.slow_speed = QAction('Slow', self.speedGroup) self.slow_speed.setCheckable(True) self.normal_speed = QAction('Normal', self.speedGroup) self.normal_speed.setCheckable(True) self.fast_speed = QAction('Fast', self.speedGroup) self.fast_speed.setCheckable(True) self.vfast_speed = QAction('Very Fast', self.speedGroup) self.vfast_speed.setCheckable(True) self.normal_speed.setChecked(True) self.speed_menu = self.optionsMenu.addMenu('Speed') self.speed_menu.addActions(self.speedGroup.actions()) self.menubar.setMouseTracking(False) self.setMenuBar(self.menubar) self.play_widget = PlayWidget(self) self.main_menu = MainMenu(self) self.start_menu = StartMenu(self) self.widgets = QStackedWidget(self) self.widgets.addWidget(self.play_widget) self.widgets.addWidget(self.main_menu) self.widgets.addWidget(self.start_menu) self.widgets.setCurrentWidget(self.main_menu) self.setCentralWidget(self.widgets) self.setGeometry(25, 50, 1028, 720) self.main_menu.startbutton.clicked.connect(self.init_game) self.main_menu.loadbutton.clicked.connect(self.load_game) self.main_menu.quitbutton.clicked.connect(self.quit) self.play_widget.quit_button.clicked.connect(self.quit_to_menu) self.play_widget.save_button.clicked.connect(self.save_game) self.start_menu.startbutton.clicked.connect(self.start_game) def setup_music(self): self.music = QMediaPlayer() self.playlist = QMediaPlaylist() self.playlist.setPlaybackMode(QMediaPlaylist.Loop) file_name = "sound/bg.mp3" self.media = QMediaContent(QUrl.fromLocalFile(file_name)) self.playlist.addMedia(self.media) self.music.setPlaylist(self.playlist) self.music.setVolume(20) self.music.play() def toggle_music(self): if self.music.isMuted(): self.music.setMuted(False) self.statusbar.showMessage('Music on', 5000) else: self.music.setMuted(True) self.statusbar.showMessage('Music off', 5000) def set_speed(self, action): if action == self.slow_speed: self.play_widget.speed = 1 elif action == self.normal_speed: self.play_widget.speed = 3 elif action == self.fast_speed: self.play_widget.speed = 4 else: self.play_widget.speed = 6 def start_game(self): self.play_widget.init_game( self.start_menu.extract_info_and_init_game()) self.widgets.setCurrentWidget(self.play_widget) self.statusbar.showMessage('Game launched', 2000) def load_game(self): path = QFileDialog.getOpenFileName(self, 'Open save file', QDir.currentPath() + '/sav')[0] if path != '': game, msg, count = load(path) self.play_widget.resume_from_save(game, msg, count) self.widgets.setCurrentWidget(self.play_widget) self.statusbar.showMessage('Loaded save file', 5000) def save_game(self): path = QFileDialog.getSaveFileName(self, 'Create save file', QDir.currentPath() + '/sav')[0] if path != '': save(path, self.play_widget.game, self.play_widget.export_log(), self.play_widget.move_count) self.statusbar.showMessage('Game saved', 5000) def init_game(self): self.widgets.setCurrentWidget(self.start_menu) self.statusbar.showMessage('Starting new game') def quit_to_menu(self): #Reset playwidget self.widgets.removeWidget(self.play_widget) speed = self.play_widget.speed self.play_widget.setParent(None) self.play_widget = PlayWidget(self) self.play_widget.speed = speed self.widgets.addWidget(self.play_widget) self.play_widget.quit_button.clicked.connect(self.quit_to_menu) self.play_widget.save_button.clicked.connect(self.save_game) self.widgets.setCurrentWidget(self.main_menu) def closeEvent(self, *args, **kwargs): #for handling closing from 'x' button self.quit() def quit(self): print('Exited game. Thanks for playing!\n') self.app.exit()
class Ui_Form(QWidget): def __init__(self): super().__init__() self.points_CAM1 = [] self.points_CAM2 = [] self.points_CAM3 = [] def setupUi(self, Form): Form.setObjectName("Form") self.tabWidget = QtWidgets.QTabWidget(Form) self.tabWidget.setObjectName("tabWidget") self.multiTab = QtWidgets.QWidget() self.multiTab.setObjectName("multiTab") # cam1 self.cam_1 = QtWidgets.QWidget(self.multiTab) self.cam_1.setObjectName("cam_1") self.CAM1 = QtWidgets.QLabel(self.cam_1) self.CAM1.setFrameShape(QtWidgets.QFrame.Box) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.CAM1.sizePolicy().hasHeightForWidth()) self.CAM1.setSizePolicy(sizePolicy) self.CAM1.setMinimumSize(QtCore.QSize(320, 240)) self.CAM1.setMaximumSize(QtCore.QSize(400, 320)) self.CAM1.setSizeIncrement(QtCore.QSize(3, 2)) self.CAM1.setScaledContents(True) self.CAM1.setObjectName("CAM1") self.startCAM1 = QtWidgets.QPushButton(self.cam_1) self.startCAM1.setObjectName("startCAM1") self.stopCAM1 = QtWidgets.QPushButton(self.cam_1) self.stopCAM1.setObjectName("stopCAM1") self.reIDBtn_1 = QtWidgets.QPushButton(self.cam_1) self.reIDBtn_1.setObjectName("reIDBtn_1") self.falldetectionBtn_1 = QtWidgets.QPushButton(self.cam_1) self.falldetectionBtn_1.setObjectName("falldetectionBtn_1") self.peoplecntBtn_1 = QtWidgets.QPushButton(self.cam_1) self.peoplecntBtn_1.setObjectName("peoplecntBtn_1") self.areaprotectionBtn_1 = QtWidgets.QPushButton(self.cam_1) self.areaprotectionBtn_1.setObjectName("areaprotectionBtn_1") layoutCam_1 = QGridLayout(self.cam_1) layoutCam_1.addWidget(self.CAM1, 0, 0, 7, 3) layoutCam_1.addWidget(self.startCAM1, 8, 0) layoutCam_1.addWidget(self.stopCAM1, 9, 0) layoutCam_1.addWidget(self.reIDBtn_1, 8, 1) layoutCam_1.addWidget(self.falldetectionBtn_1, 8, 2) layoutCam_1.addWidget(self.peoplecntBtn_1, 9, 1) layoutCam_1.addWidget(self.areaprotectionBtn_1, 9, 2) self.cam_1.setLayout(layoutCam_1) # Setting Multi_tab Cam 2 self.cam_2 = QtWidgets.QWidget(self.multiTab) self.cam_2.setObjectName("cam_2") self.CAM2 = QtWidgets.QLabel(self.cam_2) self.CAM2.setFrameShape(QtWidgets.QFrame.Box) self.CAM2.setSizePolicy(sizePolicy) self.CAM2.setMinimumSize(QtCore.QSize(320, 240)) self.CAM2.setMaximumSize(QtCore.QSize(400, 320)) self.CAM2.setSizeIncrement(QtCore.QSize(3, 2)) self.CAM2.setObjectName("CAM2") self.CAM2.setScaledContents(True) self.peoplecntBtn_2 = QtWidgets.QPushButton(self.cam_2) self.peoplecntBtn_2.setObjectName("peoplecntBtn_2") self.falldetectionBtn_2 = QtWidgets.QPushButton(self.cam_2) self.falldetectionBtn_2.setObjectName("falldetectionBtn_2") self.reIDBtn_2 = QtWidgets.QPushButton(self.cam_2) self.reIDBtn_2.setObjectName("reIDBtn_2") self.stop_CAM2 = QtWidgets.QPushButton(self.cam_2) self.stop_CAM2.setObjectName("stop_CAM2") self.start_CAM2 = QtWidgets.QPushButton(self.cam_2) self.start_CAM2.setObjectName("start_CAM2") self.areaprotectionBtn_2 = QtWidgets.QPushButton(self.cam_2) self.areaprotectionBtn_2.setObjectName("areaprotectionBtn_2") layoutCam_2 = QGridLayout(self.cam_2) layoutCam_2.addWidget(self.CAM2, 0, 0, 7, 3) layoutCam_2.addWidget(self.start_CAM2, 8, 0) layoutCam_2.addWidget(self.stop_CAM2, 9, 0) layoutCam_2.addWidget(self.reIDBtn_2, 8, 1) layoutCam_2.addWidget(self.falldetectionBtn_2, 8, 2) layoutCam_2.addWidget(self.peoplecntBtn_2, 9, 1) layoutCam_2.addWidget(self.areaprotectionBtn_2, 9, 2) self.cam_2.setLayout(layoutCam_2) # Setting Multi_tab Cam 3 self.cam_3 = QtWidgets.QWidget(self.multiTab) self.cam_3.setObjectName("cam_3") self.CAM3 = QtWidgets.QLabel(self.cam_3) self.CAM3.setFrameShape(QtWidgets.QFrame.Box) self.CAM3.setSizePolicy(sizePolicy) self.CAM3.setMinimumSize(QtCore.QSize(320, 240)) self.CAM3.setMaximumSize(QtCore.QSize(400, 320)) self.CAM3.setSizeIncrement(QtCore.QSize(3, 2)) self.CAM3.setObjectName("CAM3") self.CAM3.setScaledContents(True) self.peoplecntBtn_3 = QtWidgets.QPushButton(self.cam_3) self.peoplecntBtn_3.setObjectName("peoplecntBtn_3") self.falldetectionBtn_3 = QtWidgets.QPushButton(self.cam_3) self.falldetectionBtn_3.setObjectName("falldetectionBtn_3") self.reIDBtn_3 = QtWidgets.QPushButton(self.cam_3) self.reIDBtn_3.setObjectName("reIDBtn_3") self.stop_CAM3 = QtWidgets.QPushButton(self.cam_3) self.stop_CAM3.setObjectName("stop_CAM3") self.start_CAM3 = QtWidgets.QPushButton(self.cam_3) self.start_CAM3.setObjectName("start_CAM3") self.areaprotectionBtn_3 = QtWidgets.QPushButton(self.cam_3) self.areaprotectionBtn_3.setObjectName("areaprotectionBtn_3") layoutCam_3 = QGridLayout(self.cam_3) layoutCam_3.addWidget(self.CAM3, 0, 0, 7, 3) layoutCam_3.addWidget(self.start_CAM3, 8, 0) layoutCam_3.addWidget(self.stop_CAM3, 9, 0) layoutCam_3.addWidget(self.reIDBtn_3, 8, 1) layoutCam_3.addWidget(self.falldetectionBtn_3, 8, 2) layoutCam_3.addWidget(self.peoplecntBtn_3, 9, 1) layoutCam_3.addWidget(self.areaprotectionBtn_3, 9, 2) self.cam_3.setLayout(layoutCam_3) # Setting layout multi_tab layoutMultitab = QGridLayout(self.multiTab) layoutMultitab.addWidget(self.cam_1, 0, 0) layoutMultitab.addWidget(self.cam_2, 0, 1) layoutMultitab.addWidget(self.cam_3, 0, 2) self.multiTab.setLayout(layoutMultitab) self.tabWidget.addTab(self.multiTab, "") # Media Player self.playRec = QtWidgets.QWidget() self.playRec.setObjectName("playRec") self.tabWidget.addTab(self.playRec, "") self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) videowidget = QVideoWidget() self.openBtn = QtWidgets.QPushButton('Open Video') self.playBtn = QtWidgets.QPushButton() self.playBtn.setEnabled(False) self.playBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.stopBtn = QtWidgets.QPushButton() self.stopBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaStop)) self.slowBtn = QtWidgets.QPushButton() self.slowBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaSeekBackward)) self.fastBtn = QtWidgets.QPushButton() self.fastBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaSeekForward)) self.volumeBtn = QtWidgets.QPushButton() self.volumeBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume)) self.fullscreenBtn = QPushButton("Full Screen") self.slider = QSlider(Qt.Horizontal) self.slider.setRange(0, 0) self.volume_slider = QSlider(Qt.Horizontal) self.volume_slider.setRange(0, 100) self.volume_slider.setValue(100) self.label_2_1 = QLabel() self.label_2_1.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) self.label_2_2 = QLabel() hboxLayout_2_1 = QHBoxLayout() hboxLayout_2_2 = QHBoxLayout() hboxLayout_2_3 = QHBoxLayout() hboxLayout_2_1.addWidget(self.slider) hboxLayout_2_2.addWidget(self.openBtn) hboxLayout_2_2.addWidget(self.stopBtn) hboxLayout_2_2.addWidget(self.slowBtn) hboxLayout_2_2.addWidget(self.playBtn) hboxLayout_2_2.addWidget(self.fastBtn) hboxLayout_2_2.addWidget(self.volumeBtn) hboxLayout_2_2.addWidget(self.volume_slider) hboxLayout_2_2.addStretch(1) hboxLayout_2_2.addWidget(self.fullscreenBtn) hboxLayout_2_3.addWidget(videowidget) vboxLayout_2_1 = QVBoxLayout() vboxLayout_2_1.addLayout(hboxLayout_2_3) vboxLayout_2_1.addLayout(hboxLayout_2_1) vboxLayout_2_1.addLayout(hboxLayout_2_2) vboxLayout_2_1.addWidget(self.label_2_1) self.playRec.setLayout(vboxLayout_2_1) #Tab Setting self.setting = QtWidgets.QWidget() self.setting.setObjectName("setting") self.tabWidget.addTab(self.setting, "") # Cam 1 self.camSetting_1 = QtWidgets.QWidget(self.setting) self.camSetting_1.setObjectName("camSetting_1") self.CAM1_Draw = QtWidgets.QLabel(self.camSetting_1) self.CAM1_Draw.setFrameShape(QtWidgets.QFrame.Box) self.CAM1_Draw.setSizePolicy(sizePolicy) self.CAM1_Draw.setMinimumSize(QtCore.QSize(320, 240)) self.CAM1_Draw.setMaximumSize(QtCore.QSize(400, 320)) self.CAM1_Draw.setSizeIncrement(QtCore.QSize(3, 2)) self.CAM1_Draw.setObjectName("CAM1_Draw") self.draw_CAM1 = QtWidgets.QPushButton(self.camSetting_1) self.draw_CAM1.setObjectName("draw_CAM1") self.remove_CAM1 = QtWidgets.QPushButton(self.camSetting_1) self.remove_CAM1.setObjectName("remove_CAM1") layoutCamSetting_1 = QGridLayout() layoutCamSetting_1.addWidget(self.CAM1_Draw, 0, 0, 7, 4) layoutCamSetting_1.addWidget(self.draw_CAM1, 8, 1) layoutCamSetting_1.addWidget(self.remove_CAM1, 8, 2) self.camSetting_1.setLayout(layoutCamSetting_1) #camSetting 2 self.camSetting_2 = QtWidgets.QWidget(self.setting) self.camSetting_2.setObjectName("camSetting_2") self.CAM2_Draw = QtWidgets.QLabel(self.camSetting_2) self.CAM2_Draw.setFrameShape(QtWidgets.QFrame.Box) self.CAM2_Draw.setSizePolicy(sizePolicy) self.CAM2_Draw.setMinimumSize(QtCore.QSize(320, 240)) self.CAM2_Draw.setMaximumSize(QtCore.QSize(400, 320)) self.CAM2_Draw.setSizeIncrement(QtCore.QSize(3, 2)) self.CAM2_Draw.setObjectName("CAM2_Draw") self.draw_CAM2 = QtWidgets.QPushButton(self.camSetting_2) self.draw_CAM2.setObjectName("draw_CAM2") self.remove_CAM2 = QtWidgets.QPushButton(self.camSetting_2) self.remove_CAM2.setObjectName("remove_CAM2") layoutCamSetting_2 = QGridLayout() layoutCamSetting_2.addWidget(self.CAM2_Draw, 0, 0, 7, 4) layoutCamSetting_2.addWidget(self.draw_CAM2, 8, 1) layoutCamSetting_2.addWidget(self.remove_CAM2, 8, 2) self.camSetting_2.setLayout(layoutCamSetting_2) #camSeting 3 self.camSetting_3 = QtWidgets.QWidget(self.setting) self.camSetting_3.setObjectName("camSetting_3") self.CAM3_Draw = QtWidgets.QLabel(self.camSetting_3) self.CAM3_Draw.setFrameShape(QtWidgets.QFrame.Box) self.CAM3_Draw.setSizePolicy(sizePolicy) self.CAM3_Draw.setMinimumSize(QtCore.QSize(320, 240)) self.CAM3_Draw.setMaximumSize(QtCore.QSize(400, 320)) self.CAM3_Draw.setSizeIncrement(QtCore.QSize(3, 2)) self.CAM3_Draw.setObjectName("CAM3_Draw") self.draw_CAM3 = QtWidgets.QPushButton(self.camSetting_3) self.draw_CAM3.setObjectName("draw_CAM3") self.remove_CAM3 = QtWidgets.QPushButton(self.camSetting_3) self.remove_CAM3.setObjectName("remove_CAM3") layoutCamSetting_3 = QGridLayout() layoutCamSetting_3.addWidget(self.CAM3_Draw, 0, 0, 7, 4) layoutCamSetting_3.addWidget(self.draw_CAM3, 8, 1) layoutCamSetting_3.addWidget(self.remove_CAM3, 8, 2) self.camSetting_3.setLayout(layoutCamSetting_3) #layout Setting layoutSetting = QGridLayout() layoutSetting.addWidget(self.camSetting_1, 0, 0) layoutSetting.addWidget(self.camSetting_2, 0, 1) layoutSetting.addWidget(self.camSetting_3, 0, 2) self.setting.setLayout(layoutSetting) self.mediaPlayer.setVideoOutput(videowidget) self.openBtn.clicked.connect(self.open_file) self.playBtn.clicked.connect(self.play_video) self.stopBtn.clicked.connect(self.stop_video) self.fastBtn.clicked.connect(self.fast) self.slowBtn.clicked.connect(self.slow) self.volumeBtn.clicked.connect(self.mute) self.fullscreenBtn.clicked.connect(self.fullscreen) self.volume_slider.sliderMoved.connect(self.set_volume) self.slider.sliderMoved.connect(self.set_position) self.mediaPlayer.stateChanged.connect(self.mediastate_changed) self.mediaPlayer.positionChanged.connect(self.position_changed) self.mediaPlayer.durationChanged.connect(self.duration_changed) self.startCAM1.setEnabled(True) self.start_CAM2.setEnabled(True) self.start_CAM3.setEnabled(True) self.stopCAM1.setEnabled(False) self.stop_CAM2.setEnabled(False) self.stop_CAM3.setEnabled(False) # create a timer self.timer = QTimer() self.timer2 = QTimer() self.timer3 = QTimer() # set timer timeout callback function self.timer.timeout.connect(self.viewCam) self.startCAM1.clicked.connect(self.start_view) self.stopCAM1.clicked.connect(self.stop_view) self.timer2.timeout.connect(self.viewCam2) self.start_CAM2.clicked.connect(self.start_view2) self.stop_CAM2.clicked.connect(self.stop_view2) self.timer3.timeout.connect(self.viewCam3) self.start_CAM3.clicked.connect(self.start_view3) self.stop_CAM3.clicked.connect(self.stop_view3) self.CAM1_Draw.mousePressEvent = self.mouseEventCAM1 self.CAM2_Draw.mousePressEvent = self.mouseEventCAM2 self.CAM3_Draw.mousePressEvent = self.mouseEventCAM3 self.draw_CAM1.clicked.connect(self.startDrawAreaCAM1) self.remove_CAM1.clicked.connect(self.removeAreaCAM1) self.draw_CAM2.clicked.connect(self.startDrawAreaCAM2) self.remove_CAM2.clicked.connect(self.removeAreaCAM2) self.draw_CAM3.clicked.connect(self.startDrawAreaCAM3) self.remove_CAM3.clicked.connect(self.removeAreaCAM3) self.retranslateUi(Form) QtCore.QMetaObject.connectSlotsByName(Form) a = QVBoxLayout() a.addWidget(self.tabWidget) Form.setLayout(a) # all function def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "Form")) self.CAM1.setText(_translate("Form", "Cam 1")) self.peoplecntBtn_1.setText(_translate("Form", "People Counting")) self.falldetectionBtn_1.setText(_translate("Form", "Fall Detection")) self.reIDBtn_1.setText(_translate("Form", "Person Re-ID")) self.stopCAM1.setText(_translate("Form", "Stop")) self.startCAM1.setText(_translate("Form", "Start")) self.areaprotectionBtn_1.setText(_translate("Form", "Area Protection")) self.CAM2.setText(_translate("Form", "cam 2")) self.peoplecntBtn_2.setText(_translate("Form", "People Counting")) self.falldetectionBtn_2.setText(_translate("Form", "Fall Detection")) self.reIDBtn_2.setText(_translate("Form", "Person Re-ID")) self.stop_CAM2.setText(_translate("Form", "Stop")) self.start_CAM2.setText(_translate("Form", "Start")) self.areaprotectionBtn_2.setText(_translate("Form", "Area Protection")) self.CAM3.setText(_translate("Form", "cam 3")) self.peoplecntBtn_3.setText(_translate("Form", "People Counting")) self.falldetectionBtn_3.setText(_translate("Form", "Fall Detection")) self.reIDBtn_3.setText(_translate("Form", "Person Re-ID")) self.stop_CAM3.setText(_translate("Form", "Stop")) self.start_CAM3.setText(_translate("Form", "Start")) self.areaprotectionBtn_3.setText(_translate("Form", "Area Protection")) self.CAM1_Draw.setText(_translate("Form", "cam 1")) self.draw_CAM1.setText(_translate("Form", "Draw")) self.remove_CAM1.setText(_translate("Form", "Clean")) self.CAM2_Draw.setText(_translate("Form", "cam 2")) self.draw_CAM2.setText(_translate("Form", "Draw")) self.remove_CAM2.setText(_translate("Form", "Clean")) self.CAM3_Draw.setText(_translate("Form", "cam 3")) self.draw_CAM3.setText(_translate("Form", "Draw")) self.remove_CAM3.setText(_translate("Form", "Clean")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.multiTab), _translate("Form", "Multi_IPCam")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.playRec), _translate("Form", "Play Record")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.setting), _translate("Form", "Setting")) def open_file(self): filename, _ = QFileDialog.getOpenFileName(self, "Open Video") if filename != '': self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(filename))) self.playBtn.setEnabled(True) def play_video(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def stop_video(self): self.mediaPlayer.stop() def mediastate_changed(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.playBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) def position_changed(self, position): self.slider.setValue(position) def duration_changed(self, duration): self.slider.setRange(0, duration) def set_position(self, position): self.mediaPlayer.setPosition(position) print(position) def set_volume(self, volume): self.mediaPlayer.setVolume(volume) def mute(self): if not self.mediaPlayer.isMuted(): self.mediaPlayer.setMuted(True) self.volumeBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaVolumeMuted)) else: self.mediaPlayer.setMuted(False) self.volumeBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume)) def handle_errors(self): self.playBtn.setEnabled(False) self.label.setText("Error: " + self.mediaPlayer.errorString()) self.startCAM1.clicked.connect(self.start) self.stopCAM1.clicked.connect(self.stop) def fullscreen(self): if self.windowState() & Qt.WindowFullScreen: QApplication.setOverrideCursor(Qt.ArrowCursor) self.showNormal() print("no Fullscreen") else: Form.showFullScreen() QApplication.setOverrideCursor(Qt.BlankCursor) print("Fullscreen entered") def fast(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() + 10 * 60) def slow(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() - 10 * 60) def image_to_QImage(self, image, label): # print(label.width(), label.height()) # image = cv2.resize(image, (label.width(), label.height())) image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) height, width, channel = image.shape # print(height, width, channel) step = channel * width return QImage(image.data, width, height, step, QImage.Format_RGB888) def viewCam(self): ret, image = self.cap.read() self.outVivdeo.write(image) self.CAM1_Draw.setPixmap( QPixmap.fromImage( self.image_to_QImage( self.drawArea(image, self.points_CAM1, self.CAM1_Draw), self.CAM1_Draw))) self.CAM1.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM1))) def start_view(self): if not self.timer.isActive(): self.stopCAM1.setEnabled(True) self.startCAM1.setEnabled(False) self.cap = cv2.VideoCapture(IP_CAM_ADDRESS['CAM1']) self.flag_CAM1 = self.cap.isOpened() if self.cap.isOpened(): now = datetime.now() self.savePath1 = self.createDir('IP_CAM_1') self.startTime1 = str(now.day) + ' - ' + str( now.hour) + 'h' + str(now.minute) + ' - ' # fourcc = cv2.VideoWriter_fourcc(*'mp4v') fourcc = cv2.VideoWriter_fourcc(*'XVID') self.outVivdeo = cv2.VideoWriter( self.savePath1 + 'output.avi', fourcc, 30, (int(self.cap.get(3)), int(self.cap.get(4)))) self.timer.start(0) else: self.startCAM1.setEnabled(True) self.stopCAM1.setEnabled(False) image = cv2.imread('no-connection.jpg') self.CAM1.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM1))) def stop_view(self): self.startCAM1.setEnabled(True) self.stopCAM1.setEnabled(False) self.timer.stop() self.cap.release() self.outVivdeo.release() print("ok") image = cv2.imread('stopVideo.png') self.CAM1.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM1))) print('ok2') now = datetime.now() fileName = self.startTime1 + str(now.hour) + 'h' + str( now.minute) + '.avi' os.rename(self.savePath1 + 'output.avi', self.savePath1 + fileName) def viewCam2(self): ret, image = self.cap2.read() self.outVivdeo2.write(image) self.CAM2_Draw.setPixmap( QPixmap.fromImage( self.image_to_QImage( self.drawArea(image, self.points_CAM2, self.CAM2_Draw), self.CAM2_Draw))) self.CAM2.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM2))) def start_view2(self): if not self.timer2.isActive(): self.stop_CAM2.setEnabled(True) self.start_CAM2.setEnabled(False) self.cap2 = cv2.VideoCapture(IP_CAM_ADDRESS['CAM2']) self.flag_CAM2 = self.cap2.isOpened() if self.cap2.isOpened(): now = datetime.now() self.savePath2 = self.createDir('IP_CAM_2') self.startTime2 = str(now.day) + ' - ' + str( now.hour) + 'h' + str(now.minute) + ' - ' # fourcc = cv2.VideoWriter_fourcc(*'mp4v') fourcc = cv2.VideoWriter_fourcc(*'XVID') self.outVivdeo2 = cv2.VideoWriter( self.savePath2 + 'output2.avi', fourcc, 30, (int(self.cap2.get(3)), int(self.cap2.get(4)))) self.timer2.start(0) else: self.start_CAM2.setEnabled(True) self.stop_CAM2.setEnabled(False) image = cv2.imread('no-connection.jpg') self.CAM2.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM2))) def stop_view2(self): self.start_CAM2.setEnabled(True) self.stop_CAM2.setEnabled(False) self.timer2.stop() self.outVivdeo2.release() image = cv2.imread('stopVideo.png') self.CAM2.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM2))) self.cap2.release() now = datetime.now() fileName = self.startTime2 + str(now.hour) + 'h' + str( now.minute) + '.avi' os.rename(self.savePath2 + 'output2.avi', self.savePath2 + fileName) def viewCam3(self): ret, image = self.cap3.read() self.outVivdeo3.write(image) self.CAM3_Draw.setPixmap( QPixmap.fromImage( self.image_to_QImage( self.drawArea(image, self.points_CAM3, self.CAM3_Draw), self.CAM3_Draw))) self.CAM3.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM3))) def start_view3(self): if not self.timer3.isActive(): self.stop_CAM3.setEnabled(True) self.start_CAM3.setEnabled(False) self.cap3 = cv2.VideoCapture(IP_CAM_ADDRESS['CAM3']) self.flag_CAM3 = self.cap3.isOpened() if self.cap3.isOpened(): now = datetime.now() self.savePath3 = self.createDir('IP_CAM_3') self.startTime3 = str(now.day) + ' - ' + str( now.hour) + 'h' + str(now.minute) + ' - ' # fourcc = cv2.VideoWriter_fourcc(*'mp4v') fourcc = cv2.VideoWriter_fourcc(*'XVID') self.outVivdeo3 = cv2.VideoWriter( self.savePath3 + 'output3.avi', fourcc, 30, (int(self.cap3.get(3)), int(self.cap3.get(4)))) self.timer3.start(0) else: self.start_CAM3.setEnabled(True) self.stop_CAM3.setEnabled(False) image = cv2.imread('no-connection.jpg') self.CAM3.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM3))) def stop_view3(self): self.start_CAM3.setEnabled(True) self.stop_CAM3.setEnabled(False) self.timer3.stop() self.outVivdeo3.release() image = cv2.imread('stopVideo.png') self.CAM3.setPixmap( QPixmap.fromImage(self.image_to_QImage(image, self.CAM3))) self.cap3.release() now = datetime.now() fileName = self.startTime3 + str(now.hour) + 'h' + str( now.minute) + '.avi' os.rename(self.savePath3 + 'output3.avi', self.savePath3 + fileName) def createDir(self, IP_CAM_Number: str): now = datetime.now() year = now.year month = MONTH[now.month] curPath = os.getcwd() if not path.exists(curPath + '/IVA'): os.mkdir(curPath + '/IVA') if not path.exists(curPath + '/IVA/' + IP_CAM_Number): os.mkdir(curPath + '/IVA/' + IP_CAM_Number) # check path exists if path.exists(curPath + '/IVA/' + IP_CAM_Number + '/' + str(year)): if path.exists(curPath + '/IVA/' + IP_CAM_Number + '/' + str(year) + '/' + month): return curPath + '/IVA/' + IP_CAM_Number + '/' + str( year) + '/' + month + '/' else: os.mkdir(curPath + '/IVA/' + IP_CAM_Number + '/' + str(year) + '/' + month) return curPath + '/IVA/' + IP_CAM_Number + '/' + str( year) + '/' + month + '/' else: os.mkdir(curPath + '/IVA/' + IP_CAM_Number + '/' + str(year)) if path.exists(curPath + '/IVA/' + IP_CAM_Number + '/' + str(year) + '/' + month): return curPath + '/IVA/' + IP_CAM_Number + '/' + str( year) + '/' + month + '/' else: os.mkdir(curPath + '/IVA/' + IP_CAM_Number + '/' + str(year) + '/' + month) return curPath + '/IVA/' + IP_CAM_Number + '/' + str( year) + '/' + month + '/' # Create Mouse Event for draw protected area def mouseEventCAM1(self, event): if self.remove_CAM1.isEnabled() and ( not self.startCAM1.isEnabled()) and self.flag_CAM1 == True: x = event.pos().x() y = event.pos().y() self.points_CAM1.append([x, y]) print("Position clicked is ({}, {})".format(x, y)) def mouseEventCAM2(self, event): if self.remove_CAM2.isEnabled() and ( not self.start_CAM2.isEnabled()) and self.flag_CAM2 == True: x = event.pos().x() y = event.pos().y() self.points_CAM2.append([x, y]) print("Position clicked is ({}, {})".format(x, y)) def mouseEventCAM3(self, event): if self.remove_CAM3.isEnabled() and ( not self.start_CAM3.isEnabled()) and self.flag_CAM3 == True: x = event.pos().x() y = event.pos().y() self.points_CAM3.append([x, y]) print("Position clicked is ({}, {})".format(x, y)) def startDrawAreaCAM1(self): self.draw_CAM1.setEnabled(False) self.remove_CAM1.setEnabled(True) def removeAreaCAM1(self): while len(self.points_CAM1): self.points_CAM1.pop() self.draw_CAM1.setEnabled(True) self.remove_CAM1.setEnabled(False) def startDrawAreaCAM2(self): self.draw_CAM2.setEnabled(False) self.remove_CAM2.setEnabled(True) def removeAreaCAM2(self): while len(self.points_CAM2): self.points_CAM2.pop() self.draw_CAM2.setEnabled(True) self.remove_CAM2.setEnabled(False) def startDrawAreaCAM3(self): self.draw_CAM3.setEnabled(False) self.remove_CAM3.setEnabled(True) def removeAreaCAM3(self): while len(self.points_CAM3): self.points_CAM3.pop() self.draw_CAM3.setEnabled(True) self.remove_CAM3.setEnabled(False) def drawArea(self, image, points: list, qlabel: QtWidgets.QLabel): image_draw = image.copy() image_draw = cv2.resize(image_draw, (qlabel.width(), qlabel.height())) if len(points) > 1: cv2.polylines(image_draw, np.array([points]), 1, (255, 0, 0), 1) b, g, r = cv2.split(image_draw) cv2.fillPoly(b, np.array([points]), (0, 255, 0)) cv2.fillPoly(r, np.array([points]), (0, 255, 0)) image_draw = cv2.merge([b, g, r]) return image_draw
class Player(QWidget): muted = muted auto_play = auto_play full_screen = full_screen model = Movies session = session def __init__(self): super().__init__() self.setGeometry(0, 0, 1560, 300) from core.view import BaseView self.base_view = BaseView([], self) p = self.palette() p.setColor(QPalette.Window, Qt.black) self.setPalette(p) def run_window(self): self.base_view.set_data(self.id) self.set_setings() self.data = self.base_view.data self.init_ui() self.show() self.setWindowTitle(self.data.name) def set_star(self, stars, id): Star = None for star_array in stars: if star_array.id == id: Star = star_array return Star def set_setings(self): self.save_setings() with open('player_setings.JSON') as setings: data = json.load(setings) self.muted = data['muted'] self.auto_play = data['auto_play'] self.full_screen = data['full_screen'] def save_setings(self): array = { "muted": self.muted, "auto_play": self.auto_play, "full_screen": self.full_screen } json_array = json.dumps(array) if Path('player_setings.JSON').is_file() is False: f = open('player_setings.JSON', "x") f.write(json_array) f.close() def set_player(self): if self.muted: self.mute_clicked() if self.auto_play: self.play_video() if self.full_screen: self.full_screen_switch() def init_ui(self): self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(self.data.src))) videowidget = QVideoWidget() self.playBtn = QPushButton() self.playBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playBtn.clicked.connect(self.play_video) self.slider = QSlider(Qt.Horizontal) self.slider.setRange(0, 0) self.slider.sliderMoved.connect(self.set_position) self.show_full_screen_button = QPushButton('Full Screen') self.show_full_screen_button.clicked.connect(self.full_screen_switch) self.movie_info_button = QPushButton('Movie') self.movie_info_button.clicked.connect(self.movie_info) if self.data.series: self.series_info_button = QPushButton('Series') self.series_info_button.clicked.connect(self.series_info) self.mute = QPushButton() self.mute.setIcon(self.style().standardIcon(QStyle.SP_MediaVolume)) self.mute.clicked.connect(self.mute_clicked) self.label = QLabel() self.label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) hboxLayout = QHBoxLayout() hboxLayout.setContentsMargins(20, 20, 20, 10) hboxLayout.addWidget(self.playBtn) hboxLayout.addWidget(self.slider) hboxLayout.addWidget(self.mute) hboxLayout.addWidget(self.movie_info_button) if self.data.series: hboxLayout.addWidget(self.series_info_button) hboxLayout.addWidget(self.show_full_screen_button) self.set_player() self.hboxLayout2 = QHBoxLayout() self.hboxLayout2.setContentsMargins(10, 10, 10, 10) self.buttons_stars = QButtonGroup() self.buttons_series = QButtonGroup() self.add_grup_movies_buttons() # create vbox layout vboxLayout = QVBoxLayout() vboxLayout.addWidget(videowidget) vboxLayout.addLayout(hboxLayout) vboxLayout.addLayout(self.hboxLayout2) vboxLayout.addWidget(self.label) self.setLayout(vboxLayout) self.mediaPlayer.setVideoOutput(videowidget) # media player signals self.mediaPlayer.stateChanged.connect(self.mediastate_changed) self.mediaPlayer.positionChanged.connect(self.position_changed) self.mediaPlayer.durationChanged.connect(self.duration_changed) def series_info(self): self.base_view.load_view('series', self.data.series[0]) def movie_info(self): self.base_view.load_view('movies', self.data) def buttom_genarator(self, list, fuction, id): for button in list.buttons(): if button is list.button(id): fuction(button.data) def on_movies_series_play(self, id): self.buttom_genarator(self.buttons_series, self.next_series, id) def on_movies_star_play(self, id): self.buttom_genarator(self.buttons_stars, self.next_star, id) def add_grup_movies_buttons(self): self.button_series = [ { 'button': self.on_movies_series_play, 'obejct': self.buttons_series }, ] index = 0 for series in self.data.series: button = QPushButton('next video in series ' + str(series)) self.hboxLayout2.addWidget(button) button.data = series self.button_series[0]['obejct'].addButton(button) self.button_series[0]['obejct'].buttonClicked[int].connect( self.button_series[0]['button']) index = index + 1 self.buttons_star = [ { 'button': self.on_movies_star_play, 'obejct': self.buttons_stars }, ] index = 0 for star in self.data.stars: if len(star.movies) > 3: button = QPushButton('next video with star ' + str(star)) self.hboxLayout2.addWidget(button) button.data = star self.buttons_star[0]['obejct'].addButton(button) self.buttons_star[0]['obejct'].buttonClicked[int].connect( self.buttons_star[0]['button']) index = index + 1 def mute_clicked(self): if self.mediaPlayer.isMuted() is False: icon = QStyle.SP_MediaVolumeMuted self.mediaPlayer.setMuted(True) self.muted = True else: icon = QStyle.SP_MediaVolume self.mediaPlayer.setMuted(False) self.muted = False self.mute.setIcon(self.style().standardIcon(icon)) def next_series(self, series): movies_in_series = self.data.series[0].movies self.close() self.base_view.load_view('play', self.faind_item(movies_in_series)) def next_star(self, star): star = self.set_star(self.data.stars, star.id) movies_with_star = star.movies self.close() self.base_view.load_view('play', self.faind_item(movies_with_star)) def faind_item(self, array): def faind_item_greater_then_actual_item(array, math_index): index_item = 0 for item in array: if index_item > math_index: return index_item elif math_index == len(array) - 1: return 0 index_item = index_item + 1 math_index = '' index_in_array = 0 for item in array: if self.data.id == item.id: math_index = index_in_array index_in_array = index_in_array + 1 next_item = faind_item_greater_then_actual_item(array, math_index) return array[next_item] def full_screen_switch(self): if self.isFullScreen() is False: self.showFullScreen() self.full_screen = True else: self.showNormal() self.full_screen = False def mute_switch(self): self.changeMuting.emit(not self.muted) def play_video(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediastate_changed(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: icon = QStyle.SP_MediaPause else: icon = QStyle.SP_MediaPlay self.playBtn.setIcon(self.style().standardIcon(icon)) def position_changed(self, position): self.slider.setValue(position) def duration_changed(self, duration): self.slider.setRange(0, duration) def set_position(self, position): self.mediaPlayer.setPosition(position) def handle_errors(self): self.playBtn.setEnabled(False) self.label.setText("Error: " + self.mediaPlayer.errorString()) def closeEvent(self, QCloseEvent): os.remove("player_setings.JSON") self.save_setings() self.mediaPlayer.stop()
class InputManager: __instance = None def __init__(self): if not InputManager.__instance: self.ui_manager = UIManager.get_instance() self.radio_stations_manager = RadioStationsManager() self.player = None self.playlist = None self.probe = None self.load_state() if not self.playlist: self.init_state() self.init_signals() def init_signals(self): self.player.durationChanged.connect(self.duration_changed_slot) self.player.positionChanged.connect(self.position_changed_slot) self.player.currentMediaChanged.connect( self.current_media_changed_slot) self.player.stateChanged.connect(self.state_changed_slot) def set_position(self, new_pos): self.ui_manager.set_position_slider_value(new_pos) self.player.setPosition(new_pos) def get_duration(self): return self.player.duration() def get_position(self): return self.player.position() def duration_changed_slot(self, duration): self.ui_manager.set_position_slider_max_value(duration) def position_changed_slot(self, position): self.ui_manager.set_position_slider_value(position) def get_volume(self): return self.player.volume() def set_volume(self, value): self.ui_manager.set_volume_slider_value(value) self.player.setVolume(value) def current_media_changed_slot(self): self.ui_manager.sync_row(self.get_media_position()) def state_changed_slot(self, new_state): if new_state == QMediaPlayer.StoppedState or new_state == QMediaPlayer.PausedState: self.ui_manager.change_play_btn_state(False) else: self.ui_manager.change_play_btn_state(True) def next_media(self): self.playlist.next() def previous_media(self): self.playlist.previous() @classmethod def get_instance(cls, *args, **kwargs): if not cls.__instance: cls.__instance = InputManager(*args, **kwargs) return cls.__instance def init_state(self): self.player = QMediaPlayer() self.playlist = QMediaPlaylist() self.probe = QAudioProbe() self.probe.setSource(self.player) self.probe_connected = False self.timer = QTimer() self.timer.setInterval(100) self.timer.setSingleShot(True) self.recent_files_manager = RecentFilesManager() self.ui_manager.set_output(self.player) self.player.setPlaylist(self.playlist) def load_state(self): file = QFile("file.dat") file.open(QIODevice.ReadOnly) in_stream = QDataStream(file) cur_playlist = QVariant() in_stream >> cur_playlist self.playlist = cur_playlist.value() def get_radio_stations(self, limit=None, category=None): stations = self.radio_stations_manager.get_all_stations( limit, category) return stations def get_radio_categories(self): categories = self.radio_stations_manager.get_all_categories() return categories def save_state(self): file = QFile("file.dat") file.open(QIODevice.WriteOnly) out = QDataStream(file) out << QVariant(self.current_playlist) def add_folder(self, path: str): files = get_dir_files(path) for file in files: self.add_media(path + "/" + file, get_format(file)) def add_file(self, filename: str): format = get_format(filename) if format != FILE_FORMAT.INVALID: return self.add_media(filename, format) raise RuntimeError("Invalid file format") def add_media(self, filename: str, format: FILE_FORMAT): url = QUrl.fromLocalFile( filename) if format != FILE_FORMAT.URL else QUrl(filename) content = QMediaContent(url) self.ui_manager.append_playlist(url.fileName(), format) self.recent_files_manager.write_recent_file(url.path()) self.ui_manager.init_recent_files() self.playlist.addMedia(content) def set_media_position(self, pos): self.playlist.setCurrentIndex(pos) def get_media_position(self): return self.playlist.currentIndex() def get_current_format(self): position = self.get_media_position() if position == -1: return None item = self.ui_manager.get_list_item(self.get_media_position()) return item.data(PlaylistItemDataRole.FORMAT) def play(self): format = self.get_current_format() if format is None: return self.ui_manager.change_play_btn_state(True) if format == FILE_FORMAT.AUDIO: self.probe.audioBufferProbed.connect(self.process_buffer) self.probe_connected = True else: self.probe_connected = False self.ui_manager.show_video() self.player.play() def pause(self): self.player.pause() def stop(self): self.player.stop() def is_muted(self): return self.player.isMuted() def is_paused(self): return self.player.state() in (QMediaPlayer.StoppedState, QMediaPlayer.PausedState) def mute(self, toggle): self.ui_manager.change_mute_state(toggle, self.get_volume()) self.player.setMuted(toggle) def get_playback_rate(self): return self.player.playbackRate() def set_playback_rate(self, value): self.player.setPlaybackRate(value) def process_buffer(self, buffer): if not self.probe_connected: return if not self.timer.isActive(): self.timer.start() else: if self.timer.remainingTime() == 0: data = buffer.data() chunked = chunk(list(data.asarray(buffer.byteCount())), 12) to_visualizer = [int(sum(e) // 12 // 75) for e in chunked] self.show_visualization(to_visualizer) def show_visualization(self, to_visualizer): self.ui_manager.update_equalizer(to_visualizer) def get_audio_devices(self): return QAudioDeviceInfo.availableDevices(QAudio.AudioOutput) def get_recent_files(self): return self.recent_files_manager.get_recent_files() def clear_recent_files(self): return self.recent_files_manager.clear_recent_files() def exit(self): self.ui_manager.exit()