kmssink: add HDR10 infoframe support
authorBill Hofmann <bill.hofmann@gmail.com>
Fri, 18 Nov 2022 21:32:10 +0000 (13:32 -0800)
committerNicolas Dufresne <nicolas.dufresne@collabora.com>
Mon, 21 Nov 2022 22:55:41 +0000 (17:55 -0500)
If stream has HDR10 metadata and HDMI device EDID supports it, this patch
will set the DRM properties accordingly.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3303>

subprojects/gst-plugins-bad/sys/kms/gstkmsedid.c [new file with mode: 0644]
subprojects/gst-plugins-bad/sys/kms/gstkmsedid.h [new file with mode: 0644]
subprojects/gst-plugins-bad/sys/kms/gstkmssink.c
subprojects/gst-plugins-bad/sys/kms/gstkmssink.h
subprojects/gst-plugins-bad/sys/kms/meson.build

diff --git a/subprojects/gst-plugins-bad/sys/kms/gstkmsedid.c b/subprojects/gst-plugins-bad/sys/kms/gstkmsedid.c
new file mode 100644 (file)
index 0000000..7c5221a
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+* Copyright © 2008-2011 Kristian Høgsberg
+* Copyright © 2011 Intel Corporation
+* Copyright © 2017, 2018 Collabora, Ltd.
+* Copyright © 2017, 2018 General Electric Company
+* Copyright (c) 2018 DisplayLink (UK) Ltd.
+*
+* Permission is hereby granted, free of charge, to any person obtaining
+* a copy of this software and associated documentation files (the
+* "Software"), to deal in the Software without restriction, including
+* without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to
+* permit persons to whom the Software is furnished to do so, subject to
+* the following conditions:
+*
+* The above copyright notice and this permission notice (including the
+* next paragraph) shall be included in all copies or substantial
+* portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*/
+
+#include <math.h>
+#include "gstkmsedid.h"
+
+/* from  libweston/backend-drm/modes.c unaccepted merge, modified slightly to
+    remove non HDR stuff, return -1 if no HDR in EDID.
+    https://gitlab.freedesktop.org/jcline/weston/-/commit/b3fa65d19ca60a45d0cc0fc1bfa68eea970344ee
+ */
+#define EDID_OFFSET_EXT_COUNT                          0x7E
+#define EDID_EXTENSION_SIZE                            0x80
+// Indicates the EDID extension is a CTA extension
+#define EDID_CTA_EXTENSION_TAG                 0x02
+// Indicates the data block uses the extended tag field
+#define EDID_CTA_EXTENDED_TAG                  0x07
+// Value of the extended tag field for HDR static metadata blocks
+#define EDID_CTA_STATIC_HDR_TAG                        0x06
+
+/* Extract the HDR static metadata from a CTA EDID extension. */
+static int
+gst_kms_parse_hdr_metadata (const uint8_t * cta_ext_data,
+    struct gst_kms_hdr_static_metadata *metadata)
+{
+  int i, block_len;
+  uint8_t cta_revision = cta_ext_data[1];
+  uint8_t dtd_offset = cta_ext_data[2];
+  const uint8_t *data_blocks = cta_ext_data + 4;
+
+  if (cta_revision != 3) {
+    return -1;
+  }
+  // The data block collection ranges from byte 4 to the dtd_offset; each
+  // block begins with the block size (in bytes) in bits 0-4 of the first byte.
+  for (i = 0; i < dtd_offset; i += (data_blocks[i] & 0x1f) + 1) {
+    if ((data_blocks[i] & 0xe0) >> 5 == EDID_CTA_EXTENDED_TAG) {
+      block_len = data_blocks[i] & 0x1f;
+
+      if (data_blocks[i + 1] == EDID_CTA_STATIC_HDR_TAG) {
+        if (block_len < 2)
+          continue;
+
+        metadata->eotf = data_blocks[i + 2];
+        metadata->metadata_type = data_blocks[i + 3];
+
+        if (block_len > 3 && data_blocks[i + 4])
+          metadata->max_cll = 50.0 * pow (2, data_blocks[i + 4] / 32.0);
+        if (block_len > 4 && data_blocks[i + 5])
+          metadata->max_fall = 50.0 * pow (2, data_blocks[i + 5] / 32.0);
+        if (block_len > 5)
+          metadata->min_cll =
+              metadata->max_cll * pow (data_blocks[i + 6] / 255.0, 2) / 100.0;
+        return 0;
+      }
+    }
+  }
+  return -1;
+}
+
+int
+gst_kms_edid_parse (struct gst_kms_hdr_static_metadata *metadata,
+    const uint8_t * data, size_t length)
+{
+  int i;
+  const uint8_t *edid_extension;
+
+  /* check header */
+  if (length < 128 || length < ((size_t) data[EDID_OFFSET_EXT_COUNT] + 1) * 128)
+    return -1;
+  if (data[0] != 0x00 || data[1] != 0xff)
+    return -1;
+
+  edid_extension = data + 128;
+  for (i = 0; i < data[EDID_OFFSET_EXT_COUNT]; i++) {
+    switch (edid_extension[0]) {
+      case EDID_CTA_EXTENSION_TAG:
+        return gst_kms_parse_hdr_metadata (edid_extension, metadata);
+    }
+    edid_extension += 128;
+  }
+
+  return 0;
+}
+
+/* END from  libweston/backend-drm/modes.c unaccepted merge */
diff --git a/subprojects/gst-plugins-bad/sys/kms/gstkmsedid.h b/subprojects/gst-plugins-bad/sys/kms/gstkmsedid.h
new file mode 100644 (file)
index 0000000..1907ae2
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+  * Copyright © 2008-2011 Kristian Høgsberg
+  * Copyright © 2011 Intel Corporation
+  * Copyright © 2017, 2018 Collabora, Ltd.
+  * Copyright © 2017, 2018 General Electric Company
+  * Copyright (c) 2018 DisplayLink (UK) Ltd.
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining
+  * a copy of this software and associated documentation files (the
+  * "Software"), to deal in the Software without restriction, including
+  * without limitation the rights to use, copy, modify, merge, publish,
+  * distribute, sublicense, and/or sell copies of the Software, and to
+  * permit persons to whom the Software is furnished to do so, subject to
+  * the following conditions:
+  *
+  * The above copyright notice and this permission notice (including the
+  * next paragraph) shall be included in all copies or substantial
+  * portions of the Software.
+  *
+  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  * SOFTWARE.
+  */
+
+#ifndef __GST_KMS_EDID_H__
+#define __GST_KMS_EDID_H__
+
+/* from  libweston/backend-drm/modes.c unaccepted merge, modified slightly to
+    remove non HDR stuff, return -1 if no HDR in EDID.
+    https://gitlab.freedesktop.org/jcline/weston/-/commit/b3fa65d19ca60a45d0cc0fc1bfa68eea970344ee
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* HDR Metadata as per 861.G spec from linux/hdmi.h, modified for stdint.h */
+struct gst_kms_hdr_static_metadata
+{
+  uint8_t eotf;
+  uint8_t metadata_type;
+  uint16_t max_cll;
+  uint16_t max_fall;
+  uint16_t min_cll;
+};
+
+int
+gst_kms_edid_parse (struct gst_kms_hdr_static_metadata *metadata, const uint8_t * data,
+    size_t length);
+
+#endif /* __GST_KMS_EDID_H__ */
index e929d28..16d4afb 100644 (file)
@@ -49,6 +49,7 @@
 
 #include <gst/video/video.h>
 #include <gst/video/videooverlay.h>
