edid-decode: fix HDMI video/audio latency calculation
[edid-decode.git] / parse-cta-block.cpp
blob2eeed54d8f49f300d2aad64a7fd48aca50b3c14d
1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright 2006-2012 Red Hat, Inc.
4 * Copyright 2018-2020 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 * Author: Adam Jackson <ajax@nwnk.net>
7 * Maintainer: Hans Verkuil <hverkuil-cisco@xs4all.nl>
8 */
10 #include <algorithm>
11 #include <stdio.h>
12 #include <math.h>
14 #include "edid-decode.h"
16 static const struct timings edid_cta_modes1[] = {
17 /* VIC 1 */
18 { 640, 480, 4, 3, 25175, 0, false, 16, 96, 48, false, 10, 2, 33, false },
19 { 720, 480, 4, 3, 27000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
20 { 720, 480, 16, 9, 27000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
21 { 1280, 720, 16, 9, 74250, 0, false, 110, 40, 220, true, 5, 5, 20, true },
22 { 1920, 1080, 16, 9, 74250, 0, true, 88, 44, 148, true, 2, 5, 15, true },
23 { 1440, 480, 4, 3, 27000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
24 { 1440, 480, 16, 9, 27000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
25 { 1440, 240, 4, 3, 27000, 0, false, 38, 124, 114, false, 4, 3, 15, false },
26 { 1440, 240, 16, 9, 27000, 0, false, 38, 124, 114, false, 4, 3, 15, false },
27 { 2880, 480, 4, 3, 54000, 0, true, 76, 248, 228, false, 4, 3, 15, false },
28 /* VIC 11 */
29 { 2880, 480, 16, 9, 54000, 0, true, 76, 248, 228, false, 4, 3, 15, false },
30 { 2880, 240, 4, 3, 54000, 0, false, 76, 248, 228, false, 4, 3, 15, false },
31 { 2880, 240, 16, 9, 54000, 0, false, 76, 248, 228, false, 4, 3, 15, false },
32 { 1440, 480, 4, 3, 54000, 0, false, 32, 124, 120, false, 9, 6, 30, false },
33 { 1440, 480, 16, 9, 54000, 0, false, 32, 124, 120, false, 9, 6, 30, false },
34 { 1920, 1080, 16, 9, 148500, 0, false, 88, 44, 148, true, 4, 5, 36, true },
35 { 720, 576, 4, 3, 27000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
36 { 720, 576, 16, 9, 27000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
37 { 1280, 720, 16, 9, 74250, 0, false, 440, 40, 220, true, 5, 5, 20, true },
38 { 1920, 1080, 16, 9, 74250, 0, true, 528, 44, 148, true, 2, 5, 15, true },
39 /* VIC 21 */
40 { 1440, 576, 4, 3, 27000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
41 { 1440, 576, 16, 9, 27000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
42 { 1440, 288, 4, 3, 27000, 0, false, 24, 126, 138, false, 2, 3, 19, false },
43 { 1440, 288, 16, 9, 27000, 0, false, 24, 126, 138, false, 2, 3, 19, false },
44 { 2880, 576, 4, 3, 54000, 0, true, 48, 252, 276, false, 2, 3, 19, false },
45 { 2880, 576, 16, 9, 54000, 0, true, 48, 252, 276, false, 2, 3, 19, false },
46 { 2880, 288, 4, 3, 54000, 0, false, 48, 252, 276, false, 2, 3, 19, false },
47 { 2880, 288, 16, 9, 54000, 0, false, 48, 252, 276, false, 2, 3, 19, false },
48 { 1440, 576, 4, 3, 54000, 0, false, 24, 128, 136, false, 5, 5, 39, false },
49 { 1440, 576, 16, 9, 54000, 0, false, 24, 128, 136, false, 5, 5, 39, false },
50 /* VIC 31 */
51 { 1920, 1080, 16, 9, 148500, 0, false, 528, 44, 148, true, 4, 5, 36, true },
52 { 1920, 1080, 16, 9, 74250, 0, false, 638, 44, 148, true, 4, 5, 36, true },
53 { 1920, 1080, 16, 9, 74250, 0, false, 528, 44, 148, true, 4, 5, 36, true },
54 { 1920, 1080, 16, 9, 74250, 0, false, 88, 44, 148, true, 4, 5, 36, true },
55 { 2880, 480, 4, 3, 108000, 0, false, 64, 248, 240, false, 9, 6, 30, false },
56 { 2880, 480, 16, 9, 108000, 0, false, 64, 248, 240, false, 9, 6, 30, false },
57 { 2880, 576, 4, 3, 108000, 0, false, 48, 256, 272, false, 5, 5, 39, false },
58 { 2880, 576, 16, 9, 108000, 0, false, 48, 256, 272, false, 5, 5, 39, false },
59 { 1920, 1080, 16, 9, 72000, 0, true, 32, 168, 184, true, 23, 5, 57, false, 0, 0, true },
60 { 1920, 1080, 16, 9, 148500, 0, true, 528, 44, 148, true, 2, 5, 15, true },
61 /* VIC 41 */
62 { 1280, 720, 16, 9, 148500, 0, false, 440, 40, 220, true, 5, 5, 20, true },
63 { 720, 576, 4, 3, 54000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
64 { 720, 576, 16, 9, 54000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
65 { 1440, 576, 4, 3, 54000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
66 { 1440, 576, 16, 9, 54000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
67 { 1920, 1080, 16, 9, 148500, 0, true, 88, 44, 148, true, 2, 5, 15, true },
68 { 1280, 720, 16, 9, 148500, 0, false, 110, 40, 220, true, 5, 5, 20, true },
69 { 720, 480, 4, 3, 54000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
70 { 720, 480, 16, 9, 54000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
71 { 1440, 480, 4, 3, 54000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
72 /* VIC 51 */
73 { 1440, 480, 16, 9, 54000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
74 { 720, 576, 4, 3, 108000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
75 { 720, 576, 16, 9, 108000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
76 { 1440, 576, 4, 3, 108000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
77 { 1440, 576, 16, 9, 108000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
78 { 720, 480, 4, 3, 108000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
79 { 720, 480, 16, 9, 108000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
80 { 1440, 480, 4, 3, 108000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
81 { 1440, 480, 16, 9, 108000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
82 { 1280, 720, 16, 9, 59400, 0, false, 1760, 40, 220, true, 5, 5, 20, true },
83 /* VIC 61 */
84 { 1280, 720, 16, 9, 74250, 0, false, 2420, 40, 220, true, 5, 5, 20, true },
85 { 1280, 720, 16, 9, 74250, 0, false, 1760, 40, 220, true, 5, 5, 20, true },
86 { 1920, 1080, 16, 9, 297000, 0, false, 88, 44, 148, true, 4, 5, 36, true },
87 { 1920, 1080, 16, 9, 297000, 0, false, 528, 44, 148, true, 4, 5, 36, true },
88 { 1280, 720, 64, 27, 59400, 0, false, 1760, 40, 220, true, 5, 5, 20, true },
89 { 1280, 720, 64, 27, 74250, 0, false, 2420, 40, 220, true, 5, 5, 20, true },
90 { 1280, 720, 64, 27, 74250, 0, false, 1760, 40, 220, true, 5, 5, 20, true },
91 { 1280, 720, 64, 27, 74250, 0, false, 440, 40, 220, true, 5, 5, 20, true },
92 { 1280, 720, 64, 27, 74250, 0, false, 110, 40, 220, true, 5, 5, 20, true },
93 { 1280, 720, 64, 27, 148500, 0, false, 440, 40, 220, true, 5, 5, 20, true },
94 /* VIC 71 */
95 { 1280, 720, 64, 27, 148500, 0, false, 110, 40, 220, true, 5, 5, 20, true },
96 { 1920, 1080, 64, 27, 74250, 0, false, 638, 44, 148, true, 4, 5, 36, true },
97 { 1920, 1080, 64, 27, 74250, 0, false, 528, 44, 148, true, 4, 5, 36, true },
98 { 1920, 1080, 64, 27, 74250, 0, false, 88, 44, 148, true, 4, 5, 36, true },
99 { 1920, 1080, 64, 27, 148500, 0, false, 528, 44, 148, true, 4, 5, 36, true },
100 { 1920, 1080, 64, 27, 148500, 0, false, 88, 44, 148, true, 4, 5, 36, true },
101 { 1920, 1080, 64, 27, 297000, 0, false, 528, 44, 148, true, 4, 5, 36, true },
102 { 1920, 1080, 64, 27, 297000, 0, false, 88, 44, 148, true, 4, 5, 36, true },
103 { 1680, 720, 64, 27, 59400, 0, false, 1360, 40, 220, true, 5, 5, 20, true },
104 { 1680, 720, 64, 27, 59400, 0, false, 1228, 40, 220, true, 5, 5, 20, true },
105 /* VIC 81 */
106 { 1680, 720, 64, 27, 59400, 0, false, 700, 40, 220, true, 5, 5, 20, true },
107 { 1680, 720, 64, 27, 82500, 0, false, 260, 40, 220, true, 5, 5, 20, true },
108 { 1680, 720, 64, 27, 99000, 0, false, 260, 40, 220, true, 5, 5, 20, true },
109 { 1680, 720, 64, 27, 165000, 0, false, 60, 40, 220, true, 5, 5, 95, true },
110 { 1680, 720, 64, 27, 198000, 0, false, 60, 40, 220, true, 5, 5, 95, true },
111 { 2560, 1080, 64, 27, 99000, 0, false, 998, 44, 148, true, 4, 5, 11, true },
112 { 2560, 1080, 64, 27, 90000, 0, false, 448, 44, 148, true, 4, 5, 36, true },
113 { 2560, 1080, 64, 27, 118800, 0, false, 768, 44, 148, true, 4, 5, 36, true },
114 { 2560, 1080, 64, 27, 185625, 0, false, 548, 44, 148, true, 4, 5, 36, true },
115 { 2560, 1080, 64, 27, 198000, 0, false, 248, 44, 148, true, 4, 5, 11, true },
116 /* VIC 91 */
117 { 2560, 1080, 64, 27, 371250, 0, false, 218, 44, 148, true, 4, 5, 161, true },
118 { 2560, 1080, 64, 27, 495000, 0, false, 548, 44, 148, true, 4, 5, 161, true },
119 { 3840, 2160, 16, 9, 297000, 0, false, 1276, 88, 296, true, 8, 10, 72, true },
120 { 3840, 2160, 16, 9, 297000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
121 { 3840, 2160, 16, 9, 297000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
122 { 3840, 2160, 16, 9, 594000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
123 { 3840, 2160, 16, 9, 594000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
124 { 4096, 2160, 256, 135, 297000, 0, false, 1020, 88, 296, true, 8, 10, 72, true },
125 { 4096, 2160, 256, 135, 297000, 0, false, 968, 88, 128, true, 8, 10, 72, true },
126 { 4096, 2160, 256, 135, 297000, 0, false, 88, 88, 128, true, 8, 10, 72, true },
127 /* VIC 101 */
128 { 4096, 2160, 256, 135, 594000, 0, false, 968, 88, 128, true, 8, 10, 72, true },
129 { 4096, 2160, 256, 135, 594000, 0, false, 88, 88, 128, true, 8, 10, 72, true },
130 { 3840, 2160, 64, 27, 297000, 0, false, 1276, 88, 296, true, 8, 10, 72, true },
131 { 3840, 2160, 64, 27, 297000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
132 { 3840, 2160, 64, 27, 297000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
133 { 3840, 2160, 64, 27, 594000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
134 { 3840, 2160, 64, 27, 594000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
135 { 1280, 720, 16, 9, 90000, 0, false, 960, 40, 220, true, 5, 5, 20, true },
136 { 1280, 720, 64, 27, 90000, 0, false, 960, 40, 220, true, 5, 5, 20, true },
137 { 1680, 720, 64, 27, 99000, 0, false, 810, 40, 220, true, 5, 5, 20, true },
138 /* VIC 111 */
139 { 1920, 1080, 16, 9, 148500, 0, false, 638, 44, 148, true, 4, 5, 36, true },
140 { 1920, 1080, 64, 27, 148500, 0, false, 638, 44, 148, true, 4, 5, 36, true },
141 { 2560, 1080, 64, 27, 198000, 0, false, 998, 44, 148, true, 4, 5, 11, true },
142 { 3840, 2160, 16, 9, 594000, 0, false, 1276, 88, 296, true, 8, 10, 72, true },
143 { 4096, 2160, 256, 135, 594000, 0, false, 1020, 88, 296, true, 8, 10, 72, true },
144 { 3840, 2160, 64, 27, 594000, 0, false, 1276, 88, 296, true, 8, 10, 72, true },
145 { 3840, 2160, 16, 9, 1188000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
146 { 3840, 2160, 16, 9, 1188000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
147 { 3840, 2160, 64, 27, 1188000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
148 { 3840, 2160, 64, 27, 1188000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
149 /* VIC 121 */
150 { 5120, 2160, 64, 27, 396000, 0, false, 1996, 88, 296, true, 8, 10, 22, true },
151 { 5120, 2160, 64, 27, 396000, 0, false, 1696, 88, 296, true, 8, 10, 22, true },
152 { 5120, 2160, 64, 27, 396000, 0, false, 664, 88, 128, true, 8, 10, 22, true },
153 { 5120, 2160, 64, 27, 742500, 0, false, 746, 88, 296, true, 8, 10, 297, true },
154 { 5120, 2160, 64, 27, 742500, 0, false, 1096, 88, 296, true, 8, 10, 72, true },
155 { 5120, 2160, 64, 27, 742500, 0, false, 164, 88, 128, true, 8, 10, 72, true },
156 { 5120, 2160, 64, 27, 1485000, 0, false, 1096, 88, 296, true, 8, 10, 72, true },
159 static const struct timings edid_cta_modes2[] = {
160 /* VIC 193 */
161 { 5120, 2160, 64, 27, 1485000, 0, false, 164, 88, 128, true, 8, 10, 72, true },
162 { 7680, 4320, 16, 9, 1188000, 0, false, 2552, 176, 592, true, 16, 20, 144, true },
163 { 7680, 4320, 16, 9, 1188000, 0, false, 2352, 176, 592, true, 16, 20, 44, true },
164 { 7680, 4320, 16, 9, 1188000, 0, false, 552, 176, 592, true, 16, 20, 44, true },
165 { 7680, 4320, 16, 9, 2376000, 0, false, 2552, 176, 592, true, 16, 20, 144, true },
166 { 7680, 4320, 16, 9, 2376000, 0, false, 2352, 176, 592, true, 16, 20, 44, true },
167 { 7680, 4320, 16, 9, 2376000, 0, false, 552, 176, 592, true, 16, 20, 44, true },
168 { 7680, 4320, 16, 9, 4752000, 0, false, 2112, 176, 592, true, 16, 20, 144, true },
169 /* VIC 201 */
170 { 7680, 4320, 16, 9, 4752000, 0, false, 352, 176, 592, true, 16, 20, 144, true },
171 { 7680, 4320, 64, 27, 1188000, 0, false, 2552, 176, 592, true, 16, 20, 144, true },
172 { 7680, 4320, 64, 27, 1188000, 0, false, 2352, 176, 592, true, 16, 20, 44, true },
173 { 7680, 4320, 64, 27, 1188000, 0, false, 552, 176, 592, true, 16, 20, 44, true },
174 { 7680, 4320, 64, 27, 2376000, 0, false, 2552, 176, 592, true, 16, 20, 144, true },
175 { 7680, 4320, 64, 27, 2376000, 0, false, 2352, 176, 592, true, 16, 20, 44, true },
176 { 7680, 4320, 64, 27, 2376000, 0, false, 552, 176, 592, true, 16, 20, 44, true },
177 { 7680, 4320, 64, 27, 4752000, 0, false, 2112, 176, 592, true, 16, 20, 144, true },
178 { 7680, 4320, 64, 27, 4752000, 0, false, 352, 176, 592, true, 16, 20, 144, true },
179 { 10240, 4320, 64, 27, 1485000, 0, false, 1492, 176, 592, true, 16, 20, 594, true },
180 /* VIC 211 */
181 { 10240, 4320, 64, 27, 1485000, 0, false, 2492, 176, 592, true, 16, 20, 44, true },
182 { 10240, 4320, 64, 27, 1485000, 0, false, 288, 176, 296, true, 16, 20, 144, true },
183 { 10240, 4320, 64, 27, 2970000, 0, false, 1492, 176, 592, true, 16, 20, 594, true },
184 { 10240, 4320, 64, 27, 2970000, 0, false, 2492, 176, 592, true, 16, 20, 44, true },
185 { 10240, 4320, 64, 27, 2970000, 0, false, 288, 176, 296, true, 16, 20, 144, true },
186 { 10240, 4320, 64, 27, 5940000, 0, false, 2192, 176, 592, true, 16, 20, 144, true },
187 { 10240, 4320, 64, 27, 5940000, 0, false, 288, 176, 296, true, 16, 20, 144, true },
188 { 4096, 2160, 256, 135, 1188000, 0, false, 800, 88, 296, true, 8, 10, 72, true },
189 { 4096, 2160, 256, 135, 1188000, 0, false, 88, 88, 128, true, 8, 10, 72, true },
192 static const cta_rid rids[] = {
193 /* RID 0-9 */
194 { 0, 0, 0, 0 },
195 { 1280, 720, 16, 9 },
196 { 1280, 720, 64, 27 },
197 { 1680, 720, 64, 27 },
198 { 1920, 1080, 16, 9 },
199 { 1920, 1080, 64, 27 },
200 { 2560, 1080, 64, 27 },
201 { 3840, 1080, 32, 9 },
202 { 2560, 1440, 16, 9 },
203 { 3440, 1440, 64, 27 },
204 /* RID 10-19 */
205 { 5120, 1440, 32, 9 },
206 { 3840, 2160, 16, 9 },
207 { 3840, 2160, 64, 27 },
208 { 5120, 2160, 64, 27 },
209 { 7680, 2160, 32, 9 },
210 { 5120, 2880, 16, 9 },
211 { 5120, 2880, 64, 27 },
212 { 6880, 2880, 64, 27 },
213 { 10240, 2880, 32, 9 },
214 { 7680, 4320, 16, 9 },
215 /* RID 20-28 */
216 { 7680, 4320, 64, 27 },
217 { 10240, 4320, 64, 27 },
218 { 15360, 4320, 32, 9 },
219 { 11520, 6480, 16, 9 },
220 { 11520, 6480, 64, 27 },
221 { 15360, 6480, 64, 27 },
222 { 15360, 8640, 16, 9 },
223 { 15360, 8640, 64, 27 },
224 { 20480, 8640, 64, 27 },
227 static const unsigned char rid2vic[ARRAY_SIZE(rids)][8] = {
228 /* RID 0-9 */
230 { 60, 61, 62, 108, 19, 4, 41, 47 },
231 { 65, 66, 67, 109, 68, 69, 70, 71 },
232 { 79, 80, 81, 110, 82, 83, 84, 85 },
233 { 32, 33, 34, 111, 31, 16, 64, 63 },
234 { 72, 73, 74, 112, 75, 76, 77, 78 },
235 { 86, 87, 88, 113, 89, 90, 91, 92 },
239 /* RID 10-19 */
241 { 93, 94, 95, 114, 96, 97, 117, 118 },
242 { 103, 104, 105, 116, 106, 107, 119, 120 },
243 { 121, 122, 123, 124, 125, 126, 127, 193 },
249 { 194, 195, 196, 197, 198, 199, 200, 201 },
250 /* RID 20-28 */
251 { 202, 203, 204, 205, 206, 207, 208, 209 },
252 { 210, 211, 212, 213, 214, 215, 216, 217 },
262 static const unsigned vf_rate_values[] = {
263 /* Rate Index 0-7 */
264 0, 24, 25, 30, 48, 50, 60, 100,
265 /* Rate Index 8-15 */
266 120, 144, 200, 240, 300, 360, 400, 480,
269 static const unsigned char edid_hdmi_mode_map[] = { 95, 94, 93, 98 };
271 unsigned char hdmi_vic_to_vic(unsigned char hdmi_vic)
273 if (hdmi_vic > 0 && hdmi_vic <= ARRAY_SIZE(edid_hdmi_mode_map))
274 return edid_hdmi_mode_map[hdmi_vic - 1];
275 return 0;
278 const struct timings *find_vic_id(unsigned char vic)
280 if (vic > 0 && vic <= ARRAY_SIZE(edid_cta_modes1))
281 return edid_cta_modes1 + vic - 1;
282 if (vic >= 193 && vic < ARRAY_SIZE(edid_cta_modes2) + 193)
283 return edid_cta_modes2 + vic - 193;
284 return NULL;
287 const struct timings *find_hdmi_vic_id(unsigned char hdmi_vic)
289 if (hdmi_vic > 0 && hdmi_vic <= ARRAY_SIZE(edid_hdmi_mode_map))
290 return find_vic_id(edid_hdmi_mode_map[hdmi_vic - 1]);
291 return NULL;
294 const struct cta_rid *find_rid(unsigned char rid)
296 if (rid > 0 && rid < ARRAY_SIZE(rids))
297 return &rids[rid];
298 return NULL;
301 static unsigned char rid_to_vic(unsigned char rid, unsigned char rate_index)
303 if (vf_rate_values[rate_index] > 120)
304 return 0;
305 return rid2vic[rid][rate_index - 1];
308 const struct timings *cta_close_match_to_vic(const timings &t, unsigned &vic)
310 for (vic = 1; vic <= ARRAY_SIZE(edid_cta_modes1); vic++) {
311 if (timings_close_match(t, edid_cta_modes1[vic - 1]))
312 return &edid_cta_modes1[vic - 1];
314 for (vic = 193; vic < ARRAY_SIZE(edid_cta_modes2) + 193; vic++) {
315 if (timings_close_match(t, edid_cta_modes1[vic - 193]))
316 return &edid_cta_modes1[vic - 193];
318 vic = 0;
319 return NULL;
322 void edid_state::cta_list_vics()
324 char type[16];
325 for (unsigned vic = 1; vic <= ARRAY_SIZE(edid_cta_modes1); vic++) {
326 sprintf(type, "VIC %3u", vic);
327 print_timings("", &edid_cta_modes1[vic - 1], type, "", false, false);
329 for (unsigned vic = 193; vic < ARRAY_SIZE(edid_cta_modes2) + 193; vic++) {
330 sprintf(type, "VIC %3u", vic);
331 print_timings("", &edid_cta_modes2[vic - 193], type, "", false, false);
335 void edid_state::cta_list_hdmi_vics()
337 for (unsigned i = 0; i < ARRAY_SIZE(edid_hdmi_mode_map); i++) {
338 unsigned vic = edid_hdmi_mode_map[i];
339 char type[16];
341 sprintf(type, "HDMI VIC %u", i + 1);
342 print_timings("", find_vic_id(vic), type, "", false, false);
346 void edid_state::cta_list_rids()
348 for (unsigned i = 1; i < ARRAY_SIZE(rids); i++) {
349 printf("RID %2u: %5ux%-4u %2u:%-2u\n", i,
350 rids[i].hact, rids[i].vact,
351 rids[i].hratio, rids[i].vratio);
355 void edid_state::cta_list_rid_timings(unsigned list_rid)
357 for (unsigned rid = 1; rid < ARRAY_SIZE(rids); rid++) {
358 char type[16];
360 if (list_rid && rid != list_rid)
361 continue;
363 sprintf(type, "RID %u", rid);
364 for (unsigned i = 1; i < ARRAY_SIZE(vf_rate_values); i++) {
365 unsigned fps = vf_rate_values[i];
367 if (rid_to_vic(rid, i)) {
368 printf("%s: %5ux%-4u %7.3f Hz %3u:%-2u maps to VIC %u\n", type,
369 rids[rid].hact, rids[rid].vact, (double)fps,
370 rids[rid].hratio, rids[rid].vratio,
371 rid_to_vic(rid, i));
372 continue;
374 timings t = calc_ovt_mode(rids[rid].hact, rids[rid].vact,
375 rids[rid].hratio, rids[rid].vratio, fps);
376 print_timings("", &t, type, "", false, false);
381 static std::string audio_ext_format(unsigned char x)
383 if (x >= 1 && x <= 3)
384 fail("Obsolete Audio Ext Format 0x%02x.\n", x);
385 switch (x) {
386 case 1: return "HE AAC (Obsolete)";
387 case 2: return "HE AAC v2 (Obsolete)";
388 case 3: return "MPEG Surround (Obsolete)";
389 case 4: return "MPEG-4 HE AAC";
390 case 5: return "MPEG-4 HE AAC v2";
391 case 6: return "MPEG-4 AAC LC";
392 case 7: return "DRA";
393 case 8: return "MPEG-4 HE AAC + MPEG Surround";
394 case 10: return "MPEG-4 AAC LC + MPEG Surround";
395 case 11: return "MPEG-H 3D Audio";
396 case 12: return "AC-4";
397 case 13: return "L-PCM 3D Audio";
398 case 14: return "Auro-Cx";
399 case 15: return "MPEG-D USAC";
400 default: break;
402 fail("Unknown Audio Ext Format 0x%02x.\n", x);
403 return std::string("Unknown Audio Ext Format (") + utohex(x) + ")";
406 static std::string audio_format(unsigned char x)
408 switch (x) {
409 case 1: return "Linear PCM";
410 case 2: return "AC-3";
411 case 3: return "MPEG 1 (Layers 1 & 2)";
412 case 4: return "MPEG 1 Layer 3 (MP3)";
413 case 5: return "MPEG2 (multichannel)";
414 case 6: return "AAC LC";
415 case 7: return "DTS";
416 case 8: return "ATRAC";
417 case 9: return "One Bit Audio";
418 case 10: return "Enhanced AC-3 (DD+)";
419 case 11: return "DTS-HD";
420 case 12: return "MAT (MLP)";
421 case 13: return "DST";
422 case 14: return "WMA Pro";
423 default: break;
425 fail("Unknown Audio Format 0x%02x.\n", x);
426 return std::string("Unknown Audio Format (") + utohex(x) + ")";
429 static std::string mpeg_h_3d_audio_level(unsigned char x)
431 switch (x) {
432 case 0: return "Unspecified";
433 case 1: return "Level 1";
434 case 2: return "Level 2";
435 case 3: return "Level 3";
436 case 4: return "Level 4";
437 case 5: return "Level 5";
438 default: break;
440 fail("Unknown MPEG-H 3D Audio Level 0x%02x.\n", x);
441 return std::string("Unknown MPEG-H 3D Audio Level (") + utohex(x) + ")";
444 static void cta_audio_block(const unsigned char *x, unsigned length)
446 unsigned i, format, ext_format;
448 if (length % 3) {
449 fail("Broken CTA-861 audio block length %d.\n", length);
450 return;
453 for (i = 0; i < length; i += 3) {
454 format = (x[i] & 0x78) >> 3;
455 if (format == 0) {
456 printf(" Reserved (0x00)\n");
457 fail("Audio Format Code 0x00 is reserved.\n");
458 continue;
460 if (format != 15) {
461 ext_format = 0;
462 printf(" %s:\n", audio_format(format).c_str());
463 } else {
464 ext_format = (x[i + 2] & 0xf8) >> 3;
465 printf(" %s:\n", audio_ext_format(ext_format).c_str());
467 if (format != 15)
468 printf(" Max channels: %u\n", (x[i] & 0x07)+1);
469 else if (ext_format == 11)
470 printf(" MPEG-H 3D Audio Level: %s\n",
471 mpeg_h_3d_audio_level(x[i] & 0x07).c_str());
472 else if (ext_format == 13)
473 printf(" Max channels: %u\n",
474 (((x[i + 1] & 0x80) >> 3) | ((x[i] & 0x80) >> 4) |
475 (x[i] & 0x07))+1);
476 else if ((ext_format == 12 || ext_format == 14) && (x[i] & 0x07))
477 fail("Bits F10-F12 must be 0.\n");
478 else
479 printf(" Max channels: %u\n", (x[i] & 0x07)+1);
481 if ((format == 1 || format == 14) && (x[i + 2] & 0xf8))
482 fail("Bits F33-F37 must be 0.\n");
483 if (ext_format != 13 && (x[i+1] & 0x80))
484 fail("Bit F27 must be 0.\n");
486 // Several sample rates are not supported in certain formats
487 if (ext_format == 12 && (x[i+1] & 0x29))
488 fail("Bits F20, F23 and F25 must be 0.\n");
489 if (ext_format >= 4 && ext_format <= 6 && (x[i+1] & 0x60))
490 fail("Bits F25 and F26 must be 0.\n");
491 if ((ext_format == 8 || ext_format == 10 || ext_format == 15) && (x[i+1] & 0x60))
492 fail("Bits F25 and F26 must be 0.\n");
494 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
495 (x[i+1] & 0x40) ? " 192" : "",
496 (x[i+1] & 0x20) ? " 176.4" : "",
497 (x[i+1] & 0x10) ? " 96" : "",
498 (x[i+1] & 0x08) ? " 88.2" : "",
499 (x[i+1] & 0x04) ? " 48" : "",
500 (x[i+1] & 0x02) ? " 44.1" : "",
501 (x[i+1] & 0x01) ? " 32" : "");
502 if (format == 1 || ext_format == 13) {
503 printf(" Supported sample sizes (bits):%s%s%s\n",
504 (x[i+2] & 0x04) ? " 24" : "",
505 (x[i+2] & 0x02) ? " 20" : "",
506 (x[i+2] & 0x01) ? " 16" : "");
507 } else if (format <= 8) {
508 printf(" Maximum bit rate: %u kb/s\n", x[i+2] * 8);
509 } else if (format == 10) {
510 // As specified by the "Dolby Audio and Dolby Atmos over HDMI"
511 // specification (v1.0).
512 if (x[i+2] & 1)
513 printf(" Supports Joint Object Coding\n");
514 if (x[i+2] & 2)
515 printf(" Supports Joint Object Coding with ACMOD28\n");
516 } else if (format == 11) {
517 // Reverse engineering, see:
518 // https://www.avsforum.com/threads/lg-c9-earc-info-thread.3072900/post-61795538
519 if (x[i+2] & 2)
520 printf(" Supports DTS:X\n");
521 // Note: I strongly suspect that bit 0 indicates DTS-HD MA support.
522 printf(" Audio Format Code dependent value: 0x%02x\n", x[i+2]);
523 } else if (format == 12) {
524 if (x[i+2] & 1) {
525 printf(" Supports Dolby TrueHD, object audio PCM and channel-based PCM\n");
526 printf(" Hash calculation %srequired for object audio PCM or channel-based PCM\n",
527 (x[i+2] & 2) ? "not " : "");
528 } else {
529 printf(" Supports only Dolby TrueHD\n");
531 } else if (format == 14) {
532 printf(" Profile: %u\n", x[i+2] & 7);
533 } else if (format >= 9 && format <= 13) {
534 printf(" Audio Format Code dependent value: 0x%02x\n", x[i+2]);
535 } else if (ext_format == 11 && (x[i+2] & 1)) {
536 printf(" Supports MPEG-H 3D Audio Low Complexity Profile\n");
537 } else if ((ext_format >= 4 && ext_format <= 6) ||
538 ext_format == 8 || ext_format == 10) {
539 printf(" AAC audio frame lengths:%s%s\n",
540 (x[i+2] & 4) ? " 1024_TL" : "",
541 (x[i+2] & 2) ? " 960_TL" : "");
542 if (ext_format >= 8 && (x[i+2] & 1))
543 printf(" Supports %s signaled MPEG Surround data\n",
544 (x[i+2] & 1) ? "implicitly and explicitly" : "only implicitly");
545 if (ext_format == 6 && (x[i+2] & 1))
546 printf(" Supports 22.2ch System H\n");
547 } else if (ext_format == 12 || ext_format == 14) {
548 printf(" Audio Format Code dependent value: %u\n", x[i+2] & 7);
553 void edid_state::cta_svd(const unsigned char *x, unsigned n, bool for_ycbcr420)
555 unsigned i;
557 for (i = 0; i < n; i++) {
558 const struct timings *t = NULL;
559 unsigned char svd = x[i];
560 unsigned char native;
561 unsigned char vic;
563 if ((svd & 0x7f) == 0)
564 continue;
566 if ((svd - 1) & 0x40) {
567 vic = svd;
568 native = 0;
569 } else {
570 vic = svd & 0x7f;
571 native = svd & 0x80;
574 t = find_vic_id(vic);
575 if (t) {
576 switch (vic) {
577 case 95:
578 cta.supported_hdmi_vic_vsb_codes |= 1 << 0;
579 break;
580 case 94:
581 cta.supported_hdmi_vic_vsb_codes |= 1 << 1;
582 break;
583 case 93:
584 cta.supported_hdmi_vic_vsb_codes |= 1 << 2;
585 break;
586 case 98:
587 cta.supported_hdmi_vic_vsb_codes |= 1 << 3;
588 break;
590 bool first_svd = cta.first_svd && !for_ycbcr420;
591 bool override_pref = first_svd && cta.first_svd_might_be_preferred;
593 char type[16];
594 sprintf(type, "VIC %3u", vic);
595 const char *flags = native ? "native" : "";
597 if (for_ycbcr420) {
598 struct timings tmp = *t;
599 tmp.ycbcr420 = true;
600 print_timings(" ", &tmp, type, flags);
601 } else {
602 print_timings(" ", t, type, flags);
604 if (override_pref) {
605 if (!cta.preferred_timings.empty()) {
606 if (match_timings(cta.preferred_timings[0].t, *t))
607 warn("For improved preferred timing interoperability, set 'Native detailed modes' to 1.\n");
608 else
609 warn("VIC %u is the preferred timing, overriding the first detailed timings. Is this intended?\n", vic);
611 cta.preferred_timings.insert(cta.preferred_timings.begin(),
612 timings_ext(*t, type, flags));
613 } else if (first_svd) {
614 cta.preferred_timings.push_back(timings_ext(*t, type, flags));
616 if (first_svd) {
617 cta.first_svd = false;
618 cta.first_svd_might_be_preferred = false;
620 if (native)
621 cta.native_timings.push_back(timings_ext(*t, type, flags));
622 } else {
623 printf(" Unknown (VIC %3u)\n", vic);
624 fail("Unknown VIC %u.\n", vic);
627 if (vic == 1 && !for_ycbcr420)
628 cta.has_vic_1 = 1;
629 if (++cta.vics[vic][for_ycbcr420] == 2)
630 fail("Duplicate %sVIC %u.\n", for_ycbcr420 ? "YCbCr 4:2:0 " : "", vic);
631 if (for_ycbcr420 && cta.preparsed_has_vic[0][vic])
632 fail("YCbCr 4:2:0-only VIC %u is also a regular VIC.\n", vic);
636 cta_vfd edid_state::cta_parse_vfd(const unsigned char *x, unsigned lvfd)
638 cta_vfd vfd = {};
640 vfd.rid = x[0] & 0x3f;
641 if (vfd.rid >= ARRAY_SIZE(rids)) {
642 vfd.rid = 0;
643 return vfd;
645 vfd.bfr50 = !!(x[0] & 0x80);
646 vfd.fr24 = !!(x[0] & 0x40);
647 vfd.bfr60 = lvfd > 1 ? !!(x[1] & 0x80) : 1;
648 vfd.fr144 = lvfd > 1 ? !!(x[1] & 0x40) : 0;
649 vfd.fr_factor = lvfd > 1 ? (x[1] & 0x3f) : 3;
650 vfd.fr48 = lvfd > 2 ? !!(x[2] & 0x01) : 0;
651 return vfd;
654 static bool vfd_has_rate(cta_vfd &vfd, unsigned rate_index)
656 static const unsigned factors[6] = {
657 1, 2, 4, 8, 12, 16
659 unsigned rate = vf_rate_values[rate_index];
660 unsigned factor = 0;
662 if (!vfd.rid)
663 return false;
664 if (rate == 24)
665 return vfd.fr24;
666 if (rate == 48)
667 return vfd.fr48;
668 if (rate == 144)
669 return vfd.fr144;
671 if (!(rate % 30)) {
672 if (!vfd.bfr60)
673 return false;
674 factor = rate / 30;
676 if (!(rate % 25)) {
677 if (!vfd.bfr50)
678 return false;
679 factor = rate / 25;
682 for (unsigned i = 0; i < ARRAY_SIZE(factors); i++)
683 if (factors[i] == factor && (vfd.fr_factor & (1 << i)))
684 return true;
685 return false;
688 void edid_state::cta_vfdb(const unsigned char *x, unsigned n)
690 if (n-- == 0) {
691 fail("Length is 0.\n");
692 return;
694 unsigned char flags = *x++;
695 unsigned lvfd = (flags & 3) + 1;
697 if (n % lvfd) {
698 fail("Length - 1 is not a multiple of Lvfd (%u).\n", lvfd);
699 return;
701 if (flags & 0x80)
702 printf(" Supports YCbCr 4:2:0\n");
703 if (flags & 0x40)
704 printf(" NTSC fractional frame rates are preferred\n");
705 for (unsigned i = 0; i < n; i += lvfd, x += lvfd) {
706 unsigned char rid = x[0] & 0x3f;
707 cta_vfd vfd = cta_parse_vfd(x, lvfd);
709 if (lvfd > 2 && (x[2] & 0xfe))
710 fail("Bits F31-F37 must be 0.\n");
711 if (lvfd > 3 && x[3])
712 fail("Bits F40-F47 must be 0.\n");
713 if (rid == 0 || rid >= ARRAY_SIZE(rids)) {
714 fail("Unknown RID %u.\n", rid);
715 continue;
717 for (unsigned rate_index = 1; rate_index < ARRAY_SIZE(vf_rate_values); rate_index++) {
718 if (!vfd_has_rate(vfd, rate_index))
719 continue;
720 struct timings t = calc_ovt_mode(rids[vfd.rid].hact,
721 rids[vfd.rid].vact,
722 rids[vfd.rid].hratio,
723 rids[vfd.rid].vratio,
724 vf_rate_values[rate_index]);
725 char type[16];
726 sprintf(type, "RID %u@%up", rid, vf_rate_values[rate_index]);
727 print_timings(" ", &t, type);
728 if (rid_to_vic(vfd.rid, rate_index))
729 fail("%s not allowed since it maps to VIC %u.\n",
730 type, rid_to_vic(vfd.rid, rate_index));
735 void edid_state::print_vic_index(const char *prefix, unsigned idx, const char *suffix, bool ycbcr420)
737 if (!suffix)
738 suffix = "";
739 if (idx < cta.preparsed_svds[0].size()) {
740 unsigned char vic = cta.preparsed_svds[0][idx];
741 const struct timings *t = find_vic_id(vic);
742 char buf[16];
744 sprintf(buf, "VIC %3u", vic);
746 if (t) {
747 struct timings tmp = *t;
748 tmp.ycbcr420 = ycbcr420;
749 print_timings(prefix, &tmp, buf, suffix);
750 } else {
751 printf("%sUnknown (%s%s%s)\n", prefix, buf,
752 *suffix ? ", " : "", suffix);
754 } else {
755 // Should not happen!
756 printf("%sSVD Index %u is out of range", prefix, idx + 1);
757 if (*suffix)
758 printf(" (%s)", suffix);
759 printf("\n");
763 void edid_state::cta_y420cmdb(const unsigned char *x, unsigned length)
765 unsigned max_idx = 0;
766 unsigned i;
768 if (!length) {
769 printf(" All VDB SVDs\n");
770 return;
773 if (memchk(x, length)) {
774 printf(" Empty Capability Map\n");
775 fail("Empty Capability Map.\n");
776 return;
779 for (i = 0; i < length; i++) {
780 unsigned char v = x[i];
781 unsigned j;
783 for (j = 0; j < 8; j++) {
784 if (!(v & (1 << j)))
785 continue;
787 print_vic_index(" ", i * 8 + j, "", true);
788 max_idx = i * 8 + j;
789 if (max_idx < cta.preparsed_svds[0].size()) {
790 unsigned vic = cta.preparsed_svds[0][max_idx];
791 if (cta.preparsed_has_vic[1][vic])
792 fail("VIC %u is also a YCbCr 4:2:0-only VIC.\n", vic);
796 if (max_idx >= cta.preparsed_svds[0].size())
797 fail("Max index %u > %u (#SVDs).\n",
798 max_idx + 1, cta.preparsed_svds[0].size());
801 void edid_state::cta_print_svr(unsigned char svr, vec_timings_ext &vec_tim)
803 char suffix[24];
805 if ((svr > 0 && svr < 128) || (svr > 192 && svr < 254)) {
806 const struct timings *t;
807 unsigned char vic = svr;
809 sprintf(suffix, "VIC %3u", vic);
811 t = find_vic_id(vic);
812 if (t) {
813 print_timings(" ", t, suffix);
814 vec_tim.push_back(timings_ext(*t, suffix, ""));
815 } else {
816 printf(" %s: Unknown\n", suffix);
817 fail("Unknown VIC %u.\n", vic);
820 } else if (svr >= 129 && svr <= 144) {
821 sprintf(suffix, "DTD %3u", svr - 128);
822 if (svr >= cta.preparsed_total_dtds + 129) {
823 printf(" %s: Invalid\n", suffix);
824 fail("Invalid DTD %u.\n", svr - 128);
825 } else {
826 printf(" %s\n", suffix);
827 vec_tim.push_back(timings_ext(svr, suffix));
829 } else if (svr >= 145 && svr <= 160) {
830 sprintf(suffix, "VTDB %3u", svr - 144);
831 if (svr >= cta.preparsed_total_vtdbs + 145) {
832 printf(" %s: Invalid\n", suffix);
833 fail("Invalid VTDB %u.\n", svr - 144);
834 } else {
835 printf(" %s\n", suffix);
836 vec_tim.push_back(timings_ext(svr, suffix));
838 } else if (svr >= 161 && svr <= 175) {
839 sprintf(suffix, "RID %u@%up",
840 cta.preparsed_first_vfd.rid, vf_rate_values[svr - 160]);
841 if (!vfd_has_rate(cta.preparsed_first_vfd, svr - 160)) {
842 printf(" %s: Invalid\n", suffix);
843 fail("Invalid %s.\n", suffix);
844 } else {
845 printf(" %s\n", suffix);
846 vec_tim.push_back(timings_ext(svr, suffix));
848 } else if (svr == 254) {
849 sprintf(suffix, "T8VTDB");
850 if (!cta.preparsed_has_t8vtdb) {
851 printf(" %s: Invalid\n", suffix);
852 fail("Invalid T8VTDB.\n");
853 } else {
854 sprintf(suffix, "DMT 0x%02x", cta.preparsed_t8vtdb_dmt);
855 printf(" %s\n", suffix);
856 vec_tim.push_back(timings_ext(svr, suffix));
861 void edid_state::cta_vfpdb(const unsigned char *x, unsigned length)
863 unsigned i;
865 if (length == 0) {
866 fail("Empty Data Block with length %u.\n", length);
867 return;
869 cta.preferred_timings_vfpdb.clear();
870 for (i = 0; i < length; i++)
871 cta_print_svr(x[i], cta.preferred_timings_vfpdb);
874 void edid_state::cta_nvrdb(const unsigned char *x, unsigned length)
876 if (length == 0) {
877 fail("Empty Data Block with length %u.\n", length);
878 return;
881 unsigned char flags = length == 1 ? 0 : x[1];
883 cta.native_timing_nvrdb.clear();
884 cta_print_svr(x[0], cta.native_timing_nvrdb);
885 if ((flags & 1) && length < 6) {
886 fail("Data Block too short for Image Size (length = %u).\n", length);
887 return;
889 if (flags & 0x7e)
890 fail("Bits F41-F46 must be 0.\n");
891 if (!(flags & 1))
892 return;
894 unsigned w = (x[3] << 8) | x[2];
895 unsigned h = (x[5] << 8) | x[4];
897 if (!w || !h)
898 fail("Image Size has a zero width and/or height.\n");
900 if (flags & 0x80)
901 printf(" Image Size: %ux%u mm\n", w, h);
902 else
903 printf(" Image Size: %.1fx%.1f mm\n", w / 10.0, h / 10.0);
906 static std::string hdmi_latency2s(unsigned char l, bool is_video)
908 if (!l)
909 return "Unknown";
910 if (l == 0xff)
911 return is_video ? "Video not supported" : "Audio not supported";
912 return std::to_string(2 * (l - 1)) + " ms";
915 void edid_state::hdmi_latency(unsigned char vid_lat, unsigned char aud_lat,
916 bool is_ilaced)
918 const char *vid = is_ilaced ? "Interlaced video" : "Video";
919 const char *aud = is_ilaced ? "Interlaced audio" : "Audio";
921 printf(" %s latency: %s\n", vid, hdmi_latency2s(vid_lat, true).c_str());
922 printf(" %s latency: %s\n", aud, hdmi_latency2s(aud_lat, false).c_str());
924 if (vid_lat > 251 && vid_lat != 0xff)
925 fail("Invalid %s latency value %u.\n", vid, vid_lat);
926 if (aud_lat > 251 && aud_lat != 0xff)
927 fail("Invalid %s latency value %u.\n", aud, aud_lat);
929 if (!vid_lat || vid_lat > 251)
930 return;
931 if (!aud_lat || aud_lat > 251)
932 return;
934 unsigned vid_ms = 2 * (vid_lat - 1);
935 unsigned aud_ms = 2 * (aud_lat - 1);
937 // HDMI 2.0 latency checks for devices without HDMI output
938 if (aud_ms < vid_ms)
939 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
940 aud, vid, aud_ms, vid_ms);
941 else if (vid_ms + 20 < aud_ms)
942 warn("%s latency + 20 < %s latency (%u + 20 ms < %u ms). This is forbidden for devices without HDMI output.\n",
943 vid, aud, vid_ms, aud_ms);
944 else if (vid_ms < aud_ms)
945 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
946 vid, aud, vid_ms, aud_ms);
949 void edid_state::cta_hdmi_block(const unsigned char *x, unsigned length)
951 unsigned len_vic, len_3d;
953 if (length < 1) {
954 fail("Empty Data Block with length %u.\n", length);
955 return;
957 printf(" Source physical address: %x.%x.%x.%x\n", x[0] >> 4, x[0] & 0x0f,
958 x[1] >> 4, x[1] & 0x0f);
960 if (length < 3)
961 return;
963 if (x[2] & 0x80)
964 printf(" Supports_AI\n");
965 if (x[2] & 0x40)
966 printf(" DC_48bit\n");
967 if (x[2] & 0x20)
968 printf(" DC_36bit\n");
969 if (x[2] & 0x10)
970 printf(" DC_30bit\n");
971 if (x[2] & 0x08)
972 printf(" DC_Y444\n");
973 /* two reserved bits */
974 if (x[2] & 0x01)
975 printf(" DVI_Dual\n");
977 if (length < 4)
978 return;
980 printf(" Maximum TMDS clock: %u MHz\n", x[3] * 5);
981 if (x[3] * 5 > 340)
982 fail("HDMI VSDB Max TMDS rate is > 340.\n");
984 if (length < 5)
985 return;
987 if (x[4] & 0x0f) {
988 printf(" Supported Content Types:\n");
989 if (x[4] & 0x01)
990 printf(" Graphics\n");
991 if (x[4] & 0x02)
992 printf(" Photo\n");
993 if (x[4] & 0x04)
994 printf(" Cinema\n");
995 if (x[4] & 0x08)
996 printf(" Game\n");
999 unsigned b = 5;
1000 if (x[4] & 0x80) {
1001 hdmi_latency(x[b], x[b + 1], false);
1003 if (x[4] & 0x40) {
1004 if (x[b] == x[b + 2] &&
1005 x[b + 1] == x[b + 3])
1006 warn("Progressive and Interlaced latency values are identical, no need for both.\n");
1007 b += 2;
1008 hdmi_latency(x[b], x[b + 1], true);
1010 b += 2;
1013 if (!(x[4] & 0x20))
1014 return;
1016 bool mask = false;
1017 bool formats = false;
1019 printf(" Extended HDMI video details:\n");
1020 if (x[b] & 0x80)
1021 printf(" 3D present\n");
1022 if ((x[b] & 0x60) == 0x20) {
1023 printf(" All advertised VICs are 3D-capable\n");
1024 formats = true;
1026 if ((x[b] & 0x60) == 0x40) {
1027 printf(" 3D-capable-VIC mask present\n");
1028 formats = true;
1029 mask = true;
1031 switch (x[b] & 0x18) {
1032 case 0x00: break;
1033 case 0x08:
1034 printf(" Base EDID image size is aspect ratio\n");
1035 break;
1036 case 0x10:
1037 printf(" Base EDID image size is in units of 1 cm\n");
1038 break;
1039 case 0x18:
1040 printf(" Base EDID image size is in units of 5 cm\n");
1041 base.max_display_width_mm *= 5;
1042 base.max_display_height_mm *= 5;
1043 printf(" Recalculated image size: %u cm x %u cm\n",
1044 base.max_display_width_mm / 10, base.max_display_height_mm / 10);
1045 break;
1047 b++;
1048 len_vic = (x[b] & 0xe0) >> 5;
1049 len_3d = (x[b] & 0x1f) >> 0;
1050 b++;
1052 if (len_vic) {
1053 unsigned i;
1055 printf(" HDMI VICs:\n");
1056 for (i = 0; i < len_vic; i++) {
1057 unsigned char vic = x[b + i];
1058 const struct timings *t;
1060 if (vic && vic <= ARRAY_SIZE(edid_hdmi_mode_map)) {
1061 std::string suffix = "HDMI VIC " + std::to_string(vic);
1062 cta.supported_hdmi_vic_codes |= 1 << (vic - 1);
1063 t = find_vic_id(edid_hdmi_mode_map[vic - 1]);
1064 print_timings(" ", t, suffix.c_str());
1065 } else {
1066 printf(" Unknown (HDMI VIC %u)\n", vic);
1067 fail("Unknown HDMI VIC %u.\n", vic);
1071 b += len_vic;
1074 if (!len_3d)
1075 return;
1077 if (formats) {
1078 /* 3D_Structure_ALL_15..8 */
1079 if (x[b] & 0x80)
1080 printf(" 3D: Side-by-side (half, quincunx)\n");
1081 if (x[b] & 0x01)
1082 printf(" 3D: Side-by-side (half, horizontal)\n");
1083 /* 3D_Structure_ALL_7..0 */
1084 b++;
1085 if (x[b] & 0x40)
1086 printf(" 3D: Top-and-bottom\n");
1087 if (x[b] & 0x20)
1088 printf(" 3D: L + depth + gfx + gfx-depth\n");
1089 if (x[b] & 0x10)
1090 printf(" 3D: L + depth\n");
1091 if (x[b] & 0x08)
1092 printf(" 3D: Side-by-side (full)\n");
1093 if (x[b] & 0x04)
1094 printf(" 3D: Line-alternative\n");
1095 if (x[b] & 0x02)
1096 printf(" 3D: Field-alternative\n");
1097 if (x[b] & 0x01)
1098 printf(" 3D: Frame-packing\n");
1099 b++;
1100 len_3d -= 2;
1103 if (mask) {
1104 int max_idx = -1;
1105 unsigned i;
1107 printf(" 3D VIC indices that support these capabilities:\n");
1108 /* worst bit ordering ever */
1109 for (i = 0; i < 8; i++)
1110 if (x[b + 1] & (1 << i)) {
1111 print_vic_index(" ", i, "");
1112 max_idx = i;
1114 for (i = 0; i < 8; i++)
1115 if (x[b] & (1 << i)) {
1116 print_vic_index(" ", i + 8, "");
1117 max_idx = i + 8;
1119 b += 2;
1120 len_3d -= 2;
1121 if (max_idx >= (int)cta.preparsed_svds[0].size())
1122 fail("HDMI 3D VIC indices max index %d > %u (#SVDs).\n",
1123 max_idx + 1, cta.preparsed_svds[0].size());
1127 * list of nibbles:
1128 * 2D_VIC_Order_X
1129 * 3D_Structure_X
1130 * (optionally: 3D_Detail_X and reserved)
1132 if (!len_3d)
1133 return;
1135 unsigned end = b + len_3d;
1136 int max_idx = -1;
1138 printf(" 3D VIC indices with specific capabilities:\n");
1139 while (b < end) {
1140 unsigned char idx = x[b] >> 4;
1141 std::string s;
1143 if (idx > max_idx)
1144 max_idx = idx;
1145 switch (x[b] & 0x0f) {
1146 case 0: s = "frame packing"; break;
1147 case 1: s = "field alternative"; break;
1148 case 2: s = "line alternative"; break;
1149 case 3: s = "side-by-side (full)"; break;
1150 case 4: s = "L + depth"; break;
1151 case 5: s = "L + depth + gfx + gfx-depth"; break;
1152 case 6: s = "top-and-bottom"; break;
1153 case 8:
1154 s = "side-by-side";
1155 switch (x[b + 1] >> 4) {
1156 case 0x00: s += ", any subsampling"; break;
1157 case 0x01: s += ", horizontal"; break;
1158 case 0x02: case 0x03: case 0x04: case 0x05:
1159 s += ", not in use";
1160 fail("not-in-use 3D_Detail_X value 0x%02x.\n",
1161 x[b + 1] >> 4);
1162 break;
1163 case 0x06: s += ", all quincunx combinations"; break;
1164 case 0x07: s += ", quincunx odd/left, odd/right"; break;
1165 case 0x08: s += ", quincunx odd/left, even/right"; break;
1166 case 0x09: s += ", quincunx even/left, odd/right"; break;
1167 case 0x0a: s += ", quincunx even/left, even/right"; break;
1168 default:
1169 s += ", reserved";
1170 fail("reserved 3D_Detail_X value 0x%02x.\n",
1171 x[b + 1] >> 4);
1172 break;
1174 break;
1175 default:
1176 s = "unknown (";
1177 s += utohex(x[b] & 0x0f) + ")";
1178 fail("Unknown 3D_Structure_X value 0x%02x.\n", x[b] & 0x0f);
1179 break;
1181 print_vic_index(" ", idx, s.c_str());
1182 if ((x[b] & 0x0f) >= 8)
1183 b++;
1184 b++;
1186 if (max_idx >= (int)cta.preparsed_svds[0].size())
1187 fail("HDMI 2D VIC indices max index %d > %u (#SVDs).\n",
1188 max_idx + 1, cta.preparsed_svds[0].size());
1191 static const char *max_frl_rates[] = {
1192 "Not Supported",
1193 "3 Gbps per lane on 3 lanes",
1194 "3 and 6 Gbps per lane on 3 lanes",
1195 "3 and 6 Gbps per lane on 3 lanes, 6 Gbps on 4 lanes",
1196 "3 and 6 Gbps per lane on 3 lanes, 6 and 8 Gbps on 4 lanes",
1197 "3 and 6 Gbps per lane on 3 lanes, 6, 8 and 10 Gbps on 4 lanes",
1198 "3 and 6 Gbps per lane on 3 lanes, 6, 8, 10 and 12 Gbps on 4 lanes",
1201 static const char *dsc_max_slices[] = {
1202 "Not Supported",
1203 "up to 1 slice and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1204 "up to 2 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1205 "up to 4 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1206 "up to 8 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1207 "up to 8 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1208 "up to 12 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1209 "up to 16 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1212 static void cta_hf_eeodb(const unsigned char *x, unsigned length)
1214 printf(" EDID Extension Block Count: %u\n", x[0]);
1215 if (length != 1)
1216 fail("Block is too long.\n");
1217 if (x[0] <= 1)
1218 fail("Extension Block Count == %u.\n", x[0]);
1221 static void cta_hf_scdb(const unsigned char *x, unsigned length)
1223 unsigned rate = x[1] * 5;
1224 unsigned v;
1226 printf(" Version: %u\n", x[0]);
1227 if (rate) {
1228 printf(" Maximum TMDS Character Rate: %u MHz\n", rate);
1229 if (rate <= 340 || rate > 600)
1230 fail("Max TMDS rate is > 0 and <= 340 or > 600.\n");
1232 if (x[2] & 0x80)
1233 printf(" SCDC Present\n");
1234 if (x[2] & 0x40)
1235 printf(" SCDC Read Request Capable\n");
1236 if (x[2] & 0x20)
1237 printf(" Supports Cable Status\n");
1238 if (x[2] & 0x10)
1239 printf(" Supports Color Content Bits Per Component Indication\n");
1240 if (x[2] & 0x08)
1241 printf(" Supports scrambling for <= 340 Mcsc\n");
1242 if (x[2] & 0x04)
1243 printf(" Supports 3D Independent View signaling\n");
1244 if (x[2] & 0x02)
1245 printf(" Supports 3D Dual View signaling\n");
1246 if (x[2] & 0x01)
1247 printf(" Supports 3D OSD Disparity signaling\n");
1248 if (x[3] & 0xf0) {
1249 unsigned max_frl_rate = x[3] >> 4;
1251 printf(" Max Fixed Rate Link: ");
1252 if (max_frl_rate < ARRAY_SIZE(max_frl_rates)) {
1253 printf("%s\n", max_frl_rates[max_frl_rate]);
1254 } else {
1255 printf("Unknown (0x%02x)\n", max_frl_rate);
1256 fail("Unknown Max Fixed Rate Link (0x%02x).\n", max_frl_rate);
1258 if (max_frl_rate == 1 && rate < 300)
1259 fail("Max Fixed Rate Link is 1, but Max TMDS rate < 300.\n");
1260 else if (max_frl_rate >= 2 && rate < 600)
1261 fail("Max Fixed Rate Link is >= 2, but Max TMDS rate < 600.\n");
1263 if (x[3] & 0x08)
1264 printf(" Supports UHD VIC\n");
1265 if (x[3] & 0x04)
1266 printf(" Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1267 if (x[3] & 0x02)
1268 printf(" Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1269 if (x[3] & 0x01)
1270 printf(" Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1272 if (length <= 4)
1273 return;
1275 if (x[4] & 0x20)
1276 printf(" Supports Mdelta\n");
1277 if (x[4] & 0x10)
1278 printf(" Supports media rates below VRRmin (CinemaVRR)\n");
1279 if (x[4] & 0x08)
1280 printf(" Supports negative Mvrr values\n");
1281 if (x[4] & 0x04)
1282 printf(" Supports Fast Vactive\n");
1283 if (x[4] & 0x02)
1284 printf(" Supports Auto Low-Latency Mode\n");
1285 if (x[4] & 0x01)
1286 printf(" Supports a FAPA in blanking after first active video line\n");
1288 if (length <= 5)
1289 return;
1291 v = x[5] & 0x3f;
1292 if (v) {
1293 printf(" VRRmin: %u Hz\n", v);
1294 if (v > 48)
1295 fail("VRRmin > 48.\n");
1297 v = (x[5] & 0xc0) << 2 | x[6];
1298 if (v) {
1299 printf(" VRRmax: %u Hz\n", v);
1300 if (!(x[5] & 0x3f))
1301 fail("VRRmin == 0, but VRRmax isn't.\n");
1302 else if (v < 100)
1303 fail("VRRmax < 100.\n");
1306 if (length <= 7)
1307 return;
1309 if (x[7] & 0x80)
1310 printf(" Supports VESA DSC 1.2a compression\n");
1311 if (x[7] & 0x40)
1312 printf(" Supports Compressed Video Transport for 4:2:0 Pixel Encoding\n");
1313 if (x[7] & 0x08)
1314 printf(" Supports Compressed Video Transport at any valid 1/16th bit bpp\n");
1315 if (x[7] & 0x04)
1316 printf(" Supports 16 bpc Compressed Video Transport\n");
1317 if (x[7] & 0x02)
1318 printf(" Supports 12 bpc Compressed Video Transport\n");
1319 if (x[7] & 0x01)
1320 printf(" Supports 10 bpc Compressed Video Transport\n");
1321 if (x[8] & 0xf) {
1322 unsigned max_slices = x[8] & 0xf;
1324 printf(" DSC Max Slices: ");
1325 if (max_slices < ARRAY_SIZE(dsc_max_slices)) {
1326 printf("%s\n", dsc_max_slices[max_slices]);
1327 } else {
1328 printf("Unknown (0x%02x)\n", max_slices);
1329 fail("Unknown DSC Max Slices (0x%02x).\n", max_slices);
1332 if (x[8] & 0xf0) {
1333 unsigned max_frl_rate = x[8] >> 4;
1335 printf(" DSC Max Fixed Rate Link: ");
1336 if (max_frl_rate < ARRAY_SIZE(max_frl_rates)) {
1337 printf("%s\n", max_frl_rates[max_frl_rate]);
1338 } else {
1339 printf("Unknown (0x%02x)\n", max_frl_rate);
1340 fail("Unknown DSC Max Fixed Rate Link (0x%02x).\n", max_frl_rate);
1343 if (x[9] & 0x3f)
1344 printf(" Maximum number of bytes in a line of chunks: %u\n",
1345 1024 * (1 + (x[9] & 0x3f)));
1348 static void cta_amd(const unsigned char *x, unsigned length)
1350 // These Freesync values are reversed engineered by looking
1351 // at existing EDIDs.
1352 printf(" Version: %u.%u\n", x[0], x[1]);
1353 printf(" Minimum Refresh Rate: %u Hz\n", x[2]);
1354 printf(" Maximum Refresh Rate: %u Hz\n", x[3]);
1355 // Freesync 1.x flags
1356 // One or more of the 0xe6 bits signal that the VESA MCCS
1357 // protocol is used to switch the Freesync range
1358 printf(" Flags 1.x: 0x%02x%s\n", x[4],
1359 (x[4] & 0xe6) ? " (MCCS)" : "");
1360 if (length >= 10) {
1361 // Freesync 2.x flags
1362 // Bit 2 no doubt indicates if the monitor supports Local Dimming
1363 // There are probably also bits to signal support of the
1364 // FreeSync2_scRGB and FreeSync2_Gamma22 HDR display modes.
1365 // I suspect bits 0 and 1.
1366 printf(" Flags 2.x: 0x%02x\n", x[5]);
1367 // The AMD tone mapping tutorial referred to in the URL below
1368 // mentions that the Freesync HDR info reports max/min
1369 // luminance of the monitor with and without local dimming.
1371 // https://gpuopen.com/learn/using-amd-freesync-premium-pro-hdr-code-samples/
1373 // So I assume that the first two luminance values are
1374 // the max/min luminance of the display and the next two
1375 // luminance values are the max/min luminance values when
1376 // local dimming is disabled. The values I get seem to
1377 // support that.
1378 printf(" Maximum luminance: %u (%.3f cd/m^2)\n",
1379 x[6], 50.0 * pow(2, x[6] / 32.0));
1380 printf(" Minimum luminance: %u (%.3f cd/m^2)\n",
1381 x[7], (50.0 * pow(2, x[6] / 32.0)) * pow(x[7] / 255.0, 2) / 100.0);
1382 if (x[5] & 4) {
1383 // One or both bytes can be 0. The meaning of that
1384 // is unknown.
1385 printf(" Maximum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1386 x[8], 50.0 * pow(2, x[8] / 32.0));
1387 printf(" Minimum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1388 x[9], (50.0 * pow(2, x[8] / 32.0)) * pow(x[9] / 255.0, 2) / 100.0);
1389 } else {
1390 // These bytes are always 0x08 0x2f. If these values
1391 // represent max/min luminance as well, then these
1392 // would map to 59.460 and 0.020 cd/m^2 respectively.
1393 // I wonder if this somehow relates to SDR.
1394 printf(" Unknown: 0x%02x 0x%02x\n", x[8], x[9]);
1399 static std::string display_use_case(unsigned char x)
1401 switch (x) {
1402 case 1: return "Test equipment";
1403 case 2: return "Generic display";
1404 case 3: return "Television display";
1405 case 4: return "Desktop productivity display";
1406 case 5: return "Desktop gaming display";
1407 case 6: return "Presentation display";
1408 case 7: return "Virtual reality headset";
1409 case 8: return "Augmented reality";
1410 case 16: return "Video wall display";
1411 case 17: return "Medical imaging display";
1412 case 18: return "Dedicated gaming display";
1413 case 19: return "Dedicated video monitor display";
1414 case 20: return "Accessory display";
1415 default: break;
1417 fail("Unknown Display product primary use case 0x%02x.\n", x);
1418 return std::string("Unknown display use case (") + utohex(x) + ")";
1421 static void cta_microsoft(const unsigned char *x, unsigned length)
1423 // This VSDB is documented at:
1424 // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
1425 printf(" Version: %u\n", x[0]);
1426 if (x[0] > 2) {
1427 // In version 1 and 2 these bits should always be set to 0.
1428 printf(" Desktop Usage: %u\n", (x[1] >> 6) & 1);
1429 printf(" Third-Party Usage: %u\n", (x[1] >> 5) & 1);
1431 printf(" Display Product Primary Use Case: %u (%s)\n", x[1] & 0x1f,
1432 display_use_case(x[1] & 0x1f).c_str());
1433 printf(" Container ID: %s\n", containerid2s(x + 2).c_str());
1436 static void cta_hdr10plus(const unsigned char *x, unsigned length)
1438 if (length == 0) {
1439 fail("Empty Data Block with length %u.\n", length);
1440 return;
1442 printf(" Application Version: %u\n", x[0]);
1443 hex_block(" ", x + 1, length - 1);
1446 // Convert a PQ value (0-1) to cd/m^2 aka nits (0-10000)
1447 static double pq2nits(double pq)
1449 const double m1 = 2610.0 / 16384.0;
1450 const double m2 = 128.0 * (2523.0 / 4096.0);
1451 const double c1 = 3424.0 / 4096.0;
1452 const double c2 = 32.0 * (2413.0 / 4096.0);
1453 const double c3 = 32.0 * (2392.0 / 4096.0);
1454 double e = pow(pq, 1.0 / m2);
1455 double v = e - c1;
1457 if (v < 0)
1458 v = 0;
1459 v /= c2 - c3 * e;
1460 v = pow(v, 1.0 / m1);
1461 return v * 10000.0;
1464 static void cta_dolby_video(const unsigned char *x, unsigned length)
1466 unsigned char version = (x[0] >> 5) & 0x07;
1468 printf(" Version: %u (%u bytes)\n", version, length + 5);
1469 if (x[0] & 0x01)
1470 printf(" Supports YUV422 12 bit\n");
1472 if (version == 0) {
1473 if (x[0] & 0x02)
1474 printf(" Supports 2160p60\n");
1475 if (x[0] & 0x04)
1476 printf(" Supports global dimming\n");
1477 unsigned char dm_version = x[16];
1478 printf(" DM Version: %u.%u\n", dm_version >> 4, dm_version & 0xf);
1479 unsigned pq = (x[14] << 4) | (x[13] >> 4);
1480 printf(" Target Min PQ: %u (%.8f cd/m^2)\n", pq, pq2nits(pq / 4095.0));
1481 pq = (x[15] << 4) | (x[13] & 0xf);
1482 printf(" Target Max PQ: %u (%u cd/m^2)\n", pq, (unsigned)pq2nits(pq / 4095.0));
1483 printf(" Rx, Ry: %.8f, %.8f\n",
1484 ((x[1] >> 4) | (x[2] << 4)) / 4096.0,
1485 ((x[1] & 0xf) | (x[3] << 4)) / 4096.0);
1486 printf(" Gx, Gy: %.8f, %.8f\n",
1487 ((x[4] >> 4) | (x[5] << 4)) / 4096.0,
1488 ((x[4] & 0xf) | (x[6] << 4)) / 4096.0);
1489 printf(" Bx, By: %.8f, %.8f\n",
1490 ((x[7] >> 4) | (x[8] << 4)) / 4096.0,
1491 ((x[7] & 0xf) | (x[9] << 4)) / 4096.0);
1492 printf(" Wx, Wy: %.8f, %.8f\n",
1493 ((x[10] >> 4) | (x[11] << 4)) / 4096.0,
1494 ((x[10] & 0xf) | (x[12] << 4)) / 4096.0);
1495 return;
1498 if (version == 1) {
1499 if (x[0] & 0x02)
1500 printf(" Supports 2160p60\n");
1501 if (x[1] & 0x01)
1502 printf(" Supports global dimming\n");
1503 unsigned char dm_version = (x[0] >> 2) & 0x07;
1504 printf(" DM Version: %u.x\n", dm_version + 2);
1505 printf(" Colorimetry: %s\n", (x[2] & 0x01) ? "P3-D65" : "ITU-R BT.709");
1506 printf(" Low Latency: %s\n", (x[3] & 0x01) ? "Standard + Low Latency" : "Only Standard");
1507 double lm = (x[2] >> 1) / 127.0;
1508 printf(" Target Min Luminance: %.8f cd/m^2\n", lm * lm);
1509 printf(" Target Max Luminance: %u cd/m^2\n", 100 + (x[1] >> 1) * 50);
1510 if (length == 10) {
1511 printf(" Rx, Ry: %.8f, %.8f\n", x[4] / 256.0, x[5] / 256.0);
1512 printf(" Gx, Gy: %.8f, %.8f\n", x[6] / 256.0, x[7] / 256.0);
1513 printf(" Bx, By: %.8f, %.8f\n", x[8] / 256.0, x[9] / 256.0);
1514 } else {
1515 double xmin = 0.625;
1516 double xstep = (0.74609375 - xmin) / 31.0;
1517 double ymin = 0.25;
1518 double ystep = (0.37109375 - ymin) / 31.0;
1520 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1521 xmin + xstep * (x[6] >> 3),
1522 ymin + ystep * (((x[6] & 0x7) << 2) | (x[4] & 0x01) | ((x[5] & 0x01) << 1)));
1523 xstep = 0.49609375 / 127.0;
1524 ymin = 0.5;
1525 ystep = (0.99609375 - ymin) / 127.0;
1526 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1527 xstep * (x[4] >> 1), ymin + ystep * (x[5] >> 1));
1528 xmin = 0.125;
1529 xstep = (0.15234375 - xmin) / 7.0;
1530 ymin = 0.03125;
1531 ystep = (0.05859375 - ymin) / 7.0;
1532 printf(" Unique Bx, By: %.8f, %.8f\n",
1533 xmin + xstep * (x[3] >> 5),
1534 ymin + ystep * ((x[3] >> 2) & 0x07));
1536 return;
1539 if (version == 2) {
1540 if (x[0] & 0x02)
1541 printf(" Supports Backlight Control\n");
1542 if (x[1] & 0x04)
1543 printf(" Supports global dimming\n");
1544 unsigned char dm_version = (x[0] >> 2) & 0x07;
1545 printf(" DM Version: %u.x\n", dm_version + 2);
1546 printf(" Backlt Min Luma: %u cd/m^2\n", 25 + (x[1] & 0x03) * 25);
1547 printf(" Interface: ");
1548 switch (x[2] & 0x03) {
1549 case 0: printf("Low-Latency\n"); break;
1550 case 1: printf("Low-Latency + Low-Latency-HDMI\n"); break;
1551 case 2: printf("Standard + Low-Latency\n"); break;
1552 case 3: printf("Standard + Low-Latency + Low-Latency-HDMI\n"); break;
1554 printf(" Supports 10b 12b 444: ");
1555 switch ((x[3] & 0x01) << 1 | (x[4] & 0x01)) {
1556 case 0: printf("Not supported\n"); break;
1557 case 1: printf("10 bit\n"); break;
1558 case 2: printf("12 bit\n"); break;
1559 case 3: printf("Reserved\n"); break;
1562 // This divider constant is a guess. According to what I read
1563 // when googling for how to interpret these values, the Min PQ
1564 // maps to a range of 0-1 cd/m^2, and the Max PQ maps to a
1565 // range of 100-10000 cd/m^2. Since the maximum value for the Max PQ
1566 // is 2055 + 65 * 31 = 4070, I am guessing that that is the correct
1567 // divider, but it might well be 4095 or 4096 instead.
1569 // I'm also not sure if the divider for Min PQ is the same as for
1570 // Max PQ. To map the max value of 20 * 31 to 1 cd/m^2 you would
1571 // need a divider of 4134 or 4135, but I suspect the same divider
1572 // is used.
1573 const double dv_pq_div = 2055 + 31 * 65;
1575 unsigned pq = 20 * (x[1] >> 3);
1576 printf(" Target Min PQ v2: %u (%.8f cd/m^2)\n", pq, pq2nits(pq / dv_pq_div));
1577 pq = 2055 + 65 * (x[2] >> 3);
1578 printf(" Target Max PQ v2: %u (%u cd/m^2)\n", pq, (unsigned)pq2nits(pq / dv_pq_div));
1580 double xmin = 0.625;
1581 double xstep = (0.74609375 - xmin) / 31.0;
1582 double ymin = 0.25;
1583 double ystep = (0.37109375 - ymin) / 31.0;
1585 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1586 xmin + xstep * (x[5] >> 3),
1587 ymin + ystep * (x[6] >> 3));
1588 xstep = 0.49609375 / 127.0;
1589 ymin = 0.5;
1590 ystep = (0.99609375 - ymin) / 127.0;
1591 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1592 xstep * (x[3] >> 1), ymin + ystep * (x[4] >> 1));
1593 xmin = 0.125;
1594 xstep = (0.15234375 - xmin) / 7.0;
1595 ymin = 0.03125;
1596 ystep = (0.05859375 - ymin) / 7.0;
1597 printf(" Unique Bx, By: %.8f, %.8f\n",
1598 xmin + xstep * (x[5] & 0x07),
1599 ymin + ystep * (x[6] & 0x07));
1603 static void cta_dolby_audio(const unsigned char *x, unsigned length)
1605 unsigned char version = 1 + (x[0] & 0x07);
1607 printf(" Version: %u (%u bytes)\n", version, length + 5);
1608 if (x[0] & 0x80)
1609 printf(" Headphone playback only\n");
1610 if (x[0] & 0x40)
1611 printf(" Height speaker zone present\n");
1612 if (x[0] & 0x20)
1613 printf(" Surround speaker zone present\n");
1614 if (x[0] & 0x10)
1615 printf(" Center speaker zone present\n");
1616 if (x[1] & 0x01)
1617 printf(" Supports Dolby MAT PCM decoding at 48 kHz only, does not support TrueHD\n");
1620 static const char *speaker_map[] = {
1621 "FL/FR - Front Left/Right",
1622 "LFE1 - Low Frequency Effects 1",
1623 "FC - Front Center",
1624 "BL/BR - Back Left/Right",
1625 "BC - Back Center",
1626 "FLc/FRc - Front Left/Right of Center",
1627 "RLC/RRC - Rear Left/Right of Center (Deprecated)",
1628 "FLw/FRw - Front Left/Right Wide",
1629 "TpFL/TpFR - Top Front Left/Right",
1630 "TpC - Top Center",
1631 "TpFC - Top Front Center",
1632 "LS/RS - Left/Right Surround",
1633 "LFE2 - Low Frequency Effects 2",
1634 "TpBC - Top Back Center",
1635 "SiL/SiR - Side Left/Right",
1636 "TpSiL/TpSiR - Top Side Left/Right",
1637 "TpBL/TpBR - Top Back Left/Right",
1638 "BtFC - Bottom Front Center",
1639 "BtFL/BtFR - Bottom Front Left/Right",
1640 "TpLS/TpRS - Top Left/Right Surround (Deprecated for CTA-861)",
1641 "LSd/RSd - Left/Right Surround Direct (HDMI only)",
1644 static void cta_sadb(const unsigned char *x, unsigned length)
1646 unsigned sad;
1647 unsigned i;
1649 if (length < 3) {
1650 fail("Empty Data Block with length %u.\n", length);
1651 return;
1654 sad = ((x[2] << 16) | (x[1] << 8) | x[0]);
1656 for (i = 0; i < ARRAY_SIZE(speaker_map); i++) {
1657 if ((sad >> i) & 1)
1658 printf(" %s\n", speaker_map[i]);
1662 static void cta_vesa_dtcdb(const unsigned char *x, unsigned length)
1664 if (length != 7 && length != 15 && length != 31) {
1665 fail("Invalid length %u.\n", length);
1666 return;
1669 switch (x[0] >> 6) {
1670 case 0: printf(" White"); break;
1671 case 1: printf(" Red"); break;
1672 case 2: printf(" Green"); break;
1673 case 3: printf(" Blue"); break;
1675 unsigned v = x[0] & 0x3f;
1676 printf(" transfer characteristics: %u", v);
1677 for (unsigned i = 1; i < length; i++)
1678 printf(" %u", v += x[i]);
1679 printf(" 1023\n");
1682 static void cta_vesa_vdddb(const unsigned char *x, unsigned length)
1684 if (length != 30) {
1685 fail("Invalid length %u.\n", length);
1686 return;
1689 printf(" Interface Type: ");
1690 unsigned char v = x[0];
1691 switch (v >> 4) {
1692 case 0: printf("Analog (");
1693 switch (v & 0xf) {
1694 case 0: printf("15HD/VGA"); break;
1695 case 1: printf("VESA NAVI-V (15HD)"); break;
1696 case 2: printf("VESA NAVI-D"); break;
1697 default: printf("Reserved"); break;
1699 printf(")\n");
1700 break;
1701 case 1: printf("LVDS %u lanes", v & 0xf); break;
1702 case 2: printf("RSDS %u lanes", v & 0xf); break;
1703 case 3: printf("DVI-D %u channels", v & 0xf); break;
1704 case 4: printf("DVI-I analog"); break;
1705 case 5: printf("DVI-I digital %u channels", v & 0xf); break;
1706 case 6: printf("HDMI-A"); break;
1707 case 7: printf("HDMI-B"); break;
1708 case 8: printf("MDDI %u channels", v & 0xf); break;
1709 case 9: printf("DisplayPort %u channels", v & 0xf); break;
1710 case 10: printf("IEEE-1394"); break;
1711 case 11: printf("M1 analog"); break;
1712 case 12: printf("M1 digital %u channels", v & 0xf); break;
1713 default: printf("Reserved"); break;
1715 printf("\n");
1717 printf(" Interface Standard Version: %u.%u\n", x[1] >> 4, x[1] & 0xf);
1718 printf(" Content Protection Support: ");
1719 switch (x[2]) {
1720 case 0: printf("None\n"); break;
1721 case 1: printf("HDCP\n"); break;
1722 case 2: printf("DTCP\n"); break;
1723 case 3: printf("DPCP\n"); break;
1724 default: printf("Reserved\n"); break;
1727 printf(" Minimum Clock Frequency: %u MHz\n", x[3] >> 2);
1728 printf(" Maximum Clock Frequency: %u MHz\n", ((x[3] & 0x03) << 8) | x[4]);
1729 printf(" Device Native Pixel Format: %ux%u\n",
1730 x[5] | (x[6] << 8), x[7] | (x[8] << 8));
1731 printf(" Aspect Ratio: %.2f\n", (100 + x[9]) / 100.0);
1732 v = x[0x0a];
1733 printf(" Default Orientation: ");
1734 switch ((v & 0xc0) >> 6) {
1735 case 0x00: printf("Landscape\n"); break;
1736 case 0x01: printf("Portrait\n"); break;
1737 case 0x02: printf("Not Fixed\n"); break;
1738 case 0x03: printf("Undefined\n"); break;
1740 printf(" Rotation Capability: ");
1741 switch ((v & 0x30) >> 4) {
1742 case 0x00: printf("None\n"); break;
1743 case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
1744 case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
1745 case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
1747 printf(" Zero Pixel Location: ");
1748 switch ((v & 0x0c) >> 2) {
1749 case 0x00: printf("Upper Left\n"); break;
1750 case 0x01: printf("Upper Right\n"); break;
1751 case 0x02: printf("Lower Left\n"); break;
1752 case 0x03: printf("Lower Right\n"); break;
1754 printf(" Scan Direction: ");
1755 switch (v & 0x03) {
1756 case 0x00: printf("Not defined\n"); break;
1757 case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
1758 case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
1759 case 0x03: printf("Reserved\n");
1760 fail("Scan Direction used the reserved value 0x03.\n");
1761 break;
1763 printf(" Subpixel Information: ");
1764 switch (x[0x0b]) {
1765 case 0x00: printf("Not defined\n"); break;
1766 case 0x01: printf("RGB vertical stripes\n"); break;
1767 case 0x02: printf("RGB horizontal stripes\n"); break;
1768 case 0x03: printf("Vertical stripes using primary order\n"); break;
1769 case 0x04: printf("Horizontal stripes using primary order\n"); break;
1770 case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
1771 case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
1772 case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
1773 case 0x08: printf("Mosaic\n"); break;
1774 case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
1775 case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
1776 case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
1777 case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
1778 default: printf("Reserved\n"); break;
1780 printf(" Horizontal and vertical dot/pixel pitch: %.2f x %.2f mm\n",
1781 (double)(x[0x0c]) / 100.0, (double)(x[0x0d]) / 100.0);
1782 v = x[0x0e];
1783 printf(" Dithering: ");
1784 switch (v >> 6) {
1785 case 0: printf("None\n"); break;
1786 case 1: printf("Spatial\n"); break;
1787 case 2: printf("Temporal\n"); break;
1788 case 3: printf("Spatial and Temporal\n"); break;
1790 printf(" Direct Drive: %s\n", (v & 0x20) ? "Yes" : "No");
1791 printf(" Overdrive %srecommended\n", (v & 0x10) ? "not " : "");
1792 printf(" Deinterlacing: %s\n", (v & 0x08) ? "Yes" : "No");
1794 v = x[0x0f];
1795 printf(" Audio Support: %s\n", (v & 0x80) ? "Yes" : "No");
1796 printf(" Separate Audio Inputs Provided: %s\n", (v & 0x40) ? "Yes" : "No");
1797 printf(" Audio Input Override: %s\n", (v & 0x20) ? "Yes" : "No");
1798 v = x[0x10];
1799 if (v)
1800 printf(" Audio Delay: %s%u ms\n", (v & 0x80) ? "" : "-", (v & 0x7f) * 2);
1801 else
1802 printf(" Audio Delay: no information provided\n");
1803 v = x[0x11];
1804 printf(" Frame Rate/Mode Conversion: ");
1805 switch (v >> 6) {
1806 case 0: printf("None\n"); break;
1807 case 1: printf("Single Buffering\n"); break;
1808 case 2: printf("Double Buffering\n"); break;
1809 case 3: printf("Advanced Frame Rate Conversion\n"); break;
1811 if (v & 0x3f)
1812 printf(" Frame Rate Range: %u fps +/- %u fps\n",
1813 x[0x12], v & 0x3f);
1814 else
1815 printf(" Nominal Frame Rate: %u fps\n", x[0x12]);
1816 printf(" Color Bit Depth: %u @ interface, %u @ display\n",
1817 (x[0x13] >> 4) + 1, (x[0x13] & 0xf) + 1);
1818 v = x[0x15] & 3;
1819 if (v) {
1820 printf(" Additional Primary Chromaticities:\n");
1821 unsigned col_x = (x[0x16] << 2) | (x[0x14] >> 6);
1822 unsigned col_y = (x[0x17] << 2) | ((x[0x14] >> 4) & 3);
1823 printf(" Primary 4: 0.%04u, 0.%04u\n",
1824 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1825 if (v > 1) {
1826 col_x = (x[0x18] << 2) | ((x[0x14] >> 2) & 3);
1827 col_y = (x[0x19] << 2) | (x[0x14] & 3);
1828 printf(" Primary 5: 0.%04u, 0.%04u\n",
1829 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1830 if (v > 2) {
1831 col_x = (x[0x1a] << 2) | (x[0x15] >> 6);
1832 col_y = (x[0x1b] << 2) | ((x[0x15] >> 4) & 3);
1833 printf(" Primary 6: 0.%04u, 0.%04u\n",
1834 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1839 v = x[0x1c];
1840 printf(" Response Time %s: %u ms\n",
1841 (v & 0x80) ? "White -> Black" : "Black -> White", v & 0x7f);
1842 v = x[0x1d];
1843 printf(" Overscan: %u%% x %u%%\n", v >> 4, v & 0xf);
1846 static double decode_uchar_as_double(unsigned char x)
1848 signed char s = (signed char)x;
1850 return s / 64.0;
1853 void edid_state::cta_rcdb(const unsigned char *x, unsigned length)
1855 unsigned spm = ((x[3] << 16) | (x[2] << 8) | x[1]);
1856 unsigned i;
1858 if (length < 4) {
1859 fail("Empty Data Block with length %u.\n", length);
1860 return;
1863 if ((x[0] & 0x20) && !cta.has_sldb)
1864 fail("'SLD' flag is 1, but no Speaker Location Data Block is found.\n");
1865 else if (!(x[0] & 0x20) && cta.has_sldb)
1866 fail("'SLD' flag is 0, but a Speaker Location Data Block is present.\n");
1868 if (x[0] & 0x40) {
1869 printf(" Speaker count: %u\n", (x[0] & 0x1f) + 1);
1870 } else {
1871 if (x[0] & 0x1f)
1872 fail("'Speaker' flag is 0, but 'Speaker Count' is != 0.\n");
1873 if (x[0] & 0x20)
1874 fail("'SLD' flag is 1, but 'Speaker' is 0.\n");
1877 printf(" Speaker Presence Mask:\n");
1878 for (i = 0; i < ARRAY_SIZE(speaker_map); i++) {
1879 if ((spm >> i) & 1)
1880 printf(" %s\n", speaker_map[i]);
1883 if ((x[0] & 0xa0) == 0x80)
1884 fail("'Display' flag set, but not the 'SLD' flag.\n");
1886 bool valid_max = cta.preparsed_sld_has_coord || (x[0] & 0x80);
1888 if (valid_max && length >= 7) {
1889 printf(" Xmax: %u dm\n", x[4]);
1890 printf(" Ymax: %u dm\n", x[5]);
1891 printf(" Zmax: %u dm\n", x[6]);
1892 } else if (!valid_max && length >= 7) {
1893 // The RCDB should have been truncated.
1894 warn("'Display' flag is 0 and 'Coord' is 0 for all SLDs, but the Max coordinates are still present.\n");
1896 if ((x[0] & 0x80) && length >= 10) {
1897 printf(" DisplayX: %.3f * Xmax\n", decode_uchar_as_double(x[7]));
1898 printf(" DisplayY: %.3f * Ymax\n", decode_uchar_as_double(x[8]));
1899 printf(" DisplayZ: %.3f * Zmax\n", decode_uchar_as_double(x[9]));
1900 } else if (!(x[0] & 0x80) && length >= 10) {
1901 // The RCDB should have been truncated.
1902 warn("'Display' flag is 0, but the Display coordinates are still present.\n");
1906 static const struct {
1907 const char *name;
1908 double x, y, z;
1909 } speaker_location[] = {
1910 { "FL - Front Left", -1, 1, 0 },
1911 { "FR - Front Right", 1, 1, 0 },
1912 { "FC - Front Center", 0, 1, 0 },
1913 { "LFE1 - Low Frequency Effects 1", -0.5, 1, -1 },
1914 { "BL - Back Left", -1, -1, 0 },
1915 { "BR - Back Right", 1, -1, 0 },
1916 { "FLC - Front Left of Center", -0.5, 1, 0 },
1917 { "FRC - Front Right of Center", 0.5, 1, 0 },
1918 { "BC - Back Center", 0, -1, 0 },
1919 { "LFE2 - Low Frequency Effects 2", 0.5, 1, -1 },
1920 { "SiL - Side Left", -1, 1.0/3.0, 0 },
1921 { "SiR - Side Right", 1, 1.0/3.0, 0 },
1922 { "TpFL - Top Front Left", -1, 1, 1 },
1923 { "TpFR - Top Front Right", 1, 1, 1 },
1924 { "TpFC - Top Front Center", 0, 1, 1 },
1925 { "TpC - Top Center", 0, 0, 1 },
1926 { "TpBL - Top Back Left", -1, -1, 1 },
1927 { "TpBR - Top Back Right", 1, -1, 1 },
1928 { "TpSiL - Top Side Left", -1, 0, 1 },
1929 { "TpSiR - Top Side Right", 1, 0, 1 },
1930 { "TpBC - Top Back Center", 0, -1, 1 },
1931 { "BtFC - Bottom Front Center", 0, 1, -1 },
1932 { "BtFL - Bottom Front Left", -1, 1, -1 },
1933 { "BtFR - Bottom Front Right", 1, 1, -1 },
1934 { "FLW - Front Left Wide", -1, 2.0/3.0, 0 },
1935 { "FRW - Front Right Wide", 1, 2.0/3.0, 0 },
1936 { "LS - Left Surround", -1, 0, 0 },
1937 { "RS - Right Surround", 1, 0, 0 },
1940 void edid_state::cta_sldb(const unsigned char *x, unsigned length)
1942 if (length < 2) {
1943 fail("Empty Data Block with length %u.\n", length);
1944 return;
1947 unsigned active_cnt = 0;
1948 unsigned channel_is_active = 0;
1950 while (length >= 2) {
1951 printf(" Channel: %u (%sactive)\n", x[0] & 0x1f,
1952 (x[0] & 0x20) ? "" : "not ");
1953 if (x[0] & 0x20) {
1954 if (channel_is_active & (1U << (x[0] & 0x1f)))
1955 fail("Channel Index %u was already marked 'Active'.\n",
1956 x[0] & 0x1f);
1957 channel_is_active |= 1U << (x[0] & 0x1f);
1958 active_cnt++;
1960 if ((x[1] & 0x1f) < ARRAY_SIZE(speaker_location))
1961 printf(" Speaker: %s\n", speaker_location[x[1] & 0x1f].name);
1962 if (length >= 5 && (x[0] & 0x40)) {
1963 printf(" X: %.3f * Xmax\n", decode_uchar_as_double(x[2]));
1964 printf(" Y: %.3f * Ymax\n", decode_uchar_as_double(x[3]));
1965 printf(" Z: %.3f * Zmax\n", decode_uchar_as_double(x[4]));
1966 length -= 3;
1967 x += 3;
1968 } else {
1969 printf(" X: %.3f * Xmax (approximately)\n", speaker_location[x[1] & 0x1f].x);
1970 printf(" Y: %.3f * Ymax (approximately)\n", speaker_location[x[1] & 0x1f].y);
1971 printf(" Z: %.3f * Zmax (approximately)\n", speaker_location[x[1] & 0x1f].z);
1974 length -= 2;
1975 x += 2;
1977 if (active_cnt != cta.preparsed_speaker_count)
1978 fail("There are %u active speakers, but 'Speaker Count' is %u.\n",
1979 active_cnt, cta.preparsed_speaker_count);
1982 void edid_state::cta_preparse_sldb(const unsigned char *x, unsigned length)
1984 cta.has_sldb = true;
1985 while (length >= 2) {
1986 if (length >= 5 && (x[0] & 0x40)) {
1987 cta.preparsed_sld_has_coord = true;
1988 return;
1990 length -= 2;
1991 x += 2;
1995 void edid_state::cta_vcdb(const unsigned char *x, unsigned length)
1997 unsigned char d = x[0];
1999 cta.has_vcdb = true;
2000 if (length < 1) {
2001 fail("Empty Data Block with length %u.\n", length);
2002 return;
2004 printf(" YCbCr quantization: %s\n",
2005 (d & 0x80) ? "Selectable (via AVI YQ)" : "No Data");
2006 printf(" RGB quantization: %s\n",
2007 (d & 0x40) ? "Selectable (via AVI Q)" : "No Data");
2009 * If this bit is not set then that will result in interoperability
2010 * problems (specifically with PCs/laptops) that quite often do not
2011 * follow the default rules with respect to RGB Quantization Range
2012 * handling.
2014 * Starting with the CTA-861-H spec this bit is now required to be
2015 * 1 for new designs.
2017 if (!(d & 0x40))
2018 fail("Set Selectable RGB Quantization to avoid interop issues.\n");
2020 * Since most YCbCr formats use limited range, the interop issues are
2021 * less noticable than for RGB formats.
2023 * Starting with the CTA-861-H spec this bit is now required to be
2024 * 1 for new designs, but just warn about it (for now).
2026 if ((cta.byte3 & 0x30) && !(d & 0x80))
2027 warn("Set Selectable YCbCr Quantization to avoid interop issues.\n");
2029 unsigned char s_pt = (d >> 4) & 0x03;
2030 unsigned char s_it = (d >> 2) & 0x03;
2031 unsigned char s_ce = d & 0x03;
2033 printf(" PT scan behavior: ");
2034 switch (s_pt) {
2035 case 0: printf("No Data\n"); break;
2036 case 1: printf("Always Overscanned\n"); break;
2037 case 2: printf("Always Underscanned\n"); break;
2038 case 3: printf("Supports both over- and underscan\n"); break;
2040 printf(" IT scan behavior: ");
2041 switch (s_it) {
2042 case 0: printf("IT video formats not supported\n"); break;
2043 case 1:
2044 printf("Always Overscanned\n");
2045 // See Table 52 of CTA-861-G for a description of Byte 3
2046 if (cta.byte3 & 0x80)
2047 fail("IT video formats are always overscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to underscanned.\n");
2048 break;
2049 case 2:
2050 printf("Always Underscanned\n");
2051 // See Table 52 of CTA-861-G for a description of Byte 3
2052 if (!(cta.byte3 & 0x80))
2053 fail("IT video formats are always underscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to overscanned.\n");
2054 break;
2055 case 3: printf("Supports both over- and underscan\n"); break;
2057 if (s_it < 2)
2058 warn("IT scan behavior is expected to support underscanned.\n");
2059 printf(" CE scan behavior: ");
2060 switch (s_ce) {
2061 case 0: printf("CE video formats not supported\n"); break;
2062 case 1: printf("Always Overscanned\n"); break;
2063 case 2: printf("Always Underscanned\n"); break;
2064 case 3: printf("Supports both over- and underscan\n"); break;
2066 if (s_ce == 0)
2067 warn("'CE video formats not supported' makes no sense.\n");
2068 else if (s_pt == s_it && s_pt == s_ce)
2069 warn("S_PT is equal to S_IT and S_CE, so should be set to 0 instead.\n");
2072 static const char *colorimetry1_map[] = {
2073 "xvYCC601",
2074 "xvYCC709",
2075 "sYCC601",
2076 "opYCC601",
2077 "opRGB",
2078 "BT2020cYCC",
2079 "BT2020YCC",
2080 "BT2020RGB",
2083 static const char *colorimetry2_map[] = {
2084 "Gamut Boundary Description Metadata Profile P0",
2085 "Reserved Gamut Boundary Description Metadata Profile P1",
2086 "Reserved Gamut Boundary Description Metadata Profile P2",
2087 "Reserved Gamut Boundary Description Metadata Profile P3",
2088 "Default",
2089 "sRGB",
2090 "ICtCp",
2091 "ST2113RGB",
2094 void edid_state::cta_colorimetry_block(const unsigned char *x, unsigned length)
2096 unsigned i;
2098 if (length < 2) {
2099 fail("Empty Data Block with length %u.\n", length);
2100 return;
2102 for (i = 0; i < ARRAY_SIZE(colorimetry1_map); i++)
2103 if (x[0] & (1 << i))
2104 printf(" %s\n", colorimetry1_map[i]);
2105 // Bits MD0-MD3 are used to indicate which HDMI Gamut Boundary Description
2106 // Metadata Profiles are supported.
2108 // HDMI 1.3a in section 5.3.12 describes 4 possible profiles, but it marks
2109 // P3 as 'defined in a future specification'.
2111 // HDMI 1.4b, however, only specifies profile P0 in section 8.3.3. And I've
2112 // only seen P0 in practice. My assumption is that profiles P1-P3 are never
2113 // used, and so these bits should be 0.
2114 if (x[1] & 0xe)
2115 fail("Reserved bits MD1-MD3 must be 0.\n");
2116 for (i = 0; i < ARRAY_SIZE(colorimetry2_map); i++)
2117 if (x[1] & (1 << i))
2118 printf(" %s\n", colorimetry2_map[i]);
2119 // The sRGB bit (added in CTA-861.6) allows sources to explicitly
2120 // signal sRGB colorimetry. Without this the default colorimetry
2121 // of an RGB video is either sRGB or defaultRGB. It depends on the
2122 // Source which is used, and the Sink has no idea what it is getting.
2124 // For proper compatibility with PCs enabling sRGB support is
2125 // desirable.
2126 if (!base.uses_srgb && !(x[1] & 0x20))
2127 warn("Set the sRGB colorimetry bit to avoid interop issues.\n");
2130 static const char *eotf_map[] = {
2131 "Traditional gamma - SDR luminance range",
2132 "Traditional gamma - HDR luminance range",
2133 "SMPTE ST2084",
2134 "Hybrid Log-Gamma",
2137 static void cta_hdr_static_metadata_block(const unsigned char *x, unsigned length)
2139 unsigned i;
2141 if (length < 2) {
2142 fail("Empty Data Block with length %u.\n", length);
2143 return;
2145 printf(" Electro optical transfer functions:\n");
2146 for (i = 0; i < 6; i++) {
2147 if (x[0] & (1 << i)) {
2148 if (i < ARRAY_SIZE(eotf_map)) {
2149 printf(" %s\n", eotf_map[i]);
2150 } else {
2151 printf(" Unknown (%u)\n", i);
2152 fail("Unknown EOTF (%u).\n", i);
2156 printf(" Supported static metadata descriptors:\n");
2157 for (i = 0; i < 8; i++) {
2158 if (x[1] & (1 << i))
2159 printf(" Static metadata type %u\n", i + 1);
2162 if (length >= 3)
2163 printf(" Desired content max luminance: %u (%.3f cd/m^2)\n",
2164 x[2], 50.0 * pow(2, x[2] / 32.0));
2166 if (length >= 4)
2167 printf(" Desired content max frame-average luminance: %u (%.3f cd/m^2)\n",
2168 x[3], 50.0 * pow(2, x[3] / 32.0));
2170 if (length >= 5)
2171 printf(" Desired content min luminance: %u (%.3f cd/m^2)\n",
2172 x[4], (50.0 * pow(2, x[2] / 32.0)) * pow(x[4] / 255.0, 2) / 100.0);
2175 static void cta_hdr_dyn_metadata_block(const unsigned char *x, unsigned length)
2177 if (length < 3) {
2178 fail("Empty Data Block with length %u.\n", length);
2179 return;
2181 while (length >= 3) {
2182 unsigned type_len = x[0];
2183 unsigned type = x[1] | (x[2] << 8);
2185 if (length < type_len + 1)
2186 return;
2187 printf(" HDR Dynamic Metadata Type %u\n", type);
2188 switch (type) {
2189 case 1:
2190 case 4:
2191 if (type_len > 2)
2192 printf(" Version: %u\n", x[3] & 0xf);
2193 break;
2194 case 2:
2195 if (type_len > 2) {
2196 unsigned version = x[3] & 0xf;
2197 printf(" Version: %u\n", version);
2198 if (version >= 1) {
2199 if (x[3] & 0x10) printf(" Supports SL-HDR1 (ETSI TS 103 433-1)\n");
2200 if (x[3] & 0x20) printf(" Supports SL-HDR2 (ETSI TS 103 433-2)\n");
2201 if (x[3] & 0x40) printf(" Supports SL-HDR3 (ETSI TS 103 433-3)\n");
2204 break;
2205 default:
2206 break;
2208 length -= type_len + 1;
2209 x += type_len + 1;
2213 static const char *infoframe_types[] = {
2214 NULL,
2215 "Vendor-Specific",
2216 "Auxiliary Video Information",
2217 "Source Product Description",
2218 "Audio",
2219 "MPEG Source",
2220 "NTSC VBI",
2221 "Dynamic Range and Mastering",
2224 static void cta_ifdb(const unsigned char *x, unsigned length)
2226 unsigned len_hdr = x[0] >> 5;
2228 if (length < 2) {
2229 fail("Empty Data Block with length %u.\n", length);
2230 return;
2232 printf(" VSIFs: %u\n", x[1]);
2233 if (length < len_hdr + 2)
2234 return;
2235 length -= len_hdr + 2;
2236 x += len_hdr + 2;
2237 while (length > 0) {
2238 int payload_len = x[0] >> 5;
2239 unsigned char type = x[0] & 0x1f;
2241 const char *name = NULL;
2242 if (type < ARRAY_SIZE(infoframe_types))
2243 name = infoframe_types[type];
2244 if (!name)
2245 name = "Unknown";
2246 printf(" %s InfoFrame (%u)", name, type);
2248 if (type == 1 && length >= 4) {
2249 unsigned oui = (x[3] << 16) | (x[2] << 8) | x[1];
2251 printf(", OUI %s\n", ouitohex(oui).c_str());
2252 x += 4;
2253 length -= 4;
2254 } else {
2255 printf("\n");
2256 x++;
2257 length--;
2259 x += payload_len;
2260 length -= payload_len;
2264 void edid_state::cta_displayid_type_7(const unsigned char *x, unsigned length)
2266 check_displayid_datablock_revision(x[0], 0x00, 2);
2268 if (length < 21U + ((x[0] & 0x70) >> 4)) {
2269 fail("Empty Data Block with length %u.\n", length);
2270 return;
2272 parse_displayid_type_1_7_timing(x + 1, true, 2, true);
2275 void edid_state::cta_displayid_type_8(const unsigned char *x, unsigned length)
2277 check_displayid_datablock_revision(x[0], 0xe8, 1);
2278 if (length < ((x[0] & 0x08) ? 3 : 2)) {
2279 fail("Empty Data Block with length %u.\n", length);
2280 return;
2283 unsigned sz = (x[0] & 0x08) ? 2 : 1;
2284 unsigned type = x[0] >> 6;
2286 if (type) {
2287 fail("Only code type 0 is supported.\n");
2288 return;
2291 if (x[0] & 0x20)
2292 printf(" Also supports YCbCr 4:2:0\n");
2294 x++;
2295 length--;
2296 for (unsigned i = 0; i < length / sz; i++) {
2297 unsigned id = x[i * sz];
2299 if (sz == 2)
2300 id |= x[i * sz + 1] << 8;
2301 parse_displayid_type_4_8_timing(type, id, true);
2305 void edid_state::cta_displayid_type_10(const unsigned char *x, unsigned length)
2307 check_displayid_datablock_revision(x[0], 0x70);
2308 if (length < 7U + ((x[0] & 0x70) >> 4)) {
2309 fail("Empty Data Block with length %u.\n", length);
2310 return;
2313 unsigned sz = 6U + ((x[0] & 0x70) >> 4);
2314 x++;
2315 length--;
2316 for (unsigned i = 0; i < length / sz; i++)
2317 parse_displayid_type_10_timing(x + i * sz, sz, true);
2320 static void cta_hdmi_audio_block(const unsigned char *x, unsigned length)
2322 unsigned num_descs;
2324 if (length < 2) {
2325 fail("Empty Data Block with length %u.\n", length);
2326 return;
2328 if (x[0] & 3)
2329 printf(" Max Stream Count: %u\n", (x[0] & 3) + 1);
2330 if (x[0] & 4)
2331 printf(" Supports MS NonMixed\n");
2333 num_descs = x[1] & 7;
2334 if (num_descs == 0)
2335 return;
2336 length -= 2;
2337 x += 2;
2338 while (length >= 4) {
2339 if (length > 4) {
2340 unsigned format = x[0] & 0xf;
2342 printf(" %s, max channels %u\n", audio_format(format).c_str(),
2343 (x[1] & 0x1f)+1);
2344 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
2345 (x[2] & 0x40) ? " 192" : "",
2346 (x[2] & 0x20) ? " 176.4" : "",
2347 (x[2] & 0x10) ? " 96" : "",
2348 (x[2] & 0x08) ? " 88.2" : "",
2349 (x[2] & 0x04) ? " 48" : "",
2350 (x[2] & 0x02) ? " 44.1" : "",
2351 (x[2] & 0x01) ? " 32" : "");
2352 if (format == 1)
2353 printf(" Supported sample sizes (bits):%s%s%s\n",
2354 (x[3] & 0x04) ? " 24" : "",
2355 (x[3] & 0x02) ? " 20" : "",
2356 (x[3] & 0x01) ? " 16" : "");
2357 } else {
2358 unsigned sad = ((x[2] << 16) | (x[1] << 8) | x[0]);
2359 unsigned i;
2361 switch (x[3] >> 4) {
2362 case 1:
2363 printf(" Speaker Allocation for 10.2 channels:\n");
2364 break;
2365 case 2:
2366 printf(" Speaker Allocation for 22.2 channels:\n");
2367 break;
2368 case 3:
2369 printf(" Speaker Allocation for 30.2 channels:\n");
2370 break;
2371 default:
2372 printf(" Unknown Speaker Allocation (0x%02x)\n", x[3] >> 4);
2373 return;
2376 for (i = 0; i < ARRAY_SIZE(speaker_map); i++) {
2377 if ((sad >> i) & 1)
2378 printf(" %s\n", speaker_map[i]);
2381 length -= 4;
2382 x += 4;
2386 void edid_state::cta_block(const unsigned char *x, std::vector<unsigned> &found_tags)
2388 unsigned length = x[0] & 0x1f;
2389 unsigned tag = (x[0] & 0xe0) >> 5;
2390 unsigned extended = (tag == 0x07) ? 1 : 0;
2392 x++;
2393 if (extended && length) {
2394 tag <<= 8;
2395 tag |= x[0];
2396 length--;
2397 x++;
2400 bool dooutputname = true;
2401 bool audio_block = false;
2402 data_block.clear();
2404 switch (tag) {
2405 case 0x01: data_block = "Audio Data Block"; audio_block = true; break;
2406 case 0x02: data_block = "Video Data Block"; break;
2407 case 0x03: data_block = "Vendor-Specific Data Block"; break;
2408 case 0x04: data_block = "Speaker Allocation Data Block"; audio_block = true; break;
2409 case 0x05: data_block = "VESA Display Transfer Characteristics Data Block"; break;
2410 case 0x06: data_block = "Video Format Data Block"; break;
2411 case 0x07: data_block = "Unknown CTA-861 Data Block (extended tag truncated)"; break;
2413 case 0x700: data_block = "Video Capability Data Block"; break;
2414 case 0x701: data_block = "Vendor-Specific Video Data Block"; break;
2415 case 0x702: data_block = "VESA Video Display Device Data Block"; break;
2416 case 0x703: data_block = "VESA Video Timing Block Extension"; break;
2417 case 0x704: data_block = "Reserved for HDMI Video Data Block"; break;
2418 case 0x705: data_block = "Colorimetry Data Block"; break;
2419 case 0x706: data_block = "HDR Static Metadata Data Block"; break;
2420 case 0x707: data_block = "HDR Dynamic Metadata Data Block"; break;
2421 case 0x708: data_block = "Native Video Resolution Data Block"; break;
2423 case 0x70d: data_block = "Video Format Preference Data Block"; break;
2424 case 0x70e: data_block = "YCbCr 4:2:0 Video Data Block"; break;
2425 case 0x70f: data_block = "YCbCr 4:2:0 Capability Map Data Block"; break;
2426 case 0x710: data_block = "Reserved for CTA-861 Miscellaneous Audio Fields"; break;
2427 case 0x711: data_block = "Vendor-Specific Audio Data Block"; audio_block = true; break;
2428 case 0x712: data_block = "HDMI Audio Data Block"; audio_block = true; break;
2429 case 0x713: data_block = "Room Configuration Data Block"; audio_block = true; break;
2430 case 0x714: data_block = "Speaker Location Data Block"; audio_block = true; break;
2432 case 0x720: data_block = "InfoFrame Data Block"; break;
2434 case 0x722: data_block = "DisplayID Type VII Video Timing Data Block"; break;
2435 case 0x723: data_block = "DisplayID Type VIII Video Timing Data Block"; break;
2436 case 0x72a: data_block = "DisplayID Type X Video Timing Data Block"; break;
2438 case 0x778: data_block = "HDMI Forum EDID Extension Override Data Block"; break;
2439 case 0x779: data_block = "HDMI Forum Sink Capability Data Block"; break;
2441 default:
2442 std::string unknown_name;
2443 if (tag < 0x700) unknown_name = "Unknown CTA-861 Data Block";
2444 else if (tag < 0x70d) unknown_name = "Unknown CTA-861 Video-Related Data Block";
2445 else if (tag < 0x720) unknown_name = "Unknown CTA-861 Audio-Related Data Block";
2446 else if (tag < 0x778) unknown_name = "Unknown CTA-861 Data Block";
2447 else if (tag < 0x780) unknown_name = "Unknown CTA-861 HDMI-Related Data Block";
2448 else unknown_name = "Unknown CTA-861 Data Block";
2449 unknown_name += std::string(" (") + (extended ? "extended " : "") + "tag " + utohex(tag & 0xff) + ", length " + std::to_string(length) + ")";
2450 printf(" %s:\n", unknown_name.c_str());
2451 warn("%s.\n", unknown_name.c_str());
2452 break;
2455 switch (tag) {
2456 case 0x03:
2457 case 0x701:
2458 case 0x711: {
2459 unsigned ouinum;
2461 data_block_oui(data_block, x, length, &ouinum);
2462 x += (length < 3) ? length : 3;
2463 length -= (length < 3) ? length : 3;
2464 dooutputname = false;
2465 tag |= ouinum;
2466 break;
2470 if (dooutputname && data_block.length())
2471 printf(" %s:\n", data_block.c_str());
2473 switch (tag) {
2474 case 0x04:
2475 case 0x05:
2476 case 0x700:
2477 case 0x702:
2478 case 0x705:
2479 case 0x706:
2480 case 0x708:
2481 case 0x70d:
2482 case 0x70f:
2483 case 0x712:
2484 case 0x713:
2485 case 0x778:
2486 case 0x779:
2487 if (std::find(found_tags.begin(), found_tags.end(), tag) != found_tags.end())
2488 fail("Only one instance of this Data Block is allowed.\n");
2489 break;
2492 // See Table 52 of CTA-861-G for a description of Byte 3
2493 if (audio_block && !(cta.byte3 & 0x40))
2494 fail("Audio information is present, but bit 6 of Byte 3 of the CTA-861 Extension header indicates no Basic Audio support.\n");
2496 switch (tag) {
2497 case 0x01: cta_audio_block(x, length); break;
2498 case 0x02: cta_svd(x, length, false); break;
2499 case 0x03|kOUI_HDMI:
2500 cta_hdmi_block(x, length);
2501 // The HDMI OUI is present, so this EDID represents an HDMI
2502 // interface. And HDMI interfaces must use EDID version 1.3
2503 // according to the HDMI Specification, so check for this.
2504 if (base.edid_minor != 3)
2505 fail("The HDMI Specification requires EDID 1.3 instead of 1.%u.\n",
2506 base.edid_minor);
2507 break;
2508 case 0x03|kOUI_HDMIForum:
2509 if (cta.previous_cta_tag != (0x03|kOUI_HDMI))
2510 fail("HDMI Forum VSDB did not immediately follow the HDMI VSDB.\n");
2511 if (cta.have_hf_scdb || cta.have_hf_vsdb)
2512 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2513 cta_hf_scdb(x, length);
2514 cta.have_hf_vsdb = true;
2515 break;
2516 case 0x03|kOUI_AMD: cta_amd(x, length); break;
2517 case 0x03|kOUI_Microsoft: if (length != 0x12) goto dodefault; cta_microsoft(x, length); break;
2518 case 0x04: cta_sadb(x, length); break;
2519 case 0x05: cta_vesa_dtcdb(x, length); break;
2520 case 0x06: cta_vfdb(x, length); break;
2521 case 0x07: fail("Extended tag cannot have zero length.\n"); break;
2522 case 0x700: cta_vcdb(x, length); break;
2523 case 0x701|kOUI_HDR10: cta_hdr10plus(x, length); break;
2524 case 0x701|kOUI_Dolby: cta_dolby_video(x, length); break;
2525 // 0x701|kOUI_Apple: this almost certainly contains 'BLC Info/Corrections',
2526 // since the data (spread out over two VSDBs) is very similar to what is seen
2527 // in DisplayID blocks. Since I don't know how to parse this data, we still
2528 // default to a hex dump, but I mention this here in case data on how to
2529 // parse this becomes available.
2530 case 0x702: cta_vesa_vdddb(x, length); break;
2531 case 0x705: cta_colorimetry_block(x, length); break;
2532 case 0x706: cta_hdr_static_metadata_block(x, length); break;
2533 case 0x707: cta_hdr_dyn_metadata_block(x, length); break;
2534 case 0x708: cta_nvrdb(x, length); return;
2535 case 0x70d: cta_vfpdb(x, length); break;
2536 case 0x70e: cta_svd(x, length, true); break;
2537 case 0x70f: cta_y420cmdb(x, length); break;
2538 case 0x711|kOUI_Dolby: cta_dolby_audio(x, length); break;
2539 case 0x712: cta_hdmi_audio_block(x, length); break;
2540 case 0x713: cta_rcdb(x, length); break;
2541 case 0x714: cta_sldb(x, length); break;
2542 case 0x720: cta_ifdb(x, length); break;
2543 case 0x722: cta_displayid_type_7(x, length); break;
2544 case 0x723: cta_displayid_type_8(x, length); break;
2545 case 0x72a: cta_displayid_type_10(x, length); break;
2546 case 0x778:
2547 cta_hf_eeodb(x, length);
2548 if (block_nr != 1)
2549 fail("Data Block can only be present in Block 1.\n");
2550 // This must be the first CTA-861 block
2551 if (cta.block_number > 0)
2552 fail("Data Block starts at a wrong offset.\n");
2553 break;
2554 case 0x779:
2555 if (cta.previous_cta_tag != (0x03|kOUI_HDMI))
2556 fail("HDMI Forum SCDB did not immediately follow the HDMI VSDB.\n");
2557 if (cta.have_hf_scdb || cta.have_hf_vsdb)
2558 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2559 if (length < 2) {
2560 data_block = std::string("HDMI Forum SCDB");
2561 fail("Invalid length %u < 2.\n", length);
2562 break;
2564 if (x[0] || x[1])
2565 printf(" Non-zero SCDB reserved fields!\n");
2566 cta_hf_scdb(x + 2, length - 2);
2567 cta.have_hf_scdb = true;
2568 break;
2569 dodefault:
2570 default:
2571 hex_block(" ", x, length);
2572 break;
2575 cta.block_number++;
2576 cta.previous_cta_tag = tag;
2577 found_tags.push_back(tag);
2580 void edid_state::preparse_cta_block(unsigned char *x)
2582 unsigned version = x[1];
2583 unsigned offset = x[2];
2585 if (offset >= 4) {
2586 const unsigned char *detailed;
2588 for (detailed = x + offset; detailed + 17 < x + 127; detailed += 18) {
2589 if (memchk(detailed, 18))
2590 break;
2591 if (detailed[0] || detailed[1])
2592 cta.preparsed_total_dtds++;
2596 if (version < 3)
2597 return;
2599 for (unsigned i = 4; i < offset; i += (x[i] & 0x1f) + 1) {
2600 bool for_ycbcr420 = false;
2601 unsigned oui;
2603 switch ((x[i] & 0xe0) >> 5) {
2604 case 0x03:
2605 oui = (x[i + 3] << 16) + (x[i + 2] << 8) + x[i + 1];
2606 if (oui == 0x000c03) {
2607 cta.has_hdmi = true;
2608 cta.preparsed_phys_addr = (x[i + 4] << 8) | x[i + 5];
2609 } else if ((oui == 0xca125c || oui == 0x5c12ca) &&
2610 (x[i] & 0x1f) == 0x15 && replace_unique_ids) {
2611 memset(x + i + 6, 0, 16);
2612 replace_checksum(x, EDID_PAGE_SIZE);
2614 break;
2615 case 0x06:
2616 if (!(x[i] & 0x1f) || cta.preparsed_first_vfd.rid)
2617 break;
2618 cta.preparsed_first_vfd = cta_parse_vfd(x + i + 2, (x[i + 1] & 3) + 1);
2619 break;
2620 case 0x07:
2621 if (x[i + 1] == 0x0d)
2622 cta.has_vfpdb = true;
2623 else if (x[i + 1] == 0x05)
2624 cta.has_cdb = true;
2625 else if (x[i + 1] == 0x08)
2626 cta.has_nvrdb = true;
2627 else if (x[i + 1] == 0x13 && (x[i + 2] & 0x40)) {
2628 cta.preparsed_speaker_count = 1 + (x[i + 2] & 0x1f);
2629 cta.preparsed_sld = x[i + 2] & 0x20;
2630 } else if (x[i + 1] == 0x14)
2631 cta_preparse_sldb(x + i + 2, (x[i] & 0x1f) - 1);
2632 else if (x[i + 1] == 0x22)
2633 cta.preparsed_total_vtdbs++;
2634 else if (x[i + 1] == 0x23) {
2635 cta.preparsed_has_t8vtdb = true;
2636 cta.preparsed_t8vtdb_dmt = x[i + 3];
2637 if (x[i + 2] & 0x08)
2638 cta.preparsed_t8vtdb_dmt |= x[i + 4] << 8;
2639 } else if (x[i + 1] == 0x2a)
2640 cta.preparsed_total_vtdbs +=
2641 ((x[i] & 0x1f) - 2) / (6 + ((x[i + 2] & 0x70) >> 4));
2642 else if (x[i + 1] == 0x78)
2643 cta.hf_eeodb_blocks = x[i + 2];
2644 if (x[i + 1] != 0x0e)
2645 continue;
2646 for_ycbcr420 = true;
2647 #ifdef __EMSCRIPTEN__
2648 [[clang::fallthrough]];
2649 #endif
2650 /* fall-through */
2651 case 0x02:
2652 for (unsigned j = 1 + for_ycbcr420; j <= (x[i] & 0x1f); j++) {
2653 unsigned char vic = x[i + j];
2655 if ((vic & 0x7f) <= 64)
2656 vic &= 0x7f;
2657 cta.preparsed_svds[for_ycbcr420].push_back(vic);
2658 cta.preparsed_has_vic[for_ycbcr420][vic] = true;
2660 break;
2665 void edid_state::parse_cta_block(const unsigned char *x)
2667 unsigned version = x[1];
2668 unsigned offset = x[2];
2669 const unsigned char *detailed;
2671 // See Table 52 of CTA-861-G for a description of Byte 3
2673 printf(" Revision: %u\n", version);
2674 if (version == 0)
2675 fail("Invalid CTA-861 Extension revision 0.\n");
2676 if (version == 2)
2677 fail("Deprecated CTA-861 Extension revision 2.\n");
2678 if (cta.has_hdmi && version != 3)
2679 fail("The HDMI Specification requires CTA Extension revision 3.\n");
2680 if (version > 3)
2681 warn("Unknown CTA-861 Extension revision %u.\n", version);
2683 if (version >= 1) do {
2684 if (version == 1 && x[3] != 0)
2685 fail("Non-zero byte 3.\n");
2687 if (offset < 4)
2688 break;
2690 if (version < 3 && ((offset - 4) / 8)) {
2691 printf(" 8-byte timing descriptors: %u\n", (offset - 4) / 8);
2692 fail("8-byte descriptors were never used.\n");
2695 if (version >= 2) {
2696 if (x[3] & 0x80)
2697 printf(" Underscans IT Video Formats by default\n");
2698 else
2699 warn("IT Video Formats are overscanned by default, but normally this should be underscanned.\n");
2700 if (x[3] & 0x40)
2701 printf(" Basic audio support\n");
2702 if (x[3] & 0x20)
2703 printf(" Supports YCbCr 4:4:4\n");
2704 if (x[3] & 0x10)
2705 printf(" Supports YCbCr 4:2:2\n");
2706 // Disable this test: this fails a lot of EDIDs, and there are
2707 // also some corner cases where you only want to receive 4:4:4
2708 // and refuse a fallback to 4:2:2.
2709 // if ((x[3] & 0x30) && (x[3] & 0x30) != 0x30)
2710 // msg(!cta.has_hdmi, "If YCbCr support is indicated, then both 4:2:2 and 4:4:4 %s be supported.\n",
2711 // cta.has_hdmi ? "shall" : "should");
2712 printf(" Native detailed modes: %u\n", x[3] & 0x0f);
2713 if (cta.block_number == 0)
2714 cta.byte3 = x[3];
2715 else if (x[3] != cta.byte3)
2716 fail("Byte 3 must be the same for all CTA-861 Extension Blocks.\n");
2717 if (cta.block_number == 0) {
2718 unsigned native_dtds = x[3] & 0x0f;
2720 cta.native_timings.clear();
2721 if (!native_dtds && !cta.has_vfpdb) {
2722 cta.first_svd_might_be_preferred = true;
2723 } else if (native_dtds > cta.preparsed_total_dtds) {
2724 fail("There are more Native DTDs (%u) than DTDs (%u).\n",
2725 native_dtds, cta.preparsed_total_dtds);
2727 if (native_dtds > cta.preparsed_total_dtds)
2728 native_dtds = cta.preparsed_total_dtds;
2729 for (unsigned i = 0; i < native_dtds; i++) {
2730 char type[16];
2732 sprintf(type, "DTD %3u", i + 1);
2733 cta.native_timings.push_back(timings_ext(i + 129, type));
2735 if (cta.has_hdmi && block_nr != (block_map.saw_block_1 ? 2 : 1))
2736 fail("The HDMI Specification requires that the first Extension Block (that is not a Block Map) is an CTA-861 Extension Block.\n");
2739 if (version >= 3) {
2740 unsigned i;
2742 for (i = 4; i < offset; i += (x[i] & 0x1f) + 1) {
2743 cta_block(x + i, cta.found_tags);
2746 data_block.clear();
2747 if (i != offset)
2748 fail("Offset is %u, but should be %u.\n", offset, i);
2751 data_block = "Detailed Timing Descriptors";
2752 base.seen_non_detailed_descriptor = false;
2753 bool first = true;
2754 for (detailed = x + offset; detailed + 17 < x + 127; detailed += 18) {
2755 if (memchk(detailed, 18))
2756 break;
2757 if (first) {
2758 first = false;
2759 printf(" %s:\n", data_block.c_str());
2761 detailed_block(detailed);
2763 unused_bytes = x + 127 - detailed;
2764 if (!memchk(detailed, unused_bytes)) {
2765 data_block = "Padding";
2766 fail("Contains non-zero bytes.\n");
2768 } while (0);
2770 data_block.clear();
2771 if (base.has_serial_number && base.has_serial_string)
2772 warn("Display Product Serial Number is set, so the Serial Number in the Base EDID should be 0.\n");
2773 if (!cta.has_vic_1 && !base.has_640x480p60_est_timing)
2774 fail("Required 640x480p60 timings are missing in the established timings"
2775 " and the SVD list (VIC 1).\n");
2776 if ((cta.supported_hdmi_vic_vsb_codes & cta.supported_hdmi_vic_codes) !=
2777 cta.supported_hdmi_vic_codes)
2778 fail("HDMI VIC Codes must have their CTA-861 VIC equivalents in the VSB.\n");
2779 if (!cta.has_vcdb)
2780 fail("Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.\n");
2781 if (!base.uses_srgb && !cta.has_cdb)
2782 warn("Add a Colorimetry Data Block with the sRGB colorimetry bit set to avoid interop issues.\n");
2785 void edid_state::cta_resolve_svr(timings_ext &t_ext)
2787 if (t_ext.svr() == 254) {
2788 t_ext.flags = cta.t8vtdb.flags;
2789 add_str(t_ext.flags, ">=CTA-861-H");
2790 t_ext.t = cta.t8vtdb.t;
2791 } else if (t_ext.svr() <= 144) {
2792 t_ext.flags = cta.vec_dtds[t_ext.svr() - 129].flags;
2793 t_ext.t = cta.vec_dtds[t_ext.svr() - 129].t;
2794 } else if (t_ext.svr() <= 160) {
2795 t_ext.flags = cta.vec_vtdbs[t_ext.svr() - 145].flags;
2796 add_str(t_ext.flags, ">=CTA-861-H");
2797 t_ext.t = cta.vec_vtdbs[t_ext.svr() - 145].t;
2798 } else if (t_ext.svr() <= 175) {
2799 t_ext.flags.clear();
2800 unsigned char rid = cta.preparsed_first_vfd.rid;
2801 t_ext.t = calc_ovt_mode(rids[rid].hact, rids[rid].vact,
2802 rids[rid].hratio, rids[rid].vratio,
2803 vf_rate_values[t_ext.svr() - 160]);
2804 t_ext.flags = ">=CTA-861.6";
2808 void edid_state::cta_resolve_svrs()
2810 for (vec_timings_ext::iterator iter = cta.preferred_timings_vfpdb.begin();
2811 iter != cta.preferred_timings_vfpdb.end(); ++iter) {
2812 if (iter->has_svr())
2813 cta_resolve_svr(*iter);
2816 for (vec_timings_ext::iterator iter = cta.native_timings.begin();
2817 iter != cta.native_timings.end(); ++iter) {
2818 if (iter->has_svr())
2819 cta_resolve_svr(*iter);
2822 for (vec_timings_ext::iterator iter = cta.native_timing_nvrdb.begin();
2823 iter != cta.native_timing_nvrdb.end(); ++iter) {
2824 if (iter->has_svr())
2825 cta_resolve_svr(*iter);
2829 void edid_state::check_cta_blocks()
2831 unsigned max_pref_prog_hact = 0;
2832 unsigned max_pref_prog_vact = 0;
2833 unsigned max_pref_ilace_hact = 0;
2834 unsigned max_pref_ilace_vact = 0;
2836 data_block = "CTA-861";
2837 for (vec_timings_ext::iterator iter = cta.preferred_timings.begin();
2838 iter != cta.preferred_timings.end(); ++iter) {
2839 if (iter->t.interlaced &&
2840 (iter->t.vact > max_pref_ilace_vact ||
2841 (iter->t.vact == max_pref_ilace_vact && iter->t.hact >= max_pref_ilace_hact))) {
2842 max_pref_ilace_hact = iter->t.hact;
2843 max_pref_ilace_vact = iter->t.vact;
2845 if (!iter->t.interlaced &&
2846 (iter->t.vact > max_pref_prog_vact ||
2847 (iter->t.vact == max_pref_prog_vact && iter->t.hact >= max_pref_prog_hact))) {
2848 max_pref_prog_hact = iter->t.hact;
2849 max_pref_prog_vact = iter->t.vact;
2852 for (vec_timings_ext::iterator iter = cta.preferred_timings_vfpdb.begin();
2853 iter != cta.preferred_timings_vfpdb.end(); ++iter) {
2854 if (iter->t.interlaced &&
2855 (iter->t.vact > max_pref_ilace_vact ||
2856 (iter->t.vact == max_pref_ilace_vact && iter->t.hact >= max_pref_ilace_hact))) {
2857 max_pref_ilace_hact = iter->t.hact;
2858 max_pref_ilace_vact = iter->t.vact;
2860 if (!iter->t.interlaced &&
2861 (iter->t.vact > max_pref_prog_vact ||
2862 (iter->t.vact == max_pref_prog_vact && iter->t.hact >= max_pref_prog_hact))) {
2863 max_pref_prog_hact = iter->t.hact;
2864 max_pref_prog_vact = iter->t.vact;
2868 unsigned native_prog = 0;
2869 unsigned native_prog_hact = 0;
2870 unsigned native_prog_vact = 0;
2871 bool native_prog_mixed_resolutions = false;
2872 unsigned native_ilace = 0;
2873 unsigned native_ilace_hact = 0;
2874 unsigned native_ilace_vact = 0;
2875 bool native_ilace_mixed_resolutions = false;
2876 unsigned native_nvrdb_hact = 0;
2877 unsigned native_nvrdb_vact = 0;
2879 for (vec_timings_ext::iterator iter = cta.native_timings.begin();
2880 iter != cta.native_timings.end(); ++iter) {
2881 if (iter->t.interlaced) {
2882 native_ilace++;
2883 if (!native_ilace_hact) {
2884 native_ilace_hact = iter->t.hact;
2885 native_ilace_vact = iter->t.vact;
2886 } else if (native_ilace_hact != iter->t.hact ||
2887 native_ilace_vact != iter->t.vact) {
2888 native_ilace_mixed_resolutions = true;
2890 } else {
2891 native_prog++;
2892 if (!native_prog_hact) {
2893 native_prog_hact = iter->t.hact;
2894 native_prog_vact = iter->t.vact;
2895 } else if (native_prog_hact != iter->t.hact ||
2896 native_prog_vact != iter->t.vact) {
2897 native_prog_mixed_resolutions = true;
2902 for (vec_timings_ext::iterator iter = cta.native_timing_nvrdb.begin();
2903 iter != cta.native_timing_nvrdb.end(); ++iter) {
2904 native_nvrdb_hact = iter->t.hact;
2905 native_nvrdb_vact = iter->t.vact;
2908 if (native_prog_mixed_resolutions)
2909 fail("Native progressive timings are a mix of several resolutions.\n");
2910 if (native_ilace_mixed_resolutions)
2911 fail("Native interlaced timings are a mix of several resolutions.\n");
2912 if (native_ilace && !native_prog)
2913 fail("A native interlaced timing is present, but not a native progressive timing.\n");
2914 if (!native_prog_mixed_resolutions && native_prog > 1)
2915 warn("Multiple native progressive timings are defined.\n");
2916 if (!native_ilace_mixed_resolutions && native_ilace > 1)
2917 warn("Multiple native interlaced timings are defined.\n");
2919 if (native_nvrdb_vact &&
2920 (max_pref_prog_vact > native_nvrdb_vact ||
2921 (max_pref_prog_vact == native_nvrdb_vact && max_pref_prog_hact > native_nvrdb_hact)))
2922 warn("Native video resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
2923 native_nvrdb_hact, native_nvrdb_vact,
2924 max_pref_prog_hact, max_pref_prog_vact);
2925 else if (!native_nvrdb_vact && !native_prog_mixed_resolutions && native_prog_vact &&
2926 (max_pref_prog_vact > native_prog_vact ||
2927 (max_pref_prog_vact == native_prog_vact && max_pref_prog_hact > native_prog_hact)))
2928 warn("Native progressive resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
2929 native_prog_hact, native_prog_vact,
2930 max_pref_prog_hact, max_pref_prog_vact);
2931 if (!native_ilace_mixed_resolutions && native_ilace_vact &&
2932 (max_pref_ilace_vact > native_ilace_vact ||
2933 (max_pref_ilace_vact == native_ilace_vact && max_pref_ilace_hact > native_ilace_hact)))
2934 warn("Native interlaced resolution of %ux%u is smaller than the max preferred interlaced resolution %ux%u.\n",
2935 native_ilace_hact, native_ilace_vact,
2936 max_pref_ilace_hact, max_pref_ilace_vact);
2938 if (dispid.native_width && native_prog_hact &&
2939 !native_prog_mixed_resolutions) {
2940 if (dispid.native_width != native_prog_hact ||
2941 dispid.native_height != native_prog_vact)
2942 fail("Mismatch between CTA-861 and DisplayID native progressive resolution.\n");