import rearrangement
[enigma2-plugins.git] / vlcplayer / src / VlcPlayer.py
1 # -*- coding: ISO-8859-1 -*-
2 #===============================================================================
3 # VLC Player Plugin by A. Lätsch 2007
4 #                   modified by Volker Christian 2008
5 #
6 # This is free software; you can redistribute it and/or modify it under
7 # the terms of the GNU General Public License as published by the Free
8 # Software Foundation; either version 2, or (at your option) any later
9 # version.
10 #===============================================================================
11
12
13 from time import time
14
15 from enigma import iPlayableServicePtr
16 from enigma import iPlayableService
17 from enigma import iServiceInformation
18 from enigma import iSeekableService
19 from enigma import eServiceReference
20 from enigma import eServiceCenter
21 from enigma import eTimer
22 from Screens.Screen import Screen
23 from Screens.MessageBox import MessageBox
24 from Screens.MinuteInput import MinuteInput
25 from Screens.InfoBarGenerics import InfoBarNotifications, InfoBarAudioSelection
26 from Components.Sources.Source import Source
27 from Components.ServiceEventTracker import ServiceEventTracker
28 from Components.ActionMap import ActionMap
29 from Components.config import config
30
31
32 def isValidServiceId(id):
33         testSRef = eServiceReference(id, 0, "Just a TestReference")
34         info = eServiceCenter.getInstance().info(testSRef)
35         return info is not None
36
37 ENIGMA_SERVICEGS_ID = 0x1001
38 ENIGMA_SERVICETS_ID = 0x1002
39
40 ENIGMA_SERVICE_ID = 0
41
42 print "[VLC] Checking for buildin servicets ... ",
43 if isValidServiceId(ENIGMA_SERVICETS_ID):
44         print "yes"
45         ENIGMA_SERVICE_ID = ENIGMA_SERVICETS_ID
46         STOP_BEFORE_UNPAUSE = False
47 else:
48         print "no"
49         print "[VLC] Checking for existing and usable servicets.so ... ",
50         try:
51                 import servicets
52         except Exception, e:
53                 print e
54                 print "[VLC] Checking for usable gstreamer service ... ",
55                 if isValidServiceId(ENIGMA_SERVICEGS_ID):
56                         print "yes"
57                         ENIGMA_SERVICE_ID = ENIGMA_SERVICEGS_ID
58                         STOP_BEFORE_UNPAUSE = True
59                 else:
60                         print "no"
61                         print "[VLC] No valid VLC-Service found - VLC-streaming not supported"
62         else:
63                 print "yes"
64                 ENIGMA_SERVICE_ID = ENIGMA_SERVICETS_ID
65                 STOP_BEFORE_UNPAUSE = False
66
67 DEFAULT_VIDEO_PID = 0x44
68 DEFAULT_AUDIO_PID = 0x45
69
70
71 def isDvdUrl(url):
72         return url.startswith("dvd://") or url.startswith("dvdsimple://")
73
74
75 def splitDvdUrl(url):
76         pos = url.rfind("@", len(url)-8)
77         if pos > 0:
78                 track = url[pos+1:]
79                 url = url[0:pos]
80                 if track.find(":") >= 0:
81                         track, chapter = track.split(":")
82                 else:
83                         chapter = None
84         else:
85                 track, chapter = (None, None)
86         return (url, track, chapter)
87
88
89 class VlcService(Source, iPlayableServicePtr, iSeekableService):
90         refreshInterval = 3000
91
92         class Info(iServiceInformation):
93                 def __init__(self, name=""):
94                         self.name = name
95
96                 def getName(self):
97                         return self.name
98
99                 def getInfoObject(self, *args, **kwargs):
100                         return { }
101
102                 def getInfo(self, what):
103                         return -1
104
105                 def getInfoString(self, *args, **kwargs):
106                         return self.name
107
108                 def isPlayable(self):
109                         return True
110
111                 def getEvent(self, what):
112                         return None
113
114         def __init__(self, player):
115                 Source.__init__(self)
116                 self.__info = VlcService.Info()
117                 self.server = None
118                 self.service = self
119                 self.player = player
120                 self.lastrefresh = time()
121                 self.stats = None
122                 self.refreshTimer = eTimer()
123                 self.refreshTimer.timeout.get().append(self.__onRefresh)
124                 self.refreshTimer.start(self.refreshInterval)
125
126         def setName(self, name):
127                 i = name.rfind("/")
128                 if i >= 0:
129                         name = name[i+1:]
130                 i = name.rfind("\\")
131                 if i >= 0:
132                         name = name[i+1:]
133                 self.__info.name = name
134                 self.setChanged()
135
136         def setChanged(self):
137                 self.changed( (self.CHANGED_SPECIFIC, iPlayableService.evStart) )
138
139         def setServer(self, server):
140                 self.server = server
141
142         def __onRefresh(self):
143                 if self.server is None:
144                         self.stats = None
145                         return
146                 print "[VLC] refresh"
147                 try:
148                         self.stats = self.server.status()
149                         self.lastrefresh = time()
150                 except Exception, e:
151                         print e
152
153         def refresh(self):
154                 self.__onRefresh()
155
156         def info(self):
157                 return self.__info
158
159         # iSeekableService
160         def seek(self):
161                 return self
162
163         def getPlayPosition(self):
164                 if self.stats and self.stats.has_key("time"):
165                         pos = float(self.stats["time"])
166                         if self.player.state == VlcPlayer.STATE_PLAYING:
167                                 pos += time() - self.lastrefresh
168                         return (False, int(pos*90000))
169                 else:
170                         return (True, 0)
171
172         def getLength(self):
173                 if self.stats and self.stats.has_key("length"):
174                         return (False, int(self.stats["length"])*90000)
175                 else:
176                         return (True, 0)
177
178         # iPlayableService
179         def cueSheet(self): return None
180         def pause(self): return self.player
181         def audioTracks(self):
182                 return self.player.audioTracks()
183
184         def audioChannel(self): return None
185         def subServices(self): return None
186         def frontendInfo(self): return None
187         def timeshift(self): return None
188         def subtitle(self): return None
189         def audioDelay(self): return None
190         def rdsDecoder(self): return None
191         def stream(self): return None
192         def start(self):
193                 self.player.play()
194         def stop(self):
195                 self.player.stop()
196
197
198 class VlcPlayerSummary(Screen):
199         skin = """
200         <screen name="InfoBarMoviePlayerSummary" position="0,0" size="132,64">
201                 <widget source="session.CurrentService" render="Label" position="6,0" size="120,25" font="Regular;14" halign="center" valign="center" >
202                         <convert type="ServiceName">Name</convert>
203                 </widget>
204                 <widget source="session.CurrentService" render="Progress" position="16,27" size="100,5" borderWidth="1">
205                         <convert type="ServicePosition">Position</convert>
206                 </widget>
207                 <widget source="global.CurrentTime" render="Label" position="6,32" size="120,32" font="Regular;32" halign="center" valign="center">
208                         <convert type="ClockToText">Format:%H:%M</convert>
209                 </widget>
210                 <widget source="session.RecordState" render="FixedLabel" text=" " position="6,32" zPosition="1" size="120,32">
211                         <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
212                         <convert type="ConditionalShowHide">Blink</convert>
213                 </widget>
214         </screen>"""
215
216         def __init__(self, session, parent):
217                 Screen.__init__(self, session)
218                 self.skinName = "InfoBarMoviePlayerSummary"
219                 
220
221 class VlcPlayer(Screen, InfoBarNotifications, InfoBarAudioSelection):
222         screen_timeout = 5000
223
224         STATE_IDLE = 0
225         STATE_PLAYING = 1
226         STATE_PAUSED = 2
227
228         def __init__(self, session, server, currentList):
229                 Screen.__init__(self, session)
230                 InfoBarNotifications.__init__(self)
231                 InfoBarAudioSelection.__init__(self)
232                 self.server = server
233                 self.currentList = currentList
234                 self.skinName = "MoviePlayer"
235                 self.state = self.STATE_IDLE
236                 self.oldservice = self.session.screen["CurrentService"]
237                 self.oldNavService = self.session.nav.getCurrentlyPlayingServiceReference()
238                 self.session.nav.stopService()
239                 self.vlcservice = VlcService(self)
240                 self.session.screen["CurrentService"] = self.vlcservice
241                 self.hidetimer = eTimer()
242                 self.hidetimer.timeout.get().append(self.ok)
243                 self.onClose.append(self.__onClose)
244
245                 class VlcPlayerActionMap(ActionMap):
246                         def __init__(self, player, contexts = [ ], actions = { }, prio=0):
247                                 ActionMap.__init__(self, contexts, actions, prio)
248                                 self.player = player
249
250                         def action(self, contexts, action):
251                                 if action[:5] == "seek:":
252                                         time = int(action[5:])
253                                         self.player.seekRelative(time)
254                                         return 1
255                                 elif action[:8] == "seekdef:":
256                                         key = int(action[8:])
257                                         time = [-config.seek.selfdefined_13.value, False, config.seek.selfdefined_13.value,
258                                                         -config.seek.selfdefined_46.value, False, config.seek.selfdefined_46.value,
259                                                         -config.seek.selfdefined_79.value, False, config.seek.selfdefined_79.value][key-1]
260                                         self.player.seekRelative(time)
261                                         return 1
262                                 else:
263                                         return ActionMap.action(self, contexts, action)
264
265                 self["actions"] = VlcPlayerActionMap(self, ["OkCancelActions", "TvRadioActions", "InfobarSeekActions", "MediaPlayerActions"],
266                 {
267                                 "ok": self.ok,
268                                 "cancel": self.stop,
269                                 "keyTV": self.stop,
270                                 "pauseService": self.pause,
271                                 "unPauseService": self.play,
272                                 "play": self.play,
273                                 "seekFwd": self.seekFwd,
274                                 "seekBack": self.seekBack,
275                                 "seekFwdDown": self.seekFwd,
276                                 "seekBackDown": self.seekBack,
277                                 "seekFwdManual": self.seekManual,
278                                 "seekBackManual": self.seekManual,
279                                 "next": self.playNextFile,
280                                 "previous": self.playPrevFile
281                         }, -2)
282
283                 print "[VLC] evEOF=%d" % iPlayableService.evEOF
284                 self.__event_tracker = ServiceEventTracker(screen = self, eventmap=
285                         {
286                                 iPlayableService.evEOF: self.__evEOF,
287                         })
288
289         def createSummary(self):
290                 print "[VLC] createSummary"
291                 return VlcPlayerSummary
292
293         def __onClose(self):
294                 self.session.screen["CurrentService"] = self.oldservice
295                 self.session.nav.playService(self.oldNavService)
296
297         def __evEOF(self):
298                 print "[VLC] Event EOF"
299                 self.stop()
300
301         def playfile(self, path, name):
302                 if self.state != self.STATE_IDLE:
303                         self.stopCurrent()
304                 self.filename = path
305                 self.vlcservice.setName(name)
306                 self.play()
307
308         def play(self):
309                 if self.state == self.STATE_PAUSED:
310                         self.unpause()
311                         return
312                 print "[VLC] setupStream: " + self.filename
313                 if ENIGMA_SERVICE_ID == 0:
314                         self.hide()
315                         self.session.open(
316                                         MessageBox, _("No valid Enigma-Service to play a VLC-Stream\nCheck your installation and try again!"), MessageBox.TYPE_ERROR
317                         )
318                         self.close()
319                         return
320                 try:
321                         url = self.server.playFile(self.filename, DEFAULT_VIDEO_PID, DEFAULT_AUDIO_PID)
322                         print "[VLC] url: " + url
323                 except Exception, e:
324                         self.hide()
325                         self.session.open(
326                                         MessageBox, _("Error with VLC server:\n%s" % e), MessageBox.TYPE_ERROR
327                         )
328                         self.close()
329                         return
330                 if url is not None:
331                         sref = eServiceReference(ENIGMA_SERVICE_ID, 0, url)
332                         print "sref valid=", sref.valid()
333                         sref.setData(0, DEFAULT_VIDEO_PID)
334                         sref.setData(1, DEFAULT_AUDIO_PID)
335                         self.session.nav.playService(sref)
336                         self.state = self.STATE_PLAYING
337                         if self.shown:
338                                 self.__setHideTimer()
339                         self.vlcservice.setServer(self.server)
340                         self.vlcservice.refresh()
341
342         def pause(self):
343                 print "[VLC] pause"
344                 if self.state == self.STATE_PLAYING:
345                         self.session.nav.pause(True)
346                         self.server.pause()
347                         self.state = self.STATE_PAUSED
348                         self.vlcservice.refresh()
349                         if not self.shown:
350                                 self.hidetimer.stop()
351                                 self.show()
352                 elif self.state == self.STATE_PAUSED:
353                         self.unpause()
354
355         def unpause(self):
356                 print "[VLC] unpause"
357                 try:
358                         self.server.seek("-2")
359                         self.server.unpause()
360                 except Exception, e:
361                         self.session.open(
362                                 MessageBox, _("Error with VLC server:\n%s" % e), MessageBox.TYPE_ERROR
363                         )
364                         self.stop()
365                         return
366                 if STOP_BEFORE_UNPAUSE:
367                         self.session.nav.stopService()
368                         sref = self.session.nav.getCurrentlyPlayingServiceReference()
369                         sref.setData(0, DEFAULT_VIDEO_PID)
370                         sref.setData(1, DEFAULT_AUDIO_PID)
371                         self.session.nav.playService(sref)
372                 else:
373                         self.session.nav.pause(False)
374                 self.state = self.STATE_PLAYING
375                 self.vlcservice.refresh()
376                 if self.shown:
377                         self.__setHideTimer()
378
379         def stopCurrent(self):
380                 print "[VLC] stopCurrent"
381                 self.session.nav.stopService()
382                 if self.state == self.STATE_IDLE:
383                         self.close()
384                         return
385                 try:
386                         self.server.stop()
387                         self.server.deleteCurrentTree()
388                 except Exception, e:
389                         self.session.open(
390                                 MessageBox, _("Error with VLC server:\n%s" % e), MessageBox.TYPE_ERROR
391                         )
392                 self.state = self.STATE_IDLE
393                 self.vlcservice.setServer(None)
394                 self.vlcservice.refresh()
395
396         def stop(self):
397                 print "[VLC] stop"
398                 self.stopCurrent()
399                 self.close()
400
401         def __setHideTimer(self):
402                 self.hidetimer.start(self.screen_timeout)
403
404         def showInfobar(self):
405                 self.vlcservice.refresh()
406                 self.show()
407                 if self.state == self.STATE_PLAYING:
408                         self.__setHideTimer()
409                 else:
410                         self.vlcservice.refreshTimer.start(self.vlcservice.refreshInterval)
411
412         def hideInfobar(self):
413                 self.hide()
414                 self.hidetimer.stop()
415                 self.vlcservice.refreshTimer.stop()
416
417         def ok(self):
418                 if self.shown:
419                         self.hideInfobar()
420                 else:
421                         self.showInfobar()
422
423         def playNextFile(self):
424                 print "[VLC] playNextFile"
425                 if isDvdUrl(self.filename):
426                         url, track, chapter = splitDvdUrl(self.filename)
427                         if track is None:
428                                 track = 1
429                         else:
430                                 track = int(track)
431                         if chapter is None:
432                                 chapter = 2
433                         else:
434                                 chapter = int(chapter) + 1
435                         url = "%s@%d:%d" % (url, track, chapter)
436                         self.playfile(url, "DVD")
437                         self.showInfobar()
438                 else:
439                         if self.currentList != None:
440                                 media, name = self.currentList.getNextFile()
441                                 if media is None:
442                                         self.session.open(
443                                                         MessageBox, _("No more files in this directory"), MessageBox.TYPE_INFO
444                                         )
445                                         self.close()
446                                 else:
447                                         self.playfile(media, name)
448                                         self.showInfobar()
449
450         def playPrevFile(self):
451                 print "[VLC] playPrevFile"
452                 if isDvdUrl(self.filename):
453                         url, track, chapter = splitDvdUrl(self.filename)
454                         if track is None:
455                                 track = 1
456                         else:
457                                 track = int(track)
458                         if chapter is not None and int(chapter) > 1:
459                                 chapter = int(chapter) - 1
460                         else:
461                                 chapter = 1
462                         url = "%s@%d:%d" % (url, track, chapter)
463                         self.playfile(url, "DVD")
464                         self.showInfobar()
465                 else:
466                         if self.currentList != None:
467                                 media, name = self.currentList.getPrevFile()
468                                 if media is None:
469                                         self.session.open(
470                                                         MessageBox, _("No previous file in this directory"), MessageBox.TYPE_INFO
471                                         )
472                                         self.close()
473                                 else:
474                                         self.playfile(media, name)
475                                         self.showInfobar()
476
477         def audioTracks(self):
478                 return self.session.nav.getCurrentService() and self.session.nav.getCurrentService().audioTracks();
479
480         def seekRelative(self, delta):
481                 """delta is seconds as integer number
482                 positive=forwards, negative=backwards"""
483                 if self.state != self.STATE_IDLE:
484                         if (delta >= 0):
485                                 self.server.seek("+" + str(delta))
486                         else:
487                                 self.server.seek(str(delta))
488                 self.vlcservice.refresh()
489                 if not self.shown:
490                         self.show()
491                         self.__setHideTimer()
492
493         def seekFwd(self):
494                 if isDvdUrl(self.filename):
495                         url, track, chapter = splitDvdUrl(self.filename)
496                         if track is None:
497                                 track = 2
498                         else:
499                                 track = int(track) + 1
500                         url = "%s@%d" % (url, track)
501                         self.playfile(url, "DVD")
502                         self.showInfobar()
503                 else:
504                         self.seekRelative(600)
505
506         def seekBack(self):
507                 if isDvdUrl(self.filename):
508                         url, track, chapter = splitDvdUrl(self.filename)
509                         if track is not None and int(track) > 2:
510                                 track = int(track) - 1
511                                 url = "%s@%d" % (url, track)
512                         else:
513                                 track = 1
514                         self.playfile(url, "DVD")
515                         self.showInfobar()
516                 else:
517                         self.seekRelative(-600)
518
519         def seekToMinute(self, minutes):
520                 self.server.seek(str(int(minutes)*60))
521                 self.vlcservice.refresh()
522                 if not self.shown:
523                         self.show()
524                         self.__setHideTimer()
525
526         def seekManual(self):
527                 self.session.openWithCallback(self.seekToMinute, MinuteInput)