+#include <gst/video/video-color.h>
 #include <gst/allocators/gstdmabuf.h>
 
 #include <drm.h>
 #include "gstkmsbufferpool.h"
 #include "gstkmsallocator.h"
 
+#ifdef HAVE_DRM_HDR
+#include <math.h>
+#include "gstkmsedid.h"
+#endif
+
 #define GST_PLUGIN_NAME "kmssink"
 #define GST_PLUGIN_DESC "Video sink using the Linux kernel mode setting API"
 
@@ -104,6 +110,303 @@ enum
 
 static GParamSpec *g_properties[PROP_N] = { NULL, };
 
+#ifdef HAVE_DRM_HDR
+enum hdmi_metadata_type
+{
+  HDMI_STATIC_METADATA_TYPE1 = 0,
+};
+enum hdmi_eotf
+{
+  HDMI_EOTF_TRADITIONAL_GAMMA_SDR = 0,
+  HDMI_EOTF_TRADITIONAL_GAMMA_HDR,
+  HDMI_EOTF_SMPTE_ST2084,
+  HDMI_EOTF_BT_2100_HLG,
+};
+
+static void
+gst_kms_populate_infoframe (struct hdr_output_metadata *pinfo_frame,
+    GstVideoMasteringDisplayInfo * p_hdr_minfo,
+    GstVideoContentLightLevel * p_hdr_cll,
+    gchar colorimetry, gboolean clear_it_out)
+{
+  /* From CTA-861.3:
+   * When a source is transmitting the Dynamic Range and Mastering InfoFrame,
+   * it shall signal the end of Dynamic Range... by sending a ... InfoFrame with
+   * the EOTF field to '0', the Static_Metadata_Descriptor_ID field set to '0',
+   * and the fields of the Static_Metadata_Descriptor set to unknown (0)...
+   *
+   * See also https://dri.freedesktop.org/docs/drm/gpu/drm-uapi.html
+   */
+  if (clear_it_out) {
+    /* Static_Metadata_Descriptor_ID */
+    pinfo_frame->metadata_type = 0;
+    (void) memset ((void *) &pinfo_frame->hdmi_metadata_type1, 0,
+        sizeof (pinfo_frame->hdmi_metadata_type1));
+    return;
+  } else {
+    pinfo_frame->metadata_type = HDMI_STATIC_METADATA_TYPE1;
+    pinfo_frame->hdmi_metadata_type1.eotf = colorimetry;
+    pinfo_frame->hdmi_metadata_type1.metadata_type = HDMI_STATIC_METADATA_TYPE1;
+  }
+
+  /* For HDR Infoframe see CTA-861-G, Section 6.9.1
+   * SEI message is in units of 0.0001 cd/m2, HDMI is units of 1 cd/m2 - see
+   * x265 specs */
+  pinfo_frame->hdmi_metadata_type1.max_display_mastering_luminance =
+      round (p_hdr_minfo->max_display_mastering_luminance / 10000.0);
+  pinfo_frame->hdmi_metadata_type1.min_display_mastering_luminance =
+      p_hdr_minfo->min_display_mastering_luminance;
+
+  pinfo_frame->hdmi_metadata_type1.max_cll = p_hdr_cll->max_content_light_level;
+  pinfo_frame->hdmi_metadata_type1.max_fall =
+      p_hdr_cll->max_frame_average_light_level;
+
+  for (int i = 0; i < 3; i++) {
+    pinfo_frame->hdmi_metadata_type1.display_primaries[i].x =
+        p_hdr_minfo->display_primaries[i].x;
+    pinfo_frame->hdmi_metadata_type1.display_primaries[i].y =
+        p_hdr_minfo->display_primaries[i].y;
+  }
+
+  pinfo_frame->hdmi_metadata_type1.white_point.x = p_hdr_minfo->white_point.x;
+  pinfo_frame->hdmi_metadata_type1.white_point.y = p_hdr_minfo->white_point.y;
+}
+
+static void
+gst_kms_push_hdr_infoframe (GstKMSSink * self, gboolean clear_it_out)
+{
+  struct hdr_output_metadata info_frame;
+  drmModeObjectPropertiesPtr props;
+  uint32_t hdrBlobID;
+  int drm_fd = self->fd;
+  uint32_t conn_id = self->conn_id;
+  int ret = 0;
+
+  if (self->no_infoframe || !self->has_hdr_info || (!clear_it_out
+          && self->has_sent_hdrif)) {
+    return;
+  }
+
+  /* Check to see if the connection has the HDR_OUTPUT_METADATA property if
+   * we haven't already found it */
+  if (self->hdrPropID == 0 || self->edidPropID == 0) {
+    props =
+        drmModeObjectGetProperties (drm_fd, conn_id, DRM_MODE_OBJECT_CONNECTOR);
+
+    if (!props) {
+      GST_ERROR_OBJECT (self, "Error on drmModeObjectGetProperties %d %s",
+          errno, g_strerror (errno));
+      return;
+    }
+
+    struct gst_kms_hdr_static_metadata hdr_edid_info = { 0, 0, 0, 0, 0 };
+    for (uint32_t i = 0;
+        i < props->count_props && (self->hdrPropID == 0
+            || self->edidPropID == 0); i++) {
+      drmModePropertyPtr pprop = drmModeGetProperty (drm_fd, props->props[i]);
+
+      if (pprop) {
+        /* 7 16 DRM_MODE_PROP_BLOB HDR_OUTPUT_METADATA */
+        if (!strncmp ("HDR_OUTPUT_METADATA", pprop->name,
+                strlen ("HDR_OUTPUT_METADATA"))) {
+          self->hdrPropID = pprop->prop_id;
+          GST_DEBUG_OBJECT (self, "HDR prop ID = %d", self->hdrPropID);
+        }
+
+        if (!strncmp ("EDID", pprop->name, strlen ("EDID"))) {
+          self->edidPropID = pprop->prop_id;
+
+          /* Check if EDID indicates device supports HDR */
+          drmModePropertyBlobPtr blob;
+          blob = drmModeGetPropertyBlob (drm_fd, props->prop_values[i]);
+          if (blob) {
+            int res =
+                gst_kms_edid_parse (&hdr_edid_info, blob->data, blob->length);
+            if (res != 0) {
+              hdr_edid_info.eotf = 0;
+              hdr_edid_info.metadata_type = 0;
+            }
+          }
+
+          drmModeFreePropertyBlob (blob);
+
+          GST_DEBUG_OBJECT (self, "EDID prop ID = %d", self->edidPropID);
+          /* only these two values are guaranteed to be populated for HDR */
+          GST_DEBUG_OBJECT (self, "EDID EOTF = %u, metadata type = %u",
+              hdr_edid_info.eotf, hdr_edid_info.metadata_type);
+        }
+
+        drmModeFreeProperty (pprop);
+      } else {
+        GST_ERROR_OBJECT (self, "Error on drmModeGetProperty(%d)", i);
+      }
+    }
+
+    drmModeFreeObjectProperties (props);
+
+    if (self->hdrPropID == 0 || self->edidPropID == 0
+        || hdr_edid_info.eotf == 0) {
+      GST_DEBUG_OBJECT (self, "No HDR support on target display");
+      self->no_infoframe = TRUE;
+      /* FIXME: maybe not the right flag here... */
+      self->has_sent_hdrif = TRUE;
+      return;
+    }
+  }
+
+  if (clear_it_out)
+    GST_INFO ("Clearing HDR Infoframe on connector %d", self->conn_id);
+  else
+    GST_INFO ("Setting HDR Infoframe, if available on connector %d",
+        self->conn_id);
+
+  gst_kms_populate_infoframe (&info_frame, &self->hdr_minfo, &self->hdr_cll,
+      self->colorimetry, clear_it_out);
+
+  /* Use non-atomic property setting */
+  ret = drmModeCreatePropertyBlob (drm_fd, &info_frame,
+      sizeof (struct hdr_output_metadata), &hdrBlobID);
+  if (!ret) {
+    ret =
+        drmModeObjectSetProperty (drm_fd, conn_id, DRM_MODE_OBJECT_CONNECTOR,
+        self->hdrPropID, hdrBlobID);
+    if (ret) {
+      GST_ERROR_OBJECT (self, "drmModeObjectSetProperty result %d %d %s", ret,
+          errno, g_strerror (errno));
+    }
+    drmModeDestroyPropertyBlob (drm_fd, hdrBlobID);
+  } else {
+    GST_ERROR_OBJECT (self, "Failed to drmModeCreatePropertyBlob %d %s", errno,
+        g_strerror (errno));
+  }
+
+  if (!ret) {
+    GST_INFO ("Set HDR Infoframe on connector %d", conn_id);
+    self->has_sent_hdrif = TRUE;        // Hooray!
+  }
+}
+
+
+/* From an HDR10 stream caps:
+ *
+ * colorimetry=(string)bt2100-pq
+ * content-light-level=(string)10000:166
+ * mastering-display-info=(string)35400:14600:8500:39850:6550:2300:15635:16450:10000000:1
+ */
+static void
+gst_kms_sink_set_hdr10_caps (GstKMSSink * self, GstCaps * caps)
+{
+  GstVideoMasteringDisplayInfo hdr_minfo;
+  GstVideoContentLightLevel hdr_cll;
+  GstStructure *structure;
+  const gchar *colorimetry_s;
+  GstVideoColorimetry colorimetry;
+  gboolean has_hdr_eotf = FALSE;
+  gboolean has_cll = FALSE;
+
+  structure = gst_caps_get_structure (caps, 0);
+  if ((colorimetry_s = gst_structure_get_string (structure,
+              "colorimetry")) != NULL &&
+      gst_video_colorimetry_from_string (&colorimetry, colorimetry_s)) {
+    switch (colorimetry.transfer) {
+      case GST_VIDEO_TRANSFER_SMPTE2084:
+        self->colorimetry = HDMI_EOTF_SMPTE_ST2084;
+        has_hdr_eotf = TRUE;
+        GST_DEBUG ("Got HDR transfer value GST_VIDEO_TRANSFER_SMPTE2084: %u",
+            self->colorimetry);
+        break;
+      case GST_VIDEO_TRANSFER_BT2020_10:
+      case GST_VIDEO_TRANSFER_ARIB_STD_B67:
+        self->colorimetry = HDMI_EOTF_BT_2100_HLG;
+        has_hdr_eotf = TRUE;
+        GST_DEBUG ("Got HDR transfer value HDMI_EOTF_BT_2100_HLG: %u",
+            self->colorimetry);
+        break;
+      case GST_VIDEO_TRANSFER_BT709:
+        self->colorimetry = HDMI_EOTF_TRADITIONAL_GAMMA_SDR;
+        GST_DEBUG ("Got HDR transfer value GST_VIDEO_TRANSFER_BT709, "
+            "not HDR: %u", self->colorimetry);
+        break;
+      default:
+        /* not an HDMI and/or HDR colorimetry, we will ignore */
+        GST_DEBUG ("Unsupported transfer function, no HDR: %u",
+            colorimetry.transfer);
+        self->no_infoframe = TRUE;
+        self->has_hdr_info = FALSE;
+        break;
+    }
+  }
+
+  if (gst_video_mastering_display_info_from_caps (&hdr_minfo, caps)) {
+    if (!gst_video_mastering_display_info_is_equal (&hdr_minfo,
+            &self->hdr_minfo)) {
+      self->hdr_minfo = hdr_minfo;
+      self->no_infoframe = FALSE;
+      self->has_hdr_info = TRUE;
+      /* to send again */
+      self->has_sent_hdrif = FALSE;
+    }
+
+    GST_DEBUG ("Got mastering info: "
+        "min %u max %u wp %u %u dp[0] %u %u dp[1] %u %u dp[2] %u %u",
+        self->hdr_minfo.min_display_mastering_luminance,
+        self->hdr_minfo.max_display_mastering_luminance,
+        self->hdr_minfo.white_point.x, self->hdr_minfo.white_point.y,
+        self->hdr_minfo.display_primaries[0].x,
+        self->hdr_minfo.display_primaries[0].y,
+        self->hdr_minfo.display_primaries[1].x,
+        self->hdr_minfo.display_primaries[1].y,
+        self->hdr_minfo.display_primaries[2].x,
+        self->hdr_minfo.display_primaries[2].y);
+
+  } else {
+    if (self->has_hdr_info == TRUE) {
+      GST_WARNING ("Missing mastering display info");
+    } else {
+      self->no_infoframe = TRUE;
+      self->has_hdr_info = FALSE;
+    }
+
+    gst_video_mastering_display_info_init (&self->hdr_minfo);
+  }
+
+  if (gst_video_content_light_level_from_caps (&hdr_cll, caps)) {
+    GST_DEBUG ("Got content light level information: Max CLL: %u Max FALL: %u",
+        hdr_cll.max_content_light_level, hdr_cll.max_frame_average_light_level);
+
+    if (!gst_video_content_light_level_is_equal (&hdr_cll, &self->hdr_cll)) {
+      self->hdr_cll = hdr_cll;
+      self->no_infoframe = FALSE;
+      self->has_hdr_info = TRUE;
+      /* to send again */
+      self->has_sent_hdrif = FALSE;
+    }
+
+    has_cll = TRUE;
+  } else {
+    gst_video_content_light_level_init (&self->hdr_cll);
+
+    if (self->has_hdr_info == TRUE) {
+      GST_WARNING ("Missing content light level info");
+    }
+
+    self->no_infoframe = TRUE;
+    self->has_hdr_info = FALSE;
+  }
+
+  /* need all caps set */
+  if ((has_hdr_eotf || has_cll) && !(has_hdr_eotf && has_cll)) {
+    GST_ELEMENT_WARNING (self, STREAM, FORMAT,
+        ("Stream doesn't have all HDR components needed"),
+        ("Check stream caps"));
+
+    self->no_infoframe = TRUE;
+    self->has_hdr_info = FALSE;
+  }
+}
+
+#endif /* HAVE_DRM_HDR */
+
 static void
 gst_kms_sink_set_render_rectangle (GstVideoOverlay * overlay,
     gint x, gint y, gint width, gint height)
