class Player(): def __init__(self): self.player = QMediaPlayer() self.state = PLAYER_STATE_STOP def setMedia(self, music): self.player.setMedia(music) def play(self): print(self.player.mediaStatus()) if self.state == PLAYER_STATE_PAUSE: self.state = PLAYER_STATE_PLAY self.player.play() elif self.state == PLAYER_STATE_STOP: if self.player.mediaStatus() == LOADED_MEDIA: self.state = PLAYER_STATE_PLAY self.state.play() def pause(self): if self.state == PLAYER_STATE_PLAY: self.state = PLAYER_STATE_PAUSE self.player.pause() def stop(self): self.player.state = PLAYER_STATE_STOP
class QMediaPlayerAdapter(Player): def __init__(self, interval=1): self.__callback = None self.__player = QMediaPlayer() self.setNotifyInterval(interval) def setNotifyInterval(self, interval): self.__player.setNotifyInterval(interval) def setMusicPath(self, filePath): qUrl = QUrl(filePath) self.__player.setMedia(QMediaContent(qUrl)) def getState(self): return self.__player.state() def getStatus(self): return self.__player.mediaStatus() def getPosition(self): return self.__player.position() def getDuration(self): return self.__player.duration() def start(self): if self.__player.state() != QMediaPlayer.NoMedia: self.__player.play() # self.__player.setPosition(self.__player.duration() - 2000) else: raise ValueError( "The media of the player should be set before the player get started." ) def pause(self): self.__player.pause() def stop(self): self.__player.stop() def setCallback(self, callback): '''if not isinstance(callback, PlayerCallback): raise TypeError("The callback should be instance of PlayerCallback.")''' self.__callback = callback self.__player.mediaStatusChanged.connect( self.__callback.onMediaStatusChanged) self.__player.stateChanged.connect(self.__callback.onStateChanged) self.__player.positionChanged.connect( self.__callback.onPlayerPositionChanged)
class MainWindow(ui_mainwindow, qtbaseclass): # 详情页面 detail = None # 播放列表dock栏,初始隐藏 playListDockView = None # 当前播放列表 playList = [] # 当前播放的歌曲在列表中的索引号 songIndex = 0 # 当前播放的歌曲 song = None # 播放器 player = None # api func = netease # 是否循环播放 loop = True # 记录上次音量值 lastVolume = 0 def __init__(self, parent=None): if parent == None: parent = self ui_mainwindow.__init__(parent) qtbaseclass.__init__(parent) self.setupUi(self) self.setWindowTitle("Music") self.setWindowFlags(QtCore.Qt.FramelessWindowHint) self.setWindowIcon(QIcon('resource/format.ico')) with open('QSS/mainWindow.qss', 'r') as f: style = f.read() self.setStyleSheet(style) # 初始化 self.initList() self.initPlayWidgets() self.initTabWidgets() self.initDetailView() self.initPlayListDockView() def initList(self): # 初始化列表信息 # 设置推荐列表 self.recommandList.addItem( QListWidgetItem(QIcon('resource/music.png'), " 发现音乐")) self.recommandList.addItem( QListWidgetItem(QIcon('resource/signal.png'), " 私人FM")) self.recommandList.addItem( QListWidgetItem(QIcon('resource/movie.png'), " MV")) self.recommandList.setCurrentRow(0) # 设置我的音乐 self.myList.addItem( QListWidgetItem(QIcon('resource/notes.png'), " 本地音乐")) # 设置收藏与创建的歌单 # 未实现(动态添加) def initPlayWidgets(self): ''' 初始化播放控件状态''' self.player = QMediaPlayer(self) # self.player.setVolume(100) # 设置音量同时设置进度条 self.volumeSlider.setValue(100) self.player.stateChanged.connect(self.slot_player_stateChanged) self.player.positionChanged.connect(self.slot_player_positionChanged) self.player.durationChanged.connect(self.slot_player_durationChanged) # 隐藏暂停按键 self.pauseButton.hide() self.noVolume.hide() def initTabWidgets(self): # 初始化主窗口中TabWdidget self.detailView.hide() self.tabWidget.clear() netEase = SongsFrame(self) self.tabWidget.addTab(netEase, '网易云音乐') def initDetailView(self): # 初始化详情页 self.detail = AlbumDetailView(self) self.detailView.setWidget(self.detail) self.detail.addSongs.connect(self.slot_addSongs) def initPlayListDockView(self): # 主显示区域添加播放列表DOCK self.playListDockView = PlayListDockWidget(self) self.playListDockView.hide() # 初始状态为隐藏 self.playListDockView.doubleClicked.connect( self.slot_playList_doubleClicked) self.mainHorizontalLayout.addWidget(self.playListDockView) def mouseMoveEvent(self, event): if event.buttons() == QtCore.Qt.MiddleButton: # if event.globalPos().x() > self.pos().x(): # print("Y") # else: # print('N') self.move(event.globalPos()) event.accept() else: super().mouseMoveEvent(event) def slot_prev_page_clicked(self): '''上一页''' if self.tabWidget.isHidden(): self.tabWidget.show() self.detailView.hide() def slot_next_page_clicked(self): '''下一页''' # if self.detailView.isHidden(): # self.tabWidget.hide() # self.detailView.show() pass def slot_prev_song_clicked(self): '''上一首歌''' self.player.stateChanged.disconnect() self.songIndex = self.songIndex - 1 if self.songIndex < 0: self.songIndex = 0 else: self.song = self.playList[self.songIndex] if self.set_player_media(): self.player.play() self.playListDockView.setSelectRow(self.songIndex) self.player.stateChanged.connect(self.slot_player_stateChanged) def slot_next_song_clicked(self): '''下一首歌''' self.player.stateChanged.disconnect() self.songIndex = (self.songIndex + 1) % len(self.playList) self.song = self.playList[self.songIndex] if self.set_player_media(): self.player.play() self.playListDockView.setSelectRow(self.songIndex) self.player.stateChanged.connect(self.slot_player_stateChanged) def slot_play_clicked(self): '''播放 点击事件''' if self.player.mediaStatus() > 1 and self.player.mediaStatus() < 7: self.player.play() else: # 未添加 音乐 QMessageBox.warning(self, '警告', '播放列表为空!请先添加音乐到播放列表。') def slot_pause_clicked(self): '''暂停 点击事件''' self.player.pause() # self.playButton.show() # self.pauseButton.hide() def slot_addSongs(self, songsList): '''添加歌曲''' # 去重合并列表 ids = [x.id for x in self.playList] for song in songsList: if song.id not in ids: self.playList.append(song) # 播放列表变化,更新列表显示 self.playListDockView.setList(self.playList) # 初始化song if self.song == None: self.song = self.playList[self.songIndex] self.set_player_media() def slot_player_stateChanged(self): '''播放器状态变化''' if not self.playList: return if self.player.state() == QMediaPlayer.StoppedState: if self.loop: self.songIndex = (self.songIndex + 1) % len(self.playList) self.song = self.playList[self.songIndex] if self.set_player_media(): self.player.play() else: self.playButton.show() self.pauseButton.hide() elif self.player.state() == QMediaPlayer.PausedState: self.playButton.show() self.pauseButton.hide() elif self.player.state() == QMediaPlayer.PlayingState: self.playButton.hide() self.pauseButton.show() self.countTime.setText(self.song.time) def slot_player_positionChanged(self, pos): '''播放时间改变控件位置''' t = pos / 1000 mins = t // 60 secs = t % 60 curTime = QtCore.QTime(0, mins, secs).toString('mm:ss') self.currentTime.setText(curTime) self.timeSlider.setValue(pos) def slot_player_durationChanged(self, duration): '''设置进度条最大值''' self.timeSlider.setRange(0, duration) def set_player_media(self): '''设置播放器音乐媒体,成功返回True,否则False''' try: mp3 = self.func.singsUrl([self.song.id]) if mp3: mp3 = mp3[0]['url'] self.player.setMedia(QMediaContent(QtCore.QUrl(mp3))) return True except: # 网络异常 QMessageBox.warning(self, '获取音乐地址失败!请检查网络后重试!', '警告') return False def slot_playList_clicked(self): '''播放列表按钮 点击事件''' if self.playListDockView.isHidden(): self.playListDockView.show() else: self.playListDockView.hide() def slot_playList_doubleClicked(self, songIndex): '''播放列表双击事件 songIndex -- 为当前双击歌曲在列表中的索引号。 执行动作:立即播放该歌曲 ''' self.songIndex = songIndex if self.set_player_media(): self.player.play() def slot_volumeSlider_valueChanged(self, value): '''音量调节''' self.player.setVolume(value) if value == 0: self.noVolume.show() self.volume.hide() else: self.noVolume.hide() self.volume.show() def slot_noVolume_clicked(self): '''静音按钮点击事件,动作:切成原始音量''' # self.volumeSlider.setValue(0) self.player.setMuted(False) self.noVolume.hide() self.volume.show() def slot_volume_clicked(self): '''音量按钮点击事件,动作:切成静音''' # self.volumeSlider.setValue(0) self.player.setMuted(True) self.noVolume.show() self.volume.hide()
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 QDeckAudioListWidget(QTableWidget): deckpath = None current_deck_rowid = None dbAdapter = None current_rowid = None config = ConfigFile(None, None) audioItemsDict = [] audioPlayer = None audioRecorder = None STOPPED = 0 RECORDING = 1 PLAYING = 2 status = 0 row = None default_import_path = os.path.expanduser('~') def __init__(self): super().__init__() def setRowID(self, rowid): self.current_rowid = rowid def initAudioListWidget(self, dbAdapter, deckpath, current_rowid): self.audioItemsDict = [] self.dbAdapter = dbAdapter self.deckpath = deckpath self.current_rowid = current_rowid self.audioPlayer = QMediaPlayer() self.audioPlayer.mediaStatusChanged.connect(self.mediaStatusChanged) os_name = platform.uname()[0] if os_name == "Windows" or os_name == "Darwin": self.audioRecorder = QAudioRecorder() else: from modules.deck.gstAudioRecorder import GstAudioRecorder self.audioRecorder = GstAudioRecorder() settings = QAudioEncoderSettings() audioformat = self.config.readVar('vocable', 'audioformat') if audioformat == 'ogg': settings.setCodec("audio/vorbis") self.audioRecorder.setContainerFormat("ogg") elif audioformat == 'mp3': settings.setCodec("audio/mpeg") self.audioRecorder.setContainerFormat("mp3") elif audioformat == 'amr': settings.setCodec("audio/amr") else: settings.setCodec("audio/PCM") self.audioRecorder.setContainerFormat("wav") self.audioRecorder.setEncodingSettings(settings) self.setColumnCount(6) self.setHorizontalHeaderLabels( ["description", "", "", "", "", "filename"]) self.setRowCount(0) self.itemChanged.connect(self.onItemChanged) def getAudioFromDB(self, rowid): self.audioItemsDict = self.dbAdapter.audioFilenamesForDeckRowID(rowid) self.setRowCount(len(self.audioItemsDict)) for i, row in enumerate(self.audioItemsDict): self.setItem(i, 0, QTableWidgetItem(row["description"])) self.updateAudioListWidget() def appendNewAudio(self): self.audioItemsDict.append({ "rowid": None, "description": "", "filename": None }) self.insertRow(self.rowCount()) self.updateAudioListWidget() def updateAudioListWidget(self): for i, row in enumerate(range(self.rowCount())): button_delete = QPushButton() button_delete.setIcon(QIcon.fromTheme('edit-delete')) self.setCellWidget(row, DELETE_BUTTON_COLUMN, button_delete) button_delete.clicked.connect( partial(self.deleteAudioButtonClicked, row)) button_open_file = QPushButton() button_open_file.setIcon(QIcon.fromTheme('document-open')) self.setCellWidget(row, OPEN_FILE_BUTTON_COLUMN, button_open_file) button_open_file.clicked.connect( partial(self.importAudioFileClicked, row)) button_edit_file = QPushButton() #button_edit_file.setIcon(QIcon.fromTheme('audio-x-generic')) button_edit_file.setIcon(QIcon('./assets/icons/audacity.jpg')) self.setCellWidget(row, EDIT_FILE_BUTTON, button_edit_file) button_edit_file.clicked.connect( partial(self.editAudioFileClicked, row)) self.setItem( row, FILE_NAME_COLUMN, QTableWidgetItem(str(self.audioItemsDict[row]["filename"]))) if self.status == self.STOPPED: if self.audioItemsDict[i]["filename"]: self.insertPlayButton(row) else: self.insertRecordButton(row) elif self.status == self.PLAYING: if i == self.row: self.insertStopPlayButton(row) else: if not self.audioItemsDict[i]["filename"]: self.insertRecordButton(row) else: self.insertPlayButton(row) elif self.status == self.RECORDING: if i == self.row: self.insertStopRecordButton(row) else: if self.audioItemsDict[i]["filename"]: self.insertPlayButton(row) else: self.insertRecordButton(row) self.resizeColumnsToContents() def insertPlayButton(self, row): button_play = QPushButton() button_play.setIcon(QIcon.fromTheme('media-playback-start')) self.setCellWidget(row, PLAY_BUTTON_COLUMN, button_play) button_play.clicked.connect(partial(self.playButtonClicked, row)) def insertStopPlayButton(self, row): button_stop = QPushButton() button_stop.setIcon(QIcon.fromTheme('media-playback-stop')) self.setCellWidget(row, PLAY_BUTTON_COLUMN, button_stop) button_stop.clicked.connect(partial(self.stopPlayButtonClicked, row)) def insertRecordButton(self, row): button_record = QPushButton() button_record.setIcon(QIcon.fromTheme('media-record')) self.setCellWidget(row, RECORD_BUTTON_COLUMN, button_record) button_record.clicked.connect(partial(self.recordButtonClicked, row)) def insertStopRecordButton(self, row): button_stop = QPushButton() button_stop.setIcon(QIcon.fromTheme('media-playback-stop')) self.setCellWidget(row, RECORD_BUTTON_COLUMN, button_stop) button_stop.clicked.connect(partial(self.stopRecordButtonClicked, row)) def deleteAudioButtonClicked(self, row): reply = QMessageBox.question(self, 'Delete Audio', "really?", QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: self.removeRow(row) rowid = self.audioItemsDict[row]["rowid"] if rowid: self.dbAdapter.deleteAudioItem(rowid) filename = self.audioItemsDict[row]["filename"] if filename: self.dbAdapter.deleteAudioItemByFilename(filename) filepath = path.join(self.deckpath, filename) if path.exists(filepath): remove(filepath) del self.audioItemsDict[row] self.updateAudioListWidget() def importAudioFileClicked(self, row): file_path = QFileDialog.getOpenFileName(self, 'Please select an Audio File', self.default_import_path) self.default_import_path = file_path[0] filename = file_path[0].split(os.sep)[::-1][0] target_path = os.path.join(self.deckpath, filename) #if not os.path.exists(target_path): try: shutil.copyfile(file_path[0], target_path) except FileNotFoundError: """ there is simply no file to copy """ pass else: self.audioItemsDict[row]["filename"] = filename self.status = self.STOPPED self.updateAudioListWidget() self.saveStateToDB(self.current_rowid) def editAudioFileClicked(self, row): filename = self.audioItemsDict[row]["filename"] target_path = os.path.join(self.deckpath, filename) self.process = QProcess() self.process.errorOccurred.connect(self.onAudioEditProcessError) self.process.stateChanged.connect(self.onAudioStateChangedError) os_name = platform.uname()[0] if os_name == "Linux": open_command = "audacity " + target_path elif os_name == "Windows": open_command = '"C:\\program files (x86)\\Audacity\\audacity.exe" "' + target_path + '"' print(open_command) self.process.startDetached(open_command) def onAudioEditProcessError(self, error): print(error) def onAudioStateChangedError(self, state): print(state) def recordButtonClicked(self, row): self.stopPlayButtonClicked(row) self.stopRecordButtonClicked(row) extension = '.wav' audioformat = self.config.readVar('vocable', 'audioformat') if audioformat == 'ogg': extension = '.ogg' elif audioformat == 'mp3': extension = '.mp3' elif audioformat == 'amr': extension = '.amr' filename = str(int(time.time())) + self.randomword(5) + extension filepath = os.path.join(self.deckpath, filename) print(filepath) url = QUrl.fromLocalFile(QFileInfo(filepath).absoluteFilePath()) self.audioRecorder.setOutputLocation(url) self.audioRecorder.record() self.audioItemsDict[row]["filename"] = filename self.status = self.RECORDING self.row = row self.updateAudioListWidget() self.saveStateToDB(self.current_rowid) def stopRecordButtonClicked(self, row): self.stopPlayButtonClicked(row) self.audioRecorder.stop() self.status = self.STOPPED self.updateAudioListWidget() def playButtonClicked(self, row): self.stopRecordButtonClicked(row) filename = self.audioItemsDict[row]["filename"] filepath = path.join(self.deckpath, filename) url = QUrl.fromLocalFile(QFileInfo(filepath).absoluteFilePath()) content = QMediaContent(url) self.audioPlayer.setMedia(content) self.audioPlayer.play() self.status = self.PLAYING self.row = row self.updateAudioListWidget() def stopPlayButtonClicked(self, row): self.audioPlayer.stop() self.status = self.STOPPED self.updateAudioListWidget() def stopAllAudio(self): row = 1 self.stopPlayButtonClicked(row) self.stopRecordButtonClicked(row) self.status = self.STOPPED def mediaStatusChanged(self): status = self.audioPlayer.mediaStatus() if status == 7: self.stopAllAudio() def onItemChanged(self): for i in range(self.rowCount()): item = self.item(i, 0) if item: cell_text = self.item(i, 0).text() self.audioItemsDict[i]["description"] = cell_text def saveStateToDB(self, deck_rowid): self.dbAdapter.saveAudioDict(self.audioItemsDict, deck_rowid) def randomword(self, length): return ''.join( random.choice(string.ascii_lowercase) for i in range(length))
class Player(QMediaPlayer): def __init__(self, parent=None): super(Player, self).__init__(parent) self.parent = parent self.player = QMediaPlayer() self.queueList = QMediaPlaylist() self.player.setPlaylist(self.queueList) self.queueData = [] self.position = 0 self.volume = 100 self.player.mediaStatusChanged.connect(self.qmp_mediaStatusChanged) self.player.positionChanged.connect(self.qmp_positionChanged) self.player.durationChanged.connect(self.durationChanged) self.queueList.currentIndexChanged.connect(self.playlistPosChanged) def add(self, data): """Add track to the queue""" queueData = { 'pc_title': data['pc_title'], 'title': data['title'], 'url': data['url'], 'date': data['date_format'], 'description': data['description'] } self.queueData.append(queueData) self.queueList.addMedia(QMediaContent(QUrl(data['url']))) def playPause(self): icon = QIcon.fromTheme("media-playback-pause") if self.player.state() == QMediaPlayer.StoppedState: if self.player.mediaStatus() == QMediaPlayer.NoMedia: if self.queueList.mediaCount() != 0: self.player.play() elif self.player.mediaStatus() == QMediaPlayer.LoadedMedia: self.queueList.setCurrentIndex(self.position) self.player.play() elif self.player.mediaStatus() == QMediaPlayer.BufferedMedia: self.player.play() elif self.player.state() == QMediaPlayer.PlayingState: icon = QIcon.fromTheme("media-playback-start") self.player.pause() elif self.player.state() == QMediaPlayer.PausedState: self.player.play() self.parent.playBtn.setIcon(icon) def startPlay(self): data = self.queueData[0] self.queueList.setCurrentIndex(0) self.parent.curPCLabel.setText(data['pc_title']) self.parent.curTrackName.setText(data['title']) self.player.play() icon = QIcon.fromTheme("media-playback-pause") self.parent.playBtn.setIcon(icon) def stop(self): self.player.stop() icon = QIcon.fromTheme("media-playback-start") self.parent.playBtn.setIcon(icon) def setPosition(self, pos): self.player.setPosition(pos) def durationChanged(self, duration): total_time = '0:00:00' duration = self.player.duration() total_time = ms_to_time(duration) self.parent.timeSlider.setMaximum(duration) self.currentTrackDuration = duration self.parent.totalTimeLabel.setText(total_time) def qmp_mediaStatusChanged(self, status): icon = QIcon.fromTheme("media-playback-pause") if self.player.state() == QMediaPlayer.StoppedState: icon = QIcon.fromTheme("media-playback-start") elif self.player.state() == QMediaPlayer.PausedState: icon = QIcon.fromTheme("media-playback-start") self.parent.playBtn.setIcon(icon) def qmp_positionChanged(self, position, senderType=False): self.currentTime = position current_time = '0:00:00' if position != -1: current_time = ms_to_time(position) self.parent.timeLabel.setText(current_time) self.parent.timeSlider.blockSignals(True) self.parent.timeSlider.setValue(position) self.parent.timeSlider.blockSignals(False) def playlistPosChanged(self): pos = self.queueList.currentIndex() data = self.queueData[pos] self.parent.curPCLabel.setText(data['pc_title']) self.parent.curTrackName.setText(data['title']) windowTitle = '{0} - {1}'.format(data['pc_title'], data['title']) self.parent.setWindowTitle(windowTitle) if self.queueList.mediaCount() > 1: if pos < self.queueList.mediaCount() - 1: self.parent.queueNextBtn.setEnabled(True) else: self.parent.queueNextBtn.setEnabled(False) if pos > 0: self.parent.queuePrevBtn.setEnabled(True) else: self.parent.queuePrevBtn.setEnabled(False) if pos < self.queueList.mediaCount(): prevPos = 0 if self.position < pos: prevPos = pos - 1 else: prevPos = pos + 1 prevItem = self.parent.queueList.item(prevPos) prevWidget = self.parent.queueList.itemWidget(prevItem) if prevItem: prevWidget.statusIcon.setPixmap(QPixmap()) self.position = pos item = self.parent.queueList.item(pos) widget = self.parent.queueList.itemWidget(item) if widget: icon = QIcon.fromTheme("media-playback-start") widget.statusIcon.setPixmap(icon.pixmap(16, 16)) def setVolume(self, volume): self.player.setVolume(volume) def rev10Secs(self): position = self.player.position() new_pos = position - 10000 self.player.setPosition(new_pos) def for10Secs(self): position = self.player.position() new_pos = position + 10000 self.player.setPosition(new_pos) def delete(self, position): """ Delete the track and her data from position""" self.queueData.pop(position) self.queueList.removeMedia(position) if (position == self.position): self.playlistPosChanged()
class Window(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super().__init__(parent) # load config self.data = yaml_loader() # load ui self.setupUi(self) # load icons self.setWindowTitle("Sputofy") self.setWindowIcon(QIcon(os.path.join(RES_PATH, "logo.svg"))) loopIcon = QIcon() loopIcon.addPixmap(QPixmap(os.path.join(RES_PATH, "loopIconOFF.svg"))) self.loopBtn.setIcon(loopIcon) prevIcon = QIcon() prevIcon.addPixmap(QPixmap(os.path.join(RES_PATH, "backwardIcon.svg"))) self.prevBtn.setIcon(prevIcon) playIcon = QIcon() playIcon.addPixmap(QPixmap(os.path.join(RES_PATH, "playIcon.svg"))) self.playBtn.setIcon(playIcon) nextIcon = QIcon() nextIcon.addPixmap(QPixmap(os.path.join(RES_PATH, "forwardIcon.svg"))) self.nextBtn.setIcon(nextIcon) randomIcon = QIcon() randomIcon.addPixmap( QPixmap(os.path.join(RES_PATH, "randomIconOFF.svg"))) self.randomBtn.setIcon(randomIcon) volumeIcon = QIcon() volumeIcon.addPixmap(QPixmap(os.path.join(RES_PATH, "volumeIcon.svg"))) self.volumeBtn.setIcon(volumeIcon) # window's settings self.xCor = self.data['last_position']['xPos'] self.yCor = self.data['last_position']['yPos'] self.widthSize = self.data['last_window_size']['width'] self.heightSize = self.data['last_window_size']['height'] self.setGeometry(self.xCor, self.yCor, self.widthSize, self.heightSize) # load YouTubeToMP3 self.YouTubeToMP3 = YouTubeToMP3Window() # open YouTubeToMP3 using button self.actionYT_MP3.triggered.connect(self.YouTubeToMP3.show_window) # info action self.actionInfo.triggered.connect(self.info_handle) #=========================== mediaplayer ============================== # create media player object self.mediaPlayer = QMediaPlayer(None) # open button self.actionOpen_Song.triggered.connect(self.open_song) self.actionOpen_Folder.triggered.connect(self.open_folder) # play button self.playBtn.setEnabled(False) self.playBtn.clicked.connect( self.play_video ) # when btn is pressed: if it is playing it pause, if it is paused it plays # QShortcut(QKeySequence("Space"), self).activated.connect(self.play_video)metodo da ricordare in caso di problemi #TODO # duration slider self.durationSlider.setEnabled(False) self.durationSliderMaxValue = 0 self.durationSlider.valueChanged.connect( self.mediaPlayer.setPosition ) # set mediaPlayer position using the value took from the slider QShortcut('Right', self, lambda: self.durationSlider.setValue( self.durationSlider.value() + 10000)) # 1s = 1000ms QShortcut('Left', self, lambda: self.durationSlider.setValue( self.durationSlider.value() - 10000)) # 1s = 1000ms QShortcut('Shift+Right', self, lambda: self.durationSlider.setValue( self.durationSliderMaxValue - 1000)) # jump to the end-1s of song QShortcut('Shift+Left', self, lambda: self.durationSlider.setValue(0)) # restart song # volumeSlider self.volumeSlider.setProperty("value", 100) self.volumeSlider.setRange(0, 100) self.volumeSlider.setValue( self.data['volume'] if self.data['volume'] != 0 else self.data['volume'] + 1 ) # set slider value | if saved volume is equal to 0 load with volume = 1 else load the saved volume self.mediaPlayer.setVolume( self.data['volume'] if self.data['volume'] != 0 else self.data['volume'] + 1 ) # set mediaPlayer volume | if saved volume is equal to 0 load with volume = 1 else load the saved volume self.volumeLabel.setText( f"{self.data['volume']}%" if self.data['volume'] != 0 else f"{self.data['volume']+1}%" ) # set volume label text | if saved volume is equal to 0 load with volume = 1 else load the saved volume self.volumeSlider.valueChanged.connect( self.mediaPlayer.setVolume ) # set mediaPlayer volume using the value took from the slider QShortcut('Up', self, lambda: self.volumeSlider.setValue( self.volumeSlider.value() + 1)) # volume + 1 QShortcut('Down', self, lambda: self.volumeSlider.setValue( self.volumeSlider.value() - 1)) # volume - 1 QShortcut( 'Shift+Up', self, lambda: self.volumeSlider.setValue(100)) # set maximum volume QShortcut( 'Shift+Down', self, lambda: self.volumeSlider.setValue(0)) # set minimun volume(mute) # volumeBtn self.volumeBtn.clicked.connect( self.volume_toggle) # mute/unmute volume pressing btn self.isMuted = False # starting with a non-muted volume self.previousVolume = self.data[ 'volume'] # loading last registered volume # media player signals self.mediaPlayer.durationChanged.connect( self.duration_changed) # set range of duration slider self.mediaPlayer.positionChanged.connect( self.position_changed) # duration slider progress self.mediaPlayer.stateChanged.connect( self.player_state) # see when it's playing or in pause self.mediaPlayer.volumeChanged.connect( self.volume_icon) # change volumebtn icon #=========================== playlist ============================== # create the playlist self.playlist = QMediaPlaylist() self.playlist.setPlaybackMode(2) self.mediaPlayer.setPlaylist(self.playlist) # clear the playlist self.playlistIsEmpty = True # playlistList model self.model = PlaylistModel(self.playlist) self.playlistView.setModel(self.model) self.playlist.currentIndexChanged.connect( self.playlist_position_changed) selection_model = self.playlistView.selectionModel() selection_model.selectionChanged.connect( self.playlist_selection_changed) #=========================== playlist function ============================== self.mediaList = [] # array of loaded songs self.currentPlaylist = "" # current loaded playlist name self.isCustomPlaylist = False # add song name on title self.playlist.currentMediaChanged.connect(self.set_title) # playlist buttons self.nextBtn.clicked.connect(self.next_song) # seek track forward self.prevBtn.clicked.connect(self.prev_song) # seek track backward self.mediaPlayer.mediaStatusChanged.connect( self.auto_next_track ) # once song is ended seek track forward and play it self.actionLoopIt.triggered.connect( self.loop_song) # (1) loop the same song self.actionShuffle.triggered.connect( self.shuffle_playlist) # change song's order self.loopBtn.clicked.connect(self.loop) # (3) loop the playlist self.randomBtn.clicked.connect( self.random) # (4) play random song without end # create new playlist self.actionCreatePlaylist.triggered.connect(self.custom_playlist) # delete current playlist self.actionDeletePlaylist.triggered.connect(self.delete_playlist) # remove all songs self.actionClearQueue.triggered.connect(self.clear_queue) # load playlist self.actionDict = {} # dictionary of action Objects for action in self.data['playlistList']: self.actionDict[action] = self.menuPlaylist.addAction( action, partial(self.load_playlist, action)) if len(self.data['playlistList']) == 0: self.menuPlaylist.menuAction().setVisible(False) #================== Songs opening ==================# def open_folder(self): foldername = QFileDialog.getExistingDirectory(self, "Open folder", "c:\\") if foldername: self.playlist.clear() self.mediaList.clear() for song in os.listdir(foldername): media = f"{foldername}/{song}" self.playlist.addMedia(QMediaContent(QUrl(media))) self.mediaList.append(media) self.playlist.setCurrentIndex(0) self.playBtn.setEnabled(True) self.durationSlider.setEnabled(True) self.playlistIsEmpty = False self.isCustomPlaylist = False self.model.layoutChanged.emit() # load songs in list view self.set_title() self.mediaPlayer.pause() # adjust play/pause icon def open_song(self): filename, _ = QFileDialog.getOpenFileName(self, "Open Song", "c:\\") if filename: if self.playlistIsEmpty == False: self.playlist.clear() self.mediaList.clear() self.playlistIsEmpty = True self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(filename))) self.mediaList.append(filename) self.playBtn.setEnabled(True) self.durationSlider.setEnabled(True) self.isCustomPlaylist = False self.model.layoutChanged.emit() # load song in list view self.set_title() # adjust play/pause icon if self.playlist.mediaCount( ) == 1: # if there is 1 song and you add another self.playlist.setCurrentIndex(0) self.mediaPlayer.pause() def load_playlist(self, playlistName): self.playlist.clear() self.mediaList.clear() # reload config self.data = yaml_loader() for song in self.data['playlistList'][playlistName]: self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(song))) self.mediaList.append(song) self.playlist.setCurrentIndex(0) self.playBtn.setEnabled(True) self.durationSlider.setEnabled(True) self.playlistIsEmpty = False self.isCustomPlaylist = True self.model.layoutChanged.emit() # load songs in list view self.currentPlaylist = playlistName # name of current loaded playlist self.set_title() self.statusbar.showMessage(f'Playlist "{playlistName}" loaded', 4000) self.menuPlaylist.menuAction().setVisible(True) # adjust play/pause icon self.mediaPlayer.pause() def set_title(self): if self.playlist.mediaCount() == 0: self.setWindowTitle("Sputofy") else: if self.isCustomPlaylist == False: self.setWindowTitle( f"Sputofy - {os.path.splitext(self.playlist.currentMedia().canonicalUrl().fileName())[0]} - {self.playlist.currentIndex()+1}/{self.playlist.mediaCount()}" ) else: self.setWindowTitle( f"Sputofy - {self.currentPlaylist} - {os.path.splitext(self.playlist.currentMedia().canonicalUrl().fileName())[0]} - {self.playlist.currentIndex()+1}/{self.playlist.mediaCount()}" ) #=======================================================# #================== Player Functions ==================# def play_video(self): if self.durationSlider.isEnabled(): # if slider was enabled if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def duration_changed(self, duration): self.durationSlider.setRange(0, duration) if duration > 0: self.totalTime_Label.setText(time_format(round( duration / 1000))) # duration is in ms self.durationSliderMaxValue = duration def position_changed(self, position): if position >= 0: self.elapsedTime_Label.setText(time_format( (position / 1000))) # position is in ms # Disable the events to prevent updating triggering a setPosition event (can cause stuttering). self.durationSlider.blockSignals(True) self.durationSlider.setValue(position) self.durationSlider.blockSignals(False) #=======================================================# #================== Playlist Settings ==================# #TODO Work in progress def playlist_array(self): index = self.playlist.mediaCount() mediaList = [] for i in range(index): # songPath = (self.playlist.media(path).canonicalUrl().path())#.split("/",1)[1] # mediaList.append(songPath) # print(self.playlist.media(i).canonicalUrl().path()) mediaList.append(self.playlist.media(i).canonicalUrl().fileName()) return mediaList def custom_playlist(self): if not self.playlist.mediaCount() == 0: name, is_notEmpty = QInputDialog.getText(self, "playlist", "save playlist as:") if name: if name in self.data['playlistList']: self.statusbar.showMessage( "playlist not created (name is already used)", 4000) else: self.data['playlistList'][name] = self.mediaList yaml_dump(self.data) # add new action Object to dictionary self.actionDict[name] = self.menuPlaylist.addAction( name, partial(self.load_playlist, name)) self.load_playlist( name) # instantly loading the new playlist else: self.statusbar.showMessage( "playlist not created (you should give a name to your baby :/)", 4000) else: self.statusbar.showMessage("there are no songs to playlist", 4000) def delete_playlist(self): if self.isCustomPlaylist: if len(self.data['playlistList']) == 1: self.menuPlaylist.menuAction().setVisible(False) self.data['playlistList'].pop( self.currentPlaylist) # remove playlist from dictionary self.menuPlaylist.removeAction(self.actionDict[ self.currentPlaylist]) # remove relative action self.actionDict.pop( self.currentPlaylist) # remove relative action Object self.playlist.clear() self.model.layoutChanged.emit() self.setWindowTitle("Sputofy") yaml_dump(self.data) self.statusbar.showMessage( 'succesfully deleted "' + self.currentPlaylist + '" playlist', 4000) else: self.statusbar.showMessage("cannot delete a non custom playlist", 4000) def clear_queue(self): self.playlist.clear() self.mediaList.clear() self.playBtn.setEnabled(False) self.model.layoutChanged.emit() def playlist_position_changed(self, i): if i > -1: ix = self.model.index(i) self.playlistView.setCurrentIndex(ix) def playlist_selection_changed(self, ix): # We receive a QItemSelection from selectionChanged. i = ix.indexes()[0].row() self.posizione = i self.playlist.setCurrentIndex(i) self.mediaPlayer.play() #=======================================================# #================== Playback Settings ==================# def next_song(self): if self.playlist.currentIndex() == self.playlist.mediaCount() - 1: self.playlist.setCurrentIndex(0) else: self.playlist.next() def prev_song(self): if self.playlist.currentIndex() == 0: self.playlist.setCurrentIndex(self.playlist.mediaCount() - 1) else: self.playlist.previous() def loop_song(self): if self.playlist.playbackMode() != 1: self.playlist.setPlaybackMode(1) self.actionLoopIt.setText("Loop it: ON") self.loopBtn.setIcon( QIcon(os.path.join(RES_PATH, "loopIconOFF.svg"))) self.randomBtn.setIcon( QIcon(os.path.join(RES_PATH, "randomIconOFF.svg"))) else: self.playlist.setPlaybackMode(2) self.actionLoopIt.setText("Loop it: OFF") def shuffle_playlist(self): if self.playlist.mediaCount(): self.playlist.shuffle() self.model.layoutChanged.emit() else: self.statusbar.showMessage("there are no songs to shuffle", 4000) def loop(self): if self.playlist.playbackMode() != 3: self.playlist.setPlaybackMode(3) self.loopBtn.setIcon( QIcon(os.path.join(RES_PATH, "loopIconON.svg"))) self.randomBtn.setIcon( QIcon(os.path.join(RES_PATH, "randomIconOFF.svg"))) self.actionLoopIt.setText("Loop it: OFF") else: self.playlist.setPlaybackMode(2) self.loopBtn.setIcon( QIcon(os.path.join(RES_PATH, "loopIconOFF.svg"))) def random(self): if self.playlist.playbackMode() != 4: self.playlist.setPlaybackMode(4) self.randomBtn.setIcon( QIcon(os.path.join(RES_PATH, "randomIconON.svg"))) self.loopBtn.setIcon( QIcon(os.path.join(RES_PATH, "loopIconOFF.svg"))) self.actionLoopIt.setText("Loop it: OFF") else: self.playlist.setPlaybackMode(2) self.randomBtn.setIcon( QIcon(os.path.join(RES_PATH, "randomIconOFF.svg"))) def auto_next_track(self): if self.mediaPlayer.mediaStatus() == QMediaPlayer.EndOfMedia: if self.playlist.playbackMode() == 2: # index starts from 0 mediacount starts from 1 if self.playlist.currentIndex( ) != self.playlist.mediaCount() - 1: self.playlist.next() self.mediaPlayer.play() else: # if ended song was the last one set the index to the first one and pause self.playlist.setCurrentIndex(0) self.mediaPlayer.pause() # loop playlist elif self.playlist.playbackMode() == 3: self.playlist.next() self.mediaPlayer.play() # random song elif self.playlist.playbackMode() == 4: while self.playlist.previousIndex( ) == self.playlist.currentIndex( ): # preventing repeating the same song self.playlist.setCurrentIndex( random.randint(0, self.playlist.mediaCount() - 1)) #=======================================================# #================== Volume Settings ==================# def volume_icon(self, volume): self.volumeLabel.setText(f"{volume}%") if volume: volumeIcon = QIcon() volumeIcon.addPixmap( QPixmap(os.path.join(RES_PATH, "volumeIcon.svg")), QIcon.Normal, QIcon.Off) self.volumeBtn.setIcon(volumeIcon) self.previousVolume = self.volumeSlider.value() self.isMuted = False else: volumeMutedIcon = QIcon() volumeMutedIcon.addPixmap( QPixmap(os.path.join(RES_PATH, "volumeMutedIcon.svg")), QIcon.Normal, QIcon.Off) self.volumeBtn.setIcon(volumeMutedIcon) self.isMuted = True def volume_toggle(self): if self.isMuted == False: self.volumeSlider.setValue(0) self.isMuted = True elif self.isMuted == True: if self.previousVolume == 0: self.volumeSlider.setValue(10) else: self.volumeSlider.setValue(self.previousVolume) self.isMuted = False #=======================================================# def mousePressEvent(self, event): ''' remove the border around the buttons created by using tab key ''' focused_widget = QtWidgets.QApplication.focusWidget() try: focused_widget.clearFocus() except: pass QMainWindow.mousePressEvent(self, event) def player_state(self, event): ''' event handler that adjust the play/pause icon ''' if event == QMediaPlayer.PlayingState: pauseIcon = QIcon() pauseIcon.addPixmap( QPixmap(os.path.join(RES_PATH, "pauseIcon.svg")), QIcon.Normal, QIcon.Off) self.playBtn.setIcon(pauseIcon) elif event == QMediaPlayer.PausedState: playIcon = QIcon() playIcon.addPixmap(QPixmap(os.path.join(RES_PATH, "playIcon.svg")), QIcon.Normal, QIcon.Off) self.playBtn.setIcon(playIcon) def closeEvent(self, event): ''' event handler that take window information and save it in config before the window close ''' # retrieve position xAxis = self.geometry().x() yAxis = self.geometry().y() self.data['last_position']['xPos'] = xAxis self.data['last_position']['yPos'] = yAxis # retrieve size width = self.width() height = self.height() self.data['last_window_size']['width'] = width self.data['last_window_size']['height'] = height # retrieve volume self.data['volume'] = self.mediaPlayer.volume() # retrieve user user = os.getlogin() self.data[ 'default_folder'] = f"C:\\Users\\{user}\\Desktop\\sputofy_songs" yaml_dump(self.data) def info_handle(self): info = "Sputofy\n1.0.0\n©2020 "+\ "Sputofy is a free audio player based on the converted youtube songs made by a_str0\n\n"+\ "Sputofy is written using python 3.x and PyQt5 modules" msg = QMessageBox.about(self, "About", info)
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 PlayManager(QWidget): NO_PLAYING_SONG = "没有正在播放的歌曲" def __init__(self, layout, parent=None): super().__init__(parent) self.player = QMediaPlayer(self) self.player.setAudioRole(QAudio.MusicRole) self.player.durationChanged.connect(self.duration_changed) self.player.positionChanged.connect(self.position_changed) self.player.mediaStatusChanged.connect(self.status_changed) self.player.bufferStatusChanged.connect(self.buffering_progress) self.player.stateChanged.connect(self.state_changed) self.player.error[QMediaPlayer.Error].connect( self.display_error_message) self.play_control = PlayControl(layout, parent) self.play_control.set_state(self.player.state()) self.play_control.play.connect(self.player.play) self.play_control.pause.connect(self.player.pause) self.play_control.stop.connect(self.player.stop) self.player.stateChanged.connect(self.play_control.set_state) self.song_label = QLabel() self.song_label.setText(self.NO_PLAYING_SONG) self.song_label.setWordWrap(True) song_grid = QGridLayout(parent) song_grid.addWidget(self.song_label, 0, 0) self.duration_label = QLabel() self.duration_label.setText("00:00 / 00:00") self.slider = QSlider(Qt.Horizontal, parent) self.slider.setRange(0, self.player.duration() / 1000) self.slider.sliderMoved.connect(self.seek) progress_layout = QHBoxLayout(parent) progress_layout.insertWidget(0, self.duration_label) progress_layout.insertWidget(0, self.slider) song_grid.addLayout(progress_layout, 1, 0) self.status_label = QLabel() song_grid.addWidget(self.status_label, 2, 0) layout.addLayout(song_grid) if not self.is_player_available(): QMessageBox.warning(self, "警告", "QMediaPlayer 对象无可用的服务") return self.song = None def is_player_available(self): return self.player.isAvailable() def add_to_play(self, spider, song): self.song = song spider.get_song_url(song) url = song.url if url is None or len(url) == 0: return req = QNetworkRequest(QUrl(url)) req.setHeader(QNetworkRequest.UserAgentHeader, HttpRequestConfig.CHROME_USER_AGENT) self.player.setMedia(QMediaContent(req)) def duration_changed(self, duration): self.duration = int(duration / 1000) self.slider.setMaximum(self.duration) t = "00:00 / %s" % (self.song.get_time()) self.duration_label.setText(t) def position_changed(self, progress): if not self.slider.isSliderDown(): self.slider.setValue(int(progress / 1000)) self.update_duration_info(int(progress / 1000)) @pyqtSlot(int) def seek(self, seconds): self.player.setPosition(seconds * 1000) def state_changed(self, state): if QMediaPlayer.PlayingState == state \ or QMediaPlayer.PausedState == state: self.song_label.setText("%s - %s" % (self.song.get_singers(), self.song.name)) else: self.song_label.setText(self.NO_PLAYING_SONG) def status_changed(self, status): if QMediaPlayer.UnknownMediaStatus == status \ or QMediaPlayer.NoMedia == status \ or QMediaPlayer.LoadedMedia == status \ or QMediaPlayer.BufferedMedia == status: self.set_status_info("") elif QMediaPlayer.LoadingMedia == status: self.set_status_info("加载中...") elif QMediaPlayer.BufferingMedia == status: self.set_status_info("缓存中...") elif QMediaPlayer.StalledMedia == status: self.set_status_info("等待中...") elif QMediaPlayer.EndOfMedia == status: QApplication.alert(self) elif QMediaPlayer.InvalidMedia == status: self.display_error_message() @pyqtSlot(int) def buffering_progress(self, progress): if self.player.mediaStatus() == QMediaPlayer.StalledMedia: self.set_status_info("等待中 %d%%" % (progress, )) else: self.set_status_info("缓存中 %d%%" % (progress, )) def set_status_info(self, info): self.status_label.setText(info) def display_error_message(self): self.set_status_info(self.player.errorString()) def update_duration_info(self, current_info): s = time.strftime("%M:%S", time.gmtime(current_info)) t = "%s / %s" % (s, self.song.get_time()) self.duration_label.setText(t)
class VideoSortApp(QMainWindow, Ui_MainWindow, QWidget): def __init__(self): super(VideoSortApp, self).__init__() self.setupUi(self) self.filename = None self.directory = None self.sort.setEnabled(False) self.fileOpen.clicked.connect(self.fileDialog) self.dirOpen.clicked.connect(self.folderDialog) self.sort.clicked.connect(self.sortVideo) self.results.setViewMode(self.results.IconMode) self.results.setResizeMode(self.results.Adjust) self.features = [] self.sorted = None #player properties self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.playlist = QMediaPlaylist(self.player) self.videoItem = QGraphicsVideoItem() self.videoItem.setSize(QtCore.QSizeF(640, 480)) scene = QGraphicsScene(self) scene.addItem(self.videoItem) self.graphicsView.setScene(scene) self.player.setVideoOutput(self.videoItem) self.graphicsView.resize(640,480) self.graphicsView.show() self.results.itemDoubleClicked.connect(self.seekVideo) self.videoLoaded = False def sizeHint(self): return QtCore.QSize(640,480) def fileDialog(self): dialog = QFileDialog() if dialog.getOpenFileName: self.filename = dialog.getOpenFileName()[0] self.sort.setEnabled(True) def folderDialog(self): dialog = QFileDialog() if dialog.getExistingDirectory: self.directory = dialog.getExistingDirectory() self.sort.setEnabled(True) def sortVideo(self): dialog = QFileDialog() folder = dialog.getExistingDirectory(self, 'Select output directory for thumbnail images') if folder: if self.filename: self.getThread = VideoSort(self.filename, folder, 'frame') #self.results.setIconSize(QtCore.QSize(self.getThread.thumbInfo['resolution'][0], self.getThread.thumbInfo['resolution'][1])) #slot self.getThread.resultsSignal.connect(self.setFeatures) self.getThread.start() self.player.setMedia(QMediaContent(QtCore.QUrl.fromLocalFile(self.filename))) self.currentMedia = self.filename if self.directory: formatList = ['.mp4', '.mov', '.mkv', '.avi'] for dirname, dirnames, filenames in os.walk(self.directory): supportedFiles = [os.path.abspath(os.path.join(dirname, path)) for path in filenames if os.path.splitext(path)[1] in formatList] for filename in supportedFiles: self.getThread = VideoSort(filename, folder, os.path.splitext(filename.split('/')[-1])[0]) self.getThread.resultsSignal.connect(self.setFeatures) self.getThread.start() self.player.setMedia(QMediaContent(QtCore.QUrl.fromLocalFile(filename))) #Just set the last file as the current file self.player.setMedia(QMediaContent(QtCore.QUrl.fromLocalFile(filename))) self.currentMedia = filename def setFeatures(self, features): for feature in features: self.features.append(feature) self.hue.toggled.connect(self.displayResults) self.saturation.toggled.connect(self.displayResults) self.contours.toggled.connect(self.displayResults) def displayResults(self): self.results.clear() if self.hue.isChecked(): sortedFeatures = sorted(self.features, key=lambda res: res['hue']['std'], reverse=False) self.sorted = True if self.saturation.isChecked(): sortedFeatures = sorted(self.features, key=lambda res: res['sat']['std'], reverse=False) self.sorted = True if self.contours.isChecked(): sortedFeatures = sorted(self.features, key=lambda res: res['contours']['area'], reverse=False) self.sorted = True if self.sorted: for feature in sortedFeatures: icon = QtGui.QIcon(feature['thumbnail']) item = VideoListItem(icon, feature) self.results.addItem(item) def seekVideo(self, Qitem): #Need to write a callback function to only seek once player is loaded - provide loading media graphic or progress bar self.player.stop() print self.player.mediaStatus() if Qitem.feature['video'] != self.currentMedia: self.player.setMedia(QMediaContent(QtCore.QUrl.fromLocalFile(Qitem.feature['video']))) self.videoLoadProgress(self.player) self.currentMedia = Qitem.feature['video'] else: self.videoLoaded = True if self.videoLoaded: self.player.setPosition(Qitem.feature['milliseconds']) self.player.play() else: #set up progress bar here, or loading text def videoLoadProgress(self, QMediaPlayerObject): self.videoStatus = VideoLoadStatus(QMediaPlayerObject) self.videoStatus.videoLoaded.connect(self.getVideoStatus) def getVideoStatus(self, status): self.status = status
class DBPlayer(QWidget): # signal signaltxt = pyqtSignal(str) signalnum = pyqtSignal(int) def __init__(self): super(DBPlayer, self).__init__() self.setMaximumSize(16777215, 35) # Init Player self.messtitle = TITL_PROG self.namemedia = '' self.albumname = '' self.currentPlaylist = QMediaPlaylist() self.player = QMediaPlayer() self.player.stateChanged.connect(self.qmp_stateChanged) self.player.positionChanged.connect(self.qmp_positionChanged) self.player.volumeChanged.connect(self.qmp_volumeChanged) self.player.durationChanged.connect(self.qmp_durationChanged) self.player.setVolume(60) # Init GUI self.setLayout(self.addControls()) self.infoBox = None def addControls(self): # buttons self.playBtn = QPushButton() self.playBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playBtn.setStyleSheet('border: 0px;') stopBtn = QPushButton() stopBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaStop)) stopBtn.setStyleSheet('border: 0px;') prevBtn = QPushButton() prevBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaSkipBackward)) prevBtn.setStyleSheet('border: 0px;') nextBtn = QPushButton() nextBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaSkipForward)) nextBtn.setStyleSheet('border: 0px;') volumeDescBtn = QPushButton('▼') volumeDescBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaVolume)) volumeDescBtn.setMaximumWidth(30) volumeDescBtn.setStyleSheet('border: 0px;') volumeIncBtn = QPushButton('▲') volumeIncBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaVolume)) volumeIncBtn.setMaximumWidth(40) volumeIncBtn.setStyleSheet('border: 0px;') infoBtn = QPushButton() infoBtn.setIcon(self.style().standardIcon( QStyle.SP_FileDialogContentsView)) infoBtn.setStyleSheet('border: 0px;') # seek slider self.seekSlider = QSlider(Qt.Horizontal, self) self.seekSlider.setMinimum(0) self.seekSlider.setMaximum(100) self.seekSlider.setTracking(False) # labels position start/end self.seekSliderLabel1 = QLabel('0:00') self.seekSliderLabel2 = QLabel('0:00') # layout controlArea = QHBoxLayout() controlArea.addWidget(prevBtn) controlArea.addWidget(self.playBtn) controlArea.addWidget(stopBtn) controlArea.addWidget(nextBtn) controlArea.addWidget(self.seekSliderLabel1) controlArea.addWidget(self.seekSlider) controlArea.addWidget(self.seekSliderLabel2) controlArea.addWidget(infoBtn) controlArea.addWidget(volumeDescBtn) controlArea.addWidget(volumeIncBtn) # link buttons to media self.seekSlider.sliderMoved.connect(self.seekPosition) self.playBtn.clicked.connect(self.playHandler) stopBtn.clicked.connect(self.stopHandler) volumeDescBtn.clicked.connect(self.decreaseVolume) volumeIncBtn.clicked.connect(self.increaseVolume) prevBtn.clicked.connect(self.prevItemPlaylist) nextBtn.clicked.connect(self.nextItemPlaylist) infoBtn.clicked.connect(self.displaySongInfo) return controlArea def playHandler(self): if self.player.state() == QMediaPlayer.PlayingState: self.player.pause() message = (' [Paused at position %s]' % self.seekSliderLabel1.text()) self.messtitle = self.namemedia + message self.signaltxt.emit(self.messtitle) else: if self.player.state() == QMediaPlayer.StoppedState: if self.player.mediaStatus() == QMediaPlayer.NoMedia: if self.currentPlaylist.mediaCount() != 0: self.player.setPlaylist(self.currentPlaylist) elif self.player.mediaStatus() == QMediaPlayer.LoadedMedia: self.player.play() elif self.player.mediaStatus() == QMediaPlayer.BufferedMedia: self.player.play() elif self.player.state() == QMediaPlayer.PlayingState: pass elif self.player.state() == QMediaPlayer.PausedState: self.player.play() if self.player.volume() is not None and self.player.state( ) == QMediaPlayer.PlayingState: message = ' [Volume %d]' % self.player.volume() self.messtitle = self.namemedia + message self.signaltxt.emit(self.messtitle) def stopHandler(self): if self.player.state() == QMediaPlayer.PlayingState: self.stopState = True self.player.stop() elif self.player.state() == QMediaPlayer.PausedState: self.player.stop() elif self.player.state() == QMediaPlayer.StoppedState: pass if self.player.volume() is not None and self.player.state( ) == QMediaPlayer.PlayingState: self.messtitle = self.namemedia + (' [Stopped]') self.signaltxt.emit(self.messtitle) def qmp_stateChanged(self): if self.player.state() == QMediaPlayer.StoppedState: self.player.stop() # buttons icon play/pause change if self.player.state() == QMediaPlayer.PlayingState: self.playBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.playBtn.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) def qmp_positionChanged(self, position): # update position slider self.seekSlider.setValue(position) # update the text label self.seekSliderLabel1.setText( '%d:%02d' % (int(position / 60000), int((position / 1000) % 60))) def seekPosition(self, position): sender = self.sender() if isinstance(sender, QSlider): if self.player.isSeekable(): self.player.setPosition(position) def qmp_volumeChanged(self): if self.player.volume() is not None: message = (' [Playing at Volume %d]' % (self.player.volume())) if self.namemedia != '': self.messtitle = self.namemedia + message else: self.messtitle = "Initialisation player " + message self.signaltxt.emit(self.messtitle) def qmp_durationChanged(self, duration): self.seekSlider.setRange(0, duration) self.seekSliderLabel2.setText( '%d:%02d' % (int(duration / 60000), int((duration / 1000) % 60))) nummedia = self.currentPlaylist.mediaCount() curmedia = self.currentPlaylist.currentIndex() #artist = self.player.metaData(QMediaMetaData.Author) #tittle = self.player.metaData(QMediaMetaData.Title) self.namemedia = path.basename(self.homMed[curmedia]) self.namemedia = '[%02d/%02d' % ( curmedia + 1, nummedia) + '] "' + self.namemedia + '"' self.buildPlaylist() message = (' [Playing at Volume %d]' % (self.player.volume())) if self.player.volume() is not None and self.player.state( ) == QMediaPlayer.PlayingState: self.messtitle = self.namemedia + message self.signaltxt.emit(self.messtitle) def buildPlaylist(self): """Build play list.""" nummedia = self.currentPlaylist.mediaCount() curmedia = self.currentPlaylist.currentIndex() + 1 compteur = 1 self.textplaylist = '<b>' + self.albumname + '</b>' self.textplaylist += '<table class="tftable" border="0">' for namemedia in self.homMed: media = path.basename(namemedia) media = '[%02d/%02d' % (compteur, nummedia) + '] "' + media + '"' if curmedia == compteur: self.textplaylist += '<tr><td><b>' + media + '</b></td></tr>' else: self.textplaylist += '<tr><td>' + media + '</td></tr>' compteur += 1 self.textplaylist = self.textplaylist + '</table>' self.playBtn.setToolTip(self.textplaylist) self.signalnum.emit(curmedia - 1) def increaseVolume(self): """Volume +.""" vol = self.player.volume() vol = min(vol + 5, 100) self.player.setVolume(vol) def decreaseVolume(self): """Volume -.""" vol = self.player.volume() vol = max(vol - 5, 0) self.player.setVolume(vol) def prevItemPlaylist(self): self.player.playlist().previous() if self.currentPlaylist.currentIndex() == -1: self.player.playlist().previous() def nextItemPlaylist(self): self.player.playlist().next() if self.currentPlaylist.currentIndex() == -1: self.player.playlist().next() def addMediaslist(self, listmedias, position, albumname): if self.currentPlaylist.mediaCount() > 0: self.currentPlaylist.removeMedia(0, self.currentPlaylist.mediaCount()) self.player.stop() self.stopHandler() self.currentPlaylist.removeMedia(0, self.currentPlaylist.mediaCount()) self.albumname = albumname if listmedias: self.homMed = listmedias for media in self.homMed: self.currentPlaylist.addMedia( QMediaContent(QUrl.fromLocalFile(media))) self.currentPlaylist.setCurrentIndex(position) self.playHandler() def displaySongInfo(self): # extract datas metaDataKeyList = self.player.availableMetaData() fullText = '<table class="tftable" border="0">' for key in metaDataKeyList: value = str(self.player.metaData(key)).replace("'", "").replace( "[", "").replace("]", "") if key == 'Duration': value = '%d:%02d' % (int( int(value) / 60000), int((int(value) / 1000) % 60)) fullText = fullText + '<tr><td>' + key + '</td><td>' + value + '</td></tr>' fullText = fullText + '</table>' # re-init if self.infoBox is not None: self.infoBox.destroy() # infos box self.infoBox = QMessageBox(self) self.infoBox.setWindowTitle('Detailed Song Information') self.infoBox.setTextFormat(Qt.RichText) self.infoBox.addButton('OK', QMessageBox.AcceptRole) self.infoBox.setText(fullText) self.infoBox.show()
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] == "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 MediaWindow(QWidget): def __init__(self, stimulusWindow): super(MediaWindow, self).__init__() self.setFocusPolicy(Qt.StrongFocus) self.setStyleSheet(''' QWidget{ border-style: none; } ''') #self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint) self.showFullScreen() self.stimulusWindow = stimulusWindow stimulusWindow.showFullScreen() self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.videoProbe = QVideoProbe() self.videoProbe.videoFrameProbed.connect(self.onVideoFrame) self.videoProbe.setSource(self.mediaPlayer) self.graphicsVideoItem = QGraphicsVideoItem() self.graphicsScene = QGraphicsScene() self.graphicsView = QGraphicsView(self.graphicsScene) geom = stimulusWindow.geometry() self.graphicsView.setFixedSize(geom.width(), geom.height()) self.graphicsScene.addItem(self.graphicsVideoItem) self.graphicsView.setViewport(self.stimulusWindow) self.graphicsView.setViewportUpdateMode( QGraphicsView.FullViewportUpdate) print(self.graphicsView.contentsRect()) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.alignmentRect layout.addWidget(self.graphicsView) self.setLayout(layout) self.graphicsView.setFocusPolicy(Qt.NoFocus) self.graphicsView.viewport().installEventFilter(self) self.hide() #self.showFullScreen() self.ticker = None def eventFilter(self, object, event): if event.type() == QEvent.MouseMove: self.mouseMoveEvent(event) return False def playVideo(self, videoPath, duration): self.showFullScreen() url = QUrl.fromLocalFile(videoPath) self.mediaContent = QMediaContent(url) self.mediaPlayer.setVideoOutput(self.graphicsVideoItem) self.mediaPlayer.setMedia(self.mediaContent) self.stimulusWindow.measuredFrameInterval_s = self.stimulusWindow.expectedFrameInterval_s self.stimulusWindow.gracePeriodForFpsMeasurement = 60 print('mediaplayer: video start') print(self.mediaPlayer.mediaStatus()) self.timer.stop() self.mediaPlayer.play() self.framesToGo = duration print('frames to go: ' + str(self.framesToGo)) def stopVideo(self): #self.stimulusWindow.showFullScreen() print('mediaplayer: video stop') self.mediaPlayer.stop() self.timer.start() def onVideoFrame(self, frame): gears.onDisplayHidden() self.framesToGo = self.framesToGo - 1 if self.framesToGo == 0: self.stopVideo() def start(self, launcherWindow): print("Starting media window.") print(datetime.datetime.now().time()) self.launcherWindow = launcherWindow sequence = gears.getSequence().getPythonObject() self.expectedFrameInterval_s = sequence.getFrameInterval_s() self.measuredFrameInterval_s = self.expectedFrameInterval_s self.gracePeriodForFpsMeasurement = 60 if sequence.getUsesBusyWaitingThreadForSingals(): self.ticker = gears.startTicker() else: self.ticker = None self.timer = QTimer(self) self.timer.setInterval(0) self.timer.timeout.connect(self.onTimer) self.stimulusWindow.mediaWindow = self self.timer.start() self.firstFrame = True self.setFocus() print("Showing media window.") print(datetime.datetime.now().time()) self.showFullScreen() def stop(self): self.timer.stop() sequence = gears.getSequence().getPythonObject() if self.ticker: self.ticker.stop() self.launcherWindow.wake() QApplication.instance().processEvents() gears.reset() self.hide() self.lower() def onBufferSwap(self): if self.ticker: self.ticker.onBufferSwap() def onTimer(self): #print("Media window timer tick.") #print(datetime.datetime.now().time()) self.stimulusWindow.updateNative() def keyReleaseEvent(self, event): stimulus = gears.getCurrentStimulus().getPythonObject() try: for cb in stimulus.onKeyUp: cb(event) except AttributeError: pass def keyPressEvent(self, event): sequence = gears.getSequence().getPythonObject() if event.text() == 'q' or event.key() == Qt.Key_Escape: gears.skip(100000000) elif event.text() == 'f': self.showFps = not self.showFps elif event.key() == Qt.Key_Right or event.text() == 's': gears.skip(1) elif event.key() == Qt.Key_Left or event.text() == 'b': gears.skip(-1) elif event.text() == 'p' or event.text() == 'a': gears.pause() elif event.text() == 'y': gears.instantlyClearSignal(sequence.onKeySpikeChannel) gears.instantlyRaiseSignal(sequence.onKeySpikeChannel) elif event.text() == 'h': gears.instantlyRaiseSignal(sequence.onKeySpikeChannel) gears.instantlyClearSignal(sequence.onKeySpikeChannel) else: if event.text() == ' ': gears.setText("_____toggle info", "Press SPACE to hide this text.") gears.showText() stimulus = gears.getCurrentStimulus().getPythonObject() try: for cb in stimulus.onKey: cb(event) except AttributeError: pass def mouseMoveEvent(self, event): stimulus = gears.getCurrentStimulus().getPythonObject() try: for cb in stimulus.onMouse: cb(event) except AttributeError: pass def mousePressEvent(self, event): stimulus = gears.getCurrentStimulus().getPythonObject() try: for cb in stimulus.onMouseClick: cb(event) except AttributeError: pass def wheelEvent(self, event): stimulus = gears.getCurrentStimulus().getPythonObject() try: for cb in stimulus.onWheel: cb(event) except AttributeError: pass
class MainWindow(QMainWindow): markers_img: Image = None board_img: Image = None calibration_photo_files: np.ndarray = None calibration_info = property() _calib_info: CalibrationInfo = None video_files: np.ndarray = None player = None playlist = None video_position = pyqtSignal(int) def __init__(self, parent=None, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) uic.loadUi('./mainwindow.ui', self) self.setup_ui(self) self.connect_events() def setup_ui(self, window): self.gen_markers_arucoDict.addItems(ArucDict_dict.keys()) self.gen_markers_arucoDict.setCurrentIndex(0) self.gen_board_arucoDict.addItems(ArucDict_dict.keys()) self.gen_board_arucoDict.setCurrentIndex(0) self.calibrate_aruco_dict.addItems(ArucDict_dict.keys()) self.calibrate_aruco_dict.setCurrentIndex(0) self.gen_marker_Gview = widgets_ext.MyPicBox(self.gen_marker_Gview) self.gen_board_Gview = widgets_ext.MyPicBox(self.gen_board_Gview) self.calibrate_Gview = widgets_ext.MyPicBox(self.calibrate_Gview) self.calibrate_photo_list.setSelectionMode( QAbstractItemView.SingleSelection) self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.player.setVideoOutput(self.video) self.player.mediaStatusChanged.connect(self.print_status) # self.playlist = QMediaPlaylist(self.player) # self.player.setPlaylist(self.playlist) def connect_events(self): self.gen_markers_run_btn.clicked.connect(self.gen_markers_and_show) self.gen_markers_save_btn.clicked.connect(self.gen_markers_save) self.gen_board_run_btn.clicked.connect(self.gen_board_and_show) self.gen_board_save_btn.clicked.connect(self.gen_board_save) self.calibrate_load_photo.clicked.connect(self.load_photo_dir) self.calibrate_photo_list.itemSelectionChanged.connect( self.on_calibration_photo_selected) self.calibrate_start_btn.clicked.connect(self.calibrate_start) self.calibrate_load_settings.clicked.connect(self.load_settings) self.calibrate_save_settings.clicked.connect(self.save_settings) self.video_tracking_load_video_bnt.clicked.connect( self.load_videos_dir) self.video_tracking_list.itemSelectionChanged.connect( self.on_video_file_selected) self.play_btn.clicked.connect(self.player.play) self.pause_btn.clicked.connect(self.player.pause) self.stop_btn.clicked.connect(self.player.stop) # self.video_position.connect(self.player.position) # self.video_position.connect(self.video_slider.setValue) @calibration_info.getter def calibration_info(self): return self._calib_info @calibration_info.setter def calibration_info(self, value: CalibrationInfo): self._calib_info = value if value is None: return self.calibration_status.setText("Да") r = self._calib_info.calib_photos_ratio r1, r2 = r.numerator, r.denominator self.calibration_ratio.setText(f"{r1}:{r2}") d = self._calib_info.aruco_dict found = False for name, dict in ArucDict_dict.items(): if dict == d: self.calibration_dictionary.setText(name) found = True break if not found and d is None: msg = "В калибровочной информации отсутствует словрь меток!" mbox = QMessageBox() mbox.setWindowTitle('Ошибка!') mbox.setText(msg) mbox.exec() self.calibration_info = None def gen_markers_and_show(self): key = self.gen_markers_arucoDict.currentText() aruco_dict = ArucDict_dict[key] markers_num = self.gen_markers_num.value() markers_size = self.gen_markers_size.value() print_dpi = self.gen_markers_dpi.value() try: img = TremResearcher.gen_marks(aruco_dict=aruco_dict, markers_num=markers_num, real_size_mm=markers_size, print_dpi=print_dpi) self.markers_img = img except Exception as ex: mbox = QMessageBox() mbox.setWindowTitle('Ошибка!') mbox.setText(str(ex)) mbox.exec() return MainWindow.show_img_on_view(img, self.gen_marker_Gview) def gen_markers_save(self): if self.markers_img is None: mbox = QMessageBox() mbox.setWindowTitle('Ошибка!') mbox.setText("Маркеры еще не сгенирированы.") mbox.exec() return file_name, _ = QFileDialog.getSaveFileName(self, 'Сохранить', filter='png(*.png)') if file_name is not None and file_name != "": self.markers_img.save(file_name) def gen_board_and_show(self): key = self.gen_board_arucoDict.currentText() aruco_dict = ArucDict_dict[key] resolution = self.gen_board_scr_w.value(), self.gen_board_scr_h.value() try: img = TremResearcher.gen_board(aruco_dict=aruco_dict, screen_resolution=resolution) self.board_img = img except Exception as ex: mbox = QMessageBox() mbox.setWindowTitle('Ошибка!') mbox.setText(str(ex)) mbox.exec() return MainWindow.show_img_on_view(img, self.gen_board_Gview) def gen_board_save(self): if self.board_img is None: mbox = QMessageBox() mbox.setWindowTitle('Ошибка!') mbox.setText("Маркеры еще не сгенирированы.") mbox.exec() return file_name, _ = QFileDialog.getSaveFileName(self, 'Сохранить', filter='png(*.png)') if file_name is not None and file_name != "": self.board_img.save(file_name) def load_photo_dir(self): dialog = QFileDialog() dialog.setWindowTitle('Выберете папку с калибровочными фотографиями') dialog.setAcceptMode(QFileDialog.AcceptOpen) dialog.setFileMode(QFileDialog.Directory) if dialog.exec_() == QFileDialog.Accepted: photo_dir: str = dialog.selectedFiles()[0] files = FilesHelper.photo_files(photo_dir) self.calibration_photo_files = files self.calibrate_photo_list.clear() self.calibrate_photo_list.addItems( [f.rsplit(OS_SLASH, 1)[1] for f in files]) def on_calibration_photo_selected(self): inx: QModelIndex = self.calibrate_photo_list.currentRow() file = self.calibration_photo_files[inx] pix = QPixmap(file) self.calibrate_Gview.setPixmap(pix) def calibrate_start(self): key = self.calibrate_aruco_dict.currentText() aruco_dict = ArucDict_dict[key] resolution = self.calibrate_screen_width.value(),\ self.calibrate_screem_height.value() screen_inches = self.calibrate_screen_inches.value() photos = self.calibration_photo_files try: calib = TremResearcher.calibrate_by_monitor_photo( aruco_dict, photos, resolution, screen_inches) self.calibration_info = calib except Exception as ex: mbox = QMessageBox() mbox.setWindowTitle('Ошибка!') mbox.setText(str(ex)) mbox.exec() else: mbox = QMessageBox() mbox.setWindowTitle('Сообщение') mbox.setText('Калибровка завершена.') mbox.exec() def load_settings(self): file_name, _ = QFileDialog.getOpenFileName(self, 'Открыть', filter='pkl(*.pkl)') if file_name is not None and file_name != "": calib = CalibrationInfo.load_calibration_info(file_name) self.calibration_info = calib def save_settings(self): file_name, _ = QFileDialog.getSaveFileName(self, 'Сохранить', filter='pkl(*.pkl)') if file_name is not None and file_name != "": self.calibration_info.save(file_name) @staticmethod def show_img_on_view(img: Image, view: widgets_ext.MyPicBox): p1 = ImageQt(img) p2 = QImage(p1) p3 = QPixmap(p2) view.setPixmap(QPixmap(p3)) def load_videos_dir(self): dialog = QFileDialog() dialog.setWindowTitle('Выберете папку с видеофайлами') dialog.setAcceptMode(QFileDialog.AcceptOpen) dialog.setFileMode(QFileDialog.Directory) if dialog.exec_() == QFileDialog.Accepted: photo_dir: str = dialog.selectedFiles()[0] files = FilesHelper.video_files(photo_dir) self.video_files = files self.video_tracking_list.clear() self.video_tracking_list.addItems( [f.rsplit(OS_SLASH, 1)[1] for f in files]) def on_video_file_selected(self): inx: QModelIndex = self.video_tracking_list.currentRow() file = self.video_files[inx] self.player.setMedia( QMediaContent(QUrl("https://www.youtube.com/watch?v=7cQ5n9j5Guo"))) #self.player.setMedia(QMediaContent(QUrl.fromLocalFile(file))) def print_status(self): print("Status changed to:", self.player.mediaStatus()) self.video_slider.setMaximum(self.player.duration())
class Player(QFrame): ''' 音乐播放器 TODO 歌词系统 ''' sig_music_status_changed = pyqtSignal(bool) def __init__(self, parent): super().__init__(parent) self.parent_widget = parent self.setObjectName('Player') self.set_UI() # if parent == None: # self.setWindowFlags(Qt.FramelessWindowHint) '''用于播放音乐的对象''' self.music_player = QMediaPlayer(self) self.music_player.setVolume(70) self.music_player.setObjectName('MusicPlayer') ''' 歌曲列表 列表要显示在播放器之外的地方,因此不能把父窗口设置成self ''' self.play_list = PlayList(parent) '''播放进度''' self.millionsecond = 0 self.second = 0 self.lyric_panel = LyricPanel() self.set_connections() def set_UI(self): self.setFrameShape(QFrame.NoFrame) self.setMinimumSize(1200, 80) self.setMaximumHeight(100) self.set_buttons() self.set_sliders() self.set_labels() self.set_layout() with open('.\\QSS\\player.qss', 'r') as file_obj: self.setStyleSheet(file_obj.read()) def set_buttons(self): ''' 创建按钮 '上一首'按钮、'播放'按钮、'暂停'按钮、'下一首'按钮、'静音'按钮、'恢复音量'按钮、'播放模式'按钮、'歌词'按钮、'播放列表'按钮 ''' self.previous_button = QPushButton(self) self.previous_button.setObjectName('PreviousButton') self.previous_button.setToolTip('上一首') self.play_button = QPushButton(self) self.play_button.setObjectName('PlayButton') self.play_button.setToolTip('播放') self.pause_button = QPushButton(self) self.pause_button.setObjectName('PauseButton') self.pause_button.setToolTip('暂停') self.pause_button.hide() self.next_button = QPushButton(self) self.next_button.setObjectName('NextButton') self.next_button.setToolTip('下一首') self.mute_button = QPushButton(self) self.mute_button.setObjectName('MuteButton') self.mute_button.setToolTip('静音') self.recover_button = QPushButton(self) self.recover_button.setObjectName('RecoverButton') self.recover_button.setToolTip('恢复音量') self.recover_button.hide() self.random_button = QPushButton(self) self.random_button.setObjectName('RandomButton') self.random_button.setToolTip('随机播放') #self.random_button.hide() self.loop_button = QPushButton(self) self.loop_button.setObjectName('LoopButton') self.loop_button.setToolTip('列表循环') self.loop_button.hide() self.repeat_button = QPushButton(self) self.repeat_button.setObjectName('RepeatButton') self.repeat_button.setToolTip('单曲循环') self.repeat_button.hide() self.show_lyric_button = QPushButton(self) self.show_lyric_button.setObjectName('ShowLyricButton') self.show_lyric_button.setText('词') self.show_lyric_button.setFont(QFont('YouYuan', 14)) self.show_lyric_button.setToolTip('打开歌词') self.hide_lyric_button = QPushButton(self) self.hide_lyric_button.setObjectName('HideLyricButton') self.hide_lyric_button.setText('词') self.hide_lyric_button.setFont(QFont('YouYuan', 14)) self.hide_lyric_button.setToolTip('关闭歌词') self.hide_lyric_button.hide() self.list_button = QPushButton(self) self.list_button.setObjectName('ListButton') self.list_button.setToolTip('播放列表') def set_sliders(self): ''' 创建滑块 播放进度条、音量控制条 ''' self.progress_slider = QSlider(self) self.progress_slider.setObjectName('ProgressSlider') self.progress_slider.setOrientation(Qt.Horizontal) self.progress_slider.setTracking(False) self.volume_slider = QSlider(self) self.volume_slider.setObjectName('VolumeSlider') self.volume_slider.setOrientation(Qt.Horizontal) self.volume_slider.setRange(0, 100) self.volume_slider.setValue(100) def set_labels(self): ''' 创建标签 当前播放时间、歌曲总时间 ''' self.time_label = QLabel(self) self.time_label.setObjectName('TimeLabel') self.time_label.setFont(QFont('YouYuan')) self.duration_label = QLabel(self) self.duration_label.setObjectName('DurationLabel') self.duration_label.setFont(QFont('YouYuan')) def set_layout(self): ''' 创建布局 ''' self.layout = QHBoxLayout() self.layout.setObjectName('Layout') self.layout.addWidget(self.previous_button) self.layout.addSpacing(10) self.layout.addWidget(self.play_button) self.layout.addWidget(self.pause_button) self.layout.addSpacing(10) self.layout.addWidget(self.next_button) self.layout.addSpacing(20) self.layout.addWidget(self.time_label) self.layout.addSpacing(10) self.layout.addWidget(self.progress_slider) self.layout.addSpacing(10) self.layout.addWidget(self.duration_label) self.layout.addSpacing(20) self.layout.addWidget(self.mute_button) self.layout.addWidget(self.recover_button) self.layout.addWidget(self.volume_slider) self.layout.addSpacing(20) self.layout.addWidget(self.loop_button) self.layout.addWidget(self.random_button) self.layout.addWidget(self.repeat_button) self.layout.addSpacing(20) self.layout.addWidget(self.show_lyric_button) self.layout.addWidget(self.hide_lyric_button) self.layout.addSpacing(20) self.layout.addWidget(self.list_button) self.layout.setStretchFactor(self.previous_button, 3) self.layout.setStretchFactor(self.play_button, 3) self.layout.setStretchFactor(self.pause_button, 3) self.layout.setStretchFactor(self.next_button, 3) self.layout.setStretchFactor(self.time_label, 2) self.layout.setStretchFactor(self.progress_slider, 25) self.layout.setStretchFactor(self.duration_label, 2) self.layout.setStretchFactor(self.mute_button, 2) self.layout.setStretchFactor(self.recover_button, 2) self.layout.setStretchFactor(self.volume_slider, 7) self.layout.setStretchFactor(self.loop_button, 2) self.layout.setStretchFactor(self.random_button, 2) self.layout.setStretchFactor(self.repeat_button, 2) # self.layout.setStretchFactor(self.show_lyric_button, 2) # self.layout.setStretchFactor(self.hide_lyric_button, 2) self.layout.setStretchFactor(self.list_button, 2) self.setLayout(self.layout) self.layout.setContentsMargins(20, 5, 20, 5) def set_connections(self): ''' 连接信号和槽 ''' self.previous_button.clicked.connect(self.on_previous_clicked) self.play_button.clicked.connect(self.on_play_clicked) self.pause_button.clicked.connect(self.on_pause_clicked) self.next_button.clicked.connect(self.on_next_clicked) self.random_button.clicked.connect(self.on_random_clicked) self.repeat_button.clicked.connect(self.on_repeat_clicked) self.loop_button.clicked.connect(self.on_loop_clicked) self.list_button.clicked.connect(self.on_list_clicked) self.mute_button.clicked.connect(self.on_mute_clicked) self.recover_button.clicked.connect(self.on_recover_clicked) self.show_lyric_button.clicked.connect(self.on_show_lyric_clicked) self.hide_lyric_button.clicked.connect(self.on_hide_lyric_clicked) self.music_player.durationChanged.connect(self.on_music_changed) self.music_player.positionChanged.connect( self.on_millionsecond_changed) self.music_player.positionChanged.connect( self.lyric_panel.on_millionsecond_changed) self.progress_slider.valueChanged.connect(self.on_progress_changed) self.volume_slider.valueChanged.connect(self.on_volume_changed) '''通过点击切歌''' self.play_list.sig_music_index_changed.connect( self.on_music_index_changed) '''播放状态改变,同时改变图标''' self.sig_music_status_changed.connect( self.play_list.on_music_status_changed) # self.play_button.clicked.connect(self.play_list.on_music_played) # self.pause_button.clicked.connect(self.play_list.on_music_paused) def on_random_clicked(self): self.random_button.hide() self.repeat_button.show() self.play_list.set_play_mode(PlayMode.REPEAT) def on_repeat_clicked(self): self.repeat_button.hide() self.loop_button.show() self.play_list.set_play_mode(PlayMode.LOOP) def on_loop_clicked(self): self.loop_button.hide() self.random_button.show() self.play_list.set_play_mode(PlayMode.RANDOM) def on_list_clicked(self): if self.play_list.isVisible(): self.play_list.hide() else: self.set_list_geometry() self.play_list.show() self.play_list.raise_() def on_previous_clicked(self): content = self.play_list.previous_music() self.play_music(content) if content: self.play_button.hide() self.pause_button.show() self.sig_music_status_changed.emit(False) def on_play_clicked(self): flag = True if self.music_player.mediaStatus() == QMediaPlayer.NoMedia: '''检查播放器中是否有歌曲''' content = self.play_list.get_music() if content == None: '''歌单中没有歌曲''' flag = False self.play_music(content) else: self.play_music() if flag: self.play_button.hide() self.pause_button.show() self.sig_music_status_changed.emit(False) if self.lyric_panel.isVisible(): self.lyric_panel.restart_lyric() def on_pause_clicked(self): self.music_player.pause() self.pause_button.hide() self.play_button.show() self.sig_music_status_changed.emit(True) if self.lyric_panel.isVisible(): self.lyric_panel.pause_lyric() def on_next_clicked(self): content = self.play_list.next_music() self.play_music(content) if content: self.play_button.hide() self.pause_button.show() self.sig_music_status_changed.emit(False) def on_mute_clicked(self): self.music_player.setMuted(True) self.mute_button.hide() self.recover_button.show() def on_recover_clicked(self): self.music_player.setMuted(False) self.recover_button.hide() self.mute_button.show() def on_music_changed(self): self.time_label.setText(utils.time_int_to_str(0)) total_time = self.music_player.duration() // 1000 if total_time > 0: self.duration_label.setText(utils.time_int_to_str(total_time)) '''处理没有连接的异常''' try: self.progress_slider.valueChanged.disconnect( self.on_progress_changed) self.progress_slider.setRange(0, total_time) self.progress_slider.setValue(0) self.progress_slider.valueChanged.connect( self.on_progress_changed) except TypeError: self.progress_slider.setRange(0, total_time) self.progress_slider.setValue(0) if self.lyric_panel.isVisible(): lyric, title = self.play_list.get_lyric_and_title() current_time = 0 total_time = self.music_player.duration() self.lyric_panel.show_lyric(lyric, title, current_time, total_time) def on_millionsecond_changed(self, current_position): self.millionsecond = current_position current_position = current_position // 1000 if current_position != self.second: self.second = current_position self.on_second_changed() def on_second_changed(self): self.time_label.setText(utils.time_int_to_str(self.second)) '''处理没有连接的异常,disconnect和connect必须配对使用,否则听歌体验极差''' try: self.progress_slider.valueChanged.disconnect( self.on_progress_changed) self.increase_progress() self.progress_slider.valueChanged.connect(self.on_progress_changed) except TypeError: self.increase_progress() def on_progress_changed(self, progress): ratio = progress / self.progress_slider.maximum() position = int(self.music_player.duration() * ratio) self.music_player.setPosition(position) def on_volume_changed(self, volume): '''播放器原本的音量较大,这里稍微减少一些''' volume = int(volume / 100 * 70) self.music_player.setVolume(volume) '''用户拖动音量条,自动从静音中恢复''' self.on_recover_clicked() def on_music_index_changed(self): ''' 播放列表中正在播放的歌曲切换了 有可能是通过点击播放列表切歌 也有可能是播放新加入的歌曲 ''' content = self.play_list.get_music() self.play_music(content) self.pause_button.show() self.play_button.hide() self.sig_music_status_changed.emit(False) def on_show_lyric_clicked(self): self.show_lyric_button.hide() self.hide_lyric_button.show() if self.music_player.mediaStatus() != QMediaPlayer.NoMedia: lyric, title = self.play_list.get_lyric_and_title() current_time = self.millionsecond total_time = self.music_player.duration() self.lyric_panel.show_lyric(lyric, title, current_time, total_time) else: self.lyric_panel.show_lyric(None, None, None, None) def on_hide_lyric_clicked(self): self.hide_lyric_button.hide() self.show_lyric_button.show() self.lyric_panel.hide_lyric() def moveEvent(self, event): self.set_list_geometry() def increase_progress(self): '''进度增加1''' value = self.progress_slider.value() value += 1 if value > self.progress_slider.maximum(): self.on_next_clicked() else: self.progress_slider.setValue(value) def play_music(self, content=None): if content: self.music_player.setMedia(content) self.music_player.play() def set_list_geometry(self): x = self.x() + self.width() - self.play_list.width() y = self.y() - self.play_list.height() self.play_list.move(x, y)
class PMusic(QWidget): '''central widget''' DEFAULT_IMG = '/usr/share/pmusic/pMusic.png' def __init__(self, parent): '''initialize instance''' super().__init__(parent) self.player = QMediaPlayer() self.player.mediaStatusChanged.connect(self.onmedia_status_changed) self.playlist = QMediaPlaylist() self.playlist.setPlaybackMode(QMediaPlaylist.Loop) self.player.setVolume(100) self.resize(parent.width(), parent.height()) self.setContentsMargins(0, 0, 0, 0) self.current_albumart = '' pixmap = QPixmap(PMusic.DEFAULT_IMG) self.img_label = PImage(self, pixmap) self.img_label.resize(self.width(), self.height()) self.img_label.clicked.connect(self.onclick_img_label) self.buttonbar = PButtonBar(self) self.buttonbar.hide() # position: at the bottom self.buttonbar.move(0, self.height() - self.buttonbar.height()) self.buttonbar.clicked_left.connect(self.onclick_prev) self.buttonbar.clicked_mid.connect(self.onclick_main) self.buttonbar.clicked_right.connect(self.onclick_next) # toggle button for shuffle self.shufflebutton = QPushButton(self) self.shufflebutton.hide() self.shufflebutton.setCheckable(True) self.shufflebutton.setText('S') # position: top left corner button_size = int(self.width() * 0.2) self.shufflebutton.setGeometry(0, 0, button_size, button_size) self.shufflebutton.clicked.connect(self.onclick_shuffle) self.quitbutton = QPushButton(self) self.quitbutton.hide() self.quitbutton.setStyleSheet('color: rgb(240, 0, 0)') # red self.quitbutton.setFont(QFont('webdings', 10)) self.quitbutton.setText('r') # cross # position: top right corner self.quitbutton.setGeometry(self.width() - button_size, 0, button_size, button_size) self.quitbutton.clicked.connect(self.onclick_quit) self.show() def enterEvent(self, event): '''on mouse enter, show the buttons''' super().enterEvent(event) self.buttonbar.show() self.shufflebutton.show() self.quitbutton.show() def leaveEvent(self, event): '''on mouse leave, hide the buttons''' super().leaveEvent(event) self.buttonbar.hide() self.shufflebutton.hide() self.quitbutton.hide() @pyqtSlot() def onclick_shuffle(self): '''shuffle button was toggled''' if self.shufflebutton.isChecked(): debug('shuffle: on') self.playlist.setPlaybackMode(QMediaPlaylist.Random) else: debug('shuffle: off') self.playlist.setPlaybackMode(QMediaPlaylist.Loop) @pyqtSlot() def onclick_quit(self): '''quit button was clicked''' debug('quit') self.stop() self.parent().close() @pyqtSlot() def onclick_img_label(self): '''image label was clicked''' debug('onclick_img_label') self.pause() @pyqtSlot() def onclick_prev(self): '''back button was pressed''' debug('onclick_prev') self.playlist.previous() if self.player.state() != QMediaPlayer.PlayingState: debug('player.state == {}'.format(self.player.state())) self.play() @pyqtSlot() def onclick_next(self): '''next button was pressed''' debug('onclick_next') self.playlist.next() if self.player.state() != QMediaPlayer.PlayingState: debug('player.state == {}'.format(self.player.state())) self.play() @pyqtSlot() def onclick_main(self): '''main button was pressed''' debug('onclick_main') # bring up directory selection dialog # have a preference for $HOME/Music/ try: homedir = os.environ['HOME'] if not os.path.isdir(homedir): homedir = os.path.curdir except KeyError: homedir = os.path.curdir music_dir = os.path.join(homedir, 'Music') if not os.path.isdir(music_dir): music_dir = os.path.curdir path = QFileDialog.getExistingDirectory(self, 'Select directory', music_dir, QFileDialog.ShowDirsOnly) debug('path == [{}]'.format(path)) if not path: # cancel return self.stop() self.load_playlist(path) self.play() def onmedia_status_changed(self): '''media changed; player switched to next song''' debug('onmedia_status_changed') debug('player.state == {}'.format(self.player.state())) debug('player.mediastate == {}'.format(self.player.mediaStatus())) # we want to load albumart if the song is in another directory # and display filename on stdout or console log # this is only relevant if the QMediaPlayer is now loading new media if self.player.mediaStatus() == QMediaPlayer.LoadingMedia: media = self.player.currentMedia() if media.isNull(): debug('media isNull') return filename = media.canonicalUrl().path() debug('current media == [{}]'.format(filename)) # make a short path for informational message short_path = filename try: homedir = os.environ['HOME'] + os.path.sep if short_path.startswith(homedir): short_path = filename[len(homedir):] except KeyError: pass if short_path.startswith('Music/'): short_path = short_path[len('Music/'):] print('now playing: {}'.format(short_path)) folder = os.path.dirname(filename) self.load_albumart(folder) elif self.player.mediaStatus() == QMediaPlayer.NoMedia: debug('no media present, change albumart to default image') # change to default image pixmap = QPixmap(PMusic.DEFAULT_IMG) self.img_label.setPixmap(pixmap) self.current_albumart = '' def load_playlist(self, path): '''load new playlist''' debug('load playlist') self.playlist.clear() # Note: not actually sure these formats are all supported ... files = QDirIterator(path, ['*.mp3', '*.ogg', '*.wav', '*.flac'], flags=QDirIterator.Subdirectories) while files.hasNext(): filename = files.next() debug('+ {}'.format(filename)) url = QUrl.fromLocalFile(filename) if not self.playlist.addMedia(QMediaContent(url)): debug('addMedia() => False') self.player.setPlaylist(self.playlist) def load_albumart(self, path): '''load album art''' debug('load albumart, path == {}'.format(path)) # load album art found = False for name in ('cover.jpg', 'Folder.jpg', 'folder.jpg', 'cover.png', 'AlbumArt.jpg', 'AlbumArtSmall.jpg'): filename = os.path.join(path, name) if os.path.isfile(filename): found = True if filename == self.current_albumart: debug('same albumart, already loaded') break debug('loading albumart {}'.format(filename)) pixmap = QPixmap(filename) self.img_label.setPixmap(pixmap) self.current_albumart = filename break if not found: if not self.current_albumart: debug('no albumart found, keeping default image') else: # put default image debug('no albumart found, putting default image') pixmap = QPixmap(PMusic.DEFAULT_IMG) self.img_label.setPixmap(pixmap) self.current_albumart = '' def stop(self): '''stop playing''' debug('stop') self.player.stop() def play(self): '''start playing''' debug('play()') self.player.play() def pause(self): '''pause playing''' if self.player.state() == QMediaPlayer.PlayingState: debug('pause') self.player.pause() elif self.player.state() in (QMediaPlayer.StoppedState, QMediaPlayer.PausedState): self.player.play()
class VideoWindow(QMainWindow): def __init__(self, parent=None): super(VideoWindow, self).__init__(parent) self.readConfig() self.setWindowTitle("Endless Reddit Player") self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) videoWidget = QVideoWidget() self.data = requests.get( f'https://www.reddit.com/r/{self.subreddit}/{self.sortby}.json?limit=100', headers={ 'User-agent': 'endless video bot uwu' }).json() self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.skipButton = QPushButton() self.skipButton.setEnabled(True) self.skipButton.setIcon(self.style().standardIcon( QStyle.SP_MediaSkipForward)) self.skipButton.clicked.connect(self.selectNewVideo) self.positionSlider = QSlider(Qt.Horizontal) self.positionSlider.setRange(0, 0) self.positionSlider.sliderMoved.connect(self.setPosition) self.errorLabel = QLabel() self.errorLabel.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) # Create new action openAction = QAction(QIcon('open.png'), '&Open', self) openAction.setShortcut('Ctrl+O') openAction.setStatusTip('Open movie') openAction.triggered.connect(self.openFile) # Create exit action exitAction = QAction(QIcon('exit.png'), '&Exit', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Exit application') exitAction.triggered.connect(self.exitCall) # Create menu bar and add action menuBar = self.menuBar() fileMenu = menuBar.addMenu('&File') #fileMenu.addAction(newAction) fileMenu.addAction(openAction) fileMenu.addAction(exitAction) # Create a widget for window contents wid = QWidget(self) self.setCentralWidget(wid) # Create layouts to place inside widget controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) controlLayout.addWidget(self.playButton) controlLayout.addWidget(self.skipButton) controlLayout.addWidget(self.positionSlider) layout = QVBoxLayout() layout.addWidget(videoWidget) layout.addLayout(controlLayout) layout.addWidget(self.errorLabel) # Set widget to contain window contents wid.setLayout(layout) self.mediaPlayer.setVideoOutput(videoWidget) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.mediaStatusChanged.connect(self.mediaStatusChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.error.connect(self.handleError) def readConfig(self): with open('config.json', 'r') as file: config = json.load(file) self.subreddit = config['subreddit'] self.sortby = config['sortby'] self.offlineMode = config['offlineMode'] def openFile(self): fileName, _ = QFileDialog.getOpenFileName(self, "Open Movie", QDir.homePath()) if fileName != '': self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(fileName))) self.playButton.setEnabled(True) def exitCall(self): sys.exit(app.exec_()) def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) def mediaStatusChanged(self, status): if self.mediaPlayer.mediaStatus() == QMediaPlayer.EndOfMedia: self.mediaPlayer.pause() self.selectNewVideo() def positionChanged(self, position): self.positionSlider.setValue(position) def durationChanged(self, duration): self.positionSlider.setRange(0, duration) def setPosition(self, position): self.mediaPlayer.setPosition(position) def handleError(self): self.playButton.setEnabled(False) self.errorLabel.setText("Error: " + self.mediaPlayer.errorString()) def selectNewVideo(self): if len(self.data['data']['children']) == 0: if (self.data["data"]["after"]): self.data = requests.get( f'https://www.reddit.com/r/{self.subreddit}/{self.sortby}.json?limit=100&after={self.data["data"]["after"]}', headers={ 'User-agent': 'endless video bot uwu' }).json() else: self.data = requests.get( f'https://www.reddit.com/r/{self.subreddit}/{self.sortby}.json?limit=100', headers={ 'User-agent': 'endless video bot uwu' }).json() number = random.randrange(len(self.data['data']['children'])) if self.data['data']['children'][number]['data']['is_video']: self.url = self.data['data']['children'][number]['data']['media'][ 'reddit_video']['fallback_url'] print("selected next: " + self.url + ", " + str(len(self.data['data']['children'])) + " left before rescan.") self.mediaPlayer.setMedia(QMediaContent(QUrl(self.url))) self.playButton.setEnabled(True) self.mediaPlayer.play() del self.data['data']['children'][number] else: del self.data['data']['children'][number] self.selectNewVideo()
class Music(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.setFixedSize(400,200) self.setWindowTitle("🎧+📚=😊") self.setWindowOpacity(0.8) self.init_ui() self.custom_style() self.play_status = False # 播放状态初始化为否 self.player = QMediaPlayer(self) self.timer = QtCore.QTimer() self.timer.setInterval(1000) self.timer.start() self.timer.timeout.connect(self.check_music_status) # 设置样式 def custom_style(self): self.setStyleSheet(''' #main_widget{ border-radius:5px; background:black; } #play_btn,#pervious_btn,#next_btn{ border:none; } #play_btn:hover,#pervious_btn:hover,#next_btn:hover{ background: #696969; border-radius:5px; cursor:pointer; } ''') self.close_btn.setStyleSheet(''' QPushButton{ background:#F76677; border-radius:5px; } QPushButton:hover{ background:red; }''') self.status_label.setStyleSheet(''' QLabel{ background:#FFD85A; border-radius:5px; } ''') def init_ui(self): # 窗口布局 self.main_widget = QtWidgets.QWidget() self.main_widget.setObjectName("main_widget") self.main_layout = QtWidgets.QGridLayout() self.main_widget.setLayout(self.main_layout) # 标题 半成,接口部分未找到适合的 ''' slogan=requests.get('https://api.xygeng.cn/one').json()['data']['content'] self.title_lable = QtWidgets.QLabel(slogan) self.title_lable.setFont(font) ''' self.title_lable = QtWidgets.QLabel('🌥WindPlayer') self.title_lable.setStyleSheet(''' QLabel{ color:"gray"; } ''') self.title_lable.setFont(font) self.title_lable.setAlignment(QtCore.Qt.AlignCenter) # 关闭按钮 self.close_btn = QtWidgets.QPushButton("") # 关闭按钮 self.close_btn.clicked.connect(self.close_btn_event) self.close_btn.setFixedSize(15,15) # 音乐状态按钮 self.status_label = QtWidgets.QLabel("") # self.swith_btn.clicked.connect(self.swith_background) #此处还未完成 Darkmode 和 LightMode 的切换 self.status_label.setFixedSize(15,15) # 播放按钮 play_icon = qta.icon("fa.play-circle-o",) self.play_btn = QtWidgets.QPushButton(play_icon,"") self.play_btn.setIconSize(QtCore.QSize(80, 80)) self.play_btn.setFixedSize(82,82) self.play_btn.setObjectName("play_btn") self.play_btn.clicked.connect(self.play_music) self.play_btn.setStyleSheet(''' QPushButton{ background:black; border-radius:5px; } QPushButton:hover{ background: #696969; }''') # 下一首按钮 next_icon = qta.icon("fa.chevron-right") self.next_btn = QtWidgets.QPushButton(next_icon,"") self.next_btn.setIconSize(QtCore.QSize(80,80)) self.next_btn.setFixedSize(82,82) self.next_btn.setObjectName("next_btn") self.next_btn.clicked.connect(self.next_music) self.next_btn.setStyleSheet(''' QPushButton{ background:black; border-radius:5px; } QPushButton:hover{ background: #696969; }''') # 进度条 self.process_bar = QtWidgets.QProgressBar() self.process_value = 0 self.process_bar.setValue(self.process_value) self.process_bar.setFixedHeight(5) self.process_bar.setTextVisible(False) self.process_bar.setStyleSheet('''QProgressBar { border: 2px solid grey; border-radius: 5px; background-color: #FFFFFF;}QProgressBar::chunk { background-color: #05B8CC; width: 28px;}QProgressBar { border: 2px solid grey; border-radius: 5px; text-align: center;} ''') self.main_layout.addWidget(self.close_btn,0,0,1,1) self.main_layout.addWidget(self.title_lable,0,1,1,1) self.main_layout.addWidget(self.status_label,1,0,1,1) self.main_layout.addWidget(self.play_btn, 1, 1, 1, 1) self.main_layout.addWidget(self.next_btn, 1, 2, 1, 1) self.main_layout.addWidget(self.process_bar,2,0,1,3) self.setCentralWidget(self.main_widget) self.setWindowFlag(QtCore.Qt.FramelessWindowHint) # 隐藏边框 # 关闭程序 def close_btn_event(self): self.close() # 夜间模式切换 (未完成 ) def swich_background(self): self.main_widget.setStyleSheet(''' QWidget{ "background-color: black"} ''') # 鼠标长按事件 def mousePressEvent(self, event): if event.button() == QtCore.Qt.LeftButton: self.m_drag = True self.m_DragPosition = event.globalPos() - self.pos() event.accept() self.setCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor)) # 鼠标移动事件 def mouseMoveEvent(self, QMouseEvent): if QtCore.Qt.LeftButton and self.m_drag: self.move(QMouseEvent.globalPos() - self.m_DragPosition) QMouseEvent.accept() # 鼠标释放事件 def mouseReleaseEvent(self, QMouseEvent): self.m_drag = False self.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) # 播放音乐 def play_music(self): try: # 播放音乐 if self.play_status is False: self.play_status = True # 设置播放状态为是 self.play_btn.setIcon(qta.icon("fa.pause-circle")) # 设置播放图标 player_status = self.player.mediaStatus() # 获取播放器状态 # print("当前播放状态:",player_status) if player_status == 6: # 设置状态标签为绿色 self.status_label.setStyleSheet('''QLabel{background:#72EA72;border-radius:5px;}''') self.player.play() else: self.next_music() # 暂停音乐 else: # 设置状态为蓝色 self.status_label.setStyleSheet('''QLabel{background:#0099CC;border-radius:5px;}''') self.play_status = False self.play_btn.setIcon(qta.icon("fa.play-circle")) self.player.pause() except Exception as e: print(repr(e)) # 下一首音乐 def next_music(self): try: # 设置状态为黄色 self.status_label.setStyleSheet(''' QLabel{ background:#FFBF00; border-radius:5px; } ''') self.play_status = True # 设置播放状态为是 self.play_btn.setIcon(qta.icon("fa.pause-circle")) # 修改播放图标 self.process_value = 0 # 重置进度值 # 获取网络歌曲 self.get_music_thread = GetMusicThread() self.get_music_thread.finished_signal.connect(self.init_player) self.get_music_thread.start() except Exception as e: print(traceback.print_exc()) # 设置播放器 def init_player(self,url): # print("获取到音乐链接:",url) content = QMediaContent(QtCore.QUrl(url)) self.player.setMedia(content) self.player.setVolume(50) self.player.play() self.duration = self.player.duration() # 音乐的时长 # 设置状态为绿色 self.status_label.setStyleSheet(''' QLabel{ background:#72EA72; border-radius:5px; } ''') # 进度条计时器 self.process_timer = QtCore.QTimer() self.process_timer.setInterval(1000) self.process_timer.start() self.process_timer.timeout.connect(self.process_timer_status) # 定时器 def check_music_status(self): player_status = self.player.mediaStatus() player_duration = self.player.duration() # print("音乐时间:",player_duration) # print("当前播放器状态",player_status) if player_status == 7: self.next_music() if player_duration > 0: self.duration = player_duration # 进度条定时器 def process_timer_status(self): try: if self.play_status is True: self.process_value +=float(100 / (self.duration/1000)) #print("当前进度:",self.process_value) self.process_bar.setValue(self.process_value) except Exception as e: print('')
class MainWindowMusicPlayer(QMainWindow): stopState: bool def __init__(self): super().__init__() self.currentPlaylist = QMediaPlaylist() self.player = QMediaPlayer() self.userAction = -1 # 0 - stopped, 1 - playing 2 - paused self.player.mediaStatusChanged.connect(self.qmp_media_status_changed) self.player.stateChanged.connect(self.qmp_state_changed) self.player.positionChanged.connect(self.qmp_position_changed) self.player.volumeChanged.connect(self.qmp_volume_changed) self.player.setVolume(60) # Status bar self.statusBar().showMessage('No Media' ' :: %d' % self.player.volume()) self.home_screen() def home_screen(self): self.setWindowTitle('Music Player') self.create_menubar() self.create_toolbar() controlBar = self.add_controls() # need to add both information screen # and control bar to the central widget. centralWidget = QWidget() centralWidget.setLayout(controlBar) self.setCentralWidget(centralWidget) # Set size of the MainWindow self.resize(200, 100) self.show() def create_menubar(self): menubar = self.menuBar() file_menu = menubar.addMenu('File') file_menu.addAction(self.file_open()) file_menu.addAction(self.song_info()) file_menu.addAction(self.folder_open()) file_menu.addAction(self.exit_action()) def create_toolbar(self): pass def add_controls(self): controlArea = QVBoxLayout() seekSliderLayout = QHBoxLayout() controls = QHBoxLayout() playlistCtrlLayout = QHBoxLayout() # creating buttons playBtn = QPushButton('Play') # play button pauseBtn = QPushButton('Pause') # pause button stopBtn = QPushButton('Stop') # stop button volumeDescBtn = QPushButton('V (-)') # Decrease Volume volumeIncBtn = QPushButton('V (+)') # Increase Volume # creating playlist controls prevBtn = QPushButton('Prev Song') nextBtn = QPushButton('Next Song') # creating seek slider seekSlider = QSlider() seekSlider.setMinimum(0) seekSlider.setMaximum(100) seekSlider.setOrientation(Qt.Horizontal) seekSlider.setTracking(False) seekSlider.sliderMoved.connect(self.seek_position) # seekSlider.valueChanged.connect(self.seekPosition) seekSliderLabel1 = QLabel('0.00') seekSliderLabel2 = QLabel('0.00') seekSliderLayout.addWidget(seekSliderLabel1) seekSliderLayout.addWidget(seekSlider) seekSliderLayout.addWidget(seekSliderLabel2) # Add handler for each button. Not using the default slots. playBtn.clicked.connect(self.play_handler) pauseBtn.clicked.connect(self.pause_handler) stopBtn.clicked.connect(self.stop_handler) volumeDescBtn.clicked.connect(self.decrease_volume) volumeIncBtn.clicked.connect(self.increase_volume) # Adding to the horizontal layout controls.addWidget(volumeDescBtn) controls.addWidget(playBtn) controls.addWidget(pauseBtn) controls.addWidget(stopBtn) controls.addWidget(volumeIncBtn) # playlist control button handlers prevBtn.clicked.connect(self.prev_item_playlist) nextBtn.clicked.connect(self.next_item_playlist) playlistCtrlLayout.addWidget(prevBtn) playlistCtrlLayout.addWidget(nextBtn) # Adding to the vertical layout controlArea.addLayout(seekSliderLayout) controlArea.addLayout(controls) controlArea.addLayout(playlistCtrlLayout) return controlArea # Music playback function def play_handler(self): self.userAction = 1 self.statusBar().showMessage('Playing at Volume %d' % self.player.volume()) if self.player.state() == QMediaPlayer.StoppedState: if self.player.mediaStatus() == QMediaPlayer.NoMedia: print(self.currentPlaylist.mediaCount()) if self.currentPlaylist.mediaCount() == 0: self.open_file() if self.currentPlaylist.mediaCount() != 0: self.player.setPlaylist(self.currentPlaylist) elif self.player.mediaStatus() ==\ QMediaPlayer.LoadedMedia: self.player.play() elif self.player.mediaStatus() ==\ QMediaPlayer.BufferedMedia: self.player.play() elif self.player.state() == QMediaPlayer.PlayingState: pass elif self.player.state() == QMediaPlayer.PausedState: self.player.play() # Music pause function def pause_handler(self): self.userAction = 2 self.statusBar().showMessage( 'Paused %s at position' ' %s at Volume %d' % (self.player.metaData(QMediaMetaData.Title), self.centralWidget().layout().itemAt(0).layout().itemAt( 0).widget().text(), self.player.volume())) self.player.pause() # Music stop function def stop_handler(self): self.userAction = 0 self.statusBar().showMessage('Stopped at Volume %d' % (self.player.volume())) if self.player.state() == QMediaPlayer.PlayingState: self.stopState = True self.player.stop() elif self.player.state() == QMediaPlayer.PausedState: self.player.stop() elif self.player.state() == QMediaPlayer.StoppedState: pass # Music status change function def qmp_media_status_changed(self): if self.player.mediaStatus() == QMediaPlayer.LoadedMedia \ and self.userAction == 1: durationT = self.player.duration() self.centralWidget().layout().itemAt(0).layout() \ .itemAt(1).widget().setRange(0, durationT) self.centralWidget().layout().itemAt(0).layout() \ .itemAt(2).widget().setText( '%d:%02d' % (int(durationT / 60000), int((durationT / 1000) % 60))) self.player.play() # Music playing change function def qmp_state_changed(self): if self.player.state() == QMediaPlayer.StoppedState: self.player.stop() # Music time change function def qmp_position_changed(self, position, senderType=False): sliderLayout = self.centralWidget().layout().itemAt(0)\ .layout() if not senderType: sliderLayout.itemAt(1).widget().setValue(position) # update the text label sliderLayout.itemAt(0).widget()\ .setText('%d:%02d' % (int(position / 60000), int((position / 1000) % 60))) def seek_position(self, position): sender = self.sender() if isinstance(sender, QSlider): if self.player.isSeekable(): self.player.setPosition(position) # Music volume change function def qmp_volume_changed(self): msg = self.statusBar().currentMessage() msg = msg[:-2] + str(self.player.volume()) self.statusBar().showMessage(msg) # Music volume + change function def increase_volume(self): vol = self.player.volume() vol = min(vol + 5, 100) self.player.setVolume(vol) # Music volume - change function def decrease_volume(self): vol = self.player.volume() vol = max(vol - 5, 0) self.player.setVolume(vol) # File open function def file_open(self): fileAc = QAction(QIcon('icons\\open.png'), 'Open File', self) fileAc.setShortcut('Ctrl+O') fileAc.setStatusTip('Open File') fileAc.triggered.connect(self.open_file) return fileAc # File opening function def open_file(self): file_Chosen = QFileDialog.getOpenFileUrl(self, 'Open Music File', expanduser('~'), 'Audio (*.mp3 *.ogg *.wav)', '*.mp3 *.ogg *.wav') if file_Chosen is not None: self.currentPlaylist.addMedia(QMediaContent(file_Chosen[0])) # Folder open function def folder_open(self): folderAc = QAction(QIcon('icons\\open_fld.png'), 'Open Folder', self) folderAc.setShortcut('Ctrl+D') folderAc.setStatusTip('Open Folder ' '(Will add all the files in' ' the folder)') folderAc.triggered.connect(self.add_files) return folderAc # Folder opening function def add_files(self): folder_Chosen = QFileDialog\ .getExistingDirectory(self, 'Open Music Folder', expanduser('~')) if folder_Chosen is not None: it = QDirIterator(folder_Chosen) it.next() while it.hasNext(): if it.fileInfo().isDir() == False\ and it.filePath() != '.': fInfo = it.fileInfo() print(it.filePath(), fInfo.suffix()) if fInfo.suffix() in ('mp3', 'ogg', 'wav'): print('added file ', fInfo.fileName()) self.currentPlaylist. \ addMedia(QMediaContent( QUrl.fromLocalFile(it.filePath()))) it.next() # Song information function def song_info(self): infoAc = QAction(QIcon('icons\\info.png'), 'Info', self) infoAc.setShortcut('Ctrl+I') infoAc.setStatusTip('Displays Current Song Information') infoAc.triggered.connect(self.display_song_info) return infoAc # Show song information def display_song_info(self): metaDataKeyList = self.player.availableMetaData() fullText = '<table class="tftable" border="0">' for key in metaDataKeyList: value = self.player.metaData(key) fullText = \ fullText + '<tr><td>' + key + '</td><td>' + \ str(value) + '</td></tr>' fullText = fullText + '</table>' infoBox = QMessageBox(self) infoBox.setWindowTitle('Detailed Song Information') infoBox.setTextFormat(Qt.RichText) infoBox.setText(fullText) infoBox.addButton('OK', QMessageBox.AcceptRole) infoBox.show() # Switch to previous song def prev_item_playlist(self): self.player.playlist().previous() # Switch to next song def next_item_playlist(self): self.player.playlist().next() # exit function def exit_action(self): exitAc = QAction(QIcon('icons\\exit.png'), '&Exit', self) exitAc.setShortcut('Ctrl+Q') exitAc.setStatusTip('Exit App') exitAc.triggered.connect(self.close) return exitAc # exiting function @staticmethod def exit(): sys.exit(app.exec_())
class MainWindowAction(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MainWindowAction, self).__init__(parent) self.player = QMediaPlayer() self.playlist = QMediaPlaylist() self.local_music_path = [] self.setupUi(self) self.init() self.show() def init(self): # self.setWindowFlags(Qt.FramelessWindowHint) self.loadParams() self.playlist.setPlaybackMode(self.playlist.Loop) self.player.setPlaylist(self.playlist) self.player.play() exit_normal_icon_path = QUrl.fromLocalFile(EXIT_ICON_PATH) self.exit_normal_icon = QIcon(EXIT_ICON_PATH) self.exitButton.setStyleSheet(EXIT_BUTTON_STYLE) self.exitButton.clicked.connect(self.close) self.minButton.clicked.connect(self.showMinimized) # self.playButton.clicked.connect(self.playControl) self.nextButton.clicked.connect(self.playlist.next) self.prevButton.clicked.connect(self.playlist.previous) self.playButton.clicked.connect(self.controlPlay) self.player.currentMediaChanged.connect(self.initProgressBar) self.player.stateChanged.connect(self.changePlayState) self.player.positionChanged.connect(self.changeBar) self.playProgressBar.sliderReleased.connect(self.changePlayPosition) def loadParams(self): with open(CONFIG_PATH, 'r') as file: params = json.load(file) self.local_music_dirs = params['initParams']['LocalMusicDirs'] last_playlist = params['lastPlayParams']['Playlist'] self.initPlayList(last_playlist) def initPlayList(self, playlist_name): playlist_path = './PlayList/' + playlist_name + '.json' with open(playlist_path, 'r', encoding='UTF-8') as file: music_list = json.load(file) music_path_list = music_list['Songs'] for music_path in music_path_list: path = QUrl.fromLocalFile(music_path) music = QMediaContent(path) self.playlist.addMedia(music) def controlPlay(self): if self.player.state() == self.player.PlayingState: self.player.pause() # self.playButton.setText("Play") elif self.player.state() == self.player.PausedState: self.player.play() elif self.player.state() == self.player.StoppedState: if self.player.mediaStatus() in [ self.player.LoadingMedia, self.player.LoadedMedia, self.player.BufferedMedia, self.player.BufferingMedia ]: self.player.play() def changePlayState(self): if self.player.state() == self.player.PlayingState: self.playButton.setText("Pause") else: self.playButton.setText("Play") def initProgressBar(self): print(self.playlist.currentMedia().resources()[0].url().fileName()) self.playProgressBar.setValue(0) def changeBar(self): if self.player.state() == self.player.PlayingState: duration = self.player.duration() if duration > 0: value = self.player.position() * 100 // duration self.playProgressBar.setValue(value) def changePlayPosition(self): self.player.pause() duration = self.player.duration() value = self.playProgressBar.value() * duration // 100 self.player.setPosition(value) self.player.play()
class YtdlMusic(QMainWindow, Ui_MainWindow): def __init__(self, *args, **kwargs): QMainWindow.__init__(self, *args, **kwargs) self.setupUi(self) self.setWindowIcon(QIcon(LOCAL_DIR + '/ytdl_music.svg')) self.player = QMediaPlayer() self.player.isSeekable() self.playList = QMediaPlaylist() self.playListData = [] self.player.setPlaylist(self.playList) self.currentPos = 0 self.currentTrackDuration = '0:00:00' self.player.positionChanged.connect(self.positionChanged) self.player.durationChanged.connect(self.durationChanged) self.playList.currentIndexChanged.connect(self.playlistPosChanged) self.playlistTable.itemDoubleClicked.connect(self.changeTrack) self.playlistTable.itemSelectionChanged.connect(self.selectedTracks) # self.timeSlider.valueChanged.connect(self.setPosition) self.addBtn.clicked.connect(self.addDialog) self.removeBtn.clicked.connect(self.delTracks) self.playBtn.clicked.connect(self.playPause) self.stopBtn.clicked.connect(self.stop) self.prevBtn.clicked.connect(self.playList.previous) self.nextBtn.clicked.connect(self.playList.next) self.playlistTable.setHorizontalHeaderLabels([ '', _translate('MainWindow', 'Channel'), _translate('MainWindow', 'Title') ]) header = self.playlistTable.horizontalHeader() header.setSectionResizeMode(1, QHeaderView.Stretch) header.setSectionResizeMode(2, QHeaderView.Stretch) def setPosition(self, pos): self.player.setPosition(pos) def durationChanged(self, duration): total_time = '0:00:00' duration = self.player.duration() total_time = ms_to_time(duration) # self.timeSlider.setMaximum(duration) self.currentTrackDuration = duration # self.totalTimeLabel.setText(total_time) self.currentTrackDuration = total_time def mediaStatusChanged(self, status): icon = QIcon.fromTheme("media-playback-pause") if self.player.state() == QMediaPlayer.StoppedState: icon = QIcon.fromTheme("media-playback-start") elif self.player.state() == QMediaPlayer.PausedState: icon = QIcon.fromTheme("media-playback-start") self.playBtn.setIcon(icon) def positionChanged(self, position, senderType=False): self.currentTime = position current_time = '0:00:00' if position != -1: current_time = ms_to_time(position) self.timeLabel.setText('{0} / {1}'.format( current_time, self.currentTrackDuration)) '''self.timeSlider.blockSignals(True) self.timeSlider.setValue(position) self.timeSlider.blockSignals(False)''' def playlistPosChanged(self): pos = self.playList.currentIndex() data = self.playListData[pos] self.setWindowTitle('YouTube-dl Music: ' + data['title']) duration = ms_to_time(data['duration'] * 1000) self.timeLabel.setText('0:00:00 / {0}'.format(duration)) # self.totalTimeLabel.setText(ms_to_time(data['duration'] * 1000)) if self.playList.mediaCount() > 1: if pos < self.playList.mediaCount() - 1: self.nextBtn.setEnabled(True) else: self.nextBtn.setEnabled(False) if pos > 0: self.prevBtn.setEnabled(True) else: self.prevBtn.setEnabled(False) prevPos = 0 if pos < self.playList.mediaCount(): if self.currentPos < pos: prevPos = pos - 1 else: prevPos = pos + 1 statusItem = QLabel() icon = QIcon.fromTheme("media-playback-start") statusItem.setPixmap(icon.pixmap(16, 16)) statusItem.setAlignment(Qt.AlignCenter) self.playlistTable.setCellWidget(pos, 0, statusItem) if prevPos > -1: self.playlistTable.setCellWidget(prevPos, 0, QLabel()) else: self.playlistTable.setItem(pos, 0, QTableWidgetItem('')) self.currentPos = pos else: statusItem = QLabel() icon = QIcon.fromTheme("media-playback-start") statusItem.setPixmap(icon.pixmap(16, 16)) statusItem.setAlignment(Qt.AlignCenter) self.playlistTable.setCellWidget(pos, 0, statusItem) def playPause(self): icon = QIcon.fromTheme("media-playback-pause") if self.player.state() == QMediaPlayer.StoppedState: if self.player.mediaStatus() == QMediaPlayer.NoMedia: if self.playList.mediaCount() != 0: self.player.play() elif self.player.mediaStatus() == QMediaPlayer.LoadedMedia: self.playList.setCurrentIndex(self.currentPos) self.player.play() elif self.player.mediaStatus() == QMediaPlayer.BufferedMedia: self.player.play() elif self.player.state() == QMediaPlayer.PlayingState: icon = QIcon.fromTheme("media-playback-start") self.player.pause() elif self.player.state() == QMediaPlayer.PausedState: self.player.play() self.playBtn.setIcon(icon) def stop(self): self.player.stop() icon = QIcon.fromTheme("media-playback-start") self.playBtn.setIcon(icon) def insertTrack(self, data): if data: self.playListData.append(data) totalTracks = self.playList.mediaCount() pos = totalTracks self.playlistTable.insertRow(totalTracks) self.playlistTable.setRowCount(totalTracks + 1) self.playlistTable.setItem(pos, 0, QTableWidgetItem('')) self.playlistTable.setItem(pos, 1, QTableWidgetItem(data['channel'])) self.playlistTable.setItem(pos, 2, QTableWidgetItem(data['title'])) media = QMediaContent(QUrl(data['url'])) self.playList.addMedia(media) if totalTracks > 1: self.nextBtn.setEnabled(True) else: self.statusBar().showMessage('Total pistas: {0}'.format( self.playList.mediaCount())) def addDialog(self): url, ok = QInputDialog.getText( self, _translate('MainWindow', 'Add video/playlist'), 'URL:') if ok and url != '': self.addPCThread = addVideos(self, url) self.addPCThread.video.connect(self.insertTrack) self.addPCThread.start() def changeTrack(self, item): pos = item.row() self.playlistTable.setCellWidget(self.currentPos, 0, QLabel()) self.playList.setCurrentIndex(pos) if self.player.state() == QMediaPlayer.StoppedState: icon = QIcon.fromTheme("media-playback-pause") self.playBtn.setIcon(icon) self.player.play() def delTracks(self): indexes = self.playlistTable.selectionModel().selectedRows() del_first = True for index in sorted(indexes): pos = index.row() if not del_first: pos -= 1 else: del_first = False self.playlistTable.removeRow(pos) self.playListData.pop(pos) self.playList.removeMedia(pos) self.playlistPosChanged() def selectedTracks(self): totalSelected = len(self.playlistTable.selectedItems()) if totalSelected > 0: self.removeBtn.setEnabled(True) else: self.removeBtn.setEnabled(False)
class VideoPlayer(QWidget): def __init__(self, aPath, parent=None): super(VideoPlayer, self).__init__(parent) self.setAttribute(Qt.WA_NoSystemBackground, True) self.setAcceptDrops(True) self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.StreamPlayback) self.mediaPlayer.mediaStatusChanged.connect(self.printMediaData) self.mediaPlayer.setVolume(80) self.videoWidget = QVideoWidget(self) self.lbl = QLineEdit('00:00:00') self.lbl.setReadOnly(True) self.lbl.setFixedWidth(70) self.lbl.setUpdatesEnabled(True) self.lbl.setStyleSheet(stylesheet(self)) self.elbl = QLineEdit('00:00:00') self.elbl.setReadOnly(True) self.elbl.setFixedWidth(70) self.elbl.setUpdatesEnabled(True) self.elbl.setStyleSheet(stylesheet(self)) self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setFixedWidth(32) self.playButton.setStyleSheet("background-color: black") self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.positionSlider = QSlider(Qt.Horizontal, self) self.positionSlider.setStyleSheet(stylesheet(self)) self.positionSlider.setRange(0, 100) self.positionSlider.sliderMoved.connect(self.setPosition) self.positionSlider.sliderMoved.connect(self.handleLabel) self.positionSlider.setSingleStep(2) self.positionSlider.setPageStep(20) self.positionSlider.setAttribute(Qt.WA_TranslucentBackground, True) self.clip = QApplication.clipboard() self.process = QProcess(self) self.process.readyRead.connect(self.dataReady) # self.process.started.connect(lambda: print("grabbing YouTube URL")) self.process.finished.connect(self.playFromURL) self.myurl = "" controlLayout = QHBoxLayout() controlLayout.setContentsMargins(5, 0, 5, 0) controlLayout.addWidget(self.playButton) controlLayout.addWidget(self.lbl) controlLayout.addWidget(self.positionSlider) controlLayout.addWidget(self.elbl) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.videoWidget) layout.addLayout(controlLayout) self.setLayout(layout) self.myinfo = "©2016\nAxel Schneider\n\nMouse Wheel = Zoom\nUP = Volume Up\nDOWN = Volume Down\n" + \ "LEFT = < 1 Minute\nRIGHT = > 1 Minute\n" + \ "SHIFT+LEFT = < 10 Minutes\nSHIFT+RIGHT = > 10 Minutes" self.widescreen = True #### shortcuts #### self.shortcut = QShortcut(QKeySequence("q"), self) self.shortcut.activated.connect(self.handleQuit) self.shortcut = QShortcut(QKeySequence("u"), self) self.shortcut.activated.connect(self.playFromURL) self.shortcut = QShortcut(QKeySequence("y"), self) self.shortcut.activated.connect(self.getYTUrl) self.shortcut = QShortcut(QKeySequence("o"), self) self.shortcut.activated.connect(self.openFile) self.shortcut = QShortcut(QKeySequence(" "), self) self.shortcut.activated.connect(self.play) self.shortcut = QShortcut(QKeySequence("f"), self) self.shortcut.activated.connect(self.handleFullscreen) self.shortcut = QShortcut(QKeySequence("i"), self) self.shortcut.activated.connect(self.handleInfo) self.shortcut = QShortcut(QKeySequence("s"), self) self.shortcut.activated.connect(self.toggleSlider) self.shortcut = QShortcut(QKeySequence(Qt.Key_Right), self) self.shortcut.activated.connect(self.forwardSlider) self.shortcut = QShortcut(QKeySequence(Qt.Key_Left), self) self.shortcut.activated.connect(self.backSlider) self.shortcut = QShortcut(QKeySequence(Qt.Key_Up), self) self.shortcut.activated.connect(self.volumeUp) self.shortcut = QShortcut(QKeySequence(Qt.Key_Down), self) self.shortcut.activated.connect(self.volumeDown) self.shortcut = QShortcut( QKeySequence(Qt.ShiftModifier + Qt.Key_Right), self) self.shortcut.activated.connect(self.forwardSlider10) self.shortcut = QShortcut(QKeySequence(Qt.ShiftModifier + Qt.Key_Left), self) self.shortcut.activated.connect(self.backSlider10) self.mediaPlayer.setVideoOutput(self.videoWidget) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.positionChanged.connect(self.handleLabel) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.error.connect(self.handleError) print("QT5 Player started") self.suspend_screensaver() # msg = QMessageBox.information(self, "Qt5Player", "press o to open file") self.loadFilm("/home/brian/Dokumente/Qt5PlayerIntro.m4v") def playFromURL(self): self.mediaPlayer.pause() self.myurl = self.clip.text() self.mediaPlayer.setMedia(QMediaContent(QUrl(self.myurl))) self.playButton.setEnabled(True) self.mediaPlayer.play() self.hideSlider() print(self.myurl) def getYTUrl(self): cmd = "youtube-dl -g -f best " + self.clip.text() print("grabbing YouTube URL") self.process.start(cmd) def dataReady(self): self.myurl = str(self.process.readAll(), encoding='utf8').rstrip() ### self.myurl = self.myurl.partition("\n")[0] print(self.myurl) self.clip.setText(self.myurl) self.playFromURL() def suspend_screensaver(self): 'suspend linux screensaver' proc = subprocess.Popen( 'gsettings set org.gnome.desktop.screensaver idle-activation-enabled false', shell=True) proc.wait() def resume_screensaver(self): 'resume linux screensaver' proc = subprocess.Popen( 'gsettings set org.gnome.desktop.screensaver idle-activation-enabled true', shell=True) proc.wait() def openFile(self): fileName, _ = QFileDialog.getOpenFileName( self, "Open Movie", QDir.homePath() + "/Videos", "Media (*.webm *.mp4 *.ts *.avi *.mpeg *.mpg *.mkv *.VOB *.m4v *.3gp *.mp3 *.m4a *.wav *.ogg *.flac *.m3u *.m3u8)" ) if fileName != '': self.loadFilm(fileName) print("File loaded") def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) def positionChanged(self, position): self.positionSlider.setValue(position) def durationChanged(self, duration): self.positionSlider.setRange(0, duration) mtime = QTime(0, 0, 0, 0) mtime = mtime.addMSecs(self.mediaPlayer.duration()) self.elbl.setText(mtime.toString()) def setPosition(self, position): self.mediaPlayer.setPosition(position) def handleError(self): self.playButton.setEnabled(False) print("Error: ", self.mediaPlayer.errorString()) def handleQuit(self): self.mediaPlayer.stop() self.resume_screensaver() print("Goodbye ...") app.quit() def contextMenuRequested(self, point): menu = QMenu() actionFile = menu.addAction(QIcon.fromTheme("video-x-generic"), "open File (o)") actionclipboard = menu.addSeparator() actionURL = menu.addAction(QIcon.fromTheme("browser"), "URL from Clipboard (u)") actionclipboard = menu.addSeparator() actionYTurl = menu.addAction(QIcon.fromTheme("youtube"), "URL from YouTube (y)") actionclipboard = menu.addSeparator() actionToggle = menu.addAction(QIcon.fromTheme("next"), "show / hide Slider (s)") actionFull = menu.addAction(QIcon.fromTheme("view-fullscreen"), "Fullscreen (f)") action169 = menu.addAction(QIcon.fromTheme("tv-symbolic"), "16 : 9") action43 = menu.addAction(QIcon.fromTheme("tv-symbolic"), "4 : 3") actionSep = menu.addSeparator() actionInfo = menu.addAction(QIcon.fromTheme("help-about"), "Info (i)") action5 = menu.addSeparator() actionQuit = menu.addAction(QIcon.fromTheme("application-exit"), "Exit (q)") actionFile.triggered.connect(self.openFile) actionQuit.triggered.connect(self.handleQuit) actionFull.triggered.connect(self.handleFullscreen) actionInfo.triggered.connect(self.handleInfo) actionToggle.triggered.connect(self.toggleSlider) actionURL.triggered.connect(self.playFromURL) actionYTurl.triggered.connect(self.getYTUrl) action169.triggered.connect(self.screen169) action43.triggered.connect(self.screen43) menu.exec_(self.mapToGlobal(point)) def wheelEvent(self, event): mwidth = self.frameGeometry().width() mheight = self.frameGeometry().height() mleft = self.frameGeometry().left() mtop = self.frameGeometry().top() mscale = event.angleDelta().y() / 5 if self.widescreen == True: self.setGeometry(mleft, mtop, mwidth + mscale, (mwidth + mscale) / 1.778) else: self.setGeometry(mleft, mtop, mwidth + mscale, (mwidth + mscale) / 1.33) def screen169(self): self.widescreen = True mwidth = self.frameGeometry().width() mheight = self.frameGeometry().height() mleft = self.frameGeometry().left() mtop = self.frameGeometry().top() mratio = 1.778 self.setGeometry(mleft, mtop, mwidth, mwidth / mratio) def screen43(self): self.widescreen = False mwidth = self.frameGeometry().width() mheight = self.frameGeometry().height() mleft = self.frameGeometry().left() mtop = self.frameGeometry().top() mratio = 1.33 self.setGeometry(mleft, mtop, mwidth, mwidth / mratio) def handleFullscreen(self): if self.windowState() & Qt.WindowFullScreen: QApplication.setOverrideCursor(Qt.ArrowCursor) self.showNormal() print("no Fullscreen") else: self.showFullScreen() QApplication.setOverrideCursor(Qt.BlankCursor) print("Fullscreen entered") def handleInfo(self): msg = QMessageBox.about(self, "QT5 Player", self.myinfo) def toggleSlider(self): if self.positionSlider.isVisible(): self.hideSlider() else: self.showSlider() def hideSlider(self): self.playButton.hide() self.lbl.hide() self.positionSlider.hide() self.elbl.hide() mwidth = self.frameGeometry().width() mheight = self.frameGeometry().height() mleft = self.frameGeometry().left() mtop = self.frameGeometry().top() if self.widescreen == True: self.setGeometry(mleft, mtop, mwidth, mwidth / 1.778) else: self.setGeometry(mleft, mtop, mwidth, mwidth / 1.33) def showSlider(self): self.playButton.show() self.lbl.show() self.positionSlider.show() self.elbl.show() mwidth = self.frameGeometry().width() mheight = self.frameGeometry().height() mleft = self.frameGeometry().left() mtop = self.frameGeometry().top() if self.widescreen == True: self.setGeometry(mleft, mtop, mwidth, mwidth / 1.55) else: self.setGeometry(mleft, mtop, mwidth, mwidth / 1.33) def forwardSlider(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() + 1000 * 60) def forwardSlider10(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() + 10000 * 60) def backSlider(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() - 1000 * 60) def backSlider10(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() - 10000 * 60) def volumeUp(self): self.mediaPlayer.setVolume(self.mediaPlayer.volume() + 10) print("Volume: " + str(self.mediaPlayer.volume())) def volumeDown(self): self.mediaPlayer.setVolume(self.mediaPlayer.volume() - 10) print("Volume: " + str(self.mediaPlayer.volume())) def mouseMoveEvent(self, event): if event.buttons() == Qt.LeftButton: self.move(event.globalPos() \ - QPoint(self.frameGeometry().width() / 2, \ self.frameGeometry().height() / 2)) event.accept() def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() elif event.mimeData().hasText(): event.accept() else: event.ignore() def dropEvent(self, event): if event.mimeData().hasUrls(): url = event.mimeData().urls()[0].toString() print("url = ", url) self.mediaPlayer.stop() self.mediaPlayer.setMedia(QMediaContent(QUrl(url))) self.playButton.setEnabled(True) self.mediaPlayer.play() elif event.mimeData().hasText(): mydrop = event.mimeData().text() ### YouTube url if "youtube" in mydrop: print("is YouTube", mydrop) self.clip.setText(mydrop) self.getYTUrl() else: ### normal url print("generic url = ", mydrop) self.mediaPlayer.setMedia(QMediaContent(QUrl(mydrop))) self.playButton.setEnabled(True) self.mediaPlayer.play() self.hideSlider() def loadFilm(self, f): self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(f))) self.playButton.setEnabled(True) self.mediaPlayer.play() def printMediaData(self): if self.mediaPlayer.mediaStatus() == 6: if self.mediaPlayer.isMetaDataAvailable(): res = str(self.mediaPlayer.metaData("Resolution")).partition( "PyQt5.QtCore.QSize(")[2].replace(", ", " x ").replace(")", "") print("%s%s" % ("Video Resolution = ", res)) else: print("no metaData available") def openFileAtStart(self, filelist): matching = [s for s in filelist if ".myformat" in s] if len(matching) > 0: self.loadFilm(matching) ##################### update Label ################################## def handleLabel(self): self.lbl.clear() mtime = QTime(0, 0, 0, 0) self.time = mtime.addMSecs(self.mediaPlayer.position()) self.lbl.setText(self.time.toString())
class Window(QWidget): def __init__(self): super().__init__() self.setWindowTitle("PyQt5 Media Player") self.setGeometry(350, 100, 700, 500) self.setWindowIcon(QIcon('player.png')) #reqdata = req.get('http://192.168.0.47:2000/getcsvfile/strenght-weakness_bp') #data = reqdata.json() #print("data", data) #192.168.0.47 #http://192.168.0.47:2000/getvideo/strenght-weakness_bp #p =self.palette() #p.setColor(QPalette.Window, Qt.black) #self.setPalette(p) #data = {'name': 'Peter'} # resp = req.post("http://192.168.0.34:2000/upload/interview/postdata", data) # print(resp.text) # self.clientsocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # self.clientsocket.connect(('192.168.0.34',2000)) milli_sec = int(round(time.time() * 1000)) print(milli_sec) self.timer = QTimer() self.timer.timeout.connect(self.viewCam) fourcc = cv2.VideoWriter_fourcc(*'XVID') self.out = cv2.VideoWriter('C:/Users/brahm/OneDrive/Desktop/webcam/'+str(milli_sec)+'.mp4', fourcc, 30.0, (640, 480)) self.init_ui() self.show() def init_ui(self): #create media player object self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) #create videowidget object videowidget = QVideoWidget() #create open button openBtn = QPushButton('Open Video') openBtn.clicked.connect(self.open_file) self.videobutton = QPushButton('start') self.videobutton.clicked.connect(self.record) #create button for playing self.playBtn = QPushButton() #self.playBtn.setEnabled(False) self.playBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playBtn.clicked.connect(self.play_video) #create slider self.slider = QSlider(Qt.Horizontal) self.slider.setRange(0,0) self.slider.sliderMoved.connect(self.set_position) #create label self.label = QLabel() self.label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) #create hbox layout hboxLayout = QHBoxLayout() hboxLayout.setContentsMargins(0,0,0,0) #set widgets to the hbox layout #hboxLayout.addWidget(openBtn) hboxLayout.addWidget(self.videobutton) hboxLayout.addWidget(self.playBtn) hboxLayout.addWidget(self.slider) #create vbox layout vboxLayout = QVBoxLayout() vboxLayout.addWidget(videowidget) vboxLayout.addLayout(hboxLayout) vboxLayout.addWidget(self.label) self.setLayout(vboxLayout) self.mediaPlayer.setVideoOutput(videowidget) self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile("C:/Users/brahm/OneDrive/Desktop/face exp node/రాష్ట్రపతి పాలన ఎప్పుడు, ఎందుకు విధిస్తారు_ ఆర్టికల్ 356 ఏం చెబుతోంది_ - BBC New.wmv"))) #media player signals self.mediaPlayer.stateChanged.connect(self.mediastate_changed) self.mediaPlayer.positionChanged.connect(self.position_changed) self.mediaPlayer.durationChanged.connect(self.duration_changed) self.mediaPlayer.error.connect(self.handle_errors) def open_file(self): #sender = self.sender() 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() print('mediaStatus: ' + str(self.mediaPlayer.mediaStatus())) 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): print("position", position) self.mediaPlayer.setPosition(position) def handle_errors(self): print(self.mediaPlayer.error, 'error') print('error: ' + str(self.mediaPlayer.error())) print('mediaStatus: ' + str(self.mediaPlayer.mediaStatus())) self.playBtn.setEnabled(False) self.label.setText("Error: " + self.mediaPlayer.errorString()) def viewCam(self): # read image in BGR format ret, image = self.cap.read() #data = {'name': image} #resp = req.post("https://httpbin.org/post", data) #print(resp.text) #data = pickle.dumps(image) #print("data", data) #self.clientsocket.sendall(struct.pack("H", len(data))+data) self.out.write(image) #dtime = int(round(time.time() * 1000)) #data = QByteArray() #data.append("name=Peter&") #data.append("age=34") #videofilename = str(dtime)+'.mp4' #data.append('videoname', videofilename); #print("data", data) # convert image to RGB format def record(self): if not self.timer.isActive(): self.cap = cv2.VideoCapture(0) self.timer.start() self.videobutton.setText("Stop") else: self.timer.stop() self.cap.release() print("data", self.out) self.out.release() # update control_bt text self.videobutton.setText("Start")
class VideoWindow(QWidget): sigTimeChanged = pyqtSignal(object) def __init__(self, project=None, parent=None): super(VideoWindow, self).__init__(parent) self.project = project self.setWindowTitle("Video") self.mediaPlayer = QMediaPlayer() #None, QMediaPlayer.VideoSurface) self.last_position = 0 self.position_on_new_file = 0 self.duration = -1 self.waiting_for_file = False self.media_state_before_file_transition = self.mediaPlayer.state() self.video_time_offset = 0.0 self.play_icon = QIcon(play_icon_file) self.clock_icon = QIcon(clock_icon_file) self.pause_icon = QIcon(pause_icon_file) videoWidget = QVideoWidget() self.videoWidget = videoWidget self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setIcon(self.play_icon) self.playButton.clicked.connect(self.play) self.timeOffsetButton = QPushButton() self.timeOffsetButton.setIcon(self.clock_icon) self.timeOffsetButton.clicked.connect(self.setTimeOffset) self.positionSlider = QSlider(Qt.Horizontal) self.positionSlider.setRange(0, 0) self.positionSlider.sliderMoved.connect(self.setPosition) self.errorLabel = QLabel() self.errorLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Maximum) # Create layouts to place inside widget controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) controlLayout.addWidget(self.timeOffsetButton) controlLayout.addWidget(self.playButton) controlLayout.addWidget(self.positionSlider) layout = QVBoxLayout() layout.addWidget(videoWidget) layout.addLayout(controlLayout) layout.addWidget(self.errorLabel) # Hide error Label # Set widget to contain window contents self.setLayout(layout) self.mediaPlayer.setVideoOutput(videoWidget) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.mediaStatusChanged.connect(self.mediaStatusChanged) self.mediaPlayer.error.connect(self.handleError) self.mediaPlayer.setNotifyInterval(40) # 25 fps if self.project is None: self.current_time_range = [0, 0] self.current_file = '' # self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(self.current_file))) # self.playButton.setEnabled(True) # self.mediaPlayer.play() elif self.project.current_animal.video_files: self.current_file = self.project.current_animal.video_files[0] self.current_time_range = [ self.project.current_animal.video_init_time[0], self.project.current_animal.video_init_time[0] + self.project.current_animal.video_duration[0] ] self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(self.current_file))) self.playButton.setEnabled(True) else: self.current_file = '' self.current_time_range = [0, 0] def setTimeOffset(self): offset, okpressed = QInputDialog.getDouble( self, 'Video time offset', 'Offset video time position (seconds)', value=self.video_time_offset) if okpressed: self.video_time_offset = offset current_position = self.current_time_range[ 0] + self.last_position / 1000 self.setGlobalPosition(0) self.setGlobalPosition(current_position) def openFile(self): fileName, _ = QFileDialog.getOpenFileName(self, "Open Movie", QDir.homePath()) if fileName != '': self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(fileName))) self.playButton.setEnabled(True) def exitCall(self): sys.exit(app.exec_()) def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon(self.pause_icon) else: self.playButton.setIcon(self.play_icon) def positionChanged(self, position): # Connected to video player # print('positionChanged',position,self.last_position,self.waiting_for_file,self.duration,self.current_time_range) # if self.duration == -1: # print('positionChanged: no file - duration ==-1') # return # if self.waiting_for_file: # print('positionChanged: Waiting to load file') # return # if position == 0: # print('positionChanged: avoiding setting positions to 0') # return if position == 0 or self.waiting_for_file or self.duration == -1 or position == self.last_position: # avoid position changes on file transitions or repeated signals on same position return if position < self.duration - 40: # avoid time changes when switching files self.last_position = position self.positionSlider.setValue(position) self.sigTimeChanged.emit(position / 1000 + self.current_time_range[0]) else: # position is at the end of file - try to switch to next file pos = self.current_time_range[1] + .04 print('Trying to jump to next file', self.current_time_range[1], self.duration, pos) self.setGlobalPosition(pos) def durationChanged(self, duration): # print('duration changed',duration) self.duration = duration self.positionSlider.setRange(0, duration) self.mediaPlayer.setPosition( self.position_on_new_file ) # if duration changes avoid the position going back to 0 def setPosition(self, position): # connected to slider # print('setPosition',position) self.mediaPlayer.setPosition( position) # milliseconds since the beginning of the media def setGlobalPosition(self, pos): # Connected to project main model sigTimeChanged # open the right media if self.current_time_range[0] <= pos <= self.current_time_range[ 1]: # correct file opened position = int((pos - self.current_time_range[0]) * 1000) if self.mediaPlayer.state() == QMediaPlayer.PlayingState and abs( position - self.last_position) < 200: # skip position setting by signal of main model to ensure smooth video plaback return # go to correct relative position self.mediaPlayer.setPosition(position) # UNIX time return else: for i, file in enumerate(self.project.current_animal.video_files ): # search for file to open arange = [ self.project.current_animal.video_init_time[i] + self.video_time_offset, self.project.current_animal.video_init_time[i] + self.project.current_animal.video_duration[i] + self.video_time_offset ] if (arange[0] <= pos <= arange[1]): print('Changing video file: ', file) self.current_file = file self.errorLabel.setText("File: " + self.current_file) self.current_time_range = arange self.waiting_for_file = True self.media_state_before_file_transition = self.mediaPlayer.state( ) self.mediaPlayer.stop() position = (pos - self.current_time_range[0]) * 1000 self.position_on_new_file = int(position) # print('Changing position_on_new_file: ', self.position_on_new_file,pos) self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(file))) self.playButton.setEnabled(True) # self.duration = (arange[1]-arange[0])*1000 return print('no video file found for current position') self.errorLabel.setText("No video file found for current position") self.mediaPlayer.stop() self.mediaPlayer.setMedia(QMediaContent()) self.current_file = '' self.current_time_range = [0, 0] # self.duration = 0 self.playButton.setEnabled(False) self.positionSlider.setRange(0, 0) self.positionSlider.setValue(0) def mediaStatusChanged(self, status): if self.waiting_for_file: if self.mediaPlayer.mediaStatus() == QMediaPlayer.LoadedMedia: self.waiting_for_file = False # print('finished loading file') # self.mediaPlayer.stop() self.mediaPlayer.setPosition(self.position_on_new_file) self.mediaPlayer.play() time.sleep(.05) self.mediaPlayer.pause() if self.media_state_before_file_transition == QMediaPlayer.PlayingState: self.mediaPlayer.play() # print('finished setting position on new file') def handleError(self): self.playButton.setEnabled(False) self.errorLabel.setText("Error: " + self.mediaPlayer.errorString()) print("Video - Error: " + self.mediaPlayer.errorString())
class Player(QObject): # 信号: 当音量变化时, 参数为当前音量. volumeChanged = QtCore.pyqtSignal(int) # 信号: 当播放位置变化时, 参数为当前位置 positionChanged = QtCore.pyqtSignal(int) # 信号: 当播放状态变化时, 参数为当前状态 stateChanged = QtCore.pyqtSignal(int) # 信号: 当媒体状态变化时, 参数为当前状态 mediaStatusChanged = QtCore.pyqtSignal(int) # 信号: 当静音状态变化时, 参数为当前状态 mutedChanged = QtCore.pyqtSignal(int) localAppDataDir = os.getenv("LOCALAPPDATA") # like: # Windows: C:/Users/win10/AppData/Local/kon-windows/Temp/Music # Linux : Not test. tempDir = localAppDataDir + "/kon-windows/Temp/Music/" def __init__(self) -> None: super().__init__() self.__path = None self.__lock = Lock() self.__player = QMediaPlayer() self.__player.setVolume(50) self.__player.positionChanged.connect(self.__onPositionChanged) self.__player.mediaStatusChanged.connect(self.__onMediaStatusChanged) if not os.path.exists(self.tempDir): os.makedirs(self.tempDir) def init(self): pass def play(self, music: Music): if music is None: return self.__lock.acquire() """ 开始或继续播放。如果以前已暂停播放,则将从暂停的位置继续播放。 如果播放已停止或之前从未开始过,则播放将从头开始。 """ status = self.__player.mediaStatus() path = music.path if status == QMediaPlayer.NoMedia or self.__path != path: self.stop() content = QMediaContent(QUrl.fromLocalFile(self.__trans2wave(music))) self.__player.setMedia(content) self.__path = path state = self.__player.state() if state == QMediaPlayer.PlayingState: self.__player.pause() else: self.__player.play() player_state = self.__player.state() self.stateChanged.emit(player_state) self.__lock.release() def pause(self): """ 暂停播放 """ self.__player.pause() self.stateChanged.emit(self.__player.state()) def stop(self): self.__player.stop() self.__player.setMedia(QMediaContent()) def getVolume(self) -> int: """ 获取音量 """ return self.__player.volume() def setVolume(self, volume: int): """ 设置音量, 范围从0(静音)到100(全音量). 默认情况下,音量为100. """ self.__player.setVolume(volume) self.volumeChanged.emit(volume) def getMuted(self) -> bool: """ 获取静音状态. """ return self.__player.isMuted() def setMuted(self, muted: bool): """ 设置静音状态. """ self.__player.setMuted(muted) self.mutedChanged.emit(muted) def toggleMuted(self): """ 切换静音状态. """ self.__player.setMuted(not self.__player.isMuted()) self.mutedChanged.emit(self.__player.isMuted()) def getState(self) -> int: """ 获取播放状态. """ return self.__player.state() def playing(self) -> bool: """ 当前是否处于播放状态. """ return self.__player.state() == QMediaPlayer.PlayingState def setPosition(self, position: int): """ 跳跃到指定的时间位置。 :param position: 绝对时间位置, 毫秒。 """ self.__player.setPosition(position) self.positionChanged.emit(position) def getPosition(self) -> int: """ 获取当前播放进度. """ return self.__player.position() def getDuration(self) -> int: """ 获取时长. """ return self.__player.duration() def __onPositionChanged(self, position: int): self.positionChanged.emit(position) def __onMediaStatusChanged(self, mediaStatus: int): self.mediaStatusChanged.emit(mediaStatus) def __trans2wave(self, music: Music) -> str: """ 转换格式为 wave """ path = music.path if path.endswith(".wav"): return path dest = self.tempDir + str(music.id) + ".wav" if os.path.exists(dest): return dest # 最多保留一百个歌曲缓存 olds = os.listdir(self.tempDir) if len(olds) >= 100: # 删掉一个 os.remove(self.tempDir + olds[0]) Commons.export2wave(path, dest) return dest