[vlc-commits] [Git][videolan/vlc][master] 5 commits: vout: display: window: add ICC profile glue

Hugo Beauzée-Luyssen (@chouquette) gitlab at videolan.org
Sun Aug 7 12:19:44 UTC 2022



Hugo Beauzée-Luyssen pushed to branch master at VideoLAN / VLC


Commits:
354f3aae by Niklas Haas at 2022-08-07T11:58:21+00:00
vout: display: window: add ICC profile glue

The window backend triggers a callback of the vout, and the vout
forwards this to the display using another callback. There are several
unfortunate layers of glue and indirections in the callchain. In
particular, we need to persist these ICC profile objects in some layer,
because of init order between windowing system and the window / vout
display module itself. I've chosen to add them to `vout_display_cfg_t`
because it fits well with the other "dynamic window state" properties in
there.

This approach also allows capable vouts to read directly from the
allocated ICC profile memory, minimizing the number of memcpys.

- - - - -
690f6335 by Niklas Haas at 2022-08-07T11:58:21+00:00
vout: libplacebo: add support for display ICC profiles

Pretty straightforward. Rather than wasting cycles computing a checksum
each frame, just update the signature once per received ICC change
control event.

- - - - -
927db833 by Niklas Haas at 2022-08-07T11:58:21+00:00
xcb/window: keep track of displays using RandR

This is non-functional on its own, but introduces necessary display
tracking information that will be useful in the following commit(s),
like figuring out which display's ICC profile to query for the VLC
window.

- - - - -
8e88fd24 by Niklas Haas at 2022-08-07T11:58:21+00:00
xcb/window: move helper function

Needed for RandR-related code in future commit.

- - - - -
4823a53b by Niklas Haas at 2022-08-07T11:58:21+00:00
xcb/window: track and report ICC profile changes

We need to update the ICC profile either if the window moves to a new
display, or if the root window atom associated with a given display is
updated. To this end, we need to start tracking property changes on the
root window, as well as updating this atom every time the window moves
to a new display.

Unfortunately, this code again requires one memcpy more than I'd like to
have there, as a result of xcb not letting me fetch properties into my
own buffers. If we determine this to be a performance issue later on,
the straightforward fix would be to make vlc_icc_profile_t refcounted
with a custom free callback.

- - - - -


10 changed files:

- include/vlc_vout_display.h
- include/vlc_window.h
- modules/video_output/libplacebo/display.c
- modules/video_output/xcb/Makefile.am
- modules/video_output/xcb/window.c
- src/video_output/display.c
- src/video_output/video_output.c
- src/video_output/video_window.c
- src/video_output/vout_internal.h
- src/video_output/vout_wrapper.h


Changes:

=====================================
include/vlc_vout_display.h
=====================================
@@ -116,6 +116,7 @@ struct vout_display_placement {
 typedef struct vout_display_cfg {
     struct vlc_window *window; /**< Window */
     struct vout_display_placement display; /**< Display placement properties */
+    vlc_icc_profile_t *icc_profile; /**< Currently active ICC profile */
     vlc_viewpoint_t viewpoint;
 } vout_display_cfg_t;
 
@@ -310,6 +311,15 @@ struct vlc_display_operations
      * \param vp viewpoint to use on the next render
      */
     int        (*set_viewpoint)(vout_display_t *, const vlc_viewpoint_t *vp);
+
+    /**
+     * Notifies a change in output ICC profile.
+     *
+     * May be NULL. Memory owned by the caller.
+     *
+     * \param prof new ICC profile associated with display, or NULL for none
+     */
+    void       (*set_icc_profile)(vout_display_t *, const vlc_icc_profile_t *prof);
 };
 
 struct vout_display_t {


=====================================
include/vlc_window.h
=====================================
@@ -43,6 +43,7 @@
 struct vlc_window;
 struct wl_display;
 struct wl_surface;
+typedef struct vlc_icc_profile_t vlc_icc_profile_t;
 
 /**
  * Window handle type.
@@ -311,6 +312,18 @@ struct vlc_window_callbacks {
      */
     void (*output_event)(struct vlc_window *,
                          const char *id, const char *desc);
+
+    /**
+     * Callback for ICC profile update.
+     *
+     * This can happen either because of the window being moved to a different
+     * display, or because the ICC profile associated with a display is
+     * updated. Memory transfers to the callee.
+     *
+     * \param profile ICC profile associated with the window, or NULL to
+     *                indicate absence of an ICC profile
+     */
+    void (*icc_event)(struct vlc_window *, vlc_icc_profile_t *profile);
 };
 
 /**
@@ -735,6 +748,22 @@ static inline void vlc_window_ReportOutputDevice(vlc_window_t *window,
         window->owner.cbs->output_event(window, id, name);
 }
 
+/**
+ * Reports a change to the currently active ICC profile.
+ *
+ * \param window the window reporting the ICC profile
+ * \param prof the profile data, or NULL. Ownership transfers to callee
+ */
+static inline void vlc_window_ReportICCProfile(vlc_window_t *window,
+                                               vlc_icc_profile_t *prof)
+{
+    if (window->owner.cbs->icc_event != NULL) {
+        window->owner.cbs->icc_event(window, prof);
+    } else {
+        free(prof);
+    }
+}
+
 /** @} */
 /** @} */
 #endif /* VLC_WINDOW_H */


