From 85be38aed104e41311763361052364f02702d8b4 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 20 Mar 2022 22:58:36 +0100 Subject: ilmControl: Extend screenshot API with callback support Extend the screenshot API such that it permits user to add their own hooks into screenshot_done and screenshot_err callbacks. This way, the user can obtain the FD with the screenshot and process it instead of having the screenshot written into a file in /tmp directory. Make the filename optional, so the user can provide only the callbacks and skip writing the file into /tmp altogether. The library ABI is unaffected, the new functionality is added via two library functions, ilm_takeScreenshot5() and ilm_takeSurfaceScreenshot5(), which are now internally called by their original counterparts with callback hooks set to NULL. Signed-off-by: Marek Vasut [khangtb: rename the name of functions, ilm_takeAsyncScreenshot() and ilm_takeAsyncSurfaceScreenshot(). Define typedef for notification callbacks. Correct the minor things. remove the filename input from the function, make the non-blocking] Signed-off-by: Tran Ba Khang(MS/EMC31-XC) --- .../ilmCommon/include/ilm_types.h | 29 +++++ .../ilmControl/include/ilm_control.h | 35 +++++ .../ilmControl/src/ilm_control_wayland_platform.c | 145 ++++++++++++++++----- 3 files changed, 180 insertions(+), 29 deletions(-) diff --git a/ivi-layermanagement-api/ilmCommon/include/ilm_types.h b/ivi-layermanagement-api/ilmCommon/include/ilm_types.h index 98a8e62..64e30a7 100644 --- a/ivi-layermanagement-api/ilmCommon/include/ilm_types.h +++ b/ivi-layermanagement-api/ilmCommon/include/ilm_types.h @@ -287,4 +287,33 @@ typedef void(*notificationFunc)(ilmObjectType object, typedef void(*shutdownNotificationFunc)(t_ilm_shutdown_error_type error_type, int errornum, void* user_data); + +/** + * Typedef for notification callback on screenshot send done event + * @param user_data the use data, be passed when call the screenshot api + * @param fd fd for file containing image data, don't close it in callback, + * it will be closed and shouldn't be accessed any longer after the callback execution. + * @param width image width in pixels + * @param height image height in pixels + * @param stride number of bytes per pixel row + * @param format image format of type wl_shm.format + * @param timestamp timestamp in milliseconds + */ +typedef ilmErrorTypes(*screenshotDoneNotificationFunc)(void *user_data, + t_ilm_int fd, + t_ilm_uint width, + t_ilm_uint height, + t_ilm_uint stride, + t_ilm_uint format, + t_ilm_uint timestamp); + +/** + * Typedef for notification callback on screenshot send error event + * @param user_data the use data, be passed when call the screenshot api + * @param error error code + * @param message error description + */ +typedef void(*screenshotErrorNotificationFunc)(void *user_data, + t_ilm_uint error, + const char *message); #endif /* _ILM_TYPES_H_*/ diff --git a/ivi-layermanagement-api/ilmControl/include/ilm_control.h b/ivi-layermanagement-api/ilmControl/include/ilm_control.h index 71e4968..c67152a 100644 --- a/ivi-layermanagement-api/ilmControl/include/ilm_control.h +++ b/ivi-layermanagement-api/ilmControl/include/ilm_control.h @@ -365,6 +365,23 @@ ilmErrorTypes ilm_displaySetRenderOrder(t_ilm_display display, t_ilm_layer *pLay */ ilmErrorTypes ilm_takeScreenshot(t_ilm_uint screen, t_ilm_const_string filename); +/** + * \brief Take a screenshot from the current displayed layer scene with non-blocking. + * The function allows to setup callbacks when capturing the display, + * It helps to avoid a blocking, user can handle screenshot data or error in + * the callbacks. + * \param[in] screen Id of screen where screenshot should be taken + * \param[in] callback_done callback called when screenshot is acquired + * \param[in] callback_error callback called when screenshot acqusition failed + * \param[in] user_data callback user data passed in by called + * \return ILM_SUCCESS if the method call was successful + * \return ILM_FAILED if the client can not call the method on the service. + */ +ilmErrorTypes ilm_takeAsyncScreenshot(t_ilm_uint screen, + screenshotDoneNotificationFunc callback_done, + screenshotErrorNotificationFunc callback_error, + void *user_data); + /** * \brief Take a screenshot of a certain surface * The screenshot is saved as bmp file with the corresponding filename. @@ -376,6 +393,24 @@ ilmErrorTypes ilm_takeScreenshot(t_ilm_uint screen, t_ilm_const_string filename) */ ilmErrorTypes ilm_takeSurfaceScreenshot(t_ilm_const_string filename, t_ilm_surface surfaceid); +/** + * \brief Take a screenshot of a certain surface with non-blocking. + * The function allows to setup callbacks when capturing a surface, + * It helps to avoid a blocking, user can handle screenshot data or error in + * the callbacks. + * \ingroup ilmControl + * \param[in] surfaceid Identifier of the surface to take the screenshot of + * \param[in] callback_done callback called when screenshot is acquired + * \param[in] callback_error callback called when screenshot acqusition failed + * \param[in] user_data callback user data passed in by called + * \return ILM_SUCCESS if the method call was successful + * \return ILM_FAILED if the client can not call the method on the service. + */ +ilmErrorTypes ilm_takeAsyncSurfaceScreenshot(t_ilm_surface surfaceid, + screenshotDoneNotificationFunc callback_done, + screenshotErrorNotificationFunc callback_error, + void *user_data); + /** * \brief register for notification on property changes of layer * \ingroup ilmControl diff --git a/ivi-layermanagement-api/ilmControl/src/ilm_control_wayland_platform.c b/ivi-layermanagement-api/ilmControl/src/ilm_control_wayland_platform.c index b4fdfbf..97e4e6d 100644 --- a/ivi-layermanagement-api/ilmControl/src/ilm_control_wayland_platform.c +++ b/ivi-layermanagement-api/ilmControl/src/ilm_control_wayland_platform.c @@ -70,6 +70,9 @@ struct screen_context { struct screenshot_context { const char *filename; ilmErrorTypes result; + screenshotDoneNotificationFunc callback_done; + screenshotErrorNotificationFunc callback_error; + void *callback_priv; }; static inline void lock_context(struct ilm_control_context *ctx) @@ -2126,9 +2129,17 @@ static void screenshot_done(void *data, struct ivi_screenshot *ivi_screenshot, ctx_scrshot->filename = NULL; ivi_screenshot_destroy(ivi_screenshot); - if (filename == NULL) { - ctx_scrshot->result = ILM_FAILED; - fprintf(stderr, "screenshot file name not provided: %m\n"); + if (ctx_scrshot->callback_done) + if (ctx_scrshot->callback_done(ctx_scrshot->callback_priv, + fd, width, height, stride, format, timestamp) == ILM_FAILED) { + ctx_scrshot->result = ILM_FAILED; + close(fd); + return; + } + // if filename is null, free resource and return + if (!filename) { + close(fd); + free(ctx_scrshot); return; } @@ -2170,9 +2181,15 @@ static void screenshot_error(void *data, struct ivi_screenshot *ivi_screenshot, uint32_t error, const char *message) { struct screenshot_context *ctx_scrshot = data; + const char *filename = ctx_scrshot->filename; ctx_scrshot->filename = NULL; ivi_screenshot_destroy(ivi_screenshot); + if (ctx_scrshot->callback_error) + ctx_scrshot->callback_error(ctx_scrshot->callback_priv, error, message); fprintf(stderr, "screenshot failed, error 0x%x: %s\n", error, message); + // free resource + if (!filename) + free(ctx_scrshot); } static struct ivi_screenshot_listener screenshot_listener = { @@ -2180,75 +2197,145 @@ static struct ivi_screenshot_listener screenshot_listener = { screenshot_error, }; -ILM_EXPORT ilmErrorTypes -ilm_takeScreenshot(t_ilm_uint screen, t_ilm_const_string filename) +static ilmErrorTypes +ilm_takeShoot(t_ilm_uint screen, t_ilm_const_string filename, + screenshotDoneNotificationFunc callback_done, + screenshotErrorNotificationFunc callback_error, + void *user_data) { ilmErrorTypes returnValue = ILM_FAILED; struct ilm_control_context *const ctx = &ilm_context; struct screen_context *ctx_scrn = NULL; + // if filename, callback_done and callback_error are null, don't do anything, then return success + if (!filename && !callback_done && !callback_error) { + return ILM_SUCCESS; + } + lock_context(ctx); ctx_scrn = get_screen_context_by_id(&ctx->wl, (uint32_t)screen); if (ctx_scrn != NULL) { - struct screenshot_context ctx_scrshot = { - .filename = filename, - .result = ILM_FAILED, - }; + struct screenshot_context *ctx_scrshot = calloc(1, sizeof(struct screenshot_context)); - struct ivi_screenshot *scrshot = - ivi_wm_screen_screenshot(ctx_scrn->controller); + if (!ctx_scrshot) { + fprintf(stderr, "Failed to allocate memory for screenshot_context\n"); + goto exit; + } + ctx_scrshot->filename = filename; + ctx_scrshot->result = ILM_FAILED; + ctx_scrshot->callback_done = callback_done; + ctx_scrshot->callback_error = callback_error; + ctx_scrshot->callback_priv = user_data; + + struct ivi_screenshot *scrshot = ivi_wm_screen_screenshot(ctx_scrn->controller); if (scrshot) { - ivi_screenshot_add_listener(scrshot, &screenshot_listener, - &ctx_scrshot); + ivi_screenshot_add_listener(scrshot, &screenshot_listener, ctx_scrshot); + // don't need to wait if file name is empty + if (!filename) { + wl_display_flush(ctx->wl.display); + returnValue = ILM_SUCCESS; + goto exit; + } // dispatch until filename has been reset in done or error callback int ret; do { ret = wl_display_dispatch_queue(ctx->wl.display, ctx->wl.queue); - } while ((ret != -1) && ctx_scrshot.filename); + } while ((ret != -1) && ctx_scrshot->filename); - returnValue = ctx_scrshot.result; + returnValue = ctx_scrshot->result; } + free(ctx_scrshot); } +exit: unlock_context(ctx); - return returnValue; } ILM_EXPORT ilmErrorTypes -ilm_takeSurfaceScreenshot(t_ilm_const_string filename, - t_ilm_surface surfaceid) +ilm_takeAsyncScreenshot(t_ilm_uint screen, + screenshotDoneNotificationFunc callback_done, + screenshotErrorNotificationFunc callback_error, + void *user_data) +{ + return ilm_takeShoot(screen, NULL, callback_done, callback_error, user_data); +} + +ILM_EXPORT ilmErrorTypes +ilm_takeScreenshot(t_ilm_uint screen, t_ilm_const_string filename) +{ + return ilm_takeShoot(screen, filename, NULL, NULL, NULL); +} + +static ilmErrorTypes +ilm_takeSurfaceShoot(t_ilm_surface surfaceid, t_ilm_const_string filename, + screenshotDoneNotificationFunc callback_done, + screenshotErrorNotificationFunc callback_error, + void *user_data) { ilmErrorTypes returnValue = ILM_FAILED; struct ilm_control_context *const ctx = &ilm_context; + // if filename, callback_done and callback_error are null, don't do anything, then return success + if (!filename && !callback_done && !callback_error) { + return ILM_SUCCESS; + } + lock_context(ctx); if (ctx->wl.controller) { - struct screenshot_context ctx_scrshot = { - .filename = filename, - .result = ILM_FAILED, - }; + struct screenshot_context *ctx_scrshot = calloc(1, sizeof(struct screenshot_context)); - struct ivi_screenshot *scrshot = - ivi_wm_surface_screenshot(ctx->wl.controller, surfaceid); + if (!ctx_scrshot) { + fprintf(stderr, "Failed to allocate memory for screenshot_context\n"); + goto exit; + } + ctx_scrshot->filename = filename; + ctx_scrshot->result = ILM_FAILED; + ctx_scrshot->callback_done = callback_done; + ctx_scrshot->callback_error = callback_error; + ctx_scrshot->callback_priv = user_data; + + struct ivi_screenshot *scrshot = ivi_wm_surface_screenshot(ctx->wl.controller, surfaceid); if (scrshot) { - ivi_screenshot_add_listener(scrshot, &screenshot_listener, - &ctx_scrshot); + ivi_screenshot_add_listener(scrshot, &screenshot_listener, ctx_scrshot); + // don't need to wait if file name is empty + if (!filename) { + wl_display_flush(ctx->wl.display); + returnValue = ILM_SUCCESS; + goto exit; + } // dispatch until filename has been reset in done or error callback int ret; do { ret = wl_display_dispatch_queue(ctx->wl.display, ctx->wl.queue); - } while ((ret != -1) && ctx_scrshot.filename); + } while ((ret != -1) && ctx_scrshot->filename); - returnValue = ctx_scrshot.result; + returnValue = ctx_scrshot->result; } + free(ctx_scrshot); } +exit: unlock_context(ctx); - return returnValue; } +ILM_EXPORT ilmErrorTypes +ilm_takeAsyncSurfaceScreenshot(t_ilm_surface surfaceid, + screenshotDoneNotificationFunc callback_done, + screenshotErrorNotificationFunc callback_error, + void *user_data) +{ + return ilm_takeSurfaceShoot(surfaceid, NULL, callback_done, callback_error, user_data); +} + +ILM_EXPORT ilmErrorTypes +ilm_takeSurfaceScreenshot(t_ilm_const_string filename, + t_ilm_surface surfaceid) +{ + return ilm_takeSurfaceShoot(surfaceid, filename, NULL, NULL, NULL); +} + ILM_EXPORT ilmErrorTypes ilm_layerAddNotification(t_ilm_layer layer, layerNotificationFunc callback) -- cgit v1.2.1