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