From f2c1b01bd29ca341e0adb3ab76e5a67b37704fda Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Wed, 5 Jul 2023 14:46:18 +0300 Subject: [PATCH] info: add di_info_get_hdr_static_metadata() The low-level struct di_cta_hdr_static_metadata_block is essentially duplicated in struct di_hdr_static_metadata to make the high-level API independent of low-level API headers. It's also simpler in form, while new fields can still be added in the end while maintaining ABI backward compatibility. If new sources for HDR static metadata appear, they can be parsed into this same structure in the future when compatible. Wayland compositors will be interested in this. Signed-off-by: Pekka Paalanen --- include/info.h | 1 + include/libdisplay-info/info.h | 43 +++++++++++++++++ info.c | 87 ++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) diff --git a/include/info.h b/include/info.h index e906a81..d3586df 100644 --- a/include/info.h +++ b/include/info.h @@ -12,6 +12,7 @@ * struct di_info. These are exposed by the high-level API only. */ struct di_derived_info { + struct di_hdr_static_metadata hdr_static_metadata; struct di_color_primaries color_primaries; }; diff --git a/include/libdisplay-info/info.h b/include/libdisplay-info/info.h index 954e2cd..4361816 100644 --- a/include/libdisplay-info/info.h +++ b/include/libdisplay-info/info.h @@ -103,6 +103,49 @@ di_info_get_model(const struct di_info *info); char * di_info_get_serial(const struct di_info *info); +/** + * Display HDR static metadata + */ +struct di_hdr_static_metadata { + /* Desired content max luminance (cd/m²), zero if unset */ + float desired_content_max_luminance; + /* Desired content max frame-average luminance (cd/m²), zero if unset */ + float desired_content_max_frame_avg_luminance; + /* Desired content min luminance (cd/m²), zero if unset */ + float desired_content_min_luminance; + + /* Supported metadata types: */ + + /* Static Metadata Type 1 */ + bool type1; + + /* Supported EOFTs: */ + + /* Traditional gamma - SDR luminance range */ + bool traditional_sdr; + /* Traditional gamma - HDR luminance range */ + bool traditional_hdr; + /* Perceptual Quantization (PQ) based on SMPTE ST 2084 */ + bool pq; + /* Hybrid Log-Gamma (HLG) based on Rec. ITU-R BT.2100 */ + bool hlg; +}; + +/** + * Get HDR static metadata support information as defined in ANSI/CTA-861-H + * as HDR Static Metadata Data Block. + * + * The returned pointer is owned by the struct di_info passed in. It remains + * valid only as long as the di_info exists, and must not be freed by the + * caller. + * + * This function does not return NULL. When HDR static metadata does not exist, + * all luminance fields are zero and only traditional_sdr is flagged as + * supported. + */ +const struct di_hdr_static_metadata * +di_info_get_hdr_static_metadata(const struct di_info *info); + /** CIE 1931 2-degree observer chromaticity coordinates */ struct di_chromaticity_cie1931 { float x; diff --git a/info.c b/info.c index ea69630..e9f8fc3 100644 --- a/info.c +++ b/info.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "edid.h" #include "info.h" @@ -11,6 +12,85 @@ const char * pnp_id_table(const char *key); +static bool +di_cta_data_block_allowed_multiple(enum di_cta_data_block_tag tag) +{ + /* See CTA-861-H, 7.6 Multiple Instances of Data Blocks. */ + switch (tag) { + case DI_CTA_DATA_BLOCK_SPEAKER_ALLOC: + case DI_CTA_DATA_BLOCK_VESA_DISPLAY_TRANSFER_CHARACTERISTIC: + case DI_CTA_DATA_BLOCK_VIDEO_CAP: + case DI_CTA_DATA_BLOCK_VESA_DISPLAY_DEVICE: + case DI_CTA_DATA_BLOCK_COLORIMETRY: + case DI_CTA_DATA_BLOCK_HDR_STATIC_METADATA: + case DI_CTA_DATA_BLOCK_VIDEO_FORMAT_PREF: + case DI_CTA_DATA_BLOCK_YCBCR420_CAP_MAP: + case DI_CTA_DATA_BLOCK_HDMI_AUDIO: + case DI_CTA_DATA_BLOCK_ROOM_CONFIG: + case DI_CTA_DATA_BLOCK_HDMI_EDID_EXT_OVERRIDE: + case DI_CTA_DATA_BLOCK_HDMI_SINK_CAP: + return false; + default: + return true; + } +} + +static const struct di_cta_data_block * +di_edid_get_cta_data_block(const struct di_edid *edid, + enum di_cta_data_block_tag tag) +{ + const struct di_edid_ext *const *ext; + + /* + * Here we do not handle blocks that are allowed to occur in + * multiple instances. + */ + assert(!di_cta_data_block_allowed_multiple(tag)); + + for (ext = di_edid_get_extensions(edid); *ext; ext++) { + const struct di_edid_cta *cta; + const struct di_cta_data_block *const *block; + + if (di_edid_ext_get_tag(*ext) != DI_EDID_EXT_CEA) + continue; + + cta = di_edid_ext_get_cta(*ext); + for (block = di_edid_cta_get_data_blocks(cta); *block; block++) { + if (di_cta_data_block_get_tag(*block) == tag) + return *block; + } + } + + return NULL; +} + +static void +derive_edid_hdr_static_metadata(const struct di_edid *edid, + struct di_hdr_static_metadata *hsm) +{ + const struct di_cta_data_block *block; + const struct di_cta_hdr_static_metadata_block *cta_hsm; + + /* By default, everything unset and only traditional gamma supported. */ + hsm->traditional_sdr = true; + + block = di_edid_get_cta_data_block(edid, DI_CTA_DATA_BLOCK_HDR_STATIC_METADATA); + if (!block) + return; + + cta_hsm = di_cta_data_block_get_hdr_static_metadata(block); + assert(cta_hsm); + + hsm->desired_content_max_luminance = cta_hsm->desired_content_max_luminance; + hsm->desired_content_max_frame_avg_luminance = cta_hsm->desired_content_max_frame_avg_luminance; + hsm->desired_content_min_luminance = cta_hsm->desired_content_min_luminance; + hsm->type1 = cta_hsm->descriptors->type1; + hsm->traditional_sdr = cta_hsm->eotfs->traditional_sdr; + hsm->traditional_hdr = cta_hsm->eotfs->traditional_hdr; + hsm->pq = cta_hsm->eotfs->pq; + hsm->hlg = cta_hsm->eotfs->hlg; +} + static void derive_edid_color_primaries(const struct di_edid *edid, struct di_color_primaries *cc) @@ -93,6 +173,7 @@ di_info_parse_edid(const void *data, size_t size) else free(failure_msg_str); + derive_edid_hdr_static_metadata(info->edid, &info->derived.hdr_static_metadata); derive_edid_color_primaries(info->edid, &info->derived.color_primaries); return info; @@ -252,6 +333,12 @@ di_info_get_serial(const struct di_info *info) return NULL; } +const struct di_hdr_static_metadata * +di_info_get_hdr_static_metadata(const struct di_info *info) +{ + return &info->derived.hdr_static_metadata; +} + const struct di_color_primaries * di_info_get_default_color_primaries(const struct di_info *info) {