From d8bced54dda87c7d6f390719c3ce1c2a6ea06f22 Mon Sep 17 00:00:00 2001 From: Jiajian Wu Date: Mon, 3 Jul 2023 15:26:53 +0800 Subject: [PATCH 41/48] kmssink: Support HDR Signed-off-by: Jiajian Wu --- sys/kms/gstkmssink.c | 206 +++++++++++++++++++++++++++++++++++++++---- sys/kms/gstkmssink.h | 7 ++ 2 files changed, 195 insertions(+), 18 deletions(-) diff --git a/sys/kms/gstkmssink.c b/sys/kms/gstkmssink.c index 5b2ae38..4883c3e 100644 --- a/sys/kms/gstkmssink.c +++ b/sys/kms/gstkmssink.c @@ -57,6 +57,7 @@ #include #include #include +#include #include "gstkmssink.h" #include "gstkmsutils.h" @@ -109,6 +110,8 @@ enum PROP_FORCE_ASPECT_RATIO, PROP_SYNC_MODE, PROP_FULLSCREEN, + PROP_HDR_EN, + PROP_REQUIRED_CLL, PROP_N, }; @@ -128,6 +131,13 @@ enum hdmi_eotf HDMI_EOTF_SMPTE_ST2084, HDMI_EOTF_BT_2100_HLG, }; +/* define in include/uapi/drm/rockchip_drm.h */ +enum rockchip_crtc_feture +{ + ROCKCHIP_DRM_CRTC_FEATURE_ALPHA_SCALE, + ROCKCHIP_DRM_CRTC_FEATURE_HDR10, + ROCKCHIP_DRM_CRTC_FEATURE_NEXT_HDR, +}; static void gst_kms_populate_infoframe (struct hdr_output_metadata *pinfo_frame, @@ -178,11 +188,104 @@ gst_kms_populate_infoframe (struct hdr_output_metadata *pinfo_frame, pinfo_frame->hdmi_metadata_type1.white_point.y = p_hdr_minfo->white_point.y; } +static void +gst_kms_add_plane_properties (GstKMSSink * self, drmModeAtomicReq *req, gboolean clear_it_out) +{ + drmModeObjectPropertiesPtr props = NULL; + int zpos_idx = -1; + int eotf = HDMI_EOTF_TRADITIONAL_GAMMA_SDR; + int colorspace = V4L2_COLORSPACE_DEFAULT; + int ret; + + props = + drmModeObjectGetProperties (self->fd, self->plane_id, DRM_MODE_OBJECT_PLANE); + if (!props) + return; + + for (int i = 0; + i < props->count_props && (self->eotfPropID == 0 + || self->colorSpacePropID == 0 + || self->zposPropID == 0); i++) { + drmModePropertyPtr pprop = drmModeGetProperty (self->fd, props->props[i]); + + if (pprop) { + if(!strncmp ("EOTF", pprop->name, strlen ("EOTF"))) { + self->eotfPropID = pprop->prop_id; + } else if(!strncmp ("COLOR_SPACE", pprop->name, strlen ("COLOR_SPACE"))) { + self->colorSpacePropID = pprop->prop_id; + } else if(!strncmp ("zpos", pprop->name, strlen ("zpos")) + || !strncmp ("ZPOS", pprop->name, strlen ("ZPOS"))) { + self->zposPropID = pprop->prop_id; + zpos_idx = i; + } + } + drmModeFreeProperty (pprop); + } + + if (self->eotfPropID == 0 || self->colorSpacePropID == 0 + || self->zposPropID == 0) { + GST_ERROR_OBJECT (self, "cannot find eotf | colorspace | zpos"); + goto out; + } + + eotf = self->colorimetry; + colorspace = self->colorspace; + + drmModeAtomicAddProperty(req, self->plane_id, self->eotfPropID, + clear_it_out ? HDMI_EOTF_TRADITIONAL_GAMMA_SDR : eotf); + drmModeAtomicAddProperty(req, self->plane_id, self->colorSpacePropID, + clear_it_out ? V4L2_COLORSPACE_DEFAULT : colorspace); + + if (clear_it_out) { + if (self->saved_zpos >= 0) + drmModeAtomicAddProperty(req, self->plane_id, self->zposPropID, + self->saved_zpos); + } else { + if (self->saved_zpos < 0) + self->saved_zpos = props->prop_values[zpos_idx]; + drmModeAtomicAddProperty(req, self->plane_id, self->zposPropID, 0); + } + +out: + drmModeFreeObjectProperties (props); +} + +static int +gst_kms_check_crtc_hdr_support (GstKMSSink * self) +{ + drmModeObjectPropertiesPtr props = NULL; + drmModePropertyPtr prop = NULL; + uint32_t val = 0; + + props = drmModeObjectGetProperties (self->fd, self->crtc_id, + DRM_MODE_OBJECT_CRTC); + if (!props) + return FALSE; + + for (int i = 0; i < props->count_props; i++) { + prop = drmModeGetProperty (self->fd, props->props[i]); + if (prop) { + if (!strcmp (prop->name, "FEATURE")) { + val = props->prop_values[i]; + break; + } + } + drmModeFreeProperty (prop); + prop = NULL; + } + + drmModeFreeProperty (prop); + drmModeFreeObjectProperties (props); + + return (val & (1 << ROCKCHIP_DRM_CRTC_FEATURE_HDR10)); +} + static void gst_kms_push_hdr_infoframe (GstKMSSink * self, gboolean clear_it_out) { struct hdr_output_metadata info_frame; drmModeObjectPropertiesPtr props; + drmModeAtomicReq *req; uint32_t hdrBlobID; int drm_fd = self->fd; uint32_t conn_id = self->conn_id; @@ -193,9 +296,19 @@ gst_kms_push_hdr_infoframe (GstKMSSink * self, gboolean clear_it_out) return; } + if (gst_kms_check_crtc_hdr_support (self) == FALSE) { + GST_WARNING_OBJECT (self, "No HDR support on CRTC %d", self->crtc_id); + self->has_sent_hdrif = TRUE; + return; + } + + if (drmSetClientCap (drm_fd, DRM_CLIENT_CAP_ATOMIC, 1)) + 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) { + if (self->hdrPropID == 0 || self->edidPropID == 0 + || self->connColorSpacePropID == 0) { props = drmModeObjectGetProperties (drm_fd, conn_id, DRM_MODE_OBJECT_CONNECTOR); @@ -208,7 +321,7 @@ gst_kms_push_hdr_infoframe (GstKMSSink * self, gboolean clear_it_out) 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++) { + || self->edidPropID == 0 || self->connColorSpacePropID == 0); i++) { drmModePropertyPtr pprop = drmModeGetProperty (drm_fd, props->props[i]); if (pprop) { @@ -219,6 +332,12 @@ gst_kms_push_hdr_infoframe (GstKMSSink * self, gboolean clear_it_out) GST_DEBUG_OBJECT (self, "HDR prop ID = %d", self->hdrPropID); } + if (!strncmp ("Colorspace", pprop->name, + strlen ("Colorspace"))) { + self->connColorSpacePropID = pprop->prop_id; + GST_DEBUG_OBJECT (self, "Colorspace prop ID = %d", self->connColorSpacePropID); + } + if (!strncmp ("EDID", pprop->name, strlen ("EDID"))) { self->edidPropID = pprop->prop_id; @@ -251,6 +370,7 @@ gst_kms_push_hdr_infoframe (GstKMSSink * self, gboolean clear_it_out) drmModeFreeObjectProperties (props); if (self->hdrPropID == 0 || self->edidPropID == 0 + || self->connColorSpacePropID == 0 || hdr_edid_info.eotf == 0) { GST_DEBUG_OBJECT (self, "No HDR support on target display"); self->no_infoframe = TRUE; @@ -269,23 +389,33 @@ gst_kms_push_hdr_infoframe (GstKMSSink * self, gboolean clear_it_out) 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 { + if (ret) { GST_ERROR_OBJECT (self, "Failed to drmModeCreatePropertyBlob %d %s", errno, g_strerror (errno)); + goto err_out; } + req = drmModeAtomicAlloc(); + if (!req) { + GST_ERROR_OBJECT (self, "drmModeAtomicAlloc failed"); + drmModeDestroyPropertyBlob (drm_fd, hdrBlobID); + goto err_out; + } + + drmModeAtomicAddProperty(req, conn_id, self->connColorSpacePropID, + clear_it_out ? 0 : self->colorspace); + drmModeAtomicAddProperty(req, conn_id, self->hdrPropID, hdrBlobID); + gst_kms_add_plane_properties(self, req, clear_it_out); + ret = drmModeAtomicCommit(drm_fd, req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); + if (ret) + GST_WARNING_OBJECT (self, "drmModeAtomicCommit failed %d", ret); + drmModeAtomicFree(req); + + drmModeDestroyPropertyBlob (drm_fd, hdrBlobID); + +err_out: if (!ret) { GST_INFO ("Set HDR Infoframe on connector %d", conn_id); self->has_sent_hdrif = TRUE; // Hooray! @@ -317,6 +447,7 @@ gst_kms_sink_set_hdr10_caps (GstKMSSink * self, GstCaps * caps) switch (colorimetry.transfer) { case GST_VIDEO_TRANSFER_SMPTE2084: self->colorimetry = HDMI_EOTF_SMPTE_ST2084; + self->colorspace = V4L2_COLORSPACE_BT2020; has_hdr_eotf = TRUE; GST_DEBUG ("Got HDR transfer value GST_VIDEO_TRANSFER_SMPTE2084: %u", self->colorimetry); @@ -324,12 +455,14 @@ gst_kms_sink_set_hdr10_caps (GstKMSSink * self, GstCaps * caps) case GST_VIDEO_TRANSFER_BT2020_10: case GST_VIDEO_TRANSFER_ARIB_STD_B67: self->colorimetry = HDMI_EOTF_BT_2100_HLG; + self->colorspace = V4L2_COLORSPACE_BT2020; 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; + self->colorspace = V4L2_COLORSPACE_DEFAULT; GST_DEBUG ("Got HDR transfer value GST_VIDEO_TRANSFER_BT709, " "not HDR: %u", self->colorimetry); break; @@ -337,6 +470,7 @@ gst_kms_sink_set_hdr10_caps (GstKMSSink * self, GstCaps * caps) /* not an HDMI and/or HDR colorimetry, we will ignore */ GST_DEBUG ("Unsupported transfer function, no HDR: %u", colorimetry.transfer); + self->colorspace = V4L2_COLORSPACE_DEFAULT; self->no_infoframe = TRUE; self->has_hdr_info = FALSE; break; @@ -396,8 +530,10 @@ gst_kms_sink_set_hdr10_caps (GstKMSSink * self, GstCaps * caps) GST_WARNING ("Missing content light level info"); } - self->no_infoframe = TRUE; - self->has_hdr_info = FALSE; + if (self->required_cll) { + self->no_infoframe = TRUE; + self->has_hdr_info = FALSE; + } } /* need all caps set */ @@ -405,9 +541,10 @@ gst_kms_sink_set_hdr10_caps (GstKMSSink * self, GstCaps * caps) 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; + if (has_hdr_eotf && !has_cll && self->required_cll) { + self->no_infoframe = TRUE; + self->has_hdr_info = FALSE; + } } } @@ -1533,6 +1670,10 @@ gst_kms_sink_stop (GstBaseSink * bsink) self->saved_zpos = -1; } +#ifdef HAVE_DRM_HDR + /* Clear the HDR infoframes */ + gst_kms_push_hdr_infoframe (self, TRUE); +#endif gst_buffer_replace (&self->last_buffer, NULL); gst_caps_replace (&self->allowed_caps, NULL); gst_object_replace ((GstObject **) & self->pool, NULL); @@ -2600,6 +2741,12 @@ gst_kms_sink_set_property (GObject * object, guint prop_id, case PROP_FULLSCREEN: sink->fullscreen = g_value_get_boolean (value); break; + case PROP_HDR_EN: + sink->hdr_en = g_value_get_boolean (value); + break; + case PROP_REQUIRED_CLL: + sink->required_cll = g_value_get_boolean (value); + break; default: if (!gst_video_overlay_set_property (object, PROP_N, prop_id, value)) G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -2668,6 +2815,12 @@ gst_kms_sink_get_property (GObject * object, guint prop_id, case PROP_FULLSCREEN: g_value_set_boolean (value, sink->fullscreen); break; + case PROP_HDR_EN: + g_value_set_boolean (value, sink->hdr_en); + break; + case PROP_REQUIRED_CLL: + g_value_set_boolean (value, sink->required_cll); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2710,12 +2863,19 @@ gst_kms_sink_init (GstKMSSink * sink) sink->skip_vsync = TRUE; #ifdef HAVE_DRM_HDR + sink->hdr_en = TRUE; + sink->required_cll = FALSE; sink->no_infoframe = FALSE; sink->has_hdr_info = FALSE; sink->has_sent_hdrif = FALSE; sink->edidPropID = 0; sink->hdrPropID = 0; + sink->connColorSpacePropID = 0; + sink->eotfPropID = 0; + sink->colorSpacePropID = 0; + sink->zposPropID = 0; sink->colorimetry = HDMI_EOTF_TRADITIONAL_GAMMA_SDR; + sink->colorspace = V4L2_COLORSPACE_DEFAULT; gst_video_mastering_display_info_init (&sink->hdr_minfo); gst_video_content_light_level_init (&sink->hdr_cll); #endif @@ -2947,6 +3107,16 @@ gst_kms_sink_class_init (GstKMSSinkClass * klass) "Force showing fullscreen", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_properties[PROP_HDR_EN] = + g_param_spec_boolean ("hdr-enable", "HDR enable", + "Enable HDR", TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_properties[PROP_REQUIRED_CLL] = + g_param_spec_boolean ("required-cll", "HDR cll is required", + "Content light level information is required", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (gobject_class, PROP_N, g_properties); gst_video_overlay_install_properties (gobject_class, PROP_N); diff --git a/sys/kms/gstkmssink.h b/sys/kms/gstkmssink.h index 5c4065a..80b5c3e 100644 --- a/sys/kms/gstkmssink.h +++ b/sys/kms/gstkmssink.h @@ -111,12 +111,19 @@ struct _GstKMSSink { #ifdef HAVE_DRM_HDR /* HDR mastering related structure */ + gboolean hdr_en; + gboolean required_cll; gboolean no_infoframe; gboolean has_hdr_info; gboolean has_sent_hdrif; guint32 edidPropID; guint32 hdrPropID; + guint32 connColorSpacePropID; + guint32 eotfPropID; + guint32 colorSpacePropID; + guint32 zposPropID; gchar colorimetry; + gchar colorspace; GstVideoMasteringDisplayInfo hdr_minfo; GstVideoContentLightLevel hdr_cll; #endif -- 2.20.1