802c0b6151c18a1eca7b9d05da2fdee05eed41cd
[vuplus_dvbapp] / lib / python / Plugins / SystemPlugins / Videomode / VideoHardware.py
1 from Components.config import config, ConfigSubDict, ConfigSelection
2 from Tools.CList import CList
3 from Tools.HardwareInfo import HardwareInfo
4
5 # VideoHardware is the interface to /proc/stb/video.
6 class VideoHardware:
7         is_init = True
8
9         modes = { # a list of modes for available port
10                 "Scart" : ["PAL", "NTSC", "Multi"],
11                 "YPbPr" : ["720p", "1080i", "576p", "480p", "576i", "480i"],
12                 "DVI"   : ["720p", "1080i", "576p", "480p", "576i", "480i"],
13                 "DVI-PC": ["PC"]
14         }
15         rates = { # list of rates for available mode
16                 "PAL":   { "50Hz" : {50: "pal"},
17                                    "60Hz" : {60: "pal60"},
18                                    "multi": {50: "pal", 60: "pal60"}
19                 },
20                 "NTSC":  { "60Hz" : {60: "ntsc"} },
21                 "Multi": { "multi": {50: "pal", 60: "ntsc"} },
22                 "480i":  { "60Hz" : {60: "480i"} },
23                 "576i":  { "50Hz" : {50: "576i"} },
24                 "480p":  { "60Hz" : {60: "480p"} },
25                 "576p":  { "50Hz" : {50: "576p"} },
26                 "720p":  {
27                         "50Hz" : {50: "720p50"},
28                         "60Hz" : {60: "720p"},
29                         "multi": {50: "720p50", 60: "720p"}
30                 },
31                 "1080i": {
32                         "50Hz" : {50: "1080i50"},
33                         "60Hz" : {60: "1080i"},
34                         "multi": {50: "1080i50", 60: "1080i"}
35                 },
36                 "1080p": {
37                         "50Hz" : {50: "1080p50"},
38                         "60Hz" : {60: "1080p"},
39                         "multi": {50: "1080p50", 60: "1080p"}
40                 },
41                 "2160p": {
42                         "50Hz" : {50: "2160p50"},
43                         "60Hz" : {60: "2160p"},
44                         "multi": {50: "2160p50", 60: "2160p"}
45                 },
46                 "PC": {
47                         "1024x768": {60: "1024x768"},
48                         "800x600" : {60: "800x600"},
49                         "720x480" : {60: "720x480"},
50                         "720x576" : {60: "720x576"},
51                         "1280x720": {60: "1280x720"},
52                         "1280x720 multi": {50: "1280x720_50", 60: "1280x720"},
53                         "1920x1080": {60: "1920x1080"},
54                         "1920x1080 multi": {50: "1920x1080", 60: "1920x1080_50"},
55                         "1280x1024": {60: "1280x1024"},
56                         "1366x768": {60: "1366x768"},
57                         "1366x768 multi": {50: "1366x768", 60: "1366x768_50"},
58                         "1280x768": {60: "1280x768"},
59                         "640x480" : {60: "640x480"}
60                 }
61         }
62
63         widescreen_modes = set(["720p", "1080i", "1080p", "2160p"])
64         hdmi_hw_types = set(["dm500", "dm800se", "dm7020hd", "bm750", "solo", "uno", "ultimo", "solo2", "duo2", "solose", "zero", "solo4k"])
65         hdmi_pc_hw_types = set(["dm500", "dm800se", "dm7020hd", "bm750", "solo", "uno", "ultimo", "solo2", "duo2", "solose", "zero", "solo4k"])
66         noscart_hw_types = set(["zero", "solo4k"])
67         noypbpr_hw_types = set(["solose", "zero", "solo4k"])
68
69         def getDeviceName(self):
70                 device_name = "unknown"
71                 try:
72                         file = open("/proc/stb/info/vumodel", "r")
73                         device_name = file.readline().strip()
74                         file.close()
75                 except IOError:
76                         from Tools.HardwareInfo import HardwareInfo
77                         device_name = HardwareInfo.get_device_name()
78
79                 return device_name
80
81         def isVumodel(self, hw_type):
82                 return hw_type in set(["bm750", "solo", "uno", "ultimo", "solo2", "duo2", "solose", "zero", "solo4k"])
83
84         def isVumodel4K(self, hw_type):
85                 return hw_type in set(["solo4k"])
86
87         # re-define AVSwitch.getOutputAspect
88         def getOutputAspect(self):
89                 ret = (16,9)
90                 port = config.av.videoport.value
91                 if port not in config.av.videomode:
92                         print "current port is not available. force 16:9"
93                 else:
94                         mode = config.av.videomode[port].value
95                         force_wide = self.isWidescreenMode(mode)
96                         valstr = config.av.aspect.value
97
98                         if force_wide:
99                                 pass
100                         elif valstr == "16_10":
101                                 ret = (16,10)
102                         elif valstr == "auto":
103                                 try:
104                                         aspect_str = open("/proc/stb/vmpeg/0/aspect", "r").read()
105                                         if aspect_str == "1": # 4:3
106                                                 ret = (4,3)
107                                 except IOError:
108                                         pass
109                         elif valstr == "4_3":
110                                 ret = (4,3)
111                 return ret
112
113         def __init__(self):
114                 self.last_modes_preferred = [ ]
115                 self.on_hotplug = CList()
116
117                 self.readAvailableModes()
118
119                 if self.modes.has_key("DVI-PC") and not self.getModeList("DVI-PC"):
120                         print "remove DVI-PC because it does not exist."
121                         del self.modes["DVI-PC"]
122
123                 if self.isNoScart(self.getDeviceName()):
124                         if self.modes.has_key("Scart"):
125                                 print "remove Scart because it does not exist."
126                                 del self.modes["Scart"]
127
128                 if self.isNoYPbPr(self.getDeviceName()):
129                         if self.modes.has_key("YPbPr"):
130                                 print "remove YPbPr because it does not exist."
131                                 del self.modes["YPbPr"]
132
133                 self.createConfig()
134
135                 self.readPreferredModes()
136
137                 # re-define AVSwitch components
138                 from Components.AVSwitch import AVSwitch
139                 config.av.aspectratio.notifiers = [ ]
140                 config.av.tvsystem.notifiers = [ ]
141                 config.av.wss.notifiers = [ ]
142                 AVSwitch.getOutputAspect = self.getOutputAspect
143
144                 config.av.aspect.addNotifier(self.changedAspect)
145                 config.av.wss.addNotifier(self.changedAspect)
146                 config.av.policy_169.addNotifier(self.changedAspect)
147                 config.av.policy_43.addNotifier(self.changedAspect)
148
149                 # addNotifiers for port, mode, rate
150                 config.av.videoport.addNotifier(self.changedVideomode)
151                 for port in self.getPortList():
152                         config.av.videomode[port].addNotifier(self.changedVideomode)
153                         for mode in self.getModeList(port):
154                                 config.av.videorate[mode[0]].addNotifier(self.changedVideomode)
155
156                 self.is_init = False
157
158         def readAvailableModes(self):
159                 try:
160                         modes = open("/proc/stb/video/videomode_choices").read()[:-1]
161                         self.modes_available = modes.split(' ')
162                 except IOError:
163                         print "failed to read video_choices."
164                         self.modes_available = [ ]
165
166         def readPreferredModes(self):
167                 try:
168                         modes = open("/proc/stb/video/videomode_preferred").read()[:-1]
169                         self.modes_preferred = modes.split(' ')
170                 except IOError:
171                         print "failed to read video_preferred."
172                         self.modes_preferred = self.modes_available
173
174                 if self.modes_preferred != self.last_modes_preferred:
175                         self.last_modes_preferred = self.modes_preferred
176                         print "hotplug on DVI"
177                         self.on_hotplug("DVI") # must be DVI
178
179         # check if HDMI is available
180         def isHDMIAvailable(self, hw_type):
181                 return hw_type in self.hdmi_hw_types
182
183         # check if HDMI-PC is available
184         def isHDMI_PCAvailable(self, hw_type):
185                 return hw_type in self.hdmi_pc_hw_types
186
187         # check if mode is always widescreen
188         def isWidescreenMode(self, mode):
189                 return mode in self.widescreen_modes
190
191         # check if Scart is not available
192         def isNoScart(self, hw_type):
193                 return hw_type in self.noscart_hw_types
194
195         # check if YPbPr is not available
196         def isNoYPbPr(self, hw_type):
197                 return hw_type in self.noypbpr_hw_types
198
199         # check if rate is available for mode
200         def isModeAvailable(self, port, mode, rate):
201                 rate = self.rates[mode][rate]
202                 for mode in rate.values():
203                         if mode not in self.modes_available:
204                                 return False
205
206                 return True
207
208         # check isModeAvailable in this port
209         def isPortAvailable(self, port):
210                 for mode in self.getModeList(port):
211                         if len(self.getRateList(port, mode[0])):
212                                 return True
213
214                 return False
215
216         # get a list of all available port
217         def getPortList(self):
218                 return [port for port in self.modes if self.isPortAvailable(port)]
219
220         # get a list of all available mode for a given port
221         def getModeList(self, port):
222                 modelist = [ ]
223                 for mode in self.modes[port]:
224                         rates = self.getRateList(port, mode)
225
226                         if len(rates):
227                                 modelist.append( (mode, rates))
228
229                 return modelist
230
231         # get a list of all available rate for a given port, mode
232         def getRateList(self, port, mode):
233                 return [rate for rate in self.rates[mode] if self.isModeAvailable(port, mode, rate)]
234
235         def createConfig(self):
236                 config.av.videomode = ConfigSubDict()
237                 config.av.videorate = ConfigSubDict()
238
239                 hw_type = self.getDeviceName()
240                 # vu+ support 1080p
241                 if self.isVumodel(hw_type):
242                         self.modes["DVI"].insert(self.modes["DVI"].index("1080i")+1, "1080p")
243                         # 4K support 2160p
244                         if self.isVumodel4K(hw_type):
245                                 self.modes["DVI"].insert(self.modes["DVI"].index("1080p")+1, "2160p")
246
247                 portlist = [ ]
248                 port_choices = self.getPortList()
249
250                 for port in port_choices:
251                         desc = port
252                         if desc == 'DVI' and self.isHDMIAvailable(hw_type):
253                                 desc = 'HDMI'
254                         if desc == 'DVI-PC' and self.isHDMI_PCAvailable(hw_type):
255                                 desc = 'HDMI-PC'
256                         portlist.append( (port, desc))
257
258                         # create list of available modes
259                         modelist = [ ]
260                         mode_choices = self.getModeList(port)
261
262                         for mode in mode_choices:
263                                 modelist.append( (mode[0], mode[0]))
264
265                                 # create list of available rates
266                                 ratelist = [ ]
267                                 rate_choices = self.getRateList(port, mode[0])
268
269                                 for rate in rate_choices:
270                                         ratelist.append( (rate, rate))
271
272                                 config.av.videorate[mode[0]] = ConfigSelection(choices = ratelist)
273                         config.av.videomode[port] = ConfigSelection(choices = modelist)
274                 config.av.videoport = ConfigSelection(choices = portlist)
275
276         def changedVideomode(self, configElement):
277                 if self.is_init:
278                         return
279
280                 self.setConfiguredMode()
281
282         def setConfiguredMode(self):
283                 port = config.av.videoport.value
284                 mode = config.av.videomode[port].value
285                 rate = config.av.videorate[mode].value
286
287                 self.setVideomode(port, mode, rate)
288
289         def setVideomode(self, port, mode, rate):
290                 if port is None or port not in config.av.videomode:
291                         print "current port not available. couldn't set videomode"
292                         return
293
294                 if mode not in config.av.videorate:
295                         print "current mode not available. couldn't set videomode"
296                         return
297
298                 if mode is None:
299                         modelist = self.getModeList(port)
300                         mode = modelist[0][0]
301
302                         ratelist = self.getRateList(port, mode)
303                         rate = ratelist[0]
304
305                 if rate is None:
306                         ratelist = self.getRateList(port, mode)
307                         rate = ratelist[0]
308
309                 print "set Videomode", port, mode, rate
310
311                 modes = self.rates[mode][rate]
312                 mode_50 = modes.get(50)
313                 mode_60 = modes.get(60)
314                 if mode_50 is None:
315                         mode_50 = mode_60
316                 if mode_60 is None:
317                         mode_60 = mode_50
318
319                 if (mode_50 != mode_60):
320                         try:
321                                 open("/proc/stb/video/videomode_50hz", "w").write(mode_50)
322                                 open("/proc/stb/video/videomode_60hz", "w").write(mode_60)
323                         except IOError:
324                                 print "cannot open /proc/stb/vide/videomode_50hz or videomode_60hz"
325
326                         # Too slow moving to Scart/multi in modeSelectionMoved
327                         #try:
328                         #       open("/proc/stb/video/videomode_50hz", "w").write(mode_60)
329                         #except IOError:
330                         #       print "cannot open /proc/stb/vide/videomode_60Hz"
331
332                 else:
333                         try:
334                                 open("/proc/stb/video/videomode", "w").write(mode_50)
335                         except IOError:
336                                 print "cannot open /proc/stb/vide/videomode"
337
338                 self.changedAspect(None)
339
340         def changedAspect(self, configElement):
341                 if self.is_init:
342                         return
343                 # config.av.aspect:
344                 #       4:3                     use policy_169
345                 #       16:9, 16:10     use policy_43
346                 #       auto            always "bestfit"
347                 # config.av.policy_169:
348                 #       letterbox       use letterbox
349                 #       panscan         use panscan
350                 #       scale           use bestfit
351                 # config.av.policy_43:
352                 #       pillarbox       use panscan
353                 #       pansca          use letterbox ("panscan" is just a bad term, it is inverse-panscan)
354                 #       nonlinear       use nonlinear
355                 #       scale           use bestfit
356
357                 port = config.av.videoport.value
358                 if port not in config.av.videomode:
359                         print "current port not available. couldn't set aspect"
360                         return
361
362                 mode = config.av.videomode[port].value
363                 force_wide = self.isWidescreenMode(mode)
364                 valstr = config.av.aspect.value
365
366                 policy2 = "policy" # use main policy
367
368                 if force_wide or valstr == "16_9" or valstr == "16_10":
369                         if force_wide or valstr == "16_9":
370                                 aspect = "16:9"
371                         elif valstr == "16_10":
372                                 aspect = "16:10"
373
374                         policy = {"pillarbox": "panscan", "panscan": "letterbox", "nonlinear": "nonlinear", "scale": "bestfit"}[config.av.policy_43.value]
375                         policy2 = {"letterbox": "letterbox", "panscan": "panscan", "scale": "bestfit"}[config.av.policy_169.value]
376                 elif valstr == "auto":
377                         aspect = "any"
378                         policy = "bestfit"
379                 else:
380                         aspect = "4:3"
381                         policy = {"letterbox": "letterbox", "panscan": "panscan", "scale": "bestfit"}[config.av.policy_169.value]
382
383                 if not config.av.wss.value:
384                         wss = "auto(4:3_off)"
385                 else:
386                         wss = "auto"
387
388                 self.setAspect(aspect, policy, policy2, wss)
389
390         def setAspect(self, aspect, policy, policy2, wss):
391                 print "set aspect, policy, policy2, wss", aspect, policy, policy2, wss
392
393                 open("/proc/stb/video/aspect", "w").write(aspect)
394                 open("/proc/stb/video/policy", "w").write(policy)
395                 open("/proc/stb/denc/0/wss", "w").write(wss)
396                 try:
397                         open("/proc/stb/video/policy2", "w").write(policy2)
398                 except IOError:
399                         pass
400
401         def isPortUsed(self, port):
402                 if port == "DVI":
403                         self.readPreferredModes()
404                         return len(self.modes_preferred) != 0
405                 else:
406                         return True
407
408         def saveVideomode(self, port, mode, rate):
409                 print "save Videomode", port, mode, rate
410                 config.av.videoport.value = port
411                 config.av.videoport.save()
412                 if port in config.av.videomode:
413                         config.av.videomode[port].value = mode
414                         config.av.videomode[port].save()
415                 if mode in config.av.videorate:
416                         config.av.videorate[mode].value = rate
417                         config.av.videorate[mode].save()
418
419         # for dependency
420         def setMode(self, port, mode, rate):
421                 self.setVideomode(port, mode, rate)
422
423         def saveMode(self, port, mode, rate):
424                 self.saveVideomode(port, mode, rate)
425
426         def updateAspect(self, configElement):
427                 self.changedAspect(configElement)
428
429 video_hw = VideoHardware()
430 video_hw.setConfiguredMode()
431