=====================================
modules/video_output/libplacebo/display.c
=====================================
@@ -73,6 +73,7 @@ typedef struct vout_display_sys_t
     struct pl_dither_params dither;
     struct pl_render_params params;
     struct pl_color_space target;
+    uint64_t target_icc_signature;
     struct pl_peak_detect_params peak_detect;
     enum pl_chroma_location yuv_chroma_loc;
     int dither_depth;
@@ -98,12 +99,14 @@ static int Control(vout_display_t *, int);
 static void Close(vout_display_t *);
 static void UpdateParams(vout_display_t *);
 static void UpdateColorspaceHint(vout_display_t *, const video_format_t *);
+static void UpdateIccProfile(vout_display_t *, const vlc_icc_profile_t *);
 
 static const struct vlc_display_operations ops = {
     .close = Close,
     .prepare = PictureRender,
     .display = PictureDisplay,
     .control = Control,
+    .set_icc_profile = UpdateIccProfile,
 };
 
 static int Open(vout_display_t *vd,
@@ -291,6 +294,11 @@ static void PictureRender(vout_display_t *vd, picture_t *pic,
 
     struct pl_render_target target;
     pl_render_target_from_swapchain(&target, &frame);
+    if (vd->cfg->icc_profile) {
+        target.profile.signature = sys->target_icc_signature;
+        target.profile.data = vd->cfg->icc_profile->data;
+        target.profile.len = vd->cfg->icc_profile->size;
+    }
 
     // Set the target crop dynamically based on the swapchain flip state
     vout_display_place_t place;
@@ -524,6 +532,13 @@ static void UpdateColorspaceHint(vout_display_t *vd, const video_format_t *fmt)
 #endif
 }
 
+static void UpdateIccProfile(vout_display_t *vd, const vlc_icc_profile_t *prof)
+{
+    vout_display_sys_t *sys = vd->sys;
+    sys->target_icc_signature++;
+    (void) prof; /* we get the current value from vout_display_cfg_t */
+}
+
 static int Control(vout_display_t *vd, int query)
 {
     vout_display_sys_t *sys = vd->sys;


=====================================
modules/video_output/xcb/Makefile.am
=====================================
@@ -28,9 +28,10 @@ libxcb_window_plugin_la_SOURCES = video_output/xcb/window.c
 libxcb_window_plugin_la_CFLAGS = $(AM_CFLAGS) \
 	$(CFLAGS_xcb_window) \
 	$(XPROTO_CFLAGS) $(XCB_CFLAGS) \
-	$(XCB_XKB_CFLAGS) $(XKBCOMMON_X11_CFLAGS)
+	$(XCB_XKB_CFLAGS) $(XKBCOMMON_X11_CFLAGS) \
+	$(XCB_RANDR_CFLAGS)
 libxcb_window_plugin_la_LIBADD = $(XPROTO_LIBS) $(XCB_LIBS) \
-	$(XCB_XKB_LIBS) $(XKBCOMMON_X11_LIBS)
+	$(XCB_XKB_LIBS) $(XKBCOMMON_X11_LIBS) $(XCB_RANDR_LIBS)
 
 libxcb_egl_plugin_la_SOURCES = video_output/opengl/egl.c
 libxcb_egl_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -DUSE_PLATFORM_XCB=1


=====================================
modules/video_output/xcb/window.c
=====================================
@@ -36,6 +36,7 @@
 #endif
 
 #include <xcb/xcb.h>
+#include <xcb/randr.h>
 #ifdef HAVE_XKBCOMMON
 # include <xcb/xkb.h>
 # include <xkbcommon/xkbcommon-x11.h>
@@ -48,6 +49,7 @@ typedef xcb_atom_t Atom;
 #include <vlc_plugin.h>
 #include <vlc_actions.h>
 #include <vlc_window.h>
+#include <vlc_es.h>
 
 typedef struct
 {
@@ -62,6 +64,19 @@ typedef struct
     xcb_atom_t wm_state_fullscreen;
     xcb_atom_t motif_wm_hints;
 
+    uint8_t event_randr; /* event id of XCB_RANDR_NOTIFY, or 0 if disabled */
+    struct
+    {
+        xcb_randr_crtc_t crtc;
+        int x;
+        int y;
+        int width;
+        int height;
+    } *displays;
+    int num_displays;
+    int current_display;
+    xcb_atom_t icc_atom;
+
 #ifdef HAVE_XKBCOMMON
     struct
     {
@@ -73,6 +88,29 @@ typedef struct
 #endif
 } vout_window_sys_t;
 
+/** Request the X11 server to internalize a string into an atom */
+static inline
+xcb_intern_atom_cookie_t intern_string (xcb_connection_t *c, const char *s)
+{
+    return xcb_intern_atom (c, 0, strlen (s), s);
+}
+
+/** Extract the X11 atom from an intern request cookie */
+static
+xcb_atom_t get_atom (xcb_connection_t *conn, xcb_intern_atom_cookie_t ck)
+{
+    xcb_intern_atom_reply_t *reply;
+    xcb_atom_t atom;
+
+    reply = xcb_intern_atom_reply (conn, ck, NULL);
+    if (reply == NULL)
+        return 0;
+
+    atom = reply->atom;
+    free (reply);
+    return atom;
+}
+
 #ifdef HAVE_XKBCOMMON
 static int InitKeyboard(vlc_window_t *wnd)
 {
@@ -215,6 +253,212 @@ static void DeinitKeyboardExtension(vlc_window_t *wnd)
 # define DeinitKeyboardExtension(w) ((void)(w))
 #endif
 
+static int InitRandR(vlc_window_t *wnd)
+{
+    vout_window_sys_t *sys = wnd->sys;
+    xcb_connection_t *conn = sys->conn;
+    sys->event_randr = 0;
+
+    const xcb_query_extension_reply_t *e =
+        xcb_get_extension_data(conn, &xcb_randr_id);
+    if (!e || !e->present)
+        return VLC_ENOTSUP;
+
+    xcb_randr_query_version_reply_t *v =
+        xcb_randr_query_version_reply(conn,
+            xcb_randr_query_version(conn, 1, 2), NULL);
+    if (v == NULL)
+        return VLC_ENOTSUP;
+
+    sys->event_randr = e->first_event + XCB_RANDR_NOTIFY;
+    msg_Dbg(wnd, "using X RandR extension v%"PRIu32".%"PRIu32,
+            v->major_version, v->minor_version);
+
+    free(v);
+    xcb_randr_select_input(conn, sys->root, XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE |
+                                            XCB_RANDR_NOTIFY_MASK_RESOURCE_CHANGE);
+    return VLC_SUCCESS;
+}
+
+static int UpdateDisplays(vlc_window_t *wnd)
+{
+    vout_window_sys_t *sys = wnd->sys;
+    xcb_connection_t *conn = sys->conn;
+
+    xcb_randr_get_screen_resources_reply_t *res =
+        xcb_randr_get_screen_resources_reply(conn,
+            xcb_randr_get_screen_resources(conn, sys->root), NULL);
+    if (res == NULL)
+        return VLC_EGENERIC;
+
+    const xcb_randr_output_t *outs = xcb_randr_get_screen_resources_outputs(res);
+    sys->num_displays = 0;
+    sys->current_display = -1;
+    sys->displays = vlc_reallocarray(sys->displays, res->num_outputs,
+                                     sizeof(sys->displays[0]));
+    if (sys->displays == NULL) {
+        free(res);
+        return VLC_ENOMEM;
+    }
+
+    struct {
+        xcb_randr_get_output_info_reply_t *info;
+        xcb_randr_get_output_info_cookie_t oic;
+        xcb_randr_get_crtc_info_cookie_t cic;
+    } *tmp = vlc_reallocarray(NULL, res->num_outputs, sizeof(tmp[0]));
+    if (tmp == NULL) {
+        free(res);
+        return VLC_ENOMEM;
+    }
+
+    for (unsigned i = 0; i < res->num_outputs; i++)
+        tmp[i].oic = xcb_randr_get_output_info(conn, outs[i], res->config_timestamp);
+
+    for (unsigned i = 0; i < res->num_outputs; i++) {
+        tmp[i].info = xcb_randr_get_output_info_reply(conn, tmp[i].oic, NULL);
+        if (tmp[i].info) {
+            tmp[i].cic = xcb_randr_get_crtc_info(conn, tmp[i].info->crtc,
+                                                 res->config_timestamp);
+        }
+    }
+
+    for (unsigned i = 0; i < res->num_outputs; i++) {
+        if (!tmp[i].info)
+            continue;
+        xcb_randr_get_crtc_info_reply_t *crtc =
+            xcb_randr_get_crtc_info_reply(conn, tmp[i].cic, NULL);
+        if (crtc) {
+            int idx = sys->num_displays++;
+            assert(idx < res->num_outputs);
+            sys->displays[idx].crtc = tmp[i].info->crtc;
+            sys->displays[idx].x = crtc->x;
+            sys->displays[idx].y = crtc->y;
+            sys->displays[idx].width = crtc->width;
+            sys->displays[idx].height = crtc->height;
+            free(crtc);
+        }
+        free(tmp[i].info);
+    }
+
+    free(tmp);
+    free(res);
+    return VLC_SUCCESS;
+}
+
+static void ProcessRandREvent(vlc_window_t *wnd, xcb_generic_event_t *gev)
+{
+    xcb_randr_notify_event_t *ev = (xcb_randr_notify_event_t *) gev;
+    vout_window_sys_t *sys = wnd->sys;
+
+    switch (ev->subCode) {
+    case XCB_RANDR_NOTIFY_RESOURCE_CHANGE:
+        UpdateDisplays(wnd);
+        break;
+    case XCB_RANDR_NOTIFY_CRTC_CHANGE:
+        for (int i = 0; i < sys->num_displays; i++) {
+            const xcb_randr_crtc_change_t *cc = &ev->u.cc;
+            if (sys->displays[i].crtc != cc->crtc)
+                continue;
+            sys->displays[i].x = cc->x;
+            sys->displays[i].y = cc->y;
+            sys->displays[i].width = cc->width;
+            sys->displays[i].height = cc->height;
+            break;
+        }
+        break;
+    }
+}
+
+static void UpdateICCProfile(vlc_window_t *wnd)
+{
+    vout_window_sys_t *sys = wnd->sys;
+    xcb_connection_t *conn = sys->conn;
+
+    if (sys->icc_atom == XCB_ATOM_NONE) {
+        vlc_window_ReportICCProfile(wnd, NULL);
+        return;
+    }
+
+    long max_length = 32 * 1024 * 1024; /* corresponds to 128 MiB */
+    xcb_get_property_reply_t *r =
+        xcb_get_property_reply(conn,
+            xcb_get_property(conn, false, sys->root, sys->icc_atom,
+                             XCB_ATOM_CARDINAL, 0, max_length), NULL);
+    if (!r || r->response_type == XCB_ATOM_NONE || !r->length || r->bytes_after) {
+        vlc_window_ReportICCProfile(wnd, NULL);
+        free(r);
+        return;
+    }
+
+    int len = xcb_get_property_value_length(r);
+    struct vlc_icc_profile_t *icc = malloc(sizeof(*icc) + len);
+    if (icc) {
+        icc->size = len;
+        memcpy(icc->data, xcb_get_property_value(r), len);
+        vlc_window_ReportICCProfile(wnd, icc);
+    }
+    free(r);
+}
+
+/** Get ID of closest display to a position, or -1 if no displays */
+static int DisplayForCoords(vlc_window_t *wnd, int xpos, int ypos)
+{
+    vout_window_sys_t *sys = wnd->sys;
+    if (sys->num_displays == 0)
+        return -1;
+
+    int best = 0, idx = -1;
+    for (int i = 0; i < sys->num_displays; i++) {
+        int xclip = VLC_CLIP(xpos, sys->displays[i].x,
+                             sys->displays[i].x + sys->displays[i].width);
+        int yclip = VLC_CLIP(xpos, sys->displays[i].y,
+                             sys->displays[i].y + sys->displays[i].height);
+        int delta = abs(xpos - xclip) + abs(ypos - yclip);
+        if (delta == 0)
+            return i; /* display contains point */
+
+        if (i == 0 || best < delta) {
+            best = delta;
+            idx = i;
+        }
+    }
+
+    return idx;
+}
+
+static void DisplayChanged(vlc_window_t *wnd, int new_display)
+{
+    vout_window_sys_t *sys = wnd->sys;
+    xcb_connection_t *conn = sys->conn;
+
+    char icc_prop[32];
+    if (new_display > 0) {
+        snprintf(icc_prop, sizeof(icc_prop), "_ICC_PROFILE_%d", new_display);
+    } else {
+        assert(new_display == 0);
+        strcpy(icc_prop, "_ICC_PROFILE");
+    }
+
+    sys->icc_atom = get_atom(conn, intern_string(conn, icc_prop));
+    UpdateICCProfile(wnd);
+}
+
+static void UpdateGeometry(vlc_window_t *wnd, unsigned x, unsigned y,
+                           unsigned width, unsigned height)
+{
+    vout_window_sys_t *sys = wnd->sys;
+    vlc_window_ReportSize(wnd, width, height);
+
+    /* Detect window center moving across display boundaries */
+    unsigned xcenter = x + (width >> 1);
+    unsigned ycenter = y + (height >> 1);
+    int disp = DisplayForCoords(wnd, xcenter, ycenter);
+    if (disp != -1 && disp != sys->current_display) {
+        sys->current_display = disp;
+        DisplayChanged(wnd, disp);
+    }
+}
+
 static xcb_cursor_t CursorCreate(xcb_connection_t *conn, xcb_window_t root)
 {
     xcb_cursor_t cur = xcb_generate_id(conn);
@@ -227,9 +471,7 @@ static xcb_cursor_t CursorCreate(xcb_connection_t *conn, xcb_window_t root)
 
 static int ProcessEvent(vlc_window_t *wnd, xcb_generic_event_t *ev)
 {
-#ifdef HAVE_XKBCOMMON
     vout_window_sys_t *sys = wnd->sys;
-#endif
     int ret = 0;
 
     switch (ev->response_type & 0x7f)
@@ -284,7 +526,7 @@ static int ProcessEvent(vlc_window_t *wnd, xcb_generic_event_t *ev)
         case XCB_CONFIGURE_NOTIFY:
         {
             xcb_configure_notify_event_t *cne = (void *)ev;
-            vlc_window_ReportSize (wnd, cne->width, cne->height);
+            UpdateGeometry(wnd, cne->x, cne->y, cne->width, cne->height);
             break;
         }
         case XCB_DESTROY_NOTIFY:
@@ -304,6 +546,14 @@ static int ProcessEvent(vlc_window_t *wnd, xcb_generic_event_t *ev)
         case XCB_MAPPING_NOTIFY:
             break;
 
+        case XCB_PROPERTY_NOTIFY:
+        {
+            xcb_property_notify_event_t *pne = (void *)ev;
+            if (pne->atom == sys->icc_atom)
+                UpdateICCProfile(wnd);
+            break;
+        }
+
         default:
 #ifdef HAVE_XKBCOMMON
             if (sys->xkb.ctx != NULL && ev->response_type == sys->xkb.base)
@@ -312,6 +562,12 @@ static int ProcessEvent(vlc_window_t *wnd, xcb_generic_event_t *ev)
                 break;
             }
 #endif
+            if (sys->event_randr && ev->response_type == sys->event_randr)
+            {
+                ProcessRandREvent(wnd, ev);
+                break;
+            }
+
             msg_Dbg (wnd, "unhandled event %"PRIu8, ev->response_type);
     }
 
@@ -345,6 +601,11 @@ static void *Thread (void *data)
     /* Report initial window size (for the embedded case). */
     xcb_get_geometry_cookie_t ggc = xcb_get_geometry(conn, window);
 
+    if (p_sys->event_randr) {
+        p_sys->displays = NULL;
+        UpdateDisplays(wnd);
+    }
+
     xcb_query_pointer_reply_t *qpr = xcb_query_pointer_reply(conn, qpc, NULL);
     if (qpr != NULL) {
         while ((ev = xcb_poll_for_queued_event(conn)) != NULL)
@@ -357,7 +618,7 @@ static void *Thread (void *data)
     if (geo != NULL) {
         while ((ev = xcb_poll_for_queued_event(conn)) != NULL)
             ProcessEvent(wnd, ev);
-        vlc_window_ReportSize(wnd, geo->width, geo->height);
+        UpdateGeometry(wnd, geo->x, geo->y, geo->width, geo->height);
         free(geo);
     }
     vlc_latch_count_down(&p_sys->ready, 1);
@@ -532,29 +793,6 @@ void set_hostname_prop (xcb_connection_t *conn, xcb_window_t window)
     free(hostname);
 }
 
-/** Request the X11 server to internalize a string into an atom */
-static inline
-xcb_intern_atom_cookie_t intern_string (xcb_connection_t *c, const char *s)
-{
-    return xcb_intern_atom (c, 0, strlen (s), s);
-}
-
-/** Extract the X11 atom from an intern request cookie */
-static
-xcb_atom_t get_atom (xcb_connection_t *conn, xcb_intern_atom_cookie_t ck)
-{
-    xcb_intern_atom_reply_t *reply;
-    xcb_atom_t atom;
-
-    reply = xcb_intern_atom_reply (conn, ck, NULL);
-    if (reply == NULL)
-        return 0;
-
-    atom = reply->atom;
-    free (reply);
-    return atom;
-}
-
 static int Enable(vlc_window_t *wnd, const vlc_window_cfg_t *restrict cfg)
 {
     vout_window_sys_t *sys = wnd->sys;
@@ -603,7 +841,8 @@ static const struct vlc_window_operations ops = {
 };
 
 static int OpenCommon(vlc_window_t *wnd, char *display, xcb_connection_t *conn,
-                      xcb_window_t root, xcb_window_t window, uint32_t events)
+                      xcb_window_t root, xcb_window_t window, uint32_t events,
+                      uint32_t evroot)
 {
     vout_window_sys_t *sys = vlc_obj_malloc(VLC_OBJECT(wnd), sizeof (*sys));
     if (sys == NULL)
@@ -625,6 +864,13 @@ static int OpenCommon(vlc_window_t *wnd, char *display, xcb_connection_t *conn,
         sys->xkb.ctx = NULL;
 #endif
 
+    if (InitRandR(wnd) == VLC_SUCCESS) {
+        /* Start tracking ICC profile changes */
+        evroot |= XCB_EVENT_MASK_PROPERTY_CHANGE;
+        xcb_change_window_attributes(conn, sys->root, XCB_CW_EVENT_MASK, &evroot);
+        sys->icc_atom = XCB_ATOM_NONE;
+    }
+
     /* ICCCM */
     /* No cut&paste nor drag&drop, only Window Manager communication. */
     set_ascii_prop(conn, window, XA_WM_NAME,
@@ -766,7 +1012,7 @@ static int Open(vlc_window_t *wnd)
         goto error;
     }
 
-    ret = OpenCommon(wnd, display, conn, scr->root, window, values[1]);
+    ret = OpenCommon(wnd, display, conn, scr->root, window, values[1], 0);
     if (ret != VLC_SUCCESS)
         goto error;
 
@@ -935,7 +1181,8 @@ static int EmOpen (vlc_window_t *wnd)
 
     xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK, &value);
 
-    ret = OpenCommon(wnd, NULL, conn, root, window, value);
+    uint32_t evroot = (root == window) ? value : 0;
+    ret = OpenCommon(wnd, NULL, conn, root, window, value, evroot);
     if (ret != VLC_SUCCESS)
         goto error;
 


=====================================
src/video_output/display.c
=====================================
@@ -629,6 +629,15 @@ void vout_SetDisplayViewpoint(vout_display_t *vd,
     }
 }
 
+void vout_SetDisplayIccProfile(vout_display_t *vd,
+                               const vlc_icc_profile_t *profile)
+{
+    vout_display_priv_t *osys = container_of(vd, vout_display_priv_t, display);
+
+    if (vd->ops->set_icc_profile)
+        vd->ops->set_icc_profile(vd, profile);
+}
+
 vout_display_t *vout_display_New(vlc_object_t *parent,
                                  const video_format_t *source,
                                  vlc_video_context *vctx,


=====================================
src/video_output/video_output.c
=====================================
@@ -652,6 +652,24 @@ void vout_ChangeViewpoint(vout_thread_t *vout,
     vlc_mutex_unlock(&sys->display_lock);
 }
 
+void vout_ChangeIccProfile(vout_thread_t *vout,
+                           vlc_icc_profile_t *profile)
+{
+    vout_thread_sys_t *sys = VOUT_THREAD_TO_SYS(vout);
+    assert(!sys->dummy);
+
+    vlc_mutex_lock(&sys->window_lock);
+    free(sys->display_cfg.icc_profile);
+    sys->display_cfg.icc_profile = profile;
+
+    vlc_mutex_lock(&sys->display_lock);
+    vlc_mutex_unlock(&sys->window_lock);
+
+    if (sys->display != NULL)
+        vout_SetDisplayIccProfile(sys->display, profile);
+    vlc_mutex_unlock(&sys->display_lock);
+}
+
 /* */
 static void VoutGetDisplayCfg(vout_thread_sys_t *p_vout, const video_format_t *fmt, vout_display_cfg_t *cfg)
 {
@@ -1883,6 +1901,7 @@ void vout_Release(vout_thread_t *vout)
     }
 
     free(sys->splitter_name);
+    free(sys->display_cfg.icc_profile);
 
     if (sys->dec_device)
         vlc_decoder_device_Release(sys->dec_device);
@@ -1989,6 +2008,7 @@ vout_thread_t *vout_Create(vlc_object_t *object)
 
     /* Display */
     sys->display = NULL;
+    sys->display_cfg.icc_profile = NULL;
     vlc_mutex_init(&sys->display_lock);
 
     /* Window */


=====================================
src/video_output/video_window.c
=====================================
@@ -225,6 +225,20 @@ static void vout_display_window_OutputEvent(vlc_window_t *window,
         msg_Dbg(window, "fullscreen output %s removed", name);
 }
 
+static void vout_display_window_IccEvent(vlc_window_t *window,
+                                         vlc_icc_profile_t *profile)
+{
+    vout_display_window_t *state = window->owner.sys;
+    vout_thread_t *vout = state->vout;
+
+    if (profile != NULL)
+        msg_Dbg(window, "window got ICC profile (%zu bytes)", profile->size);
+    else
+        msg_Dbg(window, "window ICC profile cleared");
+
+    vout_ChangeIccProfile(vout, profile);
+}
+
 static const struct vlc_window_callbacks vout_display_window_cbs = {
     .resized = vout_display_window_ResizeNotify,
     .closed = vout_display_window_CloseNotify,
@@ -234,6 +248,7 @@ static const struct vlc_window_callbacks vout_display_window_cbs = {
     .mouse_event = vout_display_window_MouseEvent,
     .keyboard_event = vout_display_window_KeyboardEvent,
     .output_event = vout_display_window_OutputEvent,
+    .icc_event = vout_display_window_IccEvent,
 };
 
 void vout_display_window_SetMouseHandler(vlc_window_t *window,


=====================================
src/video_output/vout_internal.h
=====================================
@@ -164,6 +164,7 @@ void vout_ControlChangeSubSources(vout_thread_t *, const char *);
 void vout_ControlChangeSubFilters(vout_thread_t *, const char *);
 void vout_ChangeSpuChannelMargin(vout_thread_t *, enum vlc_vout_order order, int);
 void vout_ChangeViewpoint( vout_thread_t *, const vlc_viewpoint_t *);
+void vout_ChangeIccProfile(vout_thread_t *, vlc_icc_profile_t *);
 
 void vout_FilterMouse(vout_thread_t *vout, vlc_mouse_t *mouse);
 


=====================================
src/video_output/vout_wrapper.h
=====================================
@@ -39,6 +39,7 @@ void vout_SetDisplayZoom(vout_display_t *, unsigned num, unsigned den);
 void vout_SetDisplayAspect(vout_display_t *, unsigned num, unsigned den);
 void vout_SetDisplayCrop(vout_display_t *, const struct vout_crop *);
 void vout_SetDisplayViewpoint(vout_display_t *, const vlc_viewpoint_t *);
+void vout_SetDisplayIccProfile(vout_display_t *, const vlc_icc_profile_t *);
 
 #endif /* LIBVLC_VOUT_WRAPPER_H */
 



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/9d2f5d612583c7a781e7160e8d75dcb3f09eb94e...4823a53b7ba7fd11707c107a1ffc72460ff1cc1a

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/9d2f5d612583c7a781e7160e8d75dcb3f09eb94e...4823a53b7ba7fd11707c107a1ffc72460ff1cc1a
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list