Merge branch 'refs/heads/master' of ssh://sreichholf@scm.schwerkraft.elitedvb.net...
[enigma2-plugins.git] / autoresolution / src / plugin.py
1 from Screens.Screen import Screen
2 from Screens.Setup import SetupSummary
3 from Screens.MessageBox import MessageBox
4 from Components.ConfigList import ConfigList, ConfigListScreen
5 from Components.config import config, getConfigListEntry, ConfigSelection, ConfigSubsection, ConfigYesNo, ConfigSubDict, ConfigNothing
6 from Components.ServiceEventTracker import ServiceEventTracker
7 from Components.ActionMap import ActionMap
8 from Components.Label import Label
9 from Components.Sources.StaticText import StaticText
10 from enigma import iPlayableService, iServiceInformation, eTimer
11 from Plugins.Plugin import PluginDescriptor
12 from Plugins.SystemPlugins.Videomode.VideoHardware import video_hw # depends on Videomode Plugin
13
14 usable = False
15 preferedmodes = None
16 default = None
17 port = None
18 videoresolution_dictionary = {}
19 resolutionlabel = None
20
21 resolutions = (('sd_i_50', (_("SD 25/50HZ Interlace Mode"))), ('sd_i_60', (_("SD 30/60HZ Interlace Mode"))), \
22                         ('sd_p_50', (_("SD 25/50HZ Progressive Mode"))), ('sd_p_60', (_("SD 30/60HZ Progressive Mode"))), \
23                         ('hd_i', (_("HD Interlace Mode"))), ('hd_p', (_("HD Progressive Mode"))), \
24                         ('p720_24', (_("Enable 720p24 Mode"))), ('p1080_24', (_("Enable 1080p24 Mode"))), \
25                         ('p1080_25', (_("Enable 1080p25 Mode"))), ('p1080_30', (_("Enable 1080p30 Mode"))))
26
27 config.plugins.autoresolution = ConfigSubsection()
28 config.plugins.autoresolution.enable = ConfigYesNo(default = False)
29 config.plugins.autoresolution.showinfo = ConfigYesNo(default = True)
30 config.plugins.autoresolution.testmode = ConfigYesNo(default = False)
31 config.plugins.autoresolution.deinterlacer = ConfigSelection(default = "auto", choices =
32                 [("off", _("off")), ("auto", _("auto")), ("on", _("on")), ("bob", _("bob"))])
33 config.plugins.autoresolution.deinterlacer_progressive = ConfigSelection(default = "auto", choices =
34                 [("off", _("off")), ("auto", _("auto")), ("on", _("on")), ("bob", _("bob"))])
35 config.plugins.autoresolution.delay_switch_mode = ConfigSelection(default = "1000", choices = [
36                 ("1000", "1 " + _("second")), ("2000", "2 " + _("seconds")), ("3000", "3 " + _("seconds")),
37                 ("4000", "4 " + _("seconds")), ("5000", "5 " + _("seconds")), ("6000", "6 " + _("seconds")), ("7000", "7 " + _("seconds")),
38                 ("8000", "8 " + _("seconds")), ("9000", "9 " + _("seconds")), ("10000", "10 " + _("seconds"))])
39
40 def setDeinterlacer(mode):
41         print "[AutoRes] switch deinterlacer mode to %s" % mode
42         f = open('/proc/stb/vmpeg/deinterlace' , "w")
43         f.write("%s\n" % mode)
44         f.close()
45
46 frqdic = { 23976: '24', \
47                 24000: '24', \
48                 25000: '25', \
49                 29970: '30', \
50                 30000: '30', \
51                 50000: '50', \
52                 59940: '60', \
53                 60000: '60'}
54
55 class AutoRes(Screen):
56         def __init__(self, session):
57                 global port
58                 Screen.__init__(self, session)
59                 self.__event_tracker = ServiceEventTracker(screen = self, eventmap =
60                         {
61                                 iPlayableService.evVideoSizeChanged: self.__evVideoSizeChanged,
62                                 iPlayableService.evVideoProgressiveChanged: self.__evVideoProgressiveChanged,
63                                 iPlayableService.evVideoFramerateChanged: self.__evVideoFramerateChanged,
64                                 iPlayableService.evUpdatedInfo: self.__evUpdatedInfo,
65                                 iPlayableService.evStart: self.__evStart
66                         })
67                 self.timer = eTimer()
68                 self.timer.callback.append(self.determineContent)
69                 self.lastmode = config.av.videomode[config.av.videoport.value].value
70                 config.av.videoport.addNotifier(self.defaultModeChanged)
71                 config.plugins.autoresolution.enable.addNotifier(self.enableChanged, initial_call = False)
72                 config.plugins.autoresolution.deinterlacer.addNotifier(self.enableChanged, initial_call = False)
73                 config.plugins.autoresolution.deinterlacer_progressive.addNotifier(self.enableChanged, initial_call = False)
74                 self.setMode(default[0], False)
75                 self.after_switch_delay = False
76                 self.newService = False
77                 config.av.videorate["720p"].addNotifier(self.__videorate_720p_changed, initial_call = False, immediate_feedback = False)
78                 config.av.videorate["1080i"].addNotifier(self.__videorate_1080i_changed, initial_call = False, immediate_feedback = False)
79
80         def __videorate_720p_changed(self, configEntry):
81                 if self.lastmode == "720p":
82                         self.changeVideomode()
83
84         def __videorate_1080i_changed(self, configEntry):
85                 if self.lastmode == "1080i":
86                         self.changeVideomode()
87
88         def __evStart(self):
89                 self.newService = True
90
91         def __evUpdatedInfo(self):
92                 if self.newService:
93                         print "[AutoRes] service changed"
94                         self.after_switch_delay = False
95                         self.timer.start(int(config.plugins.autoresolution.delay_switch_mode.value))
96                         self.newService = False
97
98         def defaultModeChanged(self, configEntry):
99                 global preferedmodes
100                 global port
101                 global default
102                 global usable
103                 port_changed = configEntry == config.av.videoport
104                 if port_changed:
105                         print "port changed to", configEntry.value
106                         if port:
107                                 config.av.videomode[port].notifiers.remove(self.defaultModeChanged)
108                         port = config.av.videoport.value
109                         config.av.videomode[port].addNotifier(self.defaultModeChanged)
110                         usable = config.plugins.autoresolution.enable.value and not port in ('DVI-PC', 'Scart')
111                 else: # videomode changed in normal av setup
112                         global videoresolution_dictionary
113                         print "mode changed to", configEntry.value
114                         default = (configEntry.value, _("default"))
115                         preferedmodes = [mode[0] for mode in video_hw.getModeList(port) if mode[0] != default[0]]
116                         preferedmodes.append(default)
117                         print "default", default
118                         print "preferedmodes", preferedmodes
119                         videoresolution_dictionary = {}
120                         config.plugins.autoresolution.videoresolution = ConfigSubDict()
121                         for mode in resolutions:
122                                 if mode[0].startswith('p1080'):
123                                         choices = ['1080p24', '1080p25', '1080p30'] + preferedmodes
124                                 elif mode[0] == 'p720_24':
125                                         choices = ['720p24', '1080p24'] + preferedmodes
126                                 else:
127                                         choices = preferedmodes
128                                 config.plugins.autoresolution.videoresolution[mode[0]] = ConfigSelection(default = default[0], choices = choices)
129                                 config.plugins.autoresolution.videoresolution[mode[0]].addNotifier(self.modeConfigChanged, initial_call = False, immediate_feedback = False)
130                                 videoresolution_dictionary[mode[0]] = (config.plugins.autoresolution.videoresolution[mode[0]])
131
132         def modeConfigChanged(self, configElement):
133                 self.determineContent()
134
135         def enableChanged(self, configElement):
136                 global usable
137                 if configElement.value:
138                         usable = not port in ('DVI-PC', 'Scart')
139                         self.determineContent()
140                 else:
141                         usable = False
142                         self.changeVideomode()
143
144         def __evVideoFramerateChanged(self):
145                 print "[AutoRes] got event evFramerateChanged"
146                 if not self.timer.isActive() or self.after_switch_delay:
147                         self.timer.start(100) # give other pending events a chance..
148
149         def __evVideoSizeChanged(self):
150                 print "[AutoRes] got event evVideoSizeChanged"
151                 if not self.timer.isActive() or self.after_switch_delay:
152                         self.timer.start(100) # give other pending events a chance..
153
154         def __evVideoProgressiveChanged(self):
155                 print "[AutoRes] got event evVideoProgressiveChanged"
156                 if not self.timer.isActive() or self.after_switch_delay:
157                         self.timer.start(100) # give other pending events a chance..
158
159         def determineContent(self):
160                 print "[AutoRes] determineContent"
161                 self.timer.stop()
162                 self.after_switch_delay = True
163                 if usable:
164                         service = self.session.nav.getCurrentService()
165                         info = service and service.info()
166                         height = info and info.getInfo(iServiceInformation.sVideoHeight)
167                         width = info and info.getInfo(iServiceInformation.sVideoWidth)
168                         framerate = info and info.getInfo(iServiceInformation.sFrameRate)
169                         if height != -1 and width != -1 and framerate != -1:
170                                 frate = str(framerate)[:2] #fallback?
171                                 if frqdic.has_key(framerate):
172                                         frate = frqdic[framerate]
173                                 progressive = info and info.getInfo(iServiceInformation.sProgressive)
174
175                                 prog = progressive == 1 and 'p' or 'i'
176
177                                 if (height >= 900 or width >= 1600) and frate in ('24', '25', '30') and prog == 'p':    # 1080p content
178                                         new_mode = 'p1080_%s' % frate
179                                 elif (height > 576 or width > 720) and frate == '24' and prog == 'p':           # 720p24 detection
180                                         new_mode = 'p720_24'
181                                 elif (height <= 576) and (width <= 720) and frate in ('25', '50'):
182                                         new_mode = 'sd_%s_50' % prog
183                                 elif (height <= 480) and (width <= 720) and frate in ('24', '30', '60'):
184                                         new_mode = 'sd_%s_60' % prog
185                                 else:
186                                         new_mode = 'hd_%s' % prog
187
188                                 if progressive == 1:
189                                         setDeinterlacer(config.plugins.autoresolution.deinterlacer_progressive.value)
190                                 else:
191                                         setDeinterlacer(config.plugins.autoresolution.deinterlacer.value)
192
193                                 print "[AutoRes] new content is %sx%s%s%s" %(width, height, prog, frate)
194
195                                 if videoresolution_dictionary.has_key(new_mode):
196                                         new_mode = videoresolution_dictionary[new_mode].value
197                                         print '[AutoRes] determined videomode', new_mode
198                                         old = resolutionlabel["content"].getText()
199                                         resolutionlabel["content"].setText("Videocontent: %sx%s%s %sHZ" % (width, height, prog, frate))
200                                         if self.lastmode != new_mode:
201                                                 self.lastmode = new_mode
202                                                 self.changeVideomode()
203                                         elif old != resolutionlabel["content"].getText() and config.plugins.autoresolution.showinfo.value:
204                                                 resolutionlabel.show()
205
206         def changeVideomode(self):
207                 if usable:
208                         mode = self.lastmode
209                         if mode.find("1080p") != -1 or mode.find("720p24") != -1:
210                                 print "[AutoRes] switching to", mode
211                                 v = open('/proc/stb/video/videomode' , "w")
212                                 v.write("%s\n" % mode)
213                                 v.close()
214                                 resolutionlabel["restxt"].setText("Videomode: %s" % mode)
215                                 if config.plugins.autoresolution.showinfo.value:
216                                         resolutionlabel.show()
217                         else:
218                                 self.setMode(mode)
219                         if config.plugins.autoresolution.testmode.value and default[0] != mode:
220                                 resolutionlabeltxt = "Videomode: %s" % mode
221                                 self.session.openWithCallback(
222                                         self.confirm,
223                                         MessageBox,
224                                         _("Autoresolution Plugin Testmode:\nIs %s ok?") % (resolutionlabeltxt),
225                                         MessageBox.TYPE_YESNO,
226                                         timeout = 15,
227                                         default = False
228                                 )
229                 else:
230                         setDeinterlacer("auto")
231                         if self.lastmode != default[0]:
232                                 self.setMode(default[0])
233
234         def confirm(self, confirmed):
235                 if not confirmed:
236                         self.setMode(default[0])
237
238         def setMode(self, mode, set=True):
239                 rate = config.av.videorate[mode].value
240                 resolutionlabel["restxt"].setText("Videomode: %s %s %s" % (port, mode, rate))
241                 if set:
242                         print "[AutoRes] switching to %s %s %s" % (port, mode, rate)
243                         if config.plugins.autoresolution.showinfo.value:
244                                 resolutionlabel.show()
245                         video_hw.setMode(port, mode, rate)
246                 self.lastmode = mode
247
248 class ResolutionLabel(Screen):
249         skin = """
250                 <screen position="50,40" size="250,36" flags="wfNoBorder" >
251                         <widget name="content" position="0,0" size="250,18" font="Regular;16" />
252                         <widget name="restxt" position="0,18" size="250,18" font="Regular;16" />
253                 </screen>"""
254         def __init__(self, session):
255                 Screen.__init__(self, session)
256
257                 self["content"] = Label()
258                 self["restxt"] = Label()
259
260                 self.hideTimer = eTimer()
261                 self.hideTimer.callback.append(self.hide)
262
263                 self.onShow.append(self.hide_me)
264
265         def hide_me(self):
266                 self.hideTimer.start(config.usage.infobar_timeout.index * 1500, True)
267
268
269 class AutoResSetupMenu(Screen, ConfigListScreen):
270         def __init__(self, session):
271                 Screen.__init__(self, session)
272                 self.skinName = [ "AutoResSetupMenu", "Setup" ]
273                 self.setup_title = _("Autoresolution videomode setup")
274
275                 self.onChangedEntry = [ ]
276                 self.list = [ ]
277                 ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changedEntry)
278
279                 self["actions"] = ActionMap(["SetupActions"],
280                         {
281                                 "cancel": self.keyCancel,
282                                 "save": self.apply,
283                         }, -2)
284
285                 self["key_green"] = StaticText(_("OK"))
286                 self["key_red"] = StaticText(_("Cancel"))
287
288                 self.createSetup()
289                 self.onLayoutFinish.append(self.layoutFinished)
290
291         def layoutFinished(self):
292                 self.setTitle(_("Autoresolution settings"))
293
294         def createSetup(self):
295                 self.list = [ getConfigListEntry(_("Enable Autoresolution"), config.plugins.autoresolution.enable) ]
296                 if config.plugins.autoresolution.enable.value:
297                         if usable:
298                                 for mode, label in resolutions:
299                                         self.list.append(getConfigListEntry(label, videoresolution_dictionary[mode]))
300                                 self.list.extend((
301                                         getConfigListEntry(_("Refresh Rate")+" 720p", config.av.videorate["720p"]),
302                                         getConfigListEntry(_("Refresh Rate")+" 1080i", config.av.videorate["1080i"]),
303                                         getConfigListEntry(_("Show info screen"), config.plugins.autoresolution.showinfo),
304                                         getConfigListEntry(_("Delay x seconds after service started"), config.plugins.autoresolution.delay_switch_mode),
305                                         getConfigListEntry(_("Running in testmode"), config.plugins.autoresolution.testmode),
306                                         getConfigListEntry(_("Deinterlacer mode for interlaced content"), config.plugins.autoresolution.deinterlacer),
307                                         getConfigListEntry(_("Deinterlacer mode for progressive content"), config.plugins.autoresolution.deinterlacer_progressive)
308                                 ))
309                         else:
310                                 self.list.append(getConfigListEntry(_("Autoresolution is not working in Scart/DVI-PC Mode"), ConfigNothing()))
311
312                 self["config"].list = self.list
313                 self["config"].setList(self.list)
314
315         def apply(self):
316                 for x in self["config"].list:
317                         x[1].save()
318                 self.close()
319
320         def keyLeft(self):
321                 ConfigListScreen.keyLeft(self)
322                 if self["config"].getCurrent()[1] == config.plugins.autoresolution.enable:
323                         self.createSetup()
324
325         def keyRight(self):
326                 ConfigListScreen.keyRight(self)
327                 if self["config"].getCurrent()[1] == config.plugins.autoresolution.enable:
328                         self.createSetup()
329
330         # for summary:
331         def changedEntry(self):
332                 for x in self.onChangedEntry:
333                         x()
334
335         def getCurrentEntry(self):
336                 return self["config"].getCurrent()[0]
337
338         def getCurrentValue(self):
339                 return str(self["config"].getCurrent()[1].getText())
340
341         def createSummary(self):
342                 return SetupSummary
343
344 def autostart(reason, **kwargs):
345         if "session" in kwargs and resolutionlabel is None:
346                 global resolutionlabel
347                 session = kwargs["session"]
348                 resolutionlabel = session.instantiateDialog(ResolutionLabel)
349                 AutoRes(session)
350
351 def startSetup(menuid):
352         if menuid != "system":
353                 return [ ]
354         return [("Autoresolution...", autoresSetup, "autores_setup", 45)]
355
356 def autoresSetup(session, **kwargs):
357         autostart(reason=0, session=session)
358         session.open(AutoResSetupMenu)
359
360 def Plugins(path, **kwargs):
361         return [PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART], fnc = autostart), \
362                 PluginDescriptor(name="Autoresolution", description=_("Autoresolution Switch"), where = PluginDescriptor.WHERE_MENU, fnc=startSetup) ]