@@ -1148,6 +1451,10 @@ gst_kms_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
   if (GST_VIDEO_SINK_WIDTH (self) <= 0 || GST_VIDEO_SINK_HEIGHT (self) <= 0)
     goto invalid_size;
 
+#ifdef HAVE_DRM_HDR
+  gst_kms_sink_set_hdr10_caps (self, caps);
+#endif
+
   /* discard dumb buffer pool */
   if (self->pool) {
     gst_buffer_pool_set_active (self->pool, FALSE);
@@ -1665,6 +1972,10 @@ retry_set_plane:
     src.w = result.w;
     src.h = result.h;
   }
+#ifdef HAVE_DRM_HDR
+  /* Send the HDR infoframes if appropriate */
+  gst_kms_push_hdr_infoframe (self, FALSE);
+#endif
 
   GST_TRACE_OBJECT (self,
       "drmModeSetPlane at (%i,%i) %ix%i sourcing at (%i,%i) %ix%i",
@@ -1981,6 +2292,17 @@ gst_kms_sink_init (GstKMSSink * sink)
   sink->poll = gst_poll_new (TRUE);
   gst_video_info_init (&sink->vinfo);
   sink->skip_vsync = FALSE;
+
+#ifdef HAVE_DRM_HDR
+  sink->no_infoframe = FALSE;
+  sink->has_hdr_info = FALSE;
+  sink->has_sent_hdrif = FALSE;
+  sink->edidPropID = 0;
+  sink->hdrPropID = 0;
+  sink->colorimetry = HDMI_EOTF_TRADITIONAL_GAMMA_SDR;
+  gst_video_mastering_display_info_init (&sink->hdr_minfo);
+  gst_video_content_light_level_init (&sink->hdr_cll);
+#endif
 }
 
 static void
