def __init__( self, video=None, # video file name adjustr='', # vlc.VideoAdjustOption logostr='', # vlc.VideoLogoOption marquee=False, # vlc.VideoMarqueeOption raiser=False, # re-raise errors snapshot='png', # png, jpg or tiff format title='AppVLC'): # window title super(AppVLC, self).__init__(raiser=raiser, title=title) self.adjustr = adjustr self.logostr = logostr self.marquee = marquee self.media = None self.raiser = raiser self.snapshot = '.' + snapshot.lstrip('.').lower() self.Toggle = Item('Play', self.menuToggle_, key='p', ctrl=True) self.video = video if self.snapshot == '.png': self.player = vlc.MediaPlayer() # # XXX does not work, snapshots are always png # elif self.snapshot in ('.jpg', '.tiff'): # i = vlc.Instance('--snapshot-format', self.snapshot[1:]) # --verbose 2 # self.player = i.media_player_new() else: raise ValueError('invalid %s format: %r' % ('snapshot', snapshot))
def __init__(self, video=None, # video file name adjustr='', # vlc.VideoAdjustOption logostr='', # vlc.VideoLogoOption marquee=False, # vlc.VideoMarqueeOption raiser=False, # re-raise errors title='AppVLC'): # window title super(AppVLC, self).__init__(raiser=raiser, title=title) self.adjustr = adjustr self.logostr = logostr self.marquee = marquee self.media = None self.player = vlc.MediaPlayer() self.raiser = raiser self.Toggle = Item('Play', self.menuToggle_, key='p', ctrl=True) self.video = video
def appLaunched_(self, app): super(AppVLC, self).appLaunched_(app) self.window = MediaWindow(title=self.video or self.title) if self.player and self.video and isfile(self.video): # the VLC player on macOS needs an ObjC NSView self.media = self.player.set_mrl(self.video) self.player.set_nsobject(self.window.NSview) # if this window is on an external screen, # move it to the built-in screen, aka 0 # if not self.window.screen.isBuiltIn: # self.window.screen = 0 # == BuiltIn if self.adjustr: # preset video options for o in self.adjustr.lower().split(','): o, v = o.strip().split('=') o = getattr(_Adjust, o.capitalize(), None) if o is not None: self._VLCadjust(o, value=v) if self.marquee: # set up marquee self._VLCmarquee() if self.logostr: # show logo self._VLClogo(self.logostr) menu = Menu('VLC') menu.append( # the action/method name for each item # is string 'menu' + item.title + '_', # without any spaces and trailing dots, # see function pycocoa.title2action. Item('Open...', key='o'), ItemSeparator(), Item('Info', key='i'), Item('Close Windows', key='w'), ItemSeparator(), self.Toggle, # Play >< Pause Item('Rewind', key='r', ctrl=True), ItemSeparator(), Item('Zoom In', key='+'), Item('Zoom Out', key='-'), ItemSeparator(), Item('Faster', key='>', shift=True), Item('Slower', key='<', shift=True)) if _VLC_3_: menu.append(Item('Brighter', key='b', shift=True), Item('Darker', key='d', shift=True)) menu.append( ItemSeparator(), Item('Audio Filters', self.menuFilters_, key='a', shift=True), Item('Video Filters', self.menuFilters_, key='v', shift=True)) menu.append(ItemSeparator(), self.Snapshot) self.append(menu) self.menuPlay_(None) self.window.front()
class AppVLC(App): '''The application with callback methods for C{app..._}, C{menu..._} and C{window..._} events. Set things up inside the C{.__init__} and C{.appLauched_} methods, start by calling the C{.run} method. ''' adjustr = '' marquee = None logostr = '' player = None raiser = False scale = 1 # media zoom factor sized = None # video width, height Snapshot = Item('Snapshot', key='s', alt=True) snapshot = '.png' # default, or .jpg or .tiff snapshots = 0 Toggle = None video = None window = None def __init__( self, video=None, # video file name adjustr='', # vlc.VideoAdjustOption logostr='', # vlc.VideoLogoOption marquee=False, # vlc.VideoMarqueeOption raiser=False, # re-raise errors snapshot='png', # png, jpg or tiff format title='AppVLC'): # window title super(AppVLC, self).__init__(raiser=raiser, title=title) self.adjustr = adjustr self.logostr = logostr self.marquee = marquee self.media = None self.raiser = raiser self.snapshot = '.' + snapshot.lstrip('.').lower() self.Toggle = Item('Play', self.menuToggle_, key='p', ctrl=True) self.video = video if self.snapshot == '.png': self.player = vlc.MediaPlayer() # # XXX does not work, snapshots are always png # elif self.snapshot in ('.jpg', '.tiff'): # i = vlc.Instance('--snapshot-format', self.snapshot[1:]) # --verbose 2 # self.player = i.media_player_new() else: raise ValueError('invalid %s format: %r' % ('snapshot', snapshot)) def appLaunched_(self, app): super(AppVLC, self).appLaunched_(app) self.window = MediaWindow(title=self.video or self.title) if self.player and self.video and isfile(self.video): # the VLC player on macOS needs an ObjC NSView self.media = self.player.set_mrl(self.video) self.player.set_nsobject(self.window.NSview) # if this window is on an external screen, # move it to the built-in screen, aka 0 # if not self.window.screen.isBuiltIn: # self.window.screen = 0 # == BuiltIn if self.adjustr: # preset video options for o in self.adjustr.lower().split(','): o, v = o.strip().split('=') o = getattr(_Adjust, o.capitalize(), None) if o is not None: self._VLCadjust(o, value=v) if self.marquee: # set up marquee self._VLCmarquee() if self.logostr: # show logo self._VLClogo(self.logostr) menu = Menu('VLC') menu.append( # the action/method name for each item # is string 'menu' + item.title + '_', # without any spaces and trailing dots, # see function pycocoa.title2action. Item('Open...', key='o'), ItemSeparator(), Item('Info', key='i'), Item('Close Windows', key='w'), ItemSeparator(), self.Toggle, # Play >< Pause Item('Rewind', key='r', ctrl=True), ItemSeparator(), Item('Zoom In', key='+'), Item('Zoom Out', key='-'), ItemSeparator(), Item('Faster', key='>', shift=True), Item('Slower', key='<', shift=True)) if _VLC_3_: menu.append(Item('Brighter', key='b', shift=True), Item('Darker', key='d', shift=True)) menu.append( ItemSeparator(), Item('Audio Filters', self.menuFilters_, key='a', shift=True), Item('Video Filters', self.menuFilters_, key='v', shift=True)) menu.append(ItemSeparator(), self.Snapshot) self.append(menu) self.menuPlay_(None) self.window.front() def menuBrighter_(self, item): self._brightness(item, +0.1) def menuCloseWindows_(self, item): # PYCHOK expected # close window(s) from menu Cmd+W # printf('%s %r', 'close_', item) if not closeTables(): self.terminate() def menuDarker_(self, item): self._brightness(item, -0.1) def menuFaster_(self, item): self._rate(item, 1.25) def menuFilters_(self, item): try: self.menuPause_(item) # display a table of audio/video filters t = Table(' Name:150:bold', ' Short:150:Center:center', ' Long:300', 'Help') i = self.player.get_instance() b = item.title.split()[0] for f in sorted(i.audio_filter_list_get() if b == 'Audio' else i.video_filter_list_get()): while f and not f[-1]: # "rstrip" None f = f[:-1] t.append(*map(bytes2str, f)) t.display('VLC %s Filters' % (b, ), width=800) except Exception as x: if self.raiser: raise printf('%s', x, nl=1, nt=1) def menuInfo_(self, item): try: self.menuPause_(item) # display Python, vlc, libVLC, media info table p = self.player m = p.get_media() t = Table(' Name:bold', ' Value:200:Center:center', ' Alt:100') t.append(_Argv0, __version__, '20' + __version__) t.append('PyCocoa', _pycocoa_version, '20' + _pycocoa_version) t.append('Python', *_Python) t.append(*_macOS()) x = 'built-in' if self.window.screen.isBuiltIn else 'external' t.append('screen', x, str(self.window.screen.displayID)) t.separator() t.append('vlc.py', vlc.__version__, hex(vlc.hex_version())) b = ' '.join(vlc.build_date.split()[:5]) t.append('built', strftime('%x', strptime(b, '%c')), vlc.build_date) t.separator() t.append('libVLC', bytes2str(vlc.libvlc_get_version()), hex(vlc.libvlc_hex_version())) t.append('libVLC', *bytes2str(vlc.libvlc_get_compiler()).split(None, 1)) t.separator() f = mrl_unquote(bytes2str(m.get_mrl())) t.append('media', basename(f), f) if f.lower().startswith('file://'): z = getsize(f[7:]) t.append('size', z1000str(z), zSIstr(z)) t.append('state', str(p.get_state())) f = max(p.get_position(), 0) t.append('position/length', '%.2f%%' % (f * 100, ), _ms2str(p.get_length())) f = map(_ms2str, (p.get_time(), m.get_duration())) t.append('time/duration', *f) t.append('track/count', z1000str(p.video_get_track()), z1000str(p.video_get_track_count())) t.separator() f = p.get_fps() t.append('fps/mspf', '%.6f' % (f, ), '%.3f ms' % (_mspf(f), )) r = p.get_rate() t.append('rate', '%s%%' % (int(r * 100), ), r) w, h = p.video_get_size(0) t.append('video size', _ratio2str('x', w, h)) # num=0 r = _ratio2str(':', *aspect_ratio(w, h)) # p.video_get_aspect_ratio() t.append('aspect ratio', r, _ratio2str(':', *self.window.ratio)) t.append('scale', '%.3f' % (p.video_get_scale(), ), '%.3f' % (self.scale, )) t.separator() def VLCadjustr2(option): # get option value lo, _, hi = _Adjust3[option] f = self.player.video_get_adjust_float(option) p = max(0, (f - lo)) * 100.0 / (hi - lo) t = '%.2f %.1f%%' % (f, p) # return 2-tuple (value, percentage) as strings return t.replace('.0%', '%').replace('.00', '.0').split() t.append('brightness', *VLCadjustr2(_Adjust.Brightness)) t.append('contrast', *VLCadjustr2(_Adjust.Contrast)) t.append('gamma', *VLCadjustr2(_Adjust.Gamma)) t.append('hue', *VLCadjustr2(_Adjust.Hue)) t.append('saturation', *VLCadjustr2(_Adjust.Saturation)) t.separator() s = vlc.MediaStats() # re-use single MediaStats instance? if m.get_stats(s): def Kops2bpstr2(bitrate): # convert Ko/s to bits/sec # bitrates are conventionally in kilo-octets-per-sec return zSIstr(bitrate * 8000, B='bps', K=1000).split() t.append('media read', *zSIstr(s.read_bytes).split()) t.append('input bitrate', *Kops2bpstr2(s.input_bitrate)) if s.input_bitrate > 0: # XXX approximate caching, based # on <https://GitHub.com/oaubert/python-vlc/issues/61> b = s.read_bytes - s.demux_read_bytes t.append('input caching', _ms2str(b / s.input_bitrate), zSIstr(b)) t.append('demux read', *zSIstr(s.demux_read_bytes).split()) t.append('stream bitrate', *Kops2bpstr2(s.demux_bitrate)) t.append('video decoded', z1000str(s.decoded_video), 'blocks') t.append('video played', z1000str(s.displayed_pictures), 'frames') t.append('video lost', z1000str(s.lost_pictures), 'frames') t.append('audio decoded', z1000str(s.decoded_audio), 'blocks') t.append('audio played', z1000str(s.played_abuffers), 'buffers') t.append('audio lost', z1000str(s.lost_abuffers), 'buffers') t.display('Python, VLC & Media Information', width=500) except Exception as x: if self.raiser: raise printf('%s', x, nl=1, nt=1) def menuOpen_(self, item): # stop the current video and show # the panel to select another video self.menuPause_(item) self.badge.label = 'O' v = OpenPanel(_Select).pick(_Movies) if v: self.window.title = self.video = v self.player.set_mrl(v) self.sized = None def menuPause_(self, item, pause=False): # PYCHOK expected # note, .player.pause() pauses and un-pauses the video, # .player.stop() stops the video and blanks the window if pause or self.player.is_playing(): self.player.pause() self.badge.label = 'S' # stopped self.Toggle.title = 'Play' # item.title = 'Play' def menuPlay_(self, item_or_None): # PYCHOK expected self.player.play() self._resizer() self.badge.label = 'P' # Playing self.Toggle.title = 'Pause' # item.title = 'Pause' def menuRewind_(self, item): # PYCHOK expected self.player.set_position(0.0) # note, can't re-play once at the end # self.menuPlay_() self.badge.label = 'R' self.sized = None def menuSlower_(self, item): self._rate(item, 0.80) def menuSnapshot_(self, item): # PYCHOK expected w = self.lastWindow if w: self.snapshots += 1 s = '-'.join((_Argv0, 'snapshot%d' % (self.snapshots, ), w.__class__.__name__)) if isinstance(w, MediaWindow): self.player.video_take_snapshot(0, s + self.snapshot, 0, 0) elif get_printer: # in PyCocoa 18.08.04+ get_printer().printView(w.PMview, toPDF=s + '.pdf') def menuToggle_(self, item): # toggle between Pause and Play if self.player.is_playing(): self.menuPause_(item, pause=True) else: self.menuPlay_(item) def menuZoomIn_(self, item): self._zoom(item, 1.25) def menuZoomOut_(self, item): self._zoom(item, 0.80) def windowClose_(self, window): # quit or click of window close button if window is self.window: self.terminate() self.Snapshot.isEnabled = False super(AppVLC, self).windowClose_(window) def windowLast_(self, window): self.Snapshot.isEnabled = window.isPrintable or isinstance( window, MediaWindow) super(AppVLC, self).windowLast_(window) def windowResize_(self, window): if window is self.window: self._resizer() super(AppVLC, self).windowResize_(window) def windowScreen_(self, window, change): if window is self.window: self._resizer() super(AppVLC, self).windowScreen_(window, change) def _brightness(self, unused, fraction): # change brightness self._VLCadjust(_Adjust.Brightness, fraction) def _contrast(self, unused, fraction): # change contrast self._VLCadjust(_Adjust.Contrast, fraction) def _gamma(self, unused, fraction): # change gamma self._VLCadjust(_Adjust.Gamma, fraction) def _hue(self, unused, fraction): # change hue self._VLCadjust(_Adjust.Hue, fraction) def _saturation(self, unused, fraction): # change saturation self._VLCadjust(_Adjust.Saturation, fraction) def _rate(self, unused, factor): # change the video rate r = max(0.2, min(10.0, self.player.get_rate() * factor)) self.player.set_rate(r) def _resizer(self): # adjust aspect ratio and marquee height if self.sized: # window's contents' aspect ratio self.window.ratio = self.sized else: Thread(target=self._sizer).start() def _sizer(self, secs=0.1): while True: w, h = self.player.video_get_size(0) # the first call(s) returns (0, 0), # subsequent calls return (w, h) if h > 0 and w > 0: # window's contents' aspect ratio self.window.ratio = self.sized = w, h break elif secs > 0.001: sleep(secs) else: # one-shot break def _VLCadjust(self, option, fraction=0, value=None): # adjust a video option like brightness, contrast, etc. p = self.player # <https://Wiki.VideoLan.org/Documentation:Modules/adjust> # note, .Enable must be set to 1, but once is sufficient p.video_set_adjust_int(_Adjust.Enable, 1) try: lo, _, hi = _Adjust3[option] if value is None: v = p.video_get_adjust_float(option) else: v = float(value) if fraction: v += fraction * (hi - lo) v = float(max(lo, min(hi, v))) p.video_set_adjust_float(option, v) except (KeyError, ValueError): pass def _VLClogo(self, logostr): # add a video logo, example "python cocoavlc.py -logo # cone-altglass2.png\;cone-icon-small.png ..." p = self.player g = vlc.VideoLogoOption # Enum # <https://Wiki.VideoLan.org/Documentation:Modules/logo> p.video_set_logo_int(g.enable, 1) p.video_set_logo_int(g.position, vlc.Position.Center) p.video_set_logo_int(g.opacity, 128) # 0-255 # p.video_set_logo_int(g.delay, 1000) # millisec # p.video_set_logo_int(g.repeat, -1) # forever p.video_set_logo_string(g.file, logostr) def _VLCmarquee(self, size=36): # put video marquee at the bottom-center p = self.player m = vlc.VideoMarqueeOption # Enum # <https://Wiki.VideoLan.org/Documentation:Modules/marq> p.video_set_marquee_int(m.Enable, 1) p.video_set_marquee_int(m.Size, int(size)) # pixels p.video_set_marquee_int(m.Position, vlc.Position.Bottom) p.video_set_marquee_int(m.Opacity, 255) # 0-255 p.video_set_marquee_int(m.Color, _Color.Yellow) p.video_set_marquee_int(m.Timeout, 0) # millisec, 0==forever p.video_set_marquee_int(m.Refresh, 1000) # millisec (or sec?) p.video_set_marquee_string(m.Text, str2bytes('%Y-%m-%d %T %z')) def _zoom(self, unused, factor): # zoom the video rate in/out if factor > 0: self.scale *= factor self.player.video_set_scale( self.scale) # if abs(self.scale - 1.0) > 0.01 else 0.0)
def appLaunched_(self, app): # PYCHOK app unused menu = Menu('Keys') menu.append( Item('Special Keys'), # ObjC specials ItemSeparator(), Item('BackSpace', self.menuKey_, key=Keys.BS), # Delete <x] key Item('BackTab', self.menuKey_, key=Keys.BT, alt=True), # no icon Item('Cancel', self.menuKey_, key=Keys.CAN), Item('CarriageReturn', self.menuKey_, key=Keys.CR), # Return key Item('Delete', self.menuKey_, key=Keys.DEL), # Delete [x> key Item('Enter', self.menuKey_, key=Keys.ETX), Item('Escape', self.menuKey_, key=Keys.ESC), # Enter on keypad Item('FormFeed', self.menuKey_, key=Keys.FF), # Page Down key Item('NewLine', self.menuKey_, key=Keys.NL), Item('Space', self.menuKey_, key=Keys.SP, alt=True, ctrl=True), Item('Tab', self.menuKey_, key=Keys.HT, alt=True), ItemSeparator(), # other ASCII Ctrl+Alpha characters # no icon Item('Acknowledge', self.menuKey_, key=Keys.ACK), # no icon Item('Bell', self.menuKey_, key=Keys.BEL), # no icon Item('DataLineEscape', self.menuKey_, key=Keys.DLE), # no icon Item('DeviceControl1', self.menuKey_, key=Keys.DC1), # no icon Item('DeviceControl2', self.menuKey_, key=Keys.DC2), # no icon Item('DeviceControl3', self.menuKey_, key=Keys.DC3), # no icon Item('DeviceControl4', self.menuKey_, key=Keys.DC4), # no icon Item('EndOfMedium', self.menuKey_, key=Keys.EM), Item('EndOfText', self.menuKey_, key=Keys.ETX, alt=True), Item('EndOfTransmit', self.menuKey_, key=Keys.EOT), # End key # no icon Item('EndOfTransmitBlock', self.menuKey_, key=Keys.ETB), Item('Enquiry', self.menuKey_, key=Keys.ENQ), Item('FileSeparator', self.menuKey_, key=Keys.FS), Item('GroupSeparator', self.menuKey_, key=Keys.GS), Item('HorizontalTab', self.menuKey_, key=Keys.HT, alt=True), Item('LineFeed', self.menuKey_, key=Keys.LF, alt=True), # no icon Item('NegativeAcknowledge', self.menuKey_, key=Keys.NAK), Item('RecordSeparator', self.menuKey_, key=Keys.RS), # no icon Item('ShiftIn', self.menuKey_, key=Keys.SI), # no icon Item('ShiftOut', self.menuKey_, key=Keys.SO), # no icon Item('StartOfHeading', self.menuKey_, key=Keys.SOH), # no icon Item('StartOfText', self.menuKey_, key=Keys.STX), # no icon Item('SynchronousIdle', self.menuKey_, key=Keys.SYN), # no icon Item('Substitute', self.menuKey_, key=Keys.SUB), Item('UnitSeparator', self.menuKey_, key=Keys.US), Item('VerticalTab', self.menuKey_, key=Keys.VT, alt=True)) self.append(menu) menu.popUp()