edid-decode: let --replace-unique-ids replace dates as well
[edid-decode.git] / parse-cta-block.cpp
blobe26579a5171a5cd488ef5cb83b39538d4d3dc5fb
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));
856 cta.has_svrs = true;
858 } else if (svr >= 145 && svr <= 160) {
859 sprintf(suffix, "VTDB %3u", svr - 144);
860 if (svr >= cta.preparsed_total_vtdbs + 145) {
861 printf(" %s: Invalid\n", suffix);
862 fail("Invalid VTDB %u.\n", svr - 144);
863 } else {
864 printf(" %s\n", suffix);
865 vec_tim.push_back(timings_ext(svr, suffix));
866 cta.has_svrs = true;
868 } else if (svr >= 161 && svr <= 175) {
869 sprintf(suffix, "RID %u@%up",
870 cta.preparsed_first_vfd.rid, vf_rate_values[svr - 160]);
871 if (!vfd_has_rate(cta.preparsed_first_vfd, svr - 160)) {
872 printf(" %s: Invalid\n", suffix);
873 fail("Invalid %s.\n", suffix);
874 } else {
875 printf(" %s\n", suffix);
876 vec_tim.push_back(timings_ext(svr, suffix));
877 cta.has_svrs = true;
879 } else if (svr == 254) {
880 sprintf(suffix, "T8VTDB");
881 if (!cta.preparsed_has_t8vtdb) {
882 printf(" %s: Invalid\n", suffix);
883 fail("Invalid T8VTDB.\n");
884 } else {
885 sprintf(suffix, "DMT 0x%02x", cta.preparsed_t8vtdb_dmt);
886 printf(" %s\n", suffix);
887 vec_tim.push_back(timings_ext(svr, suffix));
888 cta.has_svrs = true;
893 void edid_state::cta_vfpdb(const unsigned char *x, unsigned length)
895 unsigned i;
897 if (length == 0) {
898 fail("Empty Data Block with length %u.\n", length);
899 return;
901 cta.preferred_timings_vfpdb.clear();
902 for (i = 0; i < length; i++)
903 cta_print_svr(x[i], cta.preferred_timings_vfpdb);
906 void edid_state::cta_nvrdb(const unsigned char *x, unsigned length)
908 if (length == 0) {
909 fail("Empty Data Block with length %u.\n", length);
910 return;
913 unsigned char flags = length == 1 ? 0 : x[1];
915 cta.native_timing_nvrdb.clear();
916 cta_print_svr(x[0], cta.native_timing_nvrdb);
917 if ((flags & 1) && length < 6) {
918 fail("Data Block too short for Image Size (length = %u).\n", length);
919 return;
921 if (flags & 0x7e)
922 fail("Bits F41-F46 must be 0.\n");
923 if (!(flags & 1))
924 return;
926 unsigned w = (x[3] << 8) | x[2];
927 unsigned h = (x[5] << 8) | x[4];
929 if (!w || !h)
930 fail("Image Size has a zero width and/or height.\n");
932 if (flags & 0x80)
933 printf(" Image Size: %ux%u mm\n", w, h);
934 else
935 printf(" Image Size: %.1fx%.1f mm\n", w / 10.0, h / 10.0);
938 static std::string hdmi_latency2s(unsigned char l, bool is_video)
940 if (!l)
941 return "Unknown";
942 if (l == 0xff)
943 return is_video ? "Video not supported" : "Audio not supported";
944 return std::to_string(2 * (l - 1)) + " ms";
947 void edid_state::hdmi_latency(unsigned char vid_lat, unsigned char aud_lat,
948 bool is_ilaced)
950 const char *vid = is_ilaced ? "Interlaced video" : "Video";
951 const char *aud = is_ilaced ? "Interlaced audio" : "Audio";
953 printf(" %s latency: %s\n", vid, hdmi_latency2s(vid_lat, true).c_str());
954 printf(" %s latency: %s\n", aud, hdmi_latency2s(aud_lat, false).c_str());
956 if (vid_lat > 251 && vid_lat != 0xff)
957 fail("Invalid %s latency value %u.\n", vid, vid_lat);
958 if (aud_lat > 251 && aud_lat != 0xff)
959 fail("Invalid %s latency value %u.\n", aud, aud_lat);
961 if (!vid_lat || vid_lat > 251)
962 return;
963 if (!aud_lat || aud_lat > 251)
964 return;
966 unsigned vid_ms = 2 * (vid_lat - 1);
967 unsigned aud_ms = 2 * (aud_lat - 1);
969 // HDMI 2.0 latency checks for devices without HDMI output
970 if (aud_ms < vid_ms)
971 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
972 aud, vid, aud_ms, vid_ms);
973 else if (vid_ms + 20 < aud_ms)
974 warn("%s latency + 20 < %s latency (%u + 20 ms < %u ms). This is forbidden for devices without HDMI output.\n",
975 vid, aud, vid_ms, aud_ms);
976 else if (vid_ms < aud_ms)
977 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
978 vid, aud, vid_ms, aud_ms);
981 void edid_state::cta_hdmi_block(const unsigned char *x, unsigned length)
983 unsigned len_vic, len_3d;
985 if (length < 1) {
986 fail("Empty Data Block with length %u.\n", length);
987 return;
989 printf(" Source physical address: %x.%x.%x.%x\n", x[0] >> 4, x[0] & 0x0f,
990 x[1] >> 4, x[1] & 0x0f);
992 if (length < 3)
993 return;
995 if (x[2] & 0x80)
996 printf(" Supports_AI\n");
997 if (x[2] & 0x40)
998 printf(" DC_48bit\n");
999 if (x[2] & 0x20)
1000 printf(" DC_36bit\n");
1001 if (x[2] & 0x10)
1002 printf(" DC_30bit\n");
1003 if (x[2] & 0x08)
1004 printf(" DC_Y444\n");
1005 /* two reserved bits */
1006 if (x[2] & 0x01)
1007 printf(" DVI_Dual\n");
1009 if (length < 4)
1010 return;
1012 unsigned rate = x[3] * 5;
1013 printf(" Maximum TMDS clock: %u MHz\n", rate);
1014 cta.hdmi_max_rate = rate;
1015 if (rate > 340)
1016 fail("HDMI VSDB Max TMDS rate is > 340.\n");
1018 if (length < 5)
1019 return;
1021 if (x[4] & 0x0f) {
1022 printf(" Supported Content Types:\n");
1023 if (x[4] & 0x01)
1024 printf(" Graphics\n");
1025 if (x[4] & 0x02)
1026 printf(" Photo\n");
1027 if (x[4] & 0x04)
1028 printf(" Cinema\n");
1029 if (x[4] & 0x08)
1030 printf(" Game\n");
1033 unsigned b = 5;
1034 if (x[4] & 0x80) {
1035 hdmi_latency(x[b], x[b + 1], false);
1037 if (x[4] & 0x40) {
1038 if (x[b] == x[b + 2] &&
1039 x[b + 1] == x[b + 3])
1040 warn("Progressive and Interlaced latency values are identical, no need for both.\n");
1041 b += 2;
1042 hdmi_latency(x[b], x[b + 1], true);
1044 b += 2;
1047 if (!(x[4] & 0x20))
1048 return;
1050 bool mask = false;
1051 bool formats = false;
1053 printf(" Extended HDMI video details:\n");
1054 if (x[b] & 0x80)
1055 printf(" 3D present\n");
1056 if ((x[b] & 0x60) == 0x20) {
1057 printf(" All advertised VICs are 3D-capable\n");
1058 formats = true;
1060 if ((x[b] & 0x60) == 0x40) {
1061 printf(" 3D-capable-VIC mask present\n");
1062 formats = true;
1063 mask = true;
1065 switch (x[b] & 0x18) {
1066 case 0x00: break;
1067 case 0x08:
1068 printf(" Base EDID image size is aspect ratio\n");
1069 break;
1070 case 0x10:
1071 printf(" Base EDID image size is in units of 1 cm\n");
1072 break;
1073 case 0x18:
1074 printf(" Base EDID image size is in units of 5 cm\n");
1075 base.max_display_width_mm *= 5;
1076 base.max_display_height_mm *= 5;
1077 printf(" Recalculated image size: %u cm x %u cm\n",
1078 base.max_display_width_mm / 10, base.max_display_height_mm / 10);
1079 break;
1081 b++;
1082 len_vic = (x[b] & 0xe0) >> 5;
1083 len_3d = (x[b] & 0x1f) >> 0;
1084 b++;
1086 if (len_vic) {
1087 unsigned i;
1089 printf(" HDMI VICs:\n");
1090 for (i = 0; i < len_vic; i++) {
1091 unsigned char vic = x[b + i];
1092 const struct timings *t;
1094 if (vic && vic <= ARRAY_SIZE(edid_hdmi_mode_map)) {
1095 std::string suffix = "HDMI VIC " + std::to_string(vic);
1096 cta.supported_hdmi_vic_codes |= 1 << (vic - 1);
1097 t = find_vic_id(edid_hdmi_mode_map[vic - 1]);
1098 print_timings(" ", t, suffix.c_str());
1099 } else {
1100 printf(" Unknown (HDMI VIC %u)\n", vic);
1101 fail("Unknown HDMI VIC %u.\n", vic);
1105 b += len_vic;
1108 if (!len_3d)
1109 return;
1111 if (formats) {
1112 /* 3D_Structure_ALL_15..8 */
1113 if (x[b] & 0x80)
1114 printf(" 3D: Side-by-side (half, quincunx)\n");
1115 if (x[b] & 0x01)
1116 printf(" 3D: Side-by-side (half, horizontal)\n");
1117 /* 3D_Structure_ALL_7..0 */
1118 b++;
1119 if (x[b] & 0x40)
1120 printf(" 3D: Top-and-bottom\n");
1121 if (x[b] & 0x20)
1122 printf(" 3D: L + depth + gfx + gfx-depth\n");
1123 if (x[b] & 0x10)
1124 printf(" 3D: L + depth\n");
1125 if (x[b] & 0x08)
1126 printf(" 3D: Side-by-side (full)\n");
1127 if (x[b] & 0x04)
1128 printf(" 3D: Line-alternative\n");
1129 if (x[b] & 0x02)
1130 printf(" 3D: Field-alternative\n");
1131 if (x[b] & 0x01)
1132 printf(" 3D: Frame-packing\n");
1133 b++;
1134 len_3d -= 2;
1137 if (mask) {
1138 int max_idx = -1;
1139 unsigned i;
1141 printf(" 3D VIC indices that support these capabilities:\n");
1142 /* worst bit ordering ever */
1143 for (i = 0; i < 8; i++)
1144 if (x[b + 1] & (1 << i)) {
1145 print_vic_index(" ", i, "");
1146 max_idx = i;
1148 for (i = 0; i < 8; i++)
1149 if (x[b] & (1 << i)) {
1150 print_vic_index(" ", i + 8, "");
1151 max_idx = i + 8;
1153 b += 2;
1154 len_3d -= 2;
1155 if (max_idx >= (int)cta.preparsed_svds[0].size())
1156 fail("HDMI 3D VIC indices max index %d > %u (#SVDs).\n",
1157 max_idx + 1, cta.preparsed_svds[0].size());
1161 * list of nibbles:
1162 * 2D_VIC_Order_X
1163 * 3D_Structure_X
1164 * (optionally: 3D_Detail_X and reserved)
1166 if (!len_3d)
1167 return;
1169 unsigned end = b + len_3d;
1170 int max_idx = -1;
1172 printf(" 3D VIC indices with specific capabilities:\n");
1173 while (b < end) {
1174 unsigned char idx = x[b] >> 4;
1175 std::string s;
1177 if (idx > max_idx)
1178 max_idx = idx;
1179 switch (x[b] & 0x0f) {
1180 case 0: s = "frame packing"; break;
1181 case 1: s = "field alternative"; break;
1182 case 2: s = "line alternative"; break;
1183 case 3: s = "side-by-side (full)"; break;
1184 case 4: s = "L + depth"; break;
1185 case 5: s = "L + depth + gfx + gfx-depth"; break;
1186 case 6: s = "top-and-bottom"; break;
1187 case 8:
1188 s = "side-by-side";
1189 switch (x[b + 1] >> 4) {
1190 case 0x00: s += ", any subsampling"; break;
1191 case 0x01: s += ", horizontal"; break;
1192 case 0x02: case 0x03: case 0x04: case 0x05:
1193 s += ", not in use";
1194 fail("not-in-use 3D_Detail_X value 0x%02x.\n",
1195 x[b + 1] >> 4);
1196 break;
1197 case 0x06: s += ", all quincunx combinations"; break;
1198 case 0x07: s += ", quincunx odd/left, odd/right"; break;
1199 case 0x08: s += ", quincunx odd/left, even/right"; break;
1200 case 0x09: s += ", quincunx even/left, odd/right"; break;
1201 case 0x0a: s += ", quincunx even/left, even/right"; break;
1202 default:
1203 s += ", reserved";
1204 fail("reserved 3D_Detail_X value 0x%02x.\n",
1205 x[b + 1] >> 4);
1206 break;
1208 break;
1209 default:
1210 s = "unknown (";
1211 s += utohex(x[b] & 0x0f) + ")";
1212 fail("Unknown 3D_Structure_X value 0x%02x.\n", x[b] & 0x0f);
1213 break;
1215 print_vic_index(" ", idx, s.c_str());
1216 if ((x[b] & 0x0f) >= 8)
1217 b++;
1218 b++;
1220 if (max_idx >= (int)cta.preparsed_svds[0].size())
1221 fail("HDMI 2D VIC indices max index %d > %u (#SVDs).\n",
1222 max_idx + 1, cta.preparsed_svds[0].size());
1225 static const char *max_frl_rates[] = {
1226 "Not Supported",
1227 "3 Gbps per lane on 3 lanes",
1228 "3 and 6 Gbps per lane on 3 lanes",
1229 "3 and 6 Gbps per lane on 3 lanes, 6 Gbps on 4 lanes",
1230 "3 and 6 Gbps per lane on 3 lanes, 6 and 8 Gbps on 4 lanes",
1231 "3 and 6 Gbps per lane on 3 lanes, 6, 8 and 10 Gbps on 4 lanes",
1232 "3 and 6 Gbps per lane on 3 lanes, 6, 8, 10 and 12 Gbps on 4 lanes",
1235 static const char *dsc_max_slices[] = {
1236 "Not Supported",
1237 "up to 1 slice and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1238 "up to 2 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1239 "up to 4 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1240 "up to 8 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1241 "up to 8 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1242 "up to 12 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1243 "up to 12 slices and up to (600 MHz/Ksliceadjust) pixel clock per slice",
1246 static void cta_hf_eeodb(const unsigned char *x, unsigned length)
1248 printf(" EDID Extension Block Count: %u\n", x[0]);
1249 if (length != 1)
1250 fail("Block is too long.\n");
1251 if (x[0] <= 1)
1252 fail("Extension Block Count == %u.\n", x[0]);
1255 void edid_state::cta_hf_scdb(const unsigned char *x, unsigned length)
1257 unsigned rate = x[1] * 5;
1258 unsigned v;
1260 printf(" Version: %u\n", x[0]);
1261 if (rate) {
1262 printf(" Maximum TMDS Character Rate: %u MHz\n", rate);
1263 if (rate <= 340 || rate > 600)
1264 fail("Max TMDS rate is > 0 and <= 340 or > 600.\n");
1265 if (rate < cta.hdmi_max_rate)
1266 fail("HDMI Forum VSDB rate < HDMI VSDB rate.\n");
1267 else
1268 cta.hdmi_max_rate = rate;
1270 if (x[2] & 0x80)
1271 printf(" SCDC Present\n");
1272 if (x[2] & 0x40)
1273 printf(" SCDC Read Request Capable\n");
1274 if (x[2] & 0x20)
1275 printf(" Supports Cable Status\n");
1276 if (x[2] & 0x10)
1277 printf(" Supports Color Content Bits Per Component Indication\n");
1278 if (x[2] & 0x08)
1279 printf(" Supports scrambling for <= 340 Mcsc\n");
1280 if (x[2] & 0x04)
1281 printf(" Supports 3D Independent View signaling\n");
1282 if (x[2] & 0x02)
1283 printf(" Supports 3D Dual View signaling\n");
1284 if (x[2] & 0x01)
1285 printf(" Supports 3D OSD Disparity signaling\n");
1286 if (x[3] & 0xf0) {
1287 unsigned max_frl_rate = x[3] >> 4;
1289 printf(" Max Fixed Rate Link: ");
1290 if (max_frl_rate < ARRAY_SIZE(max_frl_rates)) {
1291 printf("%s\n", max_frl_rates[max_frl_rate]);
1292 } else {
1293 printf("Unknown (0x%02x)\n", max_frl_rate);
1294 fail("Unknown Max Fixed Rate Link (0x%02x).\n", max_frl_rate);
1296 if (max_frl_rate == 1 && rate < 300)
1297 fail("Max Fixed Rate Link is 1, but Max TMDS rate < 300.\n");
1298 else if (max_frl_rate >= 2 && rate < 600)
1299 fail("Max Fixed Rate Link is >= 2, but Max TMDS rate < 600.\n");
1301 // FIXME:
1302 // Currently I do not really know how to translate the
1303 // Max FRL value to an equivalent max clock frequency.
1304 // So reset this field to 0 to skip any clock rate checks.
1305 cta.hdmi_max_rate = 0;
1307 if (x[3] & 0x08)
1308 printf(" Supports UHD VIC\n");
1309 if (x[3] & 0x04)
1310 printf(" Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1311 if (x[3] & 0x02)
1312 printf(" Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1313 if (x[3] & 0x01)
1314 printf(" Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1316 if (length <= 4)
1317 return;
1319 if (x[4] & 0x80)
1320 printf(" Supports FAPA End Extended\n");
1321 if (x[4] & 0x40)
1322 printf(" Supports QMS\n");
1323 if (x[4] & 0x20)
1324 printf(" Supports Mdelta\n");
1325 if (x[4] & 0x10) {
1326 printf(" Supports media rates below VRRmin (CinemaVRR, deprecated)\n");
1327 warn("CinemaVRR is deprecated and must be cleared.\n");
1329 if (x[4] & 0x08)
1330 printf(" Supports negative Mvrr values\n");
1331 if (x[4] & 0x04)
1332 printf(" Supports Fast Vactive\n");
1333 if (x[4] & 0x02)
1334 printf(" Supports Auto Low-Latency Mode\n");
1335 if (x[4] & 0x01)
1336 printf(" Supports a FAPA in blanking after first active video line\n");
1338 if (length <= 5)
1339 return;
1341 v = x[5] & 0x3f;
1342 if (v) {
1343 printf(" VRRmin: %u Hz\n", v);
1344 if (v > 48)
1345 fail("VRRmin > 48.\n");
1347 v = (x[5] & 0xc0) << 2 | x[6];
1348 if (v) {
1349 printf(" VRRmax: %u Hz\n", v);
1350 if (!(x[5] & 0x3f))
1351 fail("VRRmin == 0, but VRRmax isn't.\n");
1352 else if (v < 100)
1353 fail("VRRmax < 100.\n");
1356 if (length <= 7)
1357 return;
1359 if (x[7] & 0x80)
1360 printf(" Supports VESA DSC 1.2a compression\n");
1361 if (x[7] & 0x40)
1362 printf(" Supports Compressed Video Transport for 4:2:0 Pixel Encoding\n");
1363 if (x[7] & 0x20)
1364 printf(" Supports QMS TFRmax\n");
1365 if (x[7] & 0x10)
1366 printf(" Supports QMS TFRmin\n");
1367 if (x[7] & 0x08)
1368 printf(" Supports Compressed Video Transport at any valid 1/16th bit bpp\n");
1369 if (x[7] & 0x04)
1370 printf(" Supports 16 bpc Compressed Video Transport\n");
1371 if (x[7] & 0x02)
1372 printf(" Supports 12 bpc Compressed Video Transport\n");
1373 if (x[7] & 0x01)
1374 printf(" Supports 10 bpc Compressed Video Transport\n");
1375 if (x[8] & 0xf) {
1376 unsigned max_slices = x[8] & 0xf;
1378 printf(" DSC Max Slices: ");
1379 if (max_slices < ARRAY_SIZE(dsc_max_slices)) {
1380 printf("%s\n", dsc_max_slices[max_slices]);
1381 } else {
1382 printf("Unknown (%u), interpreted as: %s\n", max_slices,
1383 dsc_max_slices[7]);
1384 warn("Unknown DSC Max Slices (%u).\n", max_slices);
1387 if (x[8] & 0xf0) {
1388 unsigned max_frl_rate = x[8] >> 4;
1390 printf(" DSC Max Fixed Rate Link: ");
1391 if (max_frl_rate < ARRAY_SIZE(max_frl_rates)) {
1392 printf("%s\n", max_frl_rates[max_frl_rate]);
1393 } else {
1394 printf("Unknown (0x%02x)\n", max_frl_rate);
1395 fail("Unknown DSC Max Fixed Rate Link (0x%02x).\n", max_frl_rate);
1398 if (x[9] & 0x3f)
1399 printf(" Maximum number of bytes in a line of chunks: %u\n",
1400 1024 * (1 + (x[9] & 0x3f)));
1403 // Convert a PQ value (0-1) to cd/m^2 aka nits (0-10000)
1404 static double pq2nits(double pq)
1406 const double m1 = 2610.0 / 16384.0;
1407 const double m2 = 128.0 * (2523.0 / 4096.0);
1408 const double c1 = 3424.0 / 4096.0;
1409 const double c2 = 32.0 * (2413.0 / 4096.0);
1410 const double c3 = 32.0 * (2392.0 / 4096.0);
1411 double e = pow(pq, 1.0 / m2);
1412 double v = e - c1;
1414 if (v < 0)
1415 v = 0;
1416 v /= c2 - c3 * e;
1417 v = pow(v, 1.0 / m1);
1418 return v * 10000.0;
1421 static double chrom2d(const unsigned char *x)
1423 unsigned v = x[0] + (x[1] << 8);
1425 return v * 0.00002;
1428 static double perc2d(unsigned char x)
1430 double m = x >> 2;
1431 double e = x & 3;
1433 return 100.0 * (m / 64.0) * pow(10, -e);
1436 static void cta_hf_sbtmdb(const unsigned char *x, unsigned length)
1438 int len = length;
1440 if (!length)
1441 fail("Block is too short.\n");
1442 printf(" Version: %d\n", x[0] & 0xf);
1443 switch ((x[0] >> 5) & 3) {
1444 case 0:
1445 printf(" Does not support a General RDM format\n");
1446 break;
1447 case 1:
1448 printf(" Supports an SDR-range General RDM format\n");
1449 break;
1450 case 2:
1451 printf(" Supports an HDR-range General RDM format\n");
1452 break;
1453 default:
1454 fail("Invalid GRDM Support value.\n");
1455 break;
1457 if (!(x[0] & 0x80))
1458 return;
1460 bool uses_hgig_drdm = true;
1462 printf(" Supports a D-RDM format\n");
1463 if (x[1] & 0x10)
1464 printf(" Use HGIG D-RDM\n");
1465 switch (x[1] & 7) {
1466 case 0:
1467 printf(" HGIG D-RDM is not used\n");
1468 uses_hgig_drdm = false;
1469 break;
1470 case 1:
1471 printf(" PBnits[0] = 600 cd/m^2\n");
1472 break;
1473 case 2:
1474 printf(" PBnits[0] = 1000 cd/m^2\n");
1475 break;
1476 case 3:
1477 printf(" PBnits[0] = 4000 cd/m^2\n");
1478 break;
1479 case 4:
1480 printf(" PBnits[0] = 10000 cd/m^2\n");
1481 break;
1482 default:
1483 fail("Invalid HGIG D-DRM value.\n");
1484 break;
1487 bool has_chromaticities = false;
1489 if (x[1] & 0x20)
1490 printf(" MaxRGB\n");
1491 switch (x[1] >> 6) {
1492 case 0:
1493 printf(" Gamut is explicit\n");
1494 has_chromaticities = true;
1495 break;
1496 case 1:
1497 printf(" Gamut is Rec. ITU-R BT.709\n");
1498 break;
1499 case 2:
1500 printf(" Gamut is SMPTE ST 2113\n");
1501 break;
1502 default:
1503 printf(" Gamut is Rec. ITU-R BT.2020\n");
1504 break;
1506 x += 2;
1507 len -= 2;
1508 if (has_chromaticities) {
1509 printf(" Red: (%.5f, %.5f)\n", chrom2d(x), chrom2d(x + 2));
1510 printf(" Green: (%.5f, %.5f)\n", chrom2d(x + 4), chrom2d(x + 6));
1511 printf(" Blue: (%.5f, %.5f)\n", chrom2d(x + 8), chrom2d(x + 10));
1512 printf(" White: (%.5f, %.5f)\n", chrom2d(x + 12), chrom2d(x + 14));
1513 x += 16;
1514 len -= 16;
1516 if (uses_hgig_drdm)
1517 return;
1518 printf(" Min Brightness 10: %.8f cd/m^2\n", pq2nits((x[0] << 1) / 4095.0));
1519 printf(" Peak Brightness 100: %u cd/m^2\n", (unsigned)pq2nits((x[1] << 4) / 4095.0));
1520 x += 2;
1521 len -= 2;
1522 if (len <= 0)
1523 return;
1524 printf(" Percentage of Peak Brightness P0: %.2f%%\n", perc2d(x[0]));
1525 printf(" Peak Brightness P0: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1526 x += 2;
1527 len -= 2;
1528 if (len <= 0)
1529 return;
1530 printf(" Percentage of Peak Brightness P1: %.2f%%\n", perc2d(x[0]));
1531 printf(" Peak Brightness P1: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1532 x += 2;
1533 len -= 2;
1534 if (len <= 0)
1535 return;
1536 printf(" Percentage of Peak Brightness P2: %.2f%%\n", perc2d(x[0]));
1537 printf(" Peak Brightness P2: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1538 x += 2;
1539 len -= 2;
1540 if (len <= 0)
1541 return;
1542 printf(" Percentage of Peak Brightness P3: %.2f%%\n", perc2d(x[0]));
1543 printf(" Peak Brightness P3: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1546 static void cta_amd(const unsigned char *x, unsigned length)
1548 // These Freesync values are reversed engineered by looking
1549 // at existing EDIDs.
1550 printf(" Version: %u.%u\n", x[0], x[1]);
1551 printf(" Minimum Refresh Rate: %u Hz\n", x[2]);
1552 printf(" Maximum Refresh Rate: %u Hz\n", x[3]);
1553 // Freesync 1.x flags
1554 // One or more of the 0xe6 bits signal that the VESA MCCS
1555 // protocol is used to switch the Freesync range
1556 printf(" Flags 1.x: 0x%02x%s\n", x[4],
1557 (x[4] & 0xe6) ? " (MCCS)" : "");
1558 if (length >= 10) {
1559 // Freesync 2.x flags
1560 // Bit 2 no doubt indicates if the monitor supports Local Dimming
1561 // There are probably also bits to signal support of the
1562 // FreeSync2_scRGB and FreeSync2_Gamma22 HDR display modes.
1563 // I suspect bits 0 and 1.
1564 printf(" Flags 2.x: 0x%02x\n", x[5]);
1565 // The AMD tone mapping tutorial referred to in the URL below
1566 // mentions that the Freesync HDR info reports max/min
1567 // luminance of the monitor with and without local dimming.
1569 // https://gpuopen.com/learn/using-amd-freesync-premium-pro-hdr-code-samples/
1571 // So I assume that the first two luminance values are
1572 // the max/min luminance of the display and the next two
1573 // luminance values are the max/min luminance values when
1574 // local dimming is disabled. The values I get seem to
1575 // support that.
1576 printf(" Maximum luminance: %u (%.3f cd/m^2)\n",
1577 x[6], 50.0 * pow(2, x[6] / 32.0));
1578 printf(" Minimum luminance: %u (%.3f cd/m^2)\n",
1579 x[7], (50.0 * pow(2, x[6] / 32.0)) * pow(x[7] / 255.0, 2) / 100.0);
1580 if (x[5] & 4) {
1581 // One or both bytes can be 0. The meaning of that
1582 // is unknown.
1583 printf(" Maximum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1584 x[8], 50.0 * pow(2, x[8] / 32.0));
1585 printf(" Minimum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1586 x[9], (50.0 * pow(2, x[8] / 32.0)) * pow(x[9] / 255.0, 2) / 100.0);
1587 } else {
1588 // These bytes are always 0x08 0x2f. If these values
1589 // represent max/min luminance as well, then these
1590 // would map to 59.460 and 0.020 cd/m^2 respectively.
1591 // I wonder if this somehow relates to SDR.
1592 printf(" Unknown: 0x%02x 0x%02x\n", x[8], x[9]);
1597 static std::string display_use_case(unsigned char x)
1599 switch (x) {
1600 case 1: return "Test equipment";
1601 case 2: return "Generic display";
1602 case 3: return "Television display";
1603 case 4: return "Desktop productivity display";
1604 case 5: return "Desktop gaming display";
1605 case 6: return "Presentation display";
1606 case 7: return "Virtual reality headset";
1607 case 8: return "Augmented reality";
1608 case 16: return "Video wall display";
1609 case 17: return "Medical imaging display";
1610 case 18: return "Dedicated gaming display";
1611 case 19: return "Dedicated video monitor display";
1612 case 20: return "Accessory display";
1613 default: break;
1615 fail("Unknown Display product primary use case 0x%02x.\n", x);
1616 return std::string("Unknown display use case (") + utohex(x) + ")";
1619 static void cta_microsoft(const unsigned char *x, unsigned length)
1621 // This VSDB is documented at:
1622 // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
1623 printf(" Version: %u\n", x[0]);
1624 if (x[0] > 2) {
1625 // In version 1 and 2 these bits should always be set to 0.
1626 printf(" Desktop Usage: %u\n", (x[1] >> 6) & 1);
1627 printf(" Third-Party Usage: %u\n", (x[1] >> 5) & 1);
1629 printf(" Display Product Primary Use Case: %u (%s)\n", x[1] & 0x1f,
1630 display_use_case(x[1] & 0x1f).c_str());
1631 printf(" Container ID: %s\n", containerid2s(x + 2).c_str());
1634 static void cta_hdr10plus(const unsigned char *x, unsigned length)
1636 if (length == 0) {
1637 fail("Empty Data Block with length %u.\n", length);
1638 return;
1640 printf(" Application Version: %u\n", x[0] & 3);
1641 printf(" Full Frame Peak Luminance Index: %u\n", (x[0] >> 2) & 3);
1642 printf(" Peak Luminance Index: %u\n", x[0] >> 4);
1643 hex_block(" ", x + 1, length - 1);
1646 static void cta_dolby_video(const unsigned char *x, unsigned length)
1648 unsigned char version = (x[0] >> 5) & 0x07;
1650 printf(" Version: %u (%u bytes)\n", version, length + 5);
1651 if (x[0] & 0x01)
1652 printf(" Supports YUV422 12 bit\n");
1654 if (version == 0) {
1655 if (x[0] & 0x02)
1656 printf(" Supports 2160p60\n");
1657 if (x[0] & 0x04)
1658 printf(" Supports global dimming\n");
1659 unsigned char dm_version = x[16];
1660 printf(" DM Version: %u.%u\n", dm_version >> 4, dm_version & 0xf);
1661 unsigned pq = (x[14] << 4) | (x[13] >> 4);
1662 printf(" Target Min PQ: %u (%.8f cd/m^2)\n", pq, pq2nits(pq / 4095.0));
1663 pq = (x[15] << 4) | (x[13] & 0xf);
1664 printf(" Target Max PQ: %u (%u cd/m^2)\n", pq, (unsigned)pq2nits(pq / 4095.0));
1665 printf(" Rx, Ry: %.8f, %.8f\n",
1666 ((x[1] >> 4) | (x[2] << 4)) / 4096.0,
1667 ((x[1] & 0xf) | (x[3] << 4)) / 4096.0);
1668 printf(" Gx, Gy: %.8f, %.8f\n",
1669 ((x[4] >> 4) | (x[5] << 4)) / 4096.0,
1670 ((x[4] & 0xf) | (x[6] << 4)) / 4096.0);
1671 printf(" Bx, By: %.8f, %.8f\n",
1672 ((x[7] >> 4) | (x[8] << 4)) / 4096.0,
1673 ((x[7] & 0xf) | (x[9] << 4)) / 4096.0);
1674 printf(" Wx, Wy: %.8f, %.8f\n",
1675 ((x[10] >> 4) | (x[11] << 4)) / 4096.0,
1676 ((x[10] & 0xf) | (x[12] << 4)) / 4096.0);
1677 return;
1680 if (version == 1) {
1681 if (x[0] & 0x02)
1682 printf(" Supports 2160p60\n");
1683 if (x[1] & 0x01)
1684 printf(" Supports global dimming\n");
1685 unsigned char dm_version = (x[0] >> 2) & 0x07;
1686 printf(" DM Version: %u.x\n", dm_version + 2);
1687 printf(" Colorimetry: %s\n", (x[2] & 0x01) ? "P3-D65" : "ITU-R BT.709");
1688 printf(" Low Latency: %s\n", (x[3] & 0x01) ? "Standard + Low Latency" : "Only Standard");
1689 double lm = (x[2] >> 1) / 127.0;
1690 printf(" Target Min Luminance: %.8f cd/m^2\n", lm * lm);
1691 printf(" Target Max Luminance: %u cd/m^2\n", 100 + (x[1] >> 1) * 50);
1692 if (length == 10) {
1693 printf(" Rx, Ry: %.8f, %.8f\n", x[4] / 256.0, x[5] / 256.0);
1694 printf(" Gx, Gy: %.8f, %.8f\n", x[6] / 256.0, x[7] / 256.0);
1695 printf(" Bx, By: %.8f, %.8f\n", x[8] / 256.0, x[9] / 256.0);
1696 } else {
1697 double xmin = 0.625;
1698 double xstep = (0.74609375 - xmin) / 31.0;
1699 double ymin = 0.25;
1700 double ystep = (0.37109375 - ymin) / 31.0;
1702 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1703 xmin + xstep * (x[6] >> 3),
1704 ymin + ystep * (((x[6] & 0x7) << 2) | (x[4] & 0x01) | ((x[5] & 0x01) << 1)));
1705 xstep = 0.49609375 / 127.0;
1706 ymin = 0.5;
1707 ystep = (0.99609375 - ymin) / 127.0;
1708 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1709 xstep * (x[4] >> 1), ymin + ystep * (x[5] >> 1));
1710 xmin = 0.125;
1711 xstep = (0.15234375 - xmin) / 7.0;
1712 ymin = 0.03125;
1713 ystep = (0.05859375 - ymin) / 7.0;
1714 printf(" Unique Bx, By: %.8f, %.8f\n",
1715 xmin + xstep * (x[3] >> 5),
1716 ymin + ystep * ((x[3] >> 2) & 0x07));
1718 return;
1721 if (version == 2) {
1722 if (x[0] & 0x02)
1723 printf(" Supports Backlight Control\n");
1724 if (x[1] & 0x04)
1725 printf(" Supports global dimming\n");
1726 unsigned char dm_version = (x[0] >> 2) & 0x07;
1727 printf(" DM Version: %u.x\n", dm_version + 2);
1728 printf(" Backlt Min Luma: %u cd/m^2\n", 25 + (x[1] & 0x03) * 25);
1729 printf(" Interface: ");
1730 switch (x[2] & 0x03) {
1731 case 0: printf("Low-Latency\n"); break;
1732 case 1: printf("Low-Latency + Low-Latency-HDMI\n"); break;
1733 case 2: printf("Standard + Low-Latency\n"); break;
1734 case 3: printf("Standard + Low-Latency + Low-Latency-HDMI\n"); break;
1736 printf(" Supports 10b 12b 444: ");
1737 switch ((x[3] & 0x01) << 1 | (x[4] & 0x01)) {
1738 case 0: printf("Not supported\n"); break;
1739 case 1: printf("10 bit\n"); break;
1740 case 2: printf("12 bit\n"); break;
1741 case 3: printf("Reserved\n"); break;
1744 unsigned pq = 20 * (x[1] >> 3);
1745 printf(" Target Min PQ v2: %u (%.8f cd/m^2)\n", pq, pq2nits(pq / 4095.0));
1746 pq = 2055 + 65 * (x[2] >> 3);
1747 printf(" Target Max PQ v2: %u (%u cd/m^2)\n", pq, (unsigned)pq2nits(pq / 4095.0));
1749 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1750 0.625 + (x[5] >> 3) / 256.0,
1751 0.25 + (x[6] >> 3) / 256.0);
1752 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1753 (x[3] >> 1) / 256.0,
1754 0.5 + (x[4] >> 1) / 256.0);
1755 printf(" Unique Bx, By: %.8f, %.8f\n",
1756 0.125 + (x[5] & 0x07) / 256.0,
1757 0.03125 + (x[6] & 0x07) / 256.0);
1761 static void cta_dolby_audio(const unsigned char *x, unsigned length)
1763 unsigned char version = 1 + (x[0] & 0x07);
1765 printf(" Version: %u (%u bytes)\n", version, length + 5);
1766 if (x[0] & 0x80)
1767 printf(" Headphone playback only\n");
1768 if (x[0] & 0x40)
1769 printf(" Height speaker zone present\n");
1770 if (x[0] & 0x20)
1771 printf(" Surround speaker zone present\n");
1772 if (x[0] & 0x10)
1773 printf(" Center speaker zone present\n");
1774 if (x[1] & 0x01)
1775 printf(" Supports Dolby MAT PCM decoding at 48 kHz only, does not support TrueHD\n");
1778 static void cta_uhda_fmm(const unsigned char *x, unsigned length)
1780 printf(" Filmmaker Mode Content Type: %u\n", x[0]);
1781 printf(" Filmmaker Mode Content Subtype: %u\n", x[1]);
1784 static const char *speaker_map[] = {
1785 "FL/FR - Front Left/Right",
1786 "LFE1 - Low Frequency Effects 1",
1787 "FC - Front Center",
1788 "BL/BR - Back Left/Right",
1789 "BC - Back Center",
1790 "FLc/FRc - Front Left/Right of Center",
1791 "RLC/RRC - Rear Left/Right of Center (Deprecated)",
1792 "FLw/FRw - Front Left/Right Wide",
1793 "TpFL/TpFR - Top Front Left/Right",
1794 "TpC - Top Center",
1795 "TpFC - Top Front Center",
1796 "LS/RS - Left/Right Surround",
1797 "LFE2 - Low Frequency Effects 2",
1798 "TpBC - Top Back Center",
1799 "SiL/SiR - Side Left/Right",
1800 "TpSiL/TpSiR - Top Side Left/Right",
1801 "TpBL/TpBR - Top Back Left/Right",
1802 "BtFC - Bottom Front Center",
1803 "BtFL/BtFR - Bottom Front Left/Right",
1804 "TpLS/TpRS - Top Left/Right Surround (Deprecated for CTA-861)",
1805 "LSd/RSd - Left/Right Surround Direct (HDMI only)",
1808 static void cta_sadb(const unsigned char *x, unsigned length)
1810 unsigned sad;
1811 unsigned i;
1813 if (length < 3) {
1814 fail("Empty Data Block with length %u.\n", length);
1815 return;
1818 sad = ((x[2] << 16) | (x[1] << 8) | x[0]);
1820 for (i = 0; i < ARRAY_SIZE(speaker_map); i++) {
1821 if ((sad >> i) & 1)
1822 printf(" %s\n", speaker_map[i]);
1826 static void cta_vesa_dtcdb(const unsigned char *x, unsigned length)
1828 if (length != 7 && length != 15 && length != 31) {
1829 fail("Invalid length %u.\n", length);
1830 return;
1833 switch (x[0] >> 6) {
1834 case 0: printf(" White"); break;
1835 case 1: printf(" Red"); break;
1836 case 2: printf(" Green"); break;
1837 case 3: printf(" Blue"); break;
1839 unsigned v = x[0] & 0x3f;
1840 printf(" transfer characteristics: %u", v);
1841 for (unsigned i = 1; i < length; i++)
1842 printf(" %u", v += x[i]);
1843 printf(" 1023\n");
1846 static void cta_vesa_vdddb(const unsigned char *x, unsigned length)
1848 if (length != 30) {
1849 fail("Invalid length %u.\n", length);
1850 return;
1853 printf(" Interface Type: ");
1854 unsigned char v = x[0];
1855 switch (v >> 4) {
1856 case 0: printf("Analog (");
1857 switch (v & 0xf) {
1858 case 0: printf("15HD/VGA"); break;
1859 case 1: printf("VESA NAVI-V (15HD)"); break;
1860 case 2: printf("VESA NAVI-D"); break;
1861 default: printf("Reserved"); break;
1863 printf(")\n");
1864 break;
1865 case 1: printf("LVDS %u lanes", v & 0xf); break;
1866 case 2: printf("RSDS %u lanes", v & 0xf); break;
1867 case 3: printf("DVI-D %u channels", v & 0xf); break;
1868 case 4: printf("DVI-I analog"); break;
1869 case 5: printf("DVI-I digital %u channels", v & 0xf); break;
1870 case 6: printf("HDMI-A"); break;
1871 case 7: printf("HDMI-B"); break;
1872 case 8: printf("MDDI %u channels", v & 0xf); break;
1873 case 9: printf("DisplayPort %u channels", v & 0xf); break;
1874 case 10: printf("IEEE-1394"); break;
1875 case 11: printf("M1 analog"); break;
1876 case 12: printf("M1 digital %u channels", v & 0xf); break;
1877 default: printf("Reserved"); break;
1879 printf("\n");
1881 printf(" Interface Standard Version: %u.%u\n", x[1] >> 4, x[1] & 0xf);
1882 printf(" Content Protection Support: ");
1883 switch (x[2]) {
1884 case 0: printf("None\n"); break;
1885 case 1: printf("HDCP\n"); break;
1886 case 2: printf("DTCP\n"); break;
1887 case 3: printf("DPCP\n"); break;
1888 default: printf("Reserved\n"); break;
1891 printf(" Minimum Clock Frequency: %u MHz\n", x[3] >> 2);
1892 printf(" Maximum Clock Frequency: %u MHz\n", ((x[3] & 0x03) << 8) | x[4]);
1893 printf(" Device Native Pixel Format: %ux%u\n",
1894 x[5] | (x[6] << 8), x[7] | (x[8] << 8));
1895 printf(" Aspect Ratio: %.2f\n", (100 + x[9]) / 100.0);
1896 v = x[0x0a];
1897 printf(" Default Orientation: ");
1898 switch ((v & 0xc0) >> 6) {
1899 case 0x00: printf("Landscape\n"); break;
1900 case 0x01: printf("Portrait\n"); break;
1901 case 0x02: printf("Not Fixed\n"); break;
1902 case 0x03: printf("Undefined\n"); break;
1904 printf(" Rotation Capability: ");
1905 switch ((v & 0x30) >> 4) {
1906 case 0x00: printf("None\n"); break;
1907 case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
1908 case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
1909 case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
1911 printf(" Zero Pixel Location: ");
1912 switch ((v & 0x0c) >> 2) {
1913 case 0x00: printf("Upper Left\n"); break;
1914 case 0x01: printf("Upper Right\n"); break;
1915 case 0x02: printf("Lower Left\n"); break;
1916 case 0x03: printf("Lower Right\n"); break;
1918 printf(" Scan Direction: ");
1919 switch (v & 0x03) {
1920 case 0x00: printf("Not defined\n"); break;
1921 case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
1922 case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
1923 case 0x03: printf("Reserved\n");
1924 fail("Scan Direction used the reserved value 0x03.\n");
1925 break;
1927 printf(" Subpixel Information: ");
1928 switch (x[0x0b]) {
1929 case 0x00: printf("Not defined\n"); break;
1930 case 0x01: printf("RGB vertical stripes\n"); break;
1931 case 0x02: printf("RGB horizontal stripes\n"); break;
1932 case 0x03: printf("Vertical stripes using primary order\n"); break;
1933 case 0x04: printf("Horizontal stripes using primary order\n"); break;
1934 case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
1935 case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
1936 case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
1937 case 0x08: printf("Mosaic\n"); break;
1938 case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
1939 case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
1940 case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
1941 case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
1942 default: printf("Reserved\n"); break;
1944 printf(" Horizontal and vertical dot/pixel pitch: %.2f x %.2f mm\n",
1945 (double)(x[0x0c]) / 100.0, (double)(x[0x0d]) / 100.0);
1946 v = x[0x0e];
1947 printf(" Dithering: ");
1948 switch (v >> 6) {
1949 case 0: printf("None\n"); break;
1950 case 1: printf("Spatial\n"); break;
1951 case 2: printf("Temporal\n"); break;
1952 case 3: printf("Spatial and Temporal\n"); break;
1954 printf(" Direct Drive: %s\n", (v & 0x20) ? "Yes" : "No");
1955 printf(" Overdrive %srecommended\n", (v & 0x10) ? "not " : "");
1956 printf(" Deinterlacing: %s\n", (v & 0x08) ? "Yes" : "No");
1958 v = x[0x0f];
1959 printf(" Audio Support: %s\n", (v & 0x80) ? "Yes" : "No");
1960 printf(" Separate Audio Inputs Provided: %s\n", (v & 0x40) ? "Yes" : "No");
1961 printf(" Audio Input Override: %s\n", (v & 0x20) ? "Yes" : "No");
1962 v = x[0x10];
1963 if (v)
1964 printf(" Audio Delay: %s%u ms\n", (v & 0x80) ? "" : "-", (v & 0x7f) * 2);
1965 else
1966 printf(" Audio Delay: no information provided\n");
1967 v = x[0x11];
1968 printf(" Frame Rate/Mode Conversion: ");
1969 switch (v >> 6) {
1970 case 0: printf("None\n"); break;
1971 case 1: printf("Single Buffering\n"); break;
1972 case 2: printf("Double Buffering\n"); break;
1973 case 3: printf("Advanced Frame Rate Conversion\n"); break;
1975 if (v & 0x3f)
1976 printf(" Frame Rate Range: %u fps +/- %u fps\n",
1977 x[0x12], v & 0x3f);
1978 else
1979 printf(" Nominal Frame Rate: %u fps\n", x[0x12]);
1980 printf(" Color Bit Depth: %u @ interface, %u @ display\n",
1981 (x[0x13] >> 4) + 1, (x[0x13] & 0xf) + 1);
1982 v = x[0x15] & 3;
1983 if (v) {
1984 printf(" Additional Primary Chromaticities:\n");
1985 unsigned col_x = (x[0x16] << 2) | (x[0x14] >> 6);
1986 unsigned col_y = (x[0x17] << 2) | ((x[0x14] >> 4) & 3);
1987 printf(" Primary 4: 0.%04u, 0.%04u\n",
1988 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1989 if (v > 1) {
1990 col_x = (x[0x18] << 2) | ((x[0x14] >> 2) & 3);
1991 col_y = (x[0x19] << 2) | (x[0x14] & 3);
1992 printf(" Primary 5: 0.%04u, 0.%04u\n",
1993 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1994 if (v > 2) {
1995 col_x = (x[0x1a] << 2) | (x[0x15] >> 6);
1996 col_y = (x[0x1b] << 2) | ((x[0x15] >> 4) & 3);
1997 printf(" Primary 6: 0.%04u, 0.%04u\n",
1998 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
2003 v = x[0x1c];
2004 printf(" Response Time %s: %u ms\n",
2005 (v & 0x80) ? "White -> Black" : "Black -> White", v & 0x7f);
2006 v = x[0x1d];
2007 printf(" Overscan: %u%% x %u%%\n", v >> 4, v & 0xf);
2010 static double decode_uchar_as_double(unsigned char x)
2012 signed char s = (signed char)x;
2014 return s / 64.0;
2017 void edid_state::cta_rcdb(const unsigned char *x, unsigned length)
2019 unsigned spm = ((x[3] << 16) | (x[2] << 8) | x[1]);
2020 unsigned i;
2022 if (length < 4) {
2023 fail("Empty Data Block with length %u.\n", length);
2024 return;
2027 if ((x[0] & 0x20) && !cta.has_sldb)
2028 fail("'SLD' flag is 1, but no Speaker Location Data Block is found.\n");
2029 else if (!(x[0] & 0x20) && cta.has_sldb)
2030 fail("'SLD' flag is 0, but a Speaker Location Data Block is present.\n");
2032 if (x[0] & 0x40) {
2033 printf(" Speaker count: %u\n", (x[0] & 0x1f) + 1);
2034 } else {
2035 if (x[0] & 0x1f)
2036 fail("'Speaker' flag is 0, but 'Speaker Count' is != 0.\n");
2037 if (x[0] & 0x20)
2038 fail("'SLD' flag is 1, but 'Speaker' is 0.\n");
2041 printf(" Speaker Presence Mask:\n");
2042 for (i = 0; i < ARRAY_SIZE(speaker_map); i++) {
2043 if ((spm >> i) & 1)
2044 printf(" %s\n", speaker_map[i]);
2047 if ((x[0] & 0xa0) == 0x80)
2048 fail("'Display' flag set, but not the 'SLD' flag.\n");
2050 bool valid_max = cta.preparsed_sld_has_coord || (x[0] & 0x80);
2052 if (valid_max && length >= 7) {
2053 printf(" Xmax: %u dm\n", x[4]);
2054 printf(" Ymax: %u dm\n", x[5]);
2055 printf(" Zmax: %u dm\n", x[6]);
2056 } else if (!valid_max && length >= 7) {
2057 // The RCDB should have been truncated.
2058 warn("'Display' flag is 0 and 'Coord' is 0 for all SLDs, but the Max coordinates are still present.\n");
2060 if ((x[0] & 0x80) && length >= 10) {
2061 printf(" DisplayX: %.3f * Xmax\n", decode_uchar_as_double(x[7]));
2062 printf(" DisplayY: %.3f * Ymax\n", decode_uchar_as_double(x[8]));
2063 printf(" DisplayZ: %.3f * Zmax\n", decode_uchar_as_double(x[9]));
2064 } else if (!(x[0] & 0x80) && length >= 10) {
2065 // The RCDB should have been truncated.
2066 warn("'Display' flag is 0, but the Display coordinates are still present.\n");
2070 static const struct {
2071 const char *name;
2072 double x, y, z;
2073 } speaker_location[] = {
2074 { "FL - Front Left", -1, 1, 0 },
2075 { "FR - Front Right", 1, 1, 0 },
2076 { "FC - Front Center", 0, 1, 0 },
2077 { "LFE1 - Low Frequency Effects 1", -0.5, 1, -1 },
2078 { "BL - Back Left", -1, -1, 0 },
2079 { "BR - Back Right", 1, -1, 0 },
2080 { "FLC - Front Left of Center", -0.5, 1, 0 },
2081 { "FRC - Front Right of Center", 0.5, 1, 0 },
2082 { "BC - Back Center", 0, -1, 0 },
2083 { "LFE2 - Low Frequency Effects 2", 0.5, 1, -1 },
2084 { "SiL - Side Left", -1, 1.0/3.0, 0 },
2085 { "SiR - Side Right", 1, 1.0/3.0, 0 },
2086 { "TpFL - Top Front Left", -1, 1, 1 },
2087 { "TpFR - Top Front Right", 1, 1, 1 },
2088 { "TpFC - Top Front Center", 0, 1, 1 },
2089 { "TpC - Top Center", 0, 0, 1 },
2090 { "TpBL - Top Back Left", -1, -1, 1 },
2091 { "TpBR - Top Back Right", 1, -1, 1 },
2092 { "TpSiL - Top Side Left", -1, 0, 1 },
2093 { "TpSiR - Top Side Right", 1, 0, 1 },
2094 { "TpBC - Top Back Center", 0, -1, 1 },
2095 { "BtFC - Bottom Front Center", 0, 1, -1 },
2096 { "BtFL - Bottom Front Left", -1, 1, -1 },
2097 { "BtFR - Bottom Front Right", 1, 1, -1 },
2098 { "FLW - Front Left Wide", -1, 2.0/3.0, 0 },
2099 { "FRW - Front Right Wide", 1, 2.0/3.0, 0 },
2100 { "LS - Left Surround", -1, 0, 0 },
2101 { "RS - Right Surround", 1, 0, 0 },
2104 void edid_state::cta_sldb(const unsigned char *x, unsigned length)
2106 if (length < 2) {
2107 fail("Empty Data Block with length %u.\n", length);
2108 return;
2111 unsigned active_cnt = 0;
2112 unsigned channel_is_active = 0;
2114 while (length >= 2) {
2115 printf(" Channel: %u (%sactive)\n", x[0] & 0x1f,
2116 (x[0] & 0x20) ? "" : "not ");
2117 if (x[0] & 0x20) {
2118 if (channel_is_active & (1U << (x[0] & 0x1f)))
2119 fail("Channel Index %u was already marked 'Active'.\n",
2120 x[0] & 0x1f);
2121 channel_is_active |= 1U << (x[0] & 0x1f);
2122 active_cnt++;
2125 unsigned speaker_id = x[1] & 0x1f;
2127 if (speaker_id < ARRAY_SIZE(speaker_location)) {
2128 printf(" Speaker ID: %s\n", speaker_location[speaker_id].name);
2129 } else if (speaker_id == 0x1f) {
2130 printf(" Speaker ID: None Specified\n");
2131 } else {
2132 printf(" Speaker ID: Reserved (%u)\n", speaker_id);
2133 fail("Reserved Speaker ID specified.\n");
2135 if (length >= 5 && (x[0] & 0x40)) {
2136 printf(" X: %.3f * Xmax\n", decode_uchar_as_double(x[2]));
2137 printf(" Y: %.3f * Ymax\n", decode_uchar_as_double(x[3]));
2138 printf(" Z: %.3f * Zmax\n", decode_uchar_as_double(x[4]));
2139 length -= 3;
2140 x += 3;
2141 } else if (speaker_id < ARRAY_SIZE(speaker_location)) {
2142 printf(" X: %.3f * Xmax (approximately)\n", speaker_location[speaker_id].x);
2143 printf(" Y: %.3f * Ymax (approximately)\n", speaker_location[speaker_id].y);
2144 printf(" Z: %.3f * Zmax (approximately)\n", speaker_location[speaker_id].z);
2147 length -= 2;
2148 x += 2;
2150 if (active_cnt != cta.preparsed_speaker_count)
2151 fail("There are %u active speakers, but 'Speaker Count' is %u.\n",
2152 active_cnt, cta.preparsed_speaker_count);
2155 void edid_state::cta_preparse_sldb(const unsigned char *x, unsigned length)
2157 cta.has_sldb = true;
2158 while (length >= 2) {
2159 if (length >= 5 && (x[0] & 0x40)) {
2160 cta.preparsed_sld_has_coord = true;
2161 return;
2163 length -= 2;
2164 x += 2;
2168 void edid_state::cta_vcdb(const unsigned char *x, unsigned length)
2170 unsigned char d = x[0];
2172 cta.has_vcdb = true;
2173 if (length < 1) {
2174 fail("Empty Data Block with length %u.\n", length);
2175 return;
2177 printf(" YCbCr quantization: %s\n",
2178 (d & 0x80) ? "Selectable (via AVI YQ)" : "No Data");
2179 printf(" RGB quantization: %s\n",
2180 (d & 0x40) ? "Selectable (via AVI Q)" : "No Data");
2182 * If this bit is not set then that will result in interoperability
2183 * problems (specifically with PCs/laptops) that quite often do not
2184 * follow the default rules with respect to RGB Quantization Range
2185 * handling.
2187 * Starting with the CTA-861-H spec this bit is now required to be
2188 * 1 for new designs.
2190 if (!(d & 0x40))
2191 fail("Set Selectable RGB Quantization to avoid interop issues.\n");
2193 * Since most YCbCr formats use limited range, the interop issues are
2194 * less noticable than for RGB formats.
2196 * Starting with the CTA-861-H spec this bit is now required to be
2197 * 1 for new designs, but just warn about it (for now).
2199 if ((cta.byte3 & 0x30) && !(d & 0x80))
2200 warn("Set Selectable YCbCr Quantization to avoid interop issues.\n");
2202 unsigned char s_pt = (d >> 4) & 0x03;
2203 unsigned char s_it = (d >> 2) & 0x03;
2204 unsigned char s_ce = d & 0x03;
2206 printf(" PT scan behavior: ");
2207 switch (s_pt) {
2208 case 0: printf("No Data\n"); break;
2209 case 1: printf("Always Overscanned\n"); break;
2210 case 2: printf("Always Underscanned\n"); break;
2211 case 3: printf("Supports both over- and underscan\n"); break;
2213 printf(" IT scan behavior: ");
2214 switch (s_it) {
2215 case 0: printf("IT video formats not supported\n"); break;
2216 case 1:
2217 printf("Always Overscanned\n");
2218 // See Table 52 of CTA-861-G for a description of Byte 3
2219 if (cta.byte3 & 0x80)
2220 fail("IT video formats are always overscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to underscanned.\n");
2221 break;
2222 case 2:
2223 printf("Always Underscanned\n");
2224 // See Table 52 of CTA-861-G for a description of Byte 3
2225 if (!(cta.byte3 & 0x80))
2226 fail("IT video formats are always underscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to overscanned.\n");
2227 break;
2228 case 3: printf("Supports both over- and underscan\n"); break;
2230 if (s_it < 2)
2231 warn("IT scan behavior is expected to support underscanned.\n");
2232 printf(" CE scan behavior: ");
2233 switch (s_ce) {
2234 case 0: printf("CE video formats not supported\n"); break;
2235 case 1: printf("Always Overscanned\n"); break;
2236 case 2: printf("Always Underscanned\n"); break;
2237 case 3: printf("Supports both over- and underscan\n"); break;
2239 if (s_ce == 0)
2240 warn("'CE video formats not supported' makes no sense.\n");
2241 else if (s_pt == s_it && s_pt == s_ce)
2242 warn("S_PT is equal to S_IT and S_CE, so should be set to 0 instead.\n");
2245 static const char *colorimetry1_map[] = {
2246 "xvYCC601",
2247 "xvYCC709",
2248 "sYCC601",
2249 "opYCC601",
2250 "opRGB",
2251 "BT2020cYCC",
2252 "BT2020YCC",
2253 "BT2020RGB",
2256 static const char *colorimetry2_map[] = {
2257 "Gamut Boundary Description Metadata Profile P0",
2258 "Reserved Gamut Boundary Description Metadata Profile P1",
2259 "Reserved Gamut Boundary Description Metadata Profile P2",
2260 "Reserved Gamut Boundary Description Metadata Profile P3",
2261 "Default",
2262 "sRGB",
2263 "ICtCp",
2264 "ST2113RGB",
2267 void edid_state::cta_colorimetry_block(const unsigned char *x, unsigned length)
2269 unsigned i;
2271 if (length < 2) {
2272 fail("Empty Data Block with length %u.\n", length);
2273 return;
2275 for (i = 0; i < ARRAY_SIZE(colorimetry1_map); i++)
2276 if (x[0] & (1 << i))
2277 printf(" %s\n", colorimetry1_map[i]);
2278 // Bits MD0-MD3 are used to indicate which HDMI Gamut Boundary Description
2279 // Metadata Profiles are supported.
2281 // HDMI 1.3a in section 5.3.12 describes 4 possible profiles, but it marks
2282 // P3 as 'defined in a future specification'.
2284 // HDMI 1.4b, however, only specifies profile P0 in section 8.3.3. And I've
2285 // only seen P0 in practice. My assumption is that profiles P1-P3 are never
2286 // used, and so these bits should be 0.
2287 if (x[1] & 0xe)
2288 fail("Reserved bits MD1-MD3 must be 0.\n");
2289 for (i = 0; i < ARRAY_SIZE(colorimetry2_map); i++)
2290 if (x[1] & (1 << i))
2291 printf(" %s\n", colorimetry2_map[i]);
2292 // The sRGB bit (added in CTA-861.6) allows sources to explicitly
2293 // signal sRGB colorimetry. Without this the default colorimetry
2294 // of an RGB video is either sRGB or defaultRGB. It depends on the
2295 // Source which is used, and the Sink has no idea what it is getting.
2297 // For proper compatibility with PCs enabling sRGB support is
2298 // desirable.
2299 if (!base.uses_srgb && !(x[1] & 0x20))
2300 warn("Set the sRGB colorimetry bit to avoid interop issues.\n");
2303 static const char *eotf_map[] = {
2304 "Traditional gamma - SDR luminance range",
2305 "Traditional gamma - HDR luminance range",
2306 "SMPTE ST2084",
2307 "Hybrid Log-Gamma",
2310 static void cta_hdr_static_metadata_block(const unsigned char *x, unsigned length)
2312 unsigned i;
2314 if (length < 2) {
2315 fail("Empty Data Block with length %u.\n", length);
2316 return;
2318 printf(" Electro optical transfer functions:\n");
2319 for (i = 0; i < 6; i++) {
2320 if (x[0] & (1 << i)) {
2321 if (i < ARRAY_SIZE(eotf_map)) {
2322 printf(" %s\n", eotf_map[i]);
2323 } else {
2324 printf(" Unknown (%u)\n", i);
2325 fail("Unknown EOTF (%u).\n", i);
2329 printf(" Supported static metadata descriptors:\n");
2330 for (i = 0; i < 8; i++) {
2331 if (x[1] & (1 << i))
2332 printf(" Static metadata type %u\n", i + 1);
2335 if (length >= 3)
2336 printf(" Desired content max luminance: %u (%.3f cd/m^2)\n",
2337 x[2], 50.0 * pow(2, x[2] / 32.0));
2339 if (length >= 4)
2340 printf(" Desired content max frame-average luminance: %u (%.3f cd/m^2)\n",
2341 x[3], 50.0 * pow(2, x[3] / 32.0));
2343 if (length >= 5)
2344 printf(" Desired content min luminance: %u (%.3f cd/m^2)\n",
2345 x[4], (50.0 * pow(2, x[2] / 32.0)) * pow(x[4] / 255.0, 2) / 100.0);
2348 static void cta_hdr_dyn_metadata_block(const unsigned char *x, unsigned length)
2350 if (length < 3) {
2351 fail("Empty Data Block with length %u.\n", length);
2352 return;
2354 while (length >= 3) {
2355 unsigned type_len = x[0];
2356 unsigned type = x[1] | (x[2] << 8);
2358 if (length < type_len + 1)
2359 return;
2360 printf(" HDR Dynamic Metadata Type %u\n", type);
2361 switch (type) {
2362 case 1:
2363 case 4:
2364 if (type_len > 2)
2365 printf(" Version: %u\n", x[3] & 0xf);
2366 break;
2367 case 2:
2368 if (type_len > 2) {
2369 unsigned version = x[3] & 0xf;
2370 printf(" Version: %u\n", version);
2371 if (version >= 1) {
2372 if (x[3] & 0x10) printf(" Supports SL-HDR1 (ETSI TS 103 433-1)\n");
2373 if (x[3] & 0x20) printf(" Supports SL-HDR2 (ETSI TS 103 433-2)\n");
2374 if (x[3] & 0x40) printf(" Supports SL-HDR3 (ETSI TS 103 433-3)\n");
2377 break;
2378 default:
2379 break;
2381 length -= type_len + 1;
2382 x += type_len + 1;
2386 static const char *infoframe_types[] = {
2387 NULL,
2388 "Vendor-Specific",
2389 "Auxiliary Video Information",
2390 "Source Product Description",
2391 "Audio",
2392 "MPEG Source",
2393 "NTSC VBI",
2394 "Dynamic Range and Mastering",
2397 static void cta_ifdb(const unsigned char *x, unsigned length)
2399 unsigned len_hdr = x[0] >> 5;
2401 if (length < 2) {
2402 fail("Empty Data Block with length %u.\n", length);
2403 return;
2405 printf(" VSIFs: %u\n", x[1]);
2406 if (length < len_hdr + 2)
2407 return;
2408 length -= len_hdr + 2;
2409 x += len_hdr + 2;
2410 while (length > 0) {
2411 int payload_len = x[0] >> 5;
2412 unsigned char type = x[0] & 0x1f;
2414 const char *name = NULL;
2415 if (type < ARRAY_SIZE(infoframe_types))
2416 name = infoframe_types[type];
2417 if (!name)
2418 name = "Unknown";
2419 printf(" %s InfoFrame (%u)", name, type);
2421 if (type == 1 && length >= 4) {
2422 unsigned oui = (x[3] << 16) | (x[2] << 8) | x[1];
2424 printf(", OUI %s\n", ouitohex(oui).c_str());
2425 x += 4;
2426 length -= 4;
2427 } else {
2428 printf("\n");
2429 x++;
2430 length--;
2432 x += payload_len;
2433 length -= payload_len;
2437 void edid_state::cta_displayid_type_7(const unsigned char *x, unsigned length)
2439 check_displayid_datablock_revision(x[0], 0x00, 2);
2441 if (length < 21U + ((x[0] & 0x70) >> 4)) {
2442 fail("Empty Data Block with length %u.\n", length);
2443 return;
2445 parse_displayid_type_1_7_timing(x + 1, true, 2, true);
2448 void edid_state::cta_displayid_type_8(const unsigned char *x, unsigned length)
2450 check_displayid_datablock_revision(x[0], 0xe8, 1);
2451 if (length < ((x[0] & 0x08) ? 3 : 2)) {
2452 fail("Empty Data Block with length %u.\n", length);
2453 return;
2456 unsigned sz = (x[0] & 0x08) ? 2 : 1;
2457 unsigned type = x[0] >> 6;
2459 if (type) {
2460 fail("Only code type 0 is supported.\n");
2461 return;
2464 if (x[0] & 0x20)
2465 printf(" Also supports YCbCr 4:2:0\n");
2467 x++;
2468 length--;
2469 for (unsigned i = 0; i < length / sz; i++) {
2470 unsigned id = x[i * sz];
2472 if (sz == 2)
2473 id |= x[i * sz + 1] << 8;
2474 parse_displayid_type_4_8_timing(type, id, true);
2478 void edid_state::cta_displayid_type_10(const unsigned char *x, unsigned length)
2480 check_displayid_datablock_revision(x[0], 0x70);
2481 if (length < 7U + ((x[0] & 0x70) >> 4)) {
2482 fail("Empty Data Block with length %u.\n", length);
2483 return;
2486 unsigned sz = 6U + ((x[0] & 0x70) >> 4);
2487 x++;
2488 length--;
2489 for (unsigned i = 0; i < length / sz; i++)
2490 parse_displayid_type_10_timing(x + i * sz, sz, true);
2493 static void cta_hdmi_audio_block(const unsigned char *x, unsigned length)
2495 unsigned num_descs;
2497 if (length < 2) {
2498 fail("Empty Data Block with length %u.\n", length);
2499 return;
2501 if (x[0] & 3)
2502 printf(" Max Stream Count: %u\n", (x[0] & 3) + 1);
2503 if (x[0] & 4)
2504 printf(" Supports MS NonMixed\n");
2506 num_descs = x[1] & 7;
2507 if (num_descs == 0)
2508 return;
2509 length -= 2;
2510 x += 2;
2511 while (length >= 4) {
2512 if (length > 4) {
2513 unsigned format = x[0] & 0xf;
2515 printf(" %s, max channels %u\n", audio_format(format).c_str(),
2516 (x[1] & 0x1f)+1);
2517 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
2518 (x[2] & 0x40) ? " 192" : "",
2519 (x[2] & 0x20) ? " 176.4" : "",
2520 (x[2] & 0x10) ? " 96" : "",
2521 (x[2] & 0x08) ? " 88.2" : "",
2522 (x[2] & 0x04) ? " 48" : "",
2523 (x[2] & 0x02) ? " 44.1" : "",
2524 (x[2] & 0x01) ? " 32" : "");
2525 if (format == 1)
2526 printf(" Supported sample sizes (bits):%s%s%s\n",
2527 (x[3] & 0x04) ? " 24" : "",
2528 (x[3] & 0x02) ? " 20" : "",
2529 (x[3] & 0x01) ? " 16" : "");
2530 } else {
2531 unsigned sad = ((x[2] << 16) | (x[1] << 8) | x[0]);
2532 unsigned i;
2534 switch (x[3] >> 4) {
2535 case 1:
2536 printf(" Speaker Allocation for 10.2 channels:\n");
2537 break;
2538 case 2:
2539 printf(" Speaker Allocation for 22.2 channels:\n");
2540 break;
2541 case 3:
2542 printf(" Speaker Allocation for 30.2 channels:\n");
2543 break;
2544 default:
2545 printf(" Unknown Speaker Allocation (0x%02x)\n", x[3] >> 4);
2546 return;
2549 for (i = 0; i < ARRAY_SIZE(speaker_map); i++) {
2550 if ((sad >> i) & 1)
2551 printf(" %s\n", speaker_map[i]);
2554 length -= 4;
2555 x += 4;
2559 void edid_state::cta_block(const unsigned char *x, std::vector<unsigned> &found_tags)
2561 unsigned length = x[0] & 0x1f;
2562 unsigned tag = (x[0] & 0xe0) >> 5;
2563 unsigned extended = (tag == 0x07) ? 1 : 0;
2565 x++;
2566 if (extended && length) {
2567 tag <<= 8;
2568 tag |= x[0];
2569 length--;
2570 x++;
2573 bool dooutputname = true;
2574 bool audio_block = false;
2575 data_block.clear();
2577 switch (tag) {
2578 case 0x01: data_block = "Audio Data Block"; audio_block = true; break;
2579 case 0x02: data_block = "Video Data Block"; break;
2580 case 0x03: data_block = "Vendor-Specific Data Block"; break;
2581 case 0x04: data_block = "Speaker Allocation Data Block"; audio_block = true; break;
2582 case 0x05: data_block = "VESA Display Transfer Characteristics Data Block"; break;
2583 case 0x06: data_block = "Video Format Data Block"; break;
2584 case 0x07: data_block = "Unknown CTA-861 Data Block (extended tag truncated)"; break;
2586 case 0x700: data_block = "Video Capability Data Block"; break;
2587 case 0x701: data_block = "Vendor-Specific Video Data Block"; break;
2588 case 0x702: data_block = "VESA Video Display Device Data Block"; break;
2589 case 0x703: data_block = "VESA Video Timing Block Extension"; break;
2590 case 0x704: data_block = "Reserved for HDMI Video Data Block"; break;
2591 case 0x705: data_block = "Colorimetry Data Block"; break;
2592 case 0x706: data_block = "HDR Static Metadata Data Block"; break;
2593 case 0x707: data_block = "HDR Dynamic Metadata Data Block"; break;
2594 case 0x708: data_block = "Native Video Resolution Data Block"; break;
2596 case 0x70d: data_block = "Video Format Preference Data Block"; break;
2597 case 0x70e: data_block = "YCbCr 4:2:0 Video Data Block"; break;
2598 case 0x70f: data_block = "YCbCr 4:2:0 Capability Map Data Block"; break;
2599 case 0x710: data_block = "Reserved for CTA-861 Miscellaneous Audio Fields"; break;
2600 case 0x711: data_block = "Vendor-Specific Audio Data Block"; audio_block = true; break;
2601 case 0x712: data_block = "HDMI Audio Data Block"; audio_block = true; break;
2602 case 0x713: data_block = "Room Configuration Data Block"; audio_block = true; break;
2603 case 0x714: data_block = "Speaker Location Data Block"; audio_block = true; break;
2605 case 0x720: data_block = "InfoFrame Data Block"; break;
2607 case 0x722: data_block = "DisplayID Type VII Video Timing Data Block"; break;
2608 case 0x723: data_block = "DisplayID Type VIII Video Timing Data Block"; break;
2609 case 0x72a: data_block = "DisplayID Type X Video Timing Data Block"; break;
2611 case 0x778: data_block = "HDMI Forum EDID Extension Override Data Block"; break;
2612 case 0x779: data_block = "HDMI Forum Sink Capability Data Block"; break;
2613 case 0x77a: data_block = "HDMI Forum Source-Based Tone Mapping Data Block"; break;
2615 default:
2616 std::string unknown_name;
2617 if (tag < 0x700) unknown_name = "Unknown CTA-861 Data Block";
2618 else if (tag < 0x70d) unknown_name = "Unknown CTA-861 Video-Related Data Block";
2619 else if (tag < 0x720) unknown_name = "Unknown CTA-861 Audio-Related Data Block";
2620 else if (tag < 0x778) unknown_name = "Unknown CTA-861 Data Block";
2621 else if (tag < 0x780) unknown_name = "Unknown CTA-861 HDMI-Related Data Block";
2622 else unknown_name = "Unknown CTA-861 Data Block";
2623 unknown_name += std::string(" (") + (extended ? "extended " : "") + "tag " + utohex(tag & 0xff) + ", length " + std::to_string(length) + ")";
2624 printf(" %s:\n", unknown_name.c_str());
2625 warn("%s.\n", unknown_name.c_str());
2626 break;
2629 switch (tag) {
2630 case 0x03:
2631 case 0x701:
2632 case 0x711: {
2633 unsigned ouinum;
2635 data_block_oui(data_block, x, length, &ouinum);
2636 x += (length < 3) ? length : 3;
2637 length -= (length < 3) ? length : 3;
2638 dooutputname = false;
2639 tag |= ouinum;
2640 break;
2644 if (dooutputname && data_block.length())
2645 printf(" %s:\n", data_block.c_str());
2647 switch (tag) {
2648 case 0x04:
2649 case 0x05:
2650 case 0x700:
2651 case 0x702:
2652 case 0x705:
2653 case 0x706:
2654 case 0x708:
2655 case 0x70d:
2656 case 0x70f:
2657 case 0x712:
2658 case 0x713:
2659 case 0x778:
2660 case 0x779:
2661 case 0x77a:
2662 if (std::find(found_tags.begin(), found_tags.end(), tag) != found_tags.end())
2663 fail("Only one instance of this Data Block is allowed.\n");
2664 break;
2667 // See Table 52 of CTA-861-G for a description of Byte 3
2668 if (audio_block && !(cta.byte3 & 0x40))
2669 fail("Audio information is present, but bit 6 of Byte 3 of the CTA-861 Extension header indicates no Basic Audio support.\n");
2671 switch (tag) {
2672 case 0x01: cta_audio_block(x, length); break;
2673 case 0x02: cta_svd(x, length, false); break;
2674 case 0x03|kOUI_HDMI:
2675 cta_hdmi_block(x, length);
2676 // The HDMI OUI is present, so this EDID represents an HDMI
2677 // interface. And HDMI interfaces must use EDID version 1.3
2678 // according to the HDMI Specification, so check for this.
2679 if (base.edid_minor != 3)
2680 fail("The HDMI Specification requires EDID 1.3 instead of 1.%u.\n",
2681 base.edid_minor);
2682 break;
2683 case 0x03|kOUI_HDMIForum:
2684 if (cta.previous_cta_tag != (0x03|kOUI_HDMI))
2685 fail("HDMI Forum VSDB did not immediately follow the HDMI VSDB.\n");
2686 if (cta.have_hf_scdb || cta.have_hf_vsdb)
2687 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2688 cta_hf_scdb(x, length);
2689 cta.have_hf_vsdb = true;
2690 break;
2691 case 0x03|kOUI_AMD: cta_amd(x, length); break;
2692 case 0x03|kOUI_Microsoft: if (length != 0x12) goto dodefault; cta_microsoft(x, length); break;
2693 case 0x03|kOUI_UHDA: cta_uhda_fmm(x, length); break;
2694 case 0x04: cta_sadb(x, length); break;
2695 case 0x05: cta_vesa_dtcdb(x, length); break;
2696 case 0x06: cta_vfdb(x, length); break;
2697 case 0x07: fail("Extended tag cannot have zero length.\n"); break;
2698 case 0x700: cta_vcdb(x, length); break;
2699 case 0x701|kOUI_HDR10: cta_hdr10plus(x, length); break;
2700 case 0x701|kOUI_Dolby: cta_dolby_video(x, length); break;
2701 // 0x701|kOUI_Apple: this almost certainly contains 'BLC Info/Corrections',
2702 // since the data (spread out over two VSDBs) is very similar to what is seen
2703 // in DisplayID blocks. Since I don't know how to parse this data, we still
2704 // default to a hex dump, but I mention this here in case data on how to
2705 // parse this becomes available.
2706 case 0x702: cta_vesa_vdddb(x, length); break;
2707 case 0x705: cta_colorimetry_block(x, length); break;
2708 case 0x706: cta_hdr_static_metadata_block(x, length); break;
2709 case 0x707: cta_hdr_dyn_metadata_block(x, length); break;
2710 case 0x708: cta_nvrdb(x, length); return;
2711 case 0x70d: cta_vfpdb(x, length); break;
2712 case 0x70e: cta_svd(x, length, true); break;
2713 case 0x70f: cta_y420cmdb(x, length); break;
2714 case 0x711|kOUI_Dolby: cta_dolby_audio(x, length); break;
2715 case 0x712: cta_hdmi_audio_block(x, length); break;
2716 case 0x713: cta_rcdb(x, length); break;
2717 case 0x714: cta_sldb(x, length); break;
2718 case 0x720: cta_ifdb(x, length); break;
2719 case 0x722: cta_displayid_type_7(x, length); break;
2720 case 0x723: cta_displayid_type_8(x, length); break;
2721 case 0x72a: cta_displayid_type_10(x, length); break;
2722 case 0x778:
2723 cta_hf_eeodb(x, length);
2724 if (block_nr != 1)
2725 fail("Data Block can only be present in Block 1.\n");
2726 // This must be the first CTA-861 block
2727 if (cta.block_number > 0)
2728 fail("Data Block starts at a wrong offset.\n");
2729 break;
2730 case 0x779:
2731 if (cta.previous_cta_tag != (0x03|kOUI_HDMI))
2732 fail("HDMI Forum SCDB did not immediately follow the HDMI VSDB.\n");
2733 if (cta.have_hf_scdb || cta.have_hf_vsdb)
2734 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2735 if (block_nr != 1)
2736 fail("Data Block can only be present in Block 1.\n");
2737 if (length < 2) {
2738 data_block = std::string("HDMI Forum SCDB");
2739 fail("Invalid length %u < 2.\n", length);
2740 break;
2742 if (x[0] || x[1])
2743 printf(" Non-zero SCDB reserved fields!\n");
2744 cta_hf_scdb(x + 2, length - 2);
2745 cta.have_hf_scdb = true;
2746 break;
2747 case 0x77a:
2748 cta_hf_sbtmdb(x, length);
2749 break;
2750 dodefault:
2751 default:
2752 hex_block(" ", x, length);
2753 break;
2756 cta.block_number++;
2757 cta.previous_cta_tag = tag;
2758 found_tags.push_back(tag);
2761 void edid_state::preparse_cta_block(unsigned char *x)
2763 unsigned version = x[1];
2764 unsigned offset = x[2];
2766 if (offset >= 4) {
2767 unsigned char *detailed;
2768 bool update_checksum = false;
2770 for (detailed = x + offset; detailed + 17 < x + 127; detailed += 18) {
2771 if (memchk(detailed, 18))
2772 break;
2773 update_checksum |= preparse_detailed_block(detailed);
2774 if (detailed[0] || detailed[1])
2775 cta.preparsed_total_dtds++;
2777 if (update_checksum)
2778 replace_checksum(x, EDID_PAGE_SIZE);
2781 if (version < 3)
2782 return;
2784 for (unsigned i = 4; i < offset; i += (x[i] & 0x1f) + 1) {
2785 bool for_ycbcr420 = false;
2786 unsigned oui;
2788 switch ((x[i] & 0xe0) >> 5) {
2789 case 0x03:
2790 oui = (x[i + 3] << 16) + (x[i + 2] << 8) + x[i + 1];
2791 if (oui == 0x000c03) {
2792 cta.has_hdmi = true;
2793 cta.preparsed_phys_addr = (x[i + 4] << 8) | x[i + 5];
2794 } else if ((oui == 0xca125c || oui == 0x5c12ca) &&
2795 (x[i] & 0x1f) == 0x15 && replace_unique_ids) {
2796 memset(x + i + 6, 0, 16);
2797 replace_checksum(x, EDID_PAGE_SIZE);
2799 break;
2800 case 0x06:
2801 if (!(x[i] & 0x1f) || cta.preparsed_first_vfd.rid)
2802 break;
2803 cta.preparsed_first_vfd = cta_parse_vfd(x + i + 2, (x[i + 1] & 3) + 1);
2804 break;
2805 case 0x07:
2806 if (x[i + 1] == 0x0d)
2807 cta.has_vfpdb = true;
2808 else if (x[i + 1] == 0x05)
2809 cta.has_cdb = true;
2810 else if (x[i + 1] == 0x08)
2811 cta.has_nvrdb = true;
2812 else if (x[i + 1] == 0x13 && (x[i + 2] & 0x40)) {
2813 cta.preparsed_speaker_count = 1 + (x[i + 2] & 0x1f);
2814 cta.preparsed_sld = x[i + 2] & 0x20;
2815 } else if (x[i + 1] == 0x14)
2816 cta_preparse_sldb(x + i + 2, (x[i] & 0x1f) - 1);
2817 else if (x[i + 1] == 0x22)
2818 cta.preparsed_total_vtdbs++;
2819 else if (x[i + 1] == 0x23) {
2820 cta.preparsed_has_t8vtdb = true;
2821 cta.preparsed_t8vtdb_dmt = x[i + 3];
2822 if (x[i + 2] & 0x08)
2823 cta.preparsed_t8vtdb_dmt |= x[i + 4] << 8;
2824 } else if (x[i + 1] == 0x2a)
2825 cta.preparsed_total_vtdbs +=
2826 ((x[i] & 0x1f) - 2) / (6 + ((x[i + 2] & 0x70) >> 4));
2827 else if (x[i + 1] == 0x78)
2828 cta.hf_eeodb_blocks = x[i + 2];
2829 if (x[i + 1] != 0x0e)
2830 continue;
2831 for_ycbcr420 = true;
2832 #ifdef __EMSCRIPTEN__
2833 [[clang::fallthrough]];
2834 #endif
2835 /* fall-through */
2836 case 0x02:
2837 for (unsigned j = 1 + for_ycbcr420; j <= (x[i] & 0x1f); j++) {
2838 unsigned char vic = x[i + j];
2840 if ((vic & 0x7f) <= 64)
2841 vic &= 0x7f;
2842 cta.preparsed_svds[for_ycbcr420].push_back(vic);
2843 cta.preparsed_has_vic[for_ycbcr420][vic] = true;
2845 const struct timings *t = find_vic_id(vic);
2847 if (!for_ycbcr420 && t &&
2848 t->pixclk_khz > cta.preparsed_max_vic_pixclk_khz)
2849 cta.preparsed_max_vic_pixclk_khz = t->pixclk_khz;
2851 break;
2856 void edid_state::parse_cta_block(const unsigned char *x)
2858 unsigned version = x[1];
2859 unsigned offset = x[2];
2860 const unsigned char *detailed;
2862 // See Table 52 of CTA-861-G for a description of Byte 3
2864 printf(" Revision: %u\n", version);
2865 if (version == 0)
2866 fail("Invalid CTA-861 Extension revision 0.\n");
2867 if (version == 2)
2868 fail("Deprecated CTA-861 Extension revision 2.\n");
2869 if (cta.has_hdmi && version != 3)
2870 fail("The HDMI Specification requires CTA Extension revision 3.\n");
2871 if (version > 3)
2872 warn("Unknown CTA-861 Extension revision %u.\n", version);
2873 if (offset > 0 && offset < 4)
2874 fail("Invalid CTA-861 Extension offset value (byte 2).\n");
2876 if (version >= 1) do {
2877 if (version == 1 && x[3] != 0)
2878 fail("Non-zero byte 3.\n");
2880 if (version < 3 && offset >= 4 && ((offset - 4) / 8)) {
2881 printf(" 8-byte timing descriptors: %u\n", (offset - 4) / 8);
2882 fail("8-byte descriptors were never used.\n");
2885 if (version >= 2) {
2886 if (x[3] & 0x80)
2887 printf(" Underscans IT Video Formats by default\n");
2888 else
2889 warn("IT Video Formats are overscanned by default, but normally this should be underscanned.\n");
2890 if (x[3] & 0x40)
2891 printf(" Basic audio support\n");
2892 if (x[3] & 0x20)
2893 printf(" Supports YCbCr 4:4:4\n");
2894 if (x[3] & 0x10)
2895 printf(" Supports YCbCr 4:2:2\n");
2896 // Disable this test: this fails a lot of EDIDs, and there are
2897 // also some corner cases where you only want to receive 4:4:4
2898 // and refuse a fallback to 4:2:2.
2899 // if ((x[3] & 0x30) && (x[3] & 0x30) != 0x30)
2900 // msg(!cta.has_hdmi, "If YCbCr support is indicated, then both 4:2:2 and 4:4:4 %s be supported.\n",
2901 // cta.has_hdmi ? "shall" : "should");
2902 printf(" Native detailed modes: %u\n", x[3] & 0x0f);
2903 if (cta.block_number == 0)
2904 cta.byte3 = x[3];
2905 else if (x[3] != cta.byte3)
2906 fail("Byte 3 must be the same for all CTA-861 Extension Blocks.\n");
2907 if (cta.block_number == 0) {
2908 unsigned native_dtds = x[3] & 0x0f;
2910 cta.native_timings.clear();
2911 if (!native_dtds && !cta.has_vfpdb) {
2912 cta.first_svd_might_be_preferred = true;
2913 } else if (native_dtds > cta.preparsed_total_dtds) {
2914 fail("There are more Native DTDs (%u) than DTDs (%u).\n",
2915 native_dtds, cta.preparsed_total_dtds);
2917 if (native_dtds > cta.preparsed_total_dtds)
2918 native_dtds = cta.preparsed_total_dtds;
2919 for (unsigned i = 0; i < native_dtds; i++) {
2920 char type[16];
2922 sprintf(type, "DTD %3u", i + 1);
2923 cta.native_timings.push_back(timings_ext(i + 129, type));
2924 cta.has_svrs = true;
2926 if (cta.has_hdmi && block_nr != (block_map.saw_block_1 ? 2 : 1))
2927 fail("The HDMI Specification requires that the first Extension Block (that is not a Block Map) is an CTA-861 Extension Block.\n");
2931 if (offset < 4) {
2932 // Offset 0 means that there are no data blocks or DTDs,
2933 // so the remainder must be padding.
2934 if (!memchk(x + 4, 127 - 4)) {
2935 data_block = "Padding";
2936 fail("Contains non-zero bytes.\n");
2938 break;
2941 if (version >= 3) {
2942 unsigned i;
2944 for (i = 4; i < offset; i += (x[i] & 0x1f) + 1) {
2945 cta_block(x + i, cta.found_tags);
2948 data_block.clear();
2949 if (i != offset)
2950 fail("Offset is %u, but should be %u.\n", offset, i);
2953 data_block = "Detailed Timing Descriptors";
2954 base.seen_non_detailed_descriptor = false;
2955 bool first = true;
2956 for (detailed = x + offset; detailed + 17 < x + 127; detailed += 18) {
2957 if (memchk(detailed, 18))
2958 break;
2959 if (first) {
2960 first = false;
2961 printf(" %s:\n", data_block.c_str());
2963 detailed_block(detailed);
2965 unused_bytes = x + 127 - detailed;
2966 if (!memchk(detailed, unused_bytes)) {
2967 data_block = "Padding";
2968 fail("Contains non-zero bytes.\n");
2970 } while (0);
2972 data_block.clear();
2973 if (base.serial_number && serial_strings.size())
2974 warn("Display Product Serial Number is set, so the Serial Number in the Base EDID should be 0.\n");
2975 if (!cta.has_vic_1 && !base.has_640x480p60_est_timing)
2976 fail("Required 640x480p60 timings are missing in the established timings"
2977 " and the SVD list (VIC 1).\n");
2978 if ((cta.supported_hdmi_vic_vsb_codes & cta.supported_hdmi_vic_codes) !=
2979 cta.supported_hdmi_vic_codes)
2980 fail("HDMI VIC Codes must have their CTA-861 VIC equivalents in the VSB.\n");
2981 if (!cta.has_vcdb)
2982 fail("Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.\n");
2983 if (!base.uses_srgb && !cta.has_cdb)
2984 warn("Add a Colorimetry Data Block with the sRGB colorimetry bit set to avoid interop issues.\n");
2987 void edid_state::cta_resolve_svr(timings_ext &t_ext)
2989 if (t_ext.svr() == 254) {
2990 t_ext.flags = cta.t8vtdb.flags;
2991 add_str(t_ext.flags, ">=CTA-861-H");
2992 t_ext.t = cta.t8vtdb.t;
2993 } else if (t_ext.svr() <= 144) {
2994 if (t_ext.svr() < 129 || t_ext.svr() - 129 >= cta.vec_dtds.size())
2995 return;
2996 t_ext.flags = cta.vec_dtds[t_ext.svr() - 129].flags;
2997 t_ext.t = cta.vec_dtds[t_ext.svr() - 129].t;
2998 } else if (t_ext.svr() <= 160) {
2999 if (t_ext.svr() - 145 >= cta.vec_vtdbs.size())
3000 return;
3001 t_ext.flags = cta.vec_vtdbs[t_ext.svr() - 145].flags;
3002 add_str(t_ext.flags, ">=CTA-861-H");
3003 t_ext.t = cta.vec_vtdbs[t_ext.svr() - 145].t;
3004 } else if (t_ext.svr() <= 175) {
3005 t_ext.flags.clear();
3006 unsigned char rid = cta.preparsed_first_vfd.rid;
3007 t_ext.t = calc_ovt_mode(rids[rid].hact, rids[rid].vact,
3008 rids[rid].hratio, rids[rid].vratio,
3009 vf_rate_values[t_ext.svr() - 160]);
3010 t_ext.flags = ">=CTA-861.6";
3014 void edid_state::cta_resolve_svrs()
3016 for (vec_timings_ext::iterator iter = cta.preferred_timings_vfpdb.begin();
3017 iter != cta.preferred_timings_vfpdb.end(); ++iter) {
3018 if (iter->has_svr())
3019 cta_resolve_svr(*iter);
3022 for (vec_timings_ext::iterator iter = cta.native_timings.begin();
3023 iter != cta.native_timings.end(); ++iter) {
3024 if (iter->has_svr())
3025 cta_resolve_svr(*iter);
3028 for (vec_timings_ext::iterator iter = cta.native_timing_nvrdb.begin();
3029 iter != cta.native_timing_nvrdb.end(); ++iter) {
3030 if (iter->has_svr())
3031 cta_resolve_svr(*iter);
3035 void edid_state::check_cta_blocks()
3037 unsigned max_pref_prog_hact = 0;
3038 unsigned max_pref_prog_vact = 0;
3039 unsigned max_pref_ilace_hact = 0;
3040 unsigned max_pref_ilace_vact = 0;
3042 data_block = "CTA-861";
3044 // HDMI 1.4 goes up to 340 MHz. Dubious to have a DTD above that,
3045 // but no VICs. Displays often have a setting to turn off HDMI 2.x
3046 // support, dropping any HDMI 2.x VICs, but they sometimes forget
3047 // to replace the DTD in the base block as well.
3048 if (cta.warn_about_hdmi_2x_dtd)
3049 warn("DTD pixelclock indicates HDMI 2.x support, VICs indicate HDMI 1.x.\n");
3051 if (cta.hdmi_max_rate && max_pixclk_khz > cta.hdmi_max_rate * 1000)
3052 fail("The maximum HDMI TMDS clock is %u kHz, but one or more video timings go up to %u kHz.\n",
3053 cta.hdmi_max_rate * 1000, max_pixclk_khz);
3055 for (vec_timings_ext::iterator iter = cta.preferred_timings.begin();
3056 iter != cta.preferred_timings.end(); ++iter) {
3057 if (iter->t.interlaced &&
3058 (iter->t.vact > max_pref_ilace_vact ||
3059 (iter->t.vact == max_pref_ilace_vact && iter->t.hact >= max_pref_ilace_hact))) {
3060 max_pref_ilace_hact = iter->t.hact;
3061 max_pref_ilace_vact = iter->t.vact;
3063 if (!iter->t.interlaced &&
3064 (iter->t.vact > max_pref_prog_vact ||
3065 (iter->t.vact == max_pref_prog_vact && iter->t.hact >= max_pref_prog_hact))) {
3066 max_pref_prog_hact = iter->t.hact;
3067 max_pref_prog_vact = iter->t.vact;
3070 for (vec_timings_ext::iterator iter = cta.preferred_timings_vfpdb.begin();
3071 iter != cta.preferred_timings_vfpdb.end(); ++iter) {
3072 if (iter->t.interlaced &&
3073 (iter->t.vact > max_pref_ilace_vact ||
3074 (iter->t.vact == max_pref_ilace_vact && iter->t.hact >= max_pref_ilace_hact))) {
3075 max_pref_ilace_hact = iter->t.hact;
3076 max_pref_ilace_vact = iter->t.vact;
3078 if (!iter->t.interlaced &&
3079 (iter->t.vact > max_pref_prog_vact ||
3080 (iter->t.vact == max_pref_prog_vact && iter->t.hact >= max_pref_prog_hact))) {
3081 max_pref_prog_hact = iter->t.hact;
3082 max_pref_prog_vact = iter->t.vact;
3086 unsigned native_prog = 0;
3087 unsigned native_prog_hact = 0;
3088 unsigned native_prog_vact = 0;
3089 bool native_prog_mixed_resolutions = false;
3090 unsigned native_ilace = 0;
3091 unsigned native_ilace_hact = 0;
3092 unsigned native_ilace_vact = 0;
3093 bool native_ilace_mixed_resolutions = false;
3094 unsigned native_nvrdb_hact = 0;
3095 unsigned native_nvrdb_vact = 0;
3097 for (vec_timings_ext::iterator iter = cta.native_timings.begin();
3098 iter != cta.native_timings.end(); ++iter) {
3099 if (iter->t.interlaced) {
3100 native_ilace++;
3101 if (!native_ilace_hact) {
3102 native_ilace_hact = iter->t.hact;
3103 native_ilace_vact = iter->t.vact;
3104 } else if (native_ilace_hact != iter->t.hact ||
3105 native_ilace_vact != iter->t.vact) {
3106 native_ilace_mixed_resolutions = true;
3108 } else {
3109 native_prog++;
3110 if (!native_prog_hact) {
3111 native_prog_hact = iter->t.hact;
3112 native_prog_vact = iter->t.vact;
3113 } else if (native_prog_hact != iter->t.hact ||
3114 native_prog_vact != iter->t.vact) {
3115 native_prog_mixed_resolutions = true;
3120 for (vec_timings_ext::iterator iter = cta.native_timing_nvrdb.begin();
3121 iter != cta.native_timing_nvrdb.end(); ++iter) {
3122 native_nvrdb_hact = iter->t.hact;
3123 native_nvrdb_vact = iter->t.vact;
3126 if (native_prog_mixed_resolutions)
3127 fail("Native progressive timings are a mix of several resolutions.\n");
3128 if (native_ilace_mixed_resolutions)
3129 fail("Native interlaced timings are a mix of several resolutions.\n");
3130 if (native_ilace && !native_prog)
3131 fail("A native interlaced timing is present, but not a native progressive timing.\n");
3132 if (!native_prog_mixed_resolutions && native_prog > 1)
3133 warn("Multiple native progressive timings are defined.\n");
3134 if (!native_ilace_mixed_resolutions && native_ilace > 1)
3135 warn("Multiple native interlaced timings are defined.\n");
3137 if (native_nvrdb_vact &&
3138 (max_pref_prog_vact > native_nvrdb_vact ||
3139 (max_pref_prog_vact == native_nvrdb_vact && max_pref_prog_hact > native_nvrdb_hact)))
3140 warn("Native video resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
3141 native_nvrdb_hact, native_nvrdb_vact,
3142 max_pref_prog_hact, max_pref_prog_vact);
3143 else if (!native_nvrdb_vact && !native_prog_mixed_resolutions && native_prog_vact &&
3144 (max_pref_prog_vact > native_prog_vact ||
3145 (max_pref_prog_vact == native_prog_vact && max_pref_prog_hact > native_prog_hact)))
3146 warn("Native progressive resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
3147 native_prog_hact, native_prog_vact,
3148 max_pref_prog_hact, max_pref_prog_vact);
3149 if (!native_ilace_mixed_resolutions && native_ilace_vact &&
3150 (max_pref_ilace_vact > native_ilace_vact ||
3151 (max_pref_ilace_vact == native_ilace_vact && max_pref_ilace_hact > native_ilace_hact)))
3152 warn("Native interlaced resolution of %ux%u is smaller than the max preferred interlaced resolution %ux%u.\n",
3153 native_ilace_hact, native_ilace_vact,
3154 max_pref_ilace_hact, max_pref_ilace_vact);
3156 if (dispid.native_width && native_prog_hact &&
3157 !native_prog_mixed_resolutions) {
3158 if (dispid.native_width != native_prog_hact ||
3159 dispid.native_height != native_prog_vact)
3160 fail("Mismatch between CTA-861 and DisplayID native progressive resolution.\n");