index e20e2c3..9c33e1f 100644 (file)
@@ -27,6 +27,8 @@
 #define __GST_KMS_SINK_H__
 
 #include <gst/video/gstvideosink.h>
+#include <drm/drm_mode.h>
+#include <gst/video/video-hdr.h>
 
 G_BEGIN_DECLS
 
@@ -96,6 +98,18 @@ struct _GstKMSSink {
 
   gboolean is_internal_fd;
   gboolean skip_vsync;
+
+#ifdef HAVE_DRM_HDR
+  /* HDR mastering related structure */
+  gboolean no_infoframe;
+  gboolean has_hdr_info;
+  gboolean has_sent_hdrif;
+  guint32 edidPropID;
+  guint32 hdrPropID;
+  gchar colorimetry;
+  GstVideoMasteringDisplayInfo hdr_minfo;
+  GstVideoContentLightLevel hdr_cll;
+#endif
 };
 
 struct _GstKMSSinkClass {
index 5468870..2f960c8 100644 (file)
@@ -4,6 +4,7 @@ kmssink_sources = [
   'gstkmssink.c',
   'gstkmsutils.c',
 ]
+extra_deps = []
 
 if host_system != 'linux'
   subdir_done()
@@ -12,12 +13,22 @@ endif
 libdrm_dep = dependency('libdrm', version : '>= 2.4.98',
                         required : get_option('kms'),
                         fallback: ['libdrm', 'ext_libdrm'])
+libdrm_hdr_dep = dependency('libdrm', version : '>= 2.4.104',
+                            required : false,
+                            fallback: ['libdrm', 'ext_libdrm'])
+mathlib = cc.find_library('m', required : false)
+
+if libdrm_hdr_dep.found() and mathlib.found()
+  cdata.set('HAVE_DRM_HDR', 1)
+  kmssink_sources += 'gstkmsedid.c'
+endif
+
 if libdrm_dep.found()
   gstkmssink = library('gstkms',
     kmssink_sources,
     c_args : gst_plugins_bad_args,
     include_directories : [configinc],
-    dependencies : [gstbase_dep, gstvideo_dep, gstallocators_dep, libdrm_dep],
+    dependencies : [gstbase_dep, gstvideo_dep, gstallocators_dep, libdrm_dep, mathlib],
     install : true,
     install_dir : plugins_install_dir,
   )