def createPlaylistDock(self): # from playlist import PlayList self.next_id = 0 # self.playlist = PlayList(self, None) self.propertydock = Q.QDockWidget() self.propertydock.setWindowTitle("Playlist") self.propertydock.setFeatures(Q.QDockWidget.DockWidgetFloatable | Q.QDockWidget.DockWidgetMovable) tw = Q.QTabWidget(parent=self.propertydock) player = self.playerwidget player._property_model = AVTreePropertyModel(player=player, parent=player) if self._use_tree: tv = Q.QTreeView() tv.setModel(player._property_model) tw.addTab(tv, 'tree') tv.header().setSectionResizeMode(Q.QHeaderView.Stretch) # player._flat_model = AVFlatPropertyModel(player=player, parent=player) # if self._use_table: # self.propertymodel= AVFlatPropertyModel(player=self.playerwidget,parent=self) # self.propertyview = Q.QTableView(self.propertydock) # self.propertyview.setModel(player._flat_model) # tw.addTab(self.propertyview, 'table') # self.propertyview.horizontalHeader().setSectionResizeMode(Q.QHeaderView.Stretch) self.propertydock.setWidget(tw) tw.show() tw.parent().adjustSize() tw.parent().update() self.propertydock.show()
def index(self, row, column, parent): if not self.hasIndex(row, column, parent): return Q.QModelIndex() if not parent.isValid(): parentItem = self._rootItem else: parentItem = parent.internalPointer() childItem = parentItem.child(row) if childItem: return self.createIndex(row, column, childItem) else: return Q.QModelIndex()
def parent(self, index): if not index: return Q.QModelIndex() if not index.isValid(): return Q.QModelIndex() childItem = index.internalPointer() if not childItem: return Q.QModelIndex() parentItem = childItem.parent if not parentItem: return Q.QModelIndex() if parentItem is self._rootItem: return Q.QModelIndex() return self.indexForItem(parentItem)
def __init__(self, *args, **kwargs): player = kwargs.pop('player', None) self._player = player super().__init__(*args, **kwargs) self._headerData = ["name", "value"] self._rootItem = TreeItem(name='root', player=player) self.setupModelData(player) print(self.__class__.__name__, 'rowCount() is ', self.rowCount(Q.QModelIndex()))
def __init__(self, *args, fp=None, **kwargs): super().__init__(*args, **kwargs) self._timer = Q.QTimer() # self._timer.setInterval(int(1000/30)) self._timer.setTimerType(Q.Qt.PreciseTimer) tw = Q.QTabWidget(parent=self) cw = CtrlPlayer(*args, parent=self, **kwargs) tw.addTab(cw, "video") cw.childwidget.resize(self.size()) player = cw.childwidget # player._property_model = AVTreePropertyModel(player=player,parent=player) # tv = Q.QTreeView() # tv.setModel(player._property_model) # tw.addTab(tv,"properties") tw.setVisible(True) self.widget = cw self.playerwidget = player # self._timer.timeout.connect(self.update) # self._timer.timeout.connect(cw.update) self._timer.timeout.connect(cw.childwidget.update) # self.widget = CtrlPlayer(fp=fp,parent=self) # self.playerwidget = self.widget.childwidget self.setCentralWidget(tw) # self.toolbar = Q.QDockWidget() # self.toolbar.setFeatures(Q.QDockWidget.DockWidgetFloatable| Q.QDockWidget.DockWidgetMovable) # self.toolbar.setWidget(toolbargroup) # self.addDockWidget(Q.Qt.BottomDockWidgetArea,self.toolbar) # self.toolbar.show() # def finishPlaylist(self): # self.createPlaylistDock() # self.addDockWidget(Q.Qt.LeftDockWidgetArea,self.propertydock) # self.propertydock.fileMenu = fileMenu = self.menuBar().addMenu("&File") # fileMenu = self.propertydock.fileMenu fileMenu.addAction("&Open...", self.widget.openFile, "Ctrl+O") fileMenu.addAction("O&pen Url...", self.widget.openUrl, "Ctrl+Shift+O") fileMenu.addAction("E&xit", self.close, "Ctrl+Q")
def openFile(self, near=None): fileDialog = Q.QFileDialog(self) fileDialog.setAcceptMode(Q.QFileDialog.AcceptOpen) fileDialog.setFileMode(Q.QFileDialog.ExistingFiles) fileDialog.setFilter(Q.QDir.Hidden | Q.QDir.AllEntries | Q.QDir.System) fileDialog.setViewMode(Q.QFileDialog.Detail) if near is not None: if isinstance(near, str): near = Q.QFileInfo(near) if isinstance(near, Q.QFileInfo): if near.isDir(): near = Q.QDir(near.filePath()) else: near = near.dir() if not isinstance(near, Q.QDir): near = Q.QDir.home() fileDialog.setDirectory(near.canonicalPath()) if fileDialog.exec(): if fileDialog.selectedFiles(): for filePath in fileDialog.selectedFiles(): print("\n" + filePath + "\n") self.childwidget.try_command("loadfile", str(filePath), "append-play")
def reconfig(self, width, height): if width > 0 and width < 2**16: self.vwidth = width if height > 0 and height < 2**16: self.vheight = height if self.vwidth and self.vheight: self.childwidget.img_width = self.vwidth self.childwidget.img_height = self.vheight if (not self.sized_once) and width: self.childwidget.setMinimumSize( Q.QSize(self.vwidth, self.vheight)) self.adjustSize() self.adjustSize() parent = self.parent() if parent: parent.adjustSize() parent = parent.parent() if parent: parent.adjustSize() self.window().update() if not self.sized_once: self.sized_once = True self.show()
parser.add_argument('path') args = parser.parse_args() container = av.open(args.path) stream = next(s for s in container.streams if s.type == 'audio') fifo = av.AudioFifo() resampler = av.AudioResampler( format=av.AudioFormat('s16').packed, layout='stereo', rate=48000, ) qformat = Q.AudioFormat() qformat.setByteOrder(Q.AudioFormat.LittleEndian) qformat.setChannelCount(2) qformat.setCodec('audio/pcm') qformat.setSampleRate(48000) qformat.setSampleSize(16) qformat.setSampleType(Q.AudioFormat.SignedInt) output = Q.AudioOutput(qformat) output.setBufferSize(2 * 2 * 48000) device = output.start() print(qformat, output, device) def decode_iter():
def rowCount(self, parent=Q.QModelIndex()): return len(self._props)
def __init__(self, *args, **kwargs): fp = kwargs.pop('fp', None) use_tabs = kwargs.pop('tabs', True) super().__init__(*args, **kwargs) self.setSizePolicy( Q.QSizePolicy(Q.QSizePolicy.MinimumExpanding, Q.QSizePolicy.MinimumExpanding, Q.QSizePolicy.Frame)) childwidget = self.childwidget = AVPlayer(fp=fp, parent=self) childwidget.setSizePolicy( Q.QSizePolicy(Q.QSizePolicy.MinimumExpanding, Q.QSizePolicy.MinimumExpanding, Q.QSizePolicy.Label)) self.splitter = Q.QSplitter() self.splitter.setOrientation(Q.Qt.Vertical) self.layout = Q.QVBoxLayout() self.splitter.addWidget(self.childwidget) self.layout.addWidget(self.splitter) self.setLayout(self.layout) controls_widget = Q.QWidget() controls_layout = Q.QVBoxLayout() controls_widget.setLayout(controls_layout) self.splitter.addWidget(controls_widget) time_layout = Q.QVBoxLayout() timespin_layout = Q.QHBoxLayout() self.timespin = Q.QDoubleSpinBox() self.timespin.setFixedWidth(120) self.timespin.setDecimals(5) self.timespin.setSingleStep(1e-2) timespin_layout.addWidget(self.timespin) step_back = Q.QPushButton("step -") step_back.clicked.connect( lambda: self.childwidget.try_command('frame-back-step')) timespin_layout.addWidget(step_back) step_forward = Q.QPushButton("step +") step_forward.clicked.connect( lambda: self.childwidget.try_command('frame-step')) timespin_layout.addWidget(step_forward) timespin_layout.addStretch(-1) time_layout.addLayout(timespin_layout) self.timeline = Q.QSlider(Q.Qt.Horizontal) self.timeline.setSizePolicy(Q.QSizePolicy.Expanding, Q.QSizePolicy.Preferred) self.timeline.setEnabled(True) self.timeline.sliderReleased.connect( lambda: self.onTimelineChanged(self.timeline.value())) time_layout.addWidget(self.timeline) controls_layout.addLayout(time_layout) childwidget.time_pos.valueChanged.connect(self.onTime_posChanged) self.timeline.valueChanged.connect(self.onTimelineChanged) self.timespin.valueChanged.connect(self.onTimespinChanged) childwidget.duration.valueChanged.connect(self.onDurationChanged) self.speed = Q.QSlider(Q.Qt.Horizontal) self.speed.setSizePolicy(Q.QSizePolicy.Expanding, Q.QSizePolicy.Preferred) self.speed_base = 1e8 self.speed_max = 5.0 self.speed_pow = 5.0**(self.speed_base**-1) self.speed.setValue(self.speed_base) self.speed.setRange(16, 2 * self.speed_base) self.speed.setEnabled(True) self.speed.valueChanged.connect(self.speedChanged) childwidget.speed.valueChanged.connect(self.onSpeedChanged) play_button = Q.QPushButton("play/pause") play_button.clicked.connect(self.pause) self.play_button = play_button rate_down_button = Q.QPushButton("rate -") rate_down_button.clicked.connect(lambda: self.rate_adj(1. / 1.1)) rate_down_tmp_button = Q.QPushButton(" tmp -") rate_down_tmp_button.pressed.connect(lambda: self.temp_rate(1. / 1.1)) rate_down_tmp_button.released.connect(self.temp_rate_release) rate_up_button = Q.QPushButton("rate +") rate_up_button.clicked.connect(lambda: self.rate_adj(1.1)) rate_up_tmp_button = Q.QPushButton(" tmp +") rate_up_tmp_button.pressed.connect(lambda: self.temp_rate(1.1)) rate_up_tmp_button.released.connect(self.temp_rate_release) rate_down_layout = Q.QVBoxLayout() rate_down_layout.addWidget(rate_down_button) rate_down_layout.addWidget(rate_down_tmp_button) play_speed_layout = Q.QVBoxLayout() play_speed_layout.addWidget(play_button) play_speed_layout.addWidget(self.speed) rate_up_layout = Q.QVBoxLayout() rate_up_layout.addWidget(rate_up_button) rate_up_layout.addWidget(rate_up_tmp_button) control_layout = Q.QHBoxLayout() control_layout.addLayout(rate_down_layout) control_layout.addLayout(play_speed_layout) control_layout.addLayout(rate_up_layout) childwidget.video_params.valueChanged.connect( self.onVideo_paramsChanged) childwidget.reconfig.connect(self.reconfig) childwidget.novid.connect(self.novid) childwidget.hasvid.connect(self.hasvid) self.sized_once = False self.reconfig(640, 480) self.sized_once = False controls_layout.addLayout(control_layout) toolbarlayout = Q.QVBoxLayout() cmdlinelayout = Q.QHBoxLayout() histloglayout = Q.QHBoxLayout() self.histline = Q.QPlainTextEdit() self.histline.setReadOnly(True) self.histline.setCenterOnScroll(False) self.histline.setSizePolicy(Q.QSizePolicy.Expanding, Q.QSizePolicy.Preferred) self.logline = Q.QPlainTextEdit() self.logline.setReadOnly(True) self.logline.setSizePolicy(Q.QSizePolicy.Expanding, Q.QSizePolicy.Preferred) self.cmdline = cmdline = CmdLine() er_label = self.er_label = Q.QLabel() pr_label = self.pr_label = Q.QLabel() fr_label = self.fr_label = Q.QLabel() sr_label = self.sr_label = Q.QLabel() self._timer = Q.QTimer(self) self._timer.setInterval(int(1000 / 5)) self._timer.setTimerType(Q.Qt.CoarseTimer) def updateLabels(): self.pr_label.setText('paint rate: {:.6f}'.format( self.childwidget.paintRate)) self.er_label.setText('event rate: {:.6f}'.format( self.childwidget.eventRate)) self.fr_label.setText('frame rate: {:.6f}'.format( self.childwidget.frameRate)) self.sr_label.setText('swap rate: {:.6f}'.format( self.childwidget.swapRate)) self._timer.timeout.connect(updateLabels, Q.Qt.QueuedConnection) self._timer.start() # self.cmdline = cmdline = CmdLine(self.toolbargroup) self.cmdline.setSizePolicy(Q.QSizePolicy.Expanding, Q.QSizePolicy.Preferred) cmdlinelayout.addWidget(self.cmdline) cmdlinelayout.addWidget(er_label) cmdlinelayout.addWidget(pr_label) cmdlinelayout.addWidget(fr_label) cmdlinelayout.addWidget(sr_label) toolbarlayout.addLayout(cmdlinelayout) histloglayout.addWidget(self.histline) histloglayout.addWidget(self.logline) if use_tabs: tw = Q.QTabWidget(parent=self) tg = Q.QWidget() tg.setLayout(histloglayout) tw.addTab(tg, "history/log") childwidget._property_model = AVTreePropertyModel( player=childwidget, parent=childwidget) tv = Q.QTreeView() tv.setModel(childwidget._property_model) tw.addTab(tv, "properties") tw.setVisible(True) toolbarlayout.addWidget(tw) else: toolbarlayout.addLayout(histloglayout) controls_layout.addLayout(toolbarlayout) cmdline.submitted.connect(self.onCmdlineAccept, Q.Qt.UniqueConnection | Q.Qt.AutoConnection) cmdline.historyChanged.connect(self.redoHistory) self.childwidget.logMessage.connect(self.onLogMessage)
class CmdLine(Q.QLineEdit): submitted = Q.pyqtSignal(str, bool) historyPosChanged = Q.pyqtSignal(int) historyChanged = Q.pyqtSignal() historyAppended = Q.pyqtSignal(str) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._history = collections.deque() self._history_pos = 0 self.historyAppended.connect(self.historyChanged, Q.Qt.UniqueConnection) self.returnPressed.connect(self.onReturnPressed, Q.Qt.UniqueConnection) def keyPressEvent(self, evt): if evt.modifiers() == Q.Qt.ControlModifier: if evt.key() == Q.Qt.Key_P or evt.key() == Q.Qt.Key_Up: if self.historyPos + 1 < len(self._history): self.historyPos += 1 self.setText(self._history[self.historyPos]) return elif evt.key() == Q.Qt.Key_N or evt.key() == Q.Qt.Key_Down: if self.historyPos > 0 and self._history: self.historyPos -= 1 self.setText(self._history[self.historyPos - 1]) else: self.historyPos = -1 return elif evt.key() in (Q.Qt.Key_C, Q.Qt.Key_U): self.historyPos = -1 self.clear() return super().keyPressEvent(evt) @property def history(self): return self._history @property def historyPos(self): return self._history_pos @historyPos.setter def historyPos(self, pos): new_pos = max(min(len(self._history) - 1, int(pos)), -1) if new_pos != self._history_pos: self._history_pos = new_pos if new_pos >= 0: self.setText(self.history[new_pos]) else: self.clear() self.historyPosChanged.emit(new_pos) def historyAppend(self, text): if (text): self._history.appendleft(text) self.historyAppended.emit(text) def onReturnPressed(self): text = self.text().strip() if self._history and self._history[0] == text: text = '' if text: self.historyAppend(text) self._history_pos = -1 self.clear() self.historyPosChanged.emit(-1) self.submitted.emit(text, False) elif self._history: self._history_pos = -1 self.clear() self.historyPosChanged.emit(-1) self.submitted.emit(self._history[0], False)
def sizeHint(self): return Q.QSize(self.img_width, self.img_height)
class AVProperty(Q.QObject): mpv = __import__('mpv') valueChanged = Q.pyqtSignal(object) _value = None @property def propertyName(self): return self.objectName() @property def context(self): return self.__context__ @Q.pyqtSlot() def value(self): return self._value # return getattr(self.context,self.objectName()) @Q.pyqtSlot(object) def setValue(self, value): if self._value != value: self._value = value setattr(self.context, self.objectName(), value) def _emitValueChanged(self, value): if self._value != value: self._value = value self.valueChanged.emit(value) def __index__(self): return int(self) def __str__(self): return str(self.value()) def __bytes__(self): return bytes(self.value()) def __init__(self, prop, ctx, *args, **kwargs): super().__init__(*args, **kwargs) self.__context__ = ctx prop = ctx.attr_name(prop) self.setObjectName(prop) # ctx.request_event(ctx.mpv.EventType.property_change,True) try: self._value = self.context.get_property(self.objectName()) except: self._value = None reply_userdata = lambda val: self._emitValueChanged(val) ctx_ref = weakref.ref(ctx) def unobserve_cb(val): ctx = ctx_ref() try: ctx.unobserve_property(val) except: pass self.reply_userdata = reply_userdata ctx.observe_property(prop, reply_userdata) self._finalizer = weakref.finalize(self, unobserve_cb, reply_userdata)
def columnCount(self, parent=Q.QModelIndex()): return 2
# fmt.setProfile(fmt.CoreProfile) # fmt.setDepthBufferSize(24) # fmt.setRedBufferSize(8) # fmt.setGreenBufferSize(8) # fmt.setBlueBufferSize(8) # fmt.setAlphaBufferSize(8) # fmt.setSwapBehavior(fmt.TripleBuffer) # fmt.setSwapBehavior(fmt.SingleBuffer) # fmt.setRenderableType(fmt.OpenGL) # fmt.setOption(fmt.DeprecatedFunctions,False) # fmt.setOption(fmt.ResetNotification,True) # Q.QSurfaceFormat.setDefaultFormat(fmt) # Q.QCoreApplication.setAttribute(Q.Qt.AA_ShareOpenGLContexts) app = Q.QApplication([]) mw = Canvas() if args.forcerate is not None and args.forcerate: mw.forcedFrameRate = args.forcerate # else: # mw.forcedFrameRate = None ap = mw.playerwidget if args.getprocaddress: ap._get_proc_address = args.getprocaddress if args.getprocaddressquiet: ap._get_proc_address_debug = False def dump_fmt(fmt):
parser.add_argument('-f', '--format') parser.add_argument('path') args = parser.parse_args() def _iter_images(): video = av.open(args.path, format=args.format) stream = next(s for s in video.streams if s.type == b'video') for packet in video.demux(stream): for frame in packet.decode(): yield frame.reformat(frame.width, frame.height, 'rgb24') image_iter = _iter_images() app = Q.Application([]) glwidget = PlayerGLWidget() glwidget.setFixedWidth(WIDTH) glwidget.setFixedHeight(HEIGHT) glwidget.show() glwidget.raise_() start_time = 0 count = 0 timer = Q.Timer() timer.setInterval(1000 / 30) @timer.timeout.connect
import posix,posixpath if sys.version_info.major > 2: basestring = str from modproxy import ModuleProxy from glproxy import gl, glx from qtproxy import Q, QW, QG #from PyQt5 import Qt as Q, QtWidgets as QW, QtGui as QG from topwindow import TopWindow from player import Player if __name__ == '__main__': # Q.QSurfaceFormat.setDefaultFormat(fmt) app = Q.QApplication(sys.argv) # player = Player() args = list() kwargs = dict() for arg in sys.argv[1:]: if '=' in arg: parts = arg.partition('=') kwargs[parts[0]] = parts[2] else: args.append(arg) with SignalWakeupHandler(app): signal.signal(signal.SIGINT, lambda *a:app.quit()) win = TopWindow(*args, **kwargs)
class AVPlayer(Q.QOpenGLWidget): pfl = Q.QOpenGLVersionProfile() pfl.setVersion(4, 1) pfl.setProfile(Q.QSurfaceFormat.CoreProfile) base_options = { 'input-default-bindings': True, 'input_vo_keyboard': True, 'gapless_audio': True, 'osc': False, 'load_scripts': True, 'ytdl': True, 'vo': 'opengl-cb', 'opengl-fbo-format': 'rgba32f', 'alpha': True # ,'opengl-es':True , 'opengl-swapinterval': 1, 'opengl-waitvsync': False, 'opengl-vsync-fences': 6, 'tscale-radius': 4.0, 'tscale-wparam': 1.0, 'tscale': 'gaussian', 'interpolation': True, 'opengl-backend': 'drm', 'video-sync': 'display-resample', 'display-fps': 60.0, 'interpolation-threshold': 0.0, 'interpolation': True # ,'vo-vaapi-scaling':'nla' # ,'vo-vaapi-scaled-osd':True # ,'vo-vdpau-hqscaling':5 # ,'vo-vdpau-deint':True # ,'vd-lavc-fast':True # ,'vd-lavc-show-all':True , 'hr-seek': 'yes' # ,'hr-seek-framedrop':True , 'hwdec-preload': True, 'hwdec': 'yes', 'opengl-hwdec-interop': 'drmprime-drm' } _reportFlip = False _reportedFlip = False _externalDrive = False _get_proc_address = 'ctypes' _get_proc_address_debug = True novid = Q.pyqtSignal() hasvid = Q.pyqtSignal() reconfig = Q.pyqtSignal(int, int) fullscreen = Q.pyqtSignal(bool) wakeup = Q.pyqtSignal() mpv_event = Q.pyqtSignal() logMessage = Q.pyqtSignal(object) just_die = Q.pyqtSignal() paintRateChanged = Q.pyqtSignal(object) eventRateChanged = Q.pyqtSignal(object) frameRateChanged = Q.pyqtSignal(object) swapRateChanged = Q.pyqtSignal(object) openglInitialized = Q.pyqtSignal(object) mpv = __import__('mpv') def get_property(self, prop): try: prop_name = self.m.attr_name(prop) except: return if not prop_name: return binding = self.findChild(AVProperty, prop_name) if binding: return binding prop_object = AVProperty(prop_name, ctx=self.m, parent=self) setattr(self, prop, prop_object) if not hasattr(self, prop_name): setattr(self, prop_name, prop_object) return prop_object def __getattr__(self, prop): try: prop_name = self.m.attr_name(prop) except: # return super().__getattr__(prop) raise AttributeError if not prop_name: raise AttributeError binding = self.findChild(AVProperty, prop_name) if binding: return binding prop_object = AVProperty(prop_name, ctx=self.m, parent=self) setattr(self, prop, prop_object) if not hasattr(self, prop_name): setattr(self, prop_name, prop_object) return prop_object def sizeHint(self): return Q.QSize(self.img_width, self.img_height) # return self.get_property(prop) @staticmethod def get_options(*args, **kwargs): options = kwargs media = list() for arg in args: if arg.startswith('--'): arg, _, value = arg[2:].partition('=') options[arg] = value or True continue media.append(arg) return options, media def __init__(self, *args, fp=None, **kwargs): super().__init__(*args, **kwargs) self.paintTimes = deque(maxlen=32) self.frameTimes = deque(maxlen=32) self.swapTimes = deque(maxlen=32) self.eventTimes = deque(maxlen=32) self.setMouseTracking(True) self._updated = False self.event_handler_cache = weakref.WeakValueDictionary() self.prop_bindings = dict() import locale locale.setlocale(locale.LC_NUMERIC, 'C') options = self.base_options.copy() new_options, media = self.get_options(*args, **kwargs) options.update(new_options) options[ 'msg-level'] = 'all=status,vd=debug,hwdec=debug,vo=debug,video=v,opengl=debug' options['af'] = 'rubberband=channels=apart:pitch=quality' self.new_frame = False mpv = self.mpv self.m = mpv.Context(**options) m = self.m self.just_die.connect(m.shutdown, Q.Qt.DirectConnection) self.destroyed.connect(self.just_die, Q.Qt.DirectConnection) self.m.set_log_level('terminal-default') self.m.set_wakeup_callback_thread(self.onEvent) # self.m.set_wakeup_callback(self.onEvent) self.m.request_event(self.mpv.EventType.property_change, True) self.m.request_event(self.mpv.EventType.video_reconfig, True) self.m.request_event(self.mpv.EventType.file_loaded, True) self.m.request_event(self.mpv.EventType.log_message, True) self.img_width = 64 self.img_height = 64 self.img_update = None self.tex_id = 0 self.fbo = None self._width = self.img_width self._height = self.img_height if isinstance(fp, pathlib.Path): fp = fp.resolve().absolute().as_posix() elif isinstance(fp, Q.QFileInfo): fp = fp.canonicalFilePath() elif isinstance(fp, Q.QUrl): fp = fp.toString() Q.QTimer.singleShot(0, self.update) if fp: Q.QTimer.singleShot(0, ( lambda: self.m.command('loadfile', fp, 'append', _async=True))) def command(self, *args, **kwargs): self.m.command(*args, **kwargs) def command_string(self, cmdlist): try: self.m.command_string(cmdlist) except: pass def try_command(self, *args, **kwargs): kwargs.setdefault('_async', True) try: self.m.command(*args) except self.mpv.MPVError: pass @staticmethod def get_options(*args, **kwargs): options = kwargs media = list() for arg in args: if arg.startswith('--'): arg, _, value = arg[2:].partition('=') options[arg] = value or True continue media.append(arg) return options, media @Q.pyqtProperty(float) def paintRate(self): if len(self.paintTimes) < 2: return 0 else: return 1e6 * (len(self.paintTimes) - 1) / (self.paintTimes[-1] - self.paintTimes[0]) def paintTimeAppend(self, time): self.paintTimes.append(time) self.paintRateChanged.emit(self.paintRate) @Q.pyqtProperty(float) def frameRate(self): if len(self.frameTimes) < 2: return 0 else: return 1e6 * (len(self.frameTimes) - 1) / (self.frameTimes[-1] - self.frameTimes[0]) def frameTimeAppend(self, time): self.frameTimes.append(time) self.frameRateChanged.emit(self.frameRate) @Q.pyqtProperty(float) def swapRate(self): if len(self.swapTimes) < 2: return 0 else: return 1e6 * (len(self.swapTimes) - 1) / (self.swapTimes[-1] - self.swapTimes[0]) def swapTimeAppend(self, time): self.swapTimes.append(time) self.swapRateChanged.emit(self.swapRate) @Q.pyqtProperty(float) def eventRate(self): if len(self.eventTimes) < 2: return 0 else: return 1e6 * (len(self.eventTimes) - 1) / (self.eventTimes[-1][0] - self.eventTimes[0][0]) def eventTimeAppend(self, time, type=None): self.eventTimes.append((time, type)) self.eventRateChanged.emit(self.eventRate) @Q.pyqtSlot(object) def onEventData(self, event): m = self.m if not m: return self.eventTimeAppend(self.m.time, event.id) if event.id is self.mpv.EventType.shutdown: print("on_event -> shutdown") self.just_die.emit() elif event.id is self.mpv.EventType.idle: self.novid.emit() elif event.id is self.mpv.EventType.start_file: self.hasvid.emit() elif event.id is self.mpv.EventType.file_loaded: ao = m.ao if ao and ao[0]['name'] in ('null', 'none'): m.aid = 0 else: try: if m.current_ao in ('null', 'none'): m.aid = 0 except self.mpv.MPVError as e: if e.code == self.mpv.Error.property_unavailable: m.aid = 0 if not m.aid: if m.af: self.af = m.af m.af = "" else: if self.af and not m.af: m.af = self.af # self.durationChanged.emit(m.duration) elif event.id is self.mpv.EventType.log_message: self.logMessage.emit(event.data) # print(event.data.text,) elif (event.id is self.mpv.EventType.end_file or event.id is self.mpv.EventType.video_reconfig): try: self.m.vid = 1 self.reconfig.emit(self.m.dwidth, -self.m.dheight) except self.mpv.MPVError as ex: self.reconfig.emit(None, None) elif event.id is self.mpv.EventType.property_change: oname = event.data.name data = event.data.data if event.reply_userdata: try: event.reply_userdata(data) except: pass elif event.data.name == 'fullscreen': pass @Q.pyqtSlot() def onEvent(self): m = self.m if not m: return while True: event = m.wait_event(0) if event is None: print("Warning, received a null event.") return elif event.id is self.mpv.EventType.none: return else: try: self.onEventData(event) except Exception as e: print(e) @Q.pyqtSlot() def onWakeup(self): # if not self._externalDrive: self.frameTimeAppend(self.m.time) self.update() def initializeGL(self): print('initialize GL') if self._get_proc_address is 'ctypes': import ctypes, ctypes.util lgl = ctypes.cdll.LoadLibrary(ctypes.util.find_library('GL')) get_proc_address = lgl.glXGetProcAddress get_proc_address.restype = ctypes.c_void_p get_proc_address.argtypes = [ctypes.c_char_p] _get_proc_address = lambda name: get_proc_address( name if isinstance(name, bytes) else name.encode('latin1')) else: qgl_get_proc_address = Q.QGLContext.currentContext().getProcAddress _get_proc_address = lambda name: int( qgl_get_proc_address( name.decode('latin1') if isinstance(name, bytes) else name)) if self._get_proc_address_debug: def getprocaddr(name): res = _get_proc_address(name) print('{} -> address {}'.format(name, res)) return res else: getprocaddr = _get_proc_address self.ogl = self.m.opengl_cb_context self.ogl.init_gl(getprocaddr, None) weakref.finalize(self, lambda: self.ogl.set_update_callback(None)) self.wakeup.connect(self.onWakeup, Q.Qt.QueuedConnection | Q.Qt.UniqueConnection) self.frameSwapped.connect(self.onFrameSwapped) self.ogl.set_update_callback(self.wakeup.emit) self.openglInitialized.emit(Q.QOpenGLContext.currentContext()) @Q.pyqtSlot() def onFrameSwapped(self): self.swapTimeAppend(self.m.time) if self._updated: self._updated = False if self.reportFlip: self.ogl.report_flip(self.m.time) self._reportedFlip = True @property def reportFlip(self): return self._reportFlip @reportFlip.setter def reportFlip(self, val): if self._reportedFlip: return self._reportFlip = bool(val) @property def externalDrive(self): return self._externalDrive @externalDrive.setter def externalDrive(self, val): self._externalDrive = bool(val) def resizeGL(self, w, h): self._width = w self._height = h def paintGL(self): self.paintTimeAppend(self.m.time) self.ogl.draw(self.defaultFramebufferObject(), self._width, -self._height) self._updated = True