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