global: 'Dream Multimedia' -> 'Dream Property'
[enigma2-plugins.git] / autoresolution / src / plugin.py
1 # encoding: utf-8
2 from Screens.Screen import Screen
3 from Screens.Setup import SetupSummary
4 from Screens.MessageBox import MessageBox
5 from Components.ConfigList import ConfigList, ConfigListScreen
6 from Components.config import config, getConfigListEntry, ConfigSelection, ConfigSubsection, ConfigYesNo, ConfigSubDict, ConfigNothing
7 from Components.ServiceEventTracker import ServiceEventTracker
8 from Components.ActionMap import ActionMap
9 from Components.Label import Label
10 from Components.Sources.StaticText import StaticText
11 from enigma import iPlayableService, iServiceInformation, eTimer, getDesktop
12 from Plugins.Plugin import PluginDescriptor
13 from Plugins.SystemPlugins.Videomode.VideoHardware import video_hw # depends on Videomode Plugin
14
15 usable = False
16 preferedmodes = None
17 default = None
18 port = None
19 videoresolution_dictionary = {}
20 resolutionlabel = None
21
22 resolutions = (('sd_i_50', (_("SD 25/50HZ Interlace Mode"))), ('sd_i_60', (_("SD 30/60HZ Interlace Mode"))), \
23                         ('sd_p_50', (_("SD 25/50HZ Progressive Mode"))), ('sd_p_60', (_("SD 30/60HZ Progressive Mode"))), \
24                         ('hd_i', (_("HD Interlace Mode"))), ('hd_p', (_("HD Progressive Mode"))), \
25                         ('p720_24', (_("Enable 720p24 Mode"))), ('p1080_24', (_("Enable 1080p24 Mode"))), \
26                         ('p1080_25', (_("Enable 1080p25 Mode"))), ('p1080_30', (_("Enable 1080p30 Mode"))), \
27                         ('uhd_p', (_("UHD Progressive Mode"))), ('p2160_24', (_("Enable 2160p24 Mode"))), \
28                         ('p2160_25', (_("Enable 2160p25 Mode"))), ('p2160_30', (_("Enable 2160p30 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                 if "2160p" in config.av.videorate:
90                         config.av.videorate["2160p"].addNotifier(self.__videorate_2160p_changed, initial_call = False, immediate_feedback = False)
91
92         def __videorate_720p_changed(self, configEntry):
93                 if self.lastmode == "720p":
94                         self.changeVideomode()
95
96         def __videorate_1080i_changed(self, configEntry):
97                 if self.lastmode == "1080i":
98                         self.changeVideomode()
99
100         def __videorate_1080p_changed(self, configEntry):
101                 if self.lastmode == "1080p":
102                         self.changeVideomode()
103
104         def __videorate_2160p_changed(self, configEntry):
105                 if self.lastmode == "2160p":
106                         self.changeVideomode()
107
108         def __evStart(self):
109                 self.newService = True
110
111         def __evUpdatedInfo(self):
112                 if self.newService:
113                         print "[AutoRes] service changed"
114                         self.after_switch_delay = False
115                         self.timer.start(int(config.plugins.autoresolution.delay_switch_mode.value))
116                         self.newService = False
117
118         def defaultModeChanged(self, configEntry):
119                 global preferedmodes
120                 global port
121                 global default
122                 global usable
123                 port_changed = configEntry == config.av.videoport
124                 if port_changed:
125                         print "port changed to", configEntry.value
126                         if port:
127                                 config.av.videomode[port].removeNotifier(self.defaultModeChanged)
128                         port = config.av.videoport.value
129                         if port in config.av.videomode:
130                                 config.av.videomode[port].addNotifier(self.defaultModeChanged)
131                         usable = config.plugins.autoresolution.enable.value and not port in ('DVI-PC', 'Scart')
132                 else: # videomode changed in normal av setup
133                         global videoresolution_dictionary
134                         print "mode changed to", configEntry.value
135                         default = (configEntry.value, _("default"))
136                         preferedmodes = [mode[0] for mode in video_hw.getModeList(port) if mode[0] != default[0]]
137                         preferedmodes.append(default)
138                         print "default", default
139                         print "preferedmodes", preferedmodes
140                         videoresolution_dictionary = {}
141                         config.plugins.autoresolution.videoresolution = ConfigSubDict()
142                         have_2160p = config.av.videorate.get("2160p", False)
143                         for mode in resolutions:
144                                 if have_2160p:
145                                         if mode[0].startswith('p2160'):
146                                                 choices = ['2160p24', '2160p25', '2160p30', '1080p24', '1080p25', '1080p30'] + preferedmodes
147                                         elif mode[0].startswith('p1080_24'):
148                                                 choices = ['1080p24', '2160p24'] + preferedmodes
149                                         elif mode[0].startswith('p1080'):
150                                                 choices = ['1080p24', '1080p25', '1080p30'] + preferedmodes
151                                         elif mode[0] == 'p720_24':
152                                                 choices = ['720p24', '1080p24', '2160p24'] + preferedmodes
153                                         else:
154                                                 choices = preferedmodes
155                                 else:
156                                         if mode[0].startswith('p1080'):
157                                                 choices = ['1080p24', '1080p25', '1080p30'] + preferedmodes
158                                         elif mode[0] == 'p720_24':
159                                                 choices = ['720p24', '1080p24'] + preferedmodes
160                                         else:
161                                                 choices = preferedmodes
162                                 config.plugins.autoresolution.videoresolution[mode[0]] = ConfigSelection(default = default[0], choices = choices)
163                                 config.plugins.autoresolution.videoresolution[mode[0]].addNotifier(self.modeConfigChanged, initial_call = False, immediate_feedback = False)
164                                 videoresolution_dictionary[mode[0]] = (config.plugins.autoresolution.videoresolution[mode[0]])
165
166         def modeConfigChanged(self, configElement):
167                 self.determineContent()
168
169         def enableChanged(self, configElement):
170                 global usable
171                 if configElement.value:
172                         usable = not port in ('DVI-PC', 'Scart')
173                         self.determineContent()
174                 else:
175                         usable = False
176                         self.changeVideomode()
177
178         def __evVideoFramerateChanged(self):
179                 print "[AutoRes] got event evFramerateChanged"
180                 if not self.timer.isActive() or self.after_switch_delay:
181                         self.timer.start(100) # give other pending events a chance..
182
183         def __evVideoSizeChanged(self):
184                 print "[AutoRes] got event evVideoSizeChanged"
185                 if not self.timer.isActive() or self.after_switch_delay:
186                         self.timer.start(100) # give other pending events a chance..
187
188         def __evVideoProgressiveChanged(self):
189                 print "[AutoRes] got event evVideoProgressiveChanged"
190                 if not self.timer.isActive() or self.after_switch_delay:
191                         self.timer.start(100) # give other pending events a chance..
192
193         def determineContent(self):
194                 print "[AutoRes] determineContent"
195                 self.timer.stop()
196                 self.after_switch_delay = True
197                 if usable:
198                         service = self.session.nav.getCurrentService()
199                         info = service and service.info()
200                         height = info and info.getInfo(iServiceInformation.sVideoHeight)
201                         width = info and info.getInfo(iServiceInformation.sVideoWidth)
202                         framerate = info and info.getInfo(iServiceInformation.sFrameRate)
203                         if height != -1 and width != -1 and framerate != -1:
204                                 frate = str(framerate)[:2] #fallback?
205                                 if frqdic.has_key(framerate):
206                                         frate = frqdic[framerate]
207                                 progressive = info and info.getInfo(iServiceInformation.sProgressive)
208
209                                 prog = progressive == 1 and 'p' or 'i'
210
211                                 if (height >= 1800 or width >= 3200) and prog == 'p':   # 2160p content
212                                         if frate in ('24', '25', '30') and prog == 'p':
213                                                 new_mode = 'p2160_%s' % frate
214                                         else:
215                                                 new_mode = 'uhd_p'
216                                 elif (height >= 900 or width >= 1600) and frate in ('24', '25', '30') and prog == 'p':  # 1080p content
217                                         new_mode = 'p1080_%s' % frate
218                                 elif (height > 576 or width > 720) and frate == '24' and prog == 'p':           # 720p24 detection
219                                         new_mode = 'p720_24'
220                                 elif (height <= 576) and (width <= 720) and frate in ('25', '50'):
221                                         new_mode = 'sd_%s_50' % prog
222                                 elif (height <= 480) and (width <= 720) and frate in ('24', '30', '60'):
223                                         new_mode = 'sd_%s_60' % prog
224                                 else:
225                                         new_mode = 'hd_%s' % prog
226
227                                 if progressive == 1:
228                                         setDeinterlacer(config.plugins.autoresolution.deinterlacer_progressive.value)
229                                 else:
230                                         setDeinterlacer(config.plugins.autoresolution.deinterlacer.value)
231
232                                 print "[AutoRes] new content is %sx%s%s%s" %(width, height, prog, frate)
233
234                                 if videoresolution_dictionary.has_key(new_mode):
235                                         new_mode = videoresolution_dictionary[new_mode].value
236                                         print '[AutoRes] determined videomode', new_mode
237                                         old = resolutionlabel["content"].getText()
238                                         resolutionlabel["content"].setText("Videocontent: %sx%s%s %sHZ" % (width, height, prog, frate))
239                                         if self.lastmode != new_mode:
240                                                 self.lastmode = new_mode
241                                                 self.changeVideomode()
242                                         elif old != resolutionlabel["content"].getText() and config.plugins.autoresolution.showinfo.value:
243                                                 resolutionlabel.show()
244
245         def changeVideomode(self):
246                 if usable:
247                         mode = self.lastmode
248                         if mode.find("0p30") != -1 or mode.find("0p24") != -1 or mode.find("0p25") != -1:
249                                 print "[AutoRes] switching to", mode
250                                 v = open('/proc/stb/video/videomode' , "w")
251                                 v.write("%s\n" % mode)
252                                 v.close()
253                                 resolutionlabel["restxt"].setText("Videomode: %s" % mode)
254                                 if config.plugins.autoresolution.showinfo.value:
255                                         resolutionlabel.show()
256                         else:
257                                 self.setMode(mode)
258                         if config.plugins.autoresolution.testmode.value and default[0] != mode:
259                                 resolutionlabeltxt = "Videomode: %s" % mode
260                                 self.session.openWithCallback(
261                                         self.confirm,
262                                         MessageBox,
263                                         _("Autoresolution Plugin Testmode:\nIs %s OK?") % (resolutionlabeltxt),
264                                         MessageBox.TYPE_YESNO,
265                                         timeout = 15,
266                                         default = False
267                                 )
268                 else:
269                         setDeinterlacer("auto")
270                         if self.lastmode != default[0]:
271                                 self.setMode(default[0])
272
273         def confirm(self, confirmed):
274                 if not confirmed:
275                         self.setMode(default[0])
276
277         def setMode(self, mode, set=True):
278                 rate = config.av.videorate[mode].value
279                 port_txt = "HDMI" if port == "DVI" else port
280                 resolutionlabel["restxt"].setText("Videomode: %s %s %s" % (port_txt, mode, rate))
281                 if set:
282                         print "[AutoRes] switching to %s %s %s" % (port_txt, mode, rate)
283                         if config.plugins.autoresolution.showinfo.value:
284                                 resolutionlabel.show()
285                         video_hw.setMode(port, mode, rate)
286                 self.lastmode = mode
287
288 class ResolutionLabel(Screen):
289         height = getDesktop(0).size().height()
290         if height == 2160:
291                 skin = """
292                         <screen position="150,120" size="750,108" flags="wfNoBorder">
293                                 <widget name="content" position="0,0" size="750,54" font="Regular;48" />
294                                 <widget name="restxt" position="0,54" size="750,54" font="Regular;48" />
295                         </screen>"""
296         elif height == 1080:
297                 skin = """
298                         <screen position="75,60" size="375,54" flags="wfNoBorder">
299                                 <widget name="content" position="0,0" size="375,27" font="Regular;24" />
300                                 <widget name="restxt" position="0,27" size="375,27" font="Regular;24" />
301                         </screen>"""
302         else:
303                 skin = """
304                         <screen position="50,40" size="250,36" flags="wfNoBorder">
305                                 <widget name="content" position="0,0" size="250,18" font="Regular;16" />
306                                 <widget name="restxt" position="0,18" size="250,18" font="Regular;16" />
307                         </screen>"""
308
309         def __init__(self, session):
310                 Screen.__init__(self, session)
311
312                 self["content"] = Label()
313                 self["restxt"] = Label()
314
315                 self.hideTimer = eTimer()
316                 self.hideTimer_conn = self.hideTimer.timeout.connect(self.hide)
317
318                 self.onShow.append(self.hide_me)
319
320         def hide_me(self):
321                 self.hideTimer.start(config.usage.infobar_timeout.index * 1500, True)
322
323
324 class AutoResSetupMenu(Screen, ConfigListScreen):
325         def __init__(self, session):
326                 Screen.__init__(self, session)
327                 self.skinName = [ "AutoResSetupMenu", "Setup" ]
328                 self.setup_title = _("Autoresolution videomode setup")
329
330                 self.onChangedEntry = [ ]
331                 self.list = [ ]
332                 ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changedEntry)
333
334                 self["actions"] = ActionMap(["SetupActions"],
335                         {
336                                 "cancel": self.keyCancel,
337                                 "save": self.apply,
338                         }, -2)
339
340                 self["key_green"] = StaticText(_("OK"))
341                 self["key_red"] = StaticText(_("Cancel"))
342
343                 self.createSetup()
344                 self.onLayoutFinish.append(self.layoutFinished)
345
346         def layoutFinished(self):
347                 self.setTitle(_("Autoresolution settings"))
348
349         def createSetup(self):
350                 self.list = [ getConfigListEntry(_("Enable Autoresolution"), config.plugins.autoresolution.enable) ]
351                 if config.plugins.autoresolution.enable.value:
352                         if usable:
353                                 have_1080p = config.av.videorate.get("1080p", False)
354                                 have_2160p = config.av.videorate.get("2160p", False)
355                                 for mode, label in resolutions:
356                                         if not mode.startswith("2160p") or have_2160p:
357                                                 self.list.append(getConfigListEntry(label, videoresolution_dictionary[mode]))
358                                 self.list.extend((
359                                         getConfigListEntry(_("Refresh Rate")+" 720p", config.av.videorate["720p"]),
360                                         getConfigListEntry(_("Refresh Rate")+" 1080i", config.av.videorate["1080i"])
361                                 ))
362                                 if have_1080p:
363                                         self.list.append(getConfigListEntry(_("Refresh Rate")+" 1080p", config.av.videorate["1080p"]))
364                                 if have_2160p:
365                                         self.list.append(getConfigListEntry(_("Refresh Rate")+" 2160p", config.av.videorate["2160p"]))
366                                 self.list.extend((
367                                         getConfigListEntry(_("Show info screen"), config.plugins.autoresolution.showinfo),
368                                         getConfigListEntry(_("Delay x seconds after service started"), config.plugins.autoresolution.delay_switch_mode),
369                                         getConfigListEntry(_("Running in testmode"), config.plugins.autoresolution.testmode),
370                                         getConfigListEntry(_("Deinterlacer mode for interlaced content"), config.plugins.autoresolution.deinterlacer),
371                                         getConfigListEntry(_("Deinterlacer mode for progressive content"), config.plugins.autoresolution.deinterlacer_progressive)
372                                 ))
373                         else:
374                                 self.list.append(getConfigListEntry(_("Autoresolution is not working in Scart/DVI-PC Mode"), ConfigNothing()))
375
376                 self["config"].list = self.list
377                 self["config"].setList(self.list)
378
379         def apply(self):
380                 for x in self["config"].list:
381                         x[1].save()
382                 self.close()
383
384         def keyLeft(self):
385                 ConfigListScreen.keyLeft(self)
386                 if self["config"].getCurrent()[1] == config.plugins.autoresolution.enable:
387                         self.createSetup()
388
389         def keyRight(self):
390                 ConfigListScreen.keyRight(self)
391                 if self["config"].getCurrent()[1] == config.plugins.autoresolution.enable:
392                         self.createSetup()
393
394         # for summary:
395         def changedEntry(self):
396                 for x in self.onChangedEntry:
397                         x()
398
399         def getCurrentEntry(self):
400                 return self["config"].getCurrent()[0]
401
402         def getCurrentValue(self):
403                 return str(self["config"].getCurrent()[1].getText())
404
405         def createSummary(self):
406                 return SetupSummary
407
408 def autostart(reason, **kwargs):
409         if "session" in kwargs and resolutionlabel is None:
410                 global resolutionlabel
411                 session = kwargs["session"]
412                 resolutionlabel = session.instantiateDialog(ResolutionLabel)
413                 AutoRes(session)
414
415 def startSetup(menuid):
416         if menuid != "osd_video_audio":
417                 return [ ]
418         return [(_("Autoresolution"), autoresSetup, "autores_setup", 45)]
419
420 def autoresSetup(session, **kwargs):
421         autostart(reason=0, session=session)
422         session.open(AutoResSetupMenu)
423
424 def Plugins(path, **kwargs):
425         return [PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART], fnc = autostart), \
426                 PluginDescriptor(name="Autoresolution", description=_("Autoresolution Switch"), where = PluginDescriptor.WHERE_MENU, fnc=startSetup) ]