edid-decode: detect dummy serial number values
[edid-decode.git] / parse-cta-block.cpp
blobd1d6ca0f799195ec445bfdf53fc11bd24df32c9a
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 bool cta_matches_vic(const timings &t, unsigned &vic)
324 for (vic = 1; vic <= ARRAY_SIZE(edid_cta_modes1); vic++) {
325 if (match_timings(t, edid_cta_modes1[vic - 1]))
326 return true;
328 for (vic = 193; vic < ARRAY_SIZE(edid_cta_modes2) + 193; vic++) {
329 if (match_timings(t, edid_cta_modes1[vic - 193]))
330 return true;
332 vic = 0;
333 return false;
336 void edid_state::cta_list_vics()
338 char type[16];
339 for (unsigned vic = 1; vic <= ARRAY_SIZE(edid_cta_modes1); vic++) {
340 sprintf(type, "VIC %3u", vic);
341 print_timings("", &edid_cta_modes1[vic - 1], type, "", false, false);
343 for (unsigned vic = 193; vic < ARRAY_SIZE(edid_cta_modes2) + 193; vic++) {
344 sprintf(type, "VIC %3u", vic);
345 print_timings("", &edid_cta_modes2[vic - 193], type, "", false, false);
349 void edid_state::cta_list_hdmi_vics()
351 for (unsigned i = 0; i < ARRAY_SIZE(edid_hdmi_mode_map); i++) {
352 unsigned vic = edid_hdmi_mode_map[i];
353 char type[16];
355 sprintf(type, "HDMI VIC %u", i + 1);
356 print_timings("", find_vic_id(vic), type, "", false, false);
360 void edid_state::cta_list_rids()
362 for (unsigned i = 1; i < ARRAY_SIZE(rids); i++) {
363 printf("RID %2u: %5ux%-4u %2u:%-2u\n", i,
364 rids[i].hact, rids[i].vact,
365 rids[i].hratio, rids[i].vratio);
369 void edid_state::cta_list_rid_timings(unsigned list_rid)
371 for (unsigned rid = 1; rid < ARRAY_SIZE(rids); rid++) {
372 char type[16];
374 if (list_rid && rid != list_rid)
375 continue;
377 sprintf(type, "RID %u", rid);
378 for (unsigned i = 1; i < ARRAY_SIZE(vf_rate_values); i++) {
379 unsigned fps = vf_rate_values[i];
381 if (rid_to_vic(rid, i)) {
382 printf("%s: %5ux%-4u %7.3f Hz %3u:%-2u maps to VIC %u\n", type,
383 rids[rid].hact, rids[rid].vact, (double)fps,
384 rids[rid].hratio, rids[rid].vratio,
385 rid_to_vic(rid, i));
386 continue;
388 timings t = calc_ovt_mode(rids[rid].hact, rids[rid].vact,
389 rids[rid].hratio, rids[rid].vratio, fps);
390 print_timings("", &t, type, "", false, false);
395 static std::string audio_ext_format(unsigned char x)
397 if (x >= 1 && x <= 3)
398 fail("Obsolete Audio Ext Format 0x%02x.\n", x);
399 switch (x) {
400 case 1: return "HE AAC (Obsolete)";
401 case 2: return "HE AAC v2 (Obsolete)";
402 case 3: return "MPEG Surround (Obsolete)";
403 case 4: return "MPEG-4 HE AAC";
404 case 5: return "MPEG-4 HE AAC v2";
405 case 6: return "MPEG-4 AAC LC";
406 case 7: return "DRA";
407 case 8: return "MPEG-4 HE AAC + MPEG Surround";
408 case 10: return "MPEG-4 AAC LC + MPEG Surround";
409 case 11: return "MPEG-H 3D Audio";
410 case 12: return "AC-4";
411 case 13: return "L-PCM 3D Audio";
412 case 14: return "Auro-Cx";
413 case 15: return "MPEG-D USAC";
414 default: break;
416 fail("Unknown Audio Ext Format 0x%02x.\n", x);
417 return std::string("Unknown Audio Ext Format (") + utohex(x) + ")";
420 static std::string audio_format(unsigned char x)
422 switch (x) {
423 case 1: return "Linear PCM";
424 case 2: return "AC-3";
425 case 3: return "MPEG 1 (Layers 1 & 2)";
426 case 4: return "MPEG 1 Layer 3 (MP3)";
427 case 5: return "MPEG2 (multichannel)";
428 case 6: return "AAC LC";
429 case 7: return "DTS";
430 case 8: return "ATRAC";
431 case 9: return "One Bit Audio";
432 case 10: return "Enhanced AC-3 (DD+)";
433 case 11: return "DTS-HD";
434 case 12: return "MAT (MLP)";
435 case 13: return "DST";
436 case 14: return "WMA Pro";
437 default: break;
439 fail("Unknown Audio Format 0x%02x.\n", x);
440 return std::string("Unknown Audio Format (") + utohex(x) + ")";
443 static std::string mpeg_h_3d_audio_level(unsigned char x)
445 switch (x) {
446 case 0: return "Unspecified";
447 case 1: return "Level 1";
448 case 2: return "Level 2";
449 case 3: return "Level 3";
450 case 4: return "Level 4";
451 case 5: return "Level 5";
452 default: break;
454 fail("Unknown MPEG-H 3D Audio Level 0x%02x.\n", x);
455 return std::string("Unknown MPEG-H 3D Audio Level (") + utohex(x) + ")";
458 static void cta_audio_block(const unsigned char *x, unsigned length)
460 unsigned i, format, ext_format;
462 if (length % 3) {
463 fail("Broken CTA-861 audio block length %d.\n", length);
464 return;
467 for (i = 0; i < length; i += 3) {
468 format = (x[i] & 0x78) >> 3;
469 if (format == 0) {
470 printf(" Reserved (0x00)\n");
471 fail("Audio Format Code 0x00 is reserved.\n");
472 continue;
474 if (format != 15) {
475 ext_format = 0;
476 printf(" %s:\n", audio_format(format).c_str());
477 } else {
478 ext_format = (x[i + 2] & 0xf8) >> 3;
479 printf(" %s:\n", audio_ext_format(ext_format).c_str());
481 if (format != 15)
482 printf(" Max channels: %u\n", (x[i] & 0x07)+1);
483 else if (ext_format == 11)
484 printf(" MPEG-H 3D Audio Level: %s\n",
485 mpeg_h_3d_audio_level(x[i] & 0x07).c_str());
486 else if (ext_format == 13)
487 printf(" Max channels: %u\n",
488 (((x[i + 1] & 0x80) >> 3) | ((x[i] & 0x80) >> 4) |
489 (x[i] & 0x07))+1);
490 else if ((ext_format == 12 || ext_format == 14) && (x[i] & 0x07))
491 fail("Bits F10-F12 must be 0.\n");
492 else
493 printf(" Max channels: %u\n", (x[i] & 0x07)+1);
495 if ((format == 1 || format == 14) && (x[i + 2] & 0xf8))
496 fail("Bits F33-F37 must be 0.\n");
497 if (ext_format != 13 && (x[i+1] & 0x80))
498 fail("Bit F27 must be 0.\n");
500 // Several sample rates are not supported in certain formats
501 if (ext_format == 12 && (x[i+1] & 0x29))
502 fail("Bits F20, F23 and F25 must be 0.\n");
503 if (ext_format >= 4 && ext_format <= 6 && (x[i+1] & 0x60))
504 fail("Bits F25 and F26 must be 0.\n");
505 if ((ext_format == 8 || ext_format == 10 || ext_format == 15) && (x[i+1] & 0x60))
506 fail("Bits F25 and F26 must be 0.\n");
508 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
509 (x[i+1] & 0x40) ? " 192" : "",
510 (x[i+1] & 0x20) ? " 176.4" : "",
511 (x[i+1] & 0x10) ? " 96" : "",
512 (x[i+1] & 0x08) ? " 88.2" : "",
513 (x[i+1] & 0x04) ? " 48" : "",
514 (x[i+1] & 0x02) ? " 44.1" : "",
515 (x[i+1] & 0x01) ? " 32" : "");
516 if (format == 1 || ext_format == 13) {
517 printf(" Supported sample sizes (bits):%s%s%s\n",
518 (x[i+2] & 0x04) ? " 24" : "",
519 (x[i+2] & 0x02) ? " 20" : "",
520 (x[i+2] & 0x01) ? " 16" : "");
521 } else if (format <= 8) {
522 printf(" Maximum bit rate: %u kb/s\n", x[i+2] * 8);
523 } else if (format == 10) {
524 // As specified by the "Dolby Audio and Dolby Atmos over HDMI"
525 // specification (v1.0).
526 if (x[i+2] & 1)
527 printf(" Supports Joint Object Coding\n");
528 if (x[i+2] & 2)
529 printf(" Supports Joint Object Coding with ACMOD28\n");
530 } else if (format == 11) {
531 // Reverse engineering, see:
532 // https://www.avsforum.com/threads/lg-c9-earc-info-thread.3072900/post-61795538
533 if (x[i+2] & 2)
534 printf(" Supports DTS:X\n");
535 // Note: I strongly suspect that bit 0 indicates DTS-HD MA support.
536 printf(" Audio Format Code dependent value: 0x%02x\n", x[i+2]);
537 } else if (format == 12) {
538 if (x[i+2] & 1) {
539 printf(" Supports Dolby TrueHD, object audio PCM and channel-based PCM\n");
540 printf(" Hash calculation %srequired for object audio PCM or channel-based PCM\n",
541 (x[i+2] & 2) ? "not " : "");
542 } else {
543 printf(" Supports only Dolby TrueHD\n");
545 } else if (format == 14) {
546 printf(" Profile: %u\n", x[i+2] & 7);
547 } else if (format >= 9 && format <= 13) {
548 printf(" Audio Format Code dependent value: 0x%02x\n", x[i+2]);
549 } else if (ext_format == 11 && (x[i+2] & 1)) {
550 printf(" Supports MPEG-H 3D Audio Low Complexity Profile\n");
551 } else if ((ext_format >= 4 && ext_format <= 6) ||
552 ext_format == 8 || ext_format == 10) {
553 printf(" AAC audio frame lengths:%s%s\n",
554 (x[i+2] & 4) ? " 1024_TL" : "",
555 (x[i+2] & 2) ? " 960_TL" : "");
556 if (ext_format >= 8 && (x[i+2] & 1))
557 printf(" Supports %s signaled MPEG Surround data\n",
558 (x[i+2] & 1) ? "implicitly and explicitly" : "only implicitly");
559 if (ext_format == 6 && (x[i+2] & 1))
560 printf(" Supports 22.2ch System H\n");
561 } else if (ext_format == 12 || ext_format == 14) {
562 printf(" Audio Format Code dependent value: %u\n", x[i+2] & 7);
567 void edid_state::cta_svd(const unsigned char *x, unsigned n, bool for_ycbcr420)
569 bool ascending = !for_ycbcr420;
570 unsigned char last_vic = 0;
571 bool first_vic_is_1_to_4 = false;
572 bool have_vics_5_and_up = false;
573 unsigned i;
575 for (i = 0; i < n; i++) {
576 const struct timings *t = NULL;
577 unsigned char svd = x[i];
578 unsigned char native;
579 unsigned char vic;
581 if ((svd & 0x7f) == 0)
582 continue;
584 if ((svd - 1) & 0x40) {
585 vic = svd;
586 native = 0;
587 } else {
588 vic = svd & 0x7f;
589 native = svd & 0x80;
592 if (i == 0)
593 first_vic_is_1_to_4 = vic <= 4;
594 if (vic > 4)
595 have_vics_5_and_up = true;
596 if (vic < last_vic)
597 ascending = false;
598 last_vic = vic;
600 t = find_vic_id(vic);
601 if (t) {
602 switch (vic) {
603 case 95:
604 cta.supported_hdmi_vic_vsb_codes |= 1 << 0;
605 break;
606 case 94:
607 cta.supported_hdmi_vic_vsb_codes |= 1 << 1;
608 break;
609 case 93:
610 cta.supported_hdmi_vic_vsb_codes |= 1 << 2;
611 break;
612 case 98:
613 cta.supported_hdmi_vic_vsb_codes |= 1 << 3;
614 break;
616 bool first_svd = cta.first_svd && !for_ycbcr420;
617 bool override_pref = first_svd && cta.first_svd_might_be_preferred;
619 char type[16];
620 sprintf(type, "VIC %3u", vic);
621 const char *flags = native ? "native" : "";
623 if (for_ycbcr420) {
624 struct timings tmp = *t;
625 tmp.ycbcr420 = true;
626 print_timings(" ", &tmp, type, flags);
627 } else {
628 print_timings(" ", t, type, flags);
630 if (override_pref) {
631 if (!cta.preferred_timings.empty()) {
632 if (match_timings(cta.preferred_timings[0].t, *t))
633 warn("For improved preferred timing interoperability, set 'Native detailed modes' to 1.\n");
634 else
635 warn("VIC %u is the preferred timing, overriding the first detailed timings. Is this intended?\n", vic);
637 cta.preferred_timings.insert(cta.preferred_timings.begin(),
638 timings_ext(*t, type, flags));
639 } else if (first_svd) {
640 cta.preferred_timings.push_back(timings_ext(*t, type, flags));
642 if (first_svd) {
643 cta.first_svd = false;
644 cta.first_svd_might_be_preferred = false;
646 if (native)
647 cta.native_timings.push_back(timings_ext(*t, type, flags));
648 } else {
649 printf(" Unknown (VIC %3u)\n", vic);
650 fail("Unknown VIC %u.\n", vic);
653 if (vic == 1 && !for_ycbcr420)
654 cta.has_vic_1 = 1;
655 if (++cta.vics[vic][for_ycbcr420] == 2)
656 fail("Duplicate %sVIC %u.\n", for_ycbcr420 ? "YCbCr 4:2:0 " : "", vic);
657 if (for_ycbcr420 && cta.preparsed_has_vic[0][vic])
658 fail("YCbCr 4:2:0-only VIC %u is also a regular VIC.\n", vic);
660 if (n > 1 && ascending && first_vic_is_1_to_4 && have_vics_5_and_up)
661 warn("All VICs are in ascending order, and the first (preferred) VIC <= 4, is that intended?\n");
664 cta_vfd edid_state::cta_parse_vfd(const unsigned char *x, unsigned lvfd)
666 cta_vfd vfd = {};
668 vfd.rid = x[0] & 0x3f;
669 if (vfd.rid >= ARRAY_SIZE(rids)) {
670 vfd.rid = 0;
671 return vfd;
673 vfd.bfr50 = !!(x[0] & 0x80);
674 vfd.fr24 = !!(x[0] & 0x40);
675 vfd.bfr60 = lvfd > 1 ? !!(x[1] & 0x80) : 1;
676 vfd.fr144 = lvfd > 1 ? !!(x[1] & 0x40) : 0;
677 vfd.fr_factor = lvfd > 1 ? (x[1] & 0x3f) : 3;
678 vfd.fr48 = lvfd > 2 ? !!(x[2] & 0x01) : 0;
679 return vfd;
682 static bool vfd_has_rate(cta_vfd &vfd, unsigned rate_index)
684 static const unsigned factors[6] = {
685 1, 2, 4, 8, 12, 16
687 unsigned rate = vf_rate_values[rate_index];
688 unsigned factor = 0;
690 if (!vfd.rid)
691 return false;
692 if (rate == 24)
693 return vfd.fr24;
694 if (rate == 48)
695 return vfd.fr48;
696 if (rate == 144)
697 return vfd.fr144;
699 if (!(rate % 30)) {
700 if (!vfd.bfr60)
701 return false;
702 factor = rate / 30;
704 if (!(rate % 25)) {
705 if (!vfd.bfr50)
706 return false;
707 factor = rate / 25;
710 for (unsigned i = 0; i < ARRAY_SIZE(factors); i++)
711 if (factors[i] == factor && (vfd.fr_factor & (1 << i)))
712 return true;
713 return false;
716 void edid_state::cta_vfdb(const unsigned char *x, unsigned n)
718 if (n-- == 0) {
719 fail("Length is 0.\n");
720 return;
722 unsigned char flags = *x++;
723 unsigned lvfd = (flags & 3) + 1;
725 if (n % lvfd) {
726 fail("Length - 1 is not a multiple of Lvfd (%u).\n", lvfd);
727 return;
729 if (flags & 0x80)
730 printf(" Supports YCbCr 4:2:0\n");
731 if (flags & 0x40)
732 printf(" NTSC fractional frame rates are preferred\n");
733 for (unsigned i = 0; i < n; i += lvfd, x += lvfd) {
734 unsigned char rid = x[0] & 0x3f;
735 cta_vfd vfd = cta_parse_vfd(x, lvfd);
737 if (lvfd > 2 && (x[2] & 0xfe))
738 fail("Bits F31-F37 must be 0.\n");
739 if (lvfd > 3 && x[3])
740 fail("Bits F40-F47 must be 0.\n");
741 if (rid == 0 || rid >= ARRAY_SIZE(rids)) {
742 fail("Unknown RID %u.\n", rid);
743 continue;
745 for (unsigned rate_index = 1; rate_index < ARRAY_SIZE(vf_rate_values); rate_index++) {
746 if (!vfd_has_rate(vfd, rate_index))
747 continue;
748 struct timings t = calc_ovt_mode(rids[vfd.rid].hact,
749 rids[vfd.rid].vact,
750 rids[vfd.rid].hratio,
751 rids[vfd.rid].vratio,
752 vf_rate_values[rate_index]);
753 char type[16];
754 sprintf(type, "RID %u@%up", rid, vf_rate_values[rate_index]);
755 print_timings(" ", &t, type);
756 if (rid_to_vic(vfd.rid, rate_index))
757 fail("%s not allowed since it maps to VIC %u.\n",
758 type, rid_to_vic(vfd.rid, rate_index));
763 void edid_state::print_vic_index(const char *prefix, unsigned idx, const char *suffix, bool ycbcr420)
765 if (!suffix)
766 suffix = "";
767 if (idx < cta.preparsed_svds[0].size()) {
768 unsigned char vic = cta.preparsed_svds[0][idx];
769 const struct timings *t = find_vic_id(vic);
770 char buf[16];
772 sprintf(buf, "VIC %3u", vic);
774 if (t) {
775 struct timings tmp = *t;
776 tmp.ycbcr420 = ycbcr420;
777 print_timings(prefix, &tmp, buf, suffix);
778 } else {
779 printf("%sUnknown (%s%s%s)\n", prefix, buf,
780 *suffix ? ", " : "", suffix);
782 } else {
783 // Should not happen!
784 printf("%sSVD Index %u is out of range", prefix, idx + 1);
785 if (*suffix)
786 printf(" (%s)", suffix);
787 printf("\n");
791 void edid_state::cta_y420cmdb(const unsigned char *x, unsigned length)
793 unsigned max_idx = 0;
794 unsigned i;
796 if (!length) {
797 printf(" All VDB SVDs\n");
798 return;
801 if (memchk(x, length)) {
802 printf(" Empty Capability Map\n");
803 fail("Empty Capability Map.\n");
804 return;
807 for (i = 0; i < length; i++) {
808 unsigned char v = x[i];
809 unsigned j;
811 for (j = 0; j < 8; j++) {
812 if (!(v & (1 << j)))
813 continue;
815 print_vic_index(" ", i * 8 + j, "", true);
816 max_idx = i * 8 + j;
817 if (max_idx < cta.preparsed_svds[0].size()) {
818 unsigned vic = cta.preparsed_svds[0][max_idx];
819 if (cta.preparsed_has_vic[1][vic])
820 fail("VIC %u is also a YCbCr 4:2:0-only VIC.\n", vic);
824 if (max_idx >= cta.preparsed_svds[0].size())
825 fail("Max index %u > %u (#SVDs).\n",
826 max_idx + 1, cta.preparsed_svds[0].size());
829 void edid_state::cta_print_svr(unsigned char svr, vec_timings_ext &vec_tim)
831 char suffix[24];
833 if ((svr > 0 && svr < 128) || (svr > 192 && svr < 254)) {
834 const struct timings *t;
835 unsigned char vic = svr;
837 sprintf(suffix, "VIC %3u", vic);
839 t = find_vic_id(vic);
840 if (t) {
841 print_timings(" ", t, suffix);
842 vec_tim.push_back(timings_ext(*t, suffix, ""));
843 } else {
844 printf(" %s: Unknown\n", suffix);
845 fail("Unknown VIC %u.\n", vic);
848 } else if (svr >= 129 && svr <= 144) {
849 sprintf(suffix, "DTD %3u", svr - 128);
850 if (svr >= cta.preparsed_total_dtds + 129) {
851 printf(" %s: Invalid\n", suffix);
852 fail("Invalid DTD %u.\n", svr - 128);
853 } else {
854 printf(" %s\n", suffix);
855 vec_tim.push_back(timings_ext(svr, suffix));
857 } else if (svr >= 145 && svr <= 160) {
858 sprintf(suffix, "VTDB %3u", svr - 144);
859 if (svr >= cta.preparsed_total_vtdbs + 145) {
860 printf(" %s: Invalid\n", suffix);
861 fail("Invalid VTDB %u.\n", svr - 144);
862 } else {
863 printf(" %s\n", suffix);
864 vec_tim.push_back(timings_ext(svr, suffix));
866 } else if (svr >= 161 && svr <= 175) {
867 sprintf(suffix, "RID %u@%up",
868 cta.preparsed_first_vfd.rid, vf_rate_values[svr - 160]);
869 if (!vfd_has_rate(cta.preparsed_first_vfd, svr - 160)) {
870 printf(" %s: Invalid\n", suffix);
871 fail("Invalid %s.\n", suffix);
872 } else {
873 printf(" %s\n", suffix);
874 vec_tim.push_back(timings_ext(svr, suffix));
876 } else if (svr == 254) {
877 sprintf(suffix, "T8VTDB");
878 if (!cta.preparsed_has_t8vtdb) {
879 printf(" %s: Invalid\n", suffix);
880 fail("Invalid T8VTDB.\n");
881 } else {
882 sprintf(suffix, "DMT 0x%02x", cta.preparsed_t8vtdb_dmt);
883 printf(" %s\n", suffix);
884 vec_tim.push_back(timings_ext(svr, suffix));
889 void edid_state::cta_vfpdb(const unsigned char *x, unsigned length)
891 unsigned i;
893 if (length == 0) {
894 fail("Empty Data Block with length %u.\n", length);
895 return;
897 cta.preferred_timings_vfpdb.clear();
898 for (i = 0; i < length; i++)
899 cta_print_svr(x[i], cta.preferred_timings_vfpdb);
902 void edid_state::cta_nvrdb(const unsigned char *x, unsigned length)
904 if (length == 0) {
905 fail("Empty Data Block with length %u.\n", length);
906 return;
909 unsigned char flags = length == 1 ? 0 : x[1];
911 cta.native_timing_nvrdb.clear();
912 cta_print_svr(x[0], cta.native_timing_nvrdb);
913 if ((flags & 1) && length < 6) {
914 fail("Data Block too short for Image Size (length = %u).\n", length);
915 return;
917 if (flags & 0x7e)
918 fail("Bits F41-F46 must be 0.\n");
919 if (!(flags & 1))
920 return;
922 unsigned w = (x[3] << 8) | x[2];
923 unsigned h = (x[5] << 8) | x[4];
925 if (!w || !h)
926 fail("Image Size has a zero width and/or height.\n");
928 if (flags & 0x80)
929 printf(" Image Size: %ux%u mm\n", w, h);
930 else
931 printf(" Image Size: %.1fx%.1f mm\n", w / 10.0, h / 10.0);
934 static std::string hdmi_latency2s(unsigned char l, bool is_video)
936 if (!l)
937 return "Unknown";
938 if (l == 0xff)
939 return is_video ? "Video not supported" : "Audio not supported";
940 return std::to_string(2 * (l - 1)) + " ms";
943 void edid_state::hdmi_latency(unsigned char vid_lat, unsigned char aud_lat,
944 bool is_ilaced)
946 const char *vid = is_ilaced ? "Interlaced video" : "Video";
947 const char *aud = is_ilaced ? "Interlaced audio" : "Audio";
949 printf(" %s latency: %s\n", vid, hdmi_latency2s(vid_lat, true).c_str());
950 printf(" %s latency: %s\n", aud, hdmi_latency2s(aud_lat, false).c_str());
952 if (vid_lat > 251 && vid_lat != 0xff)
953 fail("Invalid %s latency value %u.\n", vid, vid_lat);
954 if (aud_lat > 251 && aud_lat != 0xff)
955 fail("Invalid %s latency value %u.\n", aud, aud_lat);
957 if (!vid_lat || vid_lat > 251)
958 return;
959 if (!aud_lat || aud_lat > 251)
960 return;
962 unsigned vid_ms = 2 * (vid_lat - 1);
963 unsigned aud_ms = 2 * (aud_lat - 1);
965 // HDMI 2.0 latency checks for devices without HDMI output
966 if (aud_ms < vid_ms)
967 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
968 aud, vid, aud_ms, vid_ms);
969 else if (vid_ms + 20 < aud_ms)
970 warn("%s latency + 20 < %s latency (%u + 20 ms < %u ms). This is forbidden for devices without HDMI output.\n",
971 vid, aud, vid_ms, aud_ms);
972 else if (vid_ms < aud_ms)
973 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
974 vid, aud, vid_ms, aud_ms);
977 void edid_state::cta_hdmi_block(const unsigned char *x, unsigned length)
979 unsigned len_vic, len_3d;
981 if (length < 1) {
982 fail("Empty Data Block with length %u.\n", length);
983 return;
985 printf(" Source physical address: %x.%x.%x.%x\n", x[0] >> 4, x[0] & 0x0f,
986 x[1] >> 4, x[1] & 0x0f);
988 if (length < 3)
989 return;
991 if (x[2] & 0x80)
992 printf(" Supports_AI\n");
993 if (x[2] & 0x40)
994 printf(" DC_48bit\n");
995 if (x[2] & 0x20)
996 printf(" DC_36bit\n");
997 if (x[2] & 0x10)
998 printf(" DC_30bit\n");
999 if (x[2] & 0x08)
1000 printf(" DC_Y444\n");
1001 /* two reserved bits */
1002 if (x[2] & 0x01)
1003 printf(" DVI_Dual\n");
1005 if (length < 4)
1006 return;
1008 printf(" Maximum TMDS clock: %u MHz\n", x[3] * 5);
1009 if (x[3] * 5 > 340)
1010 fail("HDMI VSDB Max TMDS rate is > 340.\n");
1012 if (length < 5)
1013 return;
1015 if (x[4] & 0x0f) {
1016 printf(" Supported Content Types:\n");
1017 if (x[4] & 0x01)
1018 printf(" Graphics\n");
1019 if (x[4] & 0x02)
1020 printf(" Photo\n");
1021 if (x[4] & 0x04)
1022 printf(" Cinema\n");
1023 if (x[4] & 0x08)
1024 printf(" Game\n");
1027 unsigned b = 5;
1028 if (x[4] & 0x80) {
1029 hdmi_latency(x[b], x[b + 1], false);
1031 if (x[4] & 0x40) {
1032 if (x[b] == x[b + 2] &&
1033 x[b + 1] == x[b + 3])
1034 warn("Progressive and Interlaced latency values are identical, no need for both.\n");
1035 b += 2;
1036 hdmi_latency(x[b], x[b + 1], true);
1038 b += 2;
1041 if (!(x[4] & 0x20))
1042 return;
1044 bool mask = false;
1045 bool formats = false;
1047 printf(" Extended HDMI video details:\n");
1048 if (x[b] & 0x80)
1049 printf(" 3D present\n");
1050 if ((x[b] & 0x60) == 0x20) {
1051 printf(" All advertised VICs are 3D-capable\n");
1052 formats = true;
1054 if ((x[b] & 0x60) == 0x40) {
1055 printf(" 3D-capable-VIC mask present\n");
1056 formats = true;
1057 mask = true;
1059 switch (x[b] & 0x18) {
1060 case 0x00: break;
1061 case 0x08:
1062 printf(" Base EDID image size is aspect ratio\n");
1063 break;
1064 case 0x10:
1065 printf(" Base EDID image size is in units of 1 cm\n");
1066 break;
1067 case 0x18:
1068 printf(" Base EDID image size is in units of 5 cm\n");
1069 base.max_display_width_mm *= 5;
1070 base.max_display_height_mm *= 5;
1071 printf(" Recalculated image size: %u cm x %u cm\n",
1072 base.max_display_width_mm / 10, base.max_display_height_mm / 10);
1073 break;
1075 b++;
1076 len_vic = (x[b] & 0xe0) >> 5;
1077 len_3d = (x[b] & 0x1f) >> 0;
1078 b++;
1080 if (len_vic) {
1081 unsigned i;
1083 printf(" HDMI VICs:\n");
1084 for (i = 0; i < len_vic; i++) {
1085 unsigned char vic = x[b + i];
1086 const struct timings *t;
1088 if (vic && vic <= ARRAY_SIZE(edid_hdmi_mode_map)) {
1089 std::string suffix = "HDMI VIC " + std::to_string(vic);
1090 cta.supported_hdmi_vic_codes |= 1 << (vic - 1);
1091 t = find_vic_id(edid_hdmi_mode_map[vic - 1]);
1092 print_timings(" ", t, suffix.c_str());
1093 } else {
1094 printf(" Unknown (HDMI VIC %u)\n", vic);
1095 fail("Unknown HDMI VIC %u.\n", vic);
1099 b += len_vic;
1102 if (!len_3d)
1103 return;
1105 if (formats) {
1106 /* 3D_Structure_ALL_15..8 */
1107 if (x[b] & 0x80)
1108 printf(" 3D: Side-by-side (half, quincunx)\n");
1109 if (x[b] & 0x01)
1110 printf(" 3D: Side-by-side (half, horizontal)\n");
1111 /* 3D_Structure_ALL_7..0 */
1112 b++;
1113 if (x[b] & 0x40)
1114 printf(" 3D: Top-and-bottom\n");
1115 if (x[b] & 0x20)
1116 printf(" 3D: L + depth + gfx + gfx-depth\n");
1117 if (x[b] & 0x10)
1118 printf(" 3D: L + depth\n");
1119 if (x[b] & 0x08)
1120 printf(" 3D: Side-by-side (full)\n");
1121 if (x[b] & 0x04)
1122 printf(" 3D: Line-alternative\n");
1123 if (x[b] & 0x02)
1124 printf(" 3D: Field-alternative\n");
1125 if (x[b] & 0x01)
1126 printf(" 3D: Frame-packing\n");
1127 b++;
1128 len_3d -= 2;
1131 if (mask) {
1132 int max_idx = -1;
1133 unsigned i;
1135 printf(" 3D VIC indices that support these capabilities:\n");
1136 /* worst bit ordering ever */
1137 for (i = 0; i < 8; i++)
1138 if (x[b + 1] & (1 << i)) {
1139 print_vic_index(" ", i, "");
1140 max_idx = i;
1142 for (i = 0; i < 8; i++)
1143 if (x[b] & (1 << i)) {
1144 print_vic_index(" ", i + 8, "");
1145 max_idx = i + 8;
1147 b += 2;
1148 len_3d -= 2;
1149 if (max_idx >= (int)cta.preparsed_svds[0].size())
1150 fail("HDMI 3D VIC indices max index %d > %u (#SVDs).\n",
1151 max_idx + 1, cta.preparsed_svds[0].size());
1155 * list of nibbles:
1156 * 2D_VIC_Order_X
1157 * 3D_Structure_X
1158 * (optionally: 3D_Detail_X and reserved)
1160 if (!len_3d)
1161 return;
1163 unsigned end = b + len_3d;
1164 int max_idx = -1;
1166 printf(" 3D VIC indices with specific capabilities:\n");
1167 while (b < end) {
1168 unsigned char idx = x[b] >> 4;
1169 std::string s;
1171 if (idx > max_idx)
1172 max_idx = idx;
1173 switch (x[b] & 0x0f) {
1174 case 0: s = "frame packing"; break;
1175 case 1: s = "field alternative"; break;
1176 case 2: s = "line alternative"; break;
1177 case 3: s = "side-by-side (full)"; break;
1178 case 4: s = "L + depth"; break;
1179 case 5: s = "L + depth + gfx + gfx-depth"; break;
1180 case 6: s = "top-and-bottom"; break;
1181 case 8:
1182 s = "side-by-side";
1183 switch (x[b + 1] >> 4) {
1184 case 0x00: s += ", any subsampling"; break;
1185 case 0x01: s += ", horizontal"; break;
1186 case 0x02: case 0x03: case 0x04: case 0x05:
1187 s += ", not in use";
1188 fail("not-in-use 3D_Detail_X value 0x%02x.\n",
1189 x[b + 1] >> 4);
1190 break;
1191 case 0x06: s += ", all quincunx combinations"; break;
1192 case 0x07: s += ", quincunx odd/left, odd/right"; break;
1193 case 0x08: s += ", quincunx odd/left, even/right"; break;
1194 case 0x09: s += ", quincunx even/left, odd/right"; break;
1195 case 0x0a: s += ", quincunx even/left, even/right"; break;
1196 default:
1197 s += ", reserved";
1198 fail("reserved 3D_Detail_X value 0x%02x.\n",
1199 x[b + 1] >> 4);
1200 break;
1202 break;
1203 default:
1204 s = "unknown (";
1205 s += utohex(x[b] & 0x0f) + ")";
1206 fail("Unknown 3D_Structure_X value 0x%02x.\n", x[b] & 0x0f);
1207 break;
1209 print_vic_index(" ", idx, s.c_str());
1210 if ((x[b] & 0x0f) >= 8)
1211 b++;
1212 b++;
1214 if (max_idx >= (int)cta.preparsed_svds[0].size())
1215 fail("HDMI 2D VIC indices max index %d > %u (#SVDs).\n",
1216 max_idx + 1, cta.preparsed_svds[0].size());
1219 static const char *max_frl_rates[] = {
1220 "Not Supported",
1221 "3 Gbps per lane on 3 lanes",
1222 "3 and 6 Gbps per lane on 3 lanes",
1223 "3 and 6 Gbps per lane on 3 lanes, 6 Gbps on 4 lanes",
1224 "3 and 6 Gbps per lane on 3 lanes, 6 and 8 Gbps on 4 lanes",
1225 "3 and 6 Gbps per lane on 3 lanes, 6, 8 and 10 Gbps on 4 lanes",
1226 "3 and 6 Gbps per lane on 3 lanes, 6, 8, 10 and 12 Gbps on 4 lanes",
1229 static const char *dsc_max_slices[] = {
1230 "Not Supported",
1231 "up to 1 slice and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1232 "up to 2 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1233 "up to 4 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1234 "up to 8 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1235 "up to 8 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1236 "up to 12 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1237 "up to 12 slices and up to (600 MHz/Ksliceadjust) pixel clock per slice",
1240 static void cta_hf_eeodb(const unsigned char *x, unsigned length)
1242 printf(" EDID Extension Block Count: %u\n", x[0]);
1243 if (length != 1)
1244 fail("Block is too long.\n");
1245 if (x[0] <= 1)
1246 fail("Extension Block Count == %u.\n", x[0]);
1249 static void cta_hf_scdb(const unsigned char *x, unsigned length)
1251 unsigned rate = x[1] * 5;
1252 unsigned v;
1254 printf(" Version: %u\n", x[0]);
1255 if (rate) {
1256 printf(" Maximum TMDS Character Rate: %u MHz\n", rate);
1257 if (rate <= 340 || rate > 600)
1258 fail("Max TMDS rate is > 0 and <= 340 or > 600.\n");
1260 if (x[2] & 0x80)
1261 printf(" SCDC Present\n");
1262 if (x[2] & 0x40)
1263 printf(" SCDC Read Request Capable\n");
1264 if (x[2] & 0x20)
1265 printf(" Supports Cable Status\n");
1266 if (x[2] & 0x10)
1267 printf(" Supports Color Content Bits Per Component Indication\n");
1268 if (x[2] & 0x08)
1269 printf(" Supports scrambling for <= 340 Mcsc\n");
1270 if (x[2] & 0x04)
1271 printf(" Supports 3D Independent View signaling\n");
1272 if (x[2] & 0x02)
1273 printf(" Supports 3D Dual View signaling\n");
1274 if (x[2] & 0x01)
1275 printf(" Supports 3D OSD Disparity signaling\n");
1276 if (x[3] & 0xf0) {
1277 unsigned max_frl_rate = x[3] >> 4;
1279 printf(" Max Fixed Rate Link: ");
1280 if (max_frl_rate < ARRAY_SIZE(max_frl_rates)) {
1281 printf("%s\n", max_frl_rates[max_frl_rate]);
1282 } else {
1283 printf("Unknown (0x%02x)\n", max_frl_rate);
1284 fail("Unknown Max Fixed Rate Link (0x%02x).\n", max_frl_rate);
1286 if (max_frl_rate == 1 && rate < 300)
1287 fail("Max Fixed Rate Link is 1, but Max TMDS rate < 300.\n");
1288 else if (max_frl_rate >= 2 && rate < 600)
1289 fail("Max Fixed Rate Link is >= 2, but Max TMDS rate < 600.\n");
1291 if (x[3] & 0x08)
1292 printf(" Supports UHD VIC\n");
1293 if (x[3] & 0x04)
1294 printf(" Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1295 if (x[3] & 0x02)
1296 printf(" Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1297 if (x[3] & 0x01)
1298 printf(" Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1300 if (length <= 4)
1301 return;
1303 if (x[4] & 0x80)
1304 printf(" Supports FAPA End Extended\n");
1305 if (x[4] & 0x40)
1306 printf(" Supports QMS\n");
1307 if (x[4] & 0x20)
1308 printf(" Supports Mdelta\n");
1309 if (x[4] & 0x10)
1310 printf(" Supports media rates below VRRmin (CinemaVRR)\n");
1311 if (x[4] & 0x08)
1312 printf(" Supports negative Mvrr values\n");
1313 if (x[4] & 0x04)
1314 printf(" Supports Fast Vactive\n");
1315 if (x[4] & 0x02)
1316 printf(" Supports Auto Low-Latency Mode\n");
1317 if (x[4] & 0x01)
1318 printf(" Supports a FAPA in blanking after first active video line\n");
1320 if (length <= 5)
1321 return;
1323 v = x[5] & 0x3f;
1324 if (v) {
1325 printf(" VRRmin: %u Hz\n", v);
1326 if (v > 48)
1327 fail("VRRmin > 48.\n");
1329 v = (x[5] & 0xc0) << 2 | x[6];
1330 if (v) {
1331 printf(" VRRmax: %u Hz\n", v);
1332 if (!(x[5] & 0x3f))
1333 fail("VRRmin == 0, but VRRmax isn't.\n");
1334 else if (v < 100)
1335 fail("VRRmax < 100.\n");
1338 if (length <= 7)
1339 return;
1341 if (x[7] & 0x80)
1342 printf(" Supports VESA DSC 1.2a compression\n");
1343 if (x[7] & 0x40)
1344 printf(" Supports Compressed Video Transport for 4:2:0 Pixel Encoding\n");
1345 if (x[7] & 0x20)
1346 printf(" Supports QMS TFRmax\n");
1347 if (x[7] & 0x10)
1348 printf(" Supports QMS TFRmin\n");
1349 if (x[7] & 0x08)
1350 printf(" Supports Compressed Video Transport at any valid 1/16th bit bpp\n");
1351 if (x[7] & 0x04)
1352 printf(" Supports 16 bpc Compressed Video Transport\n");
1353 if (x[7] & 0x02)
1354 printf(" Supports 12 bpc Compressed Video Transport\n");
1355 if (x[7] & 0x01)
1356 printf(" Supports 10 bpc Compressed Video Transport\n");
1357 if (x[8] & 0xf) {
1358 unsigned max_slices = x[8] & 0xf;
1360 printf(" DSC Max Slices: ");
1361 if (max_slices < ARRAY_SIZE(dsc_max_slices)) {
1362 printf("%s\n", dsc_max_slices[max_slices]);
1363 } else {
1364 printf("Unknown (%u), interpreted as: %s\n", max_slices,
1365 dsc_max_slices[7]);
1366 warn("Unknown DSC Max Slices (%u).\n", max_slices);
1369 if (x[8] & 0xf0) {
1370 unsigned max_frl_rate = x[8] >> 4;
1372 printf(" DSC Max Fixed Rate Link: ");
1373 if (max_frl_rate < ARRAY_SIZE(max_frl_rates)) {
1374 printf("%s\n", max_frl_rates[max_frl_rate]);
1375 } else {
1376 printf("Unknown (0x%02x)\n", max_frl_rate);
1377 fail("Unknown DSC Max Fixed Rate Link (0x%02x).\n", max_frl_rate);
1380 if (x[9] & 0x3f)
1381 printf(" Maximum number of bytes in a line of chunks: %u\n",
1382 1024 * (1 + (x[9] & 0x3f)));
1385 // Convert a PQ value (0-1) to cd/m^2 aka nits (0-10000)
1386 static double pq2nits(double pq)
1388 const double m1 = 2610.0 / 16384.0;
1389 const double m2 = 128.0 * (2523.0 / 4096.0);
1390 const double c1 = 3424.0 / 4096.0;
1391 const double c2 = 32.0 * (2413.0 / 4096.0);
1392 const double c3 = 32.0 * (2392.0 / 4096.0);
1393 double e = pow(pq, 1.0 / m2);
1394 double v = e - c1;
1396 if (v < 0)
1397 v = 0;
1398 v /= c2 - c3 * e;
1399 v = pow(v, 1.0 / m1);
1400 return v * 10000.0;
1403 static double chrom2d(const unsigned char *x)
1405 unsigned v = x[0] + (x[1] << 8);
1407 return v * 0.00002;
1410 static double perc2d(unsigned char x)
1412 double m = x >> 2;
1413 double e = x & 3;
1415 return 100.0 * (m / 64.0) * pow(10, -e);
1418 static void cta_hf_sbtmdb(const unsigned char *x, unsigned length)
1420 int len = length;
1422 if (!length)
1423 fail("Block is too short.\n");
1424 printf(" Version: %d\n", x[0] & 0xf);
1425 switch ((x[0] >> 5) & 3) {
1426 case 0:
1427 printf(" Does not support a General RDM format\n");
1428 break;
1429 case 1:
1430 printf(" Supports an SDR-range General RDM format\n");
1431 break;
1432 case 2:
1433 printf(" Supports an HDR-range General RDM format\n");
1434 break;
1435 default:
1436 fail("Invalid GRDM Support value.\n");
1437 break;
1439 if (!(x[0] & 0x80))
1440 return;
1442 bool uses_hgig_drdm = true;
1444 printf(" Supports a D-RDM format\n");
1445 if (x[1] & 0x10)
1446 printf(" Use HGIG D-RDM\n");
1447 switch (x[1] & 7) {
1448 case 0:
1449 printf(" HGIG D-RDM is not used\n");
1450 uses_hgig_drdm = false;
1451 break;
1452 case 1:
1453 printf(" PBnits[0] = 600 cd/m^2\n");
1454 break;
1455 case 2:
1456 printf(" PBnits[0] = 1000 cd/m^2\n");
1457 break;
1458 case 3:
1459 printf(" PBnits[0] = 4000 cd/m^2\n");
1460 break;
1461 case 4:
1462 printf(" PBnits[0] = 10000 cd/m^2\n");
1463 break;
1464 default:
1465 fail("Invalid HGIG D-DRM value.\n");
1466 break;
1469 bool has_chromaticities = false;
1471 if (x[1] & 0x20)
1472 printf(" MaxRGB\n");
1473 switch (x[1] >> 6) {
1474 case 0:
1475 printf(" Gamut is explicit\n");
1476 has_chromaticities = true;
1477 break;
1478 case 1:
1479 printf(" Gamut is Rec. ITU-R BT.709\n");
1480 break;
1481 case 2:
1482 printf(" Gamut is SMPTE ST 2113\n");
1483 break;
1484 default:
1485 printf(" Gamut is Rec. ITU-R BT.2020\n");
1486 break;
1488 x += 2;
1489 len -= 2;
1490 if (has_chromaticities) {
1491 printf(" Red: (%.5f, %.5f)\n", chrom2d(x), chrom2d(x + 2));
1492 printf(" Green: (%.5f, %.5f)\n", chrom2d(x + 4), chrom2d(x + 6));
1493 printf(" Blue: (%.5f, %.5f)\n", chrom2d(x + 8), chrom2d(x + 10));
1494 printf(" White: (%.5f, %.5f)\n", chrom2d(x + 12), chrom2d(x + 14));
1495 x += 16;
1496 len -= 16;
1498 if (uses_hgig_drdm)
1499 return;
1500 printf(" Min Brightness 10: %.8f cd/m^2\n", pq2nits((x[0] << 1) / 4095.0));
1501 printf(" Peak Brightness 100: %u cd/m^2\n", (unsigned)pq2nits((x[1] << 4) / 4095.0));
1502 x += 2;
1503 len -= 2;
1504 if (len <= 0)
1505 return;
1506 printf(" Percentage of Peak Brightness P0: %.2f%%\n", perc2d(x[0]));
1507 printf(" Peak Brightness P0: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1508 x += 2;
1509 len -= 2;
1510 if (len <= 0)
1511 return;
1512 printf(" Percentage of Peak Brightness P1: %.2f%%\n", perc2d(x[0]));
1513 printf(" Peak Brightness P1: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1514 x += 2;
1515 len -= 2;
1516 if (len <= 0)
1517 return;
1518 printf(" Percentage of Peak Brightness P2: %.2f%%\n", perc2d(x[0]));
1519 printf(" Peak Brightness P2: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1520 x += 2;
1521 len -= 2;
1522 if (len <= 0)
1523 return;
1524 printf(" Percentage of Peak Brightness P3: %.2f%%\n", perc2d(x[0]));
1525 printf(" Peak Brightness P3: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1528 static void cta_amd(const unsigned char *x, unsigned length)
1530 // These Freesync values are reversed engineered by looking
1531 // at existing EDIDs.
1532 printf(" Version: %u.%u\n", x[0], x[1]);
1533 printf(" Minimum Refresh Rate: %u Hz\n", x[2]);
1534 printf(" Maximum Refresh Rate: %u Hz\n", x[3]);
1535 // Freesync 1.x flags
1536 // One or more of the 0xe6 bits signal that the VESA MCCS
1537 // protocol is used to switch the Freesync range
1538 printf(" Flags 1.x: 0x%02x%s\n", x[4],
1539 (x[4] & 0xe6) ? " (MCCS)" : "");
1540 if (length >= 10) {
1541 // Freesync 2.x flags
1542 // Bit 2 no doubt indicates if the monitor supports Local Dimming
1543 // There are probably also bits to signal support of the
1544 // FreeSync2_scRGB and FreeSync2_Gamma22 HDR display modes.
1545 // I suspect bits 0 and 1.
1546 printf(" Flags 2.x: 0x%02x\n", x[5]);
1547 // The AMD tone mapping tutorial referred to in the URL below
1548 // mentions that the Freesync HDR info reports max/min
1549 // luminance of the monitor with and without local dimming.
1551 // https://gpuopen.com/learn/using-amd-freesync-premium-pro-hdr-code-samples/
1553 // So I assume that the first two luminance values are
1554 // the max/min luminance of the display and the next two
1555 // luminance values are the max/min luminance values when
1556 // local dimming is disabled. The values I get seem to
1557 // support that.
1558 printf(" Maximum luminance: %u (%.3f cd/m^2)\n",
1559 x[6], 50.0 * pow(2, x[6] / 32.0));
1560 printf(" Minimum luminance: %u (%.3f cd/m^2)\n",
1561 x[7], (50.0 * pow(2, x[6] / 32.0)) * pow(x[7] / 255.0, 2) / 100.0);
1562 if (x[5] & 4) {
1563 // One or both bytes can be 0. The meaning of that
1564 // is unknown.
1565 printf(" Maximum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1566 x[8], 50.0 * pow(2, x[8] / 32.0));
1567 printf(" Minimum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1568 x[9], (50.0 * pow(2, x[8] / 32.0)) * pow(x[9] / 255.0, 2) / 100.0);
1569 } else {
1570 // These bytes are always 0x08 0x2f. If these values
1571 // represent max/min luminance as well, then these
1572 // would map to 59.460 and 0.020 cd/m^2 respectively.
1573 // I wonder if this somehow relates to SDR.
1574 printf(" Unknown: 0x%02x 0x%02x\n", x[8], x[9]);
1579 static std::string display_use_case(unsigned char x)
1581 switch (x) {
1582 case 1: return "Test equipment";
1583 case 2: return "Generic display";
1584 case 3: return "Television display";
1585 case 4: return "Desktop productivity display";
1586 case 5: return "Desktop gaming display";
1587 case 6: return "Presentation display";
1588 case 7: return "Virtual reality headset";
1589 case 8: return "Augmented reality";
1590 case 16: return "Video wall display";
1591 case 17: return "Medical imaging display";
1592 case 18: return "Dedicated gaming display";
1593 case 19: return "Dedicated video monitor display";
1594 case 20: return "Accessory display";
1595 default: break;
1597 fail("Unknown Display product primary use case 0x%02x.\n", x);
1598 return std::string("Unknown display use case (") + utohex(x) + ")";
1601 static void cta_microsoft(const unsigned char *x, unsigned length)
1603 // This VSDB is documented at:
1604 // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
1605 printf(" Version: %u\n", x[0]);
1606 if (x[0] > 2) {
1607 // In version 1 and 2 these bits should always be set to 0.
1608 printf(" Desktop Usage: %u\n", (x[1] >> 6) & 1);
1609 printf(" Third-Party Usage: %u\n", (x[1] >> 5) & 1);
1611 printf(" Display Product Primary Use Case: %u (%s)\n", x[1] & 0x1f,
1612 display_use_case(x[1] & 0x1f).c_str());
1613 printf(" Container ID: %s\n", containerid2s(x + 2).c_str());
1616 static void cta_hdr10plus(const unsigned char *x, unsigned length)
1618 if (length == 0) {
1619 fail("Empty Data Block with length %u.\n", length);
1620 return;
1622 printf(" Application Version: %u\n", x[0] & 3);
1623 printf(" Full Frame Peak Luminance Index: %u\n", (x[0] >> 2) & 3);
1624 printf(" Peak Luminance Index: %u\n", x[0] >> 4);
1625 hex_block(" ", x + 1, length - 1);
1628 static void cta_dolby_video(const unsigned char *x, unsigned length)
1630 unsigned char version = (x[0] >> 5) & 0x07;
1632 printf(" Version: %u (%u bytes)\n", version, length + 5);
1633 if (x[0] & 0x01)
1634 printf(" Supports YUV422 12 bit\n");
1636 if (version == 0) {
1637 if (x[0] & 0x02)
1638 printf(" Supports 2160p60\n");
1639 if (x[0] & 0x04)
1640 printf(" Supports global dimming\n");
1641 unsigned char dm_version = x[16];
1642 printf(" DM Version: %u.%u\n", dm_version >> 4, dm_version & 0xf);
1643 unsigned pq = (x[14] << 4) | (x[13] >> 4);
1644 printf(" Target Min PQ: %u (%.8f cd/m^2)\n", pq, pq2nits(pq / 4095.0));
1645 pq = (x[15] << 4) | (x[13] & 0xf);
1646 printf(" Target Max PQ: %u (%u cd/m^2)\n", pq, (unsigned)pq2nits(pq / 4095.0));
1647 printf(" Rx, Ry: %.8f, %.8f\n",
1648 ((x[1] >> 4) | (x[2] << 4)) / 4096.0,
1649 ((x[1] & 0xf) | (x[3] << 4)) / 4096.0);
1650 printf(" Gx, Gy: %.8f, %.8f\n",
1651 ((x[4] >> 4) | (x[5] << 4)) / 4096.0,
1652 ((x[4] & 0xf) | (x[6] << 4)) / 4096.0);
1653 printf(" Bx, By: %.8f, %.8f\n",
1654 ((x[7] >> 4) | (x[8] << 4)) / 4096.0,
1655 ((x[7] & 0xf) | (x[9] << 4)) / 4096.0);
1656 printf(" Wx, Wy: %.8f, %.8f\n",
1657 ((x[10] >> 4) | (x[11] << 4)) / 4096.0,
1658 ((x[10] & 0xf) | (x[12] << 4)) / 4096.0);
1659 return;
1662 if (version == 1) {
1663 if (x[0] & 0x02)
1664 printf(" Supports 2160p60\n");
1665 if (x[1] & 0x01)
1666 printf(" Supports global dimming\n");
1667 unsigned char dm_version = (x[0] >> 2) & 0x07;
1668 printf(" DM Version: %u.x\n", dm_version + 2);
1669 printf(" Colorimetry: %s\n", (x[2] & 0x01) ? "P3-D65" : "ITU-R BT.709");
1670 printf(" Low Latency: %s\n", (x[3] & 0x01) ? "Standard + Low Latency" : "Only Standard");
1671 double lm = (x[2] >> 1) / 127.0;
1672 printf(" Target Min Luminance: %.8f cd/m^2\n", lm * lm);
1673 printf(" Target Max Luminance: %u cd/m^2\n", 100 + (x[1] >> 1) * 50);
1674 if (length == 10) {
1675 printf(" Rx, Ry: %.8f, %.8f\n", x[4] / 256.0, x[5] / 256.0);
1676 printf(" Gx, Gy: %.8f, %.8f\n", x[6] / 256.0, x[7] / 256.0);
1677 printf(" Bx, By: %.8f, %.8f\n", x[8] / 256.0, x[9] / 256.0);
1678 } else {
1679 double xmin = 0.625;
1680 double xstep = (0.74609375 - xmin) / 31.0;
1681 double ymin = 0.25;
1682 double ystep = (0.37109375 - ymin) / 31.0;
1684 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1685 xmin + xstep * (x[6] >> 3),
1686 ymin + ystep * (((x[6] & 0x7) << 2) | (x[4] & 0x01) | ((x[5] & 0x01) << 1)));
1687 xstep = 0.49609375 / 127.0;
1688 ymin = 0.5;
1689 ystep = (0.99609375 - ymin) / 127.0;
1690 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1691 xstep * (x[4] >> 1), ymin + ystep * (x[5] >> 1));
1692 xmin = 0.125;
1693 xstep = (0.15234375 - xmin) / 7.0;
1694 ymin = 0.03125;
1695 ystep = (0.05859375 - ymin) / 7.0;
1696 printf(" Unique Bx, By: %.8f, %.8f\n",
1697 xmin + xstep * (x[3] >> 5),
1698 ymin + ystep * ((x[3] >> 2) & 0x07));
1700 return;
1703 if (version == 2) {
1704 if (x[0] & 0x02)
1705 printf(" Supports Backlight Control\n");
1706 if (x[1] & 0x04)
1707 printf(" Supports global dimming\n");
1708 unsigned char dm_version = (x[0] >> 2) & 0x07;
1709 printf(" DM Version: %u.x\n", dm_version + 2);
1710 printf(" Backlt Min Luma: %u cd/m^2\n", 25 + (x[1] & 0x03) * 25);
1711 printf(" Interface: ");
1712 switch (x[2] & 0x03) {
1713 case 0: printf("Low-Latency\n"); break;
1714 case 1: printf("Low-Latency + Low-Latency-HDMI\n"); break;
1715 case 2: printf("Standard + Low-Latency\n"); break;
1716 case 3: printf("Standard + Low-Latency + Low-Latency-HDMI\n"); break;
1718 printf(" Supports 10b 12b 444: ");
1719 switch ((x[3] & 0x01) << 1 | (x[4] & 0x01)) {
1720 case 0: printf("Not supported\n"); break;
1721 case 1: printf("10 bit\n"); break;
1722 case 2: printf("12 bit\n"); break;
1723 case 3: printf("Reserved\n"); break;
1726 unsigned pq = 20 * (x[1] >> 3);
1727 printf(" Target Min PQ v2: %u (%.8f cd/m^2)\n", pq, pq2nits(pq / 4095.0));
1728 pq = 2055 + 65 * (x[2] >> 3);
1729 printf(" Target Max PQ v2: %u (%u cd/m^2)\n", pq, (unsigned)pq2nits(pq / 4095.0));
1731 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1732 0.625 + (x[5] >> 3) / 256.0,
1733 0.25 + (x[6] >> 3) / 256.0);
1734 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1735 (x[3] >> 1) / 256.0,
1736 0.5 + (x[4] >> 1) / 256.0);
1737 printf(" Unique Bx, By: %.8f, %.8f\n",
1738 0.125 + (x[5] & 0x07) / 256.0,
1739 0.03125 + (x[6] & 0x07) / 256.0);
1743 static void cta_dolby_audio(const unsigned char *x, unsigned length)
1745 unsigned char version = 1 + (x[0] & 0x07);
1747 printf(" Version: %u (%u bytes)\n", version, length + 5);
1748 if (x[0] & 0x80)
1749 printf(" Headphone playback only\n");
1750 if (x[0] & 0x40)
1751 printf(" Height speaker zone present\n");
1752 if (x[0] & 0x20)
1753 printf(" Surround speaker zone present\n");
1754 if (x[0] & 0x10)
1755 printf(" Center speaker zone present\n");
1756 if (x[1] & 0x01)
1757 printf(" Supports Dolby MAT PCM decoding at 48 kHz only, does not support TrueHD\n");
1760 static void cta_uhda_fmm(const unsigned char *x, unsigned length)
1762 printf(" Filmmaker Mode Content Type: %u\n", x[0]);
1763 printf(" Filmmaker Mode Content Subtype: %u\n", x[1]);
1766 static const char *speaker_map[] = {
1767 "FL/FR - Front Left/Right",
1768 "LFE1 - Low Frequency Effects 1",
1769 "FC - Front Center",
1770 "BL/BR - Back Left/Right",
1771 "BC - Back Center",
1772 "FLc/FRc - Front Left/Right of Center",
1773 "RLC/RRC - Rear Left/Right of Center (Deprecated)",
1774 "FLw/FRw - Front Left/Right Wide",
1775 "TpFL/TpFR - Top Front Left/Right",
1776 "TpC - Top Center",
1777 "TpFC - Top Front Center",
1778 "LS/RS - Left/Right Surround",
1779 "LFE2 - Low Frequency Effects 2",
1780 "TpBC - Top Back Center",
1781 "SiL/SiR - Side Left/Right",
1782 "TpSiL/TpSiR - Top Side Left/Right",
1783 "TpBL/TpBR - Top Back Left/Right",
1784 "BtFC - Bottom Front Center",
1785 "BtFL/BtFR - Bottom Front Left/Right",
1786 "TpLS/TpRS - Top Left/Right Surround (Deprecated for CTA-861)",
1787 "LSd/RSd - Left/Right Surround Direct (HDMI only)",
1790 static void cta_sadb(const unsigned char *x, unsigned length)
1792 unsigned sad;
1793 unsigned i;
1795 if (length < 3) {
1796 fail("Empty Data Block with length %u.\n", length);
1797 return;
1800 sad = ((x[2] << 16) | (x[1] << 8) | x[0]);
1802 for (i = 0; i < ARRAY_SIZE(speaker_map); i++) {
1803 if ((sad >> i) & 1)
1804 printf(" %s\n", speaker_map[i]);
1808 static void cta_vesa_dtcdb(const unsigned char *x, unsigned length)
1810 if (length != 7 && length != 15 && length != 31) {
1811 fail("Invalid length %u.\n", length);
1812 return;
1815 switch (x[0] >> 6) {
1816 case 0: printf(" White"); break;
1817 case 1: printf(" Red"); break;
1818 case 2: printf(" Green"); break;
1819 case 3: printf(" Blue"); break;
1821 unsigned v = x[0] & 0x3f;
1822 printf(" transfer characteristics: %u", v);
1823 for (unsigned i = 1; i < length; i++)
1824 printf(" %u", v += x[i]);
1825 printf(" 1023\n");
1828 static void cta_vesa_vdddb(const unsigned char *x, unsigned length)
1830 if (length != 30) {
1831 fail("Invalid length %u.\n", length);
1832 return;
1835 printf(" Interface Type: ");
1836 unsigned char v = x[0];
1837 switch (v >> 4) {
1838 case 0: printf("Analog (");
1839 switch (v & 0xf) {
1840 case 0: printf("15HD/VGA"); break;
1841 case 1: printf("VESA NAVI-V (15HD)"); break;
1842 case 2: printf("VESA NAVI-D"); break;
1843 default: printf("Reserved"); break;
1845 printf(")\n");
1846 break;
1847 case 1: printf("LVDS %u lanes", v & 0xf); break;
1848 case 2: printf("RSDS %u lanes", v & 0xf); break;
1849 case 3: printf("DVI-D %u channels", v & 0xf); break;
1850 case 4: printf("DVI-I analog"); break;
1851 case 5: printf("DVI-I digital %u channels", v & 0xf); break;
1852 case 6: printf("HDMI-A"); break;
1853 case 7: printf("HDMI-B"); break;
1854 case 8: printf("MDDI %u channels", v & 0xf); break;
1855 case 9: printf("DisplayPort %u channels", v & 0xf); break;
1856 case 10: printf("IEEE-1394"); break;
1857 case 11: printf("M1 analog"); break;
1858 case 12: printf("M1 digital %u channels", v & 0xf); break;
1859 default: printf("Reserved"); break;
1861 printf("\n");
1863 printf(" Interface Standard Version: %u.%u\n", x[1] >> 4, x[1] & 0xf);
1864 printf(" Content Protection Support: ");
1865 switch (x[2]) {
1866 case 0: printf("None\n"); break;
1867 case 1: printf("HDCP\n"); break;
1868 case 2: printf("DTCP\n"); break;
1869 case 3: printf("DPCP\n"); break;
1870 default: printf("Reserved\n"); break;
1873 printf(" Minimum Clock Frequency: %u MHz\n", x[3] >> 2);
1874 printf(" Maximum Clock Frequency: %u MHz\n", ((x[3] & 0x03) << 8) | x[4]);
1875 printf(" Device Native Pixel Format: %ux%u\n",
1876 x[5] | (x[6] << 8), x[7] | (x[8] << 8));
1877 printf(" Aspect Ratio: %.2f\n", (100 + x[9]) / 100.0);
1878 v = x[0x0a];
1879 printf(" Default Orientation: ");
1880 switch ((v & 0xc0) >> 6) {
1881 case 0x00: printf("Landscape\n"); break;
1882 case 0x01: printf("Portrait\n"); break;
1883 case 0x02: printf("Not Fixed\n"); break;
1884 case 0x03: printf("Undefined\n"); break;
1886 printf(" Rotation Capability: ");
1887 switch ((v & 0x30) >> 4) {
1888 case 0x00: printf("None\n"); break;
1889 case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
1890 case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
1891 case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
1893 printf(" Zero Pixel Location: ");
1894 switch ((v & 0x0c) >> 2) {
1895 case 0x00: printf("Upper Left\n"); break;
1896 case 0x01: printf("Upper Right\n"); break;
1897 case 0x02: printf("Lower Left\n"); break;
1898 case 0x03: printf("Lower Right\n"); break;
1900 printf(" Scan Direction: ");
1901 switch (v & 0x03) {
1902 case 0x00: printf("Not defined\n"); break;
1903 case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
1904 case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
1905 case 0x03: printf("Reserved\n");
1906 fail("Scan Direction used the reserved value 0x03.\n");
1907 break;
1909 printf(" Subpixel Information: ");
1910 switch (x[0x0b]) {
1911 case 0x00: printf("Not defined\n"); break;
1912 case 0x01: printf("RGB vertical stripes\n"); break;
1913 case 0x02: printf("RGB horizontal stripes\n"); break;
1914 case 0x03: printf("Vertical stripes using primary order\n"); break;
1915 case 0x04: printf("Horizontal stripes using primary order\n"); break;
1916 case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
1917 case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
1918 case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
1919 case 0x08: printf("Mosaic\n"); break;
1920 case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
1921 case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
1922 case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
1923 case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
1924 default: printf("Reserved\n"); break;
1926 printf(" Horizontal and vertical dot/pixel pitch: %.2f x %.2f mm\n",
1927 (double)(x[0x0c]) / 100.0, (double)(x[0x0d]) / 100.0);
1928 v = x[0x0e];
1929 printf(" Dithering: ");
1930 switch (v >> 6) {
1931 case 0: printf("None\n"); break;
1932 case 1: printf("Spatial\n"); break;
1933 case 2: printf("Temporal\n"); break;
1934 case 3: printf("Spatial and Temporal\n"); break;
1936 printf(" Direct Drive: %s\n", (v & 0x20) ? "Yes" : "No");
1937 printf(" Overdrive %srecommended\n", (v & 0x10) ? "not " : "");
1938 printf(" Deinterlacing: %s\n", (v & 0x08) ? "Yes" : "No");
1940 v = x[0x0f];
1941 printf(" Audio Support: %s\n", (v & 0x80) ? "Yes" : "No");
1942 printf(" Separate Audio Inputs Provided: %s\n", (v & 0x40) ? "Yes" : "No");
1943 printf(" Audio Input Override: %s\n", (v & 0x20) ? "Yes" : "No");
1944 v = x[0x10];
1945 if (v)
1946 printf(" Audio Delay: %s%u ms\n", (v & 0x80) ? "" : "-", (v & 0x7f) * 2);
1947 else
1948 printf(" Audio Delay: no information provided\n");
1949 v = x[0x11];
1950 printf(" Frame Rate/Mode Conversion: ");
1951 switch (v >> 6) {
1952 case 0: printf("None\n"); break;
1953 case 1: printf("Single Buffering\n"); break;
1954 case 2: printf("Double Buffering\n"); break;
1955 case 3: printf("Advanced Frame Rate Conversion\n"); break;
1957 if (v & 0x3f)
1958 printf(" Frame Rate Range: %u fps +/- %u fps\n",
1959 x[0x12], v & 0x3f);
1960 else
1961 printf(" Nominal Frame Rate: %u fps\n", x[0x12]);
1962 printf(" Color Bit Depth: %u @ interface, %u @ display\n",
1963 (x[0x13] >> 4) + 1, (x[0x13] & 0xf) + 1);
1964 v = x[0x15] & 3;
1965 if (v) {
1966 printf(" Additional Primary Chromaticities:\n");
1967 unsigned col_x = (x[0x16] << 2) | (x[0x14] >> 6);
1968 unsigned col_y = (x[0x17] << 2) | ((x[0x14] >> 4) & 3);
1969 printf(" Primary 4: 0.%04u, 0.%04u\n",
1970 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1971 if (v > 1) {
1972 col_x = (x[0x18] << 2) | ((x[0x14] >> 2) & 3);
1973 col_y = (x[0x19] << 2) | (x[0x14] & 3);
1974 printf(" Primary 5: 0.%04u, 0.%04u\n",
1975 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1976 if (v > 2) {
1977 col_x = (x[0x1a] << 2) | (x[0x15] >> 6);
1978 col_y = (x[0x1b] << 2) | ((x[0x15] >> 4) & 3);
1979 printf(" Primary 6: 0.%04u, 0.%04u\n",
1980 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1985 v = x[0x1c];
1986 printf(" Response Time %s: %u ms\n",
1987 (v & 0x80) ? "White -> Black" : "Black -> White", v & 0x7f);
1988 v = x[0x1d];
1989 printf(" Overscan: %u%% x %u%%\n", v >> 4, v & 0xf);
1992 static double decode_uchar_as_double(unsigned char x)
1994 signed char s = (signed char)x;
1996 return s / 64.0;
1999 void edid_state::cta_rcdb(const unsigned char *x, unsigned length)
2001 unsigned spm = ((x[3] << 16) | (x[2] << 8) | x[1]);
2002 unsigned i;
2004 if (length < 4) {
2005 fail("Empty Data Block with length %u.\n", length);
2006 return;
2009 if ((x[0] & 0x20) && !cta.has_sldb)
2010 fail("'SLD' flag is 1, but no Speaker Location Data Block is found.\n");
2011 else if (!(x[0] & 0x20) && cta.has_sldb)
2012 fail("'SLD' flag is 0, but a Speaker Location Data Block is present.\n");
2014 if (x[0] & 0x40) {
2015 printf(" Speaker count: %u\n", (x[0] & 0x1f) + 1);
2016 } else {
2017 if (x[0] & 0x1f)
2018 fail("'Speaker' flag is 0, but 'Speaker Count' is != 0.\n");
2019 if (x[0] & 0x20)
2020 fail("'SLD' flag is 1, but 'Speaker' is 0.\n");
2023 printf(" Speaker Presence Mask:\n");
2024 for (i = 0; i < ARRAY_SIZE(speaker_map); i++) {
2025 if ((spm >> i) & 1)
2026 printf(" %s\n", speaker_map[i]);
2029 if ((x[0] & 0xa0) == 0x80)
2030 fail("'Display' flag set, but not the 'SLD' flag.\n");
2032 bool valid_max = cta.preparsed_sld_has_coord || (x[0] & 0x80);
2034 if (valid_max && length >= 7) {
2035 printf(" Xmax: %u dm\n", x[4]);
2036 printf(" Ymax: %u dm\n", x[5]);
2037 printf(" Zmax: %u dm\n", x[6]);
2038 } else if (!valid_max && length >= 7) {
2039 // The RCDB should have been truncated.
2040 warn("'Display' flag is 0 and 'Coord' is 0 for all SLDs, but the Max coordinates are still present.\n");
2042 if ((x[0] & 0x80) && length >= 10) {
2043 printf(" DisplayX: %.3f * Xmax\n", decode_uchar_as_double(x[7]));
2044 printf(" DisplayY: %.3f * Ymax\n", decode_uchar_as_double(x[8]));
2045 printf(" DisplayZ: %.3f * Zmax\n", decode_uchar_as_double(x[9]));
2046 } else if (!(x[0] & 0x80) && length >= 10) {
2047 // The RCDB should have been truncated.
2048 warn("'Display' flag is 0, but the Display coordinates are still present.\n");
2052 static const struct {
2053 const char *name;
2054 double x, y, z;
2055 } speaker_location[] = {
2056 { "FL - Front Left", -1, 1, 0 },
2057 { "FR - Front Right", 1, 1, 0 },
2058 { "FC - Front Center", 0, 1, 0 },
2059 { "LFE1 - Low Frequency Effects 1", -0.5, 1, -1 },
2060 { "BL - Back Left", -1, -1, 0 },
2061 { "BR - Back Right", 1, -1, 0 },
2062 { "FLC - Front Left of Center", -0.5, 1, 0 },
2063 { "FRC - Front Right of Center", 0.5, 1, 0 },
2064 { "BC - Back Center", 0, -1, 0 },
2065 { "LFE2 - Low Frequency Effects 2", 0.5, 1, -1 },
2066 { "SiL - Side Left", -1, 1.0/3.0, 0 },
2067 { "SiR - Side Right", 1, 1.0/3.0, 0 },
2068 { "TpFL - Top Front Left", -1, 1, 1 },
2069 { "TpFR - Top Front Right", 1, 1, 1 },
2070 { "TpFC - Top Front Center", 0, 1, 1 },
2071 { "TpC - Top Center", 0, 0, 1 },
2072 { "TpBL - Top Back Left", -1, -1, 1 },
2073 { "TpBR - Top Back Right", 1, -1, 1 },
2074 { "TpSiL - Top Side Left", -1, 0, 1 },
2075 { "TpSiR - Top Side Right", 1, 0, 1 },
2076 { "TpBC - Top Back Center", 0, -1, 1 },
2077 { "BtFC - Bottom Front Center", 0, 1, -1 },
2078 { "BtFL - Bottom Front Left", -1, 1, -1 },
2079 { "BtFR - Bottom Front Right", 1, 1, -1 },
2080 { "FLW - Front Left Wide", -1, 2.0/3.0, 0 },
2081 { "FRW - Front Right Wide", 1, 2.0/3.0, 0 },
2082 { "LS - Left Surround", -1, 0, 0 },
2083 { "RS - Right Surround", 1, 0, 0 },
2086 void edid_state::cta_sldb(const unsigned char *x, unsigned length)
2088 if (length < 2) {
2089 fail("Empty Data Block with length %u.\n", length);
2090 return;
2093 unsigned active_cnt = 0;
2094 unsigned channel_is_active = 0;
2096 while (length >= 2) {
2097 printf(" Channel: %u (%sactive)\n", x[0] & 0x1f,
2098 (x[0] & 0x20) ? "" : "not ");
2099 if (x[0] & 0x20) {
2100 if (channel_is_active & (1U << (x[0] & 0x1f)))
2101 fail("Channel Index %u was already marked 'Active'.\n",
2102 x[0] & 0x1f);
2103 channel_is_active |= 1U << (x[0] & 0x1f);
2104 active_cnt++;
2106 if ((x[1] & 0x1f) < ARRAY_SIZE(speaker_location))
2107 printf(" Speaker: %s\n", speaker_location[x[1] & 0x1f].name);
2108 if (length >= 5 && (x[0] & 0x40)) {
2109 printf(" X: %.3f * Xmax\n", decode_uchar_as_double(x[2]));
2110 printf(" Y: %.3f * Ymax\n", decode_uchar_as_double(x[3]));
2111 printf(" Z: %.3f * Zmax\n", decode_uchar_as_double(x[4]));
2112 length -= 3;
2113 x += 3;
2114 } else {
2115 printf(" X: %.3f * Xmax (approximately)\n", speaker_location[x[1] & 0x1f].x);
2116 printf(" Y: %.3f * Ymax (approximately)\n", speaker_location[x[1] & 0x1f].y);
2117 printf(" Z: %.3f * Zmax (approximately)\n", speaker_location[x[1] & 0x1f].z);
2120 length -= 2;
2121 x += 2;
2123 if (active_cnt != cta.preparsed_speaker_count)
2124 fail("There are %u active speakers, but 'Speaker Count' is %u.\n",
2125 active_cnt, cta.preparsed_speaker_count);
2128 void edid_state::cta_preparse_sldb(const unsigned char *x, unsigned length)
2130 cta.has_sldb = true;
2131 while (length >= 2) {
2132 if (length >= 5 && (x[0] & 0x40)) {
2133 cta.preparsed_sld_has_coord = true;
2134 return;
2136 length -= 2;
2137 x += 2;
2141 void edid_state::cta_vcdb(const unsigned char *x, unsigned length)
2143 unsigned char d = x[0];
2145 cta.has_vcdb = true;
2146 if (length < 1) {
2147 fail("Empty Data Block with length %u.\n", length);
2148 return;
2150 printf(" YCbCr quantization: %s\n",
2151 (d & 0x80) ? "Selectable (via AVI YQ)" : "No Data");
2152 printf(" RGB quantization: %s\n",
2153 (d & 0x40) ? "Selectable (via AVI Q)" : "No Data");
2155 * If this bit is not set then that will result in interoperability
2156 * problems (specifically with PCs/laptops) that quite often do not
2157 * follow the default rules with respect to RGB Quantization Range
2158 * handling.
2160 * Starting with the CTA-861-H spec this bit is now required to be
2161 * 1 for new designs.
2163 if (!(d & 0x40))
2164 fail("Set Selectable RGB Quantization to avoid interop issues.\n");
2166 * Since most YCbCr formats use limited range, the interop issues are
2167 * less noticable than for RGB formats.
2169 * Starting with the CTA-861-H spec this bit is now required to be
2170 * 1 for new designs, but just warn about it (for now).
2172 if ((cta.byte3 & 0x30) && !(d & 0x80))
2173 warn("Set Selectable YCbCr Quantization to avoid interop issues.\n");
2175 unsigned char s_pt = (d >> 4) & 0x03;
2176 unsigned char s_it = (d >> 2) & 0x03;
2177 unsigned char s_ce = d & 0x03;
2179 printf(" PT scan behavior: ");
2180 switch (s_pt) {
2181 case 0: printf("No Data\n"); break;
2182 case 1: printf("Always Overscanned\n"); break;
2183 case 2: printf("Always Underscanned\n"); break;
2184 case 3: printf("Supports both over- and underscan\n"); break;
2186 printf(" IT scan behavior: ");
2187 switch (s_it) {
2188 case 0: printf("IT video formats not supported\n"); break;
2189 case 1:
2190 printf("Always Overscanned\n");
2191 // See Table 52 of CTA-861-G for a description of Byte 3
2192 if (cta.byte3 & 0x80)
2193 fail("IT video formats are always overscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to underscanned.\n");
2194 break;
2195 case 2:
2196 printf("Always Underscanned\n");
2197 // See Table 52 of CTA-861-G for a description of Byte 3
2198 if (!(cta.byte3 & 0x80))
2199 fail("IT video formats are always underscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to overscanned.\n");
2200 break;
2201 case 3: printf("Supports both over- and underscan\n"); break;
2203 if (s_it < 2)
2204 warn("IT scan behavior is expected to support underscanned.\n");
2205 printf(" CE scan behavior: ");
2206 switch (s_ce) {
2207 case 0: printf("CE video formats not supported\n"); break;
2208 case 1: printf("Always Overscanned\n"); break;
2209 case 2: printf("Always Underscanned\n"); break;
2210 case 3: printf("Supports both over- and underscan\n"); break;
2212 if (s_ce == 0)
2213 warn("'CE video formats not supported' makes no sense.\n");
2214 else if (s_pt == s_it && s_pt == s_ce)
2215 warn("S_PT is equal to S_IT and S_CE, so should be set to 0 instead.\n");
2218 static const char *colorimetry1_map[] = {
2219 "xvYCC601",
2220 "xvYCC709",
2221 "sYCC601",
2222 "opYCC601",
2223 "opRGB",
2224 "BT2020cYCC",
2225 "BT2020YCC",
2226 "BT2020RGB",
2229 static const char *colorimetry2_map[] = {
2230 "Gamut Boundary Description Metadata Profile P0",
2231 "Reserved Gamut Boundary Description Metadata Profile P1",
2232 "Reserved Gamut Boundary Description Metadata Profile P2",
2233 "Reserved Gamut Boundary Description Metadata Profile P3",
2234 "Default",
2235 "sRGB",
2236 "ICtCp",
2237 "ST2113RGB",
2240 void edid_state::cta_colorimetry_block(const unsigned char *x, unsigned length)
2242 unsigned i;
2244 if (length < 2) {
2245 fail("Empty Data Block with length %u.\n", length);
2246 return;
2248 for (i = 0; i < ARRAY_SIZE(colorimetry1_map); i++)
2249 if (x[0] & (1 << i))
2250 printf(" %s\n", colorimetry1_map[i]);
2251 // Bits MD0-MD3 are used to indicate which HDMI Gamut Boundary Description
2252 // Metadata Profiles are supported.
2254 // HDMI 1.3a in section 5.3.12 describes 4 possible profiles, but it marks
2255 // P3 as 'defined in a future specification'.
2257 // HDMI 1.4b, however, only specifies profile P0 in section 8.3.3. And I've
2258 // only seen P0 in practice. My assumption is that profiles P1-P3 are never
2259 // used, and so these bits should be 0.
2260 if (x[1] & 0xe)
2261 fail("Reserved bits MD1-MD3 must be 0.\n");
2262 for (i = 0; i < ARRAY_SIZE(colorimetry2_map); i++)
2263 if (x[1] & (1 << i))
2264 printf(" %s\n", colorimetry2_map[i]);
2265 // The sRGB bit (added in CTA-861.6) allows sources to explicitly
2266 // signal sRGB colorimetry. Without this the default colorimetry
2267 // of an RGB video is either sRGB or defaultRGB. It depends on the
2268 // Source which is used, and the Sink has no idea what it is getting.
2270 // For proper compatibility with PCs enabling sRGB support is
2271 // desirable.
2272 if (!base.uses_srgb && !(x[1] & 0x20))
2273 warn("Set the sRGB colorimetry bit to avoid interop issues.\n");
2276 static const char *eotf_map[] = {
2277 "Traditional gamma - SDR luminance range",
2278 "Traditional gamma - HDR luminance range",
2279 "SMPTE ST2084",
2280 "Hybrid Log-Gamma",
2283 static void cta_hdr_static_metadata_block(const unsigned char *x, unsigned length)
2285 unsigned i;
2287 if (length < 2) {
2288 fail("Empty Data Block with length %u.\n", length);
2289 return;
2291 printf(" Electro optical transfer functions:\n");
2292 for (i = 0; i < 6; i++) {
2293 if (x[0] & (1 << i)) {
2294 if (i < ARRAY_SIZE(eotf_map)) {
2295 printf(" %s\n", eotf_map[i]);
2296 } else {
2297 printf(" Unknown (%u)\n", i);
2298 fail("Unknown EOTF (%u).\n", i);
2302 printf(" Supported static metadata descriptors:\n");
2303 for (i = 0; i < 8; i++) {
2304 if (x[1] & (1 << i))
2305 printf(" Static metadata type %u\n", i + 1);
2308 if (length >= 3)
2309 printf(" Desired content max luminance: %u (%.3f cd/m^2)\n",
2310 x[2], 50.0 * pow(2, x[2] / 32.0));
2312 if (length >= 4)
2313 printf(" Desired content max frame-average luminance: %u (%.3f cd/m^2)\n",
2314 x[3], 50.0 * pow(2, x[3] / 32.0));
2316 if (length >= 5)
2317 printf(" Desired content min luminance: %u (%.3f cd/m^2)\n",
2318 x[4], (50.0 * pow(2, x[2] / 32.0)) * pow(x[4] / 255.0, 2) / 100.0);
2321 static void cta_hdr_dyn_metadata_block(const unsigned char *x, unsigned length)
2323 if (length < 3) {
2324 fail("Empty Data Block with length %u.\n", length);
2325 return;
2327 while (length >= 3) {
2328 unsigned type_len = x[0];
2329 unsigned type = x[1] | (x[2] << 8);
2331 if (length < type_len + 1)
2332 return;
2333 printf(" HDR Dynamic Metadata Type %u\n", type);
2334 switch (type) {
2335 case 1:
2336 case 4:
2337 if (type_len > 2)
2338 printf(" Version: %u\n", x[3] & 0xf);
2339 break;
2340 case 2:
2341 if (type_len > 2) {
2342 unsigned version = x[3] & 0xf;
2343 printf(" Version: %u\n", version);
2344 if (version >= 1) {
2345 if (x[3] & 0x10) printf(" Supports SL-HDR1 (ETSI TS 103 433-1)\n");
2346 if (x[3] & 0x20) printf(" Supports SL-HDR2 (ETSI TS 103 433-2)\n");
2347 if (x[3] & 0x40) printf(" Supports SL-HDR3 (ETSI TS 103 433-3)\n");
2350 break;
2351 default:
2352 break;
2354 length -= type_len + 1;
2355 x += type_len + 1;
2359 static const char *infoframe_types[] = {
2360 NULL,
2361 "Vendor-Specific",
2362 "Auxiliary Video Information",
2363 "Source Product Description",
2364 "Audio",
2365 "MPEG Source",
2366 "NTSC VBI",
2367 "Dynamic Range and Mastering",
2370 static void cta_ifdb(const unsigned char *x, unsigned length)
2372 unsigned len_hdr = x[0] >> 5;
2374 if (length < 2) {
2375 fail("Empty Data Block with length %u.\n", length);
2376 return;
2378 printf(" VSIFs: %u\n", x[1]);
2379 if (length < len_hdr + 2)
2380 return;
2381 length -= len_hdr + 2;
2382 x += len_hdr + 2;
2383 while (length > 0) {
2384 int payload_len = x[0] >> 5;
2385 unsigned char type = x[0] & 0x1f;
2387 const char *name = NULL;
2388 if (type < ARRAY_SIZE(infoframe_types))
2389 name = infoframe_types[type];
2390 if (!name)
2391 name = "Unknown";
2392 printf(" %s InfoFrame (%u)", name, type);
2394 if (type == 1 && length >= 4) {
2395 unsigned oui = (x[3] << 16) | (x[2] << 8) | x[1];
2397 printf(", OUI %s\n", ouitohex(oui).c_str());
2398 x += 4;
2399 length -= 4;
2400 } else {
2401 printf("\n");
2402 x++;
2403 length--;
2405 x += payload_len;
2406 length -= payload_len;
2410 void edid_state::cta_displayid_type_7(const unsigned char *x, unsigned length)
2412 check_displayid_datablock_revision(x[0], 0x00, 2);
2414 if (length < 21U + ((x[0] & 0x70) >> 4)) {
2415 fail("Empty Data Block with length %u.\n", length);
2416 return;
2418 parse_displayid_type_1_7_timing(x + 1, true, 2, true);
2421 void edid_state::cta_displayid_type_8(const unsigned char *x, unsigned length)
2423 check_displayid_datablock_revision(x[0], 0xe8, 1);
2424 if (length < ((x[0] & 0x08) ? 3 : 2)) {
2425 fail("Empty Data Block with length %u.\n", length);
2426 return;
2429 unsigned sz = (x[0] & 0x08) ? 2 : 1;
2430 unsigned type = x[0] >> 6;
2432 if (type) {
2433 fail("Only code type 0 is supported.\n");
2434 return;
2437 if (x[0] & 0x20)
2438 printf(" Also supports YCbCr 4:2:0\n");
2440 x++;
2441 length--;
2442 for (unsigned i = 0; i < length / sz; i++) {
2443 unsigned id = x[i * sz];
2445 if (sz == 2)
2446 id |= x[i * sz + 1] << 8;
2447 parse_displayid_type_4_8_timing(type, id, true);
2451 void edid_state::cta_displayid_type_10(const unsigned char *x, unsigned length)
2453 check_displayid_datablock_revision(x[0], 0x70);
2454 if (length < 7U + ((x[0] & 0x70) >> 4)) {
2455 fail("Empty Data Block with length %u.\n", length);
2456 return;
2459 unsigned sz = 6U + ((x[0] & 0x70) >> 4);
2460 x++;
2461 length--;
2462 for (unsigned i = 0; i < length / sz; i++)
2463 parse_displayid_type_10_timing(x + i * sz, sz, true);
2466 static void cta_hdmi_audio_block(const unsigned char *x, unsigned length)
2468 unsigned num_descs;
2470 if (length < 2) {
2471 fail("Empty Data Block with length %u.\n", length);
2472 return;
2474 if (x[0] & 3)
2475 printf(" Max Stream Count: %u\n", (x[0] & 3) + 1);
2476 if (x[0] & 4)
2477 printf(" Supports MS NonMixed\n");
2479 num_descs = x[1] & 7;
2480 if (num_descs == 0)
2481 return;
2482 length -= 2;
2483 x += 2;
2484 while (length >= 4) {
2485 if (length > 4) {
2486 unsigned format = x[0] & 0xf;
2488 printf(" %s, max channels %u\n", audio_format(format).c_str(),
2489 (x[1] & 0x1f)+1);
2490 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
2491 (x[2] & 0x40) ? " 192" : "",
2492 (x[2] & 0x20) ? " 176.4" : "",
2493 (x[2] & 0x10) ? " 96" : "",
2494 (x[2] & 0x08) ? " 88.2" : "",
2495 (x[2] & 0x04) ? " 48" : "",
2496 (x[2] & 0x02) ? " 44.1" : "",
2497 (x[2] & 0x01) ? " 32" : "");
2498 if (format == 1)
2499 printf(" Supported sample sizes (bits):%s%s%s\n",
2500 (x[3] & 0x04) ? " 24" : "",
2501 (x[3] & 0x02) ? " 20" : "",
2502 (x[3] & 0x01) ? " 16" : "");
2503 } else {
2504 unsigned sad = ((x[2] << 16) | (x[1] << 8) | x[0]);
2505 unsigned i;
2507 switch (x[3] >> 4) {
2508 case 1:
2509 printf(" Speaker Allocation for 10.2 channels:\n");
2510 break;
2511 case 2:
2512 printf(" Speaker Allocation for 22.2 channels:\n");
2513 break;
2514 case 3:
2515 printf(" Speaker Allocation for 30.2 channels:\n");
2516 break;
2517 default:
2518 printf(" Unknown Speaker Allocation (0x%02x)\n", x[3] >> 4);
2519 return;
2522 for (i = 0; i < ARRAY_SIZE(speaker_map); i++) {
2523 if ((sad >> i) & 1)
2524 printf(" %s\n", speaker_map[i]);
2527 length -= 4;
2528 x += 4;
2532 void edid_state::cta_block(const unsigned char *x, std::vector<unsigned> &found_tags)
2534 unsigned length = x[0] & 0x1f;
2535 unsigned tag = (x[0] & 0xe0) >> 5;
2536 unsigned extended = (tag == 0x07) ? 1 : 0;
2538 x++;
2539 if (extended && length) {
2540 tag <<= 8;
2541 tag |= x[0];
2542 length--;
2543 x++;
2546 bool dooutputname = true;
2547 bool audio_block = false;
2548 data_block.clear();
2550 switch (tag) {
2551 case 0x01: data_block = "Audio Data Block"; audio_block = true; break;
2552 case 0x02: data_block = "Video Data Block"; break;
2553 case 0x03: data_block = "Vendor-Specific Data Block"; break;
2554 case 0x04: data_block = "Speaker Allocation Data Block"; audio_block = true; break;
2555 case 0x05: data_block = "VESA Display Transfer Characteristics Data Block"; break;
2556 case 0x06: data_block = "Video Format Data Block"; break;
2557 case 0x07: data_block = "Unknown CTA-861 Data Block (extended tag truncated)"; break;
2559 case 0x700: data_block = "Video Capability Data Block"; break;
2560 case 0x701: data_block = "Vendor-Specific Video Data Block"; break;
2561 case 0x702: data_block = "VESA Video Display Device Data Block"; break;
2562 case 0x703: data_block = "VESA Video Timing Block Extension"; break;
2563 case 0x704: data_block = "Reserved for HDMI Video Data Block"; break;
2564 case 0x705: data_block = "Colorimetry Data Block"; break;
2565 case 0x706: data_block = "HDR Static Metadata Data Block"; break;
2566 case 0x707: data_block = "HDR Dynamic Metadata Data Block"; break;
2567 case 0x708: data_block = "Native Video Resolution Data Block"; break;
2569 case 0x70d: data_block = "Video Format Preference Data Block"; break;
2570 case 0x70e: data_block = "YCbCr 4:2:0 Video Data Block"; break;
2571 case 0x70f: data_block = "YCbCr 4:2:0 Capability Map Data Block"; break;
2572 case 0x710: data_block = "Reserved for CTA-861 Miscellaneous Audio Fields"; break;
2573 case 0x711: data_block = "Vendor-Specific Audio Data Block"; audio_block = true; break;
2574 case 0x712: data_block = "HDMI Audio Data Block"; audio_block = true; break;
2575 case 0x713: data_block = "Room Configuration Data Block"; audio_block = true; break;
2576 case 0x714: data_block = "Speaker Location Data Block"; audio_block = true; break;
2578 case 0x720: data_block = "InfoFrame Data Block"; break;
2580 case 0x722: data_block = "DisplayID Type VII Video Timing Data Block"; break;
2581 case 0x723: data_block = "DisplayID Type VIII Video Timing Data Block"; break;
2582 case 0x72a: data_block = "DisplayID Type X Video Timing Data Block"; break;
2584 case 0x778: data_block = "HDMI Forum EDID Extension Override Data Block"; break;
2585 case 0x779: data_block = "HDMI Forum Sink Capability Data Block"; break;
2586 case 0x77a: data_block = "HDMI Forum Source-Based Tone Mapping Data Block"; break;
2588 default:
2589 std::string unknown_name;
2590 if (tag < 0x700) unknown_name = "Unknown CTA-861 Data Block";
2591 else if (tag < 0x70d) unknown_name = "Unknown CTA-861 Video-Related Data Block";
2592 else if (tag < 0x720) unknown_name = "Unknown CTA-861 Audio-Related Data Block";
2593 else if (tag < 0x778) unknown_name = "Unknown CTA-861 Data Block";
2594 else if (tag < 0x780) unknown_name = "Unknown CTA-861 HDMI-Related Data Block";
2595 else unknown_name = "Unknown CTA-861 Data Block";
2596 unknown_name += std::string(" (") + (extended ? "extended " : "") + "tag " + utohex(tag & 0xff) + ", length " + std::to_string(length) + ")";
2597 printf(" %s:\n", unknown_name.c_str());
2598 warn("%s.\n", unknown_name.c_str());
2599 break;
2602 switch (tag) {
2603 case 0x03:
2604 case 0x701:
2605 case 0x711: {
2606 unsigned ouinum;
2608 data_block_oui(data_block, x, length, &ouinum);
2609 x += (length < 3) ? length : 3;
2610 length -= (length < 3) ? length : 3;
2611 dooutputname = false;
2612 tag |= ouinum;
2613 break;
2617 if (dooutputname && data_block.length())
2618 printf(" %s:\n", data_block.c_str());
2620 switch (tag) {
2621 case 0x04:
2622 case 0x05:
2623 case 0x700:
2624 case 0x702:
2625 case 0x705:
2626 case 0x706:
2627 case 0x708:
2628 case 0x70d:
2629 case 0x70f:
2630 case 0x712:
2631 case 0x713:
2632 case 0x778:
2633 case 0x779:
2634 case 0x77a:
2635 if (std::find(found_tags.begin(), found_tags.end(), tag) != found_tags.end())
2636 fail("Only one instance of this Data Block is allowed.\n");
2637 break;
2640 // See Table 52 of CTA-861-G for a description of Byte 3
2641 if (audio_block && !(cta.byte3 & 0x40))
2642 fail("Audio information is present, but bit 6 of Byte 3 of the CTA-861 Extension header indicates no Basic Audio support.\n");
2644 switch (tag) {
2645 case 0x01: cta_audio_block(x, length); break;
2646 case 0x02: cta_svd(x, length, false); break;
2647 case 0x03|kOUI_HDMI:
2648 cta_hdmi_block(x, length);
2649 // The HDMI OUI is present, so this EDID represents an HDMI
2650 // interface. And HDMI interfaces must use EDID version 1.3
2651 // according to the HDMI Specification, so check for this.
2652 if (base.edid_minor != 3)
2653 fail("The HDMI Specification requires EDID 1.3 instead of 1.%u.\n",
2654 base.edid_minor);
2655 break;
2656 case 0x03|kOUI_HDMIForum:
2657 if (cta.previous_cta_tag != (0x03|kOUI_HDMI))
2658 fail("HDMI Forum VSDB did not immediately follow the HDMI VSDB.\n");
2659 if (cta.have_hf_scdb || cta.have_hf_vsdb)
2660 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2661 cta_hf_scdb(x, length);
2662 cta.have_hf_vsdb = true;
2663 break;
2664 case 0x03|kOUI_AMD: cta_amd(x, length); break;
2665 case 0x03|kOUI_Microsoft: if (length != 0x12) goto dodefault; cta_microsoft(x, length); break;
2666 case 0x03|kOUI_UHDA: cta_uhda_fmm(x, length); break;
2667 case 0x04: cta_sadb(x, length); break;
2668 case 0x05: cta_vesa_dtcdb(x, length); break;
2669 case 0x06: cta_vfdb(x, length); break;
2670 case 0x07: fail("Extended tag cannot have zero length.\n"); break;
2671 case 0x700: cta_vcdb(x, length); break;
2672 case 0x701|kOUI_HDR10: cta_hdr10plus(x, length); break;
2673 case 0x701|kOUI_Dolby: cta_dolby_video(x, length); break;
2674 // 0x701|kOUI_Apple: this almost certainly contains 'BLC Info/Corrections',
2675 // since the data (spread out over two VSDBs) is very similar to what is seen
2676 // in DisplayID blocks. Since I don't know how to parse this data, we still
2677 // default to a hex dump, but I mention this here in case data on how to
2678 // parse this becomes available.
2679 case 0x702: cta_vesa_vdddb(x, length); break;
2680 case 0x705: cta_colorimetry_block(x, length); break;
2681 case 0x706: cta_hdr_static_metadata_block(x, length); break;
2682 case 0x707: cta_hdr_dyn_metadata_block(x, length); break;
2683 case 0x708: cta_nvrdb(x, length); return;
2684 case 0x70d: cta_vfpdb(x, length); break;
2685 case 0x70e: cta_svd(x, length, true); break;
2686 case 0x70f: cta_y420cmdb(x, length); break;
2687 case 0x711|kOUI_Dolby: cta_dolby_audio(x, length); break;
2688 case 0x712: cta_hdmi_audio_block(x, length); break;
2689 case 0x713: cta_rcdb(x, length); break;
2690 case 0x714: cta_sldb(x, length); break;
2691 case 0x720: cta_ifdb(x, length); break;
2692 case 0x722: cta_displayid_type_7(x, length); break;
2693 case 0x723: cta_displayid_type_8(x, length); break;
2694 case 0x72a: cta_displayid_type_10(x, length); break;
2695 case 0x778:
2696 cta_hf_eeodb(x, length);
2697 if (block_nr != 1)
2698 fail("Data Block can only be present in Block 1.\n");
2699 // This must be the first CTA-861 block
2700 if (cta.block_number > 0)
2701 fail("Data Block starts at a wrong offset.\n");
2702 break;
2703 case 0x779:
2704 if (cta.previous_cta_tag != (0x03|kOUI_HDMI))
2705 fail("HDMI Forum SCDB did not immediately follow the HDMI VSDB.\n");
2706 if (cta.have_hf_scdb || cta.have_hf_vsdb)
2707 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2708 if (block_nr != 1)
2709 fail("Data Block can only be present in Block 1.\n");
2710 if (length < 2) {
2711 data_block = std::string("HDMI Forum SCDB");
2712 fail("Invalid length %u < 2.\n", length);
2713 break;
2715 if (x[0] || x[1])
2716 printf(" Non-zero SCDB reserved fields!\n");
2717 cta_hf_scdb(x + 2, length - 2);
2718 cta.have_hf_scdb = true;
2719 break;
2720 case 0x77a:
2721 cta_hf_sbtmdb(x, length);
2722 break;
2723 dodefault:
2724 default:
2725 hex_block(" ", x, length);
2726 break;
2729 cta.block_number++;
2730 cta.previous_cta_tag = tag;
2731 found_tags.push_back(tag);
2734 void edid_state::preparse_cta_block(unsigned char *x)
2736 unsigned version = x[1];
2737 unsigned offset = x[2];
2739 if (offset >= 4) {
2740 const unsigned char *detailed;
2742 for (detailed = x + offset; detailed + 17 < x + 127; detailed += 18) {
2743 if (memchk(detailed, 18))
2744 break;
2745 if (detailed[0] || detailed[1])
2746 cta.preparsed_total_dtds++;
2750 if (version < 3)
2751 return;
2753 for (unsigned i = 4; i < offset; i += (x[i] & 0x1f) + 1) {
2754 bool for_ycbcr420 = false;
2755 unsigned oui;
2757 switch ((x[i] & 0xe0) >> 5) {
2758 case 0x03:
2759 oui = (x[i + 3] << 16) + (x[i + 2] << 8) + x[i + 1];
2760 if (oui == 0x000c03) {
2761 cta.has_hdmi = true;
2762 cta.preparsed_phys_addr = (x[i + 4] << 8) | x[i + 5];
2763 } else if ((oui == 0xca125c || oui == 0x5c12ca) &&
2764 (x[i] & 0x1f) == 0x15 && replace_unique_ids) {
2765 memset(x + i + 6, 0, 16);
2766 replace_checksum(x, EDID_PAGE_SIZE);
2768 break;
2769 case 0x06:
2770 if (!(x[i] & 0x1f) || cta.preparsed_first_vfd.rid)
2771 break;
2772 cta.preparsed_first_vfd = cta_parse_vfd(x + i + 2, (x[i + 1] & 3) + 1);
2773 break;
2774 case 0x07:
2775 if (x[i + 1] == 0x0d)
2776 cta.has_vfpdb = true;
2777 else if (x[i + 1] == 0x05)
2778 cta.has_cdb = true;
2779 else if (x[i + 1] == 0x08)
2780 cta.has_nvrdb = true;
2781 else if (x[i + 1] == 0x13 && (x[i + 2] & 0x40)) {
2782 cta.preparsed_speaker_count = 1 + (x[i + 2] & 0x1f);
2783 cta.preparsed_sld = x[i + 2] & 0x20;
2784 } else if (x[i + 1] == 0x14)
2785 cta_preparse_sldb(x + i + 2, (x[i] & 0x1f) - 1);
2786 else if (x[i + 1] == 0x22)
2787 cta.preparsed_total_vtdbs++;
2788 else if (x[i + 1] == 0x23) {
2789 cta.preparsed_has_t8vtdb = true;
2790 cta.preparsed_t8vtdb_dmt = x[i + 3];
2791 if (x[i + 2] & 0x08)
2792 cta.preparsed_t8vtdb_dmt |= x[i + 4] << 8;
2793 } else if (x[i + 1] == 0x2a)
2794 cta.preparsed_total_vtdbs +=
2795 ((x[i] & 0x1f) - 2) / (6 + ((x[i + 2] & 0x70) >> 4));
2796 else if (x[i + 1] == 0x78)
2797 cta.hf_eeodb_blocks = x[i + 2];
2798 if (x[i + 1] != 0x0e)
2799 continue;
2800 for_ycbcr420 = true;
2801 #ifdef __EMSCRIPTEN__
2802 [[clang::fallthrough]];
2803 #endif
2804 /* fall-through */
2805 case 0x02:
2806 for (unsigned j = 1 + for_ycbcr420; j <= (x[i] & 0x1f); j++) {
2807 unsigned char vic = x[i + j];
2809 if ((vic & 0x7f) <= 64)
2810 vic &= 0x7f;
2811 cta.preparsed_svds[for_ycbcr420].push_back(vic);
2812 cta.preparsed_has_vic[for_ycbcr420][vic] = true;
2814 const struct timings *t = find_vic_id(vic);
2816 if (!for_ycbcr420 && t &&
2817 t->pixclk_khz > cta.preparsed_max_vic_pixclk_khz)
2818 cta.preparsed_max_vic_pixclk_khz = t->pixclk_khz;
2820 break;
2825 void edid_state::parse_cta_block(const unsigned char *x)
2827 unsigned version = x[1];
2828 unsigned offset = x[2];
2829 const unsigned char *detailed;
2831 // See Table 52 of CTA-861-G for a description of Byte 3
2833 printf(" Revision: %u\n", version);
2834 if (version == 0)
2835 fail("Invalid CTA-861 Extension revision 0.\n");
2836 if (version == 2)
2837 fail("Deprecated CTA-861 Extension revision 2.\n");
2838 if (cta.has_hdmi && version != 3)
2839 fail("The HDMI Specification requires CTA Extension revision 3.\n");
2840 if (version > 3)
2841 warn("Unknown CTA-861 Extension revision %u.\n", version);
2842 if (offset > 0 && offset < 4)
2843 fail("Invalid CTA-861 Extension offset value (byte 2).\n");
2845 if (version >= 1) do {
2846 if (version == 1 && x[3] != 0)
2847 fail("Non-zero byte 3.\n");
2849 if (version < 3 && offset >= 4 && ((offset - 4) / 8)) {
2850 printf(" 8-byte timing descriptors: %u\n", (offset - 4) / 8);
2851 fail("8-byte descriptors were never used.\n");
2854 if (version >= 2) {
2855 if (x[3] & 0x80)
2856 printf(" Underscans IT Video Formats by default\n");
2857 else
2858 warn("IT Video Formats are overscanned by default, but normally this should be underscanned.\n");
2859 if (x[3] & 0x40)
2860 printf(" Basic audio support\n");
2861 if (x[3] & 0x20)
2862 printf(" Supports YCbCr 4:4:4\n");
2863 if (x[3] & 0x10)
2864 printf(" Supports YCbCr 4:2:2\n");
2865 // Disable this test: this fails a lot of EDIDs, and there are
2866 // also some corner cases where you only want to receive 4:4:4
2867 // and refuse a fallback to 4:2:2.
2868 // if ((x[3] & 0x30) && (x[3] & 0x30) != 0x30)
2869 // msg(!cta.has_hdmi, "If YCbCr support is indicated, then both 4:2:2 and 4:4:4 %s be supported.\n",
2870 // cta.has_hdmi ? "shall" : "should");
2871 printf(" Native detailed modes: %u\n", x[3] & 0x0f);
2872 if (cta.block_number == 0)
2873 cta.byte3 = x[3];
2874 else if (x[3] != cta.byte3)
2875 fail("Byte 3 must be the same for all CTA-861 Extension Blocks.\n");
2876 if (cta.block_number == 0) {
2877 unsigned native_dtds = x[3] & 0x0f;
2879 cta.native_timings.clear();
2880 if (!native_dtds && !cta.has_vfpdb) {
2881 cta.first_svd_might_be_preferred = true;
2882 } else if (native_dtds > cta.preparsed_total_dtds) {
2883 fail("There are more Native DTDs (%u) than DTDs (%u).\n",
2884 native_dtds, cta.preparsed_total_dtds);
2886 if (native_dtds > cta.preparsed_total_dtds)
2887 native_dtds = cta.preparsed_total_dtds;
2888 for (unsigned i = 0; i < native_dtds; i++) {
2889 char type[16];
2891 sprintf(type, "DTD %3u", i + 1);
2892 cta.native_timings.push_back(timings_ext(i + 129, type));
2894 if (cta.has_hdmi && block_nr != (block_map.saw_block_1 ? 2 : 1))
2895 fail("The HDMI Specification requires that the first Extension Block (that is not a Block Map) is an CTA-861 Extension Block.\n");
2899 if (offset < 4) {
2900 // Offset 0 means that there are no data blocks or DTDs,
2901 // so the remainder must be padding.
2902 if (!memchk(x + 4, 127 - 4)) {
2903 data_block = "Padding";
2904 fail("Contains non-zero bytes.\n");
2906 break;
2909 if (version >= 3) {
2910 unsigned i;
2912 for (i = 4; i < offset; i += (x[i] & 0x1f) + 1) {
2913 cta_block(x + i, cta.found_tags);
2916 data_block.clear();
2917 if (i != offset)
2918 fail("Offset is %u, but should be %u.\n", offset, i);
2921 data_block = "Detailed Timing Descriptors";
2922 base.seen_non_detailed_descriptor = false;
2923 bool first = true;
2924 for (detailed = x + offset; detailed + 17 < x + 127; detailed += 18) {
2925 if (memchk(detailed, 18))
2926 break;
2927 if (first) {
2928 first = false;
2929 printf(" %s:\n", data_block.c_str());
2931 detailed_block(detailed);
2933 unused_bytes = x + 127 - detailed;
2934 if (!memchk(detailed, unused_bytes)) {
2935 data_block = "Padding";
2936 fail("Contains non-zero bytes.\n");
2938 } while (0);
2940 data_block.clear();
2941 if (base.serial_number && base.has_serial_string)
2942 warn("Display Product Serial Number is set, so the Serial Number in the Base EDID should be 0.\n");
2943 if (!cta.has_vic_1 && !base.has_640x480p60_est_timing)
2944 fail("Required 640x480p60 timings are missing in the established timings"
2945 " and the SVD list (VIC 1).\n");
2946 if ((cta.supported_hdmi_vic_vsb_codes & cta.supported_hdmi_vic_codes) !=
2947 cta.supported_hdmi_vic_codes)
2948 fail("HDMI VIC Codes must have their CTA-861 VIC equivalents in the VSB.\n");
2949 if (!cta.has_vcdb)
2950 fail("Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.\n");
2951 if (!base.uses_srgb && !cta.has_cdb)
2952 warn("Add a Colorimetry Data Block with the sRGB colorimetry bit set to avoid interop issues.\n");
2955 void edid_state::cta_resolve_svr(timings_ext &t_ext)
2957 if (t_ext.svr() == 254) {
2958 t_ext.flags = cta.t8vtdb.flags;
2959 add_str(t_ext.flags, ">=CTA-861-H");
2960 t_ext.t = cta.t8vtdb.t;
2961 } else if (t_ext.svr() <= 144) {
2962 t_ext.flags = cta.vec_dtds[t_ext.svr() - 129].flags;
2963 t_ext.t = cta.vec_dtds[t_ext.svr() - 129].t;
2964 } else if (t_ext.svr() <= 160) {
2965 t_ext.flags = cta.vec_vtdbs[t_ext.svr() - 145].flags;
2966 add_str(t_ext.flags, ">=CTA-861-H");
2967 t_ext.t = cta.vec_vtdbs[t_ext.svr() - 145].t;
2968 } else if (t_ext.svr() <= 175) {
2969 t_ext.flags.clear();
2970 unsigned char rid = cta.preparsed_first_vfd.rid;
2971 t_ext.t = calc_ovt_mode(rids[rid].hact, rids[rid].vact,
2972 rids[rid].hratio, rids[rid].vratio,
2973 vf_rate_values[t_ext.svr() - 160]);
2974 t_ext.flags = ">=CTA-861.6";
2978 void edid_state::cta_resolve_svrs()
2980 for (vec_timings_ext::iterator iter = cta.preferred_timings_vfpdb.begin();
2981 iter != cta.preferred_timings_vfpdb.end(); ++iter) {
2982 if (iter->has_svr())
2983 cta_resolve_svr(*iter);
2986 for (vec_timings_ext::iterator iter = cta.native_timings.begin();
2987 iter != cta.native_timings.end(); ++iter) {
2988 if (iter->has_svr())
2989 cta_resolve_svr(*iter);
2992 for (vec_timings_ext::iterator iter = cta.native_timing_nvrdb.begin();
2993 iter != cta.native_timing_nvrdb.end(); ++iter) {
2994 if (iter->has_svr())
2995 cta_resolve_svr(*iter);
2999 void edid_state::check_cta_blocks()
3001 unsigned max_pref_prog_hact = 0;
3002 unsigned max_pref_prog_vact = 0;
3003 unsigned max_pref_ilace_hact = 0;
3004 unsigned max_pref_ilace_vact = 0;
3006 data_block = "CTA-861";
3008 // HDMI 1.4 goes up to 340 MHz. Dubious to have a DTD above that,
3009 // but no VICs. Displays often have a setting to turn off HDMI 2.x
3010 // support, dropping any HDMI 2.x VICs, but they sometimes forget
3011 // to replace the DTD in the base block as well.
3012 if (cta.warn_about_hdmi_2x_dtd)
3013 warn("DTD pixelclock indicates HDMI 2.x support, VICs indicate HDMI 1.x.\n");
3015 for (vec_timings_ext::iterator iter = cta.preferred_timings.begin();
3016 iter != cta.preferred_timings.end(); ++iter) {
3017 if (iter->t.interlaced &&
3018 (iter->t.vact > max_pref_ilace_vact ||
3019 (iter->t.vact == max_pref_ilace_vact && iter->t.hact >= max_pref_ilace_hact))) {
3020 max_pref_ilace_hact = iter->t.hact;
3021 max_pref_ilace_vact = iter->t.vact;
3023 if (!iter->t.interlaced &&
3024 (iter->t.vact > max_pref_prog_vact ||
3025 (iter->t.vact == max_pref_prog_vact && iter->t.hact >= max_pref_prog_hact))) {
3026 max_pref_prog_hact = iter->t.hact;
3027 max_pref_prog_vact = iter->t.vact;
3030 for (vec_timings_ext::iterator iter = cta.preferred_timings_vfpdb.begin();
3031 iter != cta.preferred_timings_vfpdb.end(); ++iter) {
3032 if (iter->t.interlaced &&
3033 (iter->t.vact > max_pref_ilace_vact ||
3034 (iter->t.vact == max_pref_ilace_vact && iter->t.hact >= max_pref_ilace_hact))) {
3035 max_pref_ilace_hact = iter->t.hact;
3036 max_pref_ilace_vact = iter->t.vact;
3038 if (!iter->t.interlaced &&
3039 (iter->t.vact > max_pref_prog_vact ||
3040 (iter->t.vact == max_pref_prog_vact && iter->t.hact >= max_pref_prog_hact))) {
3041 max_pref_prog_hact = iter->t.hact;
3042 max_pref_prog_vact = iter->t.vact;
3046 unsigned native_prog = 0;
3047 unsigned native_prog_hact = 0;
3048 unsigned native_prog_vact = 0;
3049 bool native_prog_mixed_resolutions = false;
3050 unsigned native_ilace = 0;
3051 unsigned native_ilace_hact = 0;
3052 unsigned native_ilace_vact = 0;
3053 bool native_ilace_mixed_resolutions = false;
3054 unsigned native_nvrdb_hact = 0;
3055 unsigned native_nvrdb_vact = 0;
3057 for (vec_timings_ext::iterator iter = cta.native_timings.begin();
3058 iter != cta.native_timings.end(); ++iter) {
3059 if (iter->t.interlaced) {
3060 native_ilace++;
3061 if (!native_ilace_hact) {
3062 native_ilace_hact = iter->t.hact;
3063 native_ilace_vact = iter->t.vact;
3064 } else if (native_ilace_hact != iter->t.hact ||
3065 native_ilace_vact != iter->t.vact) {
3066 native_ilace_mixed_resolutions = true;
3068 } else {
3069 native_prog++;
3070 if (!native_prog_hact) {
3071 native_prog_hact = iter->t.hact;
3072 native_prog_vact = iter->t.vact;
3073 } else if (native_prog_hact != iter->t.hact ||
3074 native_prog_vact != iter->t.vact) {
3075 native_prog_mixed_resolutions = true;
3080 for (vec_timings_ext::iterator iter = cta.native_timing_nvrdb.begin();
3081 iter != cta.native_timing_nvrdb.end(); ++iter) {
3082 native_nvrdb_hact = iter->t.hact;
3083 native_nvrdb_vact = iter->t.vact;
3086 if (native_prog_mixed_resolutions)
3087 fail("Native progressive timings are a mix of several resolutions.\n");
3088 if (native_ilace_mixed_resolutions)
3089 fail("Native interlaced timings are a mix of several resolutions.\n");
3090 if (native_ilace && !native_prog)
3091 fail("A native interlaced timing is present, but not a native progressive timing.\n");
3092 if (!native_prog_mixed_resolutions && native_prog > 1)
3093 warn("Multiple native progressive timings are defined.\n");
3094 if (!native_ilace_mixed_resolutions && native_ilace > 1)
3095 warn("Multiple native interlaced timings are defined.\n");
3097 if (native_nvrdb_vact &&
3098 (max_pref_prog_vact > native_nvrdb_vact ||
3099 (max_pref_prog_vact == native_nvrdb_vact && max_pref_prog_hact > native_nvrdb_hact)))
3100 warn("Native video resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
3101 native_nvrdb_hact, native_nvrdb_vact,
3102 max_pref_prog_hact, max_pref_prog_vact);
3103 else if (!native_nvrdb_vact && !native_prog_mixed_resolutions && native_prog_vact &&
3104 (max_pref_prog_vact > native_prog_vact ||
3105 (max_pref_prog_vact == native_prog_vact && max_pref_prog_hact > native_prog_hact)))
3106 warn("Native progressive resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
3107 native_prog_hact, native_prog_vact,
3108 max_pref_prog_hact, max_pref_prog_vact);
3109 if (!native_ilace_mixed_resolutions && native_ilace_vact &&
3110 (max_pref_ilace_vact > native_ilace_vact ||
3111 (max_pref_ilace_vact == native_ilace_vact && max_pref_ilace_hact > native_ilace_hact)))
3112 warn("Native interlaced resolution of %ux%u is smaller than the max preferred interlaced resolution %ux%u.\n",
3113 native_ilace_hact, native_ilace_vact,
3114 max_pref_ilace_hact, max_pref_ilace_vact);
3116 if (dispid.native_width && native_prog_hact &&
3117 !native_prog_mixed_resolutions) {
3118 if (dispid.native_width != native_prog_hact ||
3119 dispid.native_height != native_prog_vact)
3120 fail("Mismatch between CTA-861 and DisplayID native progressive resolution.\n");