edid-decode: fix emscripten build
[edid-decode.git] / parse-if.cpp
blob589594a516e41129792b61715013cf33b70f3970
1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright 2024 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5 * Author: Hans Verkuil <hverkuil-cisco@xs4all.nl>
6 */
8 #include <stdio.h>
10 #include "edid-decode.h"
12 int edid_state::parse_if_hdr(const unsigned char *x, unsigned size, unsigned char mask)
14 unsigned char length = x[2];
16 printf("%s\n", data_block.c_str());
17 printf(" Version: %u\n", x[1] & mask);
18 printf(" Length: %u\n", length);
20 if (length + 3U > size) {
21 fail("Expected InfoFrame total length of %d, but have only %d bytes.\n",
22 length + 3, size);
23 return -1;
25 if (length + 3U < size) {
26 warn("There are %d dummy bytes after the payload.\n", length + 3 - size);
27 if (!memchk(x + length + 3, length + 3 - size))
28 warn("There are non-zero dummy bytes after the payload.\n");
30 return 0;
33 static const char *Structure_map[] = {
34 "Frame packing",
35 "Field alternative",
36 "Line alternative",
37 "Side-by-Side (Full)",
38 "L + depth",
39 "L + depth + graphics + graphics-depth",
40 "Top-and-Bottom",
41 "Reserved (7)",
42 "Side-by-Side (Half)",
43 "Reserved (9)",
44 "Reserved (10)",
45 "Reserved (11)",
46 "Reserved (12)",
47 "Reserved (13)",
48 "Reserved (14)",
49 "Not in use"
52 static const char *ExtData_map[] = {
53 "Horizontal sub-sampling (0)",
54 "Horizontal sub-sampling (1)",
55 "Horizontal sub-sampling (2)",
56 "Horizontal sub-sampling (3)",
57 "Quincunx matrix: Odd/Left picture, Odd/Right picture",
58 "Quincunx matrix: Odd/Left picture, Even/Right picture",
59 "Quincunx matrix: Even/Left picture, Odd/Right picture",
60 "Quincunx matrix: Even/Left picture, Even/Right picture"
63 void edid_state::parse_if_hdmi(const unsigned char *x, unsigned len)
65 if (len < 4) {
66 fail("Expected InfoFrame length of at least 4, got %d.\n", len);
67 return;
69 if (x[4] & 0x1f)
70 fail("Bits 4-0 of PB4 are not 0.\n");
72 printf(" HDMI Video Format: ");
74 char buf[32];
76 switch (x[4] >> 5) {
77 case 0:
78 printf("No additional data\n");
79 if (!memchk(x + 5, len - 4))
80 fail("Trailing non-0 bytes.\n");
81 return;
82 case 1: {
83 printf("HDMI_VIC is present\n");
85 if (len < 5) {
86 fail("Expected InfoFrame length of at least 5, got %d.\n", len);
87 return;
89 sprintf(buf, "HDMI VIC %u", x[5]);
90 const struct timings *t = find_hdmi_vic_id(x[5]);
91 if (!t) {
92 printf(" HDMI VIC: %d (0x%02x)\n", x[5], x[5]);
93 fail("Unknown HDMI VIC code.\n");
94 } else {
95 print_timings(" ", t, buf);
97 if (!memchk(x + 6, len - 5))
98 fail("Trailing non-0 bytes.\n");
99 return;
101 case 2:
102 printf("3D format indication present\n");
104 if (len < 5) {
105 fail("Expected InfoFrame length of at least 5, got %d.\n", len);
106 return;
108 break;
109 default:
110 printf("Reserved (%d)\n", x[4] >> 5);
111 fail("Invalid HDMI Video Format (%d).\n", x[4] >> 5);
112 return;
115 // Parsing of 3D extension continues here
116 unsigned char v = x[5] >> 4;
118 printf(" 3D Structure: %s\n", Structure_map[v]);
119 if (x[5] & 7)
120 fail("Bits 2-0 of PB5 are not 0.\n");
121 printf("3D Metadata Present: %s\n", (x[5] & 8) ? "Yes" : "No");
123 if (v < 8) {
124 if (!memchk(x + 6, len - 5))
125 fail("Trailing non-0 bytes.\n");
126 return;
129 if (len < 6) {
130 fail("Expected InfoFrame length of at least 6, got %d.\n", len);
131 return;
134 if (x[6] & 0xf)
135 fail("Bits 3-0 of PB6 are not 0.\n");
137 if ((x[6] >> 4) >= 8)
138 printf(" 3D Extended Data: Reserved (%d)\n", (x[6] >> 4));
139 else
140 printf(" 3D Extended Data: %s\n", ExtData_map[x[6] >> 4]);
142 if (!(x[5] & 8)) {
143 if (!memchk(x + 7, len - 6))
144 fail("Trailing non-0 bytes.\n");
145 return;
148 if (len < 7) {
149 fail("Expected InfoFrame length of at least 7, got %d.\n", len);
150 return;
152 unsigned mlen = x[7] & 0x1f;
153 if (len < mlen + 7) {
154 fail("Expected InfoFrame length of at least %d, got %d.\n", mlen + 7, len);
155 return;
157 if (!memchk(x + mlen + 7, len - mlen - 6))
158 fail("Trailing non-0 bytes.\n");
159 if (x[7] >> 5) {
160 printf(" 3D Metadata Type: Reserved (%d)\n", x[7] >> 5);
161 fail("Invalid 3D Metadata Type.\n");
162 return;
163 } else {
164 printf(" 3D Metadata Type: Parallax Information\n");
166 printf(" Metadata: Parallax Zero: %u\n", (x[8] << 8) | x[9]);
167 printf(" Metadata: Parallax Scale: %u\n", (x[10] << 8) | x[11]);
168 printf(" Metadata: DRef: %u\n", (x[12] << 8) | x[13]);
169 printf(" Metadata: WRef: %u\n", (x[14] << 8) | x[15]);
172 void edid_state::parse_if_hdmi_forum(const unsigned char *x, unsigned len)
174 if (len < 5) {
175 fail("Expected InfoFrame length of at least 5, got %d.\n", len);
176 return;
178 if (x[5] & 0x0c)
179 fail("Bits 3-2 of PB5 are not 0.\n");
180 unsigned char v = x[5] >> 4;
181 printf(" Color Content Bits Per Component: ");
182 if (!v)
183 printf("No Indication\n");
184 else if (v > 9)
185 printf("Reserved (%d)\n", v);
186 else
187 printf("%d bits\n", v + 7);
188 if (x[5] & 1)
189 printf(" 3D Valid\n");
190 printf(" Auto Low-Latency Mode: %s\n", (x[5] & 2) ? "Yes" : "No");
191 if (!(x[5] & 1)) {
192 if (!memchk(x + 6, len - 5))
193 fail("Trailing non-0 bytes.\n");
194 return;
197 // Parsing of 3D extension continues here
198 unsigned offset = 6;
199 v = x[offset] >> 4;
201 if (len < offset)
202 goto err_len;
204 printf(" 3D Structure: %s\n", Structure_map[v]);
205 if (x[offset] & 1)
206 fail("Bit 0 of PB6 is not 0.\n");
207 printf("3D Additional Info Present: %s\n", (x[offset] & 8) ? "Yes" : "No");
208 printf("3D Disparity Data Present: %s\n", (x[offset] & 4) ? "Yes" : "No");
209 printf("3D Metadata Present: %s\n", (x[offset] & 2) ? "Yes" : "No");
210 offset++;
212 if (v >= 8) {
213 if (len < offset)
214 goto err_len;
216 if (x[offset] & 0xf)
217 fail("Bits 3-0 of PB7 are not 0.\n");
219 if ((x[offset] >> 4) >= 8)
220 printf(" 3D Extended Data: Reserved (%d)\n", (x[offset] >> 4));
221 else
222 printf(" 3D Extended Data: %s\n", ExtData_map[x[offset] >> 4]);
223 offset++;
226 if (x[6] & 8) {
227 if (len < offset)
228 goto err_len;
230 if (x[offset] & 0xe0)
231 fail("Bits 7-5 if PB%d are not 0.\n", offset);
232 printf(" 3D Dual View: %s\n", (x[offset] & 0x10) ? "Yes" : "No");
234 static const char *ViewDep_map[] = {
235 "No Indication",
236 "Independent Right View",
237 "Independent Left View",
238 "Independent Right and Left Views"
240 printf(" 3D View Dependency: %s\n", ViewDep_map[(x[offset] & 0x0c) >> 2]);
242 static const char *Pref2DView_map[] = {
243 "No Indication",
244 "Right View",
245 "Left View",
246 "Either View"
248 printf(" 3D Preferred 2D View: %s\n", Pref2DView_map[x[offset] & 3]);
249 offset++;
252 if (x[6] & 4) {
253 if (len < offset)
254 goto err_len;
256 printf(" Disparity Data Version: %d\n", x[offset] >> 5);
257 unsigned dlen = x[offset] & 0x1f;
258 printf(" Disparity Data Length: %d\n", dlen);
259 if (len < offset + dlen)
260 goto err_len;
261 offset++;
263 hex_block(" Disparity Data Payload: ", x + offset, dlen, false, dlen);
265 offset += dlen;
268 if (x[6] & 2) {
269 if (len < offset)
270 goto err_len;
272 if (x[offset] >> 5) {
273 printf(" 3D Metadata Type: Reserved (%d)\n", x[offset] >> 5);
274 fail("Invalid 3D Metadata Type.\n");
275 return;
277 printf(" 3D Metadata Type: Parallax Information\n");
278 printf(" 3D Metadata Length: %d\n", x[offset] & 0x1f);
279 if (len < offset + (x[offset] & 0x1f))
280 goto err_len;
281 offset++;
283 printf(" Metadata: Parallax Zero: %u\n", (x[offset] << 8) | x[offset+1]);
284 printf(" Metadata: Parallax Scale: %u\n", (x[offset+2] << 8) | x[offset+3]);
285 printf(" Metadata: DRef: %u\n", (x[offset+4] << 8) | x[offset+5]);
286 printf(" Metadata: WRef: %u\n", (x[offset+6] << 8) | x[offset+7]);
288 offset += x[offset - 1] & 0x1f;
291 if (!memchk(x + offset + 1, len - offset))
292 fail("Trailing non-0 bytes.\n");
293 return;
295 err_len:
296 fail("Expected InfoFrame length of at least %d, got %d.\n", offset, len);
297 return;
300 void edid_state::parse_if_vendor(const unsigned char *x, unsigned size)
302 data_block = "Vendor-Specific InfoFrame";
304 unsigned oui;
305 unsigned char len = x[2];
307 data_block_oui(data_block, x + 3, 3, &oui, false, false, false, true);
309 if (parse_if_hdr(x, size, (x[1] & 0x7f) == 2 ? 0x7f : 0xff))
310 return;
312 if (x[1] != 1 && (x[1] & 0x7f) != 2) {
313 fail("Invalid version %d\n", x[1] & 0x7f);
314 return;
316 if (len < 3) {
317 fail("Expected InfoFrame length of at least 3, got %d.\n", len);
318 return;
321 if (x[1] != 1)
322 printf(" VSIF Change: %s\n", (x[1] & 0x80) ? "Yes" : "No");
324 // After this x[1] will refer to Data Byte 1
325 x += 2;
327 switch (oui) {
328 case kOUI_HDMI:
329 parse_if_hdmi(x, len);
330 break;
331 case kOUI_HDMIForum:
332 parse_if_hdmi_forum(x, len);
333 break;
334 default:
335 hex_block(" Payload: ", x + 4, len - 3, false, len - 3);
336 break;
340 void edid_state::parse_if_avi(const unsigned char *x, unsigned size)
342 unsigned char version = x[1];
343 unsigned char length = x[2];
345 data_block = "AVI InfoFrame";
347 if (parse_if_hdr(x, size))
348 return;
350 if (version == 0 || version > 4) {
351 fail("Invalid version %u\n", version);
352 return;
354 if (version == 1)
355 fail("Sources shall not use version 1.\n");
356 if (length < 13) {
357 fail("Expected InfoFrame length of 13, got %u.\n", length);
358 return;
361 // After this x[1] will refer to Data Byte 1
362 x += 2;
364 if (version == 1) {
365 if (x[3] & 0xfc)
366 fail("Bits F37-F32 are not 0.\n");
367 if (x[4])
368 fail("Bits F47-F40 are not 0.\n");
369 if (x[5])
370 fail("Bits F57-F50 are not 0.\n");
372 if (version == 2) {
373 if (x[1] & 0x80)
374 fail("Bit Y2 is not 0.\n");
375 if (x[4] & 0x80)
376 fail("Bit VIC7 is not 0.\n");
378 if (version == 4 && length == 15) {
379 if (x[15] & 0x80)
380 fail("Bit F157 is not 0.\n");
382 if (version == 4 && length < 14) {
383 fail("Version 4 expects a length of >= 14, got %u\n", length);
384 return;
387 if (edid_size) {
388 if (version > cta.avi_version)
389 warn("AVI version is %u, but EDID indicates support for %u only.\n",
390 version, cta.avi_version);
391 if (version == 4 && length > cta.avi_v4_length)
392 warn("AVI version 4 length is %u, but EDID indicates support for %u only.\n",
393 length, cta.avi_v4_length);
396 char buf[32];
397 unsigned vic_fps = 0;
398 unsigned char vic = x[4];
399 unsigned char rid = length >= 14 ? x[15] & 0x3f : 0;
401 sprintf(buf, "VIC %3u", vic);
402 const struct timings *t = find_vic_id(vic);
403 if (t) {
404 print_timings(" ", t, buf);
405 vic_fps = calc_fps(t);
406 } else if (vic) {
407 printf(" VIC: %d (0x%02x)\n", vic, vic);
408 fail("Unknown VIC code.\n");
411 static const char *Y_map[] = {
412 "RGB",
413 "YCbCr 4:2:2",
414 "YCbCr 4:4:4",
415 "YCbCr 4:2:0",
416 "Reserved (4)",
417 "Reserved (5)",
418 "Reserved (6)",
419 "IDO-Defined",
421 unsigned char y = x[1] >> 5;
422 unsigned char v;
424 printf(" Y: Color Component Sample Format: %s\n", Y_map[y]);
425 if (y == 7 && version == 2)
426 warn("Y == 7 but AVI Version == 2.\n");
427 if (edid_size) {
428 if ((y == 1 && !cta.has_ycbcr422) ||
429 (y == 2 && !cta.has_ycbcr444) ||
430 (y == 3 && !cta.has_ycbcr420))
431 fail("Y == %s, but this capability is not enabled in the EDID.\n", Y_map[y]);
434 printf(" A: Active Format Information Present: %s\n",
435 ((x[1] >> 4) & 1) ? "Yes" : "No");
437 static const char *B_map[] = {
438 "Bar Data not present",
439 "Vertical Bar Info present",
440 "Horizontal Bar Info present",
441 "Vertical and Horizontal Bar Info present"
443 printf(" B: Bar Data Present: %s\n", B_map[(x[1] >> 2) & 3]);
445 static const char *S_map[] = {
446 "No Data",
447 "Composed for an overscanned display",
448 "Composed for an underscanned display",
449 "Reserved"
451 printf(" S: Scan Information: %s\n", S_map[x[1] & 3]);
453 static const char *C_map[] = {
454 "No Data",
455 "SMPTE ST 170",
456 "Rec. ITU-R BT.709",
457 "Extended Colorimetry Information Valid"
459 printf(" C: Colorimetry: %s\n", C_map[x[2] >> 6]);
461 static const char *M_map[] = {
462 "No Data",
463 "4:3",
464 "16:9",
465 "Reserved"
467 v = (x[2] >> 4) & 3;
468 printf(" M: Picture Aspect Ratio: %s\n", M_map[v]);
469 if ((vic || rid) && v)
470 warn("If a VID or RID is specified, then set M to 0.\n");
471 printf(" R: Active Portion Aspect Ratio: %d\n", x[2] & 0xf);
473 static const char *ITC_map[] = {
474 "No Data",
475 "IT Content (CN is valid)"
477 printf(" ITC: IT Content: %s\n", ITC_map[x[3] >> 7]);
479 static const char *EC_map[] = {
480 "xvYCC601",
481 "xvYCC709",
482 "sYCC601",
483 "opYCC601",
484 "opRGB",
485 "Rec. ITU-R BR.2020 YcCbcCrc",
486 "Rec. ITU-R BR.2020 RGB or YCbCr",
487 "Additional Colorimetry Extension Information Valid"
489 printf(" EC: Extended Colorimetry: %s\n", EC_map[(x[3] >> 4) & 7]);
491 static const char *Q_map[] = {
492 "Default",
493 "Limited Range",
494 "Full Range",
495 "Reserved"
497 printf(" Q: RGB Quantization Range: %s\n", Q_map[(x[3] >> 2) & 3]);
499 static const char *SC_map[] = {
500 "No Known non-uniform scaling",
501 "Picture has been scaled horizontally",
502 "Picture has been scaled vertically",
503 "Picture has been scaled horizontally and vertically"
505 printf(" SC: Non-Uniform Picture Scaling: %s\n", SC_map[x[3] & 3]);
507 static const char *YQ_map[] = {
508 "Limited Range",
509 "Full Range",
510 "Reserved",
511 "Reserved"
513 printf(" YQ: YCC Quantization Range: %s\n", YQ_map[x[5] >> 6]);
515 static const char *CN_map[] = {
516 "Graphics",
517 "Photo",
518 "Cinema",
519 "Game"
521 printf(" CN: IT Content Type: %s\n", CN_map[(x[5] >> 4) & 3]);
522 unsigned char pr = x[5] & 0xf;
523 printf(" PR: Pixel Data Repetition Count: %d\n", pr);
525 const unsigned short pr_2 = 2;
526 const unsigned short pr_1_10 = 0x3ff;
527 const unsigned short pr_1_2 = 3;
528 const unsigned short pr_1_2_4 = 0xb;
529 static const unsigned short vic_valid_pr[] = {
530 // VIC 0-7
531 0, 0, 0, 0, 0, 0, pr_2, pr_2,
532 // VIC 8-15
533 pr_2, pr_2, pr_1_10, pr_1_10, pr_1_10, pr_1_10, pr_1_2, pr_1_2,
534 // VIC 16-23
535 0, 0, 0, 0, 0, pr_2, pr_2, pr_2,
536 // VIC 24-31
537 pr_2, pr_1_10, pr_1_10, pr_1_10, pr_1_10, pr_1_2, pr_1_2, 0,
538 // VIC 32-39
539 0, 0, 0, pr_1_2_4, pr_1_2_4, pr_1_2_4, pr_1_2_4, 0,
540 // VIC 40-47
541 0, 0, 0, 0, pr_2, pr_2, 0, 0,
542 // VIC 48-55
543 0, 0, pr_2, pr_2, 0, 0, pr_2, pr_2,
544 // VIC 56-59
545 0, 0, pr_2, pr_2
548 if (pr >= 10)
549 fail("PR >= 10 is a reserved value.\n");
550 else if (pr && (vic >= ARRAY_SIZE(vic_valid_pr) ||
551 !(vic_valid_pr[vic] & (1 << pr))))
552 fail("PR %u is not supported by VIC %u.\n", pr, vic);
554 printf(" Line Number of End of Top Bar: %d\n", (x[7] << 8) | x[6]);
555 printf(" Line Number of Start of Bottom Bar: %d\n", (x[9] << 8) | x[8]);
556 printf(" Pixel Number of End of Left Bar: %d\n", (x[11] << 8) | x[10]);
557 printf(" Pixel Number of Start of Right Bar: %d\n", (x[13] << 8) | x[12]);
558 if (length <= 13)
559 return;
561 static const char *ACE_map[] = {
562 "SMPTE ST 2113 P3D65 RGB",
563 "SMPTE ST 2113 P3DCI RGB",
564 "Rec. ITU-R BT.2100 ICtCp",
565 "sRGB",
566 "defaultRGB",
567 "Reserved (5)",
568 "Reserved (6)",
569 "Reserved (7)",
570 "Reserved (8)",
571 "Reserved (9)",
572 "Reserved (10)",
573 "Reserved (11)",
574 "Reserved (12)",
575 "Reserved (13)",
576 "Reserved (14)",
577 "Reserved (15)"
579 printf(" ACE: Additional Colorimetry Extension: %s\n", ACE_map[x[14] >> 4]);
580 if (length <= 14) {
581 if (x[14] & 0xf) {
582 printf(" FR: %d\n", x[14] & 0xf);
583 fail("InfoFrame length is 14, but FR != 0.\n");
585 return;
588 unsigned fr = ((x[15] & 0x40) >> 2) | (x[14] >> 4);
590 printf(" RID/FR: %u/%u\n", rid, fr);
591 if (vic && rid)
592 fail("Both a RID and a VIC were specified.\n");
594 if (!rid && !fr)
595 return;
597 if (rid && !fr) {
598 fail("RID is set, but FR is 0.\n");
599 return;
602 static const unsigned fr_rate_values[] = {
603 /* FR 0-7 */
604 0, 24, 24, 25, 30, 30, 48, 48,
605 /* FR 8-15 */
606 50, 60, 60, 100, 120, 120, 144, 144,
607 /* FR 16-23 */
608 200, 240, 240, 300, 360, 360, 400, 480,
609 /* FR 24 */
612 static const bool fr_ntsc[] = {
613 /* FR 0-7 */
614 0, 1, 0, 0, 1, 0, 1, 0,
615 /* FR 8-15 */
616 0, 1, 0, 0, 1, 0, 1, 0,
617 /* FR 16-23 */
618 0, 1, 0, 0, 1, 0, 0, 1,
619 /* FR 24 */
623 if (fr >= ARRAY_SIZE(fr_rate_values)) {
624 fail("Unknown FR %u.\n", fr);
625 return;
627 unsigned fps = fr_rate_values[fr];
628 bool ntsc = fr_ntsc[fr];
630 printf(" Frame Rate: %u%s\n", fps, ntsc ? "/1.001" : "");
632 if (vic) {
633 if (vic_fps != fps)
634 warn("VIC %u is %u fps, while FR indicates %u fps.\n",
635 x[4], vic_fps, fps);
636 return;
639 if (!rid)
640 return;
642 const struct cta_rid *crid = find_rid(rid);
644 if (!crid) {
645 fail("Unknown RID %u.\n", rid);
646 return;
649 unsigned char rid_vic = rid_fps_to_vic(rid, fps);
650 if (rid_vic) {
651 sprintf(buf, "VIC %3u", rid_vic);
652 const struct timings *t = find_vic_id(rid_vic);
653 print_timings(" ", t, buf);
654 warn("RID/FR %u/%u maps to VIC %d.\n", rid, fr, rid_vic);
655 } else {
656 sprintf(buf, "RID/FR %u/%u", rid, fr);
657 timings t = calc_ovt_mode(crid->hact, crid->vact,
658 crid->hratio, crid->vratio, fps);
659 print_timings("", &t, buf, "", false, false, ntsc);
663 void edid_state::parse_if_spd(const unsigned char *x, unsigned size)
665 data_block = "Source Product Description InfoFrame";
667 if (parse_if_hdr(x, size))
668 return;
670 if (x[1] != 1) {
671 fail("Invalid version %d\n", x[1]);
672 return;
674 if (x[2] < 25) {
675 fail("Expected InfoFrame length of 25, got %d.\n", x[2]);
676 return;
679 // After this x[1] will refer to Data Byte 1
680 x += 2;
682 for (unsigned i = 1; i <= 24; i++) {
683 if (x[i] & 0x80) {
684 fail("SPD contains ASCII character with bit 7 set.\n");
687 char vendor[9] = {};
688 memcpy(vendor, x + 1, 8);
689 printf(" Vendor Name: '%s'\n", vendor);
690 unsigned len = strlen(vendor);
691 if (!memchk(x + 1 + len, 8 - len))
692 fail("Vendor name has trailing non-zero characters.\n");
694 char product[17] = {};
695 memcpy(product, x + 9, 16);
696 printf(" Product Description: '%s'\n", product);
697 len = strlen(product);
698 if (!memchk(x + 9 + len, 16 - len))
699 fail("Product name has trailing non-zero characters.\n");
701 if (x[25] >= 0x0e) {
702 printf(" Source Information: %d (Reserved)\n", x[25]);
703 fail("Source Information value %d is reserved.\n", x[25]);
704 } else {
705 static const char *SI_map[] = {
706 "Unknown",
707 "Digital STB",
708 "DVD player",
709 "D-VHS",
710 "HDD Videorecorder",
711 "DVC",
712 "DSC",
713 "Video CD",
714 "Game",
715 "PC general",
716 "Blu-Ray Disck (DB)",
717 "Super Audio CD",
718 "HD DVD",
719 "PMP"
721 printf(" Source Information: %s\n", SI_map[x[25]]);
725 void edid_state::parse_if_audio(const unsigned char *x, unsigned size)
727 data_block = "Audio InfoFrame";
729 if (parse_if_hdr(x, size))
730 return;
732 if (x[1] != 1) {
733 fail("Invalid version %d\n", x[1]);
734 return;
736 if (x[2] < 10) {
737 fail("Expected InfoFrame length of 10, got %d.\n", x[2]);
738 return;
741 // After this x[1] will refer to Data Byte 1
742 x += 2;
744 if (x[1] & 0x08)
745 fail("Bit F13 is not 0.\n");
746 if (x[2] & 0xe0)
747 fail("Bits F27-F25 are not 0.\n");
748 if (x[3] & 0xe0)
749 fail("Bits F37-F35 are not 0.\n");
750 if (x[5] & 0x04)
751 fail("Bit F52 is not 0.\n");
752 if (x[4] <= 0x31 && !memchk(x + 6, 5))
753 fail("Bits F107-F60 are not 0.\n");
754 else if (x[4] == 0xfe && (x[10] || x[9] || (x[8] & 0xf8)))
755 fail("Bits F107-F90 and/or F87-F83 are not 0.\n");
756 else if (x[4] == 0xff && x[10])
757 fail("Bits F107-F100 are not 0.\n");
759 static const char *CT_map[] = {
760 "Refer to Stream Header",
761 "L-PCM",
762 "AC-3",
763 "MPEG-1",
764 "MP3",
765 "MPEG2",
766 "AAC LC",
767 "DTS",
768 "ATRAC",
769 "DSD",
770 "Enhanced AC-3",
771 "DTS-(U)HD",
772 "MAT",
773 "DST",
774 "WMA Pro",
775 "Refer to Audio Coding Extension Type (CXT) Field"
777 printf(" CT: Audio Coding Type: %s\n", CT_map[x[1] >> 4]);
778 if (x[1] & 7)
779 printf(" CC: Audio Channel Count: %d\n", (x[1] & 7) + 1);
780 else
781 printf(" CC: Audio Channel Count: Refer to Stream Header\n");
783 static const char *SF_map[] = {
784 "Refer to Stream Header",
785 "32 kHz",
786 "44.1 kHz (CD)",
787 "48 kHz",
788 "88.2 kHz",
789 "96 kHz",
790 "176.4 kHz",
791 "192 kHz"
793 printf(" SF: Sampling Frequency: %s\n", SF_map[(x[2] >> 2) & 7]);
795 static const char *SS_map[] = {
796 "Refer to Stream Header",
797 "16 bit",
798 "20 bit",
799 "24 bit"
801 printf(" SS: Bits/Sample: %s\n", SS_map[x[2] & 3]);
803 static const char *CXT_map[] = {
804 "Refer to Audio Coding Type (CT) Field",
805 "Not in Use (1)",
806 "Not in Use (2)",
807 "Not in Use (3)",
808 "MPEG-4 HE AAC",
809 "MPEG-4 HE AAC v2",
810 "MPEG-4 AAC LC",
811 "DRA",
812 "MPEG-4 HE AAC + MPEG Surround",
813 "Reserved (9)",
814 "MPEG-4 AAC LC + MPEG Surround",
815 "MPEG-H 3D Audio",
816 "AC-4",
817 "L-PCM 3D Audio",
818 "Auro-Cx",
819 "MPEG-D USAC"
821 if ((x[3] & 0x1f) < ARRAY_SIZE(CXT_map))
822 printf(" CXT: Audio Coding Extension Type: %s\n", CXT_map[x[3] & 0x1f]);
823 else
824 printf(" CXT: Audio Coding Extension Type: Reserved (%d)\n", x[3] & 0x1f);
825 if ((x[3] & 0x1f) == 9 || (x[3] & 0x1f) >= ARRAY_SIZE(CXT_map))
826 fail("CXT: Reserved value.\n");
828 static const char *CA_map[] = {
829 "FR/FL",
830 "LFE1, FR/FL",
831 "FC, FR/FL",
832 "FC, LFE1, FR/FL",
833 "BC, FR/FL",
834 "BC, LFE1, FR/FL",
835 "BC, FC, FR/FL",
836 "BC, FC, LFE1, FR/FL",
837 "RS/LS, FR/FL",
838 "RS/LS, LFE1, FR/FL",
839 "RS/LS, FC, FR/FL",
840 "RS/LS, FC, LFE1, FR/FL",
841 "BC, RS/LS, FR/FL",
842 "BC, RS/LS, LFE1, FR/FL",
843 "BC, RS/LS, FC, FR/FL",
844 "BC, RS/LS, FC, LFE1, FR/FL",
845 "BR/BL, RS/LS, FR/FL",
846 "BR/BL, RS/LS, LFE1, FR/FL",
847 "BR/BL, RS/LS, FC, FR/FL",
848 "BR/BL, RS/LS, FC, LFE1, FR/FL",
849 "FRc/FLc, FR/FL",
850 "FRc/FLc, LFE1, FR/FL",
851 "FRc/FLc, FC, FR/FL",
852 "FRc/FLc, FC, LFE1, FR/FL",
853 "FRc/FLc, BC, FR/FL",
854 "FRc/FLc, BC, LFE1, FR/FL",
855 "FRc/FLc, BC, FC, FR/FL",
856 "FRc/FLc, BC, FC, LFE1, FR/FL",
857 "FRc/FLc, RS/LS, FR/FL",
858 "FRc/FLc, RS/LS, LFE1, FR/FL",
859 "FRc/FLc, RS/LS, FC, FR/FL",
860 "FRc/FLc, RS/LS, FC, LFE1, FR/FL",
861 "TpFC, RS/LS, FC, FR/FL",
862 "TpFC, RS/LS, FC, LFE1, FR/FL",
863 "TpC, RS/LS, FC, FR/FL",
864 "TpC, RS/LS, FC, LFE1, FR/FL",
865 "TpFR/TpFL, RS/LS, FR/FL",
866 "TpFR/TpFL, RS/LS, LFE1, FR/FL",
867 "FRw/FLw, RS/LS, FR/FL",
868 "FRw/FLw, RS/LS, LFE1, FR/FL",
869 "TpC, BC, RS/LS, FC, FR/FL",
870 "TpC, BC, RS/LS, FC, LFE1, FR/FL",
871 "TpFC, BC, RS/LS, FC, FR/FL",
872 "TpFC, BC, RS/LS, FC, FR/FL",
873 "TpC, TpFC, RS/LS, FC, FR/FL",
874 "TpC, TpFC, RS/LS, FC, FR/FL",
875 "TpFR/TpFL, RS/LS, FC, FR/FL",
876 "TpFR/TpFL, RS/LS, FC, FR/FL",
877 "FRw/FLw, RS/LS, FC, FR/FL",
878 "FRw/FLw, RS/LS, FC, FR/FL"
880 if (x[4] < ARRAY_SIZE(CA_map))
881 printf(" CA: Channel Allocation: %s\n", CA_map[x[4]]);
882 else if (x[4] < 0xfe) {
883 printf(" CA: Channel Allocation: Reserved (%d, 0x%02x)\n", x[4], x[4]);
884 fail("CA: Reserved value.\n");
886 else if (x[4] == 0xfe)
887 printf(" CA: Channel Allocation: According to the Speaker Mask\n");
888 else
889 printf(" CA: Channel Allocation: According to Channel Index\n");
890 printf(" LSV: Level Shift Value: %d dB\n", (x[5] >> 3) & 0xf);
891 printf(" DM_INH: Allow the Down Mixed Stereo Output: %s\n",
892 (x[5] & 0x80) ? "Prohibited" : "Yes");
894 static const char *LFEPBL_map[] = {
895 "Unknown or refer to other information",
896 "0 dB",
897 "+10 dB",
898 "Reserved"
900 printf(" LFEPBL: LFE Playback Level compared to other channels: %s\n", LFEPBL_map[x[5] & 3]);
901 if ((x[5] & 3) == 3)
902 fail("LFEPBL: Reserved value.\n");
904 if (x[4] < 0xfe)
905 return;
907 if (x[4] == 0xfe) {
908 if (x[6] & 0x40)
909 warn("F66 is not 0, the use of this bit is deprecated.\n");
910 if (x[8] & 0x08)
911 warn("F83 is not 0, the use of this bit is deprecated.\n");
912 printf(" SPM: Speaker Mask:\n");
914 unsigned spm = (x[8] << 16) | (x[7] << 8) | x[6];
916 for (unsigned i = 0; cta_speaker_map[i]; i++) {
917 if ((spm >> i) & 1)
918 printf(" %s\n", cta_speaker_map[i]);
920 return;
923 // CA == 0xff
924 printf(" CID: Channel Index: ");
926 unsigned cid = (x[9] << 24) | (x[8] << 16) | (x[7] << 8) | x[6];
927 bool first = true;
929 for (unsigned i = 0; i < 32; i++) {
930 if ((cid >> i) & 1) {
931 if (!first)
932 printf(" ,");
933 first = false;
934 printf("%u", i);
937 printf("\n");
940 void edid_state::parse_if_mpeg_source(const unsigned char *x, unsigned size)
942 data_block = "MPEG Source InfoFrame";
944 warn("The use of the %s is not recommended.\n", data_block.c_str());
946 if (parse_if_hdr(x, size))
947 return;
949 if (x[1] != 1) {
950 fail("Invalid version %d\n", x[1]);
951 return;
953 if (x[2] < 10) {
954 fail("Expected InfoFrame length of 10, got %d.\n", x[2]);
955 return;
958 // After this x[1] will refer to Data Byte 1
959 x += 2;
961 unsigned mb = (x[4] << 24) | (x[3] << 16) | (x[2] << 8) | x[1];
963 if (mb)
964 printf(" MB: MPEG Bit Rate: %u Hz\n", mb);
965 else
966 printf(" MB: MPEG Bit Rate: Unknown/Does Not Apply\n");
968 static const char *MF_map[] = {
969 "Unknown (No Data)",
970 "I Picture",
971 "B Picture",
972 "P Picture"
974 printf(" MF: MPEG Frame: %s\n", MF_map[x[5] & 3]);
975 printf(" FR: Field Repeat: %s\n", (x[5] & 0x10) ? "Repeated Field" : "New Field (Picture)");
976 if (x[5] & 0xec)
977 fail("Bits F57-F55 and/or F53-F52 are not 0.\n");
978 if (x[6] || x[7] || x[8] || x[9] || x[10])
979 fail("Bits F100-F60 are not 0.\n");
982 void edid_state::parse_if_ntsc_vbi(const unsigned char *x, unsigned size)
984 data_block = "NTSC VBI InfoFrame";
986 if (parse_if_hdr(x, size))
987 return;
989 int len = x[2];
991 if (x[1] != 1) {
992 fail("Invalid version %d\n", x[1]);
993 return;
996 // After this x[1] will refer to Data Byte 1
997 x += 2;
999 // See SCTE 127, Table 2 for more details
1000 hex_block(" PES_data_field: ", x + 1, len, false, len);
1003 void edid_state::parse_if_drm(const unsigned char *x, unsigned size)
1005 unsigned length = x[2];
1007 data_block = "Dynamic Range and Mastering InfoFrame";
1009 if (parse_if_hdr(x, size))
1010 return;
1012 if (x[1] != 1) {
1013 fail("Invalid version %d\n", x[1]);
1014 return;
1017 // After this x[1] will refer to Data Byte 1
1018 x += 2;
1020 if (x[1] & 0xf8)
1021 fail("Bits F17-F13 are not 0.\n");
1023 static const char *TF_map[] = {
1024 "Traditional Gamma - SDR Luminance Range",
1025 "Traditional Gamma - HDR Luminance Range",
1026 "Perceptual Quantization (PQ) based on SMPTE ST 2084",
1027 "Hybrid Log-Gamma (HLG) based on Rec. ITU-R BT.2100",
1028 "Reserved (4)",
1029 "Reserved (5)",
1030 "Reserved (6)",
1031 "Reserved (7)"
1033 printf("Transfer Function: %s\n",
1034 TF_map[x[1] & 7]);
1035 if (length < 2)
1036 return;
1038 if (x[2] & 0xf8)
1039 fail("Bits F27-F23 are not 0.\n");
1040 if (x[2] & 7) {
1041 printf("Static Metadata Descriptor ID: Reserved (%d)\n", x[2] & 7);
1042 if (!memchk(x + 3, length - 2))
1043 fail("Trailing non-zero bytes.\n");
1044 return;
1046 printf("Static Metadata Descriptor ID: Type 1\n");
1047 if (length < 26) {
1048 fail("Expected a length of 26, got %d.\n", length);
1049 return;
1051 if (!memchk(x + 3, 12)) {
1052 printf(" Display Primary 0: (%.5f, %.5f)\n", chrom2d(x + 3), chrom2d(x + 5));
1053 printf(" Display Primary 1: (%.5f, %.5f)\n", chrom2d(x + 7), chrom2d(x + 7));
1054 printf(" Display Primary 2: (%.5f, %.5f)\n", chrom2d(x + 11), chrom2d(x + 13));
1056 if (!memchk(x + 15, 4)) {
1057 printf(" White Point: (%.5f, %.5f)\n", chrom2d(x + 15), chrom2d(x + 17));
1059 if (!memchk(x + 19, 2)) {
1060 printf(" Max Display Mastering Luminance: %u cd/m^2\n",
1061 x[19] + (x[20] << 8));
1063 if (!memchk(x + 21, 2)) {
1064 printf(" Min Display Mastering Luminance: %f cd/m^2\n",
1065 (x[21] + (x[22] << 8)) * 0.0001);
1067 if (!memchk(x + 23, 2)) {
1068 printf(" Maximum Content Light Level (MaxCLL): %u cd/m^2\n",
1069 x[23] + (x[24] << 8));
1071 if (!memchk(x + 25, 2)) {
1072 printf(" Maximum Frame-Average Light Level (MaxFALL): %u cd/m^2\n",
1073 x[25] + (x[26] << 8));