edid-decode: output correct unknown block length
[edid-decode.git] / parse-cta-block.cpp
blob0301036cad7563381d8782ec39e41df963f7c469
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 unsigned char edid_hdmi_mode_map[] = { 95, 94, 93, 98 };
194 unsigned char hdmi_vic_to_vic(unsigned char hdmi_vic)
196 if (hdmi_vic > 0 && hdmi_vic <= ARRAY_SIZE(edid_hdmi_mode_map))
197 return edid_hdmi_mode_map[hdmi_vic - 1];
198 return 0;
201 const struct timings *find_vic_id(unsigned char vic)
203 if (vic > 0 && vic <= ARRAY_SIZE(edid_cta_modes1))
204 return edid_cta_modes1 + vic - 1;
205 if (vic >= 193 && vic < ARRAY_SIZE(edid_cta_modes2) + 193)
206 return edid_cta_modes2 + vic - 193;
207 return NULL;
210 const struct timings *find_hdmi_vic_id(unsigned char hdmi_vic)
212 if (hdmi_vic > 0 && hdmi_vic <= ARRAY_SIZE(edid_hdmi_mode_map))
213 return find_vic_id(edid_hdmi_mode_map[hdmi_vic - 1]);
214 return NULL;
217 const struct timings *cta_close_match_to_vic(const timings &t, unsigned &vic)
219 for (vic = 1; vic <= ARRAY_SIZE(edid_cta_modes1); vic++) {
220 if (timings_close_match(t, edid_cta_modes1[vic - 1]))
221 return &edid_cta_modes1[vic - 1];
223 for (vic = 193; vic < ARRAY_SIZE(edid_cta_modes2) + 193; vic++) {
224 if (timings_close_match(t, edid_cta_modes1[vic - 193]))
225 return &edid_cta_modes1[vic - 193];
227 vic = 0;
228 return NULL;
231 void edid_state::cta_list_vics()
233 char type[16];
234 for (unsigned vic = 1; vic <= ARRAY_SIZE(edid_cta_modes1); vic++) {
235 sprintf(type, "VIC %3u", vic);
236 print_timings("", &edid_cta_modes1[vic - 1], type, "", false, false);
238 for (unsigned vic = 193; vic < ARRAY_SIZE(edid_cta_modes2) + 193; vic++) {
239 sprintf(type, "VIC %3u", vic);
240 print_timings("", &edid_cta_modes2[vic - 193], type, "", false, false);
244 void edid_state::cta_list_hdmi_vics()
246 for (unsigned i = 0; i < ARRAY_SIZE(edid_hdmi_mode_map); i++) {
247 unsigned vic = edid_hdmi_mode_map[i];
248 char type[16];
250 sprintf(type, "HDMI VIC %u", i + 1);
251 print_timings("", find_vic_id(vic), type, "", false, false);
255 static std::string audio_ext_format(unsigned char x)
257 if (x >= 1 && x <= 3)
258 fail("Obsolete Audio Ext Format 0x%02x.\n", x);
259 switch (x) {
260 case 1: return "HE AAC (Obsolete)";
261 case 2: return "HE AAC v2 (Obsolete)";
262 case 3: return "MPEG Surround (Obsolete)";
263 case 4: return "MPEG-4 HE AAC";
264 case 5: return "MPEG-4 HE AAC v2";
265 case 6: return "MPEG-4 AAC LC";
266 case 7: return "DRA";
267 case 8: return "MPEG-4 HE AAC + MPEG Surround";
268 case 10: return "MPEG-4 AAC LC + MPEG Surround";
269 case 11: return "MPEG-H 3D Audio";
270 case 12: return "AC-4";
271 case 13: return "L-PCM 3D Audio";
272 default: break;
274 fail("Unknown Audio Ext Format 0x%02x.\n", x);
275 return std::string("Unknown Audio Ext Format (") + utohex(x) + ")";
278 static std::string audio_format(unsigned char x)
280 switch (x) {
281 case 1: return "Linear PCM";
282 case 2: return "AC-3";
283 case 3: return "MPEG 1 (Layers 1 & 2)";
284 case 4: return "MPEG 1 Layer 3 (MP3)";
285 case 5: return "MPEG2 (multichannel)";
286 case 6: return "AAC LC";
287 case 7: return "DTS";
288 case 8: return "ATRAC";
289 case 9: return "One Bit Audio";
290 case 10: return "Enhanced AC-3 (DD+)";
291 case 11: return "DTS-HD";
292 case 12: return "MAT (MLP)";
293 case 13: return "DST";
294 case 14: return "WMA Pro";
295 default: break;
297 fail("Unknown Audio Format 0x%02x.\n", x);
298 return std::string("Unknown Audio Format (") + utohex(x) + ")";
301 static std::string mpeg_h_3d_audio_level(unsigned char x)
303 switch (x) {
304 case 0: return "Unspecified";
305 case 1: return "Level 1";
306 case 2: return "Level 2";
307 case 3: return "Level 3";
308 case 4: return "Level 4";
309 case 5: return "Level 5";
310 default: break;
312 fail("Unknown MPEG-H 3D Audio Level 0x%02x.\n", x);
313 return std::string("Unknown MPEG-H 3D Audio Level (") + utohex(x) + ")";
316 static void cta_audio_block(const unsigned char *x, unsigned length)
318 unsigned i, format, ext_format;
320 if (length % 3) {
321 fail("Broken CTA-861 audio block length %d.\n", length);
322 return;
325 for (i = 0; i < length; i += 3) {
326 format = (x[i] & 0x78) >> 3;
327 if (format == 0) {
328 printf(" Reserved (0x00)\n");
329 fail("Audio Format Code 0x00 is reserved.\n");
330 continue;
332 if (format != 15) {
333 ext_format = 0;
334 printf(" %s:\n", audio_format(format).c_str());
335 } else {
336 ext_format = (x[i + 2] & 0xf8) >> 3;
337 printf(" %s:\n", audio_ext_format(ext_format).c_str());
339 if (format != 15)
340 printf(" Max channels: %u\n", (x[i] & 0x07)+1);
341 else if (ext_format == 11)
342 printf(" MPEG-H 3D Audio Level: %s\n",
343 mpeg_h_3d_audio_level(x[i] & 0x07).c_str());
344 else if (ext_format == 13)
345 printf(" Max channels: %u\n",
346 (((x[i + 1] & 0x80) >> 3) | ((x[i] & 0x80) >> 4) |
347 (x[i] & 0x07))+1);
348 else
349 printf(" Max channels: %u\n", (x[i] & 0x07)+1);
351 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
352 (x[i+1] & 0x40) ? " 192" : "",
353 (x[i+1] & 0x20) ? " 176.4" : "",
354 (x[i+1] & 0x10) ? " 96" : "",
355 (x[i+1] & 0x08) ? " 88.2" : "",
356 (x[i+1] & 0x04) ? " 48" : "",
357 (x[i+1] & 0x02) ? " 44.1" : "",
358 (x[i+1] & 0x01) ? " 32" : "");
359 if (format == 1 || ext_format == 13) {
360 printf(" Supported sample sizes (bits):%s%s%s\n",
361 (x[i+2] & 0x04) ? " 24" : "",
362 (x[i+2] & 0x02) ? " 20" : "",
363 (x[i+2] & 0x01) ? " 16" : "");
364 } else if (format <= 8) {
365 printf(" Maximum bit rate: %u kb/s\n", x[i+2] * 8);
366 } else if (format == 10) {
367 // As specified by the "Dolby Audio and Dolby Atmos over HDMI"
368 // specification (v1.0).
369 if (x[i+2] & 1)
370 printf(" Supports Joint Object Coding\n");
371 if (x[i+2] & 2)
372 printf(" Supports Joint Object Coding with ACMOD28\n");
373 } else if (format == 12) {
374 if (x[i+2] & 1) {
375 printf(" Supports Dolby TrueHD, object audio PCM and channel-based PCM\n");
376 printf(" Hash calculation %srequired for object audio PCM or channel-based PCM\n",
377 (x[i+2] & 2) ? "not " : "");
378 } else {
379 printf(" Supports only Dolby TrueHD\n");
381 } else if (format == 14) {
382 printf(" Profile: %u\n", x[i+2] & 7);
383 } else if (format >= 9 && format <= 13) {
384 printf(" Audio Format Code dependent value: 0x%02x\n", x[i+2]);
385 } else if (ext_format == 11 && (x[i+2] & 1)) {
386 printf(" Supports MPEG-H 3D Audio Low Complexity Profile\n");
387 } else if ((ext_format >= 4 && ext_format <= 6) ||
388 ext_format == 8 || ext_format == 10) {
389 printf(" AAC audio frame lengths:%s%s\n",
390 (x[i+2] & 4) ? " 1024_TL" : "",
391 (x[i+2] & 2) ? " 960_TL" : "");
392 if (ext_format >= 8 && (x[i+2] & 1))
393 printf(" Supports %s signaled MPEG Surround data\n",
394 (x[i+2] & 1) ? "implicitly and explicitly" : "only implicitly");
395 if (ext_format == 6 && (x[i+2] & 1))
396 printf(" Supports 22.2ch System H\n");
401 void edid_state::cta_svd(const unsigned char *x, unsigned n, bool for_ycbcr420)
403 unsigned i;
405 for (i = 0; i < n; i++) {
406 const struct timings *t = NULL;
407 unsigned char svd = x[i];
408 unsigned char native;
409 unsigned char vic;
411 if ((svd & 0x7f) == 0)
412 continue;
414 if ((svd - 1) & 0x40) {
415 vic = svd;
416 native = 0;
417 } else {
418 vic = svd & 0x7f;
419 native = svd & 0x80;
422 t = find_vic_id(vic);
423 if (t) {
424 switch (vic) {
425 case 95:
426 cta.supported_hdmi_vic_vsb_codes |= 1 << 0;
427 break;
428 case 94:
429 cta.supported_hdmi_vic_vsb_codes |= 1 << 1;
430 break;
431 case 93:
432 cta.supported_hdmi_vic_vsb_codes |= 1 << 2;
433 break;
434 case 98:
435 cta.supported_hdmi_vic_vsb_codes |= 1 << 3;
436 break;
438 bool first_svd = cta.first_svd && !for_ycbcr420;
439 bool override_pref = first_svd && cta.first_svd_might_be_preferred;
441 char type[16];
442 sprintf(type, "VIC %3u", vic);
443 const char *flags = native ? "native" : "";
445 if (for_ycbcr420) {
446 struct timings tmp = *t;
447 tmp.ycbcr420 = true;
448 print_timings(" ", &tmp, type, flags);
449 } else {
450 print_timings(" ", t, type, flags);
452 if (override_pref) {
453 if (!cta.preferred_timings.empty()) {
454 if (match_timings(cta.preferred_timings[0].t, *t))
455 warn("For improved preferred timing interoperability, set 'Native detailed modes' to 1.\n");
456 else
457 warn("VIC %u is the preferred timing, overriding the first detailed timings. Is this intended?\n", vic);
459 cta.preferred_timings.insert(cta.preferred_timings.begin(),
460 timings_ext(*t, type, flags));
461 } else if (first_svd) {
462 cta.preferred_timings.push_back(timings_ext(*t, type, flags));
464 if (first_svd) {
465 cta.first_svd = false;
466 cta.first_svd_might_be_preferred = false;
468 if (native)
469 cta.native_timings.push_back(timings_ext(*t, type, flags));
470 } else {
471 printf(" Unknown (VIC %3u)\n", vic);
472 fail("Unknown VIC %u.\n", vic);
475 if (vic == 1 && !for_ycbcr420)
476 cta.has_vic_1 = 1;
477 if (++cta.vics[vic][for_ycbcr420] == 2)
478 fail("Duplicate %sVIC %u.\n", for_ycbcr420 ? "YCbCr 4:2:0 " : "", vic);
479 if (for_ycbcr420 && cta.preparsed_has_vic[0][vic])
480 fail("YCbCr 4:2:0-only VIC %u is also a regular VIC.\n", vic);
484 void edid_state::print_vic_index(const char *prefix, unsigned idx, const char *suffix, bool ycbcr420)
486 if (!suffix)
487 suffix = "";
488 if (idx < cta.preparsed_svds[0].size()) {
489 unsigned char vic = cta.preparsed_svds[0][idx];
490 const struct timings *t = find_vic_id(vic);
491 char buf[16];
493 sprintf(buf, "VIC %3u", vic);
495 if (t) {
496 struct timings tmp = *t;
497 tmp.ycbcr420 = ycbcr420;
498 print_timings(prefix, &tmp, buf, suffix);
499 } else {
500 printf("%sUnknown (%s%s%s)\n", prefix, buf,
501 *suffix ? ", " : "", suffix);
503 } else {
504 // Should not happen!
505 printf("%sSVD Index %u is out of range", prefix, idx + 1);
506 if (*suffix)
507 printf(" (%s)", suffix);
508 printf("\n");
512 void edid_state::cta_y420cmdb(const unsigned char *x, unsigned length)
514 unsigned max_idx = 0;
515 unsigned i;
517 if (!length) {
518 printf(" All VDB SVDs\n");
519 return;
522 if (memchk(x, length)) {
523 printf(" Empty Capability Map\n");
524 fail("Empty Capability Map.\n");
525 return;
528 for (i = 0; i < length; i++) {
529 unsigned char v = x[i];
530 unsigned j;
532 for (j = 0; j < 8; j++) {
533 if (!(v & (1 << j)))
534 continue;
536 print_vic_index(" ", i * 8 + j, "", true);
537 max_idx = i * 8 + j;
538 if (max_idx < cta.preparsed_svds[0].size()) {
539 unsigned vic = cta.preparsed_svds[0][max_idx];
540 if (cta.preparsed_has_vic[1][vic])
541 fail("VIC %u is also a YCbCr 4:2:0-only VIC.\n", vic);
545 if (max_idx >= cta.preparsed_svds[0].size())
546 fail("Max index %u > %u (#SVDs).\n",
547 max_idx + 1, cta.preparsed_svds[0].size());
550 void edid_state::cta_vfpdb(const unsigned char *x, unsigned length)
552 unsigned i;
554 if (length == 0) {
555 fail("Empty Data Block with length %u.\n", length);
556 return;
558 cta.preferred_timings.clear();
559 for (i = 0; i < length; i++) {
560 unsigned char svr = x[i];
561 char suffix[16];
563 if ((svr > 0 && svr < 128) || (svr > 192 && svr < 254)) {
564 const struct timings *t;
565 unsigned char vic = svr;
567 sprintf(suffix, "VIC %3u", vic);
569 t = find_vic_id(vic);
570 if (t) {
571 print_timings(" ", t, suffix);
572 cta.preferred_timings.push_back(timings_ext(*t, suffix, ""));
573 } else {
574 printf(" %s: Unknown\n", suffix);
575 fail("Unknown VIC %u.\n", vic);
578 } else if (svr >= 129 && svr <= 144) {
579 sprintf(suffix, "DTD %3u", svr - 128);
580 if (svr >= cta.preparsed_total_dtds + 129) {
581 printf(" %s: Invalid\n", suffix);
582 fail("Invalid DTD %u.\n", svr - 128);
583 } else {
584 printf(" %s\n", suffix);
585 cta.preferred_timings.push_back(timings_ext(svr, suffix));
587 } else if (svr >= 145 && svr <= 160) {
588 sprintf(suffix, "VTDB %3u", svr - 144);
589 if (svr >= cta.preparsed_total_vtdbs + 145) {
590 printf(" %s: Invalid\n", suffix);
591 fail("Invalid VTDB %u.\n", svr - 144);
592 } else {
593 printf(" %s\n", suffix);
594 cta.preferred_timings.push_back(timings_ext(svr, suffix));
596 } else if (svr == 254) {
597 sprintf(suffix, "T8VTDB");
598 if (!cta.preparsed_has_t8vtdb) {
599 printf(" %s: Invalid\n", suffix);
600 fail("Invalid T8VTDB.\n");
601 } else {
602 printf(" %s\n", suffix);
603 cta.preferred_timings.push_back(timings_ext(svr, suffix));
609 static std::string hdmi_latency2s(unsigned char l, bool is_video)
611 if (!l)
612 return "Unknown";
613 if (l == 0xff)
614 return is_video ? "Video not supported" : "Audio not supported";
615 return std::to_string(1 + 2 * l) + " ms";
618 void edid_state::hdmi_latency(unsigned char vid_lat, unsigned char aud_lat,
619 bool is_ilaced)
621 const char *vid = is_ilaced ? "Interlaced video" : "Video";
622 const char *aud = is_ilaced ? "Interlaced audio" : "Audio";
624 printf(" %s latency: %s\n", vid, hdmi_latency2s(vid_lat, true).c_str());
625 printf(" %s latency: %s\n", aud, hdmi_latency2s(aud_lat, false).c_str());
627 if (vid_lat > 251 && vid_lat != 0xff)
628 fail("Invalid %s latency value %u.\n", vid, vid_lat);
629 if (aud_lat > 251 && aud_lat != 0xff)
630 fail("Invalid %s latency value %u.\n", aud, aud_lat);
632 if (!vid_lat || vid_lat > 251)
633 return;
634 if (!aud_lat || aud_lat > 251)
635 return;
637 unsigned vid_ms = 1 + 2 * vid_lat;
638 unsigned aud_ms = 1 + 2 * aud_lat;
640 // HDMI 2.0 latency checks for devices without HDMI output
641 if (aud_ms < vid_ms)
642 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
643 aud, vid, aud_ms, vid_ms);
644 else if (vid_ms + 20 < aud_ms)
645 warn("%s latency + 20 < %s latency (%u + 20 ms < %u ms). This is forbidden for devices without HDMI output.\n",
646 vid, aud, vid_ms, aud_ms);
647 else if (vid_ms < aud_ms)
648 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
649 vid, aud, vid_ms, aud_ms);
652 void edid_state::cta_hdmi_block(const unsigned char *x, unsigned length)
654 unsigned len_vic, len_3d;
656 if (length < 1) {
657 fail("Empty Data Block with length %u.\n", length);
658 return;
660 printf(" Source physical address: %x.%x.%x.%x\n", x[0] >> 4, x[0] & 0x0f,
661 x[1] >> 4, x[1] & 0x0f);
663 if (length < 3)
664 return;
666 if (x[2] & 0x80)
667 printf(" Supports_AI\n");
668 if (x[2] & 0x40)
669 printf(" DC_48bit\n");
670 if (x[2] & 0x20)
671 printf(" DC_36bit\n");
672 if (x[2] & 0x10)
673 printf(" DC_30bit\n");
674 if (x[2] & 0x08)
675 printf(" DC_Y444\n");
676 /* two reserved bits */
677 if (x[2] & 0x01)
678 printf(" DVI_Dual\n");
680 if (length < 4)
681 return;
683 printf(" Maximum TMDS clock: %u MHz\n", x[3] * 5);
684 if (x[3] * 5 > 340)
685 fail("HDMI VSDB Max TMDS rate is > 340.\n");
687 if (length < 5)
688 return;
690 if (x[4] & 0x0f) {
691 printf(" Supported Content Types:\n");
692 if (x[4] & 0x01)
693 printf(" Graphics\n");
694 if (x[4] & 0x02)
695 printf(" Photo\n");
696 if (x[4] & 0x04)
697 printf(" Cinema\n");
698 if (x[4] & 0x08)
699 printf(" Game\n");
702 unsigned b = 5;
703 if (x[4] & 0x80) {
704 hdmi_latency(x[b], x[b + 1], false);
706 if (x[4] & 0x40) {
707 if (x[b] == x[b + 2] &&
708 x[b + 1] == x[b + 3])
709 warn("Progressive and Interlaced latency values are identical, no need for both.\n");
710 b += 2;
711 hdmi_latency(x[b], x[b + 1], true);
713 b += 2;
716 if (!(x[4] & 0x20))
717 return;
719 bool mask = false;
720 bool formats = false;
722 printf(" Extended HDMI video details:\n");
723 if (x[b] & 0x80)
724 printf(" 3D present\n");
725 if ((x[b] & 0x60) == 0x20) {
726 printf(" All advertised VICs are 3D-capable\n");
727 formats = true;
729 if ((x[b] & 0x60) == 0x40) {
730 printf(" 3D-capable-VIC mask present\n");
731 formats = true;
732 mask = true;
734 switch (x[b] & 0x18) {
735 case 0x00: break;
736 case 0x08:
737 printf(" Base EDID image size is aspect ratio\n");
738 break;
739 case 0x10:
740 printf(" Base EDID image size is in units of 1 cm\n");
741 break;
742 case 0x18:
743 printf(" Base EDID image size is in units of 5 cm\n");
744 base.max_display_width_mm *= 5;
745 base.max_display_height_mm *= 5;
746 printf(" Recalculated image size: %u cm x %u cm\n",
747 base.max_display_width_mm / 10, base.max_display_height_mm / 10);
748 break;
750 b++;
751 len_vic = (x[b] & 0xe0) >> 5;
752 len_3d = (x[b] & 0x1f) >> 0;
753 b++;
755 if (len_vic) {
756 unsigned i;
758 printf(" HDMI VICs:\n");
759 for (i = 0; i < len_vic; i++) {
760 unsigned char vic = x[b + i];
761 const struct timings *t;
763 if (vic && vic <= ARRAY_SIZE(edid_hdmi_mode_map)) {
764 std::string suffix = "HDMI VIC " + std::to_string(vic);
765 cta.supported_hdmi_vic_codes |= 1 << (vic - 1);
766 t = find_vic_id(edid_hdmi_mode_map[vic - 1]);
767 print_timings(" ", t, suffix.c_str());
768 } else {
769 printf(" Unknown (HDMI VIC %u)\n", vic);
770 fail("Unknown HDMI VIC %u.\n", vic);
774 b += len_vic;
777 if (!len_3d)
778 return;
780 if (formats) {
781 /* 3D_Structure_ALL_15..8 */
782 if (x[b] & 0x80)
783 printf(" 3D: Side-by-side (half, quincunx)\n");
784 if (x[b] & 0x01)
785 printf(" 3D: Side-by-side (half, horizontal)\n");
786 /* 3D_Structure_ALL_7..0 */
787 b++;
788 if (x[b] & 0x40)
789 printf(" 3D: Top-and-bottom\n");
790 if (x[b] & 0x20)
791 printf(" 3D: L + depth + gfx + gfx-depth\n");
792 if (x[b] & 0x10)
793 printf(" 3D: L + depth\n");
794 if (x[b] & 0x08)
795 printf(" 3D: Side-by-side (full)\n");
796 if (x[b] & 0x04)
797 printf(" 3D: Line-alternative\n");
798 if (x[b] & 0x02)
799 printf(" 3D: Field-alternative\n");
800 if (x[b] & 0x01)
801 printf(" 3D: Frame-packing\n");
802 b++;
803 len_3d -= 2;
806 if (mask) {
807 int max_idx = -1;
808 unsigned i;
810 printf(" 3D VIC indices that support these capabilities:\n");
811 /* worst bit ordering ever */
812 for (i = 0; i < 8; i++)
813 if (x[b + 1] & (1 << i)) {
814 print_vic_index(" ", i, "");
815 max_idx = i;
817 for (i = 0; i < 8; i++)
818 if (x[b] & (1 << i)) {
819 print_vic_index(" ", i + 8, "");
820 max_idx = i + 8;
822 b += 2;
823 len_3d -= 2;
824 if (max_idx >= (int)cta.preparsed_svds[0].size())
825 fail("HDMI 3D VIC indices max index %d > %u (#SVDs).\n",
826 max_idx + 1, cta.preparsed_svds[0].size());
830 * list of nibbles:
831 * 2D_VIC_Order_X
832 * 3D_Structure_X
833 * (optionally: 3D_Detail_X and reserved)
835 if (!len_3d)
836 return;
838 unsigned end = b + len_3d;
839 int max_idx = -1;
841 printf(" 3D VIC indices with specific capabilities:\n");
842 while (b < end) {
843 unsigned char idx = x[b] >> 4;
844 std::string s;
846 if (idx > max_idx)
847 max_idx = idx;
848 switch (x[b] & 0x0f) {
849 case 0: s = "frame packing"; break;
850 case 1: s = "field alternative"; break;
851 case 2: s = "line alternative"; break;
852 case 3: s = "side-by-side (full)"; break;
853 case 4: s = "L + depth"; break;
854 case 5: s = "L + depth + gfx + gfx-depth"; break;
855 case 6: s = "top-and-bottom"; break;
856 case 8:
857 s = "side-by-side";
858 switch (x[b + 1] >> 4) {
859 case 0x00: s += ", any subsampling"; break;
860 case 0x01: s += ", horizontal"; break;
861 case 0x02: case 0x03: case 0x04: case 0x05:
862 s += ", not in use";
863 fail("not-in-use 3D_Detail_X value 0x%02x.\n",
864 x[b + 1] >> 4);
865 break;
866 case 0x06: s += ", all quincunx combinations"; break;
867 case 0x07: s += ", quincunx odd/left, odd/right"; break;
868 case 0x08: s += ", quincunx odd/left, even/right"; break;
869 case 0x09: s += ", quincunx even/left, odd/right"; break;
870 case 0x0a: s += ", quincunx even/left, even/right"; break;
871 default:
872 s += ", reserved";
873 fail("reserved 3D_Detail_X value 0x%02x.\n",
874 x[b + 1] >> 4);
875 break;
877 break;
878 default:
879 s = "unknown (";
880 s += utohex(x[b] & 0x0f) + ")";
881 fail("Unknown 3D_Structure_X value 0x%02x.\n", x[b] & 0x0f);
882 break;
884 print_vic_index(" ", idx, s.c_str());
885 if ((x[b] & 0x0f) >= 8)
886 b++;
887 b++;
889 if (max_idx >= (int)cta.preparsed_svds[0].size())
890 fail("HDMI 2D VIC indices max index %d > %u (#SVDs).\n",
891 max_idx + 1, cta.preparsed_svds[0].size());
894 static const char *max_frl_rates[] = {
895 "Not Supported",
896 "3 Gbps per lane on 3 lanes",
897 "3 and 6 Gbps per lane on 3 lanes",
898 "3 and 6 Gbps per lane on 3 lanes, 6 Gbps on 4 lanes",
899 "3 and 6 Gbps per lane on 3 lanes, 6 and 8 Gbps on 4 lanes",
900 "3 and 6 Gbps per lane on 3 lanes, 6, 8 and 10 Gbps on 4 lanes",
901 "3 and 6 Gbps per lane on 3 lanes, 6, 8, 10 and 12 Gbps on 4 lanes",
904 static const char *dsc_max_slices[] = {
905 "Not Supported",
906 "up to 1 slice and up to (340 MHz/Ksliceadjust) pixel clock per slice",
907 "up to 2 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
908 "up to 4 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
909 "up to 8 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
910 "up to 8 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
911 "up to 12 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
912 "up to 16 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
915 static void cta_hf_eeodb(const unsigned char *x, unsigned length)
917 printf(" EDID Extension Block Count: %u\n", x[0]);
918 if (length != 1 || x[0] == 0)
919 fail("Block is too long or reports a 0 block count.\n");
922 static void cta_hf_scdb(const unsigned char *x, unsigned length)
924 unsigned rate = x[1] * 5;
925 unsigned v;
927 printf(" Version: %u\n", x[0]);
928 if (rate) {
929 printf(" Maximum TMDS Character Rate: %u MHz\n", rate);
930 if (rate <= 340 || rate > 600)
931 fail("Max TMDS rate is > 0 and <= 340 or > 600.\n");
933 if (x[2] & 0x80)
934 printf(" SCDC Present\n");
935 if (x[2] & 0x40)
936 printf(" SCDC Read Request Capable\n");
937 if (x[2] & 0x10)
938 printf(" Supports Color Content Bits Per Component Indication\n");
939 if (x[2] & 0x08)
940 printf(" Supports scrambling for <= 340 Mcsc\n");
941 if (x[2] & 0x04)
942 printf(" Supports 3D Independent View signaling\n");
943 if (x[2] & 0x02)
944 printf(" Supports 3D Dual View signaling\n");
945 if (x[2] & 0x01)
946 printf(" Supports 3D OSD Disparity signaling\n");
947 if (x[3] & 0xf0) {
948 unsigned max_frl_rate = x[3] >> 4;
950 printf(" Max Fixed Rate Link: ");
951 if (max_frl_rate < ARRAY_SIZE(max_frl_rates)) {
952 printf("%s\n", max_frl_rates[max_frl_rate]);
953 } else {
954 printf("Unknown (0x%02x)\n", max_frl_rate);
955 fail("Unknown Max Fixed Rate Link (0x%02x).\n", max_frl_rate);
957 if (max_frl_rate == 1 && rate < 300)
958 fail("Max Fixed Rate Link is 1, but Max TMDS rate < 300.\n");
959 else if (max_frl_rate >= 2 && rate < 600)
960 fail("Max Fixed Rate Link is >= 2, but Max TMDS rate < 600.\n");
962 if (x[3] & 0x08)
963 printf(" Supports UHD VIC\n");
964 if (x[3] & 0x04)
965 printf(" Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding\n");
966 if (x[3] & 0x02)
967 printf(" Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding\n");
968 if (x[3] & 0x01)
969 printf(" Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding\n");
971 if (length <= 4)
972 return;
974 if (x[4] & 0x20)
975 printf(" Supports Mdelta\n");
976 if (x[4] & 0x10)
977 printf(" Supports media rates below VRRmin (CinemaVRR)\n");
978 if (x[4] & 0x08)
979 printf(" Supports negative Mvrr values\n");
980 if (x[4] & 0x04)
981 printf(" Supports Fast Vactive\n");
982 if (x[4] & 0x02)
983 printf(" Supports Auto Low-Latency Mode\n");
984 if (x[4] & 0x01)
985 printf(" Supports a FAPA in blanking after first active video line\n");
987 if (length <= 5)
988 return;
990 v = x[5] & 0x3f;
991 if (v) {
992 printf(" VRRmin: %u Hz\n", v);
993 if (v > 48)
994 fail("VRRmin > 48.\n");
996 v = (x[5] & 0xc0) << 2 | x[6];
997 if (v) {
998 printf(" VRRmax: %u Hz\n", v);
999 if (!(x[5] & 0x3f))
1000 fail("VRRmin == 0, but VRRmax isn't.\n");
1001 else if (v < 100)
1002 fail("VRRmax < 100.\n");
1005 if (length <= 7)
1006 return;
1008 if (x[7] & 0x80)
1009 printf(" Supports VESA DSC 1.2a compression\n");
1010 if (x[7] & 0x40)
1011 printf(" Supports Compressed Video Transport for 4:2:0 Pixel Encoding\n");
1012 if (x[7] & 0x08)
1013 printf(" Supports Compressed Video Transport at any valid 1/16th bit bpp\n");
1014 if (x[7] & 0x04)
1015 printf(" Supports 16 bpc Compressed Video Transport\n");
1016 if (x[7] & 0x02)
1017 printf(" Supports 12 bpc Compressed Video Transport\n");
1018 if (x[7] & 0x01)
1019 printf(" Supports 10 bpc Compressed Video Transport\n");
1020 if (x[8] & 0xf) {
1021 unsigned max_slices = x[8] & 0xf;
1023 printf(" DSC Max Slices: ");
1024 if (max_slices < ARRAY_SIZE(dsc_max_slices)) {
1025 printf("%s\n", dsc_max_slices[max_slices]);
1026 } else {
1027 printf("Unknown (0x%02x)\n", max_slices);
1028 fail("Unknown DSC Max Slices (0x%02x).\n", max_slices);
1031 if (x[8] & 0xf0) {
1032 unsigned max_frl_rate = x[8] >> 4;
1034 printf(" DSC Max Fixed Rate Link: ");
1035 if (max_frl_rate < ARRAY_SIZE(max_frl_rates)) {
1036 printf("%s\n", max_frl_rates[max_frl_rate]);
1037 } else {
1038 printf("Unknown (0x%02x)\n", max_frl_rate);
1039 fail("Unknown DSC Max Fixed Rate Link (0x%02x).\n", max_frl_rate);
1042 if (x[9] & 0x3f)
1043 printf(" Maximum number of bytes in a line of chunks: %u\n",
1044 1024 * (1 + (x[9] & 0x3f)));
1047 static void cta_amd(const unsigned char *x, unsigned length)
1049 // These Freesync values are reversed engineered by looking
1050 // at existing EDIDs.
1051 printf(" Version: %u.%u\n", x[0], x[1]);
1052 printf(" Minimum Refresh Rate: %u Hz\n", x[2]);
1053 printf(" Maximum Refresh Rate: %u Hz\n", x[3]);
1054 // Freesync 1.x flags
1055 // One or more of the 0xe6 bits signal that the VESA MCCS
1056 // protocol is used to switch the Freesync range
1057 printf(" Flags 1.x: 0x%02x%s\n", x[4],
1058 (x[4] & 0xe6) ? " (MCCS)" : "");
1059 if (length >= 10) {
1060 // Freesync 2.x flags
1061 // Bit 2 no doubt indicates if the monitor supports Local Dimming
1062 // There are probably also bits to signal support of the
1063 // FreeSync2_scRGB and FreeSync2_Gamma22 HDR display modes.
1064 // I suspect bits 0 and 1.
1065 printf(" Flags 2.x: 0x%02x\n", x[5]);
1066 // The AMD tone mapping tutorial referred to in the URL below
1067 // mentions that the Freesync HDR info reports max/min
1068 // luminance of the monitor with and without local dimming.
1070 // https://gpuopen.com/learn/using-amd-freesync-premium-pro-hdr-code-samples/
1072 // So I assume that the first two luminance values are
1073 // the max/min luminance of the display and the next two
1074 // luminance values are the max/min luminance values when
1075 // local dimming is disabled. The values I get seem to
1076 // support that.
1077 printf(" Maximum luminance: %u (%.3f cd/m^2)\n",
1078 x[6], 50.0 * pow(2, x[6] / 32.0));
1079 printf(" Minimum luminance: %u (%.3f cd/m^2)\n",
1080 x[7], (50.0 * pow(2, x[6] / 32.0)) * pow(x[7] / 255.0, 2) / 100.0);
1081 if (x[5] & 4) {
1082 // One or both bytes can be 0. The meaning of that
1083 // is unknown.
1084 printf(" Maximum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1085 x[8], 50.0 * pow(2, x[8] / 32.0));
1086 printf(" Minimum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1087 x[9], (50.0 * pow(2, x[8] / 32.0)) * pow(x[9] / 255.0, 2) / 100.0);
1088 } else {
1089 // These bytes are always 0x08 0x2f. If these values
1090 // represent max/min luminance as well, then these
1091 // would map to 59.460 and 0.020 cd/m^2 respectively.
1092 // I wonder if this somehow relates to SDR.
1093 printf(" Unknown: 0x%02x 0x%02x\n", x[8], x[9]);
1098 static std::string display_use_case(unsigned char x)
1100 switch (x) {
1101 case 1: return "Test equipment";
1102 case 2: return "Generic display";
1103 case 3: return "Television display";
1104 case 4: return "Desktop productivity display";
1105 case 5: return "Desktop gaming display";
1106 case 6: return "Presentation display";
1107 case 7: return "Virtual reality headset";
1108 case 8: return "Augmented reality";
1109 case 16: return "Video wall display";
1110 case 17: return "Medical imaging display";
1111 case 18: return "Dedicated gaming display";
1112 case 19: return "Dedicated video monitor display";
1113 case 20: return "Accessory display";
1114 default: break;
1116 fail("Unknown Display product primary use case 0x%02x.\n", x);
1117 return std::string("Unknown display use case (") + utohex(x) + ")";
1120 static void cta_microsoft(const unsigned char *x, unsigned length)
1122 // This VSDB is documented at:
1123 // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
1124 printf(" Version: %u\n", x[0]);
1125 if (x[0] > 2) {
1126 // In version 1 and 2 these bits should always be set to 0.
1127 printf(" Desktop Usage: %u\n", (x[1] >> 6) & 1);
1128 printf(" Third-Party Usage: %u\n", (x[1] >> 5) & 1);
1130 printf(" Display Product Primary Use Case: %u (%s)\n", x[1] & 0x1f,
1131 display_use_case(x[1] & 0x1f).c_str());
1132 printf(" Container ID: %s\n", containerid2s(x + 2).c_str());
1135 static void cta_hdr10plus(const unsigned char *x, unsigned length)
1137 if (length == 0) {
1138 fail("Empty Data Block with length %u.\n", length);
1139 return;
1141 printf(" Application Version: %u\n", x[0]);
1142 hex_block(" ", x + 1, length - 1);
1145 // Convert a PQ value (0-1) to cd/m^2 aka nits (0-10000)
1146 static double pq2nits(double pq)
1148 const double m1 = 2610.0 / 16384.0;
1149 const double m2 = 128.0 * (2523.0 / 4096.0);
1150 const double c1 = 3424.0 / 4096.0;
1151 const double c2 = 32.0 * (2413.0 / 4096.0);
1152 const double c3 = 32.0 * (2392.0 / 4096.0);
1153 double e = pow(pq, 1.0 / m2);
1154 double v = e - c1;
1156 if (v < 0)
1157 v = 0;
1158 v /= c2 - c3 * e;
1159 v = pow(v, 1.0 / m1);
1160 return v * 10000.0;
1163 static void cta_dolby_video(const unsigned char *x, unsigned length)
1165 unsigned char version = (x[0] >> 5) & 0x07;
1167 printf(" Version: %u (%u bytes)\n", version, length + 5);
1168 if (x[0] & 0x01)
1169 printf(" Supports YUV422 12 bit\n");
1171 if (version == 0) {
1172 if (x[0] & 0x02)
1173 printf(" Supports 2160p60\n");
1174 if (x[0] & 0x04)
1175 printf(" Supports global dimming\n");
1176 unsigned char dm_version = x[16];
1177 printf(" DM Version: %u.%u\n", dm_version >> 4, dm_version & 0xf);
1178 unsigned pq = (x[14] << 4) | (x[13] >> 4);
1179 printf(" Target Min PQ: %u (%.8f cd/m^2)\n", pq, pq2nits(pq / 4095.0));
1180 pq = (x[15] << 4) | (x[13] & 0xf);
1181 printf(" Target Max PQ: %u (%u cd/m^2)\n", pq, (unsigned)pq2nits(pq / 4095.0));
1182 printf(" Rx, Ry: %.8f, %.8f\n",
1183 ((x[1] >> 4) | (x[2] << 4)) / 4096.0,
1184 ((x[1] & 0xf) | (x[3] << 4)) / 4096.0);
1185 printf(" Gx, Gy: %.8f, %.8f\n",
1186 ((x[4] >> 4) | (x[5] << 4)) / 4096.0,
1187 ((x[4] & 0xf) | (x[6] << 4)) / 4096.0);
1188 printf(" Bx, By: %.8f, %.8f\n",
1189 ((x[7] >> 4) | (x[8] << 4)) / 4096.0,
1190 ((x[7] & 0xf) | (x[9] << 4)) / 4096.0);
1191 printf(" Wx, Wy: %.8f, %.8f\n",
1192 ((x[10] >> 4) | (x[11] << 4)) / 4096.0,
1193 ((x[10] & 0xf) | (x[12] << 4)) / 4096.0);
1194 return;
1197 if (version == 1) {
1198 if (x[0] & 0x02)
1199 printf(" Supports 2160p60\n");
1200 if (x[1] & 0x01)
1201 printf(" Supports global dimming\n");
1202 unsigned char dm_version = (x[0] >> 2) & 0x07;
1203 printf(" DM Version: %u.x\n", dm_version + 2);
1204 printf(" Colorimetry: %s\n", (x[2] & 0x01) ? "P3-D65" : "ITU-R BT.709");
1205 printf(" Low Latency: %s\n", (x[3] & 0x01) ? "Standard + Low Latency" : "Only Standard");
1206 double lm = (x[2] >> 1) / 127.0;
1207 printf(" Target Min Luminance: %.8f cd/m^2\n", lm * lm);
1208 printf(" Target Max Luminance: %u cd/m^2\n", 100 + (x[1] >> 1) * 50);
1209 if (length == 10) {
1210 printf(" Rx, Ry: %.8f, %.8f\n", x[4] / 256.0, x[5] / 256.0);
1211 printf(" Gx, Gy: %.8f, %.8f\n", x[6] / 256.0, x[7] / 256.0);
1212 printf(" Bx, By: %.8f, %.8f\n", x[8] / 256.0, x[9] / 256.0);
1213 } else {
1214 double xmin = 0.625;
1215 double xstep = (0.74609375 - xmin) / 31.0;
1216 double ymin = 0.25;
1217 double ystep = (0.37109375 - ymin) / 31.0;
1219 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1220 xmin + xstep * (x[6] >> 3),
1221 ymin + ystep * (((x[6] & 0x7) << 2) | (x[4] & 0x01) | ((x[5] & 0x01) << 1)));
1222 xstep = 0.49609375 / 127.0;
1223 ymin = 0.5;
1224 ystep = (0.99609375 - ymin) / 127.0;
1225 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1226 xstep * (x[4] >> 1), ymin + ystep * (x[5] >> 1));
1227 xmin = 0.125;
1228 xstep = (0.15234375 - xmin) / 7.0;
1229 ymin = 0.03125;
1230 ystep = (0.05859375 - ymin) / 7.0;
1231 printf(" Unique Bx, By: %.8f, %.8f\n",
1232 xmin + xstep * (x[3] >> 5),
1233 ymin + ystep * ((x[3] >> 2) & 0x07));
1235 return;
1238 if (version == 2) {
1239 if (x[0] & 0x02)
1240 printf(" Supports Backlight Control\n");
1241 if (x[1] & 0x04)
1242 printf(" Supports global dimming\n");
1243 unsigned char dm_version = (x[0] >> 2) & 0x07;
1244 printf(" DM Version: %u.x\n", dm_version + 2);
1245 printf(" Backlt Min Luma: %u cd/m^2\n", 25 + (x[1] & 0x03) * 25);
1246 printf(" Interface: ");
1247 switch (x[2] & 0x03) {
1248 case 0: printf("Low-Latency\n"); break;
1249 case 1: printf("Low-Latency + Low-Latency-HDMI\n"); break;
1250 case 2: printf("Standard + Low-Latency\n"); break;
1251 case 3: printf("Standard + Low-Latency + Low-Latency-HDMI\n"); break;
1253 printf(" Supports 10b 12b 444: ");
1254 switch ((x[3] & 0x01) << 1 | (x[4] & 0x01)) {
1255 case 0: printf("Not supported\n"); break;
1256 case 1: printf("10 bit\n"); break;
1257 case 2: printf("12 bit\n"); break;
1258 case 3: printf("Reserved\n"); break;
1261 // This divider constant is a guess. According to what I read
1262 // when googling for how to interpret these values, the Min PQ
1263 // maps to a range of 0-1 cd/m^2, and the Max PQ maps to a
1264 // range of 100-10000 cd/m^2. Since the maximum value for the Max PQ
1265 // is 2055 + 65 * 31 = 4070, I am guessing that that is the correct
1266 // divider, but it might well be 4095 or 4096 instead.
1268 // I'm also not sure if the divider for Min PQ is the same as for
1269 // Max PQ. To map the max value of 20 * 31 to 1 cd/m^2 you would
1270 // need a divider of 4134 or 4135, but I suspect the same divider
1271 // is used.
1272 const double dv_pq_div = 2055 + 31 * 65;
1274 unsigned pq = 20 * (x[1] >> 3);
1275 printf(" Target Min PQ v2: %u (%.8f cd/m^2)\n", pq, pq2nits(pq / dv_pq_div));
1276 pq = 2055 + 65 * (x[2] >> 3);
1277 printf(" Target Max PQ v2: %u (%u cd/m^2)\n", pq, (unsigned)pq2nits(pq / dv_pq_div));
1279 double xmin = 0.625;
1280 double xstep = (0.74609375 - xmin) / 31.0;
1281 double ymin = 0.25;
1282 double ystep = (0.37109375 - ymin) / 31.0;
1284 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1285 xmin + xstep * (x[5] >> 3),
1286 ymin + ystep * (x[6] >> 3));
1287 xstep = 0.49609375 / 127.0;
1288 ymin = 0.5;
1289 ystep = (0.99609375 - ymin) / 127.0;
1290 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1291 xstep * (x[3] >> 1), ymin + ystep * (x[4] >> 1));
1292 xmin = 0.125;
1293 xstep = (0.15234375 - xmin) / 7.0;
1294 ymin = 0.03125;
1295 ystep = (0.05859375 - ymin) / 7.0;
1296 printf(" Unique Bx, By: %.8f, %.8f\n",
1297 xmin + xstep * (x[5] & 0x07),
1298 ymin + ystep * (x[6] & 0x07));
1302 static void cta_dolby_audio(const unsigned char *x, unsigned length)
1304 unsigned char version = 1 + (x[0] & 0x07);
1306 printf(" Version: %u (%u bytes)\n", version, length + 5);
1307 if (x[0] & 0x80)
1308 printf(" Headphone playback only\n");
1309 if (x[0] & 0x40)
1310 printf(" Height speaker zone present\n");
1311 if (x[0] & 0x20)
1312 printf(" Surround speaker zone present\n");
1313 if (x[0] & 0x10)
1314 printf(" Center speaker zone present\n");
1315 if (x[1] & 0x01)
1316 printf(" Supports Dolby MAT PCM decoding at 48 kHz only, does not support TrueHD\n");
1319 static const char *speaker_map[] = {
1320 "FL/FR - Front Left/Right",
1321 "LFE1 - Low Frequency Effects 1",
1322 "FC - Front Center",
1323 "BL/BR - Back Left/Right",
1324 "BC - Back Center",
1325 "FLc/FRc - Front Left/Right of Center",
1326 "RLC/RRC - Rear Left/Right of Center (Deprecated)",
1327 "FLw/FRw - Front Left/Right Wide",
1328 "TpFL/TpFR - Top Front Left/Right",
1329 "TpC - Top Center",
1330 "TpFC - Top Front Center",
1331 "LS/RS - Left/Right Surround",
1332 "LFE2 - Low Frequency Effects 2",
1333 "TpBC - Top Back Center",
1334 "SiL/SiR - Side Left/Right",
1335 "TpSiL/TpSiR - Top Side Left/Right",
1336 "TpBL/TpBR - Top Back Left/Right",
1337 "BtFC - Bottom Front Center",
1338 "BtFL/BtFR - Bottom Front Left/Right",
1339 "TpLS/TpRS - Top Left/Right Surround (Deprecated for CTA-861)",
1340 "LSd/RSd - Left/Right Surround Direct (HDMI only)",
1343 static void cta_sadb(const unsigned char *x, unsigned length)
1345 unsigned sad;
1346 unsigned i;
1348 if (length < 3) {
1349 fail("Empty Data Block with length %u.\n", length);
1350 return;
1353 sad = ((x[2] << 16) | (x[1] << 8) | x[0]);
1355 for (i = 0; i < ARRAY_SIZE(speaker_map); i++) {
1356 if ((sad >> i) & 1)
1357 printf(" %s\n", speaker_map[i]);
1361 static void cta_vesa_dtcdb(const unsigned char *x, unsigned length)
1363 if (length != 7 && length != 15 && length != 31) {
1364 fail("Invalid length %u.\n", length);
1365 return;
1368 switch (x[0] >> 6) {
1369 case 0: printf(" White"); break;
1370 case 1: printf(" Red"); break;
1371 case 2: printf(" Green"); break;
1372 case 3: printf(" Blue"); break;
1374 unsigned v = x[0] & 0x3f;
1375 printf(" transfer characteristics: %u", v);
1376 for (unsigned i = 1; i < length; i++)
1377 printf(" %u", v += x[i]);
1378 printf(" 1023\n");
1381 static void cta_vesa_vdddb(const unsigned char *x, unsigned length)
1383 if (length != 30) {
1384 fail("Invalid length %u.\n", length);
1385 return;
1388 printf(" Interface Type: ");
1389 unsigned char v = x[0];
1390 switch (v >> 4) {
1391 case 0: printf("Analog (");
1392 switch (v & 0xf) {
1393 case 0: printf("15HD/VGA"); break;
1394 case 1: printf("VESA NAVI-V (15HD)"); break;
1395 case 2: printf("VESA NAVI-D"); break;
1396 default: printf("Reserved"); break;
1398 printf(")\n");
1399 break;
1400 case 1: printf("LVDS %u lanes", v & 0xf); break;
1401 case 2: printf("RSDS %u lanes", v & 0xf); break;
1402 case 3: printf("DVI-D %u channels", v & 0xf); break;
1403 case 4: printf("DVI-I analog"); break;
1404 case 5: printf("DVI-I digital %u channels", v & 0xf); break;
1405 case 6: printf("HDMI-A"); break;
1406 case 7: printf("HDMI-B"); break;
1407 case 8: printf("MDDI %u channels", v & 0xf); break;
1408 case 9: printf("DisplayPort %u channels", v & 0xf); break;
1409 case 10: printf("IEEE-1394"); break;
1410 case 11: printf("M1 analog"); break;
1411 case 12: printf("M1 digital %u channels", v & 0xf); break;
1412 default: printf("Reserved"); break;
1414 printf("\n");
1416 printf(" Interface Standard Version: %u.%u\n", x[1] >> 4, x[1] & 0xf);
1417 printf(" Content Protection Support: ");
1418 switch (x[2]) {
1419 case 0: printf("None\n"); break;
1420 case 1: printf("HDCP\n"); break;
1421 case 2: printf("DTCP\n"); break;
1422 case 3: printf("DPCP\n"); break;
1423 default: printf("Reserved\n"); break;
1426 printf(" Minimum Clock Frequency: %u MHz\n", x[3] >> 2);
1427 printf(" Maximum Clock Frequency: %u MHz\n", ((x[3] & 0x03) << 8) | x[4]);
1428 printf(" Device Native Pixel Format: %ux%u\n",
1429 x[5] | (x[6] << 8), x[7] | (x[8] << 8));
1430 printf(" Aspect Ratio: %.2f\n", (100 + x[9]) / 100.0);
1431 v = x[0x0a];
1432 printf(" Default Orientation: ");
1433 switch ((v & 0xc0) >> 6) {
1434 case 0x00: printf("Landscape\n"); break;
1435 case 0x01: printf("Portrait\n"); break;
1436 case 0x02: printf("Not Fixed\n"); break;
1437 case 0x03: printf("Undefined\n"); break;
1439 printf(" Rotation Capability: ");
1440 switch ((v & 0x30) >> 4) {
1441 case 0x00: printf("None\n"); break;
1442 case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
1443 case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
1444 case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
1446 printf(" Zero Pixel Location: ");
1447 switch ((v & 0x0c) >> 2) {
1448 case 0x00: printf("Upper Left\n"); break;
1449 case 0x01: printf("Upper Right\n"); break;
1450 case 0x02: printf("Lower Left\n"); break;
1451 case 0x03: printf("Lower Right\n"); break;
1453 printf(" Scan Direction: ");
1454 switch (v & 0x03) {
1455 case 0x00: printf("Not defined\n"); break;
1456 case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
1457 case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
1458 case 0x03: printf("Reserved\n");
1459 fail("Scan Direction used the reserved value 0x03.\n");
1460 break;
1462 printf(" Subpixel Information: ");
1463 switch (x[0x0b]) {
1464 case 0x00: printf("Not defined\n"); break;
1465 case 0x01: printf("RGB vertical stripes\n"); break;
1466 case 0x02: printf("RGB horizontal stripes\n"); break;
1467 case 0x03: printf("Vertical stripes using primary order\n"); break;
1468 case 0x04: printf("Horizontal stripes using primary order\n"); break;
1469 case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
1470 case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
1471 case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
1472 case 0x08: printf("Mosaic\n"); break;
1473 case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
1474 case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
1475 case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
1476 case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
1477 default: printf("Reserved\n"); break;
1479 printf(" Horizontal and vertical dot/pixel pitch: %.2f x %.2f mm\n",
1480 (double)(x[0x0c]) / 100.0, (double)(x[0x0d]) / 100.0);
1481 v = x[0x0e];
1482 printf(" Dithering: ");
1483 switch (v >> 6) {
1484 case 0: printf("None\n"); break;
1485 case 1: printf("Spatial\n"); break;
1486 case 2: printf("Temporal\n"); break;
1487 case 3: printf("Spatial and Temporal\n"); break;
1489 printf(" Direct Drive: %s\n", (v & 0x20) ? "Yes" : "No");
1490 printf(" Overdrive %srecommended\n", (v & 0x10) ? "not " : "");
1491 printf(" Deinterlacing: %s\n", (v & 0x08) ? "Yes" : "No");
1493 v = x[0x0f];
1494 printf(" Audio Support: %s\n", (v & 0x80) ? "Yes" : "No");
1495 printf(" Separate Audio Inputs Provided: %s\n", (v & 0x40) ? "Yes" : "No");
1496 printf(" Audio Input Override: %s\n", (v & 0x20) ? "Yes" : "No");
1497 v = x[0x10];
1498 if (v)
1499 printf(" Audio Delay: %s%u ms\n", (v & 0x80) ? "" : "-", (v & 0x7f) * 2);
1500 else
1501 printf(" Audio Delay: no information provided\n");
1502 v = x[0x11];
1503 printf(" Frame Rate/Mode Conversion: ");
1504 switch (v >> 6) {
1505 case 0: printf("None\n"); break;
1506 case 1: printf("Single Buffering\n"); break;
1507 case 2: printf("Double Buffering\n"); break;
1508 case 3: printf("Advanced Frame Rate Conversion\n"); break;
1510 if (v & 0x3f)
1511 printf(" Frame Rate Range: %u fps +/- %u fps\n",
1512 x[0x12], v & 0x3f);
1513 else
1514 printf(" Nominal Frame Rate: %u fps\n", x[0x12]);
1515 printf(" Color Bit Depth: %u @ interface, %u @ display\n",
1516 (x[0x13] >> 4) + 1, (x[0x13] & 0xf) + 1);
1517 v = x[0x15] & 3;
1518 if (v) {
1519 printf(" Additional Primary Chromaticities:\n");
1520 unsigned col_x = (x[0x16] << 2) | (x[0x14] >> 6);
1521 unsigned col_y = (x[0x17] << 2) | ((x[0x14] >> 4) & 3);
1522 printf(" Primary 4: 0.%04u, 0.%04u\n",
1523 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1524 if (v > 1) {
1525 col_x = (x[0x18] << 2) | ((x[0x14] >> 2) & 3);
1526 col_y = (x[0x19] << 2) | (x[0x14] & 3);
1527 printf(" Primary 5: 0.%04u, 0.%04u\n",
1528 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1529 if (v > 2) {
1530 col_x = (x[0x1a] << 2) | (x[0x15] >> 6);
1531 col_y = (x[0x1b] << 2) | ((x[0x15] >> 4) & 3);
1532 printf(" Primary 6: 0.%04u, 0.%04u\n",
1533 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1538 v = x[0x1c];
1539 printf(" Response Time %s: %u ms\n",
1540 (v & 0x80) ? "White -> Black" : "Black -> White", v & 0x7f);
1541 v = x[0x1d];
1542 printf(" Overscan: %u%% x %u%%\n", v >> 4, v & 0xf);
1545 static double decode_uchar_as_double(unsigned char x)
1547 signed char s = (signed char)x;
1549 return s / 64.0;
1552 void edid_state::cta_rcdb(const unsigned char *x, unsigned length)
1554 unsigned spm = ((x[3] << 16) | (x[2] << 8) | x[1]);
1555 unsigned i;
1557 if (length < 4) {
1558 fail("Empty Data Block with length %u.\n", length);
1559 return;
1562 if ((x[0] & 0x20) && !cta.has_sldb)
1563 fail("'SLD' flag is 1, but no Speaker Location Data Block is found.\n");
1564 else if (!(x[0] & 0x20) && cta.has_sldb)
1565 fail("'SLD' flag is 0, but a Speaker Location Data Block is present.\n");
1567 if (x[0] & 0x40) {
1568 printf(" Speaker count: %u\n", (x[0] & 0x1f) + 1);
1569 } else {
1570 if (x[0] & 0x1f)
1571 fail("'Speaker' flag is 0, but 'Speaker Count' is != 0.\n");
1572 if (x[0] & 0x20)
1573 fail("'SLD' flag is 1, but 'Speaker' is 0.\n");
1576 printf(" Speaker Presence Mask:\n");
1577 for (i = 0; i < ARRAY_SIZE(speaker_map); i++) {
1578 if ((spm >> i) & 1)
1579 printf(" %s\n", speaker_map[i]);
1582 if ((x[0] & 0xa0) == 0x80)
1583 fail("'Display' flag set, but not the 'SLD' flag.\n");
1585 bool valid_max = cta.preparsed_sld_has_coord || (x[0] & 0x80);
1587 if (valid_max && length >= 7) {
1588 printf(" Xmax: %u dm\n", x[4]);
1589 printf(" Ymax: %u dm\n", x[5]);
1590 printf(" Zmax: %u dm\n", x[6]);
1591 } else if (!valid_max && length >= 7) {
1592 // The RCDB should have been truncated.
1593 warn("'Display' flag is 0 and 'Coord' is 0 for all SLDs, but the Max coordinates are still present.\n");
1595 if ((x[0] & 0x80) && length >= 10) {
1596 printf(" DisplayX: %.3f * Xmax\n", decode_uchar_as_double(x[7]));
1597 printf(" DisplayY: %.3f * Ymax\n", decode_uchar_as_double(x[8]));
1598 printf(" DisplayZ: %.3f * Zmax\n", decode_uchar_as_double(x[9]));
1599 } else if (!(x[0] & 0x80) && length >= 10) {
1600 // The RCDB should have been truncated.
1601 warn("'Display' flag is 0, but the Display coordinates are still present.\n");
1605 static const char *speaker_location[] = {
1606 "FL - Front Left",
1607 "FR - Front Right",
1608 "FC - Front Center",
1609 "LFE1 - Low Frequency Effects 1",
1610 "BL - Back Left",
1611 "BR - Back Right",
1612 "FLC - Front Left of Center",
1613 "FRC - Front Right of Center",
1614 "BC - Back Center",
1615 "LFE2 - Low Frequency Effects 2",
1616 "SiL - Side Left",
1617 "SiR - Side Right",
1618 "TpFL - Top Front Left",
1619 "TpFR - Top Front Right",
1620 "TpFC - Top Front Center",
1621 "TpC - Top Center",
1622 "TpBL - Top Back Left",
1623 "TpBR - Top Back Right",
1624 "TpSiL - Top Side Left",
1625 "TpSiR - Top Side Right",
1626 "TpBC - Top Back Center",
1627 "BtFC - Bottom Front Center",
1628 "BtFL - Bottom Front Left",
1629 "BtFR - Bottom Front Right",
1630 "FLW - Front Left Wide",
1631 "FRW - Front Right Wide",
1632 "LS - Left Surround",
1633 "RS - Right Surround",
1636 void edid_state::cta_sldb(const unsigned char *x, unsigned length)
1638 if (length < 2) {
1639 fail("Empty Data Block with length %u.\n", length);
1640 return;
1643 unsigned active_cnt = 0;
1644 unsigned channel_is_active = 0;
1646 while (length >= 2) {
1647 printf(" Channel: %u (%sactive)\n", x[0] & 0x1f,
1648 (x[0] & 0x20) ? "" : "not ");
1649 if (x[0] & 0x20) {
1650 if (channel_is_active & (1U << (x[0] & 0x1f)))
1651 fail("Channel Index %u was already marked 'Active'.\n",
1652 x[0] & 0x1f);
1653 channel_is_active |= 1U << (x[0] & 0x1f);
1654 active_cnt++;
1656 if ((x[1] & 0x1f) < ARRAY_SIZE(speaker_location))
1657 printf(" Speaker: %s\n", speaker_location[x[1] & 0x1f]);
1658 if (length >= 5 && (x[0] & 0x40)) {
1659 printf(" X: %.3f * Xmax\n", decode_uchar_as_double(x[2]));
1660 printf(" Y: %.3f * Ymax\n", decode_uchar_as_double(x[3]));
1661 printf(" Z: %.3f * Zmax\n", decode_uchar_as_double(x[4]));
1662 length -= 3;
1663 x += 3;
1666 length -= 2;
1667 x += 2;
1669 if (active_cnt != cta.preparsed_speaker_count)
1670 fail("There are %u active speakers, but 'Speaker Count' is %u.\n",
1671 active_cnt, cta.preparsed_speaker_count);
1674 void edid_state::cta_preparse_sldb(const unsigned char *x, unsigned length)
1676 cta.has_sldb = true;
1677 while (length >= 2) {
1678 if (length >= 5 && (x[0] & 0x40)) {
1679 cta.preparsed_sld_has_coord = true;
1680 return;
1682 length -= 2;
1683 x += 2;
1687 void edid_state::cta_vcdb(const unsigned char *x, unsigned length)
1689 unsigned char d = x[0];
1691 cta.has_vcdb = true;
1692 if (length < 1) {
1693 fail("Empty Data Block with length %u.\n", length);
1694 return;
1696 printf(" YCbCr quantization: %s\n",
1697 (d & 0x80) ? "Selectable (via AVI YQ)" : "No Data");
1698 printf(" RGB quantization: %s\n",
1699 (d & 0x40) ? "Selectable (via AVI Q)" : "No Data");
1701 * If this bit is not set then that will result in interoperability
1702 * problems (specifically with PCs/laptops) that quite often do not
1703 * follow the default rules with respect to RGB Quantization Range
1704 * handling.
1706 * Starting with the CTA-861-H spec this bit is now required to be
1707 * 1 for new designs.
1709 if (!(d & 0x40))
1710 fail("Set Selectable RGB Quantization to avoid interop issues.\n");
1712 * Since most YCbCr formats use limited range, the interop issues are
1713 * less noticable than for RGB formats.
1715 * Starting with the CTA-861-H spec this bit is now required to be
1716 * 1 for new designs, but just warn about it (for now).
1718 if ((cta.byte3 & 0x30) && !(d & 0x80))
1719 warn("Set Selectable YCbCr Quantization to avoid interop issues.\n");
1721 unsigned char s_pt = (d >> 4) & 0x03;
1722 unsigned char s_it = (d >> 2) & 0x03;
1723 unsigned char s_ce = d & 0x03;
1725 printf(" PT scan behavior: ");
1726 switch (s_pt) {
1727 case 0: printf("No Data\n"); break;
1728 case 1: printf("Always Overscanned\n"); break;
1729 case 2: printf("Always Underscanned\n"); break;
1730 case 3: printf("Supports both over- and underscan\n"); break;
1732 printf(" IT scan behavior: ");
1733 switch (s_it) {
1734 case 0: printf("IT video formats not supported\n"); break;
1735 case 1:
1736 printf("Always Overscanned\n");
1737 // See Table 52 of CTA-861-G for a description of Byte 3
1738 if (cta.byte3 & 0x80)
1739 fail("IT video formats are always overscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to underscanned.\n");
1740 break;
1741 case 2:
1742 printf("Always Underscanned\n");
1743 // See Table 52 of CTA-861-G for a description of Byte 3
1744 if (!(cta.byte3 & 0x80))
1745 fail("IT video formats are always underscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to overscanned.\n");
1746 break;
1747 case 3: printf("Supports both over- and underscan\n"); break;
1749 if (s_it < 2)
1750 warn("IT scan behavior is expected to support underscanned.\n");
1751 printf(" CE scan behavior: ");
1752 switch (s_ce) {
1753 case 0: printf("CE video formats not supported\n"); break;
1754 case 1: printf("Always Overscanned\n"); break;
1755 case 2: printf("Always Underscanned\n"); break;
1756 case 3: printf("Supports both over- and underscan\n"); break;
1758 if (s_ce == 0)
1759 warn("'CE video formats not supported' makes no sense.\n");
1760 else if (s_pt == s_it && s_pt == s_ce)
1761 warn("S_PT is equal to S_IT and S_CE, so should be set to 0 instead.\n");
1764 static const char *colorimetry_map[] = {
1765 "xvYCC601",
1766 "xvYCC709",
1767 "sYCC601",
1768 "opYCC601",
1769 "opRGB",
1770 "BT2020cYCC",
1771 "BT2020YCC",
1772 "BT2020RGB",
1775 static void cta_colorimetry_block(const unsigned char *x, unsigned length)
1777 unsigned i;
1779 if (length < 2) {
1780 fail("Empty Data Block with length %u.\n", length);
1781 return;
1783 for (i = 0; i < ARRAY_SIZE(colorimetry_map); i++) {
1784 if (x[0] & (1 << i))
1785 printf(" %s\n", colorimetry_map[i]);
1787 if (x[1] & 0x80)
1788 printf(" DCI-P3\n");
1789 if (x[1] & 0x40)
1790 printf(" ICtCp\n");
1793 static const char *eotf_map[] = {
1794 "Traditional gamma - SDR luminance range",
1795 "Traditional gamma - HDR luminance range",
1796 "SMPTE ST2084",
1797 "Hybrid Log-Gamma",
1800 static void cta_hdr_static_metadata_block(const unsigned char *x, unsigned length)
1802 unsigned i;
1804 if (length < 2) {
1805 fail("Empty Data Block with length %u.\n", length);
1806 return;
1808 printf(" Electro optical transfer functions:\n");
1809 for (i = 0; i < 6; i++) {
1810 if (x[0] & (1 << i)) {
1811 if (i < ARRAY_SIZE(eotf_map)) {
1812 printf(" %s\n", eotf_map[i]);
1813 } else {
1814 printf(" Unknown (%u)\n", i);
1815 fail("Unknown EOTF (%u).\n", i);
1819 printf(" Supported static metadata descriptors:\n");
1820 for (i = 0; i < 8; i++) {
1821 if (x[1] & (1 << i))
1822 printf(" Static metadata type %u\n", i + 1);
1825 if (length >= 3)
1826 printf(" Desired content max luminance: %u (%.3f cd/m^2)\n",
1827 x[2], 50.0 * pow(2, x[2] / 32.0));
1829 if (length >= 4)
1830 printf(" Desired content max frame-average luminance: %u (%.3f cd/m^2)\n",
1831 x[3], 50.0 * pow(2, x[3] / 32.0));
1833 if (length >= 5)
1834 printf(" Desired content min luminance: %u (%.3f cd/m^2)\n",
1835 x[4], (50.0 * pow(2, x[2] / 32.0)) * pow(x[4] / 255.0, 2) / 100.0);
1838 static void cta_hdr_dyn_metadata_block(const unsigned char *x, unsigned length)
1840 if (length < 3) {
1841 fail("Empty Data Block with length %u.\n", length);
1842 return;
1844 while (length >= 3) {
1845 unsigned type_len = x[0];
1846 unsigned type = x[1] | (x[2] << 8);
1848 if (length < type_len + 1)
1849 return;
1850 printf(" HDR Dynamic Metadata Type %u\n", type);
1851 switch (type) {
1852 case 1:
1853 case 4:
1854 if (type_len > 2)
1855 printf(" Version: %u\n", x[3] & 0xf);
1856 break;
1857 case 2:
1858 if (type_len > 2) {
1859 unsigned version = x[3] & 0xf;
1860 printf(" Version: %u\n", version);
1861 if (version >= 1) {
1862 if (x[3] & 0x10) printf(" Supports SL-HDR1 (ETSI TS 103 433-1)\n");
1863 if (x[3] & 0x20) printf(" Supports SL-HDR2 (ETSI TS 103 433-2)\n");
1864 if (x[3] & 0x40) printf(" Supports SL-HDR3 (ETSI TS 103 433-3)\n");
1867 break;
1868 default:
1869 break;
1871 length -= type_len + 1;
1872 x += type_len + 1;
1876 static void cta_ifdb(const unsigned char *x, unsigned length)
1878 unsigned len_hdr = x[0] >> 5;
1880 if (length < 2) {
1881 fail("Empty Data Block with length %u.\n", length);
1882 return;
1884 printf(" VSIFs: %u\n", x[1]);
1885 if (length < len_hdr + 2)
1886 return;
1887 length -= len_hdr + 2;
1888 x += len_hdr + 2;
1889 while (length > 0) {
1890 int payload_len = x[0] >> 5;
1892 if ((x[0] & 0x1f) == 1 && length >= 4) {
1893 unsigned oui = (x[3] << 16) | (x[2] << 8) | x[1];
1895 printf(" InfoFrame Type Code %u, OUI %s\n",
1896 x[0] & 0x1f, ouitohex(oui).c_str());
1897 x += 4;
1898 length -= 4;
1899 } else {
1900 printf(" InfoFrame Type Code %u\n", x[0] & 0x1f);
1901 x++;
1902 length--;
1904 x += payload_len;
1905 length -= payload_len;
1909 void edid_state::cta_displayid_type_7(const unsigned char *x, unsigned length)
1911 check_displayid_datablock_revision(x[0], 0x00, 2);
1913 if (length < 21U + ((x[0] & 0x70) >> 4)) {
1914 fail("Empty Data Block with length %u.\n", length);
1915 return;
1917 parse_displayid_type_1_7_timing(x + 1, true, 2, true);
1920 void edid_state::cta_displayid_type_8(const unsigned char *x, unsigned length)
1922 check_displayid_datablock_revision(x[0], 0xe8, 1);
1923 if (length < ((x[0] & 0x08) ? 3 : 2)) {
1924 fail("Empty Data Block with length %u.\n", length);
1925 return;
1928 unsigned sz = (x[0] & 0x08) ? 2 : 1;
1929 unsigned type = x[0] >> 6;
1931 if (type) {
1932 fail("Only code type 0 is supported.\n");
1933 return;
1936 if (x[0] & 0x20)
1937 printf(" Also supports YCbCr 4:2:0\n");
1939 x++;
1940 length--;
1941 for (unsigned i = 0; i < length / sz; i++) {
1942 unsigned id = x[i * sz];
1944 if (sz == 2)
1945 id |= x[i * sz + 1] << 8;
1946 parse_displayid_type_4_8_timing(type, id, true);
1950 void edid_state::cta_displayid_type_10(const unsigned char *x, unsigned length)
1952 check_displayid_datablock_revision(x[0], 0x70);
1953 if (length < 7U + ((x[0] & 0x70) >> 4)) {
1954 fail("Empty Data Block with length %u.\n", length);
1955 return;
1958 unsigned sz = 6U + ((x[0] & 0x70) >> 4);
1959 x++;
1960 length--;
1961 for (unsigned i = 0; i < length / sz; i++)
1962 parse_displayid_type_10_timing(x + i * sz, sz, true);
1965 static void cta_hdmi_audio_block(const unsigned char *x, unsigned length)
1967 unsigned num_descs;
1969 if (length < 2) {
1970 fail("Empty Data Block with length %u.\n", length);
1971 return;
1973 if (x[0] & 3)
1974 printf(" Max Stream Count: %u\n", (x[0] & 3) + 1);
1975 if (x[0] & 4)
1976 printf(" Supports MS NonMixed\n");
1978 num_descs = x[1] & 7;
1979 if (num_descs == 0)
1980 return;
1981 length -= 2;
1982 x += 2;
1983 while (length >= 4) {
1984 if (length > 4) {
1985 unsigned format = x[0] & 0xf;
1987 printf(" %s, max channels %u\n", audio_format(format).c_str(),
1988 (x[1] & 0x1f)+1);
1989 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
1990 (x[2] & 0x40) ? " 192" : "",
1991 (x[2] & 0x20) ? " 176.4" : "",
1992 (x[2] & 0x10) ? " 96" : "",
1993 (x[2] & 0x08) ? " 88.2" : "",
1994 (x[2] & 0x04) ? " 48" : "",
1995 (x[2] & 0x02) ? " 44.1" : "",
1996 (x[2] & 0x01) ? " 32" : "");
1997 if (format == 1)
1998 printf(" Supported sample sizes (bits):%s%s%s\n",
1999 (x[3] & 0x04) ? " 24" : "",
2000 (x[3] & 0x02) ? " 20" : "",
2001 (x[3] & 0x01) ? " 16" : "");
2002 } else {
2003 unsigned sad = ((x[2] << 16) | (x[1] << 8) | x[0]);
2004 unsigned i;
2006 switch (x[3] >> 4) {
2007 case 1:
2008 printf(" Speaker Allocation for 10.2 channels:\n");
2009 break;
2010 case 2:
2011 printf(" Speaker Allocation for 22.2 channels:\n");
2012 break;
2013 case 3:
2014 printf(" Speaker Allocation for 30.2 channels:\n");
2015 break;
2016 default:
2017 printf(" Unknown Speaker Allocation (0x%02x)\n", x[3] >> 4);
2018 return;
2021 for (i = 0; i < ARRAY_SIZE(speaker_map); i++) {
2022 if ((sad >> i) & 1)
2023 printf(" %s\n", speaker_map[i]);
2026 length -= 4;
2027 x += 4;
2031 void edid_state::cta_block(const unsigned char *x, std::vector<unsigned> &found_tags)
2033 unsigned length = x[0] & 0x1f;
2034 unsigned tag = (x[0] & 0xe0) >> 5;
2035 unsigned extended = (tag == 0x07) ? 1 : 0;
2037 x++;
2038 if (extended && length) {
2039 tag <<= 8;
2040 tag |= x[0];
2041 length--;
2042 x++;
2045 bool dooutputname = true;
2046 bool audio_block = false;
2047 data_block.clear();
2049 switch (tag) {
2050 case 0x01: data_block = "Audio Data Block"; audio_block = true; break;
2051 case 0x02: data_block = "Video Data Block"; break;
2052 case 0x03: data_block = "Vendor-Specific Data Block"; break;
2053 case 0x04: data_block = "Speaker Allocation Data Block"; audio_block = true; break;
2054 case 0x05: data_block = "VESA Display Transfer Characteristics Data Block"; break;
2056 case 0x07: data_block = "Unknown CTA-861 Data Block (extended tag truncated)"; break;
2058 case 0x700: data_block = "Video Capability Data Block"; break;
2059 case 0x701: data_block = "Vendor-Specific Video Data Block"; break;
2060 case 0x702: data_block = "VESA Video Display Device Data Block"; break;
2061 case 0x703: data_block = "VESA Video Timing Block Extension"; break;
2062 case 0x704: data_block = "Reserved for HDMI Video Data Block"; break;
2063 case 0x705: data_block = "Colorimetry Data Block"; break;
2064 case 0x706: data_block = "HDR Static Metadata Data Block"; break;
2065 case 0x707: data_block = "HDR Dynamic Metadata Data Block"; break;
2067 case 0x70d: data_block = "Video Format Preference Data Block"; break;
2068 case 0x70e: data_block = "YCbCr 4:2:0 Video Data Block"; break;
2069 case 0x70f: data_block = "YCbCr 4:2:0 Capability Map Data Block"; break;
2070 case 0x710: data_block = "Reserved for CTA-861 Miscellaneous Audio Fields"; break;
2071 case 0x711: data_block = "Vendor-Specific Audio Data Block"; audio_block = true; break;
2072 case 0x712: data_block = "HDMI Audio Data Block"; audio_block = true; break;
2073 case 0x713: data_block = "Room Configuration Data Block"; audio_block = true; break;
2074 case 0x714: data_block = "Speaker Location Data Block"; audio_block = true; break;
2076 case 0x720: data_block = "InfoFrame Data Block"; break;
2078 case 0x734: data_block = "DisplayID Type VII Video Timing Data Block"; break;
2079 case 0x735: data_block = "DisplayID Type VIII Video Timing Data Block"; break;
2080 case 0x742: data_block = "DisplayID Type X Video Timing Data Block"; break;
2082 case 0x778: data_block = "HDMI Forum EDID Extension Override Data Block"; break;
2083 case 0x779: data_block = "HDMI Forum Sink Capability Data Block"; break;
2085 default:
2086 std::string unknown_name;
2087 if (tag < 0x700) unknown_name = "Unknown CTA-861 Data Block";
2088 else if (tag < 0x70d) unknown_name = "Unknown CTA-861 Video-Related Data Block";
2089 else if (tag < 0x720) unknown_name = "Unknown CTA-861 Audio-Related Data Block";
2090 else if (tag < 0x778) unknown_name = "Unknown CTA-861 Data Block";
2091 else if (tag < 0x780) unknown_name = "Unknown CTA-861 HDMI-Related Data Block";
2092 else unknown_name = "Unknown CTA-861 Data Block";
2093 unknown_name += std::string(" (") + (extended ? "extended " : "") + "tag " + utohex(tag & 0xff) + ", length " + std::to_string(length) + ")";
2094 printf(" %s:\n", unknown_name.c_str());
2095 warn("%s.\n", unknown_name.c_str());
2096 break;
2099 switch (tag) {
2100 case 0x03:
2101 case 0x701:
2102 case 0x711: {
2103 unsigned ouinum;
2105 data_block_oui(data_block, x, length, &ouinum);
2106 x += (length < 3) ? length : 3;
2107 length -= (length < 3) ? length : 3;
2108 dooutputname = false;
2109 tag |= ouinum;
2110 break;
2114 if (dooutputname && data_block.length())
2115 printf(" %s:\n", data_block.c_str());
2117 switch (tag) {
2118 case 0x04:
2119 case 0x05:
2120 case 0x700:
2121 case 0x702:
2122 case 0x705:
2123 case 0x706:
2124 case 0x70d:
2125 case 0x70f:
2126 case 0x712:
2127 case 0x713:
2128 case 0x778:
2129 case 0x779:
2130 if (std::find(found_tags.begin(), found_tags.end(), tag) != found_tags.end())
2131 fail("Only one instance of this Data Block is allowed.\n");
2132 break;
2135 // See Table 52 of CTA-861-G for a description of Byte 3
2136 if (audio_block && !(cta.byte3 & 0x40))
2137 fail("Audio information is present, but bit 6 of Byte 3 of the CTA-861 Extension header indicates no Basic Audio support.\n");
2139 switch (tag) {
2140 case 0x01: cta_audio_block(x, length); break;
2141 case 0x02: cta_svd(x, length, false); break;
2142 case 0x03|kOUI_HDMI:
2143 cta_hdmi_block(x, length);
2144 // The HDMI OUI is present, so this EDID represents an HDMI
2145 // interface. And HDMI interfaces must use EDID version 1.3
2146 // according to the HDMI Specification, so check for this.
2147 if (base.edid_minor != 3)
2148 fail("The HDMI Specification requires EDID 1.3 instead of 1.%u.\n",
2149 base.edid_minor);
2150 break;
2151 case 0x03|kOUI_HDMIForum:
2152 if (cta.previous_cta_tag != (0x03|kOUI_HDMI))
2153 fail("HDMI Forum VSDB did not immediately follow the HDMI VSDB.\n");
2154 if (cta.have_hf_scdb || cta.have_hf_vsdb)
2155 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2156 cta_hf_scdb(x, length);
2157 cta.have_hf_vsdb = true;
2158 break;
2159 case 0x03|kOUI_AMD: cta_amd(x, length); break;
2160 case 0x03|kOUI_Microsoft: if (length != 0x12) goto dodefault; cta_microsoft(x, length); break;
2161 case 0x04: cta_sadb(x, length); break;
2162 case 0x05: cta_vesa_dtcdb(x, length); break;
2163 case 0x07: fail("Extended tag cannot have zero length.\n"); break;
2164 case 0x700: cta_vcdb(x, length); break;
2165 case 0x701|kOUI_HDR10: cta_hdr10plus(x, length); break;
2166 case 0x701|kOUI_Dolby: cta_dolby_video(x, length); break;
2167 case 0x702: cta_vesa_vdddb(x, length); break;
2168 case 0x705: cta_colorimetry_block(x, length); break;
2169 case 0x706: cta_hdr_static_metadata_block(x, length); break;
2170 case 0x707: cta_hdr_dyn_metadata_block(x, length); break;
2171 case 0x70d: cta_vfpdb(x, length); break;
2172 case 0x70e: cta_svd(x, length, true); break;
2173 case 0x70f: cta_y420cmdb(x, length); break;
2174 case 0x711|kOUI_Dolby: cta_dolby_audio(x, length); break;
2175 case 0x712: cta_hdmi_audio_block(x, length); break;
2176 case 0x713: cta_rcdb(x, length); break;
2177 case 0x714: cta_sldb(x, length); break;
2178 case 0x720: cta_ifdb(x, length); break;
2179 case 0x734: cta_displayid_type_7(x, length); break;
2180 case 0x735: cta_displayid_type_8(x, length); break;
2181 case 0x742: cta_displayid_type_10(x, length); break;
2182 case 0x778:
2183 cta_hf_eeodb(x, length);
2184 // This must be the first CTA-861 block
2185 if (cta.block_number > 0)
2186 fail("Block starts at a wrong offset.\n");
2187 break;
2188 case 0x779:
2189 if (cta.previous_cta_tag != (0x03|kOUI_HDMI))
2190 fail("HDMI Forum SCDB did not immediately follow the HDMI VSDB.\n");
2191 if (cta.have_hf_scdb || cta.have_hf_vsdb)
2192 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2193 if (length < 2) {
2194 data_block = std::string("HDMI Forum SCDB");
2195 fail("Invalid length %u < 2.\n", length);
2196 break;
2198 if (x[0] || x[1])
2199 printf(" Non-zero SCDB reserved fields!\n");
2200 cta_hf_scdb(x + 2, length - 2);
2201 cta.have_hf_scdb = true;
2202 break;
2203 dodefault:
2204 default:
2205 hex_block(" ", x, length);
2206 break;
2209 cta.block_number++;
2210 cta.previous_cta_tag = tag;
2211 found_tags.push_back(tag);
2214 void edid_state::preparse_cta_block(const unsigned char *x)
2216 unsigned version = x[1];
2217 unsigned offset = x[2];
2219 if (offset >= 4) {
2220 const unsigned char *detailed;
2222 for (detailed = x + offset; detailed + 17 < x + 127; detailed += 18) {
2223 if (memchk(detailed, 18))
2224 break;
2225 if (detailed[0] || detailed[1])
2226 cta.preparsed_total_dtds++;
2230 if (version < 3)
2231 return;
2233 for (unsigned i = 4; i < offset; i += (x[i] & 0x1f) + 1) {
2234 bool for_ycbcr420 = false;
2235 unsigned oui;
2237 switch ((x[i] & 0xe0) >> 5) {
2238 case 0x03:
2239 oui = (x[i + 3] << 16) + (x[i + 2] << 8) + x[i + 1];
2240 if (oui == 0x000c03) {
2241 cta.has_hdmi = true;
2242 cta.preparsed_phys_addr = (x[i + 4] << 8) | x[i + 5];
2244 break;
2245 case 0x07:
2246 if (x[i + 1] == 0x0d)
2247 cta.has_vfpdb = true;
2248 if (x[i + 1] == 0x13 && (x[i + 2] & 0x40)) {
2249 cta.preparsed_speaker_count = 1 + (x[i + 2] & 0x1f);
2250 cta.preparsed_sld = x[i + 2] & 0x20;
2252 if (x[i + 1] == 0x14)
2253 cta_preparse_sldb(x + i + 2, (x[i] & 0x1f) - 1);
2254 if (x[i + 1] == 0x22)
2255 cta.preparsed_total_vtdbs++;
2256 if (x[i + 1] == 0x23)
2257 cta.preparsed_has_t8vtdb = true;
2258 if (x[i + 1] == 0x32)
2259 cta.preparsed_total_vtdbs +=
2260 ((x[i] & 0x1f) - 2) / (6 + ((x[i + 2] & 0x70) >> 4));
2261 if (x[i + 1] != 0x0e)
2262 continue;
2263 for_ycbcr420 = true;
2264 /* fall-through */
2265 case 0x02:
2266 for (unsigned j = 1 + for_ycbcr420; j <= (x[i] & 0x1f); j++) {
2267 unsigned char vic = x[i + j];
2269 if ((vic & 0x7f) <= 64)
2270 vic &= 0x7f;
2271 cta.preparsed_svds[for_ycbcr420].push_back(vic);
2272 cta.preparsed_has_vic[for_ycbcr420][vic] = true;
2274 break;
2279 void edid_state::parse_cta_block(const unsigned char *x)
2281 unsigned version = x[1];
2282 unsigned offset = x[2];
2283 const unsigned char *detailed;
2285 // See Table 52 of CTA-861-G for a description of Byte 3
2287 printf(" Revision: %u\n", version);
2288 if (version == 0)
2289 fail("Invalid CTA-861 Extension revision 0.\n");
2290 if (version == 2)
2291 fail("Deprecated CTA-861 Extension revision 2.\n");
2292 if (cta.has_hdmi && version != 3)
2293 fail("The HDMI Specification requires CTA Extension revision 3.\n");
2294 if (version > 3)
2295 warn("Unknown CTA-861 Extension revision %u.\n", version);
2297 if (version >= 1) do {
2298 if (version == 1 && x[3] != 0)
2299 fail("Non-zero byte 3.\n");
2301 if (offset < 4)
2302 break;
2304 if (version < 3 && ((offset - 4) / 8)) {
2305 printf(" 8-byte timing descriptors: %u\n", (offset - 4) / 8);
2306 fail("8-byte descriptors were never used.\n");
2309 if (version >= 2) {
2310 if (x[3] & 0x80)
2311 printf(" Underscans IT Video Formats by default\n");
2312 else
2313 warn("IT Video Formats are overscanned by default, but normally this should be underscanned.\n");
2314 if (x[3] & 0x40)
2315 printf(" Basic audio support\n");
2316 if (x[3] & 0x20)
2317 printf(" Supports YCbCr 4:4:4\n");
2318 if (x[3] & 0x10)
2319 printf(" Supports YCbCr 4:2:2\n");
2320 // Disable this test: this fails a lot of EDIDs, and there are
2321 // also some corner cases where you only want to receive 4:4:4
2322 // and refuse a fallback to 4:2:2.
2323 // if ((x[3] & 0x30) && (x[3] & 0x30) != 0x30)
2324 // msg(!cta.has_hdmi, "If YCbCr support is indicated, then both 4:2:2 and 4:4:4 %s be supported.\n",
2325 // cta.has_hdmi ? "shall" : "should");
2326 printf(" Native detailed modes: %u\n", x[3] & 0x0f);
2327 if (cta.block_number == 0)
2328 cta.byte3 = x[3];
2329 else if (x[3] != cta.byte3)
2330 fail("Byte 3 must be the same for all CTA-861 Extension Blocks.\n");
2331 if (cta.block_number == 0) {
2332 unsigned native_dtds = x[3] & 0x0f;
2334 cta.native_timings.clear();
2335 if (!native_dtds && !cta.has_vfpdb) {
2336 cta.first_svd_might_be_preferred = true;
2337 } else if (native_dtds > cta.preparsed_total_dtds) {
2338 fail("There are more Native DTDs (%u) than DTDs (%u).\n",
2339 native_dtds, cta.preparsed_total_dtds);
2341 if (native_dtds > cta.preparsed_total_dtds)
2342 native_dtds = cta.preparsed_total_dtds;
2343 for (unsigned i = 0; i < native_dtds; i++) {
2344 char type[16];
2346 sprintf(type, "DTD %3u", i + 1);
2347 cta.native_timings.push_back(timings_ext(i + 129, type));
2349 if (cta.has_hdmi && block_nr != (block_map.saw_block_1 ? 2 : 1))
2350 fail("The HDMI Specification requires that the first Extension Block (that is not a Block Map) is an CTA-861 Extension Block.\n");
2353 if (version >= 3) {
2354 unsigned i;
2356 for (i = 4; i < offset; i += (x[i] & 0x1f) + 1) {
2357 cta_block(x + i, cta.found_tags);
2360 data_block.clear();
2361 if (i != offset)
2362 fail("Offset is %u, but should be %u.\n", offset, i);
2365 data_block = "Detailed Timing Descriptors";
2366 base.seen_non_detailed_descriptor = false;
2367 bool first = true;
2368 for (detailed = x + offset; detailed + 17 < x + 127; detailed += 18) {
2369 if (memchk(detailed, 18))
2370 break;
2371 if (first) {
2372 first = false;
2373 printf(" %s:\n", data_block.c_str());
2375 detailed_block(detailed);
2377 if (!memchk(detailed, x + 127 - detailed)) {
2378 data_block = "Padding";
2379 fail("CTA-861 padding contains non-zero bytes.\n");
2381 } while (0);
2383 data_block.clear();
2384 if (base.has_serial_number && base.has_serial_string)
2385 warn("Display Product Serial Number is set, so the Serial Number in the Base EDID should be 0.\n");
2386 if (!cta.has_vic_1 && !base.has_640x480p60_est_timing)
2387 fail("Required 640x480p60 timings are missing in the established timings"
2388 " and the SVD list (VIC 1).\n");
2389 if ((cta.supported_hdmi_vic_vsb_codes & cta.supported_hdmi_vic_codes) !=
2390 cta.supported_hdmi_vic_codes)
2391 fail("HDMI VIC Codes must have their CTA-861 VIC equivalents in the VSB.\n");
2392 if (!cta.has_vcdb)
2393 fail("Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.\n");
2396 void edid_state::cta_resolve_svr(vec_timings_ext::iterator iter)
2398 if (iter->svr() == 254) {
2399 iter->flags = cta.t8vtdb.flags;
2400 iter->t = cta.t8vtdb.t;
2401 } else if (iter->svr() <= 144) {
2402 iter->flags = cta.vec_dtds[iter->svr() - 129].flags;
2403 iter->t = cta.vec_dtds[iter->svr() - 129].t;
2404 } else {
2405 iter->flags = cta.vec_vtdbs[iter->svr() - 145].flags;
2406 iter->t = cta.vec_vtdbs[iter->svr() - 145].t;
2410 void edid_state::cta_resolve_svrs()
2412 for (vec_timings_ext::iterator iter = cta.preferred_timings.begin();
2413 iter != cta.preferred_timings.end(); ++iter) {
2414 if (iter->has_svr())
2415 cta_resolve_svr(iter);
2418 for (vec_timings_ext::iterator iter = cta.native_timings.begin();
2419 iter != cta.native_timings.end(); ++iter) {
2420 if (iter->has_svr())
2421 cta_resolve_svr(iter);
2425 void edid_state::check_cta_blocks()
2427 unsigned max_pref_prog_hact = 0;
2428 unsigned max_pref_prog_vact = 0;
2429 unsigned max_pref_ilace_hact = 0;
2430 unsigned max_pref_ilace_vact = 0;
2432 data_block = "CTA-861";
2433 for (vec_timings_ext::iterator iter = cta.preferred_timings.begin();
2434 iter != cta.preferred_timings.end(); ++iter) {
2435 if (iter->t.interlaced &&
2436 (iter->t.vact > max_pref_ilace_vact ||
2437 (iter->t.vact == max_pref_ilace_vact && iter->t.hact >= max_pref_ilace_hact))) {
2438 max_pref_ilace_hact = iter->t.hact;
2439 max_pref_ilace_vact = iter->t.vact;
2441 if (!iter->t.interlaced &&
2442 (iter->t.vact > max_pref_prog_vact ||
2443 (iter->t.vact == max_pref_prog_vact && iter->t.hact >= max_pref_prog_hact))) {
2444 max_pref_prog_hact = iter->t.hact;
2445 max_pref_prog_vact = iter->t.vact;
2449 unsigned native_prog = 0;
2450 unsigned native_prog_hact = 0;
2451 unsigned native_prog_vact = 0;
2452 bool native_prog_mixed_resolutions = false;
2453 unsigned native_ilace = 0;
2454 unsigned native_ilace_hact = 0;
2455 unsigned native_ilace_vact = 0;
2456 bool native_ilace_mixed_resolutions = false;
2458 for (vec_timings_ext::iterator iter = cta.native_timings.begin();
2459 iter != cta.native_timings.end(); ++iter) {
2460 if (iter->t.interlaced) {
2461 native_ilace++;
2462 if (!native_ilace_hact) {
2463 native_ilace_hact = iter->t.hact;
2464 native_ilace_vact = iter->t.vact;
2465 } else if (native_ilace_hact != iter->t.hact ||
2466 native_ilace_vact != iter->t.vact) {
2467 native_ilace_mixed_resolutions = true;
2469 } else {
2470 native_prog++;
2471 if (!native_prog_hact) {
2472 native_prog_hact = iter->t.hact;
2473 native_prog_vact = iter->t.vact;
2474 } else if (native_prog_hact != iter->t.hact ||
2475 native_prog_vact != iter->t.vact) {
2476 native_prog_mixed_resolutions = true;
2481 if (native_prog_mixed_resolutions)
2482 fail("Native progressive timings are a mix of several resolutions.\n");
2483 if (native_ilace_mixed_resolutions)
2484 fail("Native interlaced timings are a mix of several resolutions.\n");
2485 if (native_ilace && !native_prog)
2486 fail("A native interlaced timing is present, but not a native progressive timing.\n");
2487 if (!native_prog_mixed_resolutions && native_prog > 1)
2488 warn("Multiple native progressive timings are defined.\n");
2489 if (!native_ilace_mixed_resolutions && native_ilace > 1)
2490 warn("Multiple native interlaced timings are defined.\n");
2492 if (!native_prog_mixed_resolutions && native_prog_vact &&
2493 (max_pref_prog_vact > native_prog_vact ||
2494 (max_pref_prog_vact == native_prog_vact && max_pref_prog_hact > native_prog_hact)))
2495 warn("Native progressive resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
2496 native_prog_hact, native_prog_vact,
2497 max_pref_prog_hact, max_pref_prog_vact);
2498 if (!native_ilace_mixed_resolutions && native_ilace_vact &&
2499 (max_pref_ilace_vact > native_ilace_vact ||
2500 (max_pref_ilace_vact == native_ilace_vact && max_pref_ilace_hact > native_ilace_hact)))
2501 warn("Native interlaced resolution of %ux%u is smaller than the max preferred interlaced resolution %ux%u.\n",
2502 native_ilace_hact, native_ilace_vact,
2503 max_pref_ilace_hact, max_pref_ilace_vact);
2505 if (dispid.native_width && native_prog_hact &&
2506 !native_prog_mixed_resolutions) {
2507 if (dispid.native_width != native_prog_hact ||
2508 dispid.native_height != native_prog_vact)
2509 fail("Mismatch between CTA-861 and DisplayID native progressive resolution.\n");