edid-decode: fix emscripten build
[edid-decode.git] / parse-cta-block.cpp
blobf193b568a6d0f3398c3e1324a272772299a4f641
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 unsigned char rid_fps_to_vic(unsigned char rid, unsigned fps)
310 for (unsigned i = 1; i < ARRAY_SIZE(vf_rate_values); i++) {
311 if (vf_rate_values[i] == fps)
312 return rid2vic[rid][i - 1];
314 return 0;
317 const struct timings *cta_close_match_to_vic(const timings &t, unsigned &vic)
319 for (vic = 1; vic <= ARRAY_SIZE(edid_cta_modes1); vic++) {
320 if (timings_close_match(t, edid_cta_modes1[vic - 1]))
321 return &edid_cta_modes1[vic - 1];
323 for (vic = 193; vic < ARRAY_SIZE(edid_cta_modes2) + 193; vic++) {
324 if (timings_close_match(t, edid_cta_modes1[vic - 193]))
325 return &edid_cta_modes1[vic - 193];
327 vic = 0;
328 return NULL;
331 bool cta_matches_vic(const timings &t, unsigned &vic)
333 for (vic = 1; vic <= ARRAY_SIZE(edid_cta_modes1); vic++) {
334 if (match_timings(t, edid_cta_modes1[vic - 1]))
335 return true;
337 for (vic = 193; vic < ARRAY_SIZE(edid_cta_modes2) + 193; vic++) {
338 if (match_timings(t, edid_cta_modes1[vic - 193]))
339 return true;
341 vic = 0;
342 return false;
345 void edid_state::cta_list_vics()
347 char type[16];
348 for (unsigned vic = 1; vic <= ARRAY_SIZE(edid_cta_modes1); vic++) {
349 sprintf(type, "VIC %3u", vic);
350 print_timings("", &edid_cta_modes1[vic - 1], type, "", false, false);
352 for (unsigned vic = 193; vic < ARRAY_SIZE(edid_cta_modes2) + 193; vic++) {
353 sprintf(type, "VIC %3u", vic);
354 print_timings("", &edid_cta_modes2[vic - 193], type, "", false, false);
358 void edid_state::cta_list_hdmi_vics()
360 for (unsigned i = 0; i < ARRAY_SIZE(edid_hdmi_mode_map); i++) {
361 unsigned vic = edid_hdmi_mode_map[i];
362 char type[16];
364 sprintf(type, "HDMI VIC %u", i + 1);
365 print_timings("", find_vic_id(vic), type, "", false, false);
369 void edid_state::cta_list_rids()
371 for (unsigned i = 1; i < ARRAY_SIZE(rids); i++) {
372 printf("RID %2u: %5ux%-4u %2u:%-2u\n", i,
373 rids[i].hact, rids[i].vact,
374 rids[i].hratio, rids[i].vratio);
378 void edid_state::cta_list_rid_timings(unsigned list_rid)
380 for (unsigned rid = 1; rid < ARRAY_SIZE(rids); rid++) {
381 char type[16];
383 if (list_rid && rid != list_rid)
384 continue;
386 sprintf(type, "RID %u", rid);
387 for (unsigned i = 1; i < ARRAY_SIZE(vf_rate_values); i++) {
388 unsigned fps = vf_rate_values[i];
390 if (rid_to_vic(rid, i)) {
391 printf("%s: %5ux%-4u %7.3f Hz %3u:%-2u maps to VIC %u\n", type,
392 rids[rid].hact, rids[rid].vact, (double)fps,
393 rids[rid].hratio, rids[rid].vratio,
394 rid_to_vic(rid, i));
395 continue;
397 timings t = calc_ovt_mode(rids[rid].hact, rids[rid].vact,
398 rids[rid].hratio, rids[rid].vratio, fps);
399 print_timings("", &t, type, "", false, false);
404 static std::string audio_ext_format(unsigned char x)
406 if (x >= 1 && x <= 3)
407 fail("Obsolete Audio Ext Format 0x%02x.\n", x);
408 switch (x) {
409 case 1: return "HE AAC (Obsolete)";
410 case 2: return "HE AAC v2 (Obsolete)";
411 case 3: return "MPEG Surround (Obsolete)";
412 case 4: return "MPEG-4 HE AAC";
413 case 5: return "MPEG-4 HE AAC v2";
414 case 6: return "MPEG-4 AAC LC";
415 case 7: return "DRA";
416 case 8: return "MPEG-4 HE AAC + MPEG Surround";
417 case 10: return "MPEG-4 AAC LC + MPEG Surround";
418 case 11: return "MPEG-H 3D Audio";
419 case 12: return "AC-4";
420 case 13: return "L-PCM 3D Audio";
421 case 14: return "Auro-Cx";
422 case 15: return "MPEG-D USAC";
423 default: break;
425 fail("Unknown Audio Ext Format 0x%02x.\n", x);
426 return std::string("Unknown Audio Ext Format (") + utohex(x) + ")";
429 static std::string audio_format(unsigned char x)
431 switch (x) {
432 case 1: return "Linear PCM";
433 case 2: return "AC-3";
434 case 3: return "MPEG 1 (Layers 1 & 2)";
435 case 4: return "MPEG 1 Layer 3 (MP3)";
436 case 5: return "MPEG2 (multichannel)";
437 case 6: return "AAC LC";
438 case 7: return "DTS";
439 case 8: return "ATRAC";
440 case 9: return "One Bit Audio";
441 case 10: return "Enhanced AC-3 (DD+)";
442 case 11: return "DTS-HD";
443 case 12: return "MAT (MLP)";
444 case 13: return "DST";
445 case 14: return "WMA Pro";
446 default: break;
448 fail("Unknown Audio Format 0x%02x.\n", x);
449 return std::string("Unknown Audio Format (") + utohex(x) + ")";
452 static std::string mpeg_h_3d_audio_level(unsigned char x)
454 switch (x) {
455 case 0: return "Unspecified";
456 case 1: return "Level 1";
457 case 2: return "Level 2";
458 case 3: return "Level 3";
459 case 4: return "Level 4";
460 case 5: return "Level 5";
461 default: break;
463 fail("Unknown MPEG-H 3D Audio Level 0x%02x.\n", x);
464 return std::string("Unknown MPEG-H 3D Audio Level (") + utohex(x) + ")";
467 static void cta_audio_block(const unsigned char *x, unsigned length)
469 unsigned i, format, ext_format;
471 if (length % 3) {
472 fail("Broken CTA-861 audio block length %d.\n", length);
473 return;
476 for (i = 0; i < length; i += 3) {
477 format = (x[i] & 0x78) >> 3;
478 if (format == 0) {
479 printf(" Reserved (0x00)\n");
480 fail("Audio Format Code 0x00 is reserved.\n");
481 continue;
483 if (format != 15) {
484 ext_format = 0;
485 printf(" %s:\n", audio_format(format).c_str());
486 } else {
487 ext_format = (x[i + 2] & 0xf8) >> 3;
488 printf(" %s:\n", audio_ext_format(ext_format).c_str());
490 if (format != 15)
491 printf(" Max channels: %u\n", (x[i] & 0x07)+1);
492 else if (ext_format == 11)
493 printf(" MPEG-H 3D Audio Level: %s\n",
494 mpeg_h_3d_audio_level(x[i] & 0x07).c_str());
495 else if (ext_format == 13)
496 printf(" Max channels: %u\n",
497 (((x[i + 1] & 0x80) >> 3) | ((x[i] & 0x80) >> 4) |
498 (x[i] & 0x07))+1);
499 else if ((ext_format == 12 || ext_format == 14) && (x[i] & 0x07))
500 fail("Bits F10-F12 must be 0.\n");
501 else
502 printf(" Max channels: %u\n", (x[i] & 0x07)+1);
504 if ((format == 1 || format == 14) && (x[i + 2] & 0xf8))
505 fail("Bits F33-F37 must be 0.\n");
506 if (ext_format != 13 && (x[i+1] & 0x80))
507 fail("Bit F27 must be 0.\n");
509 // Several sample rates are not supported in certain formats
510 if (ext_format == 12 && (x[i+1] & 0x29))
511 fail("Bits F20, F23 and F25 must be 0.\n");
512 if (ext_format >= 4 && ext_format <= 6 && (x[i+1] & 0x60))
513 fail("Bits F25 and F26 must be 0.\n");
514 if ((ext_format == 8 || ext_format == 10 || ext_format == 15) && (x[i+1] & 0x60))
515 fail("Bits F25 and F26 must be 0.\n");
517 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
518 (x[i+1] & 0x40) ? " 192" : "",
519 (x[i+1] & 0x20) ? " 176.4" : "",
520 (x[i+1] & 0x10) ? " 96" : "",
521 (x[i+1] & 0x08) ? " 88.2" : "",
522 (x[i+1] & 0x04) ? " 48" : "",
523 (x[i+1] & 0x02) ? " 44.1" : "",
524 (x[i+1] & 0x01) ? " 32" : "");
525 if (format == 1 || ext_format == 13) {
526 printf(" Supported sample sizes (bits):%s%s%s\n",
527 (x[i+2] & 0x04) ? " 24" : "",
528 (x[i+2] & 0x02) ? " 20" : "",
529 (x[i+2] & 0x01) ? " 16" : "");
530 } else if (format <= 8) {
531 printf(" Maximum bit rate: %u kb/s\n", x[i+2] * 8);
532 } else if (format == 10) {
533 // As specified by the "Dolby Audio and Dolby Atmos over HDMI"
534 // specification (v1.0).
535 if (x[i+2] & 1)
536 printf(" Supports Joint Object Coding\n");
537 if (x[i+2] & 2)
538 printf(" Supports Joint Object Coding with ACMOD28\n");
539 } else if (format == 11) {
540 // Reverse engineering, see:
541 // https://www.avsforum.com/threads/lg-c9-earc-info-thread.3072900/post-61795538
542 if (x[i+2] & 2)
543 printf(" Supports DTS:X\n");
544 // Note: I strongly suspect that bit 0 indicates DTS-HD MA support.
545 printf(" Audio Format Code dependent value: 0x%02x\n", x[i+2]);
546 } else if (format == 12) {
547 if (x[i+2] & 1) {
548 printf(" Supports Dolby TrueHD, object audio PCM and channel-based PCM\n");
549 printf(" Hash calculation %srequired for object audio PCM or channel-based PCM\n",
550 (x[i+2] & 2) ? "not " : "");
551 } else {
552 printf(" Supports only Dolby TrueHD\n");
554 } else if (format == 14) {
555 printf(" Profile: %u\n", x[i+2] & 7);
556 } else if (format >= 9 && format <= 13) {
557 printf(" Audio Format Code dependent value: 0x%02x\n", x[i+2]);
558 } else if (ext_format == 11 && (x[i+2] & 1)) {
559 printf(" Supports MPEG-H 3D Audio Low Complexity Profile\n");
560 } else if ((ext_format >= 4 && ext_format <= 6) ||
561 ext_format == 8 || ext_format == 10) {
562 printf(" AAC audio frame lengths:%s%s\n",
563 (x[i+2] & 4) ? " 1024_TL" : "",
564 (x[i+2] & 2) ? " 960_TL" : "");
565 if (ext_format >= 8 && (x[i+2] & 1))
566 printf(" Supports %s signaled MPEG Surround data\n",
567 (x[i+2] & 1) ? "implicitly and explicitly" : "only implicitly");
568 if (ext_format == 6 && (x[i+2] & 1))
569 printf(" Supports 22.2ch System H\n");
570 } else if (ext_format == 12 || ext_format == 14) {
571 printf(" Audio Format Code dependent value: %u\n", x[i+2] & 7);
576 void edid_state::cta_svd(const unsigned char *x, unsigned n, bool for_ycbcr420)
578 bool ascending = !for_ycbcr420;
579 unsigned char last_vic = 0;
580 bool first_vic_is_1_to_4 = false;
581 bool have_vics_5_and_up = false;
582 unsigned i;
584 for (i = 0; i < n; i++) {
585 const struct timings *t = NULL;
586 unsigned char svd = x[i];
587 unsigned char native;
588 unsigned char vic;
590 if ((svd & 0x7f) == 0)
591 continue;
593 if ((svd - 1) & 0x40) {
594 vic = svd;
595 native = 0;
596 if (cta.avi_version == 2)
597 cta.avi_version = 3;
598 } else {
599 vic = svd & 0x7f;
600 native = svd & 0x80;
603 if (i == 0)
604 first_vic_is_1_to_4 = vic <= 4;
605 if (vic > 4)
606 have_vics_5_and_up = true;
607 if (vic < last_vic)
608 ascending = false;
609 last_vic = vic;
611 t = find_vic_id(vic);
612 if (t) {
613 switch (vic) {
614 case 95:
615 cta.supported_hdmi_vic_vsb_codes |= 1 << 0;
616 break;
617 case 94:
618 cta.supported_hdmi_vic_vsb_codes |= 1 << 1;
619 break;
620 case 93:
621 cta.supported_hdmi_vic_vsb_codes |= 1 << 2;
622 break;
623 case 98:
624 cta.supported_hdmi_vic_vsb_codes |= 1 << 3;
625 break;
627 bool first_svd = cta.first_svd && !for_ycbcr420;
629 char type[16];
630 sprintf(type, "VIC %3u", vic);
631 const char *flags = native ? "native" : "";
633 if (for_ycbcr420) {
634 struct timings tmp = *t;
635 tmp.ycbcr420 = true;
636 print_timings(" ", &tmp, type, flags);
637 cta.has_ycbcr420 = true;
638 } else {
639 print_timings(" ", t, type, flags);
641 if (first_svd && !cta.preferred_timings.empty()) {
642 if (!match_timings(cta.preferred_timings[0].t, *t))
643 warn("VIC %u and the first DTD are not identical. Is this intended?\n", vic);
644 else if (cta.first_svd_might_be_preferred)
645 warn("For improved preferred timing interoperability, set 'Native detailed modes' to 1.\n");
647 if (first_svd) {
648 if (cta.first_svd_might_be_preferred)
649 cta.preferred_timings.insert(cta.preferred_timings.begin(),
650 timings_ext(*t, type, flags));
651 else
652 cta.preferred_timings.push_back(timings_ext(*t, type, flags));
654 if (first_svd) {
655 cta.first_svd = false;
656 cta.first_svd_might_be_preferred = false;
658 if (native)
659 cta.native_timings.push_back(timings_ext(*t, type, flags));
660 } else {
661 printf(" Unknown (VIC %3u)\n", vic);
662 fail("Unknown VIC %u.\n", vic);
665 if (vic == 1 && !for_ycbcr420)
666 cta.has_vic_1 = 1;
667 if (++cta.vics[vic][for_ycbcr420] == 2)
668 fail("Duplicate %sVIC %u.\n", for_ycbcr420 ? "YCbCr 4:2:0 " : "", vic);
669 if (for_ycbcr420 && cta.preparsed_has_vic[0][vic])
670 fail("YCbCr 4:2:0-only VIC %u is also a regular VIC.\n", vic);
672 if (n > 1 && ascending && first_vic_is_1_to_4 && have_vics_5_and_up)
673 warn("All VICs are in ascending order, and the first (preferred) VIC <= 4, is that intended?\n");
676 cta_vfd edid_state::cta_parse_vfd(const unsigned char *x, unsigned lvfd)
678 cta_vfd vfd = {};
680 cta.avi_version = 4;
681 if (cta.avi_v4_length < 15)
682 cta.avi_v4_length = 15;
683 vfd.rid = x[0] & 0x3f;
684 if (vfd.rid >= ARRAY_SIZE(rids)) {
685 vfd.rid = 0;
686 return vfd;
688 vfd.bfr50 = !!(x[0] & 0x80);
689 vfd.fr24 = !!(x[0] & 0x40);
690 vfd.bfr60 = lvfd > 1 ? !!(x[1] & 0x80) : 1;
691 vfd.fr144 = lvfd > 1 ? !!(x[1] & 0x40) : 0;
692 vfd.fr_factor = lvfd > 1 ? (x[1] & 0x3f) : 3;
693 vfd.fr48 = lvfd > 2 ? !!(x[2] & 0x01) : 0;
694 return vfd;
697 static bool vfd_has_rate(cta_vfd &vfd, unsigned rate_index)
699 static const unsigned factors[6] = {
700 1, 2, 4, 8, 12, 16
702 unsigned rate = vf_rate_values[rate_index];
703 unsigned factor = 0;
705 if (!vfd.rid)
706 return false;
707 if (rate == 24)
708 return vfd.fr24;
709 if (rate == 48)
710 return vfd.fr48;
711 if (rate == 144)
712 return vfd.fr144;
714 if (!(rate % 30)) {
715 if (!vfd.bfr60)
716 return false;
717 factor = rate / 30;
719 if (!(rate % 25)) {
720 if (!vfd.bfr50)
721 return false;
722 factor = rate / 25;
725 for (unsigned i = 0; i < ARRAY_SIZE(factors); i++)
726 if (factors[i] == factor && (vfd.fr_factor & (1 << i)))
727 return true;
728 return false;
731 void edid_state::cta_vfdb(const unsigned char *x, unsigned n)
733 if (n-- == 0) {
734 fail("Length is 0.\n");
735 return;
737 unsigned char flags = *x++;
738 unsigned lvfd = (flags & 3) + 1;
740 if (n % lvfd) {
741 fail("Length - 1 is not a multiple of Lvfd (%u).\n", lvfd);
742 return;
744 if (flags & 0x80)
745 printf(" Supports YCbCr 4:2:0\n");
746 if (flags & 0x40)
747 printf(" NTSC fractional frame rates are preferred\n");
748 for (unsigned i = 0; i < n; i += lvfd, x += lvfd) {
749 unsigned char rid = x[0] & 0x3f;
750 cta_vfd vfd = cta_parse_vfd(x, lvfd);
752 if (lvfd > 2 && (x[2] & 0xfe))
753 fail("Bits F31-F37 must be 0.\n");
754 if (lvfd > 3 && x[3])
755 fail("Bits F40-F47 must be 0.\n");
756 if (rid == 0 || rid >= ARRAY_SIZE(rids)) {
757 fail("Unknown RID %u.\n", rid);
758 continue;
760 for (unsigned rate_index = 1; rate_index < ARRAY_SIZE(vf_rate_values); rate_index++) {
761 if (!vfd_has_rate(vfd, rate_index))
762 continue;
763 struct timings t = calc_ovt_mode(rids[vfd.rid].hact,
764 rids[vfd.rid].vact,
765 rids[vfd.rid].hratio,
766 rids[vfd.rid].vratio,
767 vf_rate_values[rate_index]);
768 char type[16];
769 sprintf(type, "RID %u@%up", rid, vf_rate_values[rate_index]);
770 print_timings(" ", &t, type);
771 if (rid_to_vic(vfd.rid, rate_index))
772 fail("%s not allowed since it maps to VIC %u.\n",
773 type, rid_to_vic(vfd.rid, rate_index));
778 void edid_state::print_vic_index(const char *prefix, unsigned idx, const char *suffix, bool ycbcr420)
780 if (!suffix)
781 suffix = "";
782 if (idx < cta.preparsed_svds[0].size()) {
783 unsigned char vic = cta.preparsed_svds[0][idx];
784 const struct timings *t = find_vic_id(vic);
785 char buf[16];
787 sprintf(buf, "VIC %3u", vic);
789 if (t) {
790 struct timings tmp = *t;
791 tmp.ycbcr420 = ycbcr420;
792 print_timings(prefix, &tmp, buf, suffix);
793 } else {
794 printf("%sUnknown (%s%s%s)\n", prefix, buf,
795 *suffix ? ", " : "", suffix);
797 } else {
798 // Should not happen!
799 printf("%sSVD Index %u is out of range", prefix, idx + 1);
800 if (*suffix)
801 printf(" (%s)", suffix);
802 printf("\n");
806 void edid_state::cta_y420cmdb(const unsigned char *x, unsigned length)
808 unsigned max_idx = 0;
809 unsigned i;
811 if (!length) {
812 printf(" All VDB SVDs\n");
813 return;
816 if (memchk(x, length)) {
817 printf(" Empty Capability Map\n");
818 fail("Empty Capability Map.\n");
819 return;
822 for (i = 0; i < length; i++) {
823 unsigned char v = x[i];
824 unsigned j;
826 for (j = 0; j < 8; j++) {
827 if (!(v & (1 << j)))
828 continue;
830 print_vic_index(" ", i * 8 + j, "", true);
831 max_idx = i * 8 + j;
832 if (max_idx < cta.preparsed_svds[0].size()) {
833 unsigned vic = cta.preparsed_svds[0][max_idx];
834 if (cta.preparsed_has_vic[1][vic])
835 fail("VIC %u is also a YCbCr 4:2:0-only VIC.\n", vic);
837 cta.has_ycbcr420 = true;
840 if (max_idx >= cta.preparsed_svds[0].size())
841 fail("Max index %u > %u (#SVDs).\n",
842 max_idx + 1, cta.preparsed_svds[0].size());
845 void edid_state::cta_print_svr(unsigned char svr, vec_timings_ext &vec_tim)
847 char suffix[24];
849 if ((svr > 0 && svr < 128) || (svr > 192 && svr < 254)) {
850 const struct timings *t;
851 unsigned char vic = svr;
853 sprintf(suffix, "VIC %3u", vic);
855 t = find_vic_id(vic);
856 if (t) {
857 print_timings(" ", t, suffix);
858 vec_tim.push_back(timings_ext(*t, suffix, ""));
859 } else {
860 printf(" %s: Unknown\n", suffix);
861 fail("Unknown VIC %u.\n", vic);
864 } else if (svr >= 129 && svr <= 144) {
865 sprintf(suffix, "DTD %3u", svr - 128);
866 if (svr >= cta.preparsed_total_dtds + 129) {
867 printf(" %s: Invalid\n", suffix);
868 fail("Invalid DTD %u.\n", svr - 128);
869 } else {
870 printf(" %s\n", suffix);
871 vec_tim.push_back(timings_ext(svr, suffix));
872 cta.has_svrs = true;
874 } else if (svr >= 145 && svr <= 160) {
875 sprintf(suffix, "VTDB %3u", svr - 144);
876 if (svr >= cta.preparsed_total_vtdbs + 145) {
877 printf(" %s: Invalid\n", suffix);
878 fail("Invalid VTDB %u.\n", svr - 144);
879 } else {
880 printf(" %s\n", suffix);
881 vec_tim.push_back(timings_ext(svr, suffix));
882 cta.has_svrs = true;
884 } else if (svr >= 161 && svr <= 175) {
885 sprintf(suffix, "RID %u@%up",
886 cta.preparsed_first_vfd.rid, vf_rate_values[svr - 160]);
887 if (!vfd_has_rate(cta.preparsed_first_vfd, svr - 160)) {
888 printf(" %s: Invalid\n", suffix);
889 fail("Invalid %s.\n", suffix);
890 } else {
891 printf(" %s\n", suffix);
892 vec_tim.push_back(timings_ext(svr, suffix));
893 cta.has_svrs = true;
895 } else if (svr == 254) {
896 sprintf(suffix, "T8VTDB");
897 if (!cta.preparsed_has_t8vtdb) {
898 printf(" %s: Invalid\n", suffix);
899 fail("Invalid T8VTDB.\n");
900 } else {
901 sprintf(suffix, "DMT 0x%02x", cta.preparsed_t8vtdb_dmt);
902 printf(" %s\n", suffix);
903 vec_tim.push_back(timings_ext(svr, suffix));
904 cta.has_svrs = true;
909 void edid_state::cta_vfpdb(const unsigned char *x, unsigned length)
911 unsigned i;
913 if (length == 0) {
914 fail("Empty Data Block with length %u.\n", length);
915 return;
917 cta.preferred_timings_vfpdb.clear();
918 for (i = 0; i < length; i++)
919 cta_print_svr(x[i], cta.preferred_timings_vfpdb);
922 void edid_state::cta_nvrdb(const unsigned char *x, unsigned length)
924 if (length == 0) {
925 fail("Empty Data Block with length %u.\n", length);
926 return;
929 unsigned char flags = length == 1 ? 0 : x[1];
931 cta.native_timing_nvrdb.clear();
932 cta_print_svr(x[0], cta.native_timing_nvrdb);
933 if ((flags & 1) && length < 6) {
934 fail("Data Block too short for Image Size (length = %u).\n", length);
935 return;
937 if (flags & 0x7e)
938 fail("Bits F41-F46 must be 0.\n");
939 if (!(flags & 1))
940 return;
942 unsigned w = (x[3] << 8) | x[2];
943 unsigned h = (x[5] << 8) | x[4];
945 if (!w || !h)
946 fail("Image Size has a zero width and/or height.\n");
948 if (flags & 0x80)
949 printf(" Image Size: %ux%u mm\n", w, h);
950 else
951 printf(" Image Size: %.1fx%.1f mm\n", w / 10.0, h / 10.0);
954 static std::string hdmi_latency2s(unsigned char l, bool is_video)
956 if (!l)
957 return "Unknown";
958 if (l == 0xff)
959 return is_video ? "Video not supported" : "Audio not supported";
960 return std::to_string(2 * (l - 1)) + " ms";
963 void edid_state::hdmi_latency(unsigned char vid_lat, unsigned char aud_lat,
964 bool is_ilaced)
966 const char *vid = is_ilaced ? "Interlaced video" : "Video";
967 const char *aud = is_ilaced ? "Interlaced audio" : "Audio";
969 printf(" %s latency: %s\n", vid, hdmi_latency2s(vid_lat, true).c_str());
970 printf(" %s latency: %s\n", aud, hdmi_latency2s(aud_lat, false).c_str());
972 if (vid_lat > 251 && vid_lat != 0xff)
973 fail("Invalid %s latency value %u.\n", vid, vid_lat);
974 if (aud_lat > 251 && aud_lat != 0xff)
975 fail("Invalid %s latency value %u.\n", aud, aud_lat);
977 if (!vid_lat || vid_lat > 251)
978 return;
979 if (!aud_lat || aud_lat > 251)
980 return;
982 unsigned vid_ms = 2 * (vid_lat - 1);
983 unsigned aud_ms = 2 * (aud_lat - 1);
985 // HDMI 2.0 latency checks for devices without HDMI output
986 if (aud_ms < vid_ms)
987 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
988 aud, vid, aud_ms, vid_ms);
989 else if (vid_ms + 20 < aud_ms)
990 warn("%s latency + 20 < %s latency (%u + 20 ms < %u ms). This is forbidden for devices without HDMI output.\n",
991 vid, aud, vid_ms, aud_ms);
992 else if (vid_ms < aud_ms)
993 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
994 vid, aud, vid_ms, aud_ms);
997 void edid_state::cta_hdmi_block(const unsigned char *x, unsigned length)
999 unsigned len_vic, len_3d;
1001 if (length < 1) {
1002 fail("Empty Data Block with length %u.\n", length);
1003 return;
1005 printf(" Source physical address: %x.%x.%x.%x\n", x[0] >> 4, x[0] & 0x0f,
1006 x[1] >> 4, x[1] & 0x0f);
1008 if (length < 3)
1009 return;
1011 if (x[2] & 0x80)
1012 printf(" Supports_AI\n");
1013 if (x[2] & 0x40)
1014 printf(" DC_48bit\n");
1015 if (x[2] & 0x20)
1016 printf(" DC_36bit\n");
1017 if (x[2] & 0x10)
1018 printf(" DC_30bit\n");
1019 if (x[2] & 0x08)
1020 printf(" DC_Y444\n");
1021 /* two reserved bits */
1022 if (x[2] & 0x01)
1023 printf(" DVI_Dual\n");
1025 if (length < 4)
1026 return;
1028 unsigned rate = x[3] * 5;
1029 printf(" Maximum TMDS clock: %u MHz\n", rate);
1030 cta.hdmi_max_rate = rate;
1031 if (rate > 340)
1032 fail("HDMI VSDB Max TMDS rate is > 340.\n");
1034 if (length < 5)
1035 return;
1037 if (x[4] & 0x0f) {
1038 printf(" Supported Content Types:\n");
1039 if (x[4] & 0x01)
1040 printf(" Graphics\n");
1041 if (x[4] & 0x02)
1042 printf(" Photo\n");
1043 if (x[4] & 0x04)
1044 printf(" Cinema\n");
1045 if (x[4] & 0x08)
1046 printf(" Game\n");
1049 unsigned b = 5;
1050 if (x[4] & 0x80) {
1051 hdmi_latency(x[b], x[b + 1], false);
1053 if (x[4] & 0x40) {
1054 if (x[b] == x[b + 2] &&
1055 x[b + 1] == x[b + 3])
1056 warn("Progressive and Interlaced latency values are identical, no need for both.\n");
1057 b += 2;
1058 hdmi_latency(x[b], x[b + 1], true);
1060 b += 2;
1063 if (!(x[4] & 0x20))
1064 return;
1066 bool mask = false;
1067 bool formats = false;
1069 printf(" Extended HDMI video details:\n");
1070 if (x[b] & 0x80)
1071 printf(" 3D present\n");
1072 if ((x[b] & 0x60) == 0x20) {
1073 printf(" All advertised VICs are 3D-capable\n");
1074 formats = true;
1076 if ((x[b] & 0x60) == 0x40) {
1077 printf(" 3D-capable-VIC mask present\n");
1078 formats = true;
1079 mask = true;
1081 switch (x[b] & 0x18) {
1082 case 0x00: break;
1083 case 0x08:
1084 printf(" Base EDID image size is aspect ratio\n");
1085 break;
1086 case 0x10:
1087 printf(" Base EDID image size is in units of 1 cm\n");
1088 break;
1089 case 0x18:
1090 printf(" Base EDID image size is in units of 5 cm\n");
1091 base.max_display_width_mm *= 5;
1092 base.max_display_height_mm *= 5;
1093 printf(" Recalculated image size: %u cm x %u cm\n",
1094 base.max_display_width_mm / 10, base.max_display_height_mm / 10);
1095 break;
1097 b++;
1098 len_vic = (x[b] & 0xe0) >> 5;
1099 len_3d = (x[b] & 0x1f) >> 0;
1100 b++;
1102 if (len_vic) {
1103 unsigned i;
1105 printf(" HDMI VICs:\n");
1106 for (i = 0; i < len_vic; i++) {
1107 unsigned char vic = x[b + i];
1108 const struct timings *t;
1110 if (vic && vic <= ARRAY_SIZE(edid_hdmi_mode_map)) {
1111 std::string suffix = "HDMI VIC " + std::to_string(vic);
1112 cta.supported_hdmi_vic_codes |= 1 << (vic - 1);
1113 t = find_vic_id(edid_hdmi_mode_map[vic - 1]);
1114 print_timings(" ", t, suffix.c_str());
1115 } else {
1116 printf(" Unknown (HDMI VIC %u)\n", vic);
1117 fail("Unknown HDMI VIC %u.\n", vic);
1121 b += len_vic;
1124 if (!len_3d)
1125 return;
1127 if (formats) {
1128 /* 3D_Structure_ALL_15..8 */
1129 if (x[b] & 0x80)
1130 printf(" 3D: Side-by-side (half, quincunx)\n");
1131 if (x[b] & 0x01)
1132 printf(" 3D: Side-by-side (half, horizontal)\n");
1133 /* 3D_Structure_ALL_7..0 */
1134 b++;
1135 if (x[b] & 0x40)
1136 printf(" 3D: Top-and-bottom\n");
1137 if (x[b] & 0x20)
1138 printf(" 3D: L + depth + gfx + gfx-depth\n");
1139 if (x[b] & 0x10)
1140 printf(" 3D: L + depth\n");
1141 if (x[b] & 0x08)
1142 printf(" 3D: Side-by-side (full)\n");
1143 if (x[b] & 0x04)
1144 printf(" 3D: Line-alternative\n");
1145 if (x[b] & 0x02)
1146 printf(" 3D: Field-alternative\n");
1147 if (x[b] & 0x01)
1148 printf(" 3D: Frame-packing\n");
1149 b++;
1150 len_3d -= 2;
1153 if (mask) {
1154 int max_idx = -1;
1155 unsigned i;
1157 printf(" 3D VIC indices that support these capabilities:\n");
1158 /* worst bit ordering ever */
1159 for (i = 0; i < 8; i++)
1160 if (x[b + 1] & (1 << i)) {
1161 print_vic_index(" ", i, "");
1162 max_idx = i;
1164 for (i = 0; i < 8; i++)
1165 if (x[b] & (1 << i)) {
1166 print_vic_index(" ", i + 8, "");
1167 max_idx = i + 8;
1169 b += 2;
1170 len_3d -= 2;
1171 if (max_idx >= (int)cta.preparsed_svds[0].size())
1172 fail("HDMI 3D VIC indices max index %d > %u (#SVDs).\n",
1173 max_idx + 1, cta.preparsed_svds[0].size());
1177 * list of nibbles:
1178 * 2D_VIC_Order_X
1179 * 3D_Structure_X
1180 * (optionally: 3D_Detail_X and reserved)
1182 if (!len_3d)
1183 return;
1185 unsigned end = b + len_3d;
1186 int max_idx = -1;
1188 printf(" 3D VIC indices with specific capabilities:\n");
1189 while (b < end) {
1190 unsigned char idx = x[b] >> 4;
1191 std::string s;
1193 if (idx > max_idx)
1194 max_idx = idx;
1195 switch (x[b] & 0x0f) {
1196 case 0: s = "frame packing"; break;
1197 case 1: s = "field alternative"; break;
1198 case 2: s = "line alternative"; break;
1199 case 3: s = "side-by-side (full)"; break;
1200 case 4: s = "L + depth"; break;
1201 case 5: s = "L + depth + gfx + gfx-depth"; break;
1202 case 6: s = "top-and-bottom"; break;
1203 case 8:
1204 s = "side-by-side";
1205 switch (x[b + 1] >> 4) {
1206 case 0x00: s += ", any subsampling"; break;
1207 case 0x01: s += ", horizontal"; break;
1208 case 0x02: case 0x03: case 0x04: case 0x05:
1209 s += ", not in use";
1210 fail("not-in-use 3D_Detail_X value 0x%02x.\n",
1211 x[b + 1] >> 4);
1212 break;
1213 case 0x06: s += ", all quincunx combinations"; break;
1214 case 0x07: s += ", quincunx odd/left, odd/right"; break;
1215 case 0x08: s += ", quincunx odd/left, even/right"; break;
1216 case 0x09: s += ", quincunx even/left, odd/right"; break;
1217 case 0x0a: s += ", quincunx even/left, even/right"; break;
1218 default:
1219 s += ", reserved";
1220 fail("reserved 3D_Detail_X value 0x%02x.\n",
1221 x[b + 1] >> 4);
1222 break;
1224 break;
1225 default:
1226 s = "unknown (";
1227 s += utohex(x[b] & 0x0f) + ")";
1228 fail("Unknown 3D_Structure_X value 0x%02x.\n", x[b] & 0x0f);
1229 break;
1231 print_vic_index(" ", idx, s.c_str());
1232 if ((x[b] & 0x0f) >= 8)
1233 b++;
1234 b++;
1236 if (max_idx >= (int)cta.preparsed_svds[0].size())
1237 fail("HDMI 2D VIC indices max index %d > %u (#SVDs).\n",
1238 max_idx + 1, cta.preparsed_svds[0].size());
1241 static const char *max_frl_rates[] = {
1242 "Not Supported",
1243 "3 Gbps per lane on 3 lanes",
1244 "3 and 6 Gbps per lane on 3 lanes",
1245 "3 and 6 Gbps per lane on 3 lanes, 6 Gbps on 4 lanes",
1246 "3 and 6 Gbps per lane on 3 lanes, 6 and 8 Gbps on 4 lanes",
1247 "3 and 6 Gbps per lane on 3 lanes, 6, 8 and 10 Gbps on 4 lanes",
1248 "3 and 6 Gbps per lane on 3 lanes, 6, 8, 10 and 12 Gbps on 4 lanes",
1251 static const char *dsc_max_slices[] = {
1252 "Not Supported",
1253 "up to 1 slice and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1254 "up to 2 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1255 "up to 4 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1256 "up to 8 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1257 "up to 8 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1258 "up to 12 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1259 "up to 12 slices and up to (600 MHz/Ksliceadjust) pixel clock per slice",
1262 static void cta_hf_eeodb(const unsigned char *x, unsigned length)
1264 printf(" EDID Extension Block Count: %u\n", x[0]);
1265 if (length != 1)
1266 fail("Block is too long.\n");
1267 if (x[0] <= 1)
1268 fail("Extension Block Count == %u.\n", x[0]);
1271 void edid_state::cta_hf_scdb(const unsigned char *x, unsigned length)
1273 unsigned rate = x[1] * 5;
1274 unsigned v;
1276 printf(" Version: %u\n", x[0]);
1277 if (rate) {
1278 printf(" Maximum TMDS Character Rate: %u MHz\n", rate);
1279 if (rate <= 340 || rate > 600)
1280 fail("Max TMDS rate is > 0 and <= 340 or > 600.\n");
1281 if (rate < cta.hdmi_max_rate)
1282 fail("HDMI Forum VSDB rate < HDMI VSDB rate.\n");
1283 else
1284 cta.hdmi_max_rate = rate;
1286 if (x[2] & 0x80)
1287 printf(" SCDC Present\n");
1288 if (x[2] & 0x40)
1289 printf(" SCDC Read Request Capable\n");
1290 if (x[2] & 0x20)
1291 printf(" Supports Cable Status\n");
1292 if (x[2] & 0x10)
1293 printf(" Supports Color Content Bits Per Component Indication\n");
1294 if (x[2] & 0x08)
1295 printf(" Supports scrambling for <= 340 Mcsc\n");
1296 if (x[2] & 0x04)
1297 printf(" Supports 3D Independent View signaling\n");
1298 if (x[2] & 0x02)
1299 printf(" Supports 3D Dual View signaling\n");
1300 if (x[2] & 0x01)
1301 printf(" Supports 3D OSD Disparity signaling\n");
1302 if (x[3] & 0xf0) {
1303 unsigned max_frl_rate = x[3] >> 4;
1305 printf(" Max Fixed Rate Link: ");
1306 if (max_frl_rate < ARRAY_SIZE(max_frl_rates)) {
1307 printf("%s\n", max_frl_rates[max_frl_rate]);
1308 } else {
1309 printf("Unknown (0x%02x)\n", max_frl_rate);
1310 fail("Unknown Max Fixed Rate Link (0x%02x).\n", max_frl_rate);
1312 if (max_frl_rate == 1 && rate < 300)
1313 fail("Max Fixed Rate Link is 1, but Max TMDS rate < 300.\n");
1314 else if (max_frl_rate >= 2 && rate < 600)
1315 fail("Max Fixed Rate Link is >= 2, but Max TMDS rate < 600.\n");
1317 // FIXME:
1318 // Currently I do not really know how to translate the
1319 // Max FRL value to an equivalent max clock frequency.
1320 // So reset this field to 0 to skip any clock rate checks.
1321 cta.hdmi_max_rate = 0;
1323 if (x[3] & 0x08)
1324 printf(" Supports UHD VIC\n");
1325 if (x[3] & 0x04)
1326 printf(" Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1327 if (x[3] & 0x02)
1328 printf(" Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1329 if (x[3] & 0x01)
1330 printf(" Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1332 if (length <= 4)
1333 return;
1335 if (x[4] & 0x80)
1336 printf(" Supports FAPA End Extended\n");
1337 if (x[4] & 0x40)
1338 printf(" Supports QMS\n");
1339 if (x[4] & 0x20)
1340 printf(" Supports Mdelta\n");
1341 if (x[4] & 0x10) {
1342 printf(" Supports media rates below VRRmin (CinemaVRR, deprecated)\n");
1343 warn("CinemaVRR is deprecated and must be cleared.\n");
1345 if (x[4] & 0x08)
1346 printf(" Supports negative Mvrr values\n");
1347 if (x[4] & 0x04)
1348 printf(" Supports Fast Vactive\n");
1349 if (x[4] & 0x02)
1350 printf(" Supports Auto Low-Latency Mode\n");
1351 if (x[4] & 0x01)
1352 printf(" Supports a FAPA in blanking after first active video line\n");
1354 if (length <= 5)
1355 return;
1357 v = x[5] & 0x3f;
1358 if (v) {
1359 printf(" VRRmin: %u Hz\n", v);
1360 if (v > 48)
1361 fail("VRRmin > 48.\n");
1363 v = (x[5] & 0xc0) << 2 | x[6];
1364 if (v) {
1365 printf(" VRRmax: %u Hz\n", v);
1366 if (!(x[5] & 0x3f))
1367 fail("VRRmin == 0, but VRRmax isn't.\n");
1368 else if (v < 100)
1369 fail("VRRmax < 100.\n");
1372 if (length <= 7)
1373 return;
1375 if (x[7] & 0x80)
1376 printf(" Supports VESA DSC 1.2a compression\n");
1377 if (x[7] & 0x40)
1378 printf(" Supports Compressed Video Transport for 4:2:0 Pixel Encoding\n");
1379 if (x[7] & 0x20)
1380 printf(" Supports QMS TFRmax\n");
1381 if (x[7] & 0x10)
1382 printf(" Supports QMS TFRmin\n");
1383 if (x[7] & 0x08)
1384 printf(" Supports Compressed Video Transport at any valid 1/16th bit bpp\n");
1385 if (x[7] & 0x04)
1386 printf(" Supports 16 bpc Compressed Video Transport\n");
1387 if (x[7] & 0x02)
1388 printf(" Supports 12 bpc Compressed Video Transport\n");
1389 if (x[7] & 0x01)
1390 printf(" Supports 10 bpc Compressed Video Transport\n");
1391 if (x[8] & 0xf) {
1392 unsigned max_slices = x[8] & 0xf;
1394 printf(" DSC Max Slices: ");
1395 if (max_slices < ARRAY_SIZE(dsc_max_slices)) {
1396 printf("%s\n", dsc_max_slices[max_slices]);
1397 } else {
1398 printf("Unknown (%u), interpreted as: %s\n", max_slices,
1399 dsc_max_slices[7]);
1400 warn("Unknown DSC Max Slices (%u).\n", max_slices);
1403 if (x[8] & 0xf0) {
1404 unsigned max_frl_rate = x[8] >> 4;
1406 printf(" DSC Max Fixed Rate Link: ");
1407 if (max_frl_rate < ARRAY_SIZE(max_frl_rates)) {
1408 printf("%s\n", max_frl_rates[max_frl_rate]);
1409 } else {
1410 printf("Unknown (0x%02x)\n", max_frl_rate);
1411 fail("Unknown DSC Max Fixed Rate Link (0x%02x).\n", max_frl_rate);
1414 if (x[9] & 0x3f)
1415 printf(" Maximum number of bytes in a line of chunks: %u\n",
1416 1024 * (1 + (x[9] & 0x3f)));
1419 // Convert a PQ value (0-1) to cd/m^2 aka nits (0-10000)
1420 static double pq2nits(double pq)
1422 const double m1 = 2610.0 / 16384.0;
1423 const double m2 = 128.0 * (2523.0 / 4096.0);
1424 const double c1 = 3424.0 / 4096.0;
1425 const double c2 = 32.0 * (2413.0 / 4096.0);
1426 const double c3 = 32.0 * (2392.0 / 4096.0);
1427 double e = pow(pq, 1.0 / m2);
1428 double v = e - c1;
1430 if (v < 0)
1431 v = 0;
1432 v /= c2 - c3 * e;
1433 v = pow(v, 1.0 / m1);
1434 return v * 10000.0;
1437 static double perc2d(unsigned char x)
1439 double m = x >> 2;
1440 double e = x & 3;
1442 return 100.0 * (m / 64.0) * pow(10, -e);
1445 static void cta_hf_sbtmdb(const unsigned char *x, unsigned length)
1447 int len = length;
1449 if (!length)
1450 fail("Block is too short.\n");
1451 printf(" Version: %d\n", x[0] & 0xf);
1452 switch ((x[0] >> 5) & 3) {
1453 case 0:
1454 printf(" Does not support a General RDM format\n");
1455 break;
1456 case 1:
1457 printf(" Supports an SDR-range General RDM format\n");
1458 break;
1459 case 2:
1460 printf(" Supports an HDR-range General RDM format\n");
1461 break;
1462 default:
1463 fail("Invalid GRDM Support value.\n");
1464 break;
1466 if (!(x[0] & 0x80))
1467 return;
1469 bool uses_hgig_drdm = true;
1471 printf(" Supports a D-RDM format\n");
1472 if (x[1] & 0x10)
1473 printf(" Use HGIG D-RDM\n");
1474 switch (x[1] & 7) {
1475 case 0:
1476 printf(" HGIG D-RDM is not used\n");
1477 uses_hgig_drdm = false;
1478 break;
1479 case 1:
1480 printf(" PBnits[0] = 600 cd/m^2\n");
1481 break;
1482 case 2:
1483 printf(" PBnits[0] = 1000 cd/m^2\n");
1484 break;
1485 case 3:
1486 printf(" PBnits[0] = 4000 cd/m^2\n");
1487 break;
1488 case 4:
1489 printf(" PBnits[0] = 10000 cd/m^2\n");
1490 break;
1491 default:
1492 fail("Invalid HGIG D-DRM value.\n");
1493 break;
1496 bool has_chromaticities = false;
1498 if (x[1] & 0x20)
1499 printf(" MaxRGB\n");
1500 switch (x[1] >> 6) {
1501 case 0:
1502 printf(" Gamut is explicit\n");
1503 has_chromaticities = true;
1504 break;
1505 case 1:
1506 printf(" Gamut is Rec. ITU-R BT.709\n");
1507 break;
1508 case 2:
1509 printf(" Gamut is SMPTE ST 2113\n");
1510 break;
1511 default:
1512 printf(" Gamut is Rec. ITU-R BT.2020\n");
1513 break;
1515 x += 2;
1516 len -= 2;
1517 if (has_chromaticities) {
1518 printf(" Red: (%.5f, %.5f)\n", chrom2d(x), chrom2d(x + 2));
1519 printf(" Green: (%.5f, %.5f)\n", chrom2d(x + 4), chrom2d(x + 6));
1520 printf(" Blue: (%.5f, %.5f)\n", chrom2d(x + 8), chrom2d(x + 10));
1521 printf(" White: (%.5f, %.5f)\n", chrom2d(x + 12), chrom2d(x + 14));
1522 x += 16;
1523 len -= 16;
1525 if (uses_hgig_drdm)
1526 return;
1527 printf(" Min Brightness 10: %.8f cd/m^2\n", pq2nits((x[0] << 1) / 4095.0));
1528 printf(" Peak Brightness 100: %u cd/m^2\n", (unsigned)pq2nits((x[1] << 4) / 4095.0));
1529 x += 2;
1530 len -= 2;
1531 if (len <= 0)
1532 return;
1533 printf(" Percentage of Peak Brightness P0: %.2f%%\n", perc2d(x[0]));
1534 printf(" Peak Brightness P0: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1535 x += 2;
1536 len -= 2;
1537 if (len <= 0)
1538 return;
1539 printf(" Percentage of Peak Brightness P1: %.2f%%\n", perc2d(x[0]));
1540 printf(" Peak Brightness P1: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1541 x += 2;
1542 len -= 2;
1543 if (len <= 0)
1544 return;
1545 printf(" Percentage of Peak Brightness P2: %.2f%%\n", perc2d(x[0]));
1546 printf(" Peak Brightness P2: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1547 x += 2;
1548 len -= 2;
1549 if (len <= 0)
1550 return;
1551 printf(" Percentage of Peak Brightness P3: %.2f%%\n", perc2d(x[0]));
1552 printf(" Peak Brightness P3: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1555 static void cta_amd(const unsigned char *x, unsigned length)
1557 // These Freesync values are reversed engineered by looking
1558 // at existing EDIDs.
1559 printf(" Version: %u.%u\n", x[0], x[1]);
1560 printf(" Minimum Refresh Rate: %u Hz\n", x[2]);
1561 printf(" Maximum Refresh Rate: %u Hz\n", x[3]);
1562 // Freesync 1.x flags
1563 // One or more of the 0xe6 bits signal that the VESA MCCS
1564 // protocol is used to switch the Freesync range
1565 printf(" Flags 1.x: 0x%02x%s\n", x[4],
1566 (x[4] & 0xe6) ? " (MCCS)" : "");
1567 if (length >= 10) {
1568 // Freesync 2.x flags
1569 // Bit 2 no doubt indicates if the monitor supports Local Dimming
1570 // There are probably also bits to signal support of the
1571 // FreeSync2_scRGB and FreeSync2_Gamma22 HDR display modes.
1572 // I suspect bits 0 and 1.
1573 printf(" Flags 2.x: 0x%02x\n", x[5]);
1574 // The AMD tone mapping tutorial referred to in the URL below
1575 // mentions that the Freesync HDR info reports max/min
1576 // luminance of the monitor with and without local dimming.
1578 // https://gpuopen.com/learn/using-amd-freesync-premium-pro-hdr-code-samples/
1580 // So I assume that the first two luminance values are
1581 // the max/min luminance of the display and the next two
1582 // luminance values are the max/min luminance values when
1583 // local dimming is disabled. The values I get seem to
1584 // support that.
1585 printf(" Maximum luminance: %u (%.3f cd/m^2)\n",
1586 x[6], 50.0 * pow(2, x[6] / 32.0));
1587 printf(" Minimum luminance: %u (%.3f cd/m^2)\n",
1588 x[7], (50.0 * pow(2, x[6] / 32.0)) * pow(x[7] / 255.0, 2) / 100.0);
1589 if (x[5] & 4) {
1590 // One or both bytes can be 0. The meaning of that
1591 // is unknown.
1592 printf(" Maximum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1593 x[8], 50.0 * pow(2, x[8] / 32.0));
1594 printf(" Minimum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1595 x[9], (50.0 * pow(2, x[8] / 32.0)) * pow(x[9] / 255.0, 2) / 100.0);
1596 } else {
1597 // These bytes are always 0x08 0x2f. If these values
1598 // represent max/min luminance as well, then these
1599 // would map to 59.460 and 0.020 cd/m^2 respectively.
1600 // I wonder if this somehow relates to SDR.
1601 printf(" Unknown: 0x%02x 0x%02x\n", x[8], x[9]);
1606 static std::string display_use_case(unsigned char x)
1608 switch (x) {
1609 case 1: return "Test equipment";
1610 case 2: return "Generic display";
1611 case 3: return "Television display";
1612 case 4: return "Desktop productivity display";
1613 case 5: return "Desktop gaming display";
1614 case 6: return "Presentation display";
1615 case 7: return "Virtual reality headset";
1616 case 8: return "Augmented reality";
1617 case 16: return "Video wall display";
1618 case 17: return "Medical imaging display";
1619 case 18: return "Dedicated gaming display";
1620 case 19: return "Dedicated video monitor display";
1621 case 20: return "Accessory display";
1622 default: break;
1624 fail("Unknown Display product primary use case 0x%02x.\n", x);
1625 return "Unknown";
1628 static void cta_microsoft(const unsigned char *x, unsigned length)
1630 // This VSDB is documented at:
1631 // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
1632 printf(" Version: %u\n", x[0]);
1633 if (x[0] > 2) {
1634 // In version 1 and 2 these bits should always be set to 0.
1635 printf(" Desktop Usage: %u\n", (x[1] >> 6) & 1);
1636 printf(" Third-Party Usage: %u\n", (x[1] >> 5) & 1);
1638 printf(" Display Product Primary Use Case: %s\n",
1639 display_use_case(x[1] & 0x1f).c_str());
1640 printf(" Container ID: %s\n", containerid2s(x + 2).c_str());
1643 static void cta_hdr10plus(const unsigned char *x, unsigned length)
1645 if (length == 0) {
1646 fail("Empty Data Block with length %u.\n", length);
1647 return;
1649 printf(" Application Version: %u\n", x[0] & 3);
1650 printf(" Full Frame Peak Luminance Index: %u\n", (x[0] >> 2) & 3);
1651 printf(" Peak Luminance Index: %u\n", x[0] >> 4);
1652 hex_block(" ", x + 1, length - 1);
1655 static void cta_dolby_video(const unsigned char *x, unsigned length)
1657 unsigned char version = (x[0] >> 5) & 0x07;
1659 printf(" Version: %u (%u bytes)\n", version, length + 5);
1660 if (x[0] & 0x01)
1661 printf(" Supports YUV422 12 bit\n");
1663 if (version == 0) {
1664 if (x[0] & 0x02)
1665 printf(" Supports 2160p60\n");
1666 if (x[0] & 0x04)
1667 printf(" Supports global dimming\n");
1668 unsigned char dm_version = x[16];
1669 printf(" DM Version: %u.%u\n", dm_version >> 4, dm_version & 0xf);
1670 unsigned pq = (x[14] << 4) | (x[13] >> 4);
1671 printf(" Target Min PQ: %u (%.8f cd/m^2)\n", pq, pq2nits(pq / 4095.0));
1672 pq = (x[15] << 4) | (x[13] & 0xf);
1673 printf(" Target Max PQ: %u (%u cd/m^2)\n", pq, (unsigned)pq2nits(pq / 4095.0));
1674 printf(" Rx, Ry: %.8f, %.8f\n",
1675 ((x[1] >> 4) | (x[2] << 4)) / 4096.0,
1676 ((x[1] & 0xf) | (x[3] << 4)) / 4096.0);
1677 printf(" Gx, Gy: %.8f, %.8f\n",
1678 ((x[4] >> 4) | (x[5] << 4)) / 4096.0,
1679 ((x[4] & 0xf) | (x[6] << 4)) / 4096.0);
1680 printf(" Bx, By: %.8f, %.8f\n",
1681 ((x[7] >> 4) | (x[8] << 4)) / 4096.0,
1682 ((x[7] & 0xf) | (x[9] << 4)) / 4096.0);
1683 printf(" Wx, Wy: %.8f, %.8f\n",
1684 ((x[10] >> 4) | (x[11] << 4)) / 4096.0,
1685 ((x[10] & 0xf) | (x[12] << 4)) / 4096.0);
1686 return;
1689 if (version == 1) {
1690 if (x[0] & 0x02)
1691 printf(" Supports 2160p60\n");
1692 if (x[1] & 0x01)
1693 printf(" Supports global dimming\n");
1694 unsigned char dm_version = (x[0] >> 2) & 0x07;
1695 printf(" DM Version: %u.x\n", dm_version + 2);
1696 printf(" Colorimetry: %s\n", (x[2] & 0x01) ? "P3-D65" : "ITU-R BT.709");
1697 printf(" Low Latency: %s\n", (x[3] & 0x01) ? "Standard + Low Latency" : "Only Standard");
1698 double lm = (x[2] >> 1) / 127.0;
1699 printf(" Target Min Luminance: %.8f cd/m^2\n", lm * lm);
1700 printf(" Target Max Luminance: %u cd/m^2\n", 100 + (x[1] >> 1) * 50);
1701 if (length == 10) {
1702 printf(" Rx, Ry: %.8f, %.8f\n", x[4] / 256.0, x[5] / 256.0);
1703 printf(" Gx, Gy: %.8f, %.8f\n", x[6] / 256.0, x[7] / 256.0);
1704 printf(" Bx, By: %.8f, %.8f\n", x[8] / 256.0, x[9] / 256.0);
1705 } else {
1706 double xmin = 0.625;
1707 double xstep = (0.74609375 - xmin) / 31.0;
1708 double ymin = 0.25;
1709 double ystep = (0.37109375 - ymin) / 31.0;
1711 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1712 xmin + xstep * (x[6] >> 3),
1713 ymin + ystep * (((x[6] & 0x7) << 2) | (x[4] & 0x01) | ((x[5] & 0x01) << 1)));
1714 xstep = 0.49609375 / 127.0;
1715 ymin = 0.5;
1716 ystep = (0.99609375 - ymin) / 127.0;
1717 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1718 xstep * (x[4] >> 1), ymin + ystep * (x[5] >> 1));
1719 xmin = 0.125;
1720 xstep = (0.15234375 - xmin) / 7.0;
1721 ymin = 0.03125;
1722 ystep = (0.05859375 - ymin) / 7.0;
1723 printf(" Unique Bx, By: %.8f, %.8f\n",
1724 xmin + xstep * (x[3] >> 5),
1725 ymin + ystep * ((x[3] >> 2) & 0x07));
1727 return;
1730 if (version == 2) {
1731 if (x[0] & 0x02)
1732 printf(" Supports Backlight Control\n");
1733 if (x[1] & 0x04)
1734 printf(" Supports global dimming\n");
1735 unsigned char dm_version = (x[0] >> 2) & 0x07;
1736 printf(" DM Version: %u.x\n", dm_version + 2);
1737 printf(" Backlt Min Luma: %u cd/m^2\n", 25 + (x[1] & 0x03) * 25);
1738 printf(" Interface: ");
1739 switch (x[2] & 0x03) {
1740 case 0: printf("Low-Latency\n"); break;
1741 case 1: printf("Low-Latency + Low-Latency-HDMI\n"); break;
1742 case 2: printf("Standard + Low-Latency\n"); break;
1743 case 3: printf("Standard + Low-Latency + Low-Latency-HDMI\n"); break;
1745 printf(" Supports 10b 12b 444: ");
1746 switch ((x[3] & 0x01) << 1 | (x[4] & 0x01)) {
1747 case 0: printf("Not supported\n"); break;
1748 case 1: printf("10 bit\n"); break;
1749 case 2: printf("12 bit\n"); break;
1750 case 3: printf("Reserved\n"); break;
1753 unsigned pq = 20 * (x[1] >> 3);
1754 printf(" Target Min PQ v2: %u (%.8f cd/m^2)\n", pq, pq2nits(pq / 4095.0));
1755 pq = 2055 + 65 * (x[2] >> 3);
1756 printf(" Target Max PQ v2: %u (%u cd/m^2)\n", pq, (unsigned)pq2nits(pq / 4095.0));
1758 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1759 0.625 + (x[5] >> 3) / 256.0,
1760 0.25 + (x[6] >> 3) / 256.0);
1761 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1762 (x[3] >> 1) / 256.0,
1763 0.5 + (x[4] >> 1) / 256.0);
1764 printf(" Unique Bx, By: %.8f, %.8f\n",
1765 0.125 + (x[5] & 0x07) / 256.0,
1766 0.03125 + (x[6] & 0x07) / 256.0);
1770 static void cta_dolby_audio(const unsigned char *x, unsigned length)
1772 unsigned char version = 1 + (x[0] & 0x07);
1774 printf(" Version: %u (%u bytes)\n", version, length + 5);
1775 if (x[0] & 0x80)
1776 printf(" Headphone playback only\n");
1777 if (x[0] & 0x40)
1778 printf(" Height speaker zone present\n");
1779 if (x[0] & 0x20)
1780 printf(" Surround speaker zone present\n");
1781 if (x[0] & 0x10)
1782 printf(" Center speaker zone present\n");
1783 if (x[1] & 0x01)
1784 printf(" Supports Dolby MAT PCM decoding at 48 kHz only, does not support TrueHD\n");
1787 static void cta_uhda_fmm(const unsigned char *x, unsigned length)
1789 printf(" Filmmaker Mode Content Type: %u\n", x[0]);
1790 printf(" Filmmaker Mode Content Subtype: %u\n", x[1]);
1793 const char *cta_speaker_map[] = {
1794 "FL/FR - Front Left/Right",
1795 "LFE1 - Low Frequency Effects 1",
1796 "FC - Front Center",
1797 "BL/BR - Back Left/Right",
1798 "BC - Back Center",
1799 "FLc/FRc - Front Left/Right of Center",
1800 "RLC/RRC - Rear Left/Right of Center (Deprecated)",
1801 "FLw/FRw - Front Left/Right Wide",
1803 "TpFL/TpFR - Top Front Left/Right",
1804 "TpC - Top Center",
1805 "TpFC - Top Front Center",
1806 "LS/RS - Left/Right Surround",
1807 "LFE2 - Low Frequency Effects 2",
1808 "TpBC - Top Back Center",
1809 "SiL/SiR - Side Left/Right",
1810 "TpSiL/TpSiR - Top Side Left/Right",
1812 "TpBL/TpBR - Top Back Left/Right",
1813 "BtFC - Bottom Front Center",
1814 "BtFL/BtFR - Bottom Front Left/Right",
1815 "TpLS/TpRS - Top Left/Right Surround (Deprecated for CTA-861)",
1816 "LSd/RSd - Left/Right Surround Direct (HDMI only)",
1817 NULL
1820 static void cta_sadb(const unsigned char *x, unsigned length)
1822 unsigned sad_deprecated = 0x7f000;
1823 unsigned sad;
1824 unsigned i;
1826 if (length < 3) {
1827 fail("Empty Data Block with length %u.\n", length);
1828 return;
1831 sad = ((x[2] << 16) | (x[1] << 8) | x[0]);
1833 for (i = 0; cta_speaker_map[i]; i++) {
1834 bool deprecated = sad_deprecated & (1 << i);
1836 if ((sad >> i) & 1)
1837 printf(" %s%s\n", cta_speaker_map[i],
1838 deprecated ? " (Deprecated, use the RCDB)" : "");
1840 if (sad & 0xff040)
1841 warn("Specifies deprecated speakers.\n");
1844 static void cta_vesa_dtcdb(const unsigned char *x, unsigned length)
1846 if (length != 7 && length != 15 && length != 31) {
1847 fail("Invalid length %u.\n", length);
1848 return;
1851 switch (x[0] >> 6) {
1852 case 0: printf(" White"); break;
1853 case 1: printf(" Red"); break;
1854 case 2: printf(" Green"); break;
1855 case 3: printf(" Blue"); break;
1857 unsigned v = x[0] & 0x3f;
1858 printf(" transfer characteristics: %u", v);
1859 for (unsigned i = 1; i < length; i++)
1860 printf(" %u", v += x[i]);
1861 printf(" 1023\n");
1864 static void cta_vesa_vdddb(const unsigned char *x, unsigned length)
1866 if (length != 30) {
1867 fail("Invalid length %u.\n", length);
1868 return;
1871 printf(" Interface Type: ");
1872 unsigned char v = x[0];
1873 switch (v >> 4) {
1874 case 0: printf("Analog (");
1875 switch (v & 0xf) {
1876 case 0: printf("15HD/VGA"); break;
1877 case 1: printf("VESA NAVI-V (15HD)"); break;
1878 case 2: printf("VESA NAVI-D"); break;
1879 default: printf("Reserved"); break;
1881 printf(")\n");
1882 break;
1883 case 1: printf("LVDS %u lanes", v & 0xf); break;
1884 case 2: printf("RSDS %u lanes", v & 0xf); break;
1885 case 3: printf("DVI-D %u channels", v & 0xf); break;
1886 case 4: printf("DVI-I analog"); break;
1887 case 5: printf("DVI-I digital %u channels", v & 0xf); break;
1888 case 6: printf("HDMI-A"); break;
1889 case 7: printf("HDMI-B"); break;
1890 case 8: printf("MDDI %u channels", v & 0xf); break;
1891 case 9: printf("DisplayPort %u channels", v & 0xf); break;
1892 case 10: printf("IEEE-1394"); break;
1893 case 11: printf("M1 analog"); break;
1894 case 12: printf("M1 digital %u channels", v & 0xf); break;
1895 default: printf("Reserved"); break;
1897 printf("\n");
1899 printf(" Interface Standard Version: %u.%u\n", x[1] >> 4, x[1] & 0xf);
1900 printf(" Content Protection Support: ");
1901 switch (x[2]) {
1902 case 0: printf("None\n"); break;
1903 case 1: printf("HDCP\n"); break;
1904 case 2: printf("DTCP\n"); break;
1905 case 3: printf("DPCP\n"); break;
1906 default: printf("Reserved\n"); break;
1909 printf(" Minimum Clock Frequency: %u MHz\n", x[3] >> 2);
1910 printf(" Maximum Clock Frequency: %u MHz\n", ((x[3] & 0x03) << 8) | x[4]);
1911 printf(" Device Native Pixel Format: %ux%u\n",
1912 x[5] | (x[6] << 8), x[7] | (x[8] << 8));
1913 printf(" Aspect Ratio: %.2f\n", (100 + x[9]) / 100.0);
1914 v = x[0x0a];
1915 printf(" Default Orientation: ");
1916 switch ((v & 0xc0) >> 6) {
1917 case 0x00: printf("Landscape\n"); break;
1918 case 0x01: printf("Portrait\n"); break;
1919 case 0x02: printf("Not Fixed\n"); break;
1920 case 0x03: printf("Undefined\n"); break;
1922 printf(" Rotation Capability: ");
1923 switch ((v & 0x30) >> 4) {
1924 case 0x00: printf("None\n"); break;
1925 case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
1926 case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
1927 case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
1929 printf(" Zero Pixel Location: ");
1930 switch ((v & 0x0c) >> 2) {
1931 case 0x00: printf("Upper Left\n"); break;
1932 case 0x01: printf("Upper Right\n"); break;
1933 case 0x02: printf("Lower Left\n"); break;
1934 case 0x03: printf("Lower Right\n"); break;
1936 printf(" Scan Direction: ");
1937 switch (v & 0x03) {
1938 case 0x00: printf("Not defined\n"); break;
1939 case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
1940 case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
1941 case 0x03: printf("Reserved\n");
1942 fail("Scan Direction used the reserved value 0x03.\n");
1943 break;
1945 printf(" Subpixel Information: ");
1946 switch (x[0x0b]) {
1947 case 0x00: printf("Not defined\n"); break;
1948 case 0x01: printf("RGB vertical stripes\n"); break;
1949 case 0x02: printf("RGB horizontal stripes\n"); break;
1950 case 0x03: printf("Vertical stripes using primary order\n"); break;
1951 case 0x04: printf("Horizontal stripes using primary order\n"); break;
1952 case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
1953 case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
1954 case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
1955 case 0x08: printf("Mosaic\n"); break;
1956 case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
1957 case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
1958 case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
1959 case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
1960 default: printf("Reserved\n"); break;
1962 printf(" Horizontal and vertical dot/pixel pitch: %.2f x %.2f mm\n",
1963 (double)(x[0x0c]) / 100.0, (double)(x[0x0d]) / 100.0);
1964 v = x[0x0e];
1965 printf(" Dithering: ");
1966 switch (v >> 6) {
1967 case 0: printf("None\n"); break;
1968 case 1: printf("Spatial\n"); break;
1969 case 2: printf("Temporal\n"); break;
1970 case 3: printf("Spatial and Temporal\n"); break;
1972 printf(" Direct Drive: %s\n", (v & 0x20) ? "Yes" : "No");
1973 printf(" Overdrive %srecommended\n", (v & 0x10) ? "not " : "");
1974 printf(" Deinterlacing: %s\n", (v & 0x08) ? "Yes" : "No");
1976 v = x[0x0f];
1977 printf(" Audio Support: %s\n", (v & 0x80) ? "Yes" : "No");
1978 printf(" Separate Audio Inputs Provided: %s\n", (v & 0x40) ? "Yes" : "No");
1979 printf(" Audio Input Override: %s\n", (v & 0x20) ? "Yes" : "No");
1980 v = x[0x10];
1981 if (v)
1982 printf(" Audio Delay: %s%u ms\n", (v & 0x80) ? "" : "-", (v & 0x7f) * 2);
1983 else
1984 printf(" Audio Delay: no information provided\n");
1985 v = x[0x11];
1986 printf(" Frame Rate/Mode Conversion: ");
1987 switch (v >> 6) {
1988 case 0: printf("None\n"); break;
1989 case 1: printf("Single Buffering\n"); break;
1990 case 2: printf("Double Buffering\n"); break;
1991 case 3: printf("Advanced Frame Rate Conversion\n"); break;
1993 if (v & 0x3f)
1994 printf(" Frame Rate Range: %u fps +/- %u fps\n",
1995 x[0x12], v & 0x3f);
1996 else
1997 printf(" Nominal Frame Rate: %u fps\n", x[0x12]);
1998 printf(" Color Bit Depth: %u @ interface, %u @ display\n",
1999 (x[0x13] >> 4) + 1, (x[0x13] & 0xf) + 1);
2000 v = x[0x15] & 3;
2001 if (v) {
2002 printf(" Additional Primary Chromaticities:\n");
2003 unsigned col_x = (x[0x16] << 2) | (x[0x14] >> 6);
2004 unsigned col_y = (x[0x17] << 2) | ((x[0x14] >> 4) & 3);
2005 printf(" Primary 4: 0.%04u, 0.%04u\n",
2006 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
2007 if (v > 1) {
2008 col_x = (x[0x18] << 2) | ((x[0x14] >> 2) & 3);
2009 col_y = (x[0x19] << 2) | (x[0x14] & 3);
2010 printf(" Primary 5: 0.%04u, 0.%04u\n",
2011 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
2012 if (v > 2) {
2013 col_x = (x[0x1a] << 2) | (x[0x15] >> 6);
2014 col_y = (x[0x1b] << 2) | ((x[0x15] >> 4) & 3);
2015 printf(" Primary 6: 0.%04u, 0.%04u\n",
2016 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
2021 v = x[0x1c];
2022 printf(" Response Time %s: %u ms\n",
2023 (v & 0x80) ? "White -> Black" : "Black -> White", v & 0x7f);
2024 v = x[0x1d];
2025 printf(" Overscan: %u%% x %u%%\n", v >> 4, v & 0xf);
2028 static double decode_uchar_as_double(unsigned char x)
2030 signed char s = (signed char)x;
2032 return s / 64.0;
2035 void edid_state::cta_rcdb(const unsigned char *x, unsigned length)
2037 unsigned spm = ((x[3] << 16) | (x[2] << 8) | x[1]);
2038 unsigned i;
2040 if (length < 4) {
2041 fail("Empty Data Block with length %u.\n", length);
2042 return;
2045 if ((x[0] & 0x20) && !cta.has_sldb)
2046 fail("'SLD' flag is 1, but no Speaker Location Data Block is found.\n");
2047 else if (!(x[0] & 0x20) && cta.has_sldb)
2048 fail("'SLD' flag is 0, but a Speaker Location Data Block is present.\n");
2050 if (x[0] & 0x40) {
2051 printf(" Speaker count: %u\n", (x[0] & 0x1f) + 1);
2052 } else {
2053 if (x[0] & 0x1f)
2054 fail("'Speaker' flag is 0, but 'Speaker Count' is != 0.\n");
2055 if (x[0] & 0x20)
2056 fail("'SLD' flag is 1, but 'Speaker' is 0.\n");
2059 printf(" Speaker Presence Mask:\n");
2060 for (i = 0; cta_speaker_map[i]; i++) {
2061 if ((spm >> i) & 1)
2062 printf(" %s\n", cta_speaker_map[i]);
2065 if ((x[0] & 0xa0) == 0x80)
2066 fail("'Display' flag set, but not the 'SLD' flag.\n");
2068 bool valid_max = cta.preparsed_sld_has_coord || (x[0] & 0x80);
2070 if (valid_max && length >= 7) {
2071 printf(" Xmax: %u dm\n", x[4]);
2072 printf(" Ymax: %u dm\n", x[5]);
2073 printf(" Zmax: %u dm\n", x[6]);
2074 } else if (!valid_max && length >= 7) {
2075 // The RCDB should have been truncated.
2076 warn("'Display' flag is 0 and 'Coord' is 0 for all SLDs, but the Max coordinates are still present.\n");
2078 if ((x[0] & 0x80) && length >= 10) {
2079 printf(" DisplayX: %.3f * Xmax\n", decode_uchar_as_double(x[7]));
2080 printf(" DisplayY: %.3f * Ymax\n", decode_uchar_as_double(x[8]));
2081 printf(" DisplayZ: %.3f * Zmax\n", decode_uchar_as_double(x[9]));
2082 } else if (!(x[0] & 0x80) && length >= 10) {
2083 // The RCDB should have been truncated.
2084 warn("'Display' flag is 0, but the Display coordinates are still present.\n");
2088 static const struct {
2089 const char *name;
2090 double x, y, z;
2091 } speaker_location[] = {
2092 { "FL - Front Left", -1, 1, 0 },
2093 { "FR - Front Right", 1, 1, 0 },
2094 { "FC - Front Center", 0, 1, 0 },
2095 { "LFE1 - Low Frequency Effects 1", -0.5, 1, -1 },
2096 { "BL - Back Left", -1, -1, 0 },
2097 { "BR - Back Right", 1, -1, 0 },
2098 { "FLC - Front Left of Center", -0.5, 1, 0 },
2099 { "FRC - Front Right of Center", 0.5, 1, 0 },
2100 { "BC - Back Center", 0, -1, 0 },
2101 { "LFE2 - Low Frequency Effects 2", 0.5, 1, -1 },
2102 { "SiL - Side Left", -1, 1.0/3.0, 0 },
2103 { "SiR - Side Right", 1, 1.0/3.0, 0 },
2104 { "TpFL - Top Front Left", -1, 1, 1 },
2105 { "TpFR - Top Front Right", 1, 1, 1 },
2106 { "TpFC - Top Front Center", 0, 1, 1 },
2107 { "TpC - Top Center", 0, 0, 1 },
2108 { "TpBL - Top Back Left", -1, -1, 1 },
2109 { "TpBR - Top Back Right", 1, -1, 1 },
2110 { "TpSiL - Top Side Left", -1, 0, 1 },
2111 { "TpSiR - Top Side Right", 1, 0, 1 },
2112 { "TpBC - Top Back Center", 0, -1, 1 },
2113 { "BtFC - Bottom Front Center", 0, 1, -1 },
2114 { "BtFL - Bottom Front Left", -1, 1, -1 },
2115 { "BtFR - Bottom Front Right", 1, 1, -1 },
2116 { "FLW - Front Left Wide", -1, 2.0/3.0, 0 },
2117 { "FRW - Front Right Wide", 1, 2.0/3.0, 0 },
2118 { "LS - Left Surround", -1, 0, 0 },
2119 { "RS - Right Surround", 1, 0, 0 },
2122 void edid_state::cta_sldb(const unsigned char *x, unsigned length)
2124 if (length < 2) {
2125 fail("Empty Data Block with length %u.\n", length);
2126 return;
2129 unsigned active_cnt = 0;
2130 unsigned channel_is_active = 0;
2132 while (length >= 2) {
2133 printf(" Channel: %u (%sactive)\n", x[0] & 0x1f,
2134 (x[0] & 0x20) ? "" : "not ");
2135 if (x[0] & 0x20) {
2136 if (channel_is_active & (1U << (x[0] & 0x1f)))
2137 fail("Channel Index %u was already marked 'Active'.\n",
2138 x[0] & 0x1f);
2139 channel_is_active |= 1U << (x[0] & 0x1f);
2140 active_cnt++;
2143 unsigned speaker_id = x[1] & 0x1f;
2145 if (speaker_id < ARRAY_SIZE(speaker_location)) {
2146 printf(" Speaker ID: %s\n", speaker_location[speaker_id].name);
2147 } else if (speaker_id == 0x1f) {
2148 printf(" Speaker ID: None Specified\n");
2149 } else {
2150 printf(" Speaker ID: Reserved (%u)\n", speaker_id);
2151 fail("Reserved Speaker ID specified.\n");
2153 if (length >= 5 && (x[0] & 0x40)) {
2154 printf(" X: %.3f * Xmax\n", decode_uchar_as_double(x[2]));
2155 printf(" Y: %.3f * Ymax\n", decode_uchar_as_double(x[3]));
2156 printf(" Z: %.3f * Zmax\n", decode_uchar_as_double(x[4]));
2157 length -= 3;
2158 x += 3;
2159 } else if (speaker_id < ARRAY_SIZE(speaker_location)) {
2160 printf(" X: %.3f * Xmax (approximately)\n", speaker_location[speaker_id].x);
2161 printf(" Y: %.3f * Ymax (approximately)\n", speaker_location[speaker_id].y);
2162 printf(" Z: %.3f * Zmax (approximately)\n", speaker_location[speaker_id].z);
2165 length -= 2;
2166 x += 2;
2168 if (active_cnt != cta.preparsed_speaker_count)
2169 fail("There are %u active speakers, but 'Speaker Count' is %u.\n",
2170 active_cnt, cta.preparsed_speaker_count);
2173 void edid_state::cta_preparse_sldb(const unsigned char *x, unsigned length)
2175 cta.has_sldb = true;
2176 while (length >= 2) {
2177 if (length >= 5 && (x[0] & 0x40)) {
2178 cta.preparsed_sld_has_coord = true;
2179 return;
2181 length -= 2;
2182 x += 2;
2186 void edid_state::cta_vcdb(const unsigned char *x, unsigned length)
2188 unsigned char d = x[0];
2190 cta.has_vcdb = true;
2191 if (length < 1) {
2192 fail("Empty Data Block with length %u.\n", length);
2193 return;
2195 printf(" YCbCr quantization: %s\n",
2196 (d & 0x80) ? "Selectable (via AVI YQ)" : "No Data");
2197 printf(" RGB quantization: %s\n",
2198 (d & 0x40) ? "Selectable (via AVI Q)" : "No Data");
2200 * If this bit is not set then that will result in interoperability
2201 * problems (specifically with PCs/laptops) that quite often do not
2202 * follow the default rules with respect to RGB Quantization Range
2203 * handling.
2205 * Starting with the CTA-861-H spec this bit is now required to be
2206 * 1 for new designs.
2208 if (!(d & 0x40))
2209 fail("Set Selectable RGB Quantization to avoid interop issues.\n");
2211 * Since most YCbCr formats use limited range, the interop issues are
2212 * less noticable than for RGB formats.
2214 * Starting with the CTA-861-H spec this bit is now required to be
2215 * 1 for new designs, but just warn about it (for now).
2217 if ((cta.byte3 & 0x30) && !(d & 0x80))
2218 warn("Set Selectable YCbCr Quantization to avoid interop issues.\n");
2220 unsigned char s_pt = (d >> 4) & 0x03;
2221 unsigned char s_it = (d >> 2) & 0x03;
2222 unsigned char s_ce = d & 0x03;
2224 printf(" PT scan behavior: ");
2225 switch (s_pt) {
2226 case 0: printf("No Data\n"); break;
2227 case 1: printf("Always Overscanned\n"); break;
2228 case 2: printf("Always Underscanned\n"); break;
2229 case 3: printf("Supports both over- and underscan\n"); break;
2231 printf(" IT scan behavior: ");
2232 switch (s_it) {
2233 case 0: printf("IT video formats not supported\n"); break;
2234 case 1:
2235 printf("Always Overscanned\n");
2236 // See Table 52 of CTA-861-G for a description of Byte 3
2237 if (cta.byte3 & 0x80)
2238 fail("IT video formats are always overscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to underscanned.\n");
2239 break;
2240 case 2:
2241 printf("Always Underscanned\n");
2242 // See Table 52 of CTA-861-G for a description of Byte 3
2243 if (!(cta.byte3 & 0x80))
2244 fail("IT video formats are always underscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to overscanned.\n");
2245 break;
2246 case 3: printf("Supports both over- and underscan\n"); break;
2248 if (s_it < 2)
2249 warn("IT scan behavior is expected to support underscanned.\n");
2250 printf(" CE scan behavior: ");
2251 switch (s_ce) {
2252 case 0: printf("CE video formats not supported\n"); break;
2253 case 1: printf("Always Overscanned\n"); break;
2254 case 2: printf("Always Underscanned\n"); break;
2255 case 3: printf("Supports both over- and underscan\n"); break;
2257 if (s_ce == 0)
2258 warn("'CE video formats not supported' makes no sense.\n");
2259 else if (s_pt == s_it && s_pt == s_ce)
2260 warn("S_PT is equal to S_IT and S_CE, so should be set to 0 instead.\n");
2263 static const char *colorimetry1_map[] = {
2264 "xvYCC601",
2265 "xvYCC709",
2266 "sYCC601",
2267 "opYCC601",
2268 "opRGB",
2269 "BT2020cYCC",
2270 "BT2020YCC",
2271 "BT2020RGB",
2274 static const char *colorimetry2_map[] = {
2275 "Gamut Boundary Description Metadata Profile P0",
2276 "Reserved F41",
2277 "Reserved F42",
2278 "Reserved F43",
2279 "Default",
2280 "sRGB",
2281 "ICtCp",
2282 "ST2113RGB",
2285 void edid_state::cta_colorimetry_block(const unsigned char *x, unsigned length)
2287 unsigned i;
2289 if (length < 2) {
2290 fail("Empty Data Block with length %u.\n", length);
2291 return;
2293 for (i = 0; i < ARRAY_SIZE(colorimetry1_map); i++)
2294 if (x[0] & (1 << i))
2295 printf(" %s\n", colorimetry1_map[i]);
2296 // Bit MD0 is used to indicate if HDMI Gamut Boundary Description
2297 // Metadata Profile P0 is supported. Bits F41-F43 are reserved
2298 // and must be set to 0.
2299 if (x[1] & 0xe)
2300 fail("Reserved bits F41-F43 must be 0.\n");
2301 for (i = 0; i < ARRAY_SIZE(colorimetry2_map); i++)
2302 if (x[1] & (1 << i))
2303 printf(" %s\n", colorimetry2_map[i]);
2304 // The sRGB bit (added in CTA-861.6) allows sources to explicitly
2305 // signal sRGB colorimetry. Without this the default colorimetry
2306 // of an RGB video is either sRGB or defaultRGB. It depends on the
2307 // Source which is used, and the Sink has no idea what it is getting.
2309 // For proper compatibility with PCs enabling sRGB support is
2310 // desirable.
2311 if (!base.uses_srgb && !(x[1] & 0x20))
2312 warn("Set the sRGB colorimetry bit to avoid interop issues.\n");
2313 if (x[1] & 0xf0)
2314 cta.avi_version = 4;
2317 static const char *eotf_map[] = {
2318 "Traditional gamma - SDR luminance range",
2319 "Traditional gamma - HDR luminance range",
2320 "SMPTE ST2084",
2321 "Hybrid Log-Gamma",
2324 static void cta_hdr_static_metadata_block(const unsigned char *x, unsigned length)
2326 unsigned i;
2328 if (length < 2) {
2329 fail("Empty Data Block with length %u.\n", length);
2330 return;
2332 printf(" Electro optical transfer functions:\n");
2333 for (i = 0; i < 6; i++) {
2334 if (x[0] & (1 << i)) {
2335 if (i < ARRAY_SIZE(eotf_map)) {
2336 printf(" %s\n", eotf_map[i]);
2337 } else {
2338 printf(" Unknown (%u)\n", i);
2339 fail("Unknown EOTF (%u).\n", i);
2343 printf(" Supported static metadata descriptors:\n");
2344 for (i = 0; i < 8; i++) {
2345 if (x[1] & (1 << i))
2346 printf(" Static metadata type %u\n", i + 1);
2349 if (length >= 3)
2350 printf(" Desired content max luminance: %u (%.3f cd/m^2)\n",
2351 x[2], 50.0 * pow(2, x[2] / 32.0));
2353 if (length >= 4)
2354 printf(" Desired content max frame-average luminance: %u (%.3f cd/m^2)\n",
2355 x[3], 50.0 * pow(2, x[3] / 32.0));
2357 if (length >= 5)
2358 printf(" Desired content min luminance: %u (%.3f cd/m^2)\n",
2359 x[4], (50.0 * pow(2, x[2] / 32.0)) * pow(x[4] / 255.0, 2) / 100.0);
2362 static void cta_hdr_dyn_metadata_block(const unsigned char *x, unsigned length)
2364 if (length < 3) {
2365 fail("Empty Data Block with length %u.\n", length);
2366 return;
2368 while (length >= 3) {
2369 unsigned type_len = x[0];
2370 unsigned type = x[1] | (x[2] << 8);
2372 if (length < type_len + 1)
2373 return;
2374 printf(" HDR Dynamic Metadata Type %u\n", type);
2375 switch (type) {
2376 case 1:
2377 case 4:
2378 if (type_len > 2)
2379 printf(" Version: %u\n", x[3] & 0xf);
2380 break;
2381 case 2:
2382 if (type_len > 2) {
2383 unsigned version = x[3] & 0xf;
2384 printf(" Version: %u\n", version);
2385 if (version >= 1) {
2386 if (x[3] & 0x10) printf(" Supports SL-HDR1 (ETSI TS 103 433-1)\n");
2387 if (x[3] & 0x20) printf(" Supports SL-HDR2 (ETSI TS 103 433-2)\n");
2388 if (x[3] & 0x40) printf(" Supports SL-HDR3 (ETSI TS 103 433-3)\n");
2391 break;
2392 default:
2393 break;
2395 length -= type_len + 1;
2396 x += type_len + 1;
2400 static const char *infoframe_types[] = {
2401 NULL,
2402 "Vendor-Specific",
2403 "Auxiliary Video Information",
2404 "Source Product Description",
2405 "Audio",
2406 "MPEG Source",
2407 "NTSC VBI",
2408 "Dynamic Range and Mastering",
2411 static void cta_ifdb(const unsigned char *x, unsigned length)
2413 unsigned len_hdr = x[0] >> 5;
2415 if (length < 2) {
2416 fail("Empty Data Block with length %u.\n", length);
2417 return;
2419 printf(" VSIFs: %u\n", x[1]);
2420 if (length < len_hdr + 2)
2421 return;
2422 length -= len_hdr + 2;
2423 x += len_hdr + 2;
2424 while (length > 0) {
2425 int payload_len = x[0] >> 5;
2426 unsigned char type = x[0] & 0x1f;
2428 const char *name = NULL;
2429 if (type < ARRAY_SIZE(infoframe_types))
2430 name = infoframe_types[type];
2431 if (!name)
2432 name = "Unknown";
2433 printf(" %s InfoFrame (%u)", name, type);
2435 if (type == 1 && length >= 4) {
2436 unsigned oui = (x[3] << 16) | (x[2] << 8) | x[1];
2438 printf(", OUI %s\n", ouitohex(oui).c_str());
2439 x += 4;
2440 length -= 4;
2441 } else {
2442 printf("\n");
2443 x++;
2444 length--;
2446 x += payload_len;
2447 length -= payload_len;
2451 void edid_state::cta_pidb(const unsigned char *x, unsigned length)
2453 if (length < 4) {
2454 fail("Empty Data Block with length %u.\n", length);
2455 return;
2457 unsigned oui = (x[0] << 16) | (x[1] << 8) | x[2];
2458 printf(" IEEE CID/OUI: %s\n", ouitohex(oui).c_str());
2459 if (length == 4)
2460 return;
2461 printf(" Version: %u\n", x[3]);
2462 if (x[3])
2463 fail("Unsupported version %u.\n", x[3]);
2464 if (length == 5)
2465 return;
2466 char pn[26];
2467 memcpy(pn, x + 4, length - 5);
2468 pn[length - 5] = 0;
2469 for (unsigned i = 0; i < length - 5; i++)
2470 if (x[4 + i] < 0x20 || x[4 + i] >= 0x80)
2471 fail("Product Name: invalid ASCII value at position %u.\n", i);
2472 printf(" Product Name: %s\n", pn);
2475 void edid_state::cta_displayid_type_7(const unsigned char *x, unsigned length)
2477 check_displayid_datablock_revision(x[0], 0x00, 2);
2479 if (length < 21U + ((x[0] & 0x70) >> 4)) {
2480 fail("Empty Data Block with length %u.\n", length);
2481 return;
2483 parse_displayid_type_1_7_timing(x + 1, true, 2, true);
2486 void edid_state::cta_displayid_type_8(const unsigned char *x, unsigned length)
2488 check_displayid_datablock_revision(x[0], 0xe8, 1);
2489 if (length < ((x[0] & 0x08) ? 3 : 2)) {
2490 fail("Empty Data Block with length %u.\n", length);
2491 return;
2494 unsigned sz = (x[0] & 0x08) ? 2 : 1;
2495 unsigned type = x[0] >> 6;
2497 if (type) {
2498 fail("Only code type 0 is supported.\n");
2499 return;
2502 if (x[0] & 0x20)
2503 printf(" Also supports YCbCr 4:2:0\n");
2505 x++;
2506 length--;
2507 for (unsigned i = 0; i < length / sz; i++) {
2508 unsigned id = x[i * sz];
2510 if (sz == 2)
2511 id |= x[i * sz + 1] << 8;
2512 parse_displayid_type_4_8_timing(type, id, true);
2516 void edid_state::cta_displayid_type_10(const unsigned char *x, unsigned length)
2518 check_displayid_datablock_revision(x[0], 0x70);
2519 if (length < 7U + ((x[0] & 0x70) >> 4)) {
2520 fail("Empty Data Block with length %u.\n", length);
2521 return;
2524 unsigned sz = 6U + ((x[0] & 0x70) >> 4);
2525 x++;
2526 length--;
2527 for (unsigned i = 0; i < length / sz; i++)
2528 parse_displayid_type_10_timing(x + i * sz, sz, true);
2531 static void cta_hdmi_audio_block(const unsigned char *x, unsigned length)
2533 unsigned num_descs;
2535 if (length < 2) {
2536 fail("Empty Data Block with length %u.\n", length);
2537 return;
2539 if (x[0] & 3) {
2540 printf(" Max Stream Count: %u\n", (x[0] & 3) + 1);
2541 if (x[0] & 4)
2542 printf(" Supports MS NonMixed\n");
2543 } else if (x[0] & 4) {
2544 fail("MS NonMixed support indicated but Max Stream Count == 0.\n");
2547 num_descs = x[1] & 7;
2548 if (num_descs == 0)
2549 return;
2550 length -= 2;
2551 x += 2;
2552 while (length >= 4) {
2553 if (length > 4) {
2554 unsigned format = x[0] & 0xf;
2556 printf(" %s:\n", audio_format(format).c_str());
2557 printf(" Max channels: %u\n", (x[1] & 0x1f)+1);
2558 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
2559 (x[2] & 0x40) ? " 192" : "",
2560 (x[2] & 0x20) ? " 176.4" : "",
2561 (x[2] & 0x10) ? " 96" : "",
2562 (x[2] & 0x08) ? " 88.2" : "",
2563 (x[2] & 0x04) ? " 48" : "",
2564 (x[2] & 0x02) ? " 44.1" : "",
2565 (x[2] & 0x01) ? " 32" : "");
2566 if (format == 1)
2567 printf(" Supported sample sizes (bits):%s%s%s\n",
2568 (x[3] & 0x04) ? " 24" : "",
2569 (x[3] & 0x02) ? " 20" : "",
2570 (x[3] & 0x01) ? " 16" : "");
2571 } else {
2572 unsigned sad = ((x[2] << 16) | (x[1] << 8) | x[0]);
2573 unsigned i;
2575 switch (x[3] >> 4) {
2576 case 1:
2577 printf(" Speaker Allocation for 10.2 channels:\n");
2578 break;
2579 case 2:
2580 printf(" Speaker Allocation for 22.2 channels:\n");
2581 break;
2582 case 3:
2583 printf(" Speaker Allocation for 30.2 channels:\n");
2584 break;
2585 default:
2586 printf(" Unknown Speaker Allocation (0x%02x)\n", x[3] >> 4);
2587 return;
2590 for (i = 0; cta_speaker_map[i]; i++) {
2591 if ((sad >> i) & 1)
2592 printf(" %s\n", cta_speaker_map[i]);
2595 length -= 4;
2596 x += 4;
2600 void edid_state::cta_block(const unsigned char *x, std::vector<unsigned> &found_tags)
2602 unsigned length = x[0] & 0x1f;
2603 unsigned tag = (x[0] & 0xe0) >> 5;
2604 unsigned extended = (tag == 0x07) ? 1 : 0;
2606 x++;
2607 if (extended && length) {
2608 tag <<= 8;
2609 tag |= x[0];
2610 length--;
2611 x++;
2614 bool dooutputname = true;
2615 bool audio_block = false;
2616 data_block.clear();
2618 switch (tag) {
2619 case 0x01: data_block = "Audio Data Block"; audio_block = true; break;
2620 case 0x02: data_block = "Video Data Block"; break;
2621 case 0x03: data_block = "Vendor-Specific Data Block"; break;
2622 case 0x04: data_block = "Speaker Allocation Data Block"; audio_block = true; break;
2623 case 0x05: data_block = "VESA Display Transfer Characteristics Data Block"; break;
2624 case 0x06: data_block = "Video Format Data Block"; break;
2625 case 0x07: data_block = "Unknown CTA-861 Data Block (extended tag truncated)"; break;
2627 case 0x700: data_block = "Video Capability Data Block"; break;
2628 case 0x701: data_block = "Vendor-Specific Video Data Block"; break;
2629 case 0x702: data_block = "VESA Video Display Device Data Block"; break;
2630 case 0x703: data_block = "VESA Video Timing Block Extension"; break;
2631 case 0x704: data_block = "Reserved for HDMI Video Data Block"; break;
2632 case 0x705: data_block = "Colorimetry Data Block"; break;
2633 case 0x706: data_block = "HDR Static Metadata Data Block"; break;
2634 case 0x707: data_block = "HDR Dynamic Metadata Data Block"; break;
2635 case 0x708: data_block = "Native Video Resolution Data Block"; break;
2637 case 0x70d: data_block = "Video Format Preference Data Block"; break;
2638 case 0x70e: data_block = "YCbCr 4:2:0 Video Data Block"; break;
2639 case 0x70f: data_block = "YCbCr 4:2:0 Capability Map Data Block"; break;
2640 case 0x710: data_block = "Reserved for CTA-861 Miscellaneous Audio Fields"; break;
2641 case 0x711: data_block = "Vendor-Specific Audio Data Block"; audio_block = true; break;
2642 case 0x712: data_block = "HDMI Audio Data Block"; audio_block = true; break;
2643 case 0x713: data_block = "Room Configuration Data Block"; audio_block = true; break;
2644 case 0x714: data_block = "Speaker Location Data Block"; audio_block = true; break;
2646 case 0x720: data_block = "InfoFrame Data Block"; break;
2647 case 0x721: data_block = "Product Information Data Block"; break;
2649 case 0x722: data_block = "DisplayID Type VII Video Timing Data Block"; break;
2650 case 0x723: data_block = "DisplayID Type VIII Video Timing Data Block"; break;
2651 case 0x72a: data_block = "DisplayID Type X Video Timing Data Block"; break;
2653 case 0x778: data_block = "HDMI Forum EDID Extension Override Data Block"; break;
2654 case 0x779: data_block = "HDMI Forum Sink Capability Data Block"; break;
2655 case 0x77a: data_block = "HDMI Forum Source-Based Tone Mapping Data Block"; break;
2657 default:
2658 std::string unknown_name;
2659 if (tag < 0x700) unknown_name = "Unknown CTA-861 Data Block";
2660 else if (tag < 0x70d) unknown_name = "Unknown CTA-861 Video-Related Data Block";
2661 else if (tag < 0x720) unknown_name = "Unknown CTA-861 Audio-Related Data Block";
2662 else if (tag < 0x778) unknown_name = "Unknown CTA-861 Data Block";
2663 else if (tag < 0x780) unknown_name = "Unknown CTA-861 HDMI-Related Data Block";
2664 else unknown_name = "Unknown CTA-861 Data Block";
2665 unknown_name += std::string(" (") + (extended ? "extended " : "") + "tag " + utohex(tag & 0xff) + ", length " + std::to_string(length) + ")";
2666 printf(" %s:\n", unknown_name.c_str());
2667 warn("%s.\n", unknown_name.c_str());
2668 break;
2671 switch (tag) {
2672 case 0x03:
2673 case 0x701:
2674 case 0x711: {
2675 unsigned ouinum;
2677 data_block_oui(data_block, x, length, &ouinum);
2678 x += (length < 3) ? length : 3;
2679 length -= (length < 3) ? length : 3;
2680 dooutputname = false;
2681 tag |= ouinum;
2682 break;
2686 if (dooutputname && data_block.length())
2687 printf(" %s:\n", data_block.c_str());
2689 switch (tag) {
2690 case 0x04:
2691 case 0x05:
2692 case 0x700:
2693 case 0x702:
2694 case 0x705:
2695 case 0x706:
2696 case 0x708:
2697 case 0x70d:
2698 case 0x70f:
2699 case 0x712:
2700 case 0x713:
2701 case 0x721:
2702 case 0x778:
2703 case 0x779:
2704 case 0x77a:
2705 if (std::find(found_tags.begin(), found_tags.end(), tag) != found_tags.end())
2706 fail("Only one instance of this Data Block is allowed.\n");
2707 break;
2710 // See Table 52 of CTA-861-G for a description of Byte 3
2711 if (audio_block && !(cta.byte3 & 0x40))
2712 fail("Audio information is present, but bit 6 of Byte 3 of the CTA-861 Extension header indicates no Basic Audio support.\n");
2714 switch (tag) {
2715 case 0x01: cta_audio_block(x, length); break;
2716 case 0x02: cta_svd(x, length, false); break;
2717 case 0x03|kOUI_HDMI:
2718 cta_hdmi_block(x, length);
2719 // The HDMI OUI is present, so this EDID represents an HDMI
2720 // interface. And HDMI interfaces must use EDID version 1.3
2721 // according to the HDMI Specification, so check for this.
2722 if (base.edid_minor != 3)
2723 fail("The HDMI Specification requires EDID 1.3 instead of 1.%u.\n",
2724 base.edid_minor);
2725 break;
2726 case 0x03|kOUI_HDMIForum:
2727 if (cta.previous_cta_tag != (0x03|kOUI_HDMI))
2728 fail("HDMI Forum VSDB did not immediately follow the HDMI VSDB.\n");
2729 if (cta.have_hf_scdb || cta.have_hf_vsdb)
2730 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2731 cta_hf_scdb(x, length);
2732 cta.have_hf_vsdb = true;
2733 break;
2734 case 0x03|kOUI_AMD: cta_amd(x, length); break;
2735 case 0x03|kOUI_Microsoft: if (length != 0x12) goto dodefault; cta_microsoft(x, length); break;
2736 case 0x03|kOUI_UHDA: cta_uhda_fmm(x, length); break;
2737 case 0x04: cta_sadb(x, length); break;
2738 case 0x05: cta_vesa_dtcdb(x, length); break;
2739 case 0x06: cta_vfdb(x, length); break;
2740 case 0x07: fail("Extended tag cannot have zero length.\n"); break;
2741 case 0x700: cta_vcdb(x, length); break;
2742 case 0x701|kOUI_HDR10: cta_hdr10plus(x, length); break;
2743 case 0x701|kOUI_Dolby: cta_dolby_video(x, length); break;
2744 // 0x701|kOUI_Apple: this almost certainly contains 'BLC Info/Corrections',
2745 // since the data (spread out over two VSDBs) is very similar to what is seen
2746 // in DisplayID blocks. Since I don't know how to parse this data, we still
2747 // default to a hex dump, but I mention this here in case data on how to
2748 // parse this becomes available.
2749 case 0x702: cta_vesa_vdddb(x, length); break;
2750 case 0x705: cta_colorimetry_block(x, length); break;
2751 case 0x706: cta_hdr_static_metadata_block(x, length); break;
2752 case 0x707: cta_hdr_dyn_metadata_block(x, length); break;
2753 case 0x708: cta_nvrdb(x, length); return;
2754 case 0x70d: cta_vfpdb(x, length); break;
2755 case 0x70e: cta_svd(x, length, true); break;
2756 case 0x70f: cta_y420cmdb(x, length); break;
2757 case 0x711|kOUI_Dolby: cta_dolby_audio(x, length); break;
2758 case 0x712: cta_hdmi_audio_block(x, length); break;
2759 case 0x713: cta_rcdb(x, length); break;
2760 case 0x714: cta_sldb(x, length); break;
2761 case 0x720: cta_ifdb(x, length); break;
2762 case 0x721: cta_pidb(x, length); break;
2763 case 0x722: cta_displayid_type_7(x, length); break;
2764 case 0x723: cta_displayid_type_8(x, length); break;
2765 case 0x72a: cta_displayid_type_10(x, length); break;
2766 case 0x778:
2767 cta_hf_eeodb(x, length);
2768 if (block_nr != 1)
2769 fail("Data Block can only be present in Block 1.\n");
2770 // This must be the first CTA-861 block
2771 if (cta.block_number > 0)
2772 fail("Data Block starts at a wrong offset.\n");
2773 break;
2774 case 0x779:
2775 if (cta.previous_cta_tag != (0x03|kOUI_HDMI))
2776 fail("HDMI Forum SCDB did not immediately follow the HDMI VSDB.\n");
2777 if (cta.have_hf_scdb || cta.have_hf_vsdb)
2778 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2779 if (block_nr != 1)
2780 fail("Data Block can only be present in Block 1.\n");
2781 if (length < 2) {
2782 data_block = std::string("HDMI Forum SCDB");
2783 fail("Invalid length %u < 2.\n", length);
2784 break;
2786 if (x[0] || x[1])
2787 printf(" Non-zero SCDB reserved fields!\n");
2788 cta_hf_scdb(x + 2, length - 2);
2789 cta.have_hf_scdb = true;
2790 break;
2791 case 0x77a:
2792 cta_hf_sbtmdb(x, length);
2793 break;
2794 dodefault:
2795 default:
2796 hex_block(" ", x, length);
2797 break;
2800 cta.block_number++;
2801 cta.previous_cta_tag = tag;
2802 found_tags.push_back(tag);
2805 void edid_state::preparse_cta_block(unsigned char *x)
2807 unsigned version = x[1];
2808 unsigned offset = x[2];
2810 if (offset >= 4) {
2811 unsigned char *detailed;
2812 bool update_checksum = false;
2814 for (detailed = x + offset; detailed + 17 < x + 127; detailed += 18) {
2815 if (memchk(detailed, 18))
2816 break;
2817 update_checksum |= preparse_detailed_block(detailed);
2818 if (detailed[0] || detailed[1])
2819 cta.preparsed_total_dtds++;
2821 if (update_checksum)
2822 replace_checksum(x, EDID_PAGE_SIZE);
2825 if (version < 3)
2826 return;
2828 for (unsigned i = 4; i < offset; i += (x[i] & 0x1f) + 1) {
2829 bool for_ycbcr420 = false;
2830 unsigned oui;
2832 switch ((x[i] & 0xe0) >> 5) {
2833 case 0x03:
2834 oui = (x[i + 3] << 16) + (x[i + 2] << 8) + x[i + 1];
2835 if (oui == 0x000c03) {
2836 cta.has_hdmi = true;
2837 cta.preparsed_phys_addr = (x[i + 4] << 8) | x[i + 5];
2838 } else if ((oui == 0xca125c || oui == 0x5c12ca) &&
2839 (x[i] & 0x1f) == 0x15 && replace_unique_ids) {
2840 memset(x + i + 6, 0, 16);
2841 replace_checksum(x, EDID_PAGE_SIZE);
2843 break;
2844 case 0x06:
2845 if (!(x[i] & 0x1f) || cta.preparsed_first_vfd.rid)
2846 break;
2847 cta.preparsed_first_vfd = cta_parse_vfd(x + i + 2, (x[i + 1] & 3) + 1);
2848 break;
2849 case 0x07:
2850 if (x[i + 1] == 0x0d)
2851 cta.has_vfpdb = true;
2852 else if (x[i + 1] == 0x05)
2853 cta.has_cdb = true;
2854 else if (x[i + 1] == 0x08)
2855 cta.has_nvrdb = true;
2856 else if (x[i + 1] == 0x21)
2857 cta.has_pidb = true;
2858 else if (x[i + 1] == 0x13 && (x[i + 2] & 0x40)) {
2859 cta.preparsed_speaker_count = 1 + (x[i + 2] & 0x1f);
2860 cta.preparsed_sld = x[i + 2] & 0x20;
2861 } else if (x[i + 1] == 0x14)
2862 cta_preparse_sldb(x + i + 2, (x[i] & 0x1f) - 1);
2863 else if (x[i + 1] == 0x22)
2864 cta.preparsed_total_vtdbs++;
2865 else if (x[i + 1] == 0x23) {
2866 cta.preparsed_has_t8vtdb = true;
2867 cta.preparsed_t8vtdb_dmt = x[i + 3];
2868 if (x[i + 2] & 0x08)
2869 cta.preparsed_t8vtdb_dmt |= x[i + 4] << 8;
2870 } else if (x[i + 1] == 0x2a)
2871 cta.preparsed_total_vtdbs +=
2872 ((x[i] & 0x1f) - 2) / (6 + ((x[i + 2] & 0x70) >> 4));
2873 else if (x[i + 1] == 0x78)
2874 cta.hf_eeodb_blocks = x[i + 2];
2875 if (x[i + 1] != 0x0e)
2876 continue;
2877 for_ycbcr420 = true;
2878 #ifdef __EMSCRIPTEN__
2879 [[clang::fallthrough]];
2880 #endif
2881 /* fall-through */
2882 case 0x02:
2883 for (unsigned j = 1 + for_ycbcr420; j <= (x[i] & 0x1f); j++) {
2884 unsigned char vic = x[i + j];
2886 if ((vic & 0x7f) <= 64)
2887 vic &= 0x7f;
2888 cta.preparsed_svds[for_ycbcr420].push_back(vic);
2889 cta.preparsed_has_vic[for_ycbcr420][vic] = true;
2891 const struct timings *t = find_vic_id(vic);
2893 if (!for_ycbcr420 && t &&
2894 t->pixclk_khz > cta.preparsed_max_vic_pixclk_khz)
2895 cta.preparsed_max_vic_pixclk_khz = t->pixclk_khz;
2897 break;
2902 void edid_state::parse_cta_block(const unsigned char *x)
2904 unsigned version = x[1];
2905 unsigned offset = x[2];
2906 const unsigned char *detailed;
2908 // See Table 52 of CTA-861-G for a description of Byte 3
2910 printf(" Revision: %u\n", version);
2911 if (version == 0)
2912 fail("Invalid CTA-861 Extension revision 0.\n");
2913 if (version == 2)
2914 fail("Deprecated CTA-861 Extension revision 2.\n");
2915 if (cta.has_hdmi && version != 3)
2916 fail("The HDMI Specification requires CTA Extension revision 3.\n");
2917 if (version > 3)
2918 warn("Unknown CTA-861 Extension revision %u.\n", version);
2919 if (offset > 0 && offset < 4)
2920 fail("Invalid CTA-861 Extension offset value (byte 2).\n");
2922 if (version >= 1) do {
2923 if (version == 1 && x[3] != 0)
2924 fail("Non-zero byte 3.\n");
2926 if (version < 3 && offset >= 4 && ((offset - 4) / 8)) {
2927 printf(" 8-byte timing descriptors: %u\n", (offset - 4) / 8);
2928 fail("8-byte descriptors were never used.\n");
2931 if (version >= 2) {
2932 if (x[3] & 0x80)
2933 printf(" Underscans IT Video Formats by default\n");
2934 else
2935 warn("IT Video Formats are overscanned by default, but normally this should be underscanned.\n");
2936 if (x[3] & 0x40)
2937 printf(" Basic audio support\n");
2938 if (x[3] & 0x20) {
2939 printf(" Supports YCbCr 4:4:4\n");
2940 cta.has_ycbcr444 = true;
2942 if (x[3] & 0x10) {
2943 printf(" Supports YCbCr 4:2:2\n");
2944 cta.has_ycbcr422 = true;
2946 // Disable this test: this fails a lot of EDIDs, and there are
2947 // also some corner cases where you only want to receive 4:4:4
2948 // and refuse a fallback to 4:2:2.
2949 // if ((x[3] & 0x30) && (x[3] & 0x30) != 0x30)
2950 // msg(!cta.has_hdmi, "If YCbCr support is indicated, then both 4:2:2 and 4:4:4 %s be supported.\n",
2951 // cta.has_hdmi ? "shall" : "should");
2952 printf(" Native detailed modes: %u\n", x[3] & 0x0f);
2953 if (cta.block_number == 0)
2954 cta.byte3 = x[3];
2955 else if (x[3] != cta.byte3)
2956 fail("Byte 3 must be the same for all CTA-861 Extension Blocks.\n");
2957 if (cta.block_number == 0) {
2958 unsigned native_dtds = x[3] & 0x0f;
2960 cta.native_timings.clear();
2961 if (!native_dtds && !cta.has_vfpdb) {
2962 cta.first_svd_might_be_preferred = true;
2963 } else if (native_dtds > cta.preparsed_total_dtds) {
2964 fail("There are more Native DTDs (%u) than DTDs (%u).\n",
2965 native_dtds, cta.preparsed_total_dtds);
2967 if (native_dtds > cta.preparsed_total_dtds)
2968 native_dtds = cta.preparsed_total_dtds;
2969 for (unsigned i = 0; i < native_dtds; i++) {
2970 char type[16];
2972 sprintf(type, "DTD %3u", i + 1);
2973 cta.native_timings.push_back(timings_ext(i + 129, type));
2974 cta.has_svrs = true;
2976 if (cta.has_hdmi && block_nr != (block_map.saw_block_1 ? 2 : 1))
2977 fail("The HDMI Specification requires that the first Extension Block (that is not a Block Map) is an CTA-861 Extension Block.\n");
2981 if (offset < 4) {
2982 // Offset 0 means that there are no data blocks or DTDs,
2983 // so the remainder must be padding.
2984 if (!memchk(x + 4, 127 - 4)) {
2985 data_block = "Padding";
2986 fail("Contains non-zero bytes.\n");
2988 break;
2991 if (version >= 3) {
2992 unsigned i;
2994 for (i = 4; i < offset; i += (x[i] & 0x1f) + 1) {
2995 cta_block(x + i, cta.found_tags);
2998 data_block.clear();
2999 if (i != offset)
3000 fail("Offset is %u, but should be %u.\n", offset, i);
3003 data_block = "Detailed Timing Descriptors";
3004 base.seen_non_detailed_descriptor = false;
3005 bool first = true;
3006 for (detailed = x + offset; detailed + 17 < x + 127; detailed += 18) {
3007 if (memchk(detailed, 18))
3008 break;
3009 if (first) {
3010 first = false;
3011 printf(" %s:\n", data_block.c_str());
3013 detailed_block(detailed);
3015 unused_bytes = x + 127 - detailed;
3016 if (!memchk(detailed, unused_bytes)) {
3017 data_block = "Padding";
3018 fail("Contains non-zero bytes.\n");
3020 } while (0);
3022 data_block.clear();
3023 if (base.serial_number && serial_strings.size())
3024 warn("Display Product Serial Number is set, so the Serial Number in the Base EDID should be 0.\n");
3025 if (!cta.has_vic_1 && !base.has_640x480p60_est_timing)
3026 fail("Required 640x480p60 timings are missing in the established timings"
3027 " and the SVD list (VIC 1).\n");
3028 if ((cta.supported_hdmi_vic_vsb_codes & cta.supported_hdmi_vic_codes) !=
3029 cta.supported_hdmi_vic_codes)
3030 fail("HDMI VIC Codes must have their CTA-861 VIC equivalents in the VSB.\n");
3031 if (!cta.has_vcdb)
3032 fail("Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.\n");
3033 if (!base.uses_srgb && !cta.has_cdb)
3034 warn("Add a Colorimetry Data Block with the sRGB colorimetry bit set to avoid interop issues.\n");
3037 void edid_state::cta_resolve_svr(timings_ext &t_ext)
3039 if (t_ext.svr() == 254) {
3040 t_ext.flags = cta.t8vtdb.flags;
3041 add_str(t_ext.flags, ">=CTA-861-H");
3042 t_ext.t = cta.t8vtdb.t;
3043 } else if (t_ext.svr() <= 144) {
3044 if (t_ext.svr() < 129 || t_ext.svr() - 129 >= cta.vec_dtds.size())
3045 return;
3046 t_ext.flags = cta.vec_dtds[t_ext.svr() - 129].flags;
3047 t_ext.t = cta.vec_dtds[t_ext.svr() - 129].t;
3048 } else if (t_ext.svr() <= 160) {
3049 if (t_ext.svr() - 145 >= cta.vec_vtdbs.size())
3050 return;
3051 t_ext.flags = cta.vec_vtdbs[t_ext.svr() - 145].flags;
3052 add_str(t_ext.flags, ">=CTA-861-H");
3053 t_ext.t = cta.vec_vtdbs[t_ext.svr() - 145].t;
3054 } else if (t_ext.svr() <= 175) {
3055 t_ext.flags.clear();
3056 unsigned char rid = cta.preparsed_first_vfd.rid;
3057 t_ext.t = calc_ovt_mode(rids[rid].hact, rids[rid].vact,
3058 rids[rid].hratio, rids[rid].vratio,
3059 vf_rate_values[t_ext.svr() - 160]);
3060 t_ext.flags = ">=CTA-861.6";
3064 void edid_state::cta_resolve_svrs()
3066 for (vec_timings_ext::iterator iter = cta.preferred_timings_vfpdb.begin();
3067 iter != cta.preferred_timings_vfpdb.end(); ++iter) {
3068 if (iter->has_svr())
3069 cta_resolve_svr(*iter);
3072 for (vec_timings_ext::iterator iter = cta.native_timings.begin();
3073 iter != cta.native_timings.end(); ++iter) {
3074 if (iter->has_svr())
3075 cta_resolve_svr(*iter);
3078 for (vec_timings_ext::iterator iter = cta.native_timing_nvrdb.begin();
3079 iter != cta.native_timing_nvrdb.end(); ++iter) {
3080 if (iter->has_svr())
3081 cta_resolve_svr(*iter);
3085 void edid_state::check_cta_blocks()
3087 unsigned max_pref_prog_hact = 0;
3088 unsigned max_pref_prog_vact = 0;
3089 unsigned max_pref_ilace_hact = 0;
3090 unsigned max_pref_ilace_vact = 0;
3092 data_block = "CTA-861";
3094 // HDMI 1.4 goes up to 340 MHz. Dubious to have a DTD above that,
3095 // but no VICs. Displays often have a setting to turn off HDMI 2.x
3096 // support, dropping any HDMI 2.x VICs, but they sometimes forget
3097 // to replace the DTD in the base block as well.
3098 if (cta.warn_about_hdmi_2x_dtd)
3099 warn("DTD pixelclock indicates HDMI 2.x support, VICs indicate HDMI 1.x.\n");
3101 if (cta.hdmi_max_rate && max_pixclk_khz > cta.hdmi_max_rate * 1000)
3102 fail("The maximum HDMI TMDS clock is %u kHz, but one or more video timings go up to %u kHz.\n",
3103 cta.hdmi_max_rate * 1000, max_pixclk_khz);
3105 for (vec_timings_ext::iterator iter = cta.preferred_timings.begin();
3106 iter != cta.preferred_timings.end(); ++iter) {
3107 if (iter->t.interlaced &&
3108 (iter->t.vact > max_pref_ilace_vact ||
3109 (iter->t.vact == max_pref_ilace_vact && iter->t.hact >= max_pref_ilace_hact))) {
3110 max_pref_ilace_hact = iter->t.hact;
3111 max_pref_ilace_vact = iter->t.vact;
3113 if (!iter->t.interlaced &&
3114 (iter->t.vact > max_pref_prog_vact ||
3115 (iter->t.vact == max_pref_prog_vact && iter->t.hact >= max_pref_prog_hact))) {
3116 max_pref_prog_hact = iter->t.hact;
3117 max_pref_prog_vact = iter->t.vact;
3120 for (vec_timings_ext::iterator iter = cta.preferred_timings_vfpdb.begin();
3121 iter != cta.preferred_timings_vfpdb.end(); ++iter) {
3122 if (iter->t.interlaced &&
3123 (iter->t.vact > max_pref_ilace_vact ||
3124 (iter->t.vact == max_pref_ilace_vact && iter->t.hact >= max_pref_ilace_hact))) {
3125 max_pref_ilace_hact = iter->t.hact;
3126 max_pref_ilace_vact = iter->t.vact;
3128 if (!iter->t.interlaced &&
3129 (iter->t.vact > max_pref_prog_vact ||
3130 (iter->t.vact == max_pref_prog_vact && iter->t.hact >= max_pref_prog_hact))) {
3131 max_pref_prog_hact = iter->t.hact;
3132 max_pref_prog_vact = iter->t.vact;
3136 unsigned native_prog = 0;
3137 unsigned native_prog_hact = 0;
3138 unsigned native_prog_vact = 0;
3139 bool native_prog_mixed_resolutions = false;
3140 unsigned native_ilace = 0;
3141 unsigned native_ilace_hact = 0;
3142 unsigned native_ilace_vact = 0;
3143 bool native_ilace_mixed_resolutions = false;
3144 unsigned native_nvrdb_hact = 0;
3145 unsigned native_nvrdb_vact = 0;
3147 for (vec_timings_ext::iterator iter = cta.native_timings.begin();
3148 iter != cta.native_timings.end(); ++iter) {
3149 if (iter->t.interlaced) {
3150 native_ilace++;
3151 if (!native_ilace_hact) {
3152 native_ilace_hact = iter->t.hact;
3153 native_ilace_vact = iter->t.vact;
3154 } else if (native_ilace_hact != iter->t.hact ||
3155 native_ilace_vact != iter->t.vact) {
3156 native_ilace_mixed_resolutions = true;
3158 } else {
3159 native_prog++;
3160 if (!native_prog_hact) {
3161 native_prog_hact = iter->t.hact;
3162 native_prog_vact = iter->t.vact;
3163 } else if (native_prog_hact != iter->t.hact ||
3164 native_prog_vact != iter->t.vact) {
3165 native_prog_mixed_resolutions = true;
3170 for (vec_timings_ext::iterator iter = cta.native_timing_nvrdb.begin();
3171 iter != cta.native_timing_nvrdb.end(); ++iter) {
3172 native_nvrdb_hact = iter->t.hact;
3173 native_nvrdb_vact = iter->t.vact;
3176 if (native_prog_mixed_resolutions)
3177 fail("Native progressive timings are a mix of several resolutions.\n");
3178 if (native_ilace_mixed_resolutions)
3179 fail("Native interlaced timings are a mix of several resolutions.\n");
3180 if (native_ilace && !native_prog)
3181 fail("A native interlaced timing is present, but not a native progressive timing.\n");
3182 if (!native_prog_mixed_resolutions && native_prog > 1)
3183 warn("Multiple native progressive timings are defined.\n");
3184 if (!native_ilace_mixed_resolutions && native_ilace > 1)
3185 warn("Multiple native interlaced timings are defined.\n");
3187 if (native_nvrdb_vact &&
3188 (max_pref_prog_vact > native_nvrdb_vact ||
3189 (max_pref_prog_vact == native_nvrdb_vact && max_pref_prog_hact > native_nvrdb_hact)))
3190 warn("Native video resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
3191 native_nvrdb_hact, native_nvrdb_vact,
3192 max_pref_prog_hact, max_pref_prog_vact);
3193 else if (!native_nvrdb_vact && !native_prog_mixed_resolutions && native_prog_vact &&
3194 (max_pref_prog_vact > native_prog_vact ||
3195 (max_pref_prog_vact == native_prog_vact && max_pref_prog_hact > native_prog_hact)))
3196 warn("Native progressive resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
3197 native_prog_hact, native_prog_vact,
3198 max_pref_prog_hact, max_pref_prog_vact);
3199 if (!native_ilace_mixed_resolutions && native_ilace_vact &&
3200 (max_pref_ilace_vact > native_ilace_vact ||
3201 (max_pref_ilace_vact == native_ilace_vact && max_pref_ilace_hact > native_ilace_hact)))
3202 warn("Native interlaced resolution of %ux%u is smaller than the max preferred interlaced resolution %ux%u.\n",
3203 native_ilace_hact, native_ilace_vact,
3204 max_pref_ilace_hact, max_pref_ilace_vact);
3206 if (dispid.native_width && native_prog_hact &&
3207 !native_prog_mixed_resolutions) {
3208 if (dispid.native_width != native_prog_hact ||
3209 dispid.native_height != native_prog_vact)
3210 fail("Mismatch between CTA-861 and DisplayID native progressive resolution.\n");