Don't set fastblank to high if the currently selected port (vs. the to-be-selected...
[vuplus_dvbapp] / lib / python / Plugins / SystemPlugins / Videomode / VideoHardware.py
1 from Screens.Screen import Screen
2 from Plugins.Plugin import PluginDescriptor
3
4 from enigma import eTimer
5
6 from Components.ActionMap import ActionMap
7 from Components.Label import Label
8 from Components.Pixmap import Pixmap
9 from Screens.MessageBox import MessageBox
10 from Screens.Setup import SetupSummary
11 from Components.ConfigList import ConfigListScreen
12 from Components.config import getConfigListEntry, config, ConfigSelection, ConfigSubDict, ConfigYesNo
13
14 from Tools.CList import CList
15
16 # The "VideoHardware" is the interface to /proc/stb/video.
17 # It generates hotplug events, and gives you the list of 
18 # available and preferred modes, as well as handling the currently
19 # selected mode. No other strict checking is done.
20 class VideoHardware:
21         rates = { } # high-level, use selectable modes.
22
23         modes = { }  # a list of (high-level) modes for a certain port.
24
25         rates["PAL"] =                  { "50Hz":               { 50: "pal", 60: "pal"},
26                                                                                                 "60Hz":         { 50: "pal60", 60: "pal60"},
27                                                                                                 "multi":        { 50: "pal", 60: "pal60"} }
28         rates["NTSC"] =                 { "60Hz":       { 50: "ntsc", 60: "ntsc"} }
29         rates["Multi"] =                { "multi":      { 50: "pal", 60: "ntsc"} }
30         rates["720p"] =                 {       "50Hz":         { 50: "720p50", 60: "720p50"},
31                                                                                                 "60Hz":         { 50: "720p", 60: "720p"},
32                                                                                                 "multi":        { 50: "720p50", 60: "720p"} }
33         rates["1080i"] =                { "50Hz":               { 50: "1080i50", 60: "1080i50"},
34                                                                                                 "60Hz":         { 50: "1080i", 60: "1080i"},
35                                                                                                 "multi":        { 50: "1080i50", 60: "1080i"} }
36         rates["PC"] = { 
37                 "1024x768": { 60: "1024x768"}, # not possible on DM7025
38                 "800x600" : { 60: "800x600"},  # also not possible
39                 "720x480" : { 60: "720x480"},
40                 "720x576" : { 60: "720x576"},
41                 "1280x720": { 60: "1280x720"},
42                 "1280x720 multi": { 50: "1280x720_50", 60: "1280x720"},
43                 "1920x1080": { 60: "1920x1080"},
44                 "1920x1080 multi": { 50: "1920x1080", 60: "1920x1080_50"},
45                 "1280x1024" : { 60: "1280x1024"},
46                 "1366x768" : { 60: "1366x768"},
47                 "1366x768 multi" : { 50: "1366x768", 60: "1366x768_50"},
48                 "1280x768": { 60: "1280x768"},
49                 "640x480" : { 60: "640x480"} 
50         }
51
52         modes["Scart"] = ["PAL", "NTSC", "Multi"]
53         modes["YPbPr"] = ["720p", "1080i"]
54         modes["DVI"] = ["720p", "1080i", "PC"]
55
56         widescreen_modes = set(["720p", "1080i"])
57
58         def __init__(self):
59                 self.last_modes_preferred =  [ ]
60                 self.on_hotplug = CList()
61                 self.standby = False
62                 self.current_mode = None
63                 self.current_port = None
64
65                 self.readAvailableModes()
66
67                 self.createConfig()
68 #               self.on_hotplug.append(self.createConfig)
69
70                 self.readPreferredModes()
71
72                 # take over old AVSwitch component :)
73                 from Components.AVSwitch import AVSwitch
74 #               config.av.colorformat.notifiers = [ ] 
75                 config.av.aspectratio.notifiers = [ ]
76                 config.av.tvsystem.notifiers = [ ]
77                 config.av.wss.notifiers = [ ]
78                 AVSwitch.setInput = self.AVSwitchSetInput
79
80                 config.av.aspect.addNotifier(self.updateAspect)
81                 config.av.wss.addNotifier(self.updateAspect)
82                 config.av.policy_169.addNotifier(self.updateAspect)
83                 config.av.policy_43.addNotifier(self.updateAspect)
84
85                 # until we have the hotplug poll socket
86 #               self.timer = eTimer()
87 #               self.timer.callback.append(self.readPreferredModes)
88 #               self.timer.start(1000)
89
90                 config.av.colorformat.addNotifier(self.updateFastblank) 
91
92         def AVSwitchSetInput(self, mode):
93                 self.standby = mode == "SCART"
94                 self.updateStandby()
95
96         def readAvailableModes(self):
97                 try:
98                         modes = open("/proc/stb/video/videomode_choices").read()[:-1]
99                 except IOError:
100                         print "couldn't read available videomodes."
101                         self.modes_available = [ ]
102                         return
103                 self.modes_available = modes.split(' ')
104
105         def readPreferredModes(self):
106                 try:
107                         modes = open("/proc/stb/video/videomode_preferred").read()[:-1]
108                         self.modes_preferred = modes.split(' ')
109                 except IOError:
110                         print "reading preferred modes failed, using all modes"
111                         self.modes_preferred = self.modes_available
112
113                 if self.modes_preferred != self.last_modes_preferred:
114                         self.last_modes_preferred = self.modes_preferred
115                         print "hotplug on dvi"
116                         self.on_hotplug("DVI") # must be DVI
117
118         # check if a high-level mode with a given rate is available.
119         def isModeAvailable(self, port, mode, rate):
120                 rate = self.rates[mode][rate]
121                 for mode in rate.values():
122                         # DVI modes must be in "modes_preferred"
123 #                       if port == "DVI":
124 #                               if mode not in self.modes_preferred and not config.av.edid_override.value:
125 #                                       print "no, not preferred"
126 #                                       return False
127                         if mode not in self.modes_available:
128                                 return False
129                 return True
130
131         def isWidescreenMode(self, port, mode):
132                 return mode in self.widescreen_modes
133
134         def setMode(self, port, mode, rate, force = None):
135                 print "setMode - port:", port, "mode:", mode, "rate:", rate
136                 # we can ignore "port"
137                 self.current_mode = mode
138                 self.current_port = port
139                 modes = self.rates[mode][rate]
140
141                 mode_50 = modes.get(50)
142                 mode_60 = modes.get(60)
143                 if mode_50 is None or force == 60:
144                         mode_50 = mode_60
145                 if mode_60 is None or force == 50: 
146                         mode_60 = mode_50
147
148                 try:
149                         open("/proc/stb/video/videomode_50hz", "w").write(mode_50)
150                         open("/proc/stb/video/videomode_60hz", "w").write(mode_60)
151                 except IOError:
152                         try:
153                                 # fallback if no possibility to setup 50/60 hz mode
154                                 open("/proc/stb/video/videomode", "w").write(mode_50)
155                         except IOError:
156                                 print "setting videomode failed."
157
158                 try:
159                         open("/etc/videomode", "w").write(mode_50) # use 50Hz mode (if available) for booting
160                 except IOError:
161                         print "writing initial videomode to /etc/videomode failed."
162
163                 self.updateAspect(None)
164
165         def saveMode(self, port, mode, rate):
166                 config.av.videoport.value = port
167                 config.av.videomode[port].value = mode
168                 config.av.videorate[mode].value = rate
169
170         def isPortAvailable(self, port):
171                 # fixme
172                 return True
173
174         def isPortUsed(self, port):
175                 if port == "DVI":
176                         self.readPreferredModes()
177                         return len(self.modes_preferred) != 0
178                 else:
179                         return True
180
181         def getPortList(self):
182                 return [port for port in self.modes if self.isPortAvailable(port)]
183
184         # get a list with all modes, with all rates, for a given port.
185         def getModeList(self, port):
186                 print "getModeList for port", port
187                 res = [ ]
188                 for mode in self.modes[port]:
189                         # list all rates which are completely valid
190                         rates = [rate for rate in self.rates[mode] if self.isModeAvailable(port, mode, rate)]
191
192                         # if at least one rate is ok, add this mode
193                         if len(rates):
194                                 res.append( (mode, rates) )
195                 return res
196
197         def createConfig(self, *args):
198                 # create list of output ports
199                 portlist = self.getPortList()
200
201                 # create list of available modes
202                 config.av.videoport = ConfigSelection(choices = [(port, _(port)) for port in portlist])
203                 config.av.videomode = ConfigSubDict()
204                 config.av.videorate = ConfigSubDict()
205
206                 for port in portlist:
207                         modes = self.getModeList(port)
208                         if len(modes):
209                                 config.av.videomode[port] = ConfigSelection(choices = [mode for (mode, rates) in modes])
210                         for (mode, rates) in modes:
211                                 config.av.videorate[mode] = ConfigSelection(choices = rates)
212
213         def setConfiguredMode(self):
214                 port = config.av.videoport.value
215                 if port not in config.av.videomode:
216                         print "current port not available, not setting videomode"
217                         return
218
219                 mode = config.av.videomode[port].value
220
221                 if mode not in config.av.videorate:
222                         print "current mode not available, not setting videomode"
223                         return
224
225                 rate = config.av.videorate[mode].value
226                 self.setMode(port, mode, rate)
227
228         def updateAspect(self, cfgelement):
229                 # determine aspect = {any,4:3,16:9,16:10}
230                 # determine policy = {bestfit,letterbox,panscan,nonlinear}
231
232                 # based on;
233                 #   config.av.videoport.value: current video output device
234                 #     Scart: 
235                 #   config.av.aspect:
236                 #     4_3:            use policy_169
237                 #     16_9,16_10:     use policy_43
238                 #     auto            always "bestfit"
239                 #   config.av.policy_169
240                 #     letterbox       use letterbox
241                 #     panscan         use panscan
242                 #     scale           use bestfit
243                 #   config.av.policy_43
244                 #     pillarbox       use panscan
245                 #     panscan         use letterbox  ("panscan" is just a bad term, it's inverse-panscan)
246                 #     nonlinear       use nonlinear
247                 #     scale           use bestfit
248
249                 port = config.av.videoport.value
250                 if port not in config.av.videomode:
251                         print "current port not available, not setting videomode"
252                         return
253                 mode = config.av.videomode[port].value
254
255                 force_widescreen = self.isWidescreenMode(port, mode)
256
257                 is_widescreen = force_widescreen or config.av.aspect.value in ["16_9", "16_10"]
258                 is_auto = config.av.aspect.value == "auto"
259
260                 if is_widescreen:
261                         if force_widescreen:
262                                 aspect = "16:9"
263                         else:
264                                 aspect = {"16_9": "16:9", "16_10": "16:10"}[config.av.aspect.value]
265                         policy = {"pillarbox": "panscan", "panscan": "letterbox", "nonlinear": "nonlinear", "scale": "bestfit"}[config.av.policy_43.value]
266                 elif is_auto:
267                         aspect = "any"
268                         policy = "bestfit"
269                 else:
270                         aspect = "4:3"
271                         policy = {"letterbox": "letterbox", "panscan": "panscan", "scale": "bestfit"}[config.av.policy_169.value]
272
273                 if not config.av.wss.value:
274                         wss = "auto(4:3_off)"
275                 else:
276                         wss = "auto"
277
278                 print "-> setting aspect, policy, wss", aspect, policy, wss
279                 open("/proc/stb/video/aspect", "w").write(aspect)
280                 open("/proc/stb/video/policy", "w").write(policy)
281                 open("/proc/stb/denc/0/wss", "w").write(wss)
282                 self.updateSlowblank()
283                 self.updateFastblank()
284
285         def updateSlowblank(self):
286                 if self.standby:
287                         from Components.SystemInfo import SystemInfo
288                         if SystemInfo["ScartSwitch"]:
289                                 input = "scart"
290                                 sb = "vcr"
291                         else:
292                                 input = "off"
293                                 sb = "0"
294                 else:
295                         input = "encoder"
296                         sb = "auto"
297
298                 open("/proc/stb/avs/0/sb", "w").write(sb)
299                 open("/proc/stb/avs/0/input", "w").write(input)
300
301         def updateStandby(self):
302                 self.updateSlowblank()
303                 self.updateFastblank()
304
305         def updateFastblank(self, *args):
306                 if self.standby:
307                         from Components.SystemInfo import SystemInfo
308                         if SystemInfo["ScartSwitch"]:
309                                 fb = "vcr"
310                         else:
311                                 fb = "low"
312                 else:
313                         if self.current_port == "Scart" and config.av.colorformat.value == "rgb":
314                                 fb = "high"
315                         else:
316                                 fb = "low"
317                 open("/proc/stb/avs/0/fb", "w").write(fb)
318
319 config.av.edid_override = ConfigYesNo(default = False)
320 video_hw = VideoHardware()
321 video_hw.setConfiguredMode()