edid-decode: warn that CinemaVRR is deprecated
[edid-decode.git] / parse-cta-block.cpp
blob25cf276f6250c1f07df7f790520340f652212c8c
1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright 2006-2012 Red Hat, Inc.
4 * Copyright 2018-2020 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 * Author: Adam Jackson <ajax@nwnk.net>
7 * Maintainer: Hans Verkuil <hverkuil-cisco@xs4all.nl>
8 */
10 #include <algorithm>
11 #include <stdio.h>
12 #include <math.h>
14 #include "edid-decode.h"
16 static const struct timings edid_cta_modes1[] = {
17 /* VIC 1 */
18 { 640, 480, 4, 3, 25175, 0, false, 16, 96, 48, false, 10, 2, 33, false },
19 { 720, 480, 4, 3, 27000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
20 { 720, 480, 16, 9, 27000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
21 { 1280, 720, 16, 9, 74250, 0, false, 110, 40, 220, true, 5, 5, 20, true },
22 { 1920, 1080, 16, 9, 74250, 0, true, 88, 44, 148, true, 2, 5, 15, true },
23 { 1440, 480, 4, 3, 27000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
24 { 1440, 480, 16, 9, 27000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
25 { 1440, 240, 4, 3, 27000, 0, false, 38, 124, 114, false, 4, 3, 15, false },
26 { 1440, 240, 16, 9, 27000, 0, false, 38, 124, 114, false, 4, 3, 15, false },
27 { 2880, 480, 4, 3, 54000, 0, true, 76, 248, 228, false, 4, 3, 15, false },
28 /* VIC 11 */
29 { 2880, 480, 16, 9, 54000, 0, true, 76, 248, 228, false, 4, 3, 15, false },
30 { 2880, 240, 4, 3, 54000, 0, false, 76, 248, 228, false, 4, 3, 15, false },
31 { 2880, 240, 16, 9, 54000, 0, false, 76, 248, 228, false, 4, 3, 15, false },
32 { 1440, 480, 4, 3, 54000, 0, false, 32, 124, 120, false, 9, 6, 30, false },
33 { 1440, 480, 16, 9, 54000, 0, false, 32, 124, 120, false, 9, 6, 30, false },
34 { 1920, 1080, 16, 9, 148500, 0, false, 88, 44, 148, true, 4, 5, 36, true },
35 { 720, 576, 4, 3, 27000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
36 { 720, 576, 16, 9, 27000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
37 { 1280, 720, 16, 9, 74250, 0, false, 440, 40, 220, true, 5, 5, 20, true },
38 { 1920, 1080, 16, 9, 74250, 0, true, 528, 44, 148, true, 2, 5, 15, true },
39 /* VIC 21 */
40 { 1440, 576, 4, 3, 27000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
41 { 1440, 576, 16, 9, 27000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
42 { 1440, 288, 4, 3, 27000, 0, false, 24, 126, 138, false, 2, 3, 19, false },
43 { 1440, 288, 16, 9, 27000, 0, false, 24, 126, 138, false, 2, 3, 19, false },
44 { 2880, 576, 4, 3, 54000, 0, true, 48, 252, 276, false, 2, 3, 19, false },
45 { 2880, 576, 16, 9, 54000, 0, true, 48, 252, 276, false, 2, 3, 19, false },
46 { 2880, 288, 4, 3, 54000, 0, false, 48, 252, 276, false, 2, 3, 19, false },
47 { 2880, 288, 16, 9, 54000, 0, false, 48, 252, 276, false, 2, 3, 19, false },
48 { 1440, 576, 4, 3, 54000, 0, false, 24, 128, 136, false, 5, 5, 39, false },
49 { 1440, 576, 16, 9, 54000, 0, false, 24, 128, 136, false, 5, 5, 39, false },
50 /* VIC 31 */
51 { 1920, 1080, 16, 9, 148500, 0, false, 528, 44, 148, true, 4, 5, 36, true },
52 { 1920, 1080, 16, 9, 74250, 0, false, 638, 44, 148, true, 4, 5, 36, true },
53 { 1920, 1080, 16, 9, 74250, 0, false, 528, 44, 148, true, 4, 5, 36, true },
54 { 1920, 1080, 16, 9, 74250, 0, false, 88, 44, 148, true, 4, 5, 36, true },
55 { 2880, 480, 4, 3, 108000, 0, false, 64, 248, 240, false, 9, 6, 30, false },
56 { 2880, 480, 16, 9, 108000, 0, false, 64, 248, 240, false, 9, 6, 30, false },
57 { 2880, 576, 4, 3, 108000, 0, false, 48, 256, 272, false, 5, 5, 39, false },
58 { 2880, 576, 16, 9, 108000, 0, false, 48, 256, 272, false, 5, 5, 39, false },
59 { 1920, 1080, 16, 9, 72000, 0, true, 32, 168, 184, true, 23, 5, 57, false, 0, 0, true },
60 { 1920, 1080, 16, 9, 148500, 0, true, 528, 44, 148, true, 2, 5, 15, true },
61 /* VIC 41 */
62 { 1280, 720, 16, 9, 148500, 0, false, 440, 40, 220, true, 5, 5, 20, true },
63 { 720, 576, 4, 3, 54000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
64 { 720, 576, 16, 9, 54000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
65 { 1440, 576, 4, 3, 54000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
66 { 1440, 576, 16, 9, 54000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
67 { 1920, 1080, 16, 9, 148500, 0, true, 88, 44, 148, true, 2, 5, 15, true },
68 { 1280, 720, 16, 9, 148500, 0, false, 110, 40, 220, true, 5, 5, 20, true },
69 { 720, 480, 4, 3, 54000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
70 { 720, 480, 16, 9, 54000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
71 { 1440, 480, 4, 3, 54000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
72 /* VIC 51 */
73 { 1440, 480, 16, 9, 54000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
74 { 720, 576, 4, 3, 108000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
75 { 720, 576, 16, 9, 108000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
76 { 1440, 576, 4, 3, 108000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
77 { 1440, 576, 16, 9, 108000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
78 { 720, 480, 4, 3, 108000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
79 { 720, 480, 16, 9, 108000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
80 { 1440, 480, 4, 3, 108000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
81 { 1440, 480, 16, 9, 108000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
82 { 1280, 720, 16, 9, 59400, 0, false, 1760, 40, 220, true, 5, 5, 20, true },
83 /* VIC 61 */
84 { 1280, 720, 16, 9, 74250, 0, false, 2420, 40, 220, true, 5, 5, 20, true },
85 { 1280, 720, 16, 9, 74250, 0, false, 1760, 40, 220, true, 5, 5, 20, true },
86 { 1920, 1080, 16, 9, 297000, 0, false, 88, 44, 148, true, 4, 5, 36, true },
87 { 1920, 1080, 16, 9, 297000, 0, false, 528, 44, 148, true, 4, 5, 36, true },
88 { 1280, 720, 64, 27, 59400, 0, false, 1760, 40, 220, true, 5, 5, 20, true },
89 { 1280, 720, 64, 27, 74250, 0, false, 2420, 40, 220, true, 5, 5, 20, true },
90 { 1280, 720, 64, 27, 74250, 0, false, 1760, 40, 220, true, 5, 5, 20, true },
91 { 1280, 720, 64, 27, 74250, 0, false, 440, 40, 220, true, 5, 5, 20, true },
92 { 1280, 720, 64, 27, 74250, 0, false, 110, 40, 220, true, 5, 5, 20, true },
93 { 1280, 720, 64, 27, 148500, 0, false, 440, 40, 220, true, 5, 5, 20, true },
94 /* VIC 71 */
95 { 1280, 720, 64, 27, 148500, 0, false, 110, 40, 220, true, 5, 5, 20, true },
96 { 1920, 1080, 64, 27, 74250, 0, false, 638, 44, 148, true, 4, 5, 36, true },
97 { 1920, 1080, 64, 27, 74250, 0, false, 528, 44, 148, true, 4, 5, 36, true },
98 { 1920, 1080, 64, 27, 74250, 0, false, 88, 44, 148, true, 4, 5, 36, true },
99 { 1920, 1080, 64, 27, 148500, 0, false, 528, 44, 148, true, 4, 5, 36, true },
100 { 1920, 1080, 64, 27, 148500, 0, false, 88, 44, 148, true, 4, 5, 36, true },
101 { 1920, 1080, 64, 27, 297000, 0, false, 528, 44, 148, true, 4, 5, 36, true },
102 { 1920, 1080, 64, 27, 297000, 0, false, 88, 44, 148, true, 4, 5, 36, true },
103 { 1680, 720, 64, 27, 59400, 0, false, 1360, 40, 220, true, 5, 5, 20, true },
104 { 1680, 720, 64, 27, 59400, 0, false, 1228, 40, 220, true, 5, 5, 20, true },
105 /* VIC 81 */
106 { 1680, 720, 64, 27, 59400, 0, false, 700, 40, 220, true, 5, 5, 20, true },
107 { 1680, 720, 64, 27, 82500, 0, false, 260, 40, 220, true, 5, 5, 20, true },
108 { 1680, 720, 64, 27, 99000, 0, false, 260, 40, 220, true, 5, 5, 20, true },
109 { 1680, 720, 64, 27, 165000, 0, false, 60, 40, 220, true, 5, 5, 95, true },
110 { 1680, 720, 64, 27, 198000, 0, false, 60, 40, 220, true, 5, 5, 95, true },
111 { 2560, 1080, 64, 27, 99000, 0, false, 998, 44, 148, true, 4, 5, 11, true },
112 { 2560, 1080, 64, 27, 90000, 0, false, 448, 44, 148, true, 4, 5, 36, true },
113 { 2560, 1080, 64, 27, 118800, 0, false, 768, 44, 148, true, 4, 5, 36, true },
114 { 2560, 1080, 64, 27, 185625, 0, false, 548, 44, 148, true, 4, 5, 36, true },
115 { 2560, 1080, 64, 27, 198000, 0, false, 248, 44, 148, true, 4, 5, 11, true },
116 /* VIC 91 */
117 { 2560, 1080, 64, 27, 371250, 0, false, 218, 44, 148, true, 4, 5, 161, true },
118 { 2560, 1080, 64, 27, 495000, 0, false, 548, 44, 148, true, 4, 5, 161, true },
119 { 3840, 2160, 16, 9, 297000, 0, false, 1276, 88, 296, true, 8, 10, 72, true },
120 { 3840, 2160, 16, 9, 297000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
121 { 3840, 2160, 16, 9, 297000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
122 { 3840, 2160, 16, 9, 594000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
123 { 3840, 2160, 16, 9, 594000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
124 { 4096, 2160, 256, 135, 297000, 0, false, 1020, 88, 296, true, 8, 10, 72, true },
125 { 4096, 2160, 256, 135, 297000, 0, false, 968, 88, 128, true, 8, 10, 72, true },
126 { 4096, 2160, 256, 135, 297000, 0, false, 88, 88, 128, true, 8, 10, 72, true },
127 /* VIC 101 */
128 { 4096, 2160, 256, 135, 594000, 0, false, 968, 88, 128, true, 8, 10, 72, true },
129 { 4096, 2160, 256, 135, 594000, 0, false, 88, 88, 128, true, 8, 10, 72, true },
130 { 3840, 2160, 64, 27, 297000, 0, false, 1276, 88, 296, true, 8, 10, 72, true },
131 { 3840, 2160, 64, 27, 297000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
132 { 3840, 2160, 64, 27, 297000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
133 { 3840, 2160, 64, 27, 594000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
134 { 3840, 2160, 64, 27, 594000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
135 { 1280, 720, 16, 9, 90000, 0, false, 960, 40, 220, true, 5, 5, 20, true },
136 { 1280, 720, 64, 27, 90000, 0, false, 960, 40, 220, true, 5, 5, 20, true },
137 { 1680, 720, 64, 27, 99000, 0, false, 810, 40, 220, true, 5, 5, 20, true },
138 /* VIC 111 */
139 { 1920, 1080, 16, 9, 148500, 0, false, 638, 44, 148, true, 4, 5, 36, true },
140 { 1920, 1080, 64, 27, 148500, 0, false, 638, 44, 148, true, 4, 5, 36, true },
141 { 2560, 1080, 64, 27, 198000, 0, false, 998, 44, 148, true, 4, 5, 11, true },
142 { 3840, 2160, 16, 9, 594000, 0, false, 1276, 88, 296, true, 8, 10, 72, true },
143 { 4096, 2160, 256, 135, 594000, 0, false, 1020, 88, 296, true, 8, 10, 72, true },
144 { 3840, 2160, 64, 27, 594000, 0, false, 1276, 88, 296, true, 8, 10, 72, true },
145 { 3840, 2160, 16, 9, 1188000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
146 { 3840, 2160, 16, 9, 1188000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
147 { 3840, 2160, 64, 27, 1188000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
148 { 3840, 2160, 64, 27, 1188000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
149 /* VIC 121 */
150 { 5120, 2160, 64, 27, 396000, 0, false, 1996, 88, 296, true, 8, 10, 22, true },
151 { 5120, 2160, 64, 27, 396000, 0, false, 1696, 88, 296, true, 8, 10, 22, true },
152 { 5120, 2160, 64, 27, 396000, 0, false, 664, 88, 128, true, 8, 10, 22, true },
153 { 5120, 2160, 64, 27, 742500, 0, false, 746, 88, 296, true, 8, 10, 297, true },
154 { 5120, 2160, 64, 27, 742500, 0, false, 1096, 88, 296, true, 8, 10, 72, true },
155 { 5120, 2160, 64, 27, 742500, 0, false, 164, 88, 128, true, 8, 10, 72, true },
156 { 5120, 2160, 64, 27, 1485000, 0, false, 1096, 88, 296, true, 8, 10, 72, true },
159 static const struct timings edid_cta_modes2[] = {
160 /* VIC 193 */
161 { 5120, 2160, 64, 27, 1485000, 0, false, 164, 88, 128, true, 8, 10, 72, true },
162 { 7680, 4320, 16, 9, 1188000, 0, false, 2552, 176, 592, true, 16, 20, 144, true },
163 { 7680, 4320, 16, 9, 1188000, 0, false, 2352, 176, 592, true, 16, 20, 44, true },
164 { 7680, 4320, 16, 9, 1188000, 0, false, 552, 176, 592, true, 16, 20, 44, true },
165 { 7680, 4320, 16, 9, 2376000, 0, false, 2552, 176, 592, true, 16, 20, 144, true },
166 { 7680, 4320, 16, 9, 2376000, 0, false, 2352, 176, 592, true, 16, 20, 44, true },
167 { 7680, 4320, 16, 9, 2376000, 0, false, 552, 176, 592, true, 16, 20, 44, true },
168 { 7680, 4320, 16, 9, 4752000, 0, false, 2112, 176, 592, true, 16, 20, 144, true },
169 /* VIC 201 */
170 { 7680, 4320, 16, 9, 4752000, 0, false, 352, 176, 592, true, 16, 20, 144, true },
171 { 7680, 4320, 64, 27, 1188000, 0, false, 2552, 176, 592, true, 16, 20, 144, true },
172 { 7680, 4320, 64, 27, 1188000, 0, false, 2352, 176, 592, true, 16, 20, 44, true },
173 { 7680, 4320, 64, 27, 1188000, 0, false, 552, 176, 592, true, 16, 20, 44, true },
174 { 7680, 4320, 64, 27, 2376000, 0, false, 2552, 176, 592, true, 16, 20, 144, true },
175 { 7680, 4320, 64, 27, 2376000, 0, false, 2352, 176, 592, true, 16, 20, 44, true },
176 { 7680, 4320, 64, 27, 2376000, 0, false, 552, 176, 592, true, 16, 20, 44, true },
177 { 7680, 4320, 64, 27, 4752000, 0, false, 2112, 176, 592, true, 16, 20, 144, true },
178 { 7680, 4320, 64, 27, 4752000, 0, false, 352, 176, 592, true, 16, 20, 144, true },
179 { 10240, 4320, 64, 27, 1485000, 0, false, 1492, 176, 592, true, 16, 20, 594, true },
180 /* VIC 211 */
181 { 10240, 4320, 64, 27, 1485000, 0, false, 2492, 176, 592, true, 16, 20, 44, true },
182 { 10240, 4320, 64, 27, 1485000, 0, false, 288, 176, 296, true, 16, 20, 144, true },
183 { 10240, 4320, 64, 27, 2970000, 0, false, 1492, 176, 592, true, 16, 20, 594, true },
184 { 10240, 4320, 64, 27, 2970000, 0, false, 2492, 176, 592, true, 16, 20, 44, true },
185 { 10240, 4320, 64, 27, 2970000, 0, false, 288, 176, 296, true, 16, 20, 144, true },
186 { 10240, 4320, 64, 27, 5940000, 0, false, 2192, 176, 592, true, 16, 20, 144, true },
187 { 10240, 4320, 64, 27, 5940000, 0, false, 288, 176, 296, true, 16, 20, 144, true },
188 { 4096, 2160, 256, 135, 1188000, 0, false, 800, 88, 296, true, 8, 10, 72, true },
189 { 4096, 2160, 256, 135, 1188000, 0, false, 88, 88, 128, true, 8, 10, 72, true },
192 static const cta_rid rids[] = {
193 /* RID 0-9 */
194 { 0, 0, 0, 0 },
195 { 1280, 720, 16, 9 },
196 { 1280, 720, 64, 27 },
197 { 1680, 720, 64, 27 },
198 { 1920, 1080, 16, 9 },
199 { 1920, 1080, 64, 27 },
200 { 2560, 1080, 64, 27 },
201 { 3840, 1080, 32, 9 },
202 { 2560, 1440, 16, 9 },
203 { 3440, 1440, 64, 27 },
204 /* RID 10-19 */
205 { 5120, 1440, 32, 9 },
206 { 3840, 2160, 16, 9 },
207 { 3840, 2160, 64, 27 },
208 { 5120, 2160, 64, 27 },
209 { 7680, 2160, 32, 9 },
210 { 5120, 2880, 16, 9 },
211 { 5120, 2880, 64, 27 },
212 { 6880, 2880, 64, 27 },
213 { 10240, 2880, 32, 9 },
214 { 7680, 4320, 16, 9 },
215 /* RID 20-28 */
216 { 7680, 4320, 64, 27 },
217 { 10240, 4320, 64, 27 },
218 { 15360, 4320, 32, 9 },
219 { 11520, 6480, 16, 9 },
220 { 11520, 6480, 64, 27 },
221 { 15360, 6480, 64, 27 },
222 { 15360, 8640, 16, 9 },
223 { 15360, 8640, 64, 27 },
224 { 20480, 8640, 64, 27 },
227 static const unsigned char rid2vic[ARRAY_SIZE(rids)][8] = {
228 /* RID 0-9 */
230 { 60, 61, 62, 108, 19, 4, 41, 47 },
231 { 65, 66, 67, 109, 68, 69, 70, 71 },
232 { 79, 80, 81, 110, 82, 83, 84, 85 },
233 { 32, 33, 34, 111, 31, 16, 64, 63 },
234 { 72, 73, 74, 112, 75, 76, 77, 78 },
235 { 86, 87, 88, 113, 89, 90, 91, 92 },
239 /* RID 10-19 */
241 { 93, 94, 95, 114, 96, 97, 117, 118 },
242 { 103, 104, 105, 116, 106, 107, 119, 120 },
243 { 121, 122, 123, 124, 125, 126, 127, 193 },
249 { 194, 195, 196, 197, 198, 199, 200, 201 },
250 /* RID 20-28 */
251 { 202, 203, 204, 205, 206, 207, 208, 209 },
252 { 210, 211, 212, 213, 214, 215, 216, 217 },
262 static const unsigned vf_rate_values[] = {
263 /* Rate Index 0-7 */
264 0, 24, 25, 30, 48, 50, 60, 100,
265 /* Rate Index 8-15 */
266 120, 144, 200, 240, 300, 360, 400, 480,
269 static const unsigned char edid_hdmi_mode_map[] = { 95, 94, 93, 98 };
271 unsigned char hdmi_vic_to_vic(unsigned char hdmi_vic)
273 if (hdmi_vic > 0 && hdmi_vic <= ARRAY_SIZE(edid_hdmi_mode_map))
274 return edid_hdmi_mode_map[hdmi_vic - 1];
275 return 0;
278 const struct timings *find_vic_id(unsigned char vic)
280 if (vic > 0 && vic <= ARRAY_SIZE(edid_cta_modes1))
281 return edid_cta_modes1 + vic - 1;
282 if (vic >= 193 && vic < ARRAY_SIZE(edid_cta_modes2) + 193)
283 return edid_cta_modes2 + vic - 193;
284 return NULL;
287 const struct timings *find_hdmi_vic_id(unsigned char hdmi_vic)
289 if (hdmi_vic > 0 && hdmi_vic <= ARRAY_SIZE(edid_hdmi_mode_map))
290 return find_vic_id(edid_hdmi_mode_map[hdmi_vic - 1]);
291 return NULL;
294 const struct cta_rid *find_rid(unsigned char rid)
296 if (rid > 0 && rid < ARRAY_SIZE(rids))
297 return &rids[rid];
298 return NULL;
301 static unsigned char rid_to_vic(unsigned char rid, unsigned char rate_index)
303 if (vf_rate_values[rate_index] > 120)
304 return 0;
305 return rid2vic[rid][rate_index - 1];
308 const struct timings *cta_close_match_to_vic(const timings &t, unsigned &vic)
310 for (vic = 1; vic <= ARRAY_SIZE(edid_cta_modes1); vic++) {
311 if (timings_close_match(t, edid_cta_modes1[vic - 1]))
312 return &edid_cta_modes1[vic - 1];
314 for (vic = 193; vic < ARRAY_SIZE(edid_cta_modes2) + 193; vic++) {
315 if (timings_close_match(t, edid_cta_modes1[vic - 193]))
316 return &edid_cta_modes1[vic - 193];
318 vic = 0;
319 return NULL;
322 bool cta_matches_vic(const timings &t, unsigned &vic)
324 for (vic = 1; vic <= ARRAY_SIZE(edid_cta_modes1); vic++) {
325 if (match_timings(t, edid_cta_modes1[vic - 1]))
326 return true;
328 for (vic = 193; vic < ARRAY_SIZE(edid_cta_modes2) + 193; vic++) {
329 if (match_timings(t, edid_cta_modes1[vic - 193]))
330 return true;
332 vic = 0;
333 return false;
336 void edid_state::cta_list_vics()
338 char type[16];
339 for (unsigned vic = 1; vic <= ARRAY_SIZE(edid_cta_modes1); vic++) {
340 sprintf(type, "VIC %3u", vic);
341 print_timings("", &edid_cta_modes1[vic - 1], type, "", false, false);
343 for (unsigned vic = 193; vic < ARRAY_SIZE(edid_cta_modes2) + 193; vic++) {
344 sprintf(type, "VIC %3u", vic);
345 print_timings("", &edid_cta_modes2[vic - 193], type, "", false, false);
349 void edid_state::cta_list_hdmi_vics()
351 for (unsigned i = 0; i < ARRAY_SIZE(edid_hdmi_mode_map); i++) {
352 unsigned vic = edid_hdmi_mode_map[i];
353 char type[16];
355 sprintf(type, "HDMI VIC %u", i + 1);
356 print_timings("", find_vic_id(vic), type, "", false, false);
360 void edid_state::cta_list_rids()
362 for (unsigned i = 1; i < ARRAY_SIZE(rids); i++) {
363 printf("RID %2u: %5ux%-4u %2u:%-2u\n", i,
364 rids[i].hact, rids[i].vact,
365 rids[i].hratio, rids[i].vratio);
369 void edid_state::cta_list_rid_timings(unsigned list_rid)
371 for (unsigned rid = 1; rid < ARRAY_SIZE(rids); rid++) {
372 char type[16];
374 if (list_rid && rid != list_rid)
375 continue;
377 sprintf(type, "RID %u", rid);
378 for (unsigned i = 1; i < ARRAY_SIZE(vf_rate_values); i++) {
379 unsigned fps = vf_rate_values[i];
381 if (rid_to_vic(rid, i)) {
382 printf("%s: %5ux%-4u %7.3f Hz %3u:%-2u maps to VIC %u\n", type,
383 rids[rid].hact, rids[rid].vact, (double)fps,
384 rids[rid].hratio, rids[rid].vratio,
385 rid_to_vic(rid, i));
386 continue;
388 timings t = calc_ovt_mode(rids[rid].hact, rids[rid].vact,
389 rids[rid].hratio, rids[rid].vratio, fps);
390 print_timings("", &t, type, "", false, false);
395 static std::string audio_ext_format(unsigned char x)
397 if (x >= 1 && x <= 3)
398 fail("Obsolete Audio Ext Format 0x%02x.\n", x);
399 switch (x) {
400 case 1: return "HE AAC (Obsolete)";
401 case 2: return "HE AAC v2 (Obsolete)";
402 case 3: return "MPEG Surround (Obsolete)";
403 case 4: return "MPEG-4 HE AAC";
404 case 5: return "MPEG-4 HE AAC v2";
405 case 6: return "MPEG-4 AAC LC";
406 case 7: return "DRA";
407 case 8: return "MPEG-4 HE AAC + MPEG Surround";
408 case 10: return "MPEG-4 AAC LC + MPEG Surround";
409 case 11: return "MPEG-H 3D Audio";
410 case 12: return "AC-4";
411 case 13: return "L-PCM 3D Audio";
412 case 14: return "Auro-Cx";
413 case 15: return "MPEG-D USAC";
414 default: break;
416 fail("Unknown Audio Ext Format 0x%02x.\n", x);
417 return std::string("Unknown Audio Ext Format (") + utohex(x) + ")";
420 static std::string audio_format(unsigned char x)
422 switch (x) {
423 case 1: return "Linear PCM";
424 case 2: return "AC-3";
425 case 3: return "MPEG 1 (Layers 1 & 2)";
426 case 4: return "MPEG 1 Layer 3 (MP3)";
427 case 5: return "MPEG2 (multichannel)";
428 case 6: return "AAC LC";
429 case 7: return "DTS";
430 case 8: return "ATRAC";
431 case 9: return "One Bit Audio";
432 case 10: return "Enhanced AC-3 (DD+)";
433 case 11: return "DTS-HD";
434 case 12: return "MAT (MLP)";
435 case 13: return "DST";
436 case 14: return "WMA Pro";
437 default: break;
439 fail("Unknown Audio Format 0x%02x.\n", x);
440 return std::string("Unknown Audio Format (") + utohex(x) + ")";
443 static std::string mpeg_h_3d_audio_level(unsigned char x)
445 switch (x) {
446 case 0: return "Unspecified";
447 case 1: return "Level 1";
448 case 2: return "Level 2";
449 case 3: return "Level 3";
450 case 4: return "Level 4";
451 case 5: return "Level 5";
452 default: break;
454 fail("Unknown MPEG-H 3D Audio Level 0x%02x.\n", x);
455 return std::string("Unknown MPEG-H 3D Audio Level (") + utohex(x) + ")";
458 static void cta_audio_block(const unsigned char *x, unsigned length)
460 unsigned i, format, ext_format;
462 if (length % 3) {
463 fail("Broken CTA-861 audio block length %d.\n", length);
464 return;
467 for (i = 0; i < length; i += 3) {
468 format = (x[i] & 0x78) >> 3;
469 if (format == 0) {
470 printf(" Reserved (0x00)\n");
471 fail("Audio Format Code 0x00 is reserved.\n");
472 continue;
474 if (format != 15) {
475 ext_format = 0;
476 printf(" %s:\n", audio_format(format).c_str());
477 } else {
478 ext_format = (x[i + 2] & 0xf8) >> 3;
479 printf(" %s:\n", audio_ext_format(ext_format).c_str());
481 if (format != 15)
482 printf(" Max channels: %u\n", (x[i] & 0x07)+1);
483 else if (ext_format == 11)
484 printf(" MPEG-H 3D Audio Level: %s\n",
485 mpeg_h_3d_audio_level(x[i] & 0x07).c_str());
486 else if (ext_format == 13)
487 printf(" Max channels: %u\n",
488 (((x[i + 1] & 0x80) >> 3) | ((x[i] & 0x80) >> 4) |
489 (x[i] & 0x07))+1);
490 else if ((ext_format == 12 || ext_format == 14) && (x[i] & 0x07))
491 fail("Bits F10-F12 must be 0.\n");
492 else
493 printf(" Max channels: %u\n", (x[i] & 0x07)+1);
495 if ((format == 1 || format == 14) && (x[i + 2] & 0xf8))
496 fail("Bits F33-F37 must be 0.\n");
497 if (ext_format != 13 && (x[i+1] & 0x80))
498 fail("Bit F27 must be 0.\n");
500 // Several sample rates are not supported in certain formats
501 if (ext_format == 12 && (x[i+1] & 0x29))
502 fail("Bits F20, F23 and F25 must be 0.\n");
503 if (ext_format >= 4 && ext_format <= 6 && (x[i+1] & 0x60))
504 fail("Bits F25 and F26 must be 0.\n");
505 if ((ext_format == 8 || ext_format == 10 || ext_format == 15) && (x[i+1] & 0x60))
506 fail("Bits F25 and F26 must be 0.\n");
508 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
509 (x[i+1] & 0x40) ? " 192" : "",
510 (x[i+1] & 0x20) ? " 176.4" : "",
511 (x[i+1] & 0x10) ? " 96" : "",
512 (x[i+1] & 0x08) ? " 88.2" : "",
513 (x[i+1] & 0x04) ? " 48" : "",
514 (x[i+1] & 0x02) ? " 44.1" : "",
515 (x[i+1] & 0x01) ? " 32" : "");
516 if (format == 1 || ext_format == 13) {
517 printf(" Supported sample sizes (bits):%s%s%s\n",
518 (x[i+2] & 0x04) ? " 24" : "",
519 (x[i+2] & 0x02) ? " 20" : "",
520 (x[i+2] & 0x01) ? " 16" : "");
521 } else if (format <= 8) {
522 printf(" Maximum bit rate: %u kb/s\n", x[i+2] * 8);
523 } else if (format == 10) {
524 // As specified by the "Dolby Audio and Dolby Atmos over HDMI"
525 // specification (v1.0).
526 if (x[i+2] & 1)
527 printf(" Supports Joint Object Coding\n");
528 if (x[i+2] & 2)
529 printf(" Supports Joint Object Coding with ACMOD28\n");
530 } else if (format == 11) {
531 // Reverse engineering, see:
532 // https://www.avsforum.com/threads/lg-c9-earc-info-thread.3072900/post-61795538
533 if (x[i+2] & 2)
534 printf(" Supports DTS:X\n");
535 // Note: I strongly suspect that bit 0 indicates DTS-HD MA support.
536 printf(" Audio Format Code dependent value: 0x%02x\n", x[i+2]);
537 } else if (format == 12) {
538 if (x[i+2] & 1) {
539 printf(" Supports Dolby TrueHD, object audio PCM and channel-based PCM\n");
540 printf(" Hash calculation %srequired for object audio PCM or channel-based PCM\n",
541 (x[i+2] & 2) ? "not " : "");
542 } else {
543 printf(" Supports only Dolby TrueHD\n");
545 } else if (format == 14) {
546 printf(" Profile: %u\n", x[i+2] & 7);
547 } else if (format >= 9 && format <= 13) {
548 printf(" Audio Format Code dependent value: 0x%02x\n", x[i+2]);
549 } else if (ext_format == 11 && (x[i+2] & 1)) {
550 printf(" Supports MPEG-H 3D Audio Low Complexity Profile\n");
551 } else if ((ext_format >= 4 && ext_format <= 6) ||
552 ext_format == 8 || ext_format == 10) {
553 printf(" AAC audio frame lengths:%s%s\n",
554 (x[i+2] & 4) ? " 1024_TL" : "",
555 (x[i+2] & 2) ? " 960_TL" : "");
556 if (ext_format >= 8 && (x[i+2] & 1))
557 printf(" Supports %s signaled MPEG Surround data\n",
558 (x[i+2] & 1) ? "implicitly and explicitly" : "only implicitly");
559 if (ext_format == 6 && (x[i+2] & 1))
560 printf(" Supports 22.2ch System H\n");
561 } else if (ext_format == 12 || ext_format == 14) {
562 printf(" Audio Format Code dependent value: %u\n", x[i+2] & 7);
567 void edid_state::cta_svd(const unsigned char *x, unsigned n, bool for_ycbcr420)
569 bool ascending = !for_ycbcr420;
570 unsigned char last_vic = 0;
571 bool first_vic_is_1_to_4 = false;
572 bool have_vics_5_and_up = false;
573 unsigned i;
575 for (i = 0; i < n; i++) {
576 const struct timings *t = NULL;
577 unsigned char svd = x[i];
578 unsigned char native;
579 unsigned char vic;
581 if ((svd & 0x7f) == 0)
582 continue;
584 if ((svd - 1) & 0x40) {
585 vic = svd;
586 native = 0;
587 } else {
588 vic = svd & 0x7f;
589 native = svd & 0x80;
592 if (i == 0)
593 first_vic_is_1_to_4 = vic <= 4;
594 if (vic > 4)
595 have_vics_5_and_up = true;
596 if (vic < last_vic)
597 ascending = false;
598 last_vic = vic;
600 t = find_vic_id(vic);
601 if (t) {
602 switch (vic) {
603 case 95:
604 cta.supported_hdmi_vic_vsb_codes |= 1 << 0;
605 break;
606 case 94:
607 cta.supported_hdmi_vic_vsb_codes |= 1 << 1;
608 break;
609 case 93:
610 cta.supported_hdmi_vic_vsb_codes |= 1 << 2;
611 break;
612 case 98:
613 cta.supported_hdmi_vic_vsb_codes |= 1 << 3;
614 break;
616 bool first_svd = cta.first_svd && !for_ycbcr420;
617 bool override_pref = first_svd && cta.first_svd_might_be_preferred;
619 char type[16];
620 sprintf(type, "VIC %3u", vic);
621 const char *flags = native ? "native" : "";
623 if (for_ycbcr420) {
624 struct timings tmp = *t;
625 tmp.ycbcr420 = true;
626 print_timings(" ", &tmp, type, flags);
627 } else {
628 print_timings(" ", t, type, flags);
630 if (override_pref) {
631 if (!cta.preferred_timings.empty()) {
632 if (match_timings(cta.preferred_timings[0].t, *t))
633 warn("For improved preferred timing interoperability, set 'Native detailed modes' to 1.\n");
634 else
635 warn("VIC %u is the preferred timing, overriding the first detailed timings. Is this intended?\n", vic);
637 cta.preferred_timings.insert(cta.preferred_timings.begin(),
638 timings_ext(*t, type, flags));
639 } else if (first_svd) {
640 cta.preferred_timings.push_back(timings_ext(*t, type, flags));
642 if (first_svd) {
643 cta.first_svd = false;
644 cta.first_svd_might_be_preferred = false;
646 if (native)
647 cta.native_timings.push_back(timings_ext(*t, type, flags));
648 } else {
649 printf(" Unknown (VIC %3u)\n", vic);
650 fail("Unknown VIC %u.\n", vic);
653 if (vic == 1 && !for_ycbcr420)
654 cta.has_vic_1 = 1;
655 if (++cta.vics[vic][for_ycbcr420] == 2)
656 fail("Duplicate %sVIC %u.\n", for_ycbcr420 ? "YCbCr 4:2:0 " : "", vic);
657 if (for_ycbcr420 && cta.preparsed_has_vic[0][vic])
658 fail("YCbCr 4:2:0-only VIC %u is also a regular VIC.\n", vic);
660 if (n > 1 && ascending && first_vic_is_1_to_4 && have_vics_5_and_up)
661 warn("All VICs are in ascending order, and the first (preferred) VIC <= 4, is that intended?\n");
664 cta_vfd edid_state::cta_parse_vfd(const unsigned char *x, unsigned lvfd)
666 cta_vfd vfd = {};
668 vfd.rid = x[0] & 0x3f;
669 if (vfd.rid >= ARRAY_SIZE(rids)) {
670 vfd.rid = 0;
671 return vfd;
673 vfd.bfr50 = !!(x[0] & 0x80);
674 vfd.fr24 = !!(x[0] & 0x40);
675 vfd.bfr60 = lvfd > 1 ? !!(x[1] & 0x80) : 1;
676 vfd.fr144 = lvfd > 1 ? !!(x[1] & 0x40) : 0;
677 vfd.fr_factor = lvfd > 1 ? (x[1] & 0x3f) : 3;
678 vfd.fr48 = lvfd > 2 ? !!(x[2] & 0x01) : 0;
679 return vfd;
682 static bool vfd_has_rate(cta_vfd &vfd, unsigned rate_index)
684 static const unsigned factors[6] = {
685 1, 2, 4, 8, 12, 16
687 unsigned rate = vf_rate_values[rate_index];
688 unsigned factor = 0;
690 if (!vfd.rid)
691 return false;
692 if (rate == 24)
693 return vfd.fr24;
694 if (rate == 48)
695 return vfd.fr48;
696 if (rate == 144)
697 return vfd.fr144;
699 if (!(rate % 30)) {
700 if (!vfd.bfr60)
701 return false;
702 factor = rate / 30;
704 if (!(rate % 25)) {
705 if (!vfd.bfr50)
706 return false;
707 factor = rate / 25;
710 for (unsigned i = 0; i < ARRAY_SIZE(factors); i++)
711 if (factors[i] == factor && (vfd.fr_factor & (1 << i)))
712 return true;
713 return false;
716 void edid_state::cta_vfdb(const unsigned char *x, unsigned n)
718 if (n-- == 0) {
719 fail("Length is 0.\n");
720 return;
722 unsigned char flags = *x++;
723 unsigned lvfd = (flags & 3) + 1;
725 if (n % lvfd) {
726 fail("Length - 1 is not a multiple of Lvfd (%u).\n", lvfd);
727 return;
729 if (flags & 0x80)
730 printf(" Supports YCbCr 4:2:0\n");
731 if (flags & 0x40)
732 printf(" NTSC fractional frame rates are preferred\n");
733 for (unsigned i = 0; i < n; i += lvfd, x += lvfd) {
734 unsigned char rid = x[0] & 0x3f;
735 cta_vfd vfd = cta_parse_vfd(x, lvfd);
737 if (lvfd > 2 && (x[2] & 0xfe))
738 fail("Bits F31-F37 must be 0.\n");
739 if (lvfd > 3 && x[3])
740 fail("Bits F40-F47 must be 0.\n");
741 if (rid == 0 || rid >= ARRAY_SIZE(rids)) {
742 fail("Unknown RID %u.\n", rid);
743 continue;
745 for (unsigned rate_index = 1; rate_index < ARRAY_SIZE(vf_rate_values); rate_index++) {
746 if (!vfd_has_rate(vfd, rate_index))
747 continue;
748 struct timings t = calc_ovt_mode(rids[vfd.rid].hact,
749 rids[vfd.rid].vact,
750 rids[vfd.rid].hratio,
751 rids[vfd.rid].vratio,
752 vf_rate_values[rate_index]);
753 char type[16];
754 sprintf(type, "RID %u@%up", rid, vf_rate_values[rate_index]);
755 print_timings(" ", &t, type);
756 if (rid_to_vic(vfd.rid, rate_index))
757 fail("%s not allowed since it maps to VIC %u.\n",
758 type, rid_to_vic(vfd.rid, rate_index));
763 void edid_state::print_vic_index(const char *prefix, unsigned idx, const char *suffix, bool ycbcr420)
765 if (!suffix)
766 suffix = "";
767 if (idx < cta.preparsed_svds[0].size()) {
768 unsigned char vic = cta.preparsed_svds[0][idx];
769 const struct timings *t = find_vic_id(vic);
770 char buf[16];
772 sprintf(buf, "VIC %3u", vic);
774 if (t) {
775 struct timings tmp = *t;
776 tmp.ycbcr420 = ycbcr420;
777 print_timings(prefix, &tmp, buf, suffix);
778 } else {
779 printf("%sUnknown (%s%s%s)\n", prefix, buf,
780 *suffix ? ", " : "", suffix);
782 } else {
783 // Should not happen!
784 printf("%sSVD Index %u is out of range", prefix, idx + 1);
785 if (*suffix)
786 printf(" (%s)", suffix);
787 printf("\n");
791 void edid_state::cta_y420cmdb(const unsigned char *x, unsigned length)
793 unsigned max_idx = 0;
794 unsigned i;
796 if (!length) {
797 printf(" All VDB SVDs\n");
798 return;
801 if (memchk(x, length)) {
802 printf(" Empty Capability Map\n");
803 fail("Empty Capability Map.\n");
804 return;
807 for (i = 0; i < length; i++) {
808 unsigned char v = x[i];
809 unsigned j;
811 for (j = 0; j < 8; j++) {
812 if (!(v & (1 << j)))
813 continue;
815 print_vic_index(" ", i * 8 + j, "", true);
816 max_idx = i * 8 + j;
817 if (max_idx < cta.preparsed_svds[0].size()) {
818 unsigned vic = cta.preparsed_svds[0][max_idx];
819 if (cta.preparsed_has_vic[1][vic])
820 fail("VIC %u is also a YCbCr 4:2:0-only VIC.\n", vic);
824 if (max_idx >= cta.preparsed_svds[0].size())
825 fail("Max index %u > %u (#SVDs).\n",
826 max_idx + 1, cta.preparsed_svds[0].size());
829 void edid_state::cta_print_svr(unsigned char svr, vec_timings_ext &vec_tim)
831 char suffix[24];
833 if ((svr > 0 && svr < 128) || (svr > 192 && svr < 254)) {
834 const struct timings *t;
835 unsigned char vic = svr;
837 sprintf(suffix, "VIC %3u", vic);
839 t = find_vic_id(vic);
840 if (t) {
841 print_timings(" ", t, suffix);
842 vec_tim.push_back(timings_ext(*t, suffix, ""));
843 } else {
844 printf(" %s: Unknown\n", suffix);
845 fail("Unknown VIC %u.\n", vic);
848 } else if (svr >= 129 && svr <= 144) {
849 sprintf(suffix, "DTD %3u", svr - 128);
850 if (svr >= cta.preparsed_total_dtds + 129) {
851 printf(" %s: Invalid\n", suffix);
852 fail("Invalid DTD %u.\n", svr - 128);
853 } else {
854 printf(" %s\n", suffix);
855 vec_tim.push_back(timings_ext(svr, suffix));
856 cta.has_svrs = true;
858 } else if (svr >= 145 && svr <= 160) {
859 sprintf(suffix, "VTDB %3u", svr - 144);
860 if (svr >= cta.preparsed_total_vtdbs + 145) {
861 printf(" %s: Invalid\n", suffix);
862 fail("Invalid VTDB %u.\n", svr - 144);
863 } else {
864 printf(" %s\n", suffix);
865 vec_tim.push_back(timings_ext(svr, suffix));
866 cta.has_svrs = true;
868 } else if (svr >= 161 && svr <= 175) {
869 sprintf(suffix, "RID %u@%up",
870 cta.preparsed_first_vfd.rid, vf_rate_values[svr - 160]);
871 if (!vfd_has_rate(cta.preparsed_first_vfd, svr - 160)) {
872 printf(" %s: Invalid\n", suffix);
873 fail("Invalid %s.\n", suffix);
874 } else {
875 printf(" %s\n", suffix);
876 vec_tim.push_back(timings_ext(svr, suffix));
877 cta.has_svrs = true;
879 } else if (svr == 254) {
880 sprintf(suffix, "T8VTDB");
881 if (!cta.preparsed_has_t8vtdb) {
882 printf(" %s: Invalid\n", suffix);
883 fail("Invalid T8VTDB.\n");
884 } else {
885 sprintf(suffix, "DMT 0x%02x", cta.preparsed_t8vtdb_dmt);
886 printf(" %s\n", suffix);
887 vec_tim.push_back(timings_ext(svr, suffix));
888 cta.has_svrs = true;
893 void edid_state::cta_vfpdb(const unsigned char *x, unsigned length)
895 unsigned i;
897 if (length == 0) {
898 fail("Empty Data Block with length %u.\n", length);
899 return;
901 cta.preferred_timings_vfpdb.clear();
902 for (i = 0; i < length; i++)
903 cta_print_svr(x[i], cta.preferred_timings_vfpdb);
906 void edid_state::cta_nvrdb(const unsigned char *x, unsigned length)
908 if (length == 0) {
909 fail("Empty Data Block with length %u.\n", length);
910 return;
913 unsigned char flags = length == 1 ? 0 : x[1];
915 cta.native_timing_nvrdb.clear();
916 cta_print_svr(x[0], cta.native_timing_nvrdb);
917 if ((flags & 1) && length < 6) {
918 fail("Data Block too short for Image Size (length = %u).\n", length);
919 return;
921 if (flags & 0x7e)
922 fail("Bits F41-F46 must be 0.\n");
923 if (!(flags & 1))
924 return;
926 unsigned w = (x[3] << 8) | x[2];
927 unsigned h = (x[5] << 8) | x[4];
929 if (!w || !h)
930 fail("Image Size has a zero width and/or height.\n");
932 if (flags & 0x80)
933 printf(" Image Size: %ux%u mm\n", w, h);
934 else
935 printf(" Image Size: %.1fx%.1f mm\n", w / 10.0, h / 10.0);
938 static std::string hdmi_latency2s(unsigned char l, bool is_video)
940 if (!l)
941 return "Unknown";
942 if (l == 0xff)
943 return is_video ? "Video not supported" : "Audio not supported";
944 return std::to_string(2 * (l - 1)) + " ms";
947 void edid_state::hdmi_latency(unsigned char vid_lat, unsigned char aud_lat,
948 bool is_ilaced)
950 const char *vid = is_ilaced ? "Interlaced video" : "Video";
951 const char *aud = is_ilaced ? "Interlaced audio" : "Audio";
953 printf(" %s latency: %s\n", vid, hdmi_latency2s(vid_lat, true).c_str());
954 printf(" %s latency: %s\n", aud, hdmi_latency2s(aud_lat, false).c_str());
956 if (vid_lat > 251 && vid_lat != 0xff)
957 fail("Invalid %s latency value %u.\n", vid, vid_lat);
958 if (aud_lat > 251 && aud_lat != 0xff)
959 fail("Invalid %s latency value %u.\n", aud, aud_lat);
961 if (!vid_lat || vid_lat > 251)
962 return;
963 if (!aud_lat || aud_lat > 251)
964 return;
966 unsigned vid_ms = 2 * (vid_lat - 1);
967 unsigned aud_ms = 2 * (aud_lat - 1);
969 // HDMI 2.0 latency checks for devices without HDMI output
970 if (aud_ms < vid_ms)
971 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
972 aud, vid, aud_ms, vid_ms);
973 else if (vid_ms + 20 < aud_ms)
974 warn("%s latency + 20 < %s latency (%u + 20 ms < %u ms). This is forbidden for devices without HDMI output.\n",
975 vid, aud, vid_ms, aud_ms);
976 else if (vid_ms < aud_ms)
977 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
978 vid, aud, vid_ms, aud_ms);
981 void edid_state::cta_hdmi_block(const unsigned char *x, unsigned length)
983 unsigned len_vic, len_3d;
985 if (length < 1) {
986 fail("Empty Data Block with length %u.\n", length);
987 return;
989 printf(" Source physical address: %x.%x.%x.%x\n", x[0] >> 4, x[0] & 0x0f,
990 x[1] >> 4, x[1] & 0x0f);
992 if (length < 3)
993 return;
995 if (x[2] & 0x80)
996 printf(" Supports_AI\n");
997 if (x[2] & 0x40)
998 printf(" DC_48bit\n");
999 if (x[2] & 0x20)
1000 printf(" DC_36bit\n");
1001 if (x[2] & 0x10)
1002 printf(" DC_30bit\n");
1003 if (x[2] & 0x08)
1004 printf(" DC_Y444\n");
1005 /* two reserved bits */
1006 if (x[2] & 0x01)
1007 printf(" DVI_Dual\n");
1009 if (length < 4)
1010 return;
1012 printf(" Maximum TMDS clock: %u MHz\n", x[3] * 5);
1013 if (x[3] * 5 > 340)
1014 fail("HDMI VSDB Max TMDS rate is > 340.\n");
1016 if (length < 5)
1017 return;
1019 if (x[4] & 0x0f) {
1020 printf(" Supported Content Types:\n");
1021 if (x[4] & 0x01)
1022 printf(" Graphics\n");
1023 if (x[4] & 0x02)
1024 printf(" Photo\n");
1025 if (x[4] & 0x04)
1026 printf(" Cinema\n");
1027 if (x[4] & 0x08)
1028 printf(" Game\n");
1031 unsigned b = 5;
1032 if (x[4] & 0x80) {
1033 hdmi_latency(x[b], x[b + 1], false);
1035 if (x[4] & 0x40) {
1036 if (x[b] == x[b + 2] &&
1037 x[b + 1] == x[b + 3])
1038 warn("Progressive and Interlaced latency values are identical, no need for both.\n");
1039 b += 2;
1040 hdmi_latency(x[b], x[b + 1], true);
1042 b += 2;
1045 if (!(x[4] & 0x20))
1046 return;
1048 bool mask = false;
1049 bool formats = false;
1051 printf(" Extended HDMI video details:\n");
1052 if (x[b] & 0x80)
1053 printf(" 3D present\n");
1054 if ((x[b] & 0x60) == 0x20) {
1055 printf(" All advertised VICs are 3D-capable\n");
1056 formats = true;
1058 if ((x[b] & 0x60) == 0x40) {
1059 printf(" 3D-capable-VIC mask present\n");
1060 formats = true;
1061 mask = true;
1063 switch (x[b] & 0x18) {
1064 case 0x00: break;
1065 case 0x08:
1066 printf(" Base EDID image size is aspect ratio\n");
1067 break;
1068 case 0x10:
1069 printf(" Base EDID image size is in units of 1 cm\n");
1070 break;
1071 case 0x18:
1072 printf(" Base EDID image size is in units of 5 cm\n");
1073 base.max_display_width_mm *= 5;
1074 base.max_display_height_mm *= 5;
1075 printf(" Recalculated image size: %u cm x %u cm\n",
1076 base.max_display_width_mm / 10, base.max_display_height_mm / 10);
1077 break;
1079 b++;
1080 len_vic = (x[b] & 0xe0) >> 5;
1081 len_3d = (x[b] & 0x1f) >> 0;
1082 b++;
1084 if (len_vic) {
1085 unsigned i;
1087 printf(" HDMI VICs:\n");
1088 for (i = 0; i < len_vic; i++) {
1089 unsigned char vic = x[b + i];
1090 const struct timings *t;
1092 if (vic && vic <= ARRAY_SIZE(edid_hdmi_mode_map)) {
1093 std::string suffix = "HDMI VIC " + std::to_string(vic);
1094 cta.supported_hdmi_vic_codes |= 1 << (vic - 1);
1095 t = find_vic_id(edid_hdmi_mode_map[vic - 1]);
1096 print_timings(" ", t, suffix.c_str());
1097 } else {
1098 printf(" Unknown (HDMI VIC %u)\n", vic);
1099 fail("Unknown HDMI VIC %u.\n", vic);
1103 b += len_vic;
1106 if (!len_3d)
1107 return;
1109 if (formats) {
1110 /* 3D_Structure_ALL_15..8 */
1111 if (x[b] & 0x80)
1112 printf(" 3D: Side-by-side (half, quincunx)\n");
1113 if (x[b] & 0x01)
1114 printf(" 3D: Side-by-side (half, horizontal)\n");
1115 /* 3D_Structure_ALL_7..0 */
1116 b++;
1117 if (x[b] & 0x40)
1118 printf(" 3D: Top-and-bottom\n");
1119 if (x[b] & 0x20)
1120 printf(" 3D: L + depth + gfx + gfx-depth\n");
1121 if (x[b] & 0x10)
1122 printf(" 3D: L + depth\n");
1123 if (x[b] & 0x08)
1124 printf(" 3D: Side-by-side (full)\n");
1125 if (x[b] & 0x04)
1126 printf(" 3D: Line-alternative\n");
1127 if (x[b] & 0x02)
1128 printf(" 3D: Field-alternative\n");
1129 if (x[b] & 0x01)
1130 printf(" 3D: Frame-packing\n");
1131 b++;
1132 len_3d -= 2;
1135 if (mask) {
1136 int max_idx = -1;
1137 unsigned i;
1139 printf(" 3D VIC indices that support these capabilities:\n");
1140 /* worst bit ordering ever */
1141 for (i = 0; i < 8; i++)
1142 if (x[b + 1] & (1 << i)) {
1143 print_vic_index(" ", i, "");
1144 max_idx = i;
1146 for (i = 0; i < 8; i++)
1147 if (x[b] & (1 << i)) {
1148 print_vic_index(" ", i + 8, "");
1149 max_idx = i + 8;
1151 b += 2;
1152 len_3d -= 2;
1153 if (max_idx >= (int)cta.preparsed_svds[0].size())
1154 fail("HDMI 3D VIC indices max index %d > %u (#SVDs).\n",
1155 max_idx + 1, cta.preparsed_svds[0].size());
1159 * list of nibbles:
1160 * 2D_VIC_Order_X
1161 * 3D_Structure_X
1162 * (optionally: 3D_Detail_X and reserved)
1164 if (!len_3d)
1165 return;
1167 unsigned end = b + len_3d;
1168 int max_idx = -1;
1170 printf(" 3D VIC indices with specific capabilities:\n");
1171 while (b < end) {
1172 unsigned char idx = x[b] >> 4;
1173 std::string s;
1175 if (idx > max_idx)
1176 max_idx = idx;
1177 switch (x[b] & 0x0f) {
1178 case 0: s = "frame packing"; break;
1179 case 1: s = "field alternative"; break;
1180 case 2: s = "line alternative"; break;
1181 case 3: s = "side-by-side (full)"; break;
1182 case 4: s = "L + depth"; break;
1183 case 5: s = "L + depth + gfx + gfx-depth"; break;
1184 case 6: s = "top-and-bottom"; break;
1185 case 8:
1186 s = "side-by-side";
1187 switch (x[b + 1] >> 4) {
1188 case 0x00: s += ", any subsampling"; break;
1189 case 0x01: s += ", horizontal"; break;
1190 case 0x02: case 0x03: case 0x04: case 0x05:
1191 s += ", not in use";
1192 fail("not-in-use 3D_Detail_X value 0x%02x.\n",
1193 x[b + 1] >> 4);
1194 break;
1195 case 0x06: s += ", all quincunx combinations"; break;
1196 case 0x07: s += ", quincunx odd/left, odd/right"; break;
1197 case 0x08: s += ", quincunx odd/left, even/right"; break;
1198 case 0x09: s += ", quincunx even/left, odd/right"; break;
1199 case 0x0a: s += ", quincunx even/left, even/right"; break;
1200 default:
1201 s += ", reserved";
1202 fail("reserved 3D_Detail_X value 0x%02x.\n",
1203 x[b + 1] >> 4);
1204 break;
1206 break;
1207 default:
1208 s = "unknown (";
1209 s += utohex(x[b] & 0x0f) + ")";
1210 fail("Unknown 3D_Structure_X value 0x%02x.\n", x[b] & 0x0f);
1211 break;
1213 print_vic_index(" ", idx, s.c_str());
1214 if ((x[b] & 0x0f) >= 8)
1215 b++;
1216 b++;
1218 if (max_idx >= (int)cta.preparsed_svds[0].size())
1219 fail("HDMI 2D VIC indices max index %d > %u (#SVDs).\n",
1220 max_idx + 1, cta.preparsed_svds[0].size());
1223 static const char *max_frl_rates[] = {
1224 "Not Supported",
1225 "3 Gbps per lane on 3 lanes",
1226 "3 and 6 Gbps per lane on 3 lanes",
1227 "3 and 6 Gbps per lane on 3 lanes, 6 Gbps on 4 lanes",
1228 "3 and 6 Gbps per lane on 3 lanes, 6 and 8 Gbps on 4 lanes",
1229 "3 and 6 Gbps per lane on 3 lanes, 6, 8 and 10 Gbps on 4 lanes",
1230 "3 and 6 Gbps per lane on 3 lanes, 6, 8, 10 and 12 Gbps on 4 lanes",
1233 static const char *dsc_max_slices[] = {
1234 "Not Supported",
1235 "up to 1 slice and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1236 "up to 2 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1237 "up to 4 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1238 "up to 8 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1239 "up to 8 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1240 "up to 12 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1241 "up to 12 slices and up to (600 MHz/Ksliceadjust) pixel clock per slice",
1244 static void cta_hf_eeodb(const unsigned char *x, unsigned length)
1246 printf(" EDID Extension Block Count: %u\n", x[0]);
1247 if (length != 1)
1248 fail("Block is too long.\n");
1249 if (x[0] <= 1)
1250 fail("Extension Block Count == %u.\n", x[0]);
1253 static void cta_hf_scdb(const unsigned char *x, unsigned length)
1255 unsigned rate = x[1] * 5;
1256 unsigned v;
1258 printf(" Version: %u\n", x[0]);
1259 if (rate) {
1260 printf(" Maximum TMDS Character Rate: %u MHz\n", rate);
1261 if (rate <= 340 || rate > 600)
1262 fail("Max TMDS rate is > 0 and <= 340 or > 600.\n");
1264 if (x[2] & 0x80)
1265 printf(" SCDC Present\n");
1266 if (x[2] & 0x40)
1267 printf(" SCDC Read Request Capable\n");
1268 if (x[2] & 0x20)
1269 printf(" Supports Cable Status\n");
1270 if (x[2] & 0x10)
1271 printf(" Supports Color Content Bits Per Component Indication\n");
1272 if (x[2] & 0x08)
1273 printf(" Supports scrambling for <= 340 Mcsc\n");
1274 if (x[2] & 0x04)
1275 printf(" Supports 3D Independent View signaling\n");
1276 if (x[2] & 0x02)
1277 printf(" Supports 3D Dual View signaling\n");
1278 if (x[2] & 0x01)
1279 printf(" Supports 3D OSD Disparity signaling\n");
1280 if (x[3] & 0xf0) {
1281 unsigned max_frl_rate = x[3] >> 4;
1283 printf(" Max Fixed Rate Link: ");
1284 if (max_frl_rate < ARRAY_SIZE(max_frl_rates)) {
1285 printf("%s\n", max_frl_rates[max_frl_rate]);
1286 } else {
1287 printf("Unknown (0x%02x)\n", max_frl_rate);
1288 fail("Unknown Max Fixed Rate Link (0x%02x).\n", max_frl_rate);
1290 if (max_frl_rate == 1 && rate < 300)
1291 fail("Max Fixed Rate Link is 1, but Max TMDS rate < 300.\n");
1292 else if (max_frl_rate >= 2 && rate < 600)
1293 fail("Max Fixed Rate Link is >= 2, but Max TMDS rate < 600.\n");
1295 if (x[3] & 0x08)
1296 printf(" Supports UHD VIC\n");
1297 if (x[3] & 0x04)
1298 printf(" Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1299 if (x[3] & 0x02)
1300 printf(" Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1301 if (x[3] & 0x01)
1302 printf(" Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1304 if (length <= 4)
1305 return;
1307 if (x[4] & 0x80)
1308 printf(" Supports FAPA End Extended\n");
1309 if (x[4] & 0x40)
1310 printf(" Supports QMS\n");
1311 if (x[4] & 0x20)
1312 printf(" Supports Mdelta\n");
1313 if (x[4] & 0x10) {
1314 printf(" Supports media rates below VRRmin (CinemaVRR, deprecated)\n");
1315 warn("CinemaVRR is deprecated and must be cleared.\n");
1317 if (x[4] & 0x08)
1318 printf(" Supports negative Mvrr values\n");
1319 if (x[4] & 0x04)
1320 printf(" Supports Fast Vactive\n");
1321 if (x[4] & 0x02)
1322 printf(" Supports Auto Low-Latency Mode\n");
1323 if (x[4] & 0x01)
1324 printf(" Supports a FAPA in blanking after first active video line\n");
1326 if (length <= 5)
1327 return;
1329 v = x[5] & 0x3f;
1330 if (v) {
1331 printf(" VRRmin: %u Hz\n", v);
1332 if (v > 48)
1333 fail("VRRmin > 48.\n");
1335 v = (x[5] & 0xc0) << 2 | x[6];
1336 if (v) {
1337 printf(" VRRmax: %u Hz\n", v);
1338 if (!(x[5] & 0x3f))
1339 fail("VRRmin == 0, but VRRmax isn't.\n");
1340 else if (v < 100)
1341 fail("VRRmax < 100.\n");
1344 if (length <= 7)
1345 return;
1347 if (x[7] & 0x80)
1348 printf(" Supports VESA DSC 1.2a compression\n");
1349 if (x[7] & 0x40)
1350 printf(" Supports Compressed Video Transport for 4:2:0 Pixel Encoding\n");
1351 if (x[7] & 0x20)
1352 printf(" Supports QMS TFRmax\n");
1353 if (x[7] & 0x10)
1354 printf(" Supports QMS TFRmin\n");
1355 if (x[7] & 0x08)
1356 printf(" Supports Compressed Video Transport at any valid 1/16th bit bpp\n");
1357 if (x[7] & 0x04)
1358 printf(" Supports 16 bpc Compressed Video Transport\n");
1359 if (x[7] & 0x02)
1360 printf(" Supports 12 bpc Compressed Video Transport\n");
1361 if (x[7] & 0x01)
1362 printf(" Supports 10 bpc Compressed Video Transport\n");
1363 if (x[8] & 0xf) {
1364 unsigned max_slices = x[8] & 0xf;
1366 printf(" DSC Max Slices: ");
1367 if (max_slices < ARRAY_SIZE(dsc_max_slices)) {
1368 printf("%s\n", dsc_max_slices[max_slices]);
1369 } else {
1370 printf("Unknown (%u), interpreted as: %s\n", max_slices,
1371 dsc_max_slices[7]);
1372 warn("Unknown DSC Max Slices (%u).\n", max_slices);
1375 if (x[8] & 0xf0) {
1376 unsigned max_frl_rate = x[8] >> 4;
1378 printf(" DSC Max Fixed Rate Link: ");
1379 if (max_frl_rate < ARRAY_SIZE(max_frl_rates)) {
1380 printf("%s\n", max_frl_rates[max_frl_rate]);
1381 } else {
1382 printf("Unknown (0x%02x)\n", max_frl_rate);
1383 fail("Unknown DSC Max Fixed Rate Link (0x%02x).\n", max_frl_rate);
1386 if (x[9] & 0x3f)
1387 printf(" Maximum number of bytes in a line of chunks: %u\n",
1388 1024 * (1 + (x[9] & 0x3f)));
1391 // Convert a PQ value (0-1) to cd/m^2 aka nits (0-10000)
1392 static double pq2nits(double pq)
1394 const double m1 = 2610.0 / 16384.0;
1395 const double m2 = 128.0 * (2523.0 / 4096.0);
1396 const double c1 = 3424.0 / 4096.0;
1397 const double c2 = 32.0 * (2413.0 / 4096.0);
1398 const double c3 = 32.0 * (2392.0 / 4096.0);
1399 double e = pow(pq, 1.0 / m2);
1400 double v = e - c1;
1402 if (v < 0)
1403 v = 0;
1404 v /= c2 - c3 * e;
1405 v = pow(v, 1.0 / m1);
1406 return v * 10000.0;
1409 static double chrom2d(const unsigned char *x)
1411 unsigned v = x[0] + (x[1] << 8);
1413 return v * 0.00002;
1416 static double perc2d(unsigned char x)
1418 double m = x >> 2;
1419 double e = x & 3;
1421 return 100.0 * (m / 64.0) * pow(10, -e);
1424 static void cta_hf_sbtmdb(const unsigned char *x, unsigned length)
1426 int len = length;
1428 if (!length)
1429 fail("Block is too short.\n");
1430 printf(" Version: %d\n", x[0] & 0xf);
1431 switch ((x[0] >> 5) & 3) {
1432 case 0:
1433 printf(" Does not support a General RDM format\n");
1434 break;
1435 case 1:
1436 printf(" Supports an SDR-range General RDM format\n");
1437 break;
1438 case 2:
1439 printf(" Supports an HDR-range General RDM format\n");
1440 break;
1441 default:
1442 fail("Invalid GRDM Support value.\n");
1443 break;
1445 if (!(x[0] & 0x80))
1446 return;
1448 bool uses_hgig_drdm = true;
1450 printf(" Supports a D-RDM format\n");
1451 if (x[1] & 0x10)
1452 printf(" Use HGIG D-RDM\n");
1453 switch (x[1] & 7) {
1454 case 0:
1455 printf(" HGIG D-RDM is not used\n");
1456 uses_hgig_drdm = false;
1457 break;
1458 case 1:
1459 printf(" PBnits[0] = 600 cd/m^2\n");
1460 break;
1461 case 2:
1462 printf(" PBnits[0] = 1000 cd/m^2\n");
1463 break;
1464 case 3:
1465 printf(" PBnits[0] = 4000 cd/m^2\n");
1466 break;
1467 case 4:
1468 printf(" PBnits[0] = 10000 cd/m^2\n");
1469 break;
1470 default:
1471 fail("Invalid HGIG D-DRM value.\n");
1472 break;
1475 bool has_chromaticities = false;
1477 if (x[1] & 0x20)
1478 printf(" MaxRGB\n");
1479 switch (x[1] >> 6) {
1480 case 0:
1481 printf(" Gamut is explicit\n");
1482 has_chromaticities = true;
1483 break;
1484 case 1:
1485 printf(" Gamut is Rec. ITU-R BT.709\n");
1486 break;
1487 case 2:
1488 printf(" Gamut is SMPTE ST 2113\n");
1489 break;
1490 default:
1491 printf(" Gamut is Rec. ITU-R BT.2020\n");
1492 break;
1494 x += 2;
1495 len -= 2;
1496 if (has_chromaticities) {
1497 printf(" Red: (%.5f, %.5f)\n", chrom2d(x), chrom2d(x + 2));
1498 printf(" Green: (%.5f, %.5f)\n", chrom2d(x + 4), chrom2d(x + 6));
1499 printf(" Blue: (%.5f, %.5f)\n", chrom2d(x + 8), chrom2d(x + 10));
1500 printf(" White: (%.5f, %.5f)\n", chrom2d(x + 12), chrom2d(x + 14));
1501 x += 16;
1502 len -= 16;
1504 if (uses_hgig_drdm)
1505 return;
1506 printf(" Min Brightness 10: %.8f cd/m^2\n", pq2nits((x[0] << 1) / 4095.0));
1507 printf(" Peak Brightness 100: %u cd/m^2\n", (unsigned)pq2nits((x[1] << 4) / 4095.0));
1508 x += 2;
1509 len -= 2;
1510 if (len <= 0)
1511 return;
1512 printf(" Percentage of Peak Brightness P0: %.2f%%\n", perc2d(x[0]));
1513 printf(" Peak Brightness P0: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1514 x += 2;
1515 len -= 2;
1516 if (len <= 0)
1517 return;
1518 printf(" Percentage of Peak Brightness P1: %.2f%%\n", perc2d(x[0]));
1519 printf(" Peak Brightness P1: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1520 x += 2;
1521 len -= 2;
1522 if (len <= 0)
1523 return;
1524 printf(" Percentage of Peak Brightness P2: %.2f%%\n", perc2d(x[0]));
1525 printf(" Peak Brightness P2: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1526 x += 2;
1527 len -= 2;
1528 if (len <= 0)
1529 return;
1530 printf(" Percentage of Peak Brightness P3: %.2f%%\n", perc2d(x[0]));
1531 printf(" Peak Brightness P3: %.8f cd/m^2\n", pq2nits((x[1] << 1) / 4095.0));
1534 static void cta_amd(const unsigned char *x, unsigned length)
1536 // These Freesync values are reversed engineered by looking
1537 // at existing EDIDs.
1538 printf(" Version: %u.%u\n", x[0], x[1]);
1539 printf(" Minimum Refresh Rate: %u Hz\n", x[2]);
1540 printf(" Maximum Refresh Rate: %u Hz\n", x[3]);
1541 // Freesync 1.x flags
1542 // One or more of the 0xe6 bits signal that the VESA MCCS
1543 // protocol is used to switch the Freesync range
1544 printf(" Flags 1.x: 0x%02x%s\n", x[4],
1545 (x[4] & 0xe6) ? " (MCCS)" : "");
1546 if (length >= 10) {
1547 // Freesync 2.x flags
1548 // Bit 2 no doubt indicates if the monitor supports Local Dimming
1549 // There are probably also bits to signal support of the
1550 // FreeSync2_scRGB and FreeSync2_Gamma22 HDR display modes.
1551 // I suspect bits 0 and 1.
1552 printf(" Flags 2.x: 0x%02x\n", x[5]);
1553 // The AMD tone mapping tutorial referred to in the URL below
1554 // mentions that the Freesync HDR info reports max/min
1555 // luminance of the monitor with and without local dimming.
1557 // https://gpuopen.com/learn/using-amd-freesync-premium-pro-hdr-code-samples/
1559 // So I assume that the first two luminance values are
1560 // the max/min luminance of the display and the next two
1561 // luminance values are the max/min luminance values when
1562 // local dimming is disabled. The values I get seem to
1563 // support that.
1564 printf(" Maximum luminance: %u (%.3f cd/m^2)\n",
1565 x[6], 50.0 * pow(2, x[6] / 32.0));
1566 printf(" Minimum luminance: %u (%.3f cd/m^2)\n",
1567 x[7], (50.0 * pow(2, x[6] / 32.0)) * pow(x[7] / 255.0, 2) / 100.0);
1568 if (x[5] & 4) {
1569 // One or both bytes can be 0. The meaning of that
1570 // is unknown.
1571 printf(" Maximum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1572 x[8], 50.0 * pow(2, x[8] / 32.0));
1573 printf(" Minimum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1574 x[9], (50.0 * pow(2, x[8] / 32.0)) * pow(x[9] / 255.0, 2) / 100.0);
1575 } else {
1576 // These bytes are always 0x08 0x2f. If these values
1577 // represent max/min luminance as well, then these
1578 // would map to 59.460 and 0.020 cd/m^2 respectively.
1579 // I wonder if this somehow relates to SDR.
1580 printf(" Unknown: 0x%02x 0x%02x\n", x[8], x[9]);
1585 static std::string display_use_case(unsigned char x)
1587 switch (x) {
1588 case 1: return "Test equipment";
1589 case 2: return "Generic display";
1590 case 3: return "Television display";
1591 case 4: return "Desktop productivity display";
1592 case 5: return "Desktop gaming display";
1593 case 6: return "Presentation display";
1594 case 7: return "Virtual reality headset";
1595 case 8: return "Augmented reality";
1596 case 16: return "Video wall display";
1597 case 17: return "Medical imaging display";
1598 case 18: return "Dedicated gaming display";
1599 case 19: return "Dedicated video monitor display";
1600 case 20: return "Accessory display";
1601 default: break;
1603 fail("Unknown Display product primary use case 0x%02x.\n", x);
1604 return std::string("Unknown display use case (") + utohex(x) + ")";
1607 static void cta_microsoft(const unsigned char *x, unsigned length)
1609 // This VSDB is documented at:
1610 // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
1611 printf(" Version: %u\n", x[0]);
1612 if (x[0] > 2) {
1613 // In version 1 and 2 these bits should always be set to 0.
1614 printf(" Desktop Usage: %u\n", (x[1] >> 6) & 1);
1615 printf(" Third-Party Usage: %u\n", (x[1] >> 5) & 1);
1617 printf(" Display Product Primary Use Case: %u (%s)\n", x[1] & 0x1f,
1618 display_use_case(x[1] & 0x1f).c_str());
1619 printf(" Container ID: %s\n", containerid2s(x + 2).c_str());
1622 static void cta_hdr10plus(const unsigned char *x, unsigned length)
1624 if (length == 0) {
1625 fail("Empty Data Block with length %u.\n", length);
1626 return;
1628 printf(" Application Version: %u\n", x[0] & 3);
1629 printf(" Full Frame Peak Luminance Index: %u\n", (x[0] >> 2) & 3);
1630 printf(" Peak Luminance Index: %u\n", x[0] >> 4);
1631 hex_block(" ", x + 1, length - 1);
1634 static void cta_dolby_video(const unsigned char *x, unsigned length)
1636 unsigned char version = (x[0] >> 5) & 0x07;
1638 printf(" Version: %u (%u bytes)\n", version, length + 5);
1639 if (x[0] & 0x01)
1640 printf(" Supports YUV422 12 bit\n");
1642 if (version == 0) {
1643 if (x[0] & 0x02)
1644 printf(" Supports 2160p60\n");
1645 if (x[0] & 0x04)
1646 printf(" Supports global dimming\n");
1647 unsigned char dm_version = x[16];
1648 printf(" DM Version: %u.%u\n", dm_version >> 4, dm_version & 0xf);
1649 unsigned pq = (x[14] << 4) | (x[13] >> 4);
1650 printf(" Target Min PQ: %u (%.8f cd/m^2)\n", pq, pq2nits(pq / 4095.0));
1651 pq = (x[15] << 4) | (x[13] & 0xf);
1652 printf(" Target Max PQ: %u (%u cd/m^2)\n", pq, (unsigned)pq2nits(pq / 4095.0));
1653 printf(" Rx, Ry: %.8f, %.8f\n",
1654 ((x[1] >> 4) | (x[2] << 4)) / 4096.0,
1655 ((x[1] & 0xf) | (x[3] << 4)) / 4096.0);
1656 printf(" Gx, Gy: %.8f, %.8f\n",
1657 ((x[4] >> 4) | (x[5] << 4)) / 4096.0,
1658 ((x[4] & 0xf) | (x[6] << 4)) / 4096.0);
1659 printf(" Bx, By: %.8f, %.8f\n",
1660 ((x[7] >> 4) | (x[8] << 4)) / 4096.0,
1661 ((x[7] & 0xf) | (x[9] << 4)) / 4096.0);
1662 printf(" Wx, Wy: %.8f, %.8f\n",
1663 ((x[10] >> 4) | (x[11] << 4)) / 4096.0,
1664 ((x[10] & 0xf) | (x[12] << 4)) / 4096.0);
1665 return;
1668 if (version == 1) {
1669 if (x[0] & 0x02)
1670 printf(" Supports 2160p60\n");
1671 if (x[1] & 0x01)
1672 printf(" Supports global dimming\n");
1673 unsigned char dm_version = (x[0] >> 2) & 0x07;
1674 printf(" DM Version: %u.x\n", dm_version + 2);
1675 printf(" Colorimetry: %s\n", (x[2] & 0x01) ? "P3-D65" : "ITU-R BT.709");
1676 printf(" Low Latency: %s\n", (x[3] & 0x01) ? "Standard + Low Latency" : "Only Standard");
1677 double lm = (x[2] >> 1) / 127.0;
1678 printf(" Target Min Luminance: %.8f cd/m^2\n", lm * lm);
1679 printf(" Target Max Luminance: %u cd/m^2\n", 100 + (x[1] >> 1) * 50);
1680 if (length == 10) {
1681 printf(" Rx, Ry: %.8f, %.8f\n", x[4] / 256.0, x[5] / 256.0);
1682 printf(" Gx, Gy: %.8f, %.8f\n", x[6] / 256.0, x[7] / 256.0);
1683 printf(" Bx, By: %.8f, %.8f\n", x[8] / 256.0, x[9] / 256.0);
1684 } else {
1685 double xmin = 0.625;
1686 double xstep = (0.74609375 - xmin) / 31.0;
1687 double ymin = 0.25;
1688 double ystep = (0.37109375 - ymin) / 31.0;
1690 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1691 xmin + xstep * (x[6] >> 3),
1692 ymin + ystep * (((x[6] & 0x7) << 2) | (x[4] & 0x01) | ((x[5] & 0x01) << 1)));
1693 xstep = 0.49609375 / 127.0;
1694 ymin = 0.5;
1695 ystep = (0.99609375 - ymin) / 127.0;
1696 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1697 xstep * (x[4] >> 1), ymin + ystep * (x[5] >> 1));
1698 xmin = 0.125;
1699 xstep = (0.15234375 - xmin) / 7.0;
1700 ymin = 0.03125;
1701 ystep = (0.05859375 - ymin) / 7.0;
1702 printf(" Unique Bx, By: %.8f, %.8f\n",
1703 xmin + xstep * (x[3] >> 5),
1704 ymin + ystep * ((x[3] >> 2) & 0x07));
1706 return;
1709 if (version == 2) {
1710 if (x[0] & 0x02)
1711 printf(" Supports Backlight Control\n");
1712 if (x[1] & 0x04)
1713 printf(" Supports global dimming\n");
1714 unsigned char dm_version = (x[0] >> 2) & 0x07;
1715 printf(" DM Version: %u.x\n", dm_version + 2);
1716 printf(" Backlt Min Luma: %u cd/m^2\n", 25 + (x[1] & 0x03) * 25);
1717 printf(" Interface: ");
1718 switch (x[2] & 0x03) {
1719 case 0: printf("Low-Latency\n"); break;
1720 case 1: printf("Low-Latency + Low-Latency-HDMI\n"); break;
1721 case 2: printf("Standard + Low-Latency\n"); break;
1722 case 3: printf("Standard + Low-Latency + Low-Latency-HDMI\n"); break;
1724 printf(" Supports 10b 12b 444: ");
1725 switch ((x[3] & 0x01) << 1 | (x[4] & 0x01)) {
1726 case 0: printf("Not supported\n"); break;
1727 case 1: printf("10 bit\n"); break;
1728 case 2: printf("12 bit\n"); break;
1729 case 3: printf("Reserved\n"); break;
1732 unsigned pq = 20 * (x[1] >> 3);
1733 printf(" Target Min PQ v2: %u (%.8f cd/m^2)\n", pq, pq2nits(pq / 4095.0));
1734 pq = 2055 + 65 * (x[2] >> 3);
1735 printf(" Target Max PQ v2: %u (%u cd/m^2)\n", pq, (unsigned)pq2nits(pq / 4095.0));
1737 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1738 0.625 + (x[5] >> 3) / 256.0,
1739 0.25 + (x[6] >> 3) / 256.0);
1740 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1741 (x[3] >> 1) / 256.0,
1742 0.5 + (x[4] >> 1) / 256.0);
1743 printf(" Unique Bx, By: %.8f, %.8f\n",
1744 0.125 + (x[5] & 0x07) / 256.0,
1745 0.03125 + (x[6] & 0x07) / 256.0);
1749 static void cta_dolby_audio(const unsigned char *x, unsigned length)
1751 unsigned char version = 1 + (x[0] & 0x07);
1753 printf(" Version: %u (%u bytes)\n", version, length + 5);
1754 if (x[0] & 0x80)
1755 printf(" Headphone playback only\n");
1756 if (x[0] & 0x40)
1757 printf(" Height speaker zone present\n");
1758 if (x[0] & 0x20)
1759 printf(" Surround speaker zone present\n");
1760 if (x[0] & 0x10)
1761 printf(" Center speaker zone present\n");
1762 if (x[1] & 0x01)
1763 printf(" Supports Dolby MAT PCM decoding at 48 kHz only, does not support TrueHD\n");
1766 static void cta_uhda_fmm(const unsigned char *x, unsigned length)
1768 printf(" Filmmaker Mode Content Type: %u\n", x[0]);
1769 printf(" Filmmaker Mode Content Subtype: %u\n", x[1]);
1772 static const char *speaker_map[] = {
1773 "FL/FR - Front Left/Right",
1774 "LFE1 - Low Frequency Effects 1",
1775 "FC - Front Center",
1776 "BL/BR - Back Left/Right",
1777 "BC - Back Center",
1778 "FLc/FRc - Front Left/Right of Center",
1779 "RLC/RRC - Rear Left/Right of Center (Deprecated)",
1780 "FLw/FRw - Front Left/Right Wide",
1781 "TpFL/TpFR - Top Front Left/Right",
1782 "TpC - Top Center",
1783 "TpFC - Top Front Center",
1784 "LS/RS - Left/Right Surround",
1785 "LFE2 - Low Frequency Effects 2",
1786 "TpBC - Top Back Center",
1787 "SiL/SiR - Side Left/Right",
1788 "TpSiL/TpSiR - Top Side Left/Right",
1789 "TpBL/TpBR - Top Back Left/Right",
1790 "BtFC - Bottom Front Center",
1791 "BtFL/BtFR - Bottom Front Left/Right",
1792 "TpLS/TpRS - Top Left/Right Surround (Deprecated for CTA-861)",
1793 "LSd/RSd - Left/Right Surround Direct (HDMI only)",
1796 static void cta_sadb(const unsigned char *x, unsigned length)
1798 unsigned sad;
1799 unsigned i;
1801 if (length < 3) {
1802 fail("Empty Data Block with length %u.\n", length);
1803 return;
1806 sad = ((x[2] << 16) | (x[1] << 8) | x[0]);
1808 for (i = 0; i < ARRAY_SIZE(speaker_map); i++) {
1809 if ((sad >> i) & 1)
1810 printf(" %s\n", speaker_map[i]);
1814 static void cta_vesa_dtcdb(const unsigned char *x, unsigned length)
1816 if (length != 7 && length != 15 && length != 31) {
1817 fail("Invalid length %u.\n", length);
1818 return;
1821 switch (x[0] >> 6) {
1822 case 0: printf(" White"); break;
1823 case 1: printf(" Red"); break;
1824 case 2: printf(" Green"); break;
1825 case 3: printf(" Blue"); break;
1827 unsigned v = x[0] & 0x3f;
1828 printf(" transfer characteristics: %u", v);
1829 for (unsigned i = 1; i < length; i++)
1830 printf(" %u", v += x[i]);
1831 printf(" 1023\n");
1834 static void cta_vesa_vdddb(const unsigned char *x, unsigned length)
1836 if (length != 30) {
1837 fail("Invalid length %u.\n", length);
1838 return;
1841 printf(" Interface Type: ");
1842 unsigned char v = x[0];
1843 switch (v >> 4) {
1844 case 0: printf("Analog (");
1845 switch (v & 0xf) {
1846 case 0: printf("15HD/VGA"); break;
1847 case 1: printf("VESA NAVI-V (15HD)"); break;
1848 case 2: printf("VESA NAVI-D"); break;
1849 default: printf("Reserved"); break;
1851 printf(")\n");
1852 break;
1853 case 1: printf("LVDS %u lanes", v & 0xf); break;
1854 case 2: printf("RSDS %u lanes", v & 0xf); break;
1855 case 3: printf("DVI-D %u channels", v & 0xf); break;
1856 case 4: printf("DVI-I analog"); break;
1857 case 5: printf("DVI-I digital %u channels", v & 0xf); break;
1858 case 6: printf("HDMI-A"); break;
1859 case 7: printf("HDMI-B"); break;
1860 case 8: printf("MDDI %u channels", v & 0xf); break;
1861 case 9: printf("DisplayPort %u channels", v & 0xf); break;
1862 case 10: printf("IEEE-1394"); break;
1863 case 11: printf("M1 analog"); break;
1864 case 12: printf("M1 digital %u channels", v & 0xf); break;
1865 default: printf("Reserved"); break;
1867 printf("\n");
1869 printf(" Interface Standard Version: %u.%u\n", x[1] >> 4, x[1] & 0xf);
1870 printf(" Content Protection Support: ");
1871 switch (x[2]) {
1872 case 0: printf("None\n"); break;
1873 case 1: printf("HDCP\n"); break;
1874 case 2: printf("DTCP\n"); break;
1875 case 3: printf("DPCP\n"); break;
1876 default: printf("Reserved\n"); break;
1879 printf(" Minimum Clock Frequency: %u MHz\n", x[3] >> 2);
1880 printf(" Maximum Clock Frequency: %u MHz\n", ((x[3] & 0x03) << 8) | x[4]);
1881 printf(" Device Native Pixel Format: %ux%u\n",
1882 x[5] | (x[6] << 8), x[7] | (x[8] << 8));
1883 printf(" Aspect Ratio: %.2f\n", (100 + x[9]) / 100.0);
1884 v = x[0x0a];
1885 printf(" Default Orientation: ");
1886 switch ((v & 0xc0) >> 6) {
1887 case 0x00: printf("Landscape\n"); break;
1888 case 0x01: printf("Portrait\n"); break;
1889 case 0x02: printf("Not Fixed\n"); break;
1890 case 0x03: printf("Undefined\n"); break;
1892 printf(" Rotation Capability: ");
1893 switch ((v & 0x30) >> 4) {
1894 case 0x00: printf("None\n"); break;
1895 case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
1896 case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
1897 case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
1899 printf(" Zero Pixel Location: ");
1900 switch ((v & 0x0c) >> 2) {
1901 case 0x00: printf("Upper Left\n"); break;
1902 case 0x01: printf("Upper Right\n"); break;
1903 case 0x02: printf("Lower Left\n"); break;
1904 case 0x03: printf("Lower Right\n"); break;
1906 printf(" Scan Direction: ");
1907 switch (v & 0x03) {
1908 case 0x00: printf("Not defined\n"); break;
1909 case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
1910 case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
1911 case 0x03: printf("Reserved\n");
1912 fail("Scan Direction used the reserved value 0x03.\n");
1913 break;
1915 printf(" Subpixel Information: ");
1916 switch (x[0x0b]) {
1917 case 0x00: printf("Not defined\n"); break;
1918 case 0x01: printf("RGB vertical stripes\n"); break;
1919 case 0x02: printf("RGB horizontal stripes\n"); break;
1920 case 0x03: printf("Vertical stripes using primary order\n"); break;
1921 case 0x04: printf("Horizontal stripes using primary order\n"); break;
1922 case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
1923 case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
1924 case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
1925 case 0x08: printf("Mosaic\n"); break;
1926 case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
1927 case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
1928 case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
1929 case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
1930 default: printf("Reserved\n"); break;
1932 printf(" Horizontal and vertical dot/pixel pitch: %.2f x %.2f mm\n",
1933 (double)(x[0x0c]) / 100.0, (double)(x[0x0d]) / 100.0);
1934 v = x[0x0e];
1935 printf(" Dithering: ");
1936 switch (v >> 6) {
1937 case 0: printf("None\n"); break;
1938 case 1: printf("Spatial\n"); break;
1939 case 2: printf("Temporal\n"); break;
1940 case 3: printf("Spatial and Temporal\n"); break;
1942 printf(" Direct Drive: %s\n", (v & 0x20) ? "Yes" : "No");
1943 printf(" Overdrive %srecommended\n", (v & 0x10) ? "not " : "");
1944 printf(" Deinterlacing: %s\n", (v & 0x08) ? "Yes" : "No");
1946 v = x[0x0f];
1947 printf(" Audio Support: %s\n", (v & 0x80) ? "Yes" : "No");
1948 printf(" Separate Audio Inputs Provided: %s\n", (v & 0x40) ? "Yes" : "No");
1949 printf(" Audio Input Override: %s\n", (v & 0x20) ? "Yes" : "No");
1950 v = x[0x10];
1951 if (v)
1952 printf(" Audio Delay: %s%u ms\n", (v & 0x80) ? "" : "-", (v & 0x7f) * 2);
1953 else
1954 printf(" Audio Delay: no information provided\n");
1955 v = x[0x11];
1956 printf(" Frame Rate/Mode Conversion: ");
1957 switch (v >> 6) {
1958 case 0: printf("None\n"); break;
1959 case 1: printf("Single Buffering\n"); break;
1960 case 2: printf("Double Buffering\n"); break;
1961 case 3: printf("Advanced Frame Rate Conversion\n"); break;
1963 if (v & 0x3f)
1964 printf(" Frame Rate Range: %u fps +/- %u fps\n",
1965 x[0x12], v & 0x3f);
1966 else
1967 printf(" Nominal Frame Rate: %u fps\n", x[0x12]);
1968 printf(" Color Bit Depth: %u @ interface, %u @ display\n",
1969 (x[0x13] >> 4) + 1, (x[0x13] & 0xf) + 1);
1970 v = x[0x15] & 3;
1971 if (v) {
1972 printf(" Additional Primary Chromaticities:\n");
1973 unsigned col_x = (x[0x16] << 2) | (x[0x14] >> 6);
1974 unsigned col_y = (x[0x17] << 2) | ((x[0x14] >> 4) & 3);
1975 printf(" Primary 4: 0.%04u, 0.%04u\n",
1976 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1977 if (v > 1) {
1978 col_x = (x[0x18] << 2) | ((x[0x14] >> 2) & 3);
1979 col_y = (x[0x19] << 2) | (x[0x14] & 3);
1980 printf(" Primary 5: 0.%04u, 0.%04u\n",
1981 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1982 if (v > 2) {
1983 col_x = (x[0x1a] << 2) | (x[0x15] >> 6);
1984 col_y = (x[0x1b] << 2) | ((x[0x15] >> 4) & 3);
1985 printf(" Primary 6: 0.%04u, 0.%04u\n",
1986 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1991 v = x[0x1c];
1992 printf(" Response Time %s: %u ms\n",
1993 (v & 0x80) ? "White -> Black" : "Black -> White", v & 0x7f);
1994 v = x[0x1d];
1995 printf(" Overscan: %u%% x %u%%\n", v >> 4, v & 0xf);
1998 static double decode_uchar_as_double(unsigned char x)
2000 signed char s = (signed char)x;
2002 return s / 64.0;
2005 void edid_state::cta_rcdb(const unsigned char *x, unsigned length)
2007 unsigned spm = ((x[3] << 16) | (x[2] << 8) | x[1]);
2008 unsigned i;
2010 if (length < 4) {
2011 fail("Empty Data Block with length %u.\n", length);
2012 return;
2015 if ((x[0] & 0x20) && !cta.has_sldb)
2016 fail("'SLD' flag is 1, but no Speaker Location Data Block is found.\n");
2017 else if (!(x[0] & 0x20) && cta.has_sldb)
2018 fail("'SLD' flag is 0, but a Speaker Location Data Block is present.\n");
2020 if (x[0] & 0x40) {
2021 printf(" Speaker count: %u\n", (x[0] & 0x1f) + 1);
2022 } else {
2023 if (x[0] & 0x1f)
2024 fail("'Speaker' flag is 0, but 'Speaker Count' is != 0.\n");
2025 if (x[0] & 0x20)
2026 fail("'SLD' flag is 1, but 'Speaker' is 0.\n");
2029 printf(" Speaker Presence Mask:\n");
2030 for (i = 0; i < ARRAY_SIZE(speaker_map); i++) {
2031 if ((spm >> i) & 1)
2032 printf(" %s\n", speaker_map[i]);
2035 if ((x[0] & 0xa0) == 0x80)
2036 fail("'Display' flag set, but not the 'SLD' flag.\n");
2038 bool valid_max = cta.preparsed_sld_has_coord || (x[0] & 0x80);
2040 if (valid_max && length >= 7) {
2041 printf(" Xmax: %u dm\n", x[4]);
2042 printf(" Ymax: %u dm\n", x[5]);
2043 printf(" Zmax: %u dm\n", x[6]);
2044 } else if (!valid_max && length >= 7) {
2045 // The RCDB should have been truncated.
2046 warn("'Display' flag is 0 and 'Coord' is 0 for all SLDs, but the Max coordinates are still present.\n");
2048 if ((x[0] & 0x80) && length >= 10) {
2049 printf(" DisplayX: %.3f * Xmax\n", decode_uchar_as_double(x[7]));
2050 printf(" DisplayY: %.3f * Ymax\n", decode_uchar_as_double(x[8]));
2051 printf(" DisplayZ: %.3f * Zmax\n", decode_uchar_as_double(x[9]));
2052 } else if (!(x[0] & 0x80) && length >= 10) {
2053 // The RCDB should have been truncated.
2054 warn("'Display' flag is 0, but the Display coordinates are still present.\n");
2058 static const struct {
2059 const char *name;
2060 double x, y, z;
2061 } speaker_location[] = {
2062 { "FL - Front Left", -1, 1, 0 },
2063 { "FR - Front Right", 1, 1, 0 },
2064 { "FC - Front Center", 0, 1, 0 },
2065 { "LFE1 - Low Frequency Effects 1", -0.5, 1, -1 },
2066 { "BL - Back Left", -1, -1, 0 },
2067 { "BR - Back Right", 1, -1, 0 },
2068 { "FLC - Front Left of Center", -0.5, 1, 0 },
2069 { "FRC - Front Right of Center", 0.5, 1, 0 },
2070 { "BC - Back Center", 0, -1, 0 },
2071 { "LFE2 - Low Frequency Effects 2", 0.5, 1, -1 },
2072 { "SiL - Side Left", -1, 1.0/3.0, 0 },
2073 { "SiR - Side Right", 1, 1.0/3.0, 0 },
2074 { "TpFL - Top Front Left", -1, 1, 1 },
2075 { "TpFR - Top Front Right", 1, 1, 1 },
2076 { "TpFC - Top Front Center", 0, 1, 1 },
2077 { "TpC - Top Center", 0, 0, 1 },
2078 { "TpBL - Top Back Left", -1, -1, 1 },
2079 { "TpBR - Top Back Right", 1, -1, 1 },
2080 { "TpSiL - Top Side Left", -1, 0, 1 },
2081 { "TpSiR - Top Side Right", 1, 0, 1 },
2082 { "TpBC - Top Back Center", 0, -1, 1 },
2083 { "BtFC - Bottom Front Center", 0, 1, -1 },
2084 { "BtFL - Bottom Front Left", -1, 1, -1 },
2085 { "BtFR - Bottom Front Right", 1, 1, -1 },
2086 { "FLW - Front Left Wide", -1, 2.0/3.0, 0 },
2087 { "FRW - Front Right Wide", 1, 2.0/3.0, 0 },
2088 { "LS - Left Surround", -1, 0, 0 },
2089 { "RS - Right Surround", 1, 0, 0 },
2092 void edid_state::cta_sldb(const unsigned char *x, unsigned length)
2094 if (length < 2) {
2095 fail("Empty Data Block with length %u.\n", length);
2096 return;
2099 unsigned active_cnt = 0;
2100 unsigned channel_is_active = 0;
2102 while (length >= 2) {
2103 printf(" Channel: %u (%sactive)\n", x[0] & 0x1f,
2104 (x[0] & 0x20) ? "" : "not ");
2105 if (x[0] & 0x20) {
2106 if (channel_is_active & (1U << (x[0] & 0x1f)))
2107 fail("Channel Index %u was already marked 'Active'.\n",
2108 x[0] & 0x1f);
2109 channel_is_active |= 1U << (x[0] & 0x1f);
2110 active_cnt++;
2113 unsigned speaker_id = x[1] & 0x1f;
2115 if (speaker_id < ARRAY_SIZE(speaker_location)) {
2116 printf(" Speaker ID: %s\n", speaker_location[speaker_id].name);
2117 } else if (speaker_id == 0x1f) {
2118 printf(" Speaker ID: None Specified\n");
2119 } else {
2120 printf(" Speaker ID: Reserved (%u)\n", speaker_id);
2121 fail("Reserved Speaker ID specified.\n");
2123 if (length >= 5 && (x[0] & 0x40)) {
2124 printf(" X: %.3f * Xmax\n", decode_uchar_as_double(x[2]));
2125 printf(" Y: %.3f * Ymax\n", decode_uchar_as_double(x[3]));
2126 printf(" Z: %.3f * Zmax\n", decode_uchar_as_double(x[4]));
2127 length -= 3;
2128 x += 3;
2129 } else if (speaker_id < ARRAY_SIZE(speaker_location)) {
2130 printf(" X: %.3f * Xmax (approximately)\n", speaker_location[speaker_id].x);
2131 printf(" Y: %.3f * Ymax (approximately)\n", speaker_location[speaker_id].y);
2132 printf(" Z: %.3f * Zmax (approximately)\n", speaker_location[speaker_id].z);
2135 length -= 2;
2136 x += 2;
2138 if (active_cnt != cta.preparsed_speaker_count)
2139 fail("There are %u active speakers, but 'Speaker Count' is %u.\n",
2140 active_cnt, cta.preparsed_speaker_count);
2143 void edid_state::cta_preparse_sldb(const unsigned char *x, unsigned length)
2145 cta.has_sldb = true;
2146 while (length >= 2) {
2147 if (length >= 5 && (x[0] & 0x40)) {
2148 cta.preparsed_sld_has_coord = true;
2149 return;
2151 length -= 2;
2152 x += 2;
2156 void edid_state::cta_vcdb(const unsigned char *x, unsigned length)
2158 unsigned char d = x[0];
2160 cta.has_vcdb = true;
2161 if (length < 1) {
2162 fail("Empty Data Block with length %u.\n", length);
2163 return;
2165 printf(" YCbCr quantization: %s\n",
2166 (d & 0x80) ? "Selectable (via AVI YQ)" : "No Data");
2167 printf(" RGB quantization: %s\n",
2168 (d & 0x40) ? "Selectable (via AVI Q)" : "No Data");
2170 * If this bit is not set then that will result in interoperability
2171 * problems (specifically with PCs/laptops) that quite often do not
2172 * follow the default rules with respect to RGB Quantization Range
2173 * handling.
2175 * Starting with the CTA-861-H spec this bit is now required to be
2176 * 1 for new designs.
2178 if (!(d & 0x40))
2179 fail("Set Selectable RGB Quantization to avoid interop issues.\n");
2181 * Since most YCbCr formats use limited range, the interop issues are
2182 * less noticable than for RGB formats.
2184 * Starting with the CTA-861-H spec this bit is now required to be
2185 * 1 for new designs, but just warn about it (for now).
2187 if ((cta.byte3 & 0x30) && !(d & 0x80))
2188 warn("Set Selectable YCbCr Quantization to avoid interop issues.\n");
2190 unsigned char s_pt = (d >> 4) & 0x03;
2191 unsigned char s_it = (d >> 2) & 0x03;
2192 unsigned char s_ce = d & 0x03;
2194 printf(" PT scan behavior: ");
2195 switch (s_pt) {
2196 case 0: printf("No Data\n"); break;
2197 case 1: printf("Always Overscanned\n"); break;
2198 case 2: printf("Always Underscanned\n"); break;
2199 case 3: printf("Supports both over- and underscan\n"); break;
2201 printf(" IT scan behavior: ");
2202 switch (s_it) {
2203 case 0: printf("IT video formats not supported\n"); break;
2204 case 1:
2205 printf("Always Overscanned\n");
2206 // See Table 52 of CTA-861-G for a description of Byte 3
2207 if (cta.byte3 & 0x80)
2208 fail("IT video formats are always overscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to underscanned.\n");
2209 break;
2210 case 2:
2211 printf("Always Underscanned\n");
2212 // See Table 52 of CTA-861-G for a description of Byte 3
2213 if (!(cta.byte3 & 0x80))
2214 fail("IT video formats are always underscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to overscanned.\n");
2215 break;
2216 case 3: printf("Supports both over- and underscan\n"); break;
2218 if (s_it < 2)
2219 warn("IT scan behavior is expected to support underscanned.\n");
2220 printf(" CE scan behavior: ");
2221 switch (s_ce) {
2222 case 0: printf("CE video formats not supported\n"); break;
2223 case 1: printf("Always Overscanned\n"); break;
2224 case 2: printf("Always Underscanned\n"); break;
2225 case 3: printf("Supports both over- and underscan\n"); break;
2227 if (s_ce == 0)
2228 warn("'CE video formats not supported' makes no sense.\n");
2229 else if (s_pt == s_it && s_pt == s_ce)
2230 warn("S_PT is equal to S_IT and S_CE, so should be set to 0 instead.\n");
2233 static const char *colorimetry1_map[] = {
2234 "xvYCC601",
2235 "xvYCC709",
2236 "sYCC601",
2237 "opYCC601",
2238 "opRGB",
2239 "BT2020cYCC",
2240 "BT2020YCC",
2241 "BT2020RGB",
2244 static const char *colorimetry2_map[] = {
2245 "Gamut Boundary Description Metadata Profile P0",
2246 "Reserved Gamut Boundary Description Metadata Profile P1",
2247 "Reserved Gamut Boundary Description Metadata Profile P2",
2248 "Reserved Gamut Boundary Description Metadata Profile P3",
2249 "Default",
2250 "sRGB",
2251 "ICtCp",
2252 "ST2113RGB",
2255 void edid_state::cta_colorimetry_block(const unsigned char *x, unsigned length)
2257 unsigned i;
2259 if (length < 2) {
2260 fail("Empty Data Block with length %u.\n", length);
2261 return;
2263 for (i = 0; i < ARRAY_SIZE(colorimetry1_map); i++)
2264 if (x[0] & (1 << i))
2265 printf(" %s\n", colorimetry1_map[i]);
2266 // Bits MD0-MD3 are used to indicate which HDMI Gamut Boundary Description
2267 // Metadata Profiles are supported.
2269 // HDMI 1.3a in section 5.3.12 describes 4 possible profiles, but it marks
2270 // P3 as 'defined in a future specification'.
2272 // HDMI 1.4b, however, only specifies profile P0 in section 8.3.3. And I've
2273 // only seen P0 in practice. My assumption is that profiles P1-P3 are never
2274 // used, and so these bits should be 0.
2275 if (x[1] & 0xe)
2276 fail("Reserved bits MD1-MD3 must be 0.\n");
2277 for (i = 0; i < ARRAY_SIZE(colorimetry2_map); i++)
2278 if (x[1] & (1 << i))
2279 printf(" %s\n", colorimetry2_map[i]);
2280 // The sRGB bit (added in CTA-861.6) allows sources to explicitly
2281 // signal sRGB colorimetry. Without this the default colorimetry
2282 // of an RGB video is either sRGB or defaultRGB. It depends on the
2283 // Source which is used, and the Sink has no idea what it is getting.
2285 // For proper compatibility with PCs enabling sRGB support is
2286 // desirable.
2287 if (!base.uses_srgb && !(x[1] & 0x20))
2288 warn("Set the sRGB colorimetry bit to avoid interop issues.\n");
2291 static const char *eotf_map[] = {
2292 "Traditional gamma - SDR luminance range",
2293 "Traditional gamma - HDR luminance range",
2294 "SMPTE ST2084",
2295 "Hybrid Log-Gamma",
2298 static void cta_hdr_static_metadata_block(const unsigned char *x, unsigned length)
2300 unsigned i;
2302 if (length < 2) {
2303 fail("Empty Data Block with length %u.\n", length);
2304 return;
2306 printf(" Electro optical transfer functions:\n");
2307 for (i = 0; i < 6; i++) {
2308 if (x[0] & (1 << i)) {
2309 if (i < ARRAY_SIZE(eotf_map)) {
2310 printf(" %s\n", eotf_map[i]);
2311 } else {
2312 printf(" Unknown (%u)\n", i);
2313 fail("Unknown EOTF (%u).\n", i);
2317 printf(" Supported static metadata descriptors:\n");
2318 for (i = 0; i < 8; i++) {
2319 if (x[1] & (1 << i))
2320 printf(" Static metadata type %u\n", i + 1);
2323 if (length >= 3)
2324 printf(" Desired content max luminance: %u (%.3f cd/m^2)\n",
2325 x[2], 50.0 * pow(2, x[2] / 32.0));
2327 if (length >= 4)
2328 printf(" Desired content max frame-average luminance: %u (%.3f cd/m^2)\n",
2329 x[3], 50.0 * pow(2, x[3] / 32.0));
2331 if (length >= 5)
2332 printf(" Desired content min luminance: %u (%.3f cd/m^2)\n",
2333 x[4], (50.0 * pow(2, x[2] / 32.0)) * pow(x[4] / 255.0, 2) / 100.0);
2336 static void cta_hdr_dyn_metadata_block(const unsigned char *x, unsigned length)
2338 if (length < 3) {
2339 fail("Empty Data Block with length %u.\n", length);
2340 return;
2342 while (length >= 3) {
2343 unsigned type_len = x[0];
2344 unsigned type = x[1] | (x[2] << 8);
2346 if (length < type_len + 1)
2347 return;
2348 printf(" HDR Dynamic Metadata Type %u\n", type);
2349 switch (type) {
2350 case 1:
2351 case 4:
2352 if (type_len > 2)
2353 printf(" Version: %u\n", x[3] & 0xf);
2354 break;
2355 case 2:
2356 if (type_len > 2) {
2357 unsigned version = x[3] & 0xf;
2358 printf(" Version: %u\n", version);
2359 if (version >= 1) {
2360 if (x[3] & 0x10) printf(" Supports SL-HDR1 (ETSI TS 103 433-1)\n");
2361 if (x[3] & 0x20) printf(" Supports SL-HDR2 (ETSI TS 103 433-2)\n");
2362 if (x[3] & 0x40) printf(" Supports SL-HDR3 (ETSI TS 103 433-3)\n");
2365 break;
2366 default:
2367 break;
2369 length -= type_len + 1;
2370 x += type_len + 1;
2374 static const char *infoframe_types[] = {
2375 NULL,
2376 "Vendor-Specific",
2377 "Auxiliary Video Information",
2378 "Source Product Description",
2379 "Audio",
2380 "MPEG Source",
2381 "NTSC VBI",
2382 "Dynamic Range and Mastering",
2385 static void cta_ifdb(const unsigned char *x, unsigned length)
2387 unsigned len_hdr = x[0] >> 5;
2389 if (length < 2) {
2390 fail("Empty Data Block with length %u.\n", length);
2391 return;
2393 printf(" VSIFs: %u\n", x[1]);
2394 if (length < len_hdr + 2)
2395 return;
2396 length -= len_hdr + 2;
2397 x += len_hdr + 2;
2398 while (length > 0) {
2399 int payload_len = x[0] >> 5;
2400 unsigned char type = x[0] & 0x1f;
2402 const char *name = NULL;
2403 if (type < ARRAY_SIZE(infoframe_types))
2404 name = infoframe_types[type];
2405 if (!name)
2406 name = "Unknown";
2407 printf(" %s InfoFrame (%u)", name, type);
2409 if (type == 1 && length >= 4) {
2410 unsigned oui = (x[3] << 16) | (x[2] << 8) | x[1];
2412 printf(", OUI %s\n", ouitohex(oui).c_str());
2413 x += 4;
2414 length -= 4;
2415 } else {
2416 printf("\n");
2417 x++;
2418 length--;
2420 x += payload_len;
2421 length -= payload_len;
2425 void edid_state::cta_displayid_type_7(const unsigned char *x, unsigned length)
2427 check_displayid_datablock_revision(x[0], 0x00, 2);
2429 if (length < 21U + ((x[0] & 0x70) >> 4)) {
2430 fail("Empty Data Block with length %u.\n", length);
2431 return;
2433 parse_displayid_type_1_7_timing(x + 1, true, 2, true);
2436 void edid_state::cta_displayid_type_8(const unsigned char *x, unsigned length)
2438 check_displayid_datablock_revision(x[0], 0xe8, 1);
2439 if (length < ((x[0] & 0x08) ? 3 : 2)) {
2440 fail("Empty Data Block with length %u.\n", length);
2441 return;
2444 unsigned sz = (x[0] & 0x08) ? 2 : 1;
2445 unsigned type = x[0] >> 6;
2447 if (type) {
2448 fail("Only code type 0 is supported.\n");
2449 return;
2452 if (x[0] & 0x20)
2453 printf(" Also supports YCbCr 4:2:0\n");
2455 x++;
2456 length--;
2457 for (unsigned i = 0; i < length / sz; i++) {
2458 unsigned id = x[i * sz];
2460 if (sz == 2)
2461 id |= x[i * sz + 1] << 8;
2462 parse_displayid_type_4_8_timing(type, id, true);
2466 void edid_state::cta_displayid_type_10(const unsigned char *x, unsigned length)
2468 check_displayid_datablock_revision(x[0], 0x70);
2469 if (length < 7U + ((x[0] & 0x70) >> 4)) {
2470 fail("Empty Data Block with length %u.\n", length);
2471 return;
2474 unsigned sz = 6U + ((x[0] & 0x70) >> 4);
2475 x++;
2476 length--;
2477 for (unsigned i = 0; i < length / sz; i++)
2478 parse_displayid_type_10_timing(x + i * sz, sz, true);
2481 static void cta_hdmi_audio_block(const unsigned char *x, unsigned length)
2483 unsigned num_descs;
2485 if (length < 2) {
2486 fail("Empty Data Block with length %u.\n", length);
2487 return;
2489 if (x[0] & 3)
2490 printf(" Max Stream Count: %u\n", (x[0] & 3) + 1);
2491 if (x[0] & 4)
2492 printf(" Supports MS NonMixed\n");
2494 num_descs = x[1] & 7;
2495 if (num_descs == 0)
2496 return;
2497 length -= 2;
2498 x += 2;
2499 while (length >= 4) {
2500 if (length > 4) {
2501 unsigned format = x[0] & 0xf;
2503 printf(" %s, max channels %u\n", audio_format(format).c_str(),
2504 (x[1] & 0x1f)+1);
2505 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
2506 (x[2] & 0x40) ? " 192" : "",
2507 (x[2] & 0x20) ? " 176.4" : "",
2508 (x[2] & 0x10) ? " 96" : "",
2509 (x[2] & 0x08) ? " 88.2" : "",
2510 (x[2] & 0x04) ? " 48" : "",
2511 (x[2] & 0x02) ? " 44.1" : "",
2512 (x[2] & 0x01) ? " 32" : "");
2513 if (format == 1)
2514 printf(" Supported sample sizes (bits):%s%s%s\n",
2515 (x[3] & 0x04) ? " 24" : "",
2516 (x[3] & 0x02) ? " 20" : "",
2517 (x[3] & 0x01) ? " 16" : "");
2518 } else {
2519 unsigned sad = ((x[2] << 16) | (x[1] << 8) | x[0]);
2520 unsigned i;
2522 switch (x[3] >> 4) {
2523 case 1:
2524 printf(" Speaker Allocation for 10.2 channels:\n");
2525 break;
2526 case 2:
2527 printf(" Speaker Allocation for 22.2 channels:\n");
2528 break;
2529 case 3:
2530 printf(" Speaker Allocation for 30.2 channels:\n");
2531 break;
2532 default:
2533 printf(" Unknown Speaker Allocation (0x%02x)\n", x[3] >> 4);
2534 return;
2537 for (i = 0; i < ARRAY_SIZE(speaker_map); i++) {
2538 if ((sad >> i) & 1)
2539 printf(" %s\n", speaker_map[i]);
2542 length -= 4;
2543 x += 4;
2547 void edid_state::cta_block(const unsigned char *x, std::vector<unsigned> &found_tags)
2549 unsigned length = x[0] & 0x1f;
2550 unsigned tag = (x[0] & 0xe0) >> 5;
2551 unsigned extended = (tag == 0x07) ? 1 : 0;
2553 x++;
2554 if (extended && length) {
2555 tag <<= 8;
2556 tag |= x[0];
2557 length--;
2558 x++;
2561 bool dooutputname = true;
2562 bool audio_block = false;
2563 data_block.clear();
2565 switch (tag) {
2566 case 0x01: data_block = "Audio Data Block"; audio_block = true; break;
2567 case 0x02: data_block = "Video Data Block"; break;
2568 case 0x03: data_block = "Vendor-Specific Data Block"; break;
2569 case 0x04: data_block = "Speaker Allocation Data Block"; audio_block = true; break;
2570 case 0x05: data_block = "VESA Display Transfer Characteristics Data Block"; break;
2571 case 0x06: data_block = "Video Format Data Block"; break;
2572 case 0x07: data_block = "Unknown CTA-861 Data Block (extended tag truncated)"; break;
2574 case 0x700: data_block = "Video Capability Data Block"; break;
2575 case 0x701: data_block = "Vendor-Specific Video Data Block"; break;
2576 case 0x702: data_block = "VESA Video Display Device Data Block"; break;
2577 case 0x703: data_block = "VESA Video Timing Block Extension"; break;
2578 case 0x704: data_block = "Reserved for HDMI Video Data Block"; break;
2579 case 0x705: data_block = "Colorimetry Data Block"; break;
2580 case 0x706: data_block = "HDR Static Metadata Data Block"; break;
2581 case 0x707: data_block = "HDR Dynamic Metadata Data Block"; break;
2582 case 0x708: data_block = "Native Video Resolution Data Block"; break;
2584 case 0x70d: data_block = "Video Format Preference Data Block"; break;
2585 case 0x70e: data_block = "YCbCr 4:2:0 Video Data Block"; break;
2586 case 0x70f: data_block = "YCbCr 4:2:0 Capability Map Data Block"; break;
2587 case 0x710: data_block = "Reserved for CTA-861 Miscellaneous Audio Fields"; break;
2588 case 0x711: data_block = "Vendor-Specific Audio Data Block"; audio_block = true; break;
2589 case 0x712: data_block = "HDMI Audio Data Block"; audio_block = true; break;
2590 case 0x713: data_block = "Room Configuration Data Block"; audio_block = true; break;
2591 case 0x714: data_block = "Speaker Location Data Block"; audio_block = true; break;
2593 case 0x720: data_block = "InfoFrame Data Block"; break;
2595 case 0x722: data_block = "DisplayID Type VII Video Timing Data Block"; break;
2596 case 0x723: data_block = "DisplayID Type VIII Video Timing Data Block"; break;
2597 case 0x72a: data_block = "DisplayID Type X Video Timing Data Block"; break;
2599 case 0x778: data_block = "HDMI Forum EDID Extension Override Data Block"; break;
2600 case 0x779: data_block = "HDMI Forum Sink Capability Data Block"; break;
2601 case 0x77a: data_block = "HDMI Forum Source-Based Tone Mapping Data Block"; break;
2603 default:
2604 std::string unknown_name;
2605 if (tag < 0x700) unknown_name = "Unknown CTA-861 Data Block";
2606 else if (tag < 0x70d) unknown_name = "Unknown CTA-861 Video-Related Data Block";
2607 else if (tag < 0x720) unknown_name = "Unknown CTA-861 Audio-Related Data Block";
2608 else if (tag < 0x778) unknown_name = "Unknown CTA-861 Data Block";
2609 else if (tag < 0x780) unknown_name = "Unknown CTA-861 HDMI-Related Data Block";
2610 else unknown_name = "Unknown CTA-861 Data Block";
2611 unknown_name += std::string(" (") + (extended ? "extended " : "") + "tag " + utohex(tag & 0xff) + ", length " + std::to_string(length) + ")";
2612 printf(" %s:\n", unknown_name.c_str());
2613 warn("%s.\n", unknown_name.c_str());
2614 break;
2617 switch (tag) {
2618 case 0x03:
2619 case 0x701:
2620 case 0x711: {
2621 unsigned ouinum;
2623 data_block_oui(data_block, x, length, &ouinum);
2624 x += (length < 3) ? length : 3;
2625 length -= (length < 3) ? length : 3;
2626 dooutputname = false;
2627 tag |= ouinum;
2628 break;
2632 if (dooutputname && data_block.length())
2633 printf(" %s:\n", data_block.c_str());
2635 switch (tag) {
2636 case 0x04:
2637 case 0x05:
2638 case 0x700:
2639 case 0x702:
2640 case 0x705:
2641 case 0x706:
2642 case 0x708:
2643 case 0x70d:
2644 case 0x70f:
2645 case 0x712:
2646 case 0x713:
2647 case 0x778:
2648 case 0x779:
2649 case 0x77a:
2650 if (std::find(found_tags.begin(), found_tags.end(), tag) != found_tags.end())
2651 fail("Only one instance of this Data Block is allowed.\n");
2652 break;
2655 // See Table 52 of CTA-861-G for a description of Byte 3
2656 if (audio_block && !(cta.byte3 & 0x40))
2657 fail("Audio information is present, but bit 6 of Byte 3 of the CTA-861 Extension header indicates no Basic Audio support.\n");
2659 switch (tag) {
2660 case 0x01: cta_audio_block(x, length); break;
2661 case 0x02: cta_svd(x, length, false); break;
2662 case 0x03|kOUI_HDMI:
2663 cta_hdmi_block(x, length);
2664 // The HDMI OUI is present, so this EDID represents an HDMI
2665 // interface. And HDMI interfaces must use EDID version 1.3
2666 // according to the HDMI Specification, so check for this.
2667 if (base.edid_minor != 3)
2668 fail("The HDMI Specification requires EDID 1.3 instead of 1.%u.\n",
2669 base.edid_minor);
2670 break;
2671 case 0x03|kOUI_HDMIForum:
2672 if (cta.previous_cta_tag != (0x03|kOUI_HDMI))
2673 fail("HDMI Forum VSDB did not immediately follow the HDMI VSDB.\n");
2674 if (cta.have_hf_scdb || cta.have_hf_vsdb)
2675 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2676 cta_hf_scdb(x, length);
2677 cta.have_hf_vsdb = true;
2678 break;
2679 case 0x03|kOUI_AMD: cta_amd(x, length); break;
2680 case 0x03|kOUI_Microsoft: if (length != 0x12) goto dodefault; cta_microsoft(x, length); break;
2681 case 0x03|kOUI_UHDA: cta_uhda_fmm(x, length); break;
2682 case 0x04: cta_sadb(x, length); break;
2683 case 0x05: cta_vesa_dtcdb(x, length); break;
2684 case 0x06: cta_vfdb(x, length); break;
2685 case 0x07: fail("Extended tag cannot have zero length.\n"); break;
2686 case 0x700: cta_vcdb(x, length); break;
2687 case 0x701|kOUI_HDR10: cta_hdr10plus(x, length); break;
2688 case 0x701|kOUI_Dolby: cta_dolby_video(x, length); break;
2689 // 0x701|kOUI_Apple: this almost certainly contains 'BLC Info/Corrections',
2690 // since the data (spread out over two VSDBs) is very similar to what is seen
2691 // in DisplayID blocks. Since I don't know how to parse this data, we still
2692 // default to a hex dump, but I mention this here in case data on how to
2693 // parse this becomes available.
2694 case 0x702: cta_vesa_vdddb(x, length); break;
2695 case 0x705: cta_colorimetry_block(x, length); break;
2696 case 0x706: cta_hdr_static_metadata_block(x, length); break;
2697 case 0x707: cta_hdr_dyn_metadata_block(x, length); break;
2698 case 0x708: cta_nvrdb(x, length); return;
2699 case 0x70d: cta_vfpdb(x, length); break;
2700 case 0x70e: cta_svd(x, length, true); break;
2701 case 0x70f: cta_y420cmdb(x, length); break;
2702 case 0x711|kOUI_Dolby: cta_dolby_audio(x, length); break;
2703 case 0x712: cta_hdmi_audio_block(x, length); break;
2704 case 0x713: cta_rcdb(x, length); break;
2705 case 0x714: cta_sldb(x, length); break;
2706 case 0x720: cta_ifdb(x, length); break;
2707 case 0x722: cta_displayid_type_7(x, length); break;
2708 case 0x723: cta_displayid_type_8(x, length); break;
2709 case 0x72a: cta_displayid_type_10(x, length); break;
2710 case 0x778:
2711 cta_hf_eeodb(x, length);
2712 if (block_nr != 1)
2713 fail("Data Block can only be present in Block 1.\n");
2714 // This must be the first CTA-861 block
2715 if (cta.block_number > 0)
2716 fail("Data Block starts at a wrong offset.\n");
2717 break;
2718 case 0x779:
2719 if (cta.previous_cta_tag != (0x03|kOUI_HDMI))
2720 fail("HDMI Forum SCDB did not immediately follow the HDMI VSDB.\n");
2721 if (cta.have_hf_scdb || cta.have_hf_vsdb)
2722 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2723 if (block_nr != 1)
2724 fail("Data Block can only be present in Block 1.\n");
2725 if (length < 2) {
2726 data_block = std::string("HDMI Forum SCDB");
2727 fail("Invalid length %u < 2.\n", length);
2728 break;
2730 if (x[0] || x[1])
2731 printf(" Non-zero SCDB reserved fields!\n");
2732 cta_hf_scdb(x + 2, length - 2);
2733 cta.have_hf_scdb = true;
2734 break;
2735 case 0x77a:
2736 cta_hf_sbtmdb(x, length);
2737 break;
2738 dodefault:
2739 default:
2740 hex_block(" ", x, length);
2741 break;
2744 cta.block_number++;
2745 cta.previous_cta_tag = tag;
2746 found_tags.push_back(tag);
2749 void edid_state::preparse_cta_block(unsigned char *x)
2751 unsigned version = x[1];
2752 unsigned offset = x[2];
2754 if (offset >= 4) {
2755 const unsigned char *detailed;
2757 for (detailed = x + offset; detailed + 17 < x + 127; detailed += 18) {
2758 if (memchk(detailed, 18))
2759 break;
2760 if (detailed[0] || detailed[1])
2761 cta.preparsed_total_dtds++;
2765 if (version < 3)
2766 return;
2768 for (unsigned i = 4; i < offset; i += (x[i] & 0x1f) + 1) {
2769 bool for_ycbcr420 = false;
2770 unsigned oui;
2772 switch ((x[i] & 0xe0) >> 5) {
2773 case 0x03:
2774 oui = (x[i + 3] << 16) + (x[i + 2] << 8) + x[i + 1];
2775 if (oui == 0x000c03) {
2776 cta.has_hdmi = true;
2777 cta.preparsed_phys_addr = (x[i + 4] << 8) | x[i + 5];
2778 } else if ((oui == 0xca125c || oui == 0x5c12ca) &&
2779 (x[i] & 0x1f) == 0x15 && replace_unique_ids) {
2780 memset(x + i + 6, 0, 16);
2781 replace_checksum(x, EDID_PAGE_SIZE);
2783 break;
2784 case 0x06:
2785 if (!(x[i] & 0x1f) || cta.preparsed_first_vfd.rid)
2786 break;
2787 cta.preparsed_first_vfd = cta_parse_vfd(x + i + 2, (x[i + 1] & 3) + 1);
2788 break;
2789 case 0x07:
2790 if (x[i + 1] == 0x0d)
2791 cta.has_vfpdb = true;
2792 else if (x[i + 1] == 0x05)
2793 cta.has_cdb = true;
2794 else if (x[i + 1] == 0x08)
2795 cta.has_nvrdb = true;
2796 else if (x[i + 1] == 0x13 && (x[i + 2] & 0x40)) {
2797 cta.preparsed_speaker_count = 1 + (x[i + 2] & 0x1f);
2798 cta.preparsed_sld = x[i + 2] & 0x20;
2799 } else if (x[i + 1] == 0x14)
2800 cta_preparse_sldb(x + i + 2, (x[i] & 0x1f) - 1);
2801 else if (x[i + 1] == 0x22)
2802 cta.preparsed_total_vtdbs++;
2803 else if (x[i + 1] == 0x23) {
2804 cta.preparsed_has_t8vtdb = true;
2805 cta.preparsed_t8vtdb_dmt = x[i + 3];
2806 if (x[i + 2] & 0x08)
2807 cta.preparsed_t8vtdb_dmt |= x[i + 4] << 8;
2808 } else if (x[i + 1] == 0x2a)
2809 cta.preparsed_total_vtdbs +=
2810 ((x[i] & 0x1f) - 2) / (6 + ((x[i + 2] & 0x70) >> 4));
2811 else if (x[i + 1] == 0x78)
2812 cta.hf_eeodb_blocks = x[i + 2];
2813 if (x[i + 1] != 0x0e)
2814 continue;
2815 for_ycbcr420 = true;
2816 #ifdef __EMSCRIPTEN__
2817 [[clang::fallthrough]];
2818 #endif
2819 /* fall-through */
2820 case 0x02:
2821 for (unsigned j = 1 + for_ycbcr420; j <= (x[i] & 0x1f); j++) {
2822 unsigned char vic = x[i + j];
2824 if ((vic & 0x7f) <= 64)
2825 vic &= 0x7f;
2826 cta.preparsed_svds[for_ycbcr420].push_back(vic);
2827 cta.preparsed_has_vic[for_ycbcr420][vic] = true;
2829 const struct timings *t = find_vic_id(vic);
2831 if (!for_ycbcr420 && t &&
2832 t->pixclk_khz > cta.preparsed_max_vic_pixclk_khz)
2833 cta.preparsed_max_vic_pixclk_khz = t->pixclk_khz;
2835 break;
2840 void edid_state::parse_cta_block(const unsigned char *x)
2842 unsigned version = x[1];
2843 unsigned offset = x[2];
2844 const unsigned char *detailed;
2846 // See Table 52 of CTA-861-G for a description of Byte 3
2848 printf(" Revision: %u\n", version);
2849 if (version == 0)
2850 fail("Invalid CTA-861 Extension revision 0.\n");
2851 if (version == 2)
2852 fail("Deprecated CTA-861 Extension revision 2.\n");
2853 if (cta.has_hdmi && version != 3)
2854 fail("The HDMI Specification requires CTA Extension revision 3.\n");
2855 if (version > 3)
2856 warn("Unknown CTA-861 Extension revision %u.\n", version);
2857 if (offset > 0 && offset < 4)
2858 fail("Invalid CTA-861 Extension offset value (byte 2).\n");
2860 if (version >= 1) do {
2861 if (version == 1 && x[3] != 0)
2862 fail("Non-zero byte 3.\n");
2864 if (version < 3 && offset >= 4 && ((offset - 4) / 8)) {
2865 printf(" 8-byte timing descriptors: %u\n", (offset - 4) / 8);
2866 fail("8-byte descriptors were never used.\n");
2869 if (version >= 2) {
2870 if (x[3] & 0x80)
2871 printf(" Underscans IT Video Formats by default\n");
2872 else
2873 warn("IT Video Formats are overscanned by default, but normally this should be underscanned.\n");
2874 if (x[3] & 0x40)
2875 printf(" Basic audio support\n");
2876 if (x[3] & 0x20)
2877 printf(" Supports YCbCr 4:4:4\n");
2878 if (x[3] & 0x10)
2879 printf(" Supports YCbCr 4:2:2\n");
2880 // Disable this test: this fails a lot of EDIDs, and there are
2881 // also some corner cases where you only want to receive 4:4:4
2882 // and refuse a fallback to 4:2:2.
2883 // if ((x[3] & 0x30) && (x[3] & 0x30) != 0x30)
2884 // msg(!cta.has_hdmi, "If YCbCr support is indicated, then both 4:2:2 and 4:4:4 %s be supported.\n",
2885 // cta.has_hdmi ? "shall" : "should");
2886 printf(" Native detailed modes: %u\n", x[3] & 0x0f);
2887 if (cta.block_number == 0)
2888 cta.byte3 = x[3];
2889 else if (x[3] != cta.byte3)
2890 fail("Byte 3 must be the same for all CTA-861 Extension Blocks.\n");
2891 if (cta.block_number == 0) {
2892 unsigned native_dtds = x[3] & 0x0f;
2894 cta.native_timings.clear();
2895 if (!native_dtds && !cta.has_vfpdb) {
2896 cta.first_svd_might_be_preferred = true;
2897 } else if (native_dtds > cta.preparsed_total_dtds) {
2898 fail("There are more Native DTDs (%u) than DTDs (%u).\n",
2899 native_dtds, cta.preparsed_total_dtds);
2901 if (native_dtds > cta.preparsed_total_dtds)
2902 native_dtds = cta.preparsed_total_dtds;
2903 for (unsigned i = 0; i < native_dtds; i++) {
2904 char type[16];
2906 sprintf(type, "DTD %3u", i + 1);
2907 cta.native_timings.push_back(timings_ext(i + 129, type));
2909 if (cta.has_hdmi && block_nr != (block_map.saw_block_1 ? 2 : 1))
2910 fail("The HDMI Specification requires that the first Extension Block (that is not a Block Map) is an CTA-861 Extension Block.\n");
2914 if (offset < 4) {
2915 // Offset 0 means that there are no data blocks or DTDs,
2916 // so the remainder must be padding.
2917 if (!memchk(x + 4, 127 - 4)) {
2918 data_block = "Padding";
2919 fail("Contains non-zero bytes.\n");
2921 break;
2924 if (version >= 3) {
2925 unsigned i;
2927 for (i = 4; i < offset; i += (x[i] & 0x1f) + 1) {
2928 cta_block(x + i, cta.found_tags);
2931 data_block.clear();
2932 if (i != offset)
2933 fail("Offset is %u, but should be %u.\n", offset, i);
2936 data_block = "Detailed Timing Descriptors";
2937 base.seen_non_detailed_descriptor = false;
2938 bool first = true;
2939 for (detailed = x + offset; detailed + 17 < x + 127; detailed += 18) {
2940 if (memchk(detailed, 18))
2941 break;
2942 if (first) {
2943 first = false;
2944 printf(" %s:\n", data_block.c_str());
2946 detailed_block(detailed);
2948 unused_bytes = x + 127 - detailed;
2949 if (!memchk(detailed, unused_bytes)) {
2950 data_block = "Padding";
2951 fail("Contains non-zero bytes.\n");
2953 } while (0);
2955 data_block.clear();
2956 if (base.serial_number && base.has_serial_string)
2957 warn("Display Product Serial Number is set, so the Serial Number in the Base EDID should be 0.\n");
2958 if (!cta.has_vic_1 && !base.has_640x480p60_est_timing)
2959 fail("Required 640x480p60 timings are missing in the established timings"
2960 " and the SVD list (VIC 1).\n");
2961 if ((cta.supported_hdmi_vic_vsb_codes & cta.supported_hdmi_vic_codes) !=
2962 cta.supported_hdmi_vic_codes)
2963 fail("HDMI VIC Codes must have their CTA-861 VIC equivalents in the VSB.\n");
2964 if (!cta.has_vcdb)
2965 fail("Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.\n");
2966 if (!base.uses_srgb && !cta.has_cdb)
2967 warn("Add a Colorimetry Data Block with the sRGB colorimetry bit set to avoid interop issues.\n");
2970 void edid_state::cta_resolve_svr(timings_ext &t_ext)
2972 if (t_ext.svr() == 254) {
2973 t_ext.flags = cta.t8vtdb.flags;
2974 add_str(t_ext.flags, ">=CTA-861-H");
2975 t_ext.t = cta.t8vtdb.t;
2976 } else if (t_ext.svr() <= 144) {
2977 if (t_ext.svr() < 129 || t_ext.svr() - 129 >= cta.vec_dtds.size())
2978 return;
2979 t_ext.flags = cta.vec_dtds[t_ext.svr() - 129].flags;
2980 t_ext.t = cta.vec_dtds[t_ext.svr() - 129].t;
2981 } else if (t_ext.svr() <= 160) {
2982 if (t_ext.svr() - 145 >= cta.vec_vtdbs.size())
2983 return;
2984 t_ext.flags = cta.vec_vtdbs[t_ext.svr() - 145].flags;
2985 add_str(t_ext.flags, ">=CTA-861-H");
2986 t_ext.t = cta.vec_vtdbs[t_ext.svr() - 145].t;
2987 } else if (t_ext.svr() <= 175) {
2988 t_ext.flags.clear();
2989 unsigned char rid = cta.preparsed_first_vfd.rid;
2990 t_ext.t = calc_ovt_mode(rids[rid].hact, rids[rid].vact,
2991 rids[rid].hratio, rids[rid].vratio,
2992 vf_rate_values[t_ext.svr() - 160]);
2993 t_ext.flags = ">=CTA-861.6";
2997 void edid_state::cta_resolve_svrs()
2999 for (vec_timings_ext::iterator iter = cta.preferred_timings_vfpdb.begin();
3000 iter != cta.preferred_timings_vfpdb.end(); ++iter) {
3001 if (iter->has_svr())
3002 cta_resolve_svr(*iter);
3005 for (vec_timings_ext::iterator iter = cta.native_timings.begin();
3006 iter != cta.native_timings.end(); ++iter) {
3007 if (iter->has_svr())
3008 cta_resolve_svr(*iter);
3011 for (vec_timings_ext::iterator iter = cta.native_timing_nvrdb.begin();
3012 iter != cta.native_timing_nvrdb.end(); ++iter) {
3013 if (iter->has_svr())
3014 cta_resolve_svr(*iter);
3018 void edid_state::check_cta_blocks()
3020 unsigned max_pref_prog_hact = 0;
3021 unsigned max_pref_prog_vact = 0;
3022 unsigned max_pref_ilace_hact = 0;
3023 unsigned max_pref_ilace_vact = 0;
3025 data_block = "CTA-861";
3027 // HDMI 1.4 goes up to 340 MHz. Dubious to have a DTD above that,
3028 // but no VICs. Displays often have a setting to turn off HDMI 2.x
3029 // support, dropping any HDMI 2.x VICs, but they sometimes forget
3030 // to replace the DTD in the base block as well.
3031 if (cta.warn_about_hdmi_2x_dtd)
3032 warn("DTD pixelclock indicates HDMI 2.x support, VICs indicate HDMI 1.x.\n");
3034 for (vec_timings_ext::iterator iter = cta.preferred_timings.begin();
3035 iter != cta.preferred_timings.end(); ++iter) {
3036 if (iter->t.interlaced &&
3037 (iter->t.vact > max_pref_ilace_vact ||
3038 (iter->t.vact == max_pref_ilace_vact && iter->t.hact >= max_pref_ilace_hact))) {
3039 max_pref_ilace_hact = iter->t.hact;
3040 max_pref_ilace_vact = iter->t.vact;
3042 if (!iter->t.interlaced &&
3043 (iter->t.vact > max_pref_prog_vact ||
3044 (iter->t.vact == max_pref_prog_vact && iter->t.hact >= max_pref_prog_hact))) {
3045 max_pref_prog_hact = iter->t.hact;
3046 max_pref_prog_vact = iter->t.vact;
3049 for (vec_timings_ext::iterator iter = cta.preferred_timings_vfpdb.begin();
3050 iter != cta.preferred_timings_vfpdb.end(); ++iter) {
3051 if (iter->t.interlaced &&
3052 (iter->t.vact > max_pref_ilace_vact ||
3053 (iter->t.vact == max_pref_ilace_vact && iter->t.hact >= max_pref_ilace_hact))) {
3054 max_pref_ilace_hact = iter->t.hact;
3055 max_pref_ilace_vact = iter->t.vact;
3057 if (!iter->t.interlaced &&
3058 (iter->t.vact > max_pref_prog_vact ||
3059 (iter->t.vact == max_pref_prog_vact && iter->t.hact >= max_pref_prog_hact))) {
3060 max_pref_prog_hact = iter->t.hact;
3061 max_pref_prog_vact = iter->t.vact;
3065 unsigned native_prog = 0;
3066 unsigned native_prog_hact = 0;
3067 unsigned native_prog_vact = 0;
3068 bool native_prog_mixed_resolutions = false;
3069 unsigned native_ilace = 0;
3070 unsigned native_ilace_hact = 0;
3071 unsigned native_ilace_vact = 0;
3072 bool native_ilace_mixed_resolutions = false;
3073 unsigned native_nvrdb_hact = 0;
3074 unsigned native_nvrdb_vact = 0;
3076 for (vec_timings_ext::iterator iter = cta.native_timings.begin();
3077 iter != cta.native_timings.end(); ++iter) {
3078 if (iter->t.interlaced) {
3079 native_ilace++;
3080 if (!native_ilace_hact) {
3081 native_ilace_hact = iter->t.hact;
3082 native_ilace_vact = iter->t.vact;
3083 } else if (native_ilace_hact != iter->t.hact ||
3084 native_ilace_vact != iter->t.vact) {
3085 native_ilace_mixed_resolutions = true;
3087 } else {
3088 native_prog++;
3089 if (!native_prog_hact) {
3090 native_prog_hact = iter->t.hact;
3091 native_prog_vact = iter->t.vact;
3092 } else if (native_prog_hact != iter->t.hact ||
3093 native_prog_vact != iter->t.vact) {
3094 native_prog_mixed_resolutions = true;
3099 for (vec_timings_ext::iterator iter = cta.native_timing_nvrdb.begin();
3100 iter != cta.native_timing_nvrdb.end(); ++iter) {
3101 native_nvrdb_hact = iter->t.hact;
3102 native_nvrdb_vact = iter->t.vact;
3105 if (native_prog_mixed_resolutions)
3106 fail("Native progressive timings are a mix of several resolutions.\n");
3107 if (native_ilace_mixed_resolutions)
3108 fail("Native interlaced timings are a mix of several resolutions.\n");
3109 if (native_ilace && !native_prog)
3110 fail("A native interlaced timing is present, but not a native progressive timing.\n");
3111 if (!native_prog_mixed_resolutions && native_prog > 1)
3112 warn("Multiple native progressive timings are defined.\n");
3113 if (!native_ilace_mixed_resolutions && native_ilace > 1)
3114 warn("Multiple native interlaced timings are defined.\n");
3116 if (native_nvrdb_vact &&
3117 (max_pref_prog_vact > native_nvrdb_vact ||
3118 (max_pref_prog_vact == native_nvrdb_vact && max_pref_prog_hact > native_nvrdb_hact)))
3119 warn("Native video resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
3120 native_nvrdb_hact, native_nvrdb_vact,
3121 max_pref_prog_hact, max_pref_prog_vact);
3122 else if (!native_nvrdb_vact && !native_prog_mixed_resolutions && native_prog_vact &&
3123 (max_pref_prog_vact > native_prog_vact ||
3124 (max_pref_prog_vact == native_prog_vact && max_pref_prog_hact > native_prog_hact)))
3125 warn("Native progressive resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
3126 native_prog_hact, native_prog_vact,
3127 max_pref_prog_hact, max_pref_prog_vact);
3128 if (!native_ilace_mixed_resolutions && native_ilace_vact &&
3129 (max_pref_ilace_vact > native_ilace_vact ||
3130 (max_pref_ilace_vact == native_ilace_vact && max_pref_ilace_hact > native_ilace_hact)))
3131 warn("Native interlaced resolution of %ux%u is smaller than the max preferred interlaced resolution %ux%u.\n",
3132 native_ilace_hact, native_ilace_vact,
3133 max_pref_ilace_hact, max_pref_ilace_vact);
3135 if (dispid.native_width && native_prog_hact &&
3136 !native_prog_mixed_resolutions) {
3137 if (dispid.native_width != native_prog_hact ||
3138 dispid.native_height != native_prog_vact)
3139 fail("Mismatch between CTA-861 and DisplayID native progressive resolution.\n");