예제 #1
0
class AudioPlayer:
    def __init__(self):
        self._widget = None
        self._player = None
        self._timer = None

    def toggle_playback(self, widget):
        if self._widget == widget:
            if self._player.get_pause():
                plugins.video.video_player.pause_playback()
                self._player.set_pause(False)
                self._widget.audio_state = 'play'
                self._timer = Clock.schedule_interval(self._playback_update,
                                                      .1)
            else:
                self.pause_playback()
        else:
            plugins.video.video_player.pause_playback()
            if self._widget is not None:
                self.pause_playback()
            self._widget = widget
            self._widget.audio_state = 'play'
            self._player = MediaPlayer(filename=self._widget.audio_source,
                                       ff_opts={
                                           'paused': True,
                                           'ss': self._widget.audio_pos
                                       })
            Clock.schedule_interval(self._start_playback, .1)

    def _start_playback(self, dt):
        if self._player.get_metadata()['duration'] is not None:
            self._player.set_pause(False)
            self._timer = Clock.schedule_interval(self._playback_update, .1)
            return False

    def pause_playback(self):
        if self._timer is not None:
            self._timer.cancel()
        if self._player is not None and not self._player.get_pause():
            self._player.set_pause(True)
        if self._widget is not None:
            self._widget.audio_state = 'pause'

    def _playback_update(self, dt):
        pts = self._player.get_pts()
        if pts >= self._widget.audio_length:
            self._player.set_pause(True)
            self._player.seek(pts=0, relative=False, accurate=True)
            self._widget.audio_state = 'pause'
            self._widget.audio_pos = 0
            return False
        self._widget.audio_pos = pts

    def update_audio_pos(self, widget, pts):
        if self._widget == widget and self._player is not None:
            self._player.seek(pts=pts, relative=False, accurate=True)
        widget.audio_pos = pts
