waylandsink: Parse and set the HDR10 metadata
Basically whenever the compositor have support for it, and the caps includes it, set the mastering display and light content level information. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/9353>
This commit is contained in:
parent
c61b6f76b0
commit
c803ce7a9c
@ -105,6 +105,10 @@ typedef struct _GstGtkWaylandSinkPrivate
|
||||
gboolean video_info_changed;
|
||||
GstVideoInfo video_info;
|
||||
GstVideoInfoDmaDrm drm_info;
|
||||
GstVideoMasteringDisplayInfo minfo;
|
||||
GstVideoContentLightLevel linfo;
|
||||
gboolean have_mastering_info;
|
||||
gboolean have_light_info;
|
||||
GstCaps *caps;
|
||||
|
||||
GMutex render_lock;
|
||||
@ -931,6 +935,11 @@ gst_gtk_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
gst_video_info_dma_drm_init (&priv->drm_info);
|
||||
}
|
||||
|
||||
priv->have_mastering_info =
|
||||
gst_video_mastering_display_info_from_caps (&priv->minfo, caps);
|
||||
priv->have_light_info =
|
||||
gst_video_content_light_level_from_caps (&priv->linfo, caps);
|
||||
|
||||
priv->video_info_changed = TRUE;
|
||||
priv->skip_dumb_buffer_copy = FALSE;
|
||||
|
||||
@ -1050,6 +1059,8 @@ render_last_buffer (GstGtkWaylandSink * self, gboolean redraw)
|
||||
gst_gtk_wayland_sink_get_instance_private (self);
|
||||
GstWlBuffer *wlbuffer;
|
||||
const GstVideoInfo *info = NULL;
|
||||
const GstVideoMasteringDisplayInfo *minfo = NULL;
|
||||
const GstVideoContentLightLevel *linfo = NULL;
|
||||
|
||||
if (!priv->wl_window)
|
||||
return FALSE;
|
||||
@ -1058,9 +1069,17 @@ render_last_buffer (GstGtkWaylandSink * self, gboolean redraw)
|
||||
|
||||
if (G_UNLIKELY (priv->video_info_changed && !redraw)) {
|
||||
info = &priv->video_info;
|
||||
|
||||
if (priv->have_mastering_info)
|
||||
minfo = &priv->minfo;
|
||||
|
||||
if (priv->have_light_info)
|
||||
linfo = &priv->linfo;
|
||||
|
||||
priv->video_info_changed = FALSE;
|
||||
}
|
||||
return gst_wl_window_render (priv->wl_window, wlbuffer, info);
|
||||
return gst_wl_window_render_hdr (priv->wl_window, wlbuffer, info, minfo,
|
||||
linfo);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
|
@ -755,6 +755,11 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
gst_video_info_dma_drm_init (&self->drm_info);
|
||||
}
|
||||
|
||||
self->have_mastering_info =
|
||||
gst_video_mastering_display_info_from_caps (&self->minfo, caps);
|
||||
self->have_light_info =
|
||||
gst_video_content_light_level_from_caps (&self->linfo, caps);
|
||||
|
||||
self->video_info_changed = TRUE;
|
||||
self->skip_dumb_buffer_copy = FALSE;
|
||||
|
||||
@ -863,14 +868,23 @@ render_last_buffer (GstWaylandSink * self, gboolean redraw)
|
||||
{
|
||||
GstWlBuffer *wlbuffer;
|
||||
const GstVideoInfo *info = NULL;
|
||||
const GstVideoMasteringDisplayInfo *minfo = NULL;
|
||||
const GstVideoContentLightLevel *linfo = NULL;
|
||||
|
||||
wlbuffer = gst_buffer_get_wl_buffer (self->display, self->last_buffer);
|
||||
|
||||
if (G_UNLIKELY (self->video_info_changed && !redraw)) {
|
||||
info = &self->video_info;
|
||||
|
||||
if (self->have_mastering_info)
|
||||
minfo = &self->minfo;
|
||||
|
||||
if (self->have_light_info)
|
||||
linfo = &self->linfo;
|
||||
|
||||
self->video_info_changed = FALSE;
|
||||
}
|
||||
return gst_wl_window_render (self->window, wlbuffer, info);
|
||||
return gst_wl_window_render_hdr (self->window, wlbuffer, info, minfo, linfo);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -55,6 +55,10 @@ struct _GstWaylandSink
|
||||
gboolean video_info_changed;
|
||||
GstVideoInfo video_info;
|
||||
GstVideoInfoDmaDrm drm_info;
|
||||
GstVideoMasteringDisplayInfo minfo;
|
||||
GstVideoContentLightLevel linfo;
|
||||
gboolean have_mastering_info;
|
||||
gboolean have_light_info;
|
||||
gboolean fullscreen;
|
||||
GstCaps *caps;
|
||||
|
||||
|
@ -82,6 +82,8 @@ typedef struct _GstWlWindowPrivate
|
||||
GMutex window_lock;
|
||||
GstWlBuffer *next_buffer;
|
||||
GstVideoInfo *next_video_info;
|
||||
GstVideoMasteringDisplayInfo *next_minfo;
|
||||
GstVideoContentLightLevel *next_linfo;
|
||||
GstWlBuffer *staged_buffer;
|
||||
gboolean clear_window;
|
||||
struct wl_callback *frame_callback;
|
||||
@ -111,7 +113,9 @@ static void gst_wl_window_commit_buffer (GstWlWindow * self,
|
||||
GstWlBuffer * buffer);
|
||||
|
||||
static void gst_wl_window_set_colorimetry (GstWlWindow * self,
|
||||
GstVideoColorimetry * colorimetry);
|
||||
const GstVideoColorimetry * colorimetry,
|
||||
const GstVideoMasteringDisplayInfo * minfo,
|
||||
const GstVideoContentLightLevel * linfo);
|
||||
|
||||
static void
|
||||
handle_xdg_toplevel_close (void *data, struct xdg_toplevel *xdg_toplevel)
|
||||
@ -583,6 +587,8 @@ gst_wl_window_commit_buffer (GstWlWindow * self, GstWlBuffer * buffer)
|
||||
{
|
||||
GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self);
|
||||
GstVideoInfo *info = priv->next_video_info;
|
||||
GstVideoMasteringDisplayInfo *minfo = priv->next_minfo;
|
||||
GstVideoContentLightLevel *linfo = priv->next_linfo;
|
||||
struct wl_callback *callback;
|
||||
|
||||
if (G_UNLIKELY (info)) {
|
||||
@ -595,7 +601,7 @@ gst_wl_window_commit_buffer (GstWlWindow * self, GstWlBuffer * buffer)
|
||||
gst_wl_window_resize_video_surface (self, FALSE);
|
||||
gst_wl_window_set_opaque (self, info);
|
||||
|
||||
gst_wl_window_set_colorimetry (self, &info->colorimetry);
|
||||
gst_wl_window_set_colorimetry (self, &info->colorimetry, minfo, linfo);
|
||||
}
|
||||
|
||||
if (G_LIKELY (buffer)) {
|
||||
@ -630,6 +636,8 @@ gst_wl_window_commit_buffer (GstWlWindow * self, GstWlBuffer * buffer)
|
||||
wl_subsurface_set_desync (priv->video_subsurface);
|
||||
gst_video_info_free (priv->next_video_info);
|
||||
priv->next_video_info = NULL;
|
||||
g_clear_pointer (&priv->next_minfo, g_free);
|
||||
g_clear_pointer (&priv->next_linfo, g_free);
|
||||
}
|
||||
|
||||
}
|
||||
@ -661,6 +669,14 @@ static const struct wl_callback_listener commit_listener = {
|
||||
gboolean
|
||||
gst_wl_window_render (GstWlWindow * self, GstWlBuffer * buffer,
|
||||
const GstVideoInfo * info)
|
||||
{
|
||||
return gst_wl_window_render_hdr (self, buffer, info, NULL, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_wl_window_render_hdr (GstWlWindow * self, GstWlBuffer * buffer,
|
||||
const GstVideoInfo * info, const GstVideoMasteringDisplayInfo * minfo,
|
||||
const GstVideoContentLightLevel * linfo)
|
||||
{
|
||||
GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self);
|
||||
gboolean ret = TRUE;
|
||||
@ -672,6 +688,16 @@ gst_wl_window_render (GstWlWindow * self, GstWlBuffer * buffer,
|
||||
if (G_UNLIKELY (info))
|
||||
priv->next_video_info = gst_video_info_copy (info);
|
||||
|
||||
if (G_UNLIKELY (minfo)) {
|
||||
g_clear_pointer (&priv->next_minfo, g_free);
|
||||
priv->next_minfo = g_memdup2 (minfo, sizeof (*minfo));
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (linfo)) {
|
||||
g_clear_pointer (&priv->next_linfo, g_free);
|
||||
priv->next_linfo = g_memdup2 (linfo, sizeof (*linfo));
|
||||
}
|
||||
|
||||
if (priv->next_buffer && priv->staged_buffer) {
|
||||
GST_LOG_OBJECT (self, "buffer %p dropped (replaced)", priv->staged_buffer);
|
||||
gst_wl_buffer_unref_buffer (priv->staged_buffer);
|
||||
@ -954,7 +980,9 @@ gst_colorimetry_range_to_wl (GstVideoColorRange range)
|
||||
|
||||
static void
|
||||
gst_wl_window_set_image_description (GstWlWindow * self,
|
||||
GstVideoColorimetry * colorimetry)
|
||||
const GstVideoColorimetry * colorimetry,
|
||||
const GstVideoMasteringDisplayInfo * minfo,
|
||||
const GstVideoContentLightLevel * linfo)
|
||||
{
|
||||
GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self);
|
||||
struct wl_display *wl_display;
|
||||
@ -1010,6 +1038,41 @@ gst_wl_window_set_image_description (GstWlWindow * self,
|
||||
wp_image_description_creator_params_v1_set_primaries_named (params,
|
||||
wl_primaries);
|
||||
|
||||
if (gst_wl_display_is_color_mastering_display_supported (priv->display)
|
||||
&& minfo) {
|
||||
/* first validate our luminance range */
|
||||
guint min_luminance = minfo->min_display_mastering_luminance / 10000;
|
||||
guint max_luminance =
|
||||
MAX (min_luminance + 1, minfo->max_display_mastering_luminance / 10000);
|
||||
|
||||
/* We need to convert from 0.00002 unit to 0.000001 */
|
||||
const guint f = 20;
|
||||
wp_image_description_creator_params_v1_set_mastering_display_primaries
|
||||
(params,
|
||||
minfo->display_primaries[0].x * f, minfo->display_primaries[0].y * f,
|
||||
minfo->display_primaries[1].x * f, minfo->display_primaries[1].y * f,
|
||||
minfo->display_primaries[2].x * f, minfo->display_primaries[2].y * f,
|
||||
minfo->white_point.x, minfo->white_point.y);
|
||||
wp_image_description_creator_params_v1_set_mastering_luminance (params,
|
||||
minfo->min_display_mastering_luminance, max_luminance);
|
||||
|
||||
/*
|
||||
* FIXME its unclear what makes a color volume exceeds the primary volume,
|
||||
* and how to verify it, ignoring this aspect for now, but may need to be
|
||||
* revisited.
|
||||
*/
|
||||
|
||||
/* We can't set the light level if we don't know the luminance range */
|
||||
if (linfo) {
|
||||
guint maxFALL = CLAMP (min_luminance + 1,
|
||||
linfo->max_frame_average_light_level, max_luminance);
|
||||
guint maxCLL =
|
||||
CLAMP (maxFALL, linfo->max_content_light_level, max_luminance);
|
||||
wp_image_description_creator_params_v1_set_max_cll (params, maxCLL);
|
||||
wp_image_description_creator_params_v1_set_max_fall (params, maxFALL);
|
||||
}
|
||||
}
|
||||
|
||||
image_description = wp_image_description_creator_params_v1_create (params);
|
||||
wp_image_description_v1_add_listener (image_description,
|
||||
&description_listerer, &image_description_feedback);
|
||||
@ -1040,7 +1103,7 @@ gst_wl_window_set_image_description (GstWlWindow * self,
|
||||
|
||||
static void
|
||||
gst_wl_window_set_color_representation (GstWlWindow * self,
|
||||
GstVideoColorimetry * colorimetry)
|
||||
const GstVideoColorimetry * colorimetry)
|
||||
{
|
||||
GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self);
|
||||
struct wp_color_representation_manager_v1 *cr_manager;
|
||||
@ -1097,14 +1160,16 @@ gst_wl_window_set_color_representation (GstWlWindow * self,
|
||||
|
||||
static void
|
||||
gst_wl_window_set_colorimetry (GstWlWindow * self,
|
||||
GstVideoColorimetry * colorimetry)
|
||||
const GstVideoColorimetry * colorimetry,
|
||||
const GstVideoMasteringDisplayInfo * minfo,
|
||||
const GstVideoContentLightLevel * linfo)
|
||||
{
|
||||
GST_OBJECT_LOCK (self);
|
||||
|
||||
GST_INFO_OBJECT (self, "Trying to set colorimetry: %s",
|
||||
gst_video_colorimetry_to_string (colorimetry));
|
||||
|
||||
gst_wl_window_set_image_description (self, colorimetry);
|
||||
gst_wl_window_set_image_description (self, colorimetry, minfo, linfo);
|
||||
gst_wl_window_set_color_representation (self, colorimetry);
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
@ -63,6 +63,11 @@ GST_WL_API
|
||||
gboolean gst_wl_window_render (GstWlWindow * self, GstWlBuffer * buffer,
|
||||
const GstVideoInfo * info);
|
||||
|
||||
GST_WL_API
|
||||
gboolean gst_wl_window_render_hdr (GstWlWindow * self, GstWlBuffer * buffer,
|
||||
const GstVideoInfo * info, const GstVideoMasteringDisplayInfo *minfo,
|
||||
const GstVideoContentLightLevel *linfo);
|
||||
|
||||
GST_WL_API
|
||||
void gst_wl_window_set_render_rectangle (GstWlWindow * self, gint x, gint y,
|
||||
gint w, gint h);
|
||||
|
Loading…
x
Reference in New Issue
Block a user