support for servicets.so
[enigma2-plugins.git] / vlcplayer / src / VlcPlayer.py
1 # -*- coding: ISO-8859-1 -*-
2 #===============================================================================
3 # VLC Player Plugin by A. Lätsch 2007
4 #
5 # This is free software; you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free
7 # Software Foundation; either version 2, or (at your option) any later
8 # version.
9 #===============================================================================
10
11 from enigma import iPlayableServicePtr
12 from time import time
13 from Screens.Screen import Screen
14 from Screens.MessageBox import MessageBox
15 from Screens.InfoBarGenerics import InfoBarNotifications
16 from Components.config import config
17 from enigma import eServiceReference
18 from Components.Sources.Source import Source
19 from Components.ServiceEventTracker import ServiceEventTracker
20 from enigma import iPlayableService
21 from enigma import eTimer
22 from Components.ActionMap import ActionMap
23 from VlcControlTelnet import VlcControlTelnet
24 from VlcControlHttp import VlcControlHttp
25
26 DEFAULT_VIDEO_PID = 0x44
27 DEFAULT_AUDIO_PID = 0x45
28
29 try:
30         import servicets
31 except:
32         ENIGMA_SERVICE_ID = 0x1001
33         STOP_BEFORE_UNPAUSE = True
34         print "[VLC] use Gstreamer"
35 else:
36         ENIGMA_SERVICE_ID = 0x1002
37         STOP_BEFORE_UNPAUSE = False
38         print "[VLC] use servicets.so"
39
40 class VlcService(Source, iPlayableServicePtr):
41         refreshInterval = 3000
42         
43         class Info:
44                 def __init__(self, name=""):
45                         self.name = name
46                 def getName(self):
47                         return self.name
48                 def getInfoObject(self, *args, **kwargs):
49                         return { }
50                 def getInfo(self, what):
51                         return -1
52                 def getInfoString(self, *args, **kwargs):
53                         return self.name
54                 def isPlayable(self):
55                         return True
56                 def getEvent(self, what):
57                         return None
58
59         def __init__(self, player):
60                 Source.__init__(self)
61                 self.__info = VlcService.Info()
62                 self.vlccontrol = None
63                 self.service = self
64                 self.player = player
65                 self.lastrefresh = time()
66                 self.stats = None
67                 self.refreshTimer = eTimer()
68                 self.refreshTimer.timeout.get().append(self.__onRefresh)
69                 self.refreshTimer.start(self.refreshInterval)
70         
71         def setFilename(self, filename):
72                 i = filename.rfind("/")
73                 if i >= 0:
74                         filename = filename[i+1:]
75                 i = filename.rfind("\\")
76                 if i >= 0:
77                         filename = filename[i+1:]
78                 self.__info.name = filename
79                 self.setChanged()
80         
81         def setChanged(self):
82                 self.changed( (self.CHANGED_SPECIFIC, iPlayableService.evStart) )
83         
84         def setControl(self, control):
85                 self.vlccontrol = control
86                 
87         def __onRefresh(self):
88                 if self.vlccontrol is None: 
89                         self.stats = None
90                         return
91                 print "[VLC] refresh"
92                 try:
93                         self.stats = self.vlccontrol.status()
94                         self.lastrefresh = time()
95                 except Exception, e:
96                         print e
97         
98         def refresh(self):
99                 self.__onRefresh()
100         
101         def info(self):
102                 return self.__info
103         
104         # iSeekableService
105         def seek(self):
106                 return self
107         def getPlayPosition(self):
108                 if self.stats and self.stats.has_key("time"):
109                         pos = float(self.stats["time"])
110                         if self.player.state == VlcPlayer.STATE_PLAYING:
111                                 pos += time() - self.lastrefresh
112                         return (False, int(pos*90000))
113                 else:
114                         return (True, 0)
115         
116         def getLength(self):
117                 if self.stats and self.stats.has_key("length"):
118                         return (False, int(self.stats["length"])*90000)
119                 else:
120                         return (True, 0)
121         
122         # iPlayableService
123         def cueSheet(self): return None
124         def pause(self): return self.player
125         def audioTracks(self): return None
126         def audioChannel(self): return None
127         def subServices(self): return None
128         def frontendInfo(self): return None
129         def timeshift(self): return None
130         def subtitle(self): return None
131         def audioDelay(self): return None
132         def rdsDecoder(self): return None
133         def stream(self): return None
134         def start(self):
135                 self.player.play()
136         def stop(self):
137                 self.player.stop()
138
139 class VlcPlayer(Screen, InfoBarNotifications):
140         screen_timeout = 5000
141         
142         STATE_IDLE = 0
143         STATE_PLAYING = 1
144         STATE_PAUSED = 2
145         
146         def __init__(self, session, vlcfilelist):
147                 Screen.__init__(self, session)
148                 InfoBarNotifications.__init__(self)
149                 self.filelist = vlcfilelist
150                 self.skinName = "MoviePlayer"
151                 self.state = self.STATE_IDLE
152                 self.url = None
153                 self.oldservice = self.session.screen["CurrentService"]
154                 self.vlcservice = VlcService(self)
155                 self["CurrentService"] = self.vlcservice
156                 self.session.screen["CurrentService"] = self.vlcservice
157                 self.hidetimer = eTimer()
158                 self.hidetimer.timeout.get().append(self.ok)
159                 self.onClose.append(self.__onClose)
160
161                 class InfoBarSeekActionMap(ActionMap):
162                         def __init__(self, player, contexts = [ ], actions = { }, prio=0):
163                                 ActionMap.__init__(self, contexts, actions, prio)
164                                 self.player = player
165                                 
166                         def action(self, contexts, action):
167                                 if action[:5] == "seek:":
168                                         time = int(action[5:])
169                                         self.player.seekRelative(time)
170                                         return 1
171                                 elif action[:8] == "seekdef:":
172                                         key = int(action[8:])
173                                         time = [-config.seek.selfdefined_13.value, False, config.seek.selfdefined_13.value,
174                                                         -config.seek.selfdefined_46.value, False, config.seek.selfdefined_46.value,
175                                                         -config.seek.selfdefined_79.value, False, config.seek.selfdefined_79.value][key-1]
176                                         self.player.seekRelative(time)
177                                         return 1
178                                 else:
179                                         return ActionMap.action(self, contexts, action)
180                 
181                 self["actions"] = InfoBarSeekActionMap(self, ["OkCancelActions", "TvRadioActions", "InfobarSeekActions", "MediaPlayerActions"],
182                 {
183                                 "ok": self.ok,
184                                 "cancel": self.cancel,
185                                 "keyTV": self.stop,
186                                 "pauseService": self.pause,
187                                 "unPauseService": self.play,
188                                 "seekFwd": self.seekFwd,
189                                 "seekBack": self.seekBack,
190                                 "seekFwdDown": self.seekFwd,
191                                 "seekBackDown": self.seekBack,
192                                 "next": self.playNextFile,
193                                 "previous": self.playPrevFile
194                         }, -2)
195
196                 print "evEOF=%d" % iPlayableService.evEOF
197                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
198                         {
199                                 iPlayableService.evEOF: self.__evEOF,
200 #                               iPlayableService.evSOF: self.__evSOF,
201                         })
202         def __onClose(self):
203                 self.session.screen["CurrentService"] = self.oldservice
204         
205         def __evEOF(self):
206                 print "[VLC] Event EOF"
207                 self.stop()
208         
209         def playfile(self, servernum, path):
210                 if self.state != self.STATE_IDLE:
211                         self.stop()
212
213                 cfg = config.plugins.vlcplayer.servers[servernum]
214                 if cfg.method.value == "telnet":
215                         self.vlccontrol = VlcControlTelnet(servernum)
216                         streamName = VlcControlTelnet.defaultStreamName
217                 else:
218                         self.vlccontrol = VlcControlHttp(servernum)
219                         streamName = VlcControlHttp.defaultStreamName
220                 self.vlcservice.setFilename(path)
221                 
222                 self.url = "http://%s:%d/%s.ts" % (cfg.host.value, cfg.httpport.value, streamName)
223                 self.filename = path
224                 transcode = "vcodec=%s,vb=%d,width=%s,height=%s,fps=%s,scale=1,acodec=%s,ab=%d,channels=%d,samplerate=%s" % (
225                         config.plugins.vlcplayer.vcodec.value, 
226                         config.plugins.vlcplayer.vb.value, 
227                         config.plugins.vlcplayer.width.value, 
228                         config.plugins.vlcplayer.height.value, 
229                         config.plugins.vlcplayer.fps.value, 
230                         config.plugins.vlcplayer.acodec.value, 
231                         config.plugins.vlcplayer.ab.value, 
232                         config.plugins.vlcplayer.channels.value,
233                         config.plugins.vlcplayer.samplerate.value
234                 )
235                 if config.plugins.vlcplayer.aspect.value != "none":
236                         transcode += ",canvas-width=%s,canvas-height=%s,canvas-aspect=%s" % (
237                                 config.plugins.vlcplayer.width.value, 
238                                 config.plugins.vlcplayer.height.value, 
239                                 config.plugins.vlcplayer.aspect.value
240                         ) 
241                 if config.plugins.vlcplayer.soverlay.value:
242                         transcode += ",soverlay"
243                 mux="ts{pid-video=%d,pid-audio=%d}" % (DEFAULT_VIDEO_PID, DEFAULT_AUDIO_PID)
244                 self.output = "#transcode{%s}:std{access=http,mux=%s,dst=/%s.ts}" % (transcode, mux, streamName)
245                 self.play()
246
247         def play(self):
248                 if self.state == self.STATE_PAUSED:
249                         self.unpause()
250                         return
251                 elif self.state == self.STATE_IDLE and self.url is not None:
252                         print "[VLC] setupStream: " + self.filename + " " + self.output
253                         try:
254                                 self.vlccontrol.playfile(self.filename, self.output)
255                         except Exception, e:
256                                 self.session.open(
257                                         MessageBox, _("Error with VLC server:\n%s" % e), MessageBox.TYPE_ERROR)
258                                 return
259                         sref = eServiceReference(ENIGMA_SERVICE_ID, 0, self.url)
260                         print "sref valid=", sref.valid()
261                         sref.setData(0, DEFAULT_VIDEO_PID)
262                         sref.setData(1, DEFAULT_AUDIO_PID)
263                         self.session.nav.playService(sref)
264                         self.state = self.STATE_PLAYING
265                         if self.shown:
266                                 self.__setHideTimer()
267                 self.vlcservice.setControl(self.vlccontrol)
268                 self.vlcservice.refresh()
269
270         def pause(self):
271                 print "[VLC] pause"
272                 if self.state == self.STATE_PLAYING:
273                         self.session.nav.pause(True)
274                         self.vlccontrol.pause()
275                         self.state = self.STATE_PAUSED
276                         self.vlcservice.refresh()
277                         if not self.shown:
278                                 self.hidetimer.stop()
279                                 self.show()
280                 elif self.state == self.STATE_PAUSED:
281                         self.unpause()
282
283         def unpause(self):
284                 print "[VLC] unpause"
285                 try:
286                         self.vlccontrol.seek("-2")
287                         self.vlccontrol.play()
288                 except Exception, e:
289                         self.session.open(
290                                 MessageBox, _("Error with VLC server:\n%s" % e), MessageBox.TYPE_ERROR)
291                         self.stop()
292                         return
293                 if STOP_BEFORE_UNPAUSE:
294                         self.session.nav.stopService()
295                         sref = eServiceReference(ENIGMA_SERVICE_ID, 0, self.url)
296                         sref.setData(0, DEFAULT_VIDEO_PID)
297                         sref.setData(1, DEFAULT_AUDIO_PID)
298                         self.session.nav.playService(sref)
299                 else:
300                         self.session.nav.pause(False)
301                 self.state = self.STATE_PLAYING
302                 self.vlcservice.refresh()
303                 if self.shown:
304                         self.__setHideTimer()
305                 
306         def stop(self):
307                 print "[VLC] stop"
308                 self.session.nav.stopService()
309                 if self.state == self.STATE_IDLE:
310                         self.close()
311                         return
312                 if self.vlccontrol is not None:
313                         try:
314                                 self.vlccontrol.stop()
315                                 self.vlccontrol.delete()
316                         except Exception, e:
317                                 self.session.open(
318                                         MessageBox, _("Error with VLC server:\n%s" % e), MessageBox.TYPE_ERROR)
319                 self.state = self.STATE_IDLE
320                 self.vlcservice.setControl(None)
321                 self.vlcservice.refresh()
322                 self.show()
323
324         def __setHideTimer(self):
325                 self.hidetimer.start(self.screen_timeout)
326
327         def ok(self):
328                 if self.shown:
329                         self.hide()
330                         self.hidetimer.stop()
331                         self.vlcservice.refreshTimer.stop()
332                 else:
333                         self.vlcservice.refresh()
334                         self.show()
335                         if self.state == self.STATE_PLAYING:
336                                 self.__setHideTimer()
337                         else:
338                                 self.vlcservice.refreshTimer.start(self.vlcservice.refreshInterval)
339
340         def cancel(self):
341                 self.stop()
342                 self.close()
343         
344         def playNextFile(self):
345                 print "[VLC] playNextFile"
346                 path = self.filelist.getNextFile()
347                 if path is None:
348                         self.session.open(MessageBox, _("No more files in this directory"), MessageBox.TYPE_INFO)
349                 else:
350                         servernum, path = path.split(":", 1)
351                         self.playfile(int(servernum), path)
352
353         def playPrevFile(self):
354                 print "[VLC] playPrevFile"
355                 path = self.filelist.getPrevFile()
356                 if path is None:
357                         self.session.open(MessageBox, _("No previous file in this directory"), MessageBox.TYPE_INFO)
358                 else:
359                         servernum, path = path.split(":", 1)
360                         self.playfile(int(servernum), path)
361
362         def seekRelative(self, delta):
363                 """delta is seconds as integer number
364                 positive=forwards, negative=backwards"""
365                 if self.state != self.STATE_IDLE:
366                         if (delta >= 0):
367                                 self.vlccontrol.seek("+"+str(delta))
368                         else:
369                                 self.vlccontrol.seek(str(delta))
370                 self.vlcservice.refresh()
371                 if not self.shown:
372                         self.show()
373                         self.__setHideTimer()
374
375         def seekFwd(self):
376                 self.seekRelative(600)
377
378         def seekBack(self):
379                 self.seekRelative(-600)