예제 #2
0
class Window(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.Listadd()
        self.step = 0
        self.loop = 1
        self.flag = True

    def Listadd(self):
        if os.path.isfile('CPlayerlist.txt'):
            with open('CPlayerlist.txt') as f:
                for filelist in f:
                    filelist = filelist.strip()
                    self.list.addItem(filelist)

    def Add(self):
        filelists, _ = QFileDialog.getOpenFileNames(self, '添加到播放列表', '.',
                                                    '媒体文件(*)')
        self.list.addItems(filelists)
        self.Listchanged()

    def Remove(self):
        self.list.takeItem(self.list.currentRow())
        self.Listchanged()

    def Clear(self):
        self.list.clear()
        os.remove('CPlayerlist.txt')

    def Listchanged(self):
        with open('CPlayerlist.txt', 'w') as f:
            for i in range(self.list.count()):
                f.write(self.list.item(i).text() + '\n')

    def Loop(self):
        if self.loop == 0:
            self.loop = 1
            self.bloop.setIcon(QIcon(r'img\withloop.png'))
            self.bloop.setToolTip('循环播放')
        else:
            self.loop = 0
            self.bloop.setIcon(QIcon(r'img\withoutloop.png'))
            self.bloop.setToolTip('取消循环')

    def Play(self):
        try:
            if self.flag:
                self.playitem = self.list.currentItem().text()
                self.player = MediaPlayer("%s" % self.playitem)
                self.timer = QTimer()
                self.timer.start(50)
                self.timer.timeout.connect(self.Show)
                self.steptimer = QTimer()
                self.steptimer.start(1000)
                self.steptimer.timeout.connect(self.Step)
                self.flag = False
                self.bplay.setIcon(QIcon(r'img\pause.png'))
                self.bplay.setToolTip('暂停')
            else:
                if self.list.currentItem().text() == self.playitem:
                    self.player.toggle_pause()
                    if self.player.get_pause():
                        self.timer.stop()
                        self.steptimer.stop()
                        self.bplay.setIcon(QIcon(r'img\play.png'))
                        self.bplay.setToolTip('播放')
                    else:
                        self.timer.start()
                        self.steptimer.start()
                        self.bplay.setIcon(QIcon(r'img\pause.png'))
                        self.bplay.setToolTip('暂停')
                else:
                    self.step = 0
                    self.stime.setValue(0)
                    self.playitem = self.list.currentItem().text()
                    self.player = MediaPlayer("%s" % self.playitem)
                    self.timer.start()
                    self.steptimer.start()
        except:
            QMessageBox.warning(self, '错误', '找不到要播放的文件!')

    def Show(self):
        frame, self.val = self.player.get_frame()
        self.lmedia.setPixmap(QPixmap(''))
        if self.val != 'eof' and frame is not None:
            img, t = frame
            data = img.to_bytearray()[0]
            width, height = img.get_size()
            qimg = QImage(data, width, height, QImage.Format_RGB888)
            self.lmedia.setPixmap(QPixmap.fromImage(qimg))
        self.mediatime = self.player.get_metadata()['duration']
        self.stime.setMaximum(int(self.mediatime))
        mediamin, mediasec = divmod(self.mediatime, 60)
        mediahour, mediamin = divmod(mediamin, 60)
        playmin, playsec = divmod(self.step, 60)
        playhour, playmin = divmod(playmin, 60)
        self.ltime.setText(
            '%02d:%02d:%02d/%02d:%02d:%02d' %
            (playhour, playmin, playsec, mediahour, mediamin, mediasec))

    def Stop(self):
        if self.flag == False:
            self.player.close_player()
            self.timer.stop()
            self.steptimer.stop()
            self.step = 0
            self.loop = 1
            self.flag = True
            self.stime.setValue(0)
            self.ltime.setText('')
            self.bplay.setIcon(QIcon(r'img\play.png'))
            self.bplay.setToolTip('播放')
            self.lmedia.setPixmap(QPixmap(''))

    def Curvol(self):
        self.curvol = self.svolume.value()

    def Mute(self):
        if self.flag == False:
            if self.player.get_volume() != 0:
                self.player.set_volume(0)
                self.bmute.setIcon(QIcon(r'img\withoutvolume.png'))
                self.bmute.setToolTip('取消静音')
            else:
                if self.svolume.value() != 0:
                    self.player.set_volume(self.svolume.value())
                else:
                    self.player.set_volume(self.curvol / 100)
                    self.svolume.setValue(self.curvol)
                self.bmute.setIcon(QIcon(r'img\withvolume.png'))
                self.bmute.setToolTip('静音')

    def Volume(self):
        if self.flag == False:
            if self.svolume.value() == 0:
                self.bmute.setIcon(QIcon(r'img\withoutvolume.png'))
                self.bmute.setToolTip('取消静音')
            else:
                self.bmute.setIcon(QIcon(r'img\withvolume.png'))
                self.bmute.setToolTip('静音')
            self.player.set_volume(self.svolume.value() / 100)

    def Step(self):
        if self.step >= int(self.mediatime):
            self.step = int(self.mediatime)
            if self.loop == 0:
                self.step = 0
                self.flag = True
                self.Play()
            else:
                if self.val == 'eof':
                    self.timer.stop()
                    self.steptimer.stop()
                    self.step = 0
                    self.loop = 1
                    self.flag = True
                    self.stime.setValue(0)
                    self.player.close_player()
                    self.bplay.setIcon(QIcon(r'img\play.png'))
                    self.bplay.setToolTip('播放')
        else:
            self.step += 1
            self.stime.setValue(self.step)

    def Slidechanged(self):
        self.step = self.stime.value()

    def Slidemoved(self):
        self.timer.start()
        self.steptimer.start()
        self.player = MediaPlayer("%s" % self.playitem,
                                  ff_opts={'ss': self.step})
        self.bplay.setIcon(QIcon(r'img\pause.png'))
        self.bplay.setToolTip('暂停')

    def Fastforward(self):
        self.step += 10
        if self.step >= int(self.mediatime):
            self.stime.setValue(int(self.mediatime))
        self.timer.start()
        self.steptimer.start()
        self.player = MediaPlayer("%s" % self.playitem,
                                  ff_opts={'ss': self.step})
        self.bplay.setIcon(QIcon(r'img\pause.png'))
        self.bplay.setToolTip('暂停')

    def Fastback(self):
        self.step -= 10
        if self.step <= 0:
            self.step = 0
        self.timer.start()
        self.steptimer.start()
        self.player = MediaPlayer("%s" % self.playitem,
                                  ff_opts={'ss': self.step})
        self.bplay.setIcon(QIcon(r'img\pause.png'))
        self.bplay.setToolTip('暂停')
예제 #3
0
class VideoPlayer:
    def __init__(self):
        self._widget = None
        self._player = None
        self._timer = None
        self._frame = None
        self._texture = None
        self._trigger = Clock.create_trigger(self._redraw)

    def toggle_playback(self, widget):
        if self._widget == widget:
            if self._player.get_pause():
                plugins.audio.audio_player.pause_playback()
                self._player.set_pause(False)
                self._widget.video_state = 'play'
                Clock.schedule_once(self._next_frame)
            else:
                self.pause_playback()
        else:
            plugins.audio.audio_player.pause_playback()
            if self._widget is not None:
                self.pause_playback()
            self._widget = widget
            self._widget.video_state = 'play'
            self._texture = None
            self._player = MediaPlayer(filename=self._widget.video_source,
                                       ff_opts={
                                           'paused': True,
                                           'ss': self._widget.video_pos
                                       })
            Clock.schedule_interval(self._start_playback, .1)

    def _start_playback(self, dt):
        if self._player.get_metadata()['duration'] is None:
            return
        if self._player.get_pause():
            self._player.set_pause(False)
        Clock.schedule_once(self._next_frame, 0)
        return False

    def pause_playback(self):
        if self._timer is not None:
            self._timer.cancel()
        if self._player is not None:
            self._player.set_pause(True)
        self._frame = None
        self._texture = None
        if self._widget is not None:
            self._widget.video_state = 'pause'

    def update_video_pos(self, widget, pts):
        if self._widget == widget and self._player is not None:
            self._player.seek(pts=pts, relative=False, accurate=True)
        widget.video_pos = pts

    def _next_frame(self, dt):
        frame, val = self._player.get_frame()
        if val == 'eof':
            self._player.set_pause(True)
            self._player.seek(pts=0, relative=False, accurate=True)
            self._widget.video_image.texture = self._widget.video_cover_image_texture
            self._widget.video_state = 'pause'
            self._widget.video_pos = 0
        elif val == 'paused':
            return
        elif frame is None:
            Clock.schedule_once(self._next_frame, 1 / 100)
        else:
            val = val if val else 1 / 30
            self._frame = frame
            self._trigger()
            Clock.schedule_once(self._next_frame, val)

    def _redraw(self, dt):
        if self._player.get_pause() is None or self._frame is None:
            return
        img, pts = self._frame
        if self._texture is None:
            self._texture = Texture.create(size=img.get_size(), colorfmt='rgb')
            self._texture.flip_vertical()
        self._texture.blit_buffer(img.to_memoryview()[0])
        self._widget.video_image.texture = None
        self._widget.video_image.texture = self._texture
        self._widget.video_pos = pts
예제 #4
0
class Track:
    def __init__(self, name=None, track_id=None):
        # this block of code determines the attribute to be used to construct the object
        # i.e. wether to construct based on a search term of directly from an ID
        self.__type = None
        for attribute in [name, track_id]:
            if attribute is not None:
                self.__type = [
                    key for key, value in locals().items()
                    if value == attribute
                ][0]
        if self.__type is None:
            raise NoAttributesSupplied

        self.track_id = track_id
        self.title = name
        self.fetch_type = None

        print(':::fetching url')
        html = requests.get("https://www.youtube.com/results?search_query=" +
                            self.title.replace(' ', '+'))
        video = pafy.new(
            re.findall(r"watch\?v=(\S{11})", str(html.content))[0])
        best_stream = video.getbestaudio(preftype="wav", ftypestrict=False)

        self.ext = '.' + best_stream.extension
        self.title = filter_search_term(video.title).strip()
        self.url = best_stream.url
        self.filename = self.title + self.ext
        print('video title:::', filter_search_term(video.title))

        # dont repeat if all the data's been already fetched
        if not self.fetch_type is None:
            return

        if self.__type == 'track_id':
            track = spotify.track(self.track_id)
        elif self.__type == 'name':
            track_search = spotify.search(self.title, type='track', limit=1)
            if len(track_search['tracks']['items']) <= 0:
                print(
                    ':::track not available from spotify, doing a minimal fetch'
                )
                if '-' in self.title:
                    self.artists = [self.title.split('-')[0].strip()]
                else:
                    self.artists = None
                self.__artists_names = None
                self.album = None
                self.track_id = None
                self.genres = None
                self.fetch_type = 'minimal'
                return
            else:
                track = track_search['tracks']['items'][0]

        self.track_id = track['id']

        self.artists = []
        self.__artists_names = []
        for artist in track['artists']:
            self.artists.append(Artist(artist_id=artist['id']))
            self.__artists_names.append(artist['name'])

        self.genres = []
        for artist in self.artists:
            for genre in artist.genres:
                self.genres.append(genre)

        self.album = Album(album_id=track['album']['id'])

        self.fetch_type = 'full'

        print(':::fetched')

    def send_notification(self):
        print(":::sending notif")
        # send notification

        # fetch metadata for the track if it has'nt already been fetched
        if self.fetch_type is None:
            self.fetch_metadata()
        message = ''
        if not self.__artists_names is None:
            message = self.__artists_names
            if len(message) == 1: pass
            elif len(message) == 2: message.insert(1, ' and ')
            else:
                increment = 1
                for i in range(len(message)):
                    if not i == len(message) - 1:
                        insert_index = i + increment
                        message.insert(insert_index, ' and ')
                        increment += insert_index + 1
            message = ''.join(message)
        if not self.album is None:
            message += f'\nfrom album {self.album.name}'
        notification.notify(
            title=self.title,
            message=message,
            app_icon=r'C:\users\gadit\downloads\music_icon0.ico',
            app_name='M E L O D I N E',
            timeout=10,
            toast=False)

    def download(self, custom=None, no_part=True):
        global audio_downloader
        audio_downloader = YoutubeDL({
            #'buffersize': 512,
            #'http_chunk_size': 256,
            'audioformat': 'wav',
            'format': 'bestaudio',
            'outtmpl': self.title + self.ext,
            'extractaudio': True,
            'retries': 5,
            'continuedl': True,
            'nopart': no_part,
            'hls_prefer_native': True,
            'quiet': True
        })
        audio_downloader.extract_info(self.url)

    def play(self):
        self.fetch_metadata()
        self.download(no_part=True)
        print('::: downloaded')
        threading._start_new_thread(self.send_notification, ())

        self.player = MediaPlayer(self.filename)
        time.sleep(0.5)
        print('::: playing')

        last_pts = 0
        updated_pts = 0
        while True:
            updated_pts = int(float(str(self.player.get_pts())[:3])) - 3
            print(':::updated', updated_pts)
            # print(player.get_pts())

            while self.player.get_pause():
                time.sleep(0.5)
            if updated_pts == last_pts:
                self.player.toggle_pause()
                print("---buffered out, pausing")
                time.sleep(1)
                self.player.toggle_pause()
            if int(float(str(self.player.get_pts())[:3])) - 3 == int(
                    float(str(
                        self.player.get_metadata()['duration'])[:3])) - 3:
                print(':::breaking')
                self.player.toggle_pause()
                self.player.close_player()

            last_pts = updated_pts
            time.sleep(1)
        print(':::finished playing')
예제 #5
0
class Window(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.Listadd()
        self.step = 0
        self.loop = 1
        self.tag = self.flag = self.listtag = self.fulltag = True
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move(int((screen.width() - size.width()) / 2),
                  int((screen.height() - size.height()) / 2))

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_P:
            self.Listhide()
        if event.key() == Qt.Key_T:
            self.Fastback()
        if event.key() == Qt.Key_L:
            self.Loop()
        if event.key() == Qt.Key_Space:
            self.Play()
        if event.key() == Qt.Key_S:
            self.Stop()
        if event.key() == Qt.Key_F:
            self.Full()
        if event.key() == Qt.Key_J:
            self.Fastforward()
        if event.key() == Qt.Key_M:
            self.Mute()
        if event.key() == Qt.Key_A:
            self.svolume.setValue(self.svolume.value() + 1)
        if event.key() == Qt.Key_R:
            self.svolume.setValue(self.svolume.value() - 1)

    def eventFilter(self, sender, event):
        if (event.type() == event.ChildRemoved):
            self.Moved()
        return False

    def Listmenu(self, position):
        lm = QMenu()
        addact = QAction("添加到播放列表", self, triggered=self.Add)
        removeact = QAction("从播放列表移除", self, triggered=self.Remove)
        renameact = QAction('重命名', self, triggered=self.Rename)
        clearact = QAction('清空播放列表', self, triggered=self.Clear)
        saveact = QAction('保存当前播放列表', self, triggered=self.Saved)
        lm.addAction(addact)
        if self.list.itemAt(position):
            lm.addAction(removeact)
            lm.addAction(renameact)
        lm.addAction(clearact)
        lm.addAction(saveact)
        lm.exec_(self.list.mapToGlobal(position))

    def Listadd(self):
        self.l = []
        self.list.installEventFilter(self)
        if os.path.isfile('CPlayerlist.txt'):
            with open('CPlayerlist.txt') as f:
                for i in f:
                    i = i.strip()
                    name = i[0:i.find(',')]
                    filelist = i[i.find(',') + 1:len(i)]
                    self.list.addItem(name)
                    self.l.append(filelist)

    def Add(self):
        filelists, _ = QFileDialog.getOpenFileNames(self, '添加到播放列表', '.',
                                                    '媒体文件(*)')
        for filelist in filelists:
            name = filelist[filelist.rfind('/') + 1:filelist.rfind('.')]
            self.list.addItem(name)
            self.l.append(filelist)

    def Remove(self):
        ltmp = []
        for i in self.list.selectedIndexes():
            ltmp.append(i.row())
        ltmp.sort(reverse=True)
        for j in ltmp:
            self.list.takeItem(j)
            self.l.pop(j)

    def Rename(self):
        item = self.list.item(self.list.currentRow())
        item.setFlags(item.flags() | Qt.ItemIsEditable)
        self.list.editItem(item)

    def Clear(self):
        self.l = []
        self.list.clear()
        if os.path.isfile('CPlayerlist.txt'):
            os.remove('CPlayerlist.txt')

    def Drag(self):
        self.tmp1 = []
        self.tmp2 = self.l[:]
        for i in range(self.list.count()):
            self.tmp1.append(self.list.item(i).text())

    def Moved(self):
        for i in range(self.list.count()):
            if self.list.item(i).text() == self.tmp1[i]:
                continue
            else:
                self.l[i] = self.tmp2[self.tmp1.index(
                    self.list.item(i).text())]

    def Saved(self):
        with open('CPlayerlist.txt', 'w') as f:
            for i in range(self.list.count()):
                f.write('%s,%s\n' % (self.list.item(i).text(), self.l[i]))
        QMessageBox.information(self, '保存', '播放列表保存成功!')

    def Listhide(self):
        if self.listtag:
            self.frame.hide()
            self.listtag = False
        else:
            self.frame.show()
            self.listtag = True

    def Loop(self):
        if self.loop == 0:
            self.loop = 1
            self.bloop.setIcon(QIcon(r'img\withloop.png'))
            self.bloop.setToolTip('循环播放,快捷键“l”')
        else:
            self.loop = 0
            self.bloop.setIcon(QIcon(r'img\withoutloop.png'))
            self.bloop.setToolTip('取消循环,快捷键“l”')

    def Play(self):
        if self.flag:
            try:
                self.playitem = self.l[self.list.currentRow()]
                if os.path.isfile("%s" % self.playitem):
                    self.player = MediaPlayer("%s" % self.playitem)
                    self.timer = QTimer()
                    self.timer.start(50)
                    self.timer.timeout.connect(self.Show)
                    self.steptimer = QTimer()
                    self.steptimer.start(1000)
                    self.steptimer.timeout.connect(self.Step)
                    self.flag = False
                    self.bplay.setIcon(QIcon(r'img\pause.png'))
                    self.bplay.setToolTip('暂停,快捷键“Space”')
                else:
                    QMessageBox.warning(self, '错误', '找不到要播放的文件!')
            except:
                QMessageBox.warning(self, '错误', '找不到要播放的文件!')
        else:
            if self.l[self.list.currentRow()] == self.playitem:
                self.player.toggle_pause()
                if self.player.get_pause():
                    self.timer.stop()
                    self.steptimer.stop()
                    self.bplay.setIcon(QIcon(r'img\play.png'))
                    self.bplay.setToolTip('播放,快捷键“Space”')
                else:
                    self.timer.start()
                    self.steptimer.start()
                    self.bplay.setIcon(QIcon(r'img\pause.png'))
                    self.bplay.setToolTip('暂停,快捷键“Space”')
            else:
                self.playitem = self.l[self.list.currentRow()]
                if os.path.isfile("%s" % self.playitem):
                    self.step = 0
                    self.stime.setValue(0)
                    self.player = MediaPlayer("%s" % self.playitem)
                    self.timer.start()
                    self.steptimer.start()
                    self.bplay.setIcon(QIcon(r'img\pause.png'))
                    self.bplay.setToolTip('暂停,快捷键“Space”')
                else:
                    QMessageBox.warning(self, '错误', '找不到要播放的文件!')

    def Show(self):
        if self.tag:
            self.player.set_volume(self.svolume.value() / 100)
        else:
            self.player.set_volume(0)
        frame, self.val = self.player.get_frame()
        self.lmedia.setPixmap(QPixmap(''))
        if self.val != 'eof' and frame is not None:
            img, t = frame
            data = img.to_bytearray()[0]
            width, height = img.get_size()
            qimg = QImage(data, width, height, QImage.Format_RGB888)
            self.lmedia.setPixmap(QPixmap.fromImage(qimg))
        self.mediatime = self.player.get_metadata()['duration']
        if self.mediatime:
            self.stime.setMaximum(int(self.mediatime))
            mediamin, mediasec = divmod(self.mediatime, 60)
            mediahour, mediamin = divmod(mediamin, 60)
            playmin, playsec = divmod(self.step, 60)
            playhour, playmin = divmod(playmin, 60)
            self.ltime.setText(
                '%02d:%02d:%02d/%02d:%02d:%02d' %
                (playhour, playmin, playsec, mediahour, mediamin, mediasec))

    def Stop(self):
        if self.flag == False:
            self.player.close_player()
            self.timer.stop()
            self.steptimer.stop()
            self.step = 0
            self.loop = 1
            self.flag = True
            self.stime.setValue(0)
            self.ltime.setText('')
            self.bplay.setIcon(QIcon(r'img\play.png'))
            self.bplay.setToolTip('播放,快捷键“Space”')
            self.lmedia.setPixmap(QPixmap(''))

    def Full(self):
        if self.fulltag:
            self.frame.hide()
            self.frame_2.hide()
            self.showFullScreen()
            self.bfull.setIcon(QIcon(r'img\exitfullscreen.png'))
            self.bfull.setToolTip('退出全屏,快捷键“f”')
            self.fulltag = False
        else:
            self.frame.show()
            self.frame_2.show()
            self.showNormal()
            self.bfull.setIcon(QIcon(r'img\expandfullscreen.png'))
            self.bfull.setToolTip('全屏,快捷键“f”')
            self.fulltag = True

    def Curvol(self):
        self.curvol = self.svolume.value()

    def Mute(self):
        if self.flag == False:
            if self.player.get_volume() != 0:
                self.player.set_volume(0)
                self.bmute.setIcon(QIcon(r'img\withoutvolume.png'))
                self.bmute.setToolTip('取消静音,快捷键“m”')
                self.tag = False
            else:
                if self.svolume.value() != 0:
                    self.player.set_volume(self.svolume.value() / 100)
                else:
                    self.player.set_volume(self.curvol / 100)
                    self.svolume.setValue(self.curvol)
                self.bmute.setIcon(QIcon(r'img\withvolume.png'))
                self.bmute.setToolTip('静音,快捷键“m”')
                self.tag = True

    def Volume(self):
        if self.flag == False:
            if self.svolume.value() == 0:
                self.bmute.setIcon(QIcon(r'img\withoutvolume.png'))
                self.bmute.setToolTip('取消静音,快捷键“m”')
            else:
                self.bmute.setIcon(QIcon(r'img\withvolume.png'))
                self.bmute.setToolTip('静音,快捷键“m”')
            self.player.set_volume(self.svolume.value() / 100)

    def Step(self):
        if self.step >= int(self.mediatime):
            self.step = int(self.mediatime)
            if self.loop == 0:
                self.step = 0
                self.stime.setValue(0)
                self.flag = True
                self.Play()
            else:
                if self.val == 'eof':
                    self.Stop()
        else:
            self.step += 1
            self.stime.setValue(self.step)

    def Slidechanged(self):
        self.step = self.stime.value()

    def Slidemoved(self):
        if self.flag == False:
            self.timer.start()
            self.steptimer.start()
            self.player = MediaPlayer("%s" % self.playitem,
                                      ff_opts={'ss': self.step})
            self.bplay.setIcon(QIcon(r'img\pause.png'))
            self.bplay.setToolTip('暂停,快捷键“Space”')

    def Fastforward(self):
        if self.flag == False:
            self.step += 10
            if self.step >= int(self.mediatime):
                self.stime.setValue(int(self.mediatime))
            self.timer.start()
            self.steptimer.start()
            self.player = MediaPlayer("%s" % self.playitem,
                                      ff_opts={'ss': self.step})
            self.bplay.setIcon(QIcon(r'img\pause.png'))
            self.bplay.setToolTip('暂停,快捷键“Space”')

    def Fastback(self):
        if self.flag == False:
            self.step -= 10
            if self.step <= 0:
                self.step = 0
                self.stime.setValue(0)
            self.timer.start()
            self.steptimer.start()
            self.player = MediaPlayer("%s" % self.playitem,
                                      ff_opts={'ss': self.step})
            self.bplay.setIcon(QIcon(r'img\pause.png'))
            self.bplay.setToolTip('暂停,快捷键“Space”')
예제 #6
0
class Window(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.Listadd()
        self.step = 0
        self.loop = 1
        self.tag = True
        self.flag = True
        self.hidetag = True
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move(int((screen.width() - size.width()) / 2),
                  int((screen.height() - size.height()) / 2))

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_P:
            self.Listhide()
        if event.key() == Qt.Key_T:
            self.Fastback()
        if event.key() == Qt.Key_L:
            self.Loop()
        if event.key() == Qt.Key_Space:
            self.Play()
        if event.key() == Qt.Key_S:
            self.Stop()
        if event.key() == Qt.Key_F:
            self.Full()
        if event.key() == Qt.Key_J:
            self.Fastforward()
        if event.key() == Qt.Key_M:
            self.Mute()
        if event.key() == Qt.Key_A:
            self.svolume.setValue(self.svolume.value() + 1)
        if event.key() == Qt.Key_R:
            self.svolume.setValue(self.svolume.value() - 1)

    def Listadd(self):
        if os.path.isfile('CPlayerlist.txt'):
            with open('CPlayerlist.txt') as f:
                for filelist in f:
                    filelist = filelist.strip()
                    self.list.addItem(filelist)

    def Add(self):
        filelists, _ = QFileDialog.getOpenFileNames(self, '添加到播放列表', '.',
                                                    '媒体文件(*)')
        self.list.addItems(filelists)
        self.Listchanged()

    def Remove(self):
        self.list.takeItem(self.list.currentRow())
        self.Listchanged()

    def Clear(self):
        self.list.clear()
        os.remove('CPlayerlist.txt')

    def Listchanged(self):
        with open('CPlayerlist.txt', 'w') as f:
            for i in range(self.list.count()):
                f.write(self.list.item(i).text() + '\n')

    def Listhide(self):
        if self.hidetag:
            self.frame.hide()
            self.hidetag = False
        else:
            self.frame.show()
            self.hidetag = True

    def Loop(self):
        if self.loop == 0:
            self.loop = 1
            self.bloop.setIcon(QIcon(r'img\withloop.png'))
            self.bloop.setToolTip('循环播放,快捷键“l”')
        else:
            self.loop = 0
            self.bloop.setIcon(QIcon(r'img\withoutloop.png'))
            self.bloop.setToolTip('取消循环,快捷键“l”')

    def Play(self):
        if self.flag:
            try:
                self.playitem = self.list.currentItem().text()
                if os.path.isfile("%s" % self.playitem):
                    self.player = MediaPlayer("%s" % self.playitem)
                    self.timer = QTimer()
                    self.timer.start(50)
                    self.timer.timeout.connect(self.Show)
                    self.steptimer = QTimer()
                    self.steptimer.start(1000)
                    self.steptimer.timeout.connect(self.Step)
                    self.flag = False
                    self.bplay.setIcon(QIcon(r'img\pause.png'))
                    self.bplay.setToolTip('暂停,快捷键“Space”')
                else:
                    QMessageBox.warning(self, '错误', '找不到要播放的文件!')
            except:
                QMessageBox.warning(self, '错误', '找不到要播放的文件!')
        else:
            if self.list.currentItem().text() == self.playitem:
                self.player.toggle_pause()
                if self.player.get_pause():
                    self.timer.stop()
                    self.steptimer.stop()
                    self.bplay.setIcon(QIcon(r'img\play.png'))
                    self.bplay.setToolTip('播放,快捷键“Space”')
                else:
                    self.timer.start()
                    self.steptimer.start()
                    self.bplay.setIcon(QIcon(r'img\pause.png'))
                    self.bplay.setToolTip('暂停,快捷键“Space”')
            else:
                self.playitem = self.list.currentItem().text()
                if os.path.isfile("%s" % self.playitem):
                    self.step = 0
                    self.stime.setValue(0)
                    self.player = MediaPlayer("%s" % self.playitem)
                    self.timer.start()
                    self.steptimer.start()
                else:
                    QMessageBox.warning(self, '错误', '找不到要播放的文件!')

    def Show(self):
        if self.tag:
            self.player.set_volume(self.svolume.value() / 100)
        else:
            self.player.set_volume(0)
        frame, self.val = self.player.get_frame()
        self.lmedia.setPixmap(QPixmap(''))
        if self.val != 'eof' and frame is not None:
            img, t = frame
            data = img.to_bytearray()[0]
            width, height = img.get_size()
            qimg = QImage(data, width, height, QImage.Format_RGB888)
            self.lmedia.setPixmap(QPixmap.fromImage(qimg))
        self.mediatime = self.player.get_metadata()['duration']
        if self.mediatime:
            self.stime.setMaximum(int(self.mediatime))
            mediamin, mediasec = divmod(self.mediatime, 60)
            mediahour, mediamin = divmod(mediamin, 60)
            playmin, playsec = divmod(self.step, 60)
            playhour, playmin = divmod(playmin, 60)
            self.ltime.setText(
                '%02d:%02d:%02d/%02d:%02d:%02d' %
                (playhour, playmin, playsec, mediahour, mediamin, mediasec))

    def Stop(self):
        if self.flag == False:
            self.player.close_player()
            self.timer.stop()
            self.steptimer.stop()
            self.step = 0
            self.loop = 1
            self.flag = True
            self.stime.setValue(0)
            self.ltime.setText('')
            self.bplay.setIcon(QIcon(r'img\play.png'))
            self.bplay.setToolTip('播放,快捷键“Space”')
            self.lmedia.setPixmap(QPixmap(''))

    def Full(self):
        if self.hidetag:
            self.setWindowFlags(Qt.FramelessWindowHint)
            rect = QApplication.desktop().geometry()
            self.setGeometry(rect)
            self.frame.hide()
            self.frame_2.hide()
            self.show()
            self.bfull.setIcon(QIcon(r'img\exitfullscreen.png'))
            self.bfull.setToolTip('退出全屏,快捷键“f”')
            self.hidetag = False
        else:
            self.setWindowFlags(Qt.Widget)
            self.setGeometry(0, 0, 1144, 705)
            self.frame.show()
            self.frame_2.show()
            screen = QDesktopWidget().screenGeometry()
            size = self.geometry()
            self.move(int((screen.width() - size.width()) / 2),
                      int((screen.height() - size.height()) / 2))
            self.show()
            self.bfull.setIcon(QIcon(r'img\expandfullscreen.png'))
            self.bfull.setToolTip('全屏,快捷键“f”')
            self.hidetag = True

    def Curvol(self):
        self.curvol = self.svolume.value()

    def Mute(self):
        if self.flag == False:
            if self.player.get_volume() != 0:
                self.player.set_volume(0)
                self.bmute.setIcon(QIcon(r'img\withoutvolume.png'))
                self.bmute.setToolTip('取消静音,快捷键“m”')
                self.tag = False
            else:
                if self.svolume.value() != 0:
                    self.player.set_volume(self.svolume.value() / 100)
                else:
                    self.player.set_volume(self.curvol / 100)
                    self.svolume.setValue(self.curvol)
                self.bmute.setIcon(QIcon(r'img\withvolume.png'))
                self.bmute.setToolTip('静音,快捷键“m”')
                self.tag = True

    def Volume(self):
        if self.flag == False:
            if self.svolume.value() == 0:
                self.bmute.setIcon(QIcon(r'img\withoutvolume.png'))
                self.bmute.setToolTip('取消静音,快捷键“m”')
            else:
                self.bmute.setIcon(QIcon(r'img\withvolume.png'))
                self.bmute.setToolTip('静音,快捷键“m”')
            self.player.set_volume(self.svolume.value() / 100)

    def Step(self):
        if self.step >= int(self.mediatime):
            self.step = int(self.mediatime)
            if self.loop == 0:
                self.step = 0
                self.flag = True
                self.Play()
            else:
                if self.val == 'eof':
                    self.timer.stop()
                    self.steptimer.stop()
                    self.step = 0
                    self.loop = 1
                    self.flag = True
                    self.stime.setValue(0)
                    self.player.close_player()
                    self.bplay.setIcon(QIcon(r'img\play.png'))
                    self.bplay.setToolTip('播放,快捷键“Space”')
        else:
            self.step += 1
            self.stime.setValue(self.step)

    def Slidechanged(self):
        self.step = self.stime.value()

    def Slidemoved(self):
        self.timer.start()
        self.steptimer.start()
        self.player = MediaPlayer("%s" % self.playitem,
                                  ff_opts={'ss': self.step})
        self.bplay.setIcon(QIcon(r'img\pause.png'))
        self.bplay.setToolTip('暂停,快捷键“Space”')

    def Fastforward(self):
        if self.flag == False:
            self.step += 10
            if self.step >= int(self.mediatime):
                self.stime.setValue(int(self.mediatime))
            self.timer.start()
            self.steptimer.start()
            self.player = MediaPlayer("%s" % self.playitem,
                                      ff_opts={'ss': self.step})
            self.bplay.setIcon(QIcon(r'img\pause.png'))
            self.bplay.setToolTip('暂停,快捷键“Space”')

    def Fastback(self):
        if self.flag == False:
            self.step -= 10
            if self.step <= 0:
                self.step = 0
            self.timer.start()
            self.steptimer.start()
            self.player = MediaPlayer("%s" % self.playitem,
                                      ff_opts={'ss': self.step})
            self.bplay.setIcon(QIcon(r'img\pause.png'))
            self.bplay.setToolTip('暂停,快捷键“Space”')
예제 #7
0
class PlayerThread(QThread):
    image_sig = pyqtSignal(QtGui.QImage)
    status_sig = pyqtSignal(bool)
    progress_sig = pyqtSignal(float)

    def __init__(self, parent):
        super().__init__(parent)
        self.label = parent.label
        self.image_sig.connect(parent.set_image)
        self.status_sig.connect(parent.set_status)
        self.progress_sig.connect(parent.set_progress)
        self.player = None
        self.duration = None
        self.progress = 0
        self.ratio_mode = Qt.KeepAspectRatio
        self.config = {}

    def set_video_name(self, video_name):
        if self.player is not None:
            self.player.close_player()
        self.player = MediaPlayer(video_name)
        self.status_sig.emit(self.player.get_pause())
        self.start()

    def set_config(self, config):
        self.config = config

    def close(self):
        if self.player is not None:
            self.player.close_player()
        self.quit()

    def pause(self):
        if self.player is not None:
            self.player.set_pause(True)
            self.status_sig.emit(True)

    def toggle_pause(self):
        if self.player is not None:
            self.player.toggle_pause()
            self.status_sig.emit(self.player.get_pause())

    def next_prev(self, is_forward):
        if self.player is not None:
            chunk_position = self.find_chunk(self.progress)
            if is_forward:
                if chunk_position < self.config['total'] - 1:
                    chunk_position += 1
                    self.player.seek(self.config['chunks'][chunk_position][0] / 1000, relative=False, accurate=False)
            else:
                if chunk_position > 0:
                    chunk_position -= 1
                self.player.seek(self.config['chunks'][chunk_position][0] / 1000, relative=False, accurate=False)

    def find_chunk(self, pts):
        if self.config:
            pts_ms = int(1000 * pts)
            front = 0
            rear = self.config['total'] - 1
            chunks = self.config['chunks']
            while front != rear:
                middle = (front + rear) // 2
                if pts_ms > chunks[middle][0]:
                    if pts_ms < chunks[middle + 1][0]:
                        break
                    else:
                        front = middle + 1
                else:
                    rear = middle
            return (front + rear) // 2
        else:
            return 0

    def seek(self, ratio):
        if self.duration is not None:
            pts = ratio * self.duration
            self.player.seek(pts, relative=False, accurate=False)

    def image_stretch(self, is_stretch):
        if is_stretch:
            self.ratio_mode = Qt.IgnoreAspectRatio
        else:
            self.ratio_mode = Qt.KeepAspectRatio

    def run(self):
        val = ''
        while val != 'eof':
            frame, val = self.player.get_frame()
            if self.duration is None:
                self.duration = self.player.get_metadata()['duration']
            if val != 'eof' and frame is not None:
                img, t = frame
                if img is not None:
                    byte = img.to_bytearray()[0]
                    width, height = img.get_size()
                    convert_to_qt_format = QtGui.QImage(byte, width, height, QImage.Format_RGB888)
                    p = convert_to_qt_format.scaled(self.label.width(), self.label.height(), self.ratio_mode)
                    self.image_sig.emit(p)
                    self.progress = t
                    if self.duration is not None:
                        self.progress_sig.emit(t / self.duration)
                    time.sleep(val)
예제 #8
0
class FFPyPlayer(BaseMoviePlayer):
    """Interface class for the FFPyPlayer library for use with `MovieStim`.

    This class also serves as the reference implementation for classes which
    interface with movie codec libraries for use with `MovieStim`. Creating new
    player classes which closely replicate the behaviour of this one should
    allow them to smoothly plug into `MovieStim`.

    """
    _movieLib = 'ffpyplayer'

    def __init__(self, parent):
        self._filename = u""

        self.parent = parent

        # handle to `ffpyplayer`
        self._handle = None

        # thread for reading frames asynchronously
        self._tStream = None

        # data from stream thread
        self._lastFrame = NULL_MOVIE_FRAME_INFO
        self._frameIndex = -1
        self._loopCount = 0
        self._metadata = None  # metadata from the stream

        self._lastPlayerOpts = DEFAULT_FF_OPTS.copy()

        # options from the parent
        if self.parent.loop:  # infinite loop
            self._lastPlayerOpts['loop'] = 0
        else:
            self._lastPlayerOpts['loop'] = 1  # play once

        if hasattr(self.parent, '_noAudio'):
            self._lastPlayerOpts['an'] = self.parent._noAudio

        # status flags
        self._status = NOT_STARTED

    def start(self, log=True):
        """Initialize and start the decoder. This method will return when a
        valid frame is made available.

        """
        # clear queued data from previous streams
        self._lastFrame = None
        self._frameIndex = -1

        # open the media player
        self._handle = MediaPlayer(self._filename,
                                   ff_opts=self._lastPlayerOpts)
        self._handle.set_pause(True)

        # Pull the first frame to get metadata. NB - `_enqueueFrame` should be
        # able to do this but the logic in there depends on having access to
        # metadata first. That may be rewritten at some point to reduce all of
        # this to just a single `_enqeueFrame` call.
        #
        self._status = NOT_STARTED

        # hand off the player interface to the thread
        self._tStream = MovieStreamThreadFFPyPlayer(self._handle)
        self._tStream.begin()

        # make sure we have metadata
        self.update()

    def load(self, pathToMovie):
        """Load a movie file from disk.

        Parameters
        ----------
        pathToMovie : str
            Path to movie file, stream (URI) or camera. Must be a format that
            FFMPEG supports.

        """
        # set the file path
        self._filename = pathToString(pathToMovie)

        # Check if the player is already started. Close it and load a new
        # instance if so.
        if self._handle is not None:  # player already started
            # make sure it's the correct type
            if not isinstance(self._handle, MediaPlayer):
                raise TypeError(
                    'Incorrect type for `FFMovieStim._player`, expected '
                    '`ffpyplayer.player.MediaPlayer`. Got type `{}` '
                    'instead.'.format(type(self._handle).__name__))

            # close the player and reset
            self.unload()

            # self._selectWindow(self.win)  # free buffers here !!!

        self.start()

        self._status = NOT_STARTED

    def unload(self):
        """Unload the video stream and reset.
        """
        self._handle.close_player()
        self._filename = u""
        self._frameIndex = -1
        self._handle = None  # reset

    @property
    def handle(self):
        """Handle to the `MediaPlayer` object exposed by FFPyPlayer. If `None`,
        no media player object has yet been initialized.
        """
        return self._handle

    @property
    def isLoaded(self):
        return self._handle is not None

    @property
    def metadata(self):
        """Most recent metadata (`MovieMetadata`).
        """
        return self.getMetadata()

    def getMetadata(self):
        """Get metadata from the movie stream.

        Returns
        -------
        MovieMetadata
            Movie metadata object. If no movie is loaded, `NULL_MOVIE_METADATA`
            is returned. At a minimum, fields `duration`, `size`, and
            `frameRate` are populated if a valid movie has been previously
            loaded.

        """
        self._assertMediaPlayer()

        metadata = self._metadata

        # write metadata to the fields of a `MovieMetadata` object
        toReturn = MovieMetadata(mediaPath=self._filename,
                                 title=metadata['title'],
                                 duration=metadata['duration'],
                                 frameRate=metadata['frame_rate'],
                                 size=metadata['src_vid_size'],
                                 pixelFormat=metadata['src_pix_fmt'],
                                 movieLib=self._movieLib,
                                 userData=None)

        return toReturn

    def _assertMediaPlayer(self):
        """Ensure the media player instance is available. Raises a
        `RuntimeError` if no movie is loaded.
        """
        if isinstance(self._handle, MediaPlayer):
            return  # nop if we're good

        raise RuntimeError(
            "Calling this class method requires a successful call to "
            "`load` first.")

    @property
    def status(self):
        """Player status flag (`int`).
        """
        return self._status

    @property
    def isPlaying(self):
        """`True` if the video is presently playing (`bool`)."""
        # Status flags as properties are pretty useful for users since they are
        # self documenting and prevent the user from touching the status flag
        # attribute directly.
        #
        return self.status == PLAYING

    @property
    def isNotStarted(self):
        """`True` if the video has not be started yet (`bool`). This status is
        given after a video is loaded and play has yet to be called.
        """
        return self.status == NOT_STARTED

    @property
    def isStopped(self):
        """`True` if the movie has been stopped.
        """
        return self.status == STOPPED

    @property
    def isPaused(self):
        """`True` if the movie has been paused.
        """
        self._assertMediaPlayer()

        return self._handle.get_pause()

    @property
    def isFinished(self):
        """`True` if the video is finished (`bool`).
        """
        # why is this the same as STOPPED?
        return self.status == FINISHED

    def play(self, log=False):
        """Start or continue a paused movie from current position.

        Parameters
        ----------
        log : bool
            Log the play event.

        Returns
        -------
        int or None
            Frame index playback started at. Should always be `0` if starting at
            the beginning of the video. Returns `None` if the player has not
            been initialized.

        """
        self._assertMediaPlayer()

        self._tStream.play()

        self._status = PLAYING

    def stop(self, log=False):
        """Stop the current point in the movie (sound will stop, current frame
        will not advance). Once stopped the movie cannot be restarted - it must
        be loaded again.

        Use `pause()` instead if you may need to restart the movie.

        Parameters
        ----------
        log : bool
            Log the stop event.

        """
        if self._tStream is None:
            raise RuntimeError("Cannot close stream, not opened yet.")

        # close the thread
        if not self._tStream.isDone():
            self._tStream.shutdown()
        self._tStream.join()  # wait until thread exits
        self._tStream = None

        if self._handle is not None:
            self._handle.close_player()
            self._handle = None  # reset

    def pause(self, log=False):
        """Pause the current point in the movie. The image of the last frame
        will persist on-screen until `play()` or `stop()` are called.

        Parameters
        ----------
        log : bool
            Log this event.

        """
        self._assertMediaPlayer()

        self._tStream.pause()

        return False

    def seek(self, timestamp, log=False):
        """Seek to a particular timestamp in the movie.

        Parameters
        ----------
        timestamp : float
            Time in seconds.
        log : bool
            Log the seek event.

        """
        raise NotImplementedError(
            "This feature is not available for the current backend.")

    def rewind(self, seconds=5, log=False):
        """Rewind the video.

        Parameters
        ----------
        seconds : float
            Time in seconds to rewind from the current position. Default is 5
            seconds.
        log : bool
            Log this event.

        Returns
        -------
        float
            Timestamp after rewinding the video.

        """
        raise NotImplementedError(
            "This feature is not available for the current backend.")

    def fastForward(self, seconds=5, log=False):
        """Fast-forward the video.

        Parameters
        ----------
        seconds : float
            Time in seconds to fast forward from the current position. Default
            is 5 seconds.
        log : bool
            Log this event.

        Returns
        -------
        float
            Timestamp at new position after fast forwarding the video.

        """
        raise NotImplementedError(
            "This feature is not available for the current backend.")

    def replay(self, autoStart=True, log=False):
        """Replay the movie from the beginning.

        Parameters
        ----------
        autoStart : bool
            Start playback immediately. If `False`, you must call `play()`
            afterwards to initiate playback.
        log : bool
            Log this event.

        Notes
        -----
        * This tears down the current media player instance and creates a new
          one. Similar to calling `stop()` and `loadMovie()`. Use `seek(0.0)` if
          you would like to restart the movie without reloading.

        """
        lastMovieFile = self._filename
        self.stop()  # stop the movie
        # self._autoStart = autoStart
        self.load(lastMovieFile)  # will play if auto start

    # --------------------------------------------------------------------------
    # Audio stream control methods
    #

    @property
    def muted(self):
        """`True` if the stream audio is muted (`bool`).
        """
        return self._handle.get_mute()  # thread-safe?

    @muted.setter
    def muted(self, value):
        self._tStream.setMute(value)

    def volumeUp(self, amount):
        """Increase the volume by a fixed amount.

        Parameters
        ----------
        amount : float or int
            Amount to increase the volume relative to the current volume.

        """
        self._assertMediaPlayer()

        # get the current volume from the player
        self.volume = self.volume + amount

        return self.volume

    def volumeDown(self, amount):
        """Decrease the volume by a fixed amount.

        Parameters
        ----------
        amount : float or int
            Amount to decrease the volume relative to the current volume.

        """
        self._assertMediaPlayer()

        # get the current volume from the player
        self.volume = self.volume - amount

        return self.volume

    @property
    def volume(self):
        """Volume for the audio track for this movie (`int` or `float`).
        """
        self._assertMediaPlayer()

        return self._handle.get_volume()  # thread-safe?

    @volume.setter
    def volume(self, value):
        self._assertMediaPlayer()
        self._tStream.setVolume(max(min(value, 1.0), 0.0))

    @property
    def loopCount(self):
        """Number of loops completed since playback started (`int`). This value
        is reset when either `stop` or `loadMovie` is called.
        """
        return self._loopCount

    # --------------------------------------------------------------------------
    # Timing related methods
    #
    # The methods here are used to handle timing, such as converting between
    # movie and experiment timestamps.
    #

    @property
    def pts(self):
        """Presentation timestamp for the current movie frame in seconds
        (`float`).

        The value for this either comes from the decoder or some other time
        source. This should be synchronized to the start of the audio track. A
        value of `-1.0` is invalid.

        """
        if self._handle is None:
            return -1.0

        return self._lastFrame.absTime

    def getStartAbsTime(self):
        """Get the absolute experiment time in seconds the movie starts at
        (`float`).

        This value reflects the time which the movie would have started if
        played continuously from the start. Seeking and pausing the movie causes
        this value to change.

        Returns
        -------
        float
            Start time of the movie in absolute experiment time.

        """
        self._assertMediaPlayer()

        return getTime() - self._lastFrame.absTime

    def movieToAbsTime(self, movieTime):
        """Convert a movie timestamp to absolute experiment timestamp.

        Parameters
        ----------
        movieTime : float
            Movie timestamp to convert to absolute experiment time.

        Returns
        -------
        float
            Timestamp in experiment time which is coincident with the provided
            `movieTime` timestamp. The returned value should usually be precise
            down to about five decimal places.

        """
        self._assertMediaPlayer()

        # type checks on parameters
        if not isinstance(movieTime, float):
            raise TypeError(
                "Value for parameter `movieTime` must have type `float` or "
                "`int`.")

        return self.getStartAbsTime() + movieTime

    def absToMovieTime(self, absTime):
        """Convert absolute experiment timestamp to a movie timestamp.

        Parameters
        ----------
        absTime : float
            Absolute experiment time to convert to movie time.

        Returns
        -------
        float
            Movie time referenced to absolute experiment time. If the value is
            negative then provided `absTime` happens before the beginning of the
            movie from the current time stamp. The returned value should usually
            be precise down to about five decimal places.

        """
        self._assertMediaPlayer()

        # type checks on parameters
        if not isinstance(absTime, float):
            raise TypeError(
                "Value for parameter `absTime` must have type `float` or "
                "`int`.")

        return absTime - self.getStartAbsTime()

    def movieTimeFromFrameIndex(self, frameIdx):
        """Get the movie time a specific a frame with a given index is
        scheduled to be presented.

        This is used to handle logic for seeking through a video feed (if
        permitted by the player).

        Parameters
        ----------
        frameIdx : int
            Frame index. Negative values are accepted but they will return
            negative timestamps.

        """
        self._assertMediaPlayer()

        return frameIdx * self._metadata.frameInterval

    def frameIndexFromMovieTime(self, movieTime):
        """Get the frame index of a given movie time.

        Parameters
        ----------
        movieTime : float
            Timestamp in movie time to convert to a frame index.

        Returns
        -------
        int
            Frame index that should be presented at the specified movie time.

        """
        self._assertMediaPlayer()

        return math.floor(movieTime / self._metadata.frameInterval)

    @property
    def isSeekable(self):
        """Is seeking allowed for the video stream (`bool`)? If `False` then
        `frameIndex` will increase monotonically.
        """
        return False  # fixed for now

    @property
    def frameInterval(self):
        """Duration a single frame is to be presented in seconds (`float`). This
        is derived from the framerate information in the metadata. If not movie
        is loaded, the returned value will be invalid.
        """
        return self.metadata.frameInterval

    @property
    def frameIndex(self):
        """Current frame index (`int`).

        Index of the current frame in the stream. If playing from a file or any
        other seekable source, this value may not increase monotonically with
        time. A value of `-1` is invalid, meaning either the video is not
        started or there is some issue with the stream.

        """
        return self._lastFrame.frameIndex

    def getPercentageComplete(self):
        """Provides a value between 0.0 and 100.0, indicating the amount of the
        movie that has been already played (`float`).
        """
        duration = self.metadata.duration

        return (self.pts / duration) * 100.0

    # --------------------------------------------------------------------------
    # Methods for getting video frames from the encoder
    #

    def _enqueueFrame(self):
        """Grab the latest frame from the stream.

        Returns
        -------
        bool
            `True` if a frame has been enqueued. Returns `False` if the camera
            is not ready or if the stream was closed.

        """
        self._assertMediaPlayer()

        # If the queue is empty, the decoder thread has not yielded a new frame
        # since the last call.
        enqueuedFrame = self._tStream.getRecentFrame()
        if enqueuedFrame is None:
            return False

        # Unpack the data we got back ...
        # Note - Bit messy here, we should just hold onto the `enqueuedFrame`
        # instance and reference its fields from properties. Keeping like this
        # for now.
        frameImage = enqueuedFrame.frameImage
        streamStatus = enqueuedFrame.streamStatus
        self._metadata = enqueuedFrame.metadata
        self.parent.status = self._status = streamStatus.status
        self._frameIndex = streamStatus.frameIndex
        self._loopCount = streamStatus.loopCount

        # status information
        self._streamTime = streamStatus.streamTime  # stream time for the camera

        # if we have a new frame, update the frame information
        videoBuffer = frameImage.to_bytearray()[0]
        videoFrameArray = np.frombuffer(videoBuffer, dtype=np.uint8)

        # provide the last frame
        self._lastFrame = MovieFrame(
            frameIndex=self._frameIndex,
            absTime=self._streamTime,
            displayTime=self.metadata.frameInterval,
            size=frameImage.get_size(),
            colorData=videoFrameArray,
            audioChannels=0,  # not populated yet ...
            audioSamples=None,
            metadata=self.metadata,
            movieLib=u'ffpyplayer',
            userData=None)

        return True

    def update(self):
        """Update this player.

        This get the latest data from the video stream and updates the player
        accordingly. This should be called at a higher frequency than the frame
        rate of the movie to avoid frame skips.

        """
        self._assertMediaPlayer()

        # check if the stream reader thread is present and alive, if not the
        # movie is finished
        if not self._tStream.isDone():
            self._enqueueFrame()
        else:
            self.parent.status = self._status = FINISHED

    def getMovieFrame(self):
        """Get the movie frame scheduled to be displayed at the current time.

        Returns
        -------
        `~psychopy.visual.movies.frame.MovieFrame`
            Current movie frame.

        """
        self.update()

        return self._lastFrame

    def __del__(self):
        """Cleanup when unloading.
        """
        if hasattr(self, '_tStream'):
            if self._tStream is not None:
                if not self._tStream.isDone():
                    self._tStream.shutdown()
                self._tStream.join()

        if hasattr(self, '_handle'):
            if self._handle is not None:
                self._handle.close_player()
예제 #9
0
class VideoStream:
    def __init__(self, video_source=None):
        ff_opts = {'paused': True, 'autoexit': False}  # Audio options
        self.video_surce = video_source
        # Open the video source
        self.player = MediaPlayer(video_source, ff_opts=ff_opts)
        # TODO: colocar pausa de tiempo para cargas mediaplayer y obtener los datos
        # conseguir el frame rate para la sincronizacion self.dalay
        while self.player.get_metadata()['src_vid_size'] == (0, 0):
            time.sleep(0.01)
        data = self.player.get_metadata()
        print('data -->', data)
        self.f_rate = data['frame_rate']
        print('delay -> ', self.f_rate)
        self.w, self.h = data['src_vid_size']
        print('WxH -> ', self.w, self.h)
        self.pts = self.player.get_pts(
        )  # Returns the elapsed play time. float
        print('pts ->', self.pts)
        self.duration = data['duration']
        print('duration', self.duration)
        self.pause = self.player.get_pause(
        )  # Returns whether the player is paused.
        print('pause ->', self.pause)
        self.volume = self.player.get_volume(
        )  # Returns the volume of the audio. loat: A value between 0.0 - 1.0
        print('volume ->', self.volume)
        self.player.toggle_pause(
        )  # Toggles -alterna- the player’s pause state
        # self.player.set_pause(False) # auses or un-pauses the file. state: bool
        cond = True
        while cond:
            self.l_frame, self.val = self.player.get_frame()
            if self.val == 'eof':
                print('can not open source: ', video_source)
                break
            elif self.l_frame is None:
                time.sleep(0.01)
            else:
                self._imagen, self.pts = self.l_frame
                print('pts ->', self.pts)
                # arr = self._imagen.to_memoryview()[0] # array image
                # self.imagen = Image.frombytes("RGB", self.original_size, arr.memview)
                # self.imagen.show()
                cond = False

    # propierties.
    @property
    def f_rate(self):
        return self.__f_rate

    @f_rate.setter
    def f_rate(self, val):
        import math
        vn = val[0]
        vd = val[1]
        if vd <= 1:
            self.__f_rate = vn
        elif vd > 1:
            self.__f_rate = int(round(vn / vd))
        else:
            self.__f_rate = 30

    # end properties.

    def get_frame(self):
        '''
        Return valores:
            val : 'eof' or 'pause' 
            pts : time location aduio imagen.
            imagen : frame image
        Return (val, t, imagen)
        '''
        self.l_frame, self.val = self.player.get_frame()
        if self.val == 'eof':
            # condicion final fichero, salimos if and while
            # self.player.toggle_pause() # ponemos en pause
            return self.val, None, None
        elif self.l_frame is None:
            time.sleep(0.01)
            return self.val, None, None
        else:
            # import math
            self._imagen, self.pts = self.l_frame
            return self.val, self.pts, self._imagen
            # w, h = self._imagen.get_size()
            # linesize = [int(math.ceil(w * 3 / 32.) * 32)]
            # self._imagen = pic.Image(plane_buffers=[bytes(b' ') * (h * linesize[0])],
            #             pix_fmt=self._imagen.get_pixel_format(), size=(w, h), linesize=linesize)
            # self._imagen.get_linesizes(keep_align=True)

            # if self.new_size is not None:
            #     sws = None
            #     n_w , n_h = self.new_size
            #     if n_w > n_h:
            #         sws = pic.SWScale(w, h, self._imagen.get_pixel_format(), oh=n_h)
            #     else:
            #         sws = pic.SWScale(w, h, self._imagen.get_pixel_format(), ow=n_w)
            #     self._imagen = sws.scale(self._imagen)

            # size = self._imagen.get_size()
            # arr = self._imagen.to_memoryview()[0] # array image
            # self.imagen = Image.frombytes("RGB", size, arr.memview)
            # print('>>> videostream::get_frame()::self.pts ->', self.pts)

    def toggle_pause(self):
        '''
            Function: toggle_pause
        '''
        try:  # Stopping audio
            self.player.toggle_pause()
            # self.player = None
        except:
            pass

    def seek(self, pts=None, relative=False, accurate=False):
        if not pts:
            return
        self.player.seek(pts, relative=False, accurate=False)

    def snapshot(self, road=None):
        '''
        get current frame
        '''
        img = self.l_frame[0]
        if img is not None:
            size = img.get_size()
            arr = img.to_memoryview()[0]  # array image
            img = Image.frombytes("RGB", size, arr.memview)
            # vamos a guardar esto.
            time_str = time.strftime("%d-%m-%Y-%H-%M-%S")
            frame_name = f"frame-{time_str}.jpg"
            if not road:
                ruta = os.path.dirname(self.video_surce)
                name_out = os.path.join(ruta, frame_name)
            else:
                name_out = os.path.join(road, frame_name)
            img.save(name_out)

    # Release the video source when the object is destroyed
    def __del__(self):
        self.player.close_player()
        print('__del__')