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