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