diff --git a/cta.c b/cta.c index e3c5290..a8e6660 100644 --- a/cta.c +++ b/cta.c @@ -84,6 +84,45 @@ parse_video_block(struct di_edid_cta *cta, struct di_cta_video_block *video, return true; } +static bool +parse_video_cap_block(struct di_edid_cta *cta, + struct di_cta_video_cap_block *video_cap, + const uint8_t *data, size_t size) +{ + if (size < 1) { + add_failure(cta, + "Video Capability Data Block: Empty Data Block with length %u.", + size); + return false; + } + + video_cap->selectable_ycc_quantization_range = has_bit(data[0], 7); + video_cap->selectable_rgb_quantization_range = has_bit(data[0], 6); + video_cap->pt_over_underscan = get_bit_range(data[0], 5, 4); + video_cap->it_over_underscan = get_bit_range(data[0], 3, 2); + video_cap->ce_over_underscan = get_bit_range(data[0], 1, 0); + + if (!video_cap->selectable_rgb_quantization_range && cta->revision >= 3) + add_failure(cta, + "Video Capability Data Block: Set Selectable RGB Quantization to avoid interop issues."); + /* TODO: add failure if selectable_ycc_quantization_range is unset, + * the sink supports YCbCr formats and the revision is 3+ */ + + switch (video_cap->it_over_underscan) { + case DI_CTA_VIDEO_CAP_ALWAYS_OVERSCAN: + if (cta->flags.it_underscan) + add_failure(cta, "Video Capability Data Block: IT video formats are always overscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to underscanned."); + break; + case DI_CTA_VIDEO_CAP_ALWAYS_UNDERSCAN: + if (!cta->flags.it_underscan) + add_failure(cta, "Video Capability Data Block: IT video formats are always underscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to overscanned."); + default: + break; + } + + return true; +} + static bool parse_colorimetry_block(struct di_edid_cta *cta, struct di_cta_colorimetry_block *colorimetry, @@ -237,6 +276,9 @@ parse_data_block(struct di_edid_cta *cta, uint8_t raw_tag, const uint8_t *data, switch (extended_tag) { case 0: tag = DI_CTA_DATA_BLOCK_VIDEO_CAP; + if (!parse_video_cap_block(cta, &data_block->video_cap, + data, size)) + goto skip; break; case 2: tag = DI_CTA_DATA_BLOCK_VESA_DISPLAY_DEVICE; @@ -477,6 +519,15 @@ di_cta_data_block_get_hdr_static_metadata(const struct di_cta_data_block *block) return &block->hdr_static_metadata.base; } +const struct di_cta_video_cap_block * +di_cta_data_block_get_video_cap(const struct di_cta_data_block *block) +{ + if (block->tag != DI_CTA_DATA_BLOCK_VIDEO_CAP) { + return NULL; + } + return &block->video_cap; +} + const struct di_edid_detailed_timing_def *const * di_edid_cta_get_detailed_timing_defs(const struct di_edid_cta *cta) { diff --git a/di-edid-decode.c b/di-edid-decode.c index 58fe679..310b8ba 100644 --- a/di-edid-decode.c +++ b/di-edid-decode.c @@ -594,6 +594,23 @@ cta_data_block_tag_name(enum di_cta_data_block_tag tag) return "Unknown CTA-861 Data Block"; } +static const char * +video_cap_over_underscan_name(enum di_cta_video_cap_over_underscan over_underscan, + const char *unknown) +{ + switch (over_underscan) { + case DI_CTA_VIDEO_CAP_UNKNOWN_OVER_UNDERSCAN: + return unknown; + case DI_CTA_VIDEO_CAP_ALWAYS_OVERSCAN: + return "Always Overscanned"; + case DI_CTA_VIDEO_CAP_ALWAYS_UNDERSCAN: + return "Always Underscanned"; + case DI_CTA_VIDEO_CAP_BOTH_OVER_UNDERSCAN: + return "Supports both over- and underscan"; + } + abort(); +} + static void print_cta(const struct di_edid_cta *cta) { @@ -602,6 +619,7 @@ print_cta(const struct di_edid_cta *cta) const struct di_cta_data_block *data_block; enum di_cta_data_block_tag data_block_tag; const struct di_cta_svd *const *svds; + const struct di_cta_video_cap_block *video_cap; const struct di_cta_colorimetry_block *colorimetry; const struct di_cta_hdr_static_metadata_block *hdr_static_metadata; size_t i; @@ -636,6 +654,24 @@ print_cta(const struct di_edid_cta *cta) svds = di_cta_data_block_get_svds(data_block); printf_cta_svds(svds); break; + case DI_CTA_DATA_BLOCK_VIDEO_CAP: + video_cap = di_cta_data_block_get_video_cap(data_block); + printf(" YCbCr quantization: %s\n", + video_cap->selectable_ycc_quantization_range ? + "Selectable (via AVI YQ)" : "No Data"); + printf(" RGB quantization: %s\n", + video_cap->selectable_ycc_quantization_range ? + "Selectable (via AVI Q)" : "No Data"); + printf(" PT scan behavior: %s\n", + video_cap_over_underscan_name(video_cap->pt_over_underscan, + "No Data")); + printf(" IT scan behavior: %s\n", + video_cap_over_underscan_name(video_cap->it_over_underscan, + "IT video formats not supported")); + printf(" CE scan behavior: %s\n", + video_cap_over_underscan_name(video_cap->ce_over_underscan, + "CE video formats not supported")); + break; case DI_CTA_DATA_BLOCK_COLORIMETRY: colorimetry = di_cta_data_block_get_colorimetry(data_block); if (colorimetry->xvycc_601) diff --git a/include/cta.h b/include/cta.h index 563ce08..e5182ee 100644 --- a/include/cta.h +++ b/include/cta.h @@ -59,6 +59,8 @@ struct di_cta_data_block { /* Used for DI_CTA_DATA_BLOCK_VIDEO */ struct di_cta_video_block video; + /* Used for DI_CTA_DATA_BLOCK_VIDEO_CAP */ + struct di_cta_video_cap_block video_cap; /* Used for DI_CTA_DATA_BLOCK_COLORIMETRY */ struct di_cta_colorimetry_block colorimetry; /* Used for DI_CTA_DATA_BLOCK_HDR_STATIC_METADATA */ diff --git a/include/libdisplay-info/cta.h b/include/libdisplay-info/cta.h index 19a15a9..2e3f1e2 100644 --- a/include/libdisplay-info/cta.h +++ b/include/libdisplay-info/cta.h @@ -117,6 +117,45 @@ enum di_cta_data_block_tag { enum di_cta_data_block_tag di_cta_data_block_get_tag(const struct di_cta_data_block *block); +/** + * Over- and underscan capability. + */ +enum di_cta_video_cap_over_underscan { + /* No data */ + DI_CTA_VIDEO_CAP_UNKNOWN_OVER_UNDERSCAN = 0x00, + /* Always overscanned */ + DI_CTA_VIDEO_CAP_ALWAYS_OVERSCAN = 0x01, + /* Always underscanned */ + DI_CTA_VIDEO_CAP_ALWAYS_UNDERSCAN = 0x02, + /* Supports both over- and underscan */ + DI_CTA_VIDEO_CAP_BOTH_OVER_UNDERSCAN = 0x03, +}; + +/** + * Video capability data block (VCDB), defined in section 7.5.6. + */ +struct di_cta_video_cap_block { + /* If set to true, YCC quantization range is selectable (via AVI YQ). */ + bool selectable_ycc_quantization_range; + /* If set to true, RGB quantization range is selectable (via AVI Q). */ + bool selectable_rgb_quantization_range; + /* Overscan/underscan behavior for PT video formats (if set to unknown, + * use the IT/CE behavior) */ + enum di_cta_video_cap_over_underscan pt_over_underscan; + /* Overscan/underscan behavior for IT video formats */ + enum di_cta_video_cap_over_underscan it_over_underscan; + /* Overscan/underscan behavior for CE video formats */ + enum di_cta_video_cap_over_underscan ce_over_underscan; +}; + +/** + * Get the video capabilities from a CTA data block. + * + * Returns NULL if the data block tag is not DI_CTA_DATA_BLOCK_VIDEO_CAP. + */ +const struct di_cta_video_cap_block * +di_cta_data_block_get_video_cap(const struct di_cta_data_block *block); + /** * CTA colorimetry data block, defined in section 7.5.5. */ diff --git a/test/data/hp-5dq99aa-hdmi.diff b/test/data/hp-5dq99aa-hdmi.diff index e72cb61..74af4a9 100644 --- a/test/data/hp-5dq99aa-hdmi.diff +++ b/test/data/hp-5dq99aa-hdmi.diff @@ -23,7 +23,7 @@ Detailed Timing Descriptors: DTD 1: 2560x1440 59.950550 Hz 16:9 88.787 kHz 241.500000 MHz (597 mm x 339 mm) Hfront 48 Hsync 32 Hback 80 Hpol P -@@ -51,32 +51,16 @@ +@@ -51,32 +51,21 @@ Supports YCbCr 4:2:2 Native detailed modes: 1 Video Data Block: @@ -52,11 +52,11 @@ + VIC 17 + VIC 1 Video Capability Data Block: -- YCbCr quantization: No Data -- RGB quantization: No Data -- PT scan behavior: Always Underscanned -- IT scan behavior: Always Underscanned -- CE scan behavior: Supports both over- and underscan + YCbCr quantization: No Data + RGB quantization: No Data + PT scan behavior: Always Underscanned + IT scan behavior: Always Underscanned + CE scan behavior: Supports both over- and underscan - Vendor-Specific Data Block (AMD), OUI 00-00-1A: - Version: 1.1 - Minimum Refresh Rate: 46 Hz @@ -65,7 +65,7 @@ Colorimetry Data Block: BT2020cYCC BT2020YCC -@@ -104,20 +88,8 @@ +@@ -104,20 +93,12 @@ DTD 5: 1920x1080 74.972503 Hz 16:9 83.894 kHz 174.500000 MHz (597 mm x 339 mm) Hfront 48 Hsync 32 Hback 80 Hpol P Vfront 3 Vsync 5 Vback 31 Vpol N @@ -81,10 +81,9 @@ - Colorimetry Data Block: Set the sRGB colorimetry bit to avoid interop issues. - Display Product Serial Number is set, so the Serial Number in the Base EDID should be 0. - --Failures: + Failures: + + Block 1, CTA-861 Extension Block: + Video Capability Data Block: Set Selectable RGB Quantization to avoid interop issues. - --Block 1, CTA-861 Extension Block: -- Video Capability Data Block: Set Selectable RGB Quantization to avoid interop issues. -- --EDID conformity: FAIL -+EDID conformity: PASS + EDID conformity: FAIL