1 # -*- coding: ISO-8859-1 -*-
2 #===============================================================================
3 # VLC Player Plugin by A. Lätsch 2007
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
9 #===============================================================================
11 from enigma import iPlayableServicePtr
13 from Screens.Screen import Screen
14 from Screens.MessageBox import MessageBox
15 from Screens.InfoBarGenerics import InfoBarNotifications, InfoBarAudioSelection
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 VlcControlHttp import VlcControlHttp
26 DEFAULT_VIDEO_PID = 0x44
27 DEFAULT_AUDIO_PID = 0x45
32 ENIGMA_SERVICE_ID = 0x1001
33 STOP_BEFORE_UNPAUSE = True
34 print "[VLC] use Gstreamer", e
36 ENIGMA_SERVICE_ID = 0x1002
37 STOP_BEFORE_UNPAUSE = False
38 print "[VLC] use servicets.so"
41 return url.startswith("dvd://") or url.startswith("dvdsimple://")
44 pos = url.rfind("@", len(url)-8)
48 if track.find(":") >= 0:
49 track, chapter = track.split(":")
53 track, chapter = (None, None)
54 return (url, track, chapter)
56 class VlcService(Source, iPlayableServicePtr):
57 refreshInterval = 3000
60 def __init__(self, name=""):
64 def getInfoObject(self, *args, **kwargs):
66 def getInfo(self, what):
68 def getInfoString(self, *args, **kwargs):
72 def getEvent(self, what):
75 def __init__(self, player):
77 self.__info = VlcService.Info()
78 self.vlccontrol = None
81 self.lastrefresh = time()
83 self.refreshTimer = eTimer()
84 self.refreshTimer.timeout.get().append(self.__onRefresh)
85 self.refreshTimer.start(self.refreshInterval)
87 def setFilename(self, filename):
88 i = filename.rfind("/")
90 filename = filename[i+1:]
91 i = filename.rfind("\\")
93 filename = filename[i+1:]
94 self.__info.name = filename
98 self.changed( (self.CHANGED_SPECIFIC, iPlayableService.evStart) )
100 def setControl(self, control):
101 self.vlccontrol = control
103 def __onRefresh(self):
104 if self.vlccontrol is None:
107 print "[VLC] refresh"
109 self.stats = self.vlccontrol.status()
110 self.lastrefresh = time()
123 def getPlayPosition(self):
124 if self.stats and self.stats.has_key("time"):
125 pos = float(self.stats["time"])
126 if self.player.state == VlcPlayer.STATE_PLAYING:
127 pos += time() - self.lastrefresh
128 return (False, int(pos*90000))
133 if self.stats and self.stats.has_key("length"):
134 return (False, int(self.stats["length"])*90000)
139 def cueSheet(self): return None
140 def pause(self): return self.player
141 def audioTracks(self):
142 return self.player.audioTracks();
143 def audioChannel(self): return None
144 def subServices(self): return None
145 def frontendInfo(self): return None
146 def timeshift(self): return None
147 def subtitle(self): return None
148 def audioDelay(self): return None
149 def rdsDecoder(self): return None
150 def stream(self): return None
156 class VlcPlayer(Screen, InfoBarNotifications, InfoBarAudioSelection):
157 screen_timeout = 5000
163 def __init__(self, session, vlcfilelist):
164 Screen.__init__(self, session)
165 InfoBarNotifications.__init__(self)
166 InfoBarAudioSelection.__init__(self)
167 self.filelist = vlcfilelist
168 self.skinName = "MoviePlayer"
169 self.state = self.STATE_IDLE
171 self.oldservice = self.session.screen["CurrentService"]
172 self.vlcservice = VlcService(self)
173 self["CurrentService"] = self.vlcservice
174 self.session.screen["CurrentService"] = self.vlcservice
175 self.hidetimer = eTimer()
176 self.hidetimer.timeout.get().append(self.ok)
177 self.onClose.append(self.__onClose)
179 class VlcPlayerActionMap(ActionMap):
180 def __init__(self, player, contexts = [ ], actions = { }, prio=0):
181 ActionMap.__init__(self, contexts, actions, prio)
184 def action(self, contexts, action):
185 if action[:5] == "seek:":
186 time = int(action[5:])
187 self.player.seekRelative(time)
189 elif action[:8] == "seekdef:":
190 key = int(action[8:])
191 time = [-config.seek.selfdefined_13.value, False, config.seek.selfdefined_13.value,
192 -config.seek.selfdefined_46.value, False, config.seek.selfdefined_46.value,
193 -config.seek.selfdefined_79.value, False, config.seek.selfdefined_79.value][key-1]
194 self.player.seekRelative(time)
197 return ActionMap.action(self, contexts, action)
199 self["actions"] = VlcPlayerActionMap(self, ["OkCancelActions", "TvRadioActions", "InfobarSeekActions", "MediaPlayerActions"],
202 "cancel": self.cancel,
204 "pauseService": self.pause,
205 "unPauseService": self.play,
206 "seekFwd": self.seekFwd,
207 "seekBack": self.seekBack,
208 "seekFwdDown": self.seekFwd,
209 "seekBackDown": self.seekBack,
210 "next": self.playNextFile,
211 "previous": self.playPrevFile
214 print "evEOF=%d" % iPlayableService.evEOF
215 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
217 iPlayableService.evEOF: self.__evEOF,
218 # iPlayableService.evSOF: self.__evSOF,
221 self.session.screen["CurrentService"] = self.oldservice
224 print "[VLC] Event EOF"
227 def playfile(self, servernum, path):
228 if self.state != self.STATE_IDLE:
231 cfg = config.plugins.vlcplayer.servers[servernum]
232 self.vlccontrol = VlcControlHttp(servernum)
233 streamName = VlcControlHttp.defaultStreamName
234 self.vlcservice.setFilename(path)
236 self.servernum = servernum
237 self.url = "http://%s:%d/%s.ts" % (cfg.host.value, cfg.httpport.value, streamName)
238 if path.lower().endswith(".iso") and not isDvdUrl(path):
239 self.filename = "dvdsimple://" + path
243 do_direct = isDvdUrl(self.filename) or re.match("(?i).*\.(mpg|mpeg|ts)$", self.filename)
244 if do_direct and config.plugins.vlcplayer.notranscode.value:
247 transcode = "vcodec=%s,vb=%d,venc=ffmpeg{strict-rc=1},width=%s,height=%s,fps=%s,scale=1,acodec=%s,ab=%d,channels=%d,samplerate=%s" % (
248 config.plugins.vlcplayer.vcodec.value,
249 config.plugins.vlcplayer.vb.value,
250 config.plugins.vlcplayer.width.value,
251 config.plugins.vlcplayer.height.value,
252 config.plugins.vlcplayer.fps.value,
253 config.plugins.vlcplayer.acodec.value,
254 config.plugins.vlcplayer.ab.value,
255 config.plugins.vlcplayer.channels.value,
256 config.plugins.vlcplayer.samplerate.value
258 if config.plugins.vlcplayer.aspect.value != "none":
259 transcode += ",canvas-width=%s,canvas-height=%s,canvas-aspect=%s" % (
260 config.plugins.vlcplayer.width.value,
261 config.plugins.vlcplayer.height.value,
262 config.plugins.vlcplayer.aspect.value
264 if config.plugins.vlcplayer.soverlay.value:
265 transcode += ",soverlay"
266 self.output = "#transcode{%s}:" % transcode
267 mux="ts{pid-video=%d,pid-audio=%d}" % (DEFAULT_VIDEO_PID, DEFAULT_AUDIO_PID)
268 self.output = self.output + "std{access=http,mux=%s,dst=/%s.ts} :sout-all" % (mux, streamName)
272 if self.state == self.STATE_PAUSED:
275 elif self.state == self.STATE_IDLE and self.url is not None:
276 print "[VLC] setupStream: " + self.filename + " " + self.output
278 self.vlccontrol.playfile(self.filename, self.output)
281 MessageBox, _("Error with VLC server:\n%s" % e), MessageBox.TYPE_ERROR)
283 sref = eServiceReference(ENIGMA_SERVICE_ID, 0, self.url)
284 print "sref valid=", sref.valid()
285 sref.setData(0, DEFAULT_VIDEO_PID)
286 sref.setData(1, DEFAULT_AUDIO_PID)
287 self.session.nav.playService(sref)
288 self.state = self.STATE_PLAYING
290 self.__setHideTimer()
291 self.vlcservice.setControl(self.vlccontrol)
292 self.vlcservice.refresh()
296 if self.state == self.STATE_PLAYING:
297 self.session.nav.pause(True)
298 self.vlccontrol.pause()
299 self.state = self.STATE_PAUSED
300 self.vlcservice.refresh()
302 self.hidetimer.stop()
304 elif self.state == self.STATE_PAUSED:
308 print "[VLC] unpause"
310 self.vlccontrol.seek("-2")
311 self.vlccontrol.play()
314 MessageBox, _("Error with VLC server:\n%s" % e), MessageBox.TYPE_ERROR)
317 if STOP_BEFORE_UNPAUSE:
318 self.session.nav.stopService()
319 sref = eServiceReference(ENIGMA_SERVICE_ID, 0, self.url)
320 sref.setData(0, DEFAULT_VIDEO_PID)
321 sref.setData(1, DEFAULT_AUDIO_PID)
322 self.session.nav.playService(sref)
324 self.session.nav.pause(False)
325 self.state = self.STATE_PLAYING
326 self.vlcservice.refresh()
328 self.__setHideTimer()
332 self.session.nav.stopService()
333 if self.state == self.STATE_IDLE:
336 if self.vlccontrol is not None:
338 self.vlccontrol.stop()
339 self.vlccontrol.delete()
342 MessageBox, _("Error with VLC server:\n%s" % e), MessageBox.TYPE_ERROR)
343 self.state = self.STATE_IDLE
344 self.vlcservice.setControl(None)
345 self.vlcservice.refresh()
348 def __setHideTimer(self):
349 self.hidetimer.start(self.screen_timeout)
354 self.hidetimer.stop()
355 self.vlcservice.refreshTimer.stop()
357 self.vlcservice.refresh()
359 if self.state == self.STATE_PLAYING:
360 self.__setHideTimer()
362 self.vlcservice.refreshTimer.start(self.vlcservice.refreshInterval)
368 def playNextFile(self):
369 print "[VLC] playNextFile",self.filename
370 if isDvdUrl(self.filename):
371 url,track,chapter = splitDvdUrl(self.filename)
375 track = int(track) + 1
376 url = "%s@%d" % (url, track)
377 self.playfile(self.servernum, url)
379 path = self.filelist.getNextFile()
381 self.session.open(MessageBox, _("No more files in this directory"), MessageBox.TYPE_INFO)
383 servernum, path = path.split(":", 1)
384 self.playfile(int(servernum), path)
386 def playPrevFile(self):
387 print "[VLC] playPrevFile"
388 if isDvdUrl(self.filename):
389 url,track,chapter = splitDvdUrl(self.filename)
390 if track is not None and int(track) > 2:
391 track = int(track) - 1
392 url = "%s@%d" % (url, track)
393 self.playfile(self.servernum, url)
395 path = self.filelist.getPrevFile()
397 self.session.open(MessageBox, _("No previous file in this directory"), MessageBox.TYPE_INFO)
399 servernum, path = path.split(":", 1)
400 self.playfile(int(servernum), path)
402 def audioTracks(self):
403 return self.session.nav.getCurrentService() and self.session.nav.getCurrentService().audioTracks();
405 def seekRelative(self, delta):
406 """delta is seconds as integer number
407 positive=forwards, negative=backwards"""
408 if self.state != self.STATE_IDLE:
410 self.vlccontrol.seek("+"+str(delta))
412 self.vlccontrol.seek(str(delta))
413 self.vlcservice.refresh()
416 self.__setHideTimer()
419 self.seekRelative(600)
422 self.seekRelative(-600)