From ec5cd3457b93d767bc928c3b2d611f4a97541c27 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Sat, 27 Aug 2022 13:28:47 +0900 Subject: [PATCH] screenmirror: init screenmirror if execute start, send tbm_surface to user by set handler until execute stop. sent tbm_surface must be destroyed by user. Change-Id: I6895b37c61001e87786f80bc5b2b68c841d032d9 Signed-off-by: Junkyeong Kim --- include/efl_util_screenshot_extension.h | 102 +++++++++ src/efl_util.c | 394 ++++++++++++++++++++++++++++++++ 2 files changed, 496 insertions(+) diff --git a/include/efl_util_screenshot_extension.h b/include/efl_util_screenshot_extension.h index d3ffc87..50fb8dd 100644 --- a/include/efl_util_screenshot_extension.h +++ b/include/efl_util_screenshot_extension.h @@ -71,6 +71,108 @@ API int efl_util_screenshot_set_auto_rotation(efl_util_screenshot_h screenshot, API int efl_util_screenshot_get_auto_rotation(efl_util_screenshot_h screenshot, int *set); /** + * @platform + * @brief Definition for the screenmirror handle. + * @since_tizen 7.0 + */ +typedef struct _efl_util_screenmirror_h * efl_util_screenmirror_h; + +/** + * @brief The screenmirror handler + * @details This handler will be called when mirror buffer is received. + * @since_tizen 7.0 + */ +typedef void (*efl_util_screenmirror_handler)(efl_util_screenmirror_h screenmirror, + tbm_surface_h t_surface, void *user_data); + +/** + * @platform + * @brief Initializes a screenmirror. + * @since_tizen 7.0 + * @privlevel platform + * @privilege %http://tizen.org/privilege/screenshot + * @remarks The specific error code can be obtained using the get_last_result() + * method. Error codes are described in Exception section. + * @param[in] width width of the screenmirror surface + * @param[in] height height of the screenmirror surface + * @return #efl_util_screenmirror_h on success, otherwise @c NULL + * @retval #efl_util_screenmirror_h The screenmirror handle + * @exception #EFL_UTIL_ERROR_NONE Successful + * @exception #EFL_UTIL_ERROR_INVALID_PARAMETER Invalid parameter + * @exception #EFL_UTIL_ERROR_OUT_OF_MEMORY Memory allocation failure + * @exception #EFL_UTIL_ERROR_SCREENSHOT_INIT_FAIL Initialization failure + * @exception #EFL_UTIL_ERROR_PERMISSION_DENIED No permission for screenmirror + * @see efl_util_screenmirror_deinitialize() + */ +API efl_util_screenmirror_h efl_util_screenmirror_initialize(int width, int height); + +/** + * @platform + * @brief Deinitializes the screenmirror. + * @since_tizen 7.0 + * @privlevel platform + * @privilege %http://tizen.org/privilege/screenshot + * @param[in] screenmirror #efl_util_screenmirror_h handle + * @return @c 0 on success, otherwise a negative error value + * @retval #EFL_UTIL_ERROR_NONE Successful + * @retval #EFL_UTIL_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #EFL_UTIL_ERROR_PERMISSION_DENIED No permission for screenmirror + * @see efl_util_screenmirror_initialize() + */ +API int efl_util_screenmirror_deinitialize(efl_util_screenmirror_h screenmirror); + +/** + * @platform + * @brief Set handler to get screenmirror buffer. + * @since_tizen 7.0 + * @privlevel platform + * @privilege %http://tizen.org/privilege/screenshot + * @param[in] screenmirror #efl_util_screenmirror_h handle + * @param[in] func mirror buffer get handler + * @param[in] data user data + * @return @c 0 on success, otherwise a negative error value + * @retval #EFL_UTIL_ERROR_NONE Successful + * @retval #EFL_UTIL_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #EFL_UTIL_ERROR_PERMISSION_DENIED No permission for screenmirror + * @see efl_util_screenmirror_initialize() + */ +API int efl_util_screenmirror_set_handler(efl_util_screenmirror_h screenmirror, + efl_util_screenmirror_handler func, void *data); + +/** + * @platform + * @brief Start the screenmirror. + * @since_tizen 7.0 + * @privlevel platform + * @privilege %http://tizen.org/privilege/screenshot + * @param[in] screenmirror #efl_util_screenmirror_h handle + * @return @c 0 on success, otherwise a negative error value + * @retval #EFL_UTIL_ERROR_NONE Successful + * @retval #EFL_UTIL_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #EFL_UTIL_ERROR_SCREENSHOT_EXECUTION_FAIL Execution failure + * @retval #EFL_UTIL_ERROR_PERMISSION_DENIED No permission for screenmirror + * @see efl_util_screenmirror_initialize() + */ +API int efl_util_screenmirror_start(efl_util_screenmirror_h screenmirror); + +/** + * @platform + * @brief Stop the screenmirror. + * @since_tizen 7.0 + * @privlevel platform + * @privilege %http://tizen.org/privilege/screenshot + * @param[in] screenmirror #efl_util_screenmirror_h handle + * @return @c 0 on success, otherwise a negative error value + * @retval #EFL_UTIL_ERROR_NONE Successful + * @retval #EFL_UTIL_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #EFL_UTIL_ERROR_SCREENSHOT_EXECUTION_FAIL Execution failure + * @retval #EFL_UTIL_ERROR_PERMISSION_DENIED No permission for screenmirror + * @see efl_util_screenmirror_initialize() + * @see efl_util_screenmirror_start(); + */ +API int efl_util_screenmirror_stop(efl_util_screenmirror_h screenmirror); + +/** * @} */ diff --git a/src/efl_util.c b/src/efl_util.c index 4a837c5..aabd4c2 100644 --- a/src/efl_util.c +++ b/src/efl_util.c @@ -2314,6 +2314,400 @@ efl_util_screenshot_get_auto_rotation(efl_util_screenshot_h screenshot, int *set return EFL_UTIL_ERROR_NONE; } +/* LCOV_EXCL_START */ +struct _efl_util_screenmirror_h +{ + struct tizen_screenmirror *tz_screenmirror; + pthread_t thread; + int width; + int height; + + tbm_bufmgr bufmgr; + Eina_List *buffer_list; + + Eina_Bool mirror_working; + Eina_Bool cb_start; + Eina_Bool cb_stop; + Eina_Bool cb_content; + efl_util_screenmirror_handler user_func; + void *user_data; +}; + +typedef struct _efl_util_mirror_buffer efl_util_mirror_buffer; +struct _efl_util_mirror_buffer +{ + struct wl_buffer *buffer; + int w, h; + tbm_surface_h t_surface; +}; + +static efl_util_screenmirror_h g_screenmirror; + +static void * +_efl_util_screenmirror_loop(void *data) +{ + efl_util_screenmirror_h screenmirror; + int ret = 0; + + screenmirror = (efl_util_screenmirror_h)data; + + while (1) + { + if (!screenmirror->mirror_working) + break; + + ret = wl_display_dispatch_queue(_eflutil.wl.dpy, _eflutil.wl.shot.queue); + if (ret == -1) + { + fprintf(stderr, "[screenmirror] fail: dispatch_queue\n"); + break; + } + } + + return NULL; +} + +static efl_util_mirror_buffer * +_efl_util_create_mirror_buffer(efl_util_screenmirror_h screenmirror) +{ + efl_util_mirror_buffer *mbuffer; + + mbuffer = calloc(1, sizeof(struct _efl_util_mirror_buffer)); + EINA_SAFETY_ON_NULL_RETURN_VAL(mbuffer, NULL); + + mbuffer->w = screenmirror->width; + mbuffer->h = screenmirror->height; + + mbuffer->t_surface = tbm_surface_internal_create_with_flags(mbuffer->w, + mbuffer->h, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT); + EINA_SAFETY_ON_NULL_GOTO(mbuffer->t_surface, fail_create_surface); + + mbuffer->buffer = wayland_tbm_client_create_buffer(_eflutil.wl.shot.tbm_client, mbuffer->t_surface); + EINA_SAFETY_ON_NULL_GOTO(mbuffer->buffer, fail_create_buffer); + + return mbuffer; + +fail_create_buffer: + tbm_surface_destroy(mbuffer->t_surface); +fail_create_surface: + free(mbuffer); + + return NULL; +} + +static void +_efl_util_destroy_mirror_buffer(efl_util_mirror_buffer *mbuffer) +{ + EINA_SAFETY_ON_NULL_RETURN(mbuffer); + + if (mbuffer->buffer) + wl_buffer_destroy(mbuffer->buffer); + + free(mbuffer); +} + +static void +_efl_util_screenmirror_handle_dequeued(void *data, + struct tizen_screenmirror *tz_screenmirror, struct wl_buffer *buffer) +{ + efl_util_screenmirror_h screenmirror; + efl_util_mirror_buffer *mbuffer; + Eina_List *l, *ll; + + screenmirror = (efl_util_screenmirror_h)data; + screenmirror->cb_start = EINA_TRUE; + + EINA_LIST_FOREACH_SAFE(screenmirror->buffer_list, l, ll, mbuffer) + { + if (mbuffer->buffer == buffer) + { + if (mbuffer->w != screenmirror->width || mbuffer->h != screenmirror->height || + !screenmirror->mirror_working) + tbm_surface_destroy(mbuffer->t_surface); + else + screenmirror->user_func(screenmirror, mbuffer->t_surface, screenmirror->user_data); + + screenmirror->buffer_list = eina_list_remove_list(screenmirror->buffer_list, l); + _efl_util_destroy_mirror_buffer(mbuffer); + + break; + } + } + + mbuffer = _efl_util_create_mirror_buffer(screenmirror); + if (mbuffer == NULL) + { + fprintf(stderr, "[screenmirror] fail: buffer create\n"); + return; + } + screenmirror->buffer_list = eina_list_append(screenmirror->buffer_list, mbuffer); + tizen_screenmirror_queue(screenmirror->tz_screenmirror, mbuffer->buffer); +} + +static void +_efl_util_screenmirror_handle_content(void *data, + struct tizen_screenmirror *tz_screenmirror, uint32_t content) +{ + efl_util_screenmirror_h screenmirror = NULL; + + screenmirror = (efl_util_screenmirror_h)data; + screenmirror->cb_content = EINA_TRUE; +} + +static void +_efl_util_screenmirror_handle_stop(void *data, struct tizen_screenmirror *tz_screenmirror) +{ + efl_util_screenmirror_h screenmirror = NULL; + + screenmirror = (efl_util_screenmirror_h)data; + screenmirror->cb_stop = EINA_TRUE; +} + +static const struct tizen_screenmirror_listener efl_util_screenmirror_listener = { + _efl_util_screenmirror_handle_dequeued, + _efl_util_screenmirror_handle_content, + _efl_util_screenmirror_handle_stop +}; + +API efl_util_screenmirror_h +efl_util_screenmirror_initialize(int width, int height) +{ + efl_util_screenmirror_h screenmirror = NULL; + efl_util_mirror_buffer *mbuffer; + Efl_Util_Wl_Output_Info *output; + int ret = 0, i; + + if (width <= 0 || height <= 0) + { + set_last_result(EFL_UTIL_ERROR_INVALID_PARAMETER); + return NULL; + } + + _screenshot_mutex_lock(); + + if (g_screenmirror) + { + if (g_screenmirror->mirror_working) + { + set_last_result(EFL_UTIL_ERROR_INVALID_OPERATION); + _screenshot_mutex_unlock(); + return NULL; + } + else + { + g_screenmirror->width = width; + g_screenmirror->height = height; + set_last_result(EFL_UTIL_ERROR_NONE); + _screenshot_mutex_unlock(); + return g_screenmirror; + } + } + + screenmirror = calloc(1, sizeof(struct _efl_util_screenmirror_h)); + if (screenmirror == NULL) + { + set_last_result(EFL_UTIL_ERROR_OUT_OF_MEMORY); + _screenshot_mutex_unlock(); + return NULL; + } + + if (!_eflutil.wl.shot.tz_screenshooter) + { + if (_efl_util_wl_screenshooter_init() == EINA_FALSE) + { + if (_eflutil.wl.shot.noti == 0) + set_last_result(EFL_UTIL_ERROR_PERMISSION_DENIED); + else + set_last_result(EFL_UTIL_ERROR_SCREENSHOT_INIT_FAIL); + + goto fail_wl_init; + } + } + + output = eina_list_nth(_eflutil.wl.shot.output_list, 0); + if (!output) + { + set_last_result(EFL_UTIL_ERROR_NO_RESOURCE_AVAILABLE); + fprintf(stderr, "[screenmirror] fail: no output for screenmirror\n"); + goto fail_get_output; + } + + screenmirror->tz_screenmirror = tizen_screenshooter_get_screenmirror(_eflutil.wl.shot.tz_screenshooter, output->output); + wl_proxy_set_queue((struct wl_proxy *)screenmirror->tz_screenmirror, _eflutil.wl.shot.queue); + tizen_screenmirror_add_listener(screenmirror->tz_screenmirror, &efl_util_screenmirror_listener, screenmirror); + tizen_screenmirror_set_stretch(screenmirror->tz_screenmirror, TIZEN_SCREENMIRROR_STRETCH_KEEP_RATIO); + screenmirror->width = width; + screenmirror->height = height; + + g_screenmirror = screenmirror; + + for (i = 0; i < 1; i++) + { + mbuffer = _efl_util_create_mirror_buffer(screenmirror); + if (mbuffer) + { + screenmirror->buffer_list = eina_list_append(screenmirror->buffer_list, mbuffer); + tizen_screenmirror_queue(screenmirror->tz_screenmirror, mbuffer->buffer); + } + else + fprintf(stderr, "[screenmirror] fail: buffer create %d\n", i); + } + while (!screenmirror->cb_content && ret != -1) + ret = wl_display_dispatch_queue(_eflutil.wl.dpy, _eflutil.wl.shot.queue); + + _screenshot_mutex_unlock(); + + return screenmirror; + +fail_get_output: +fail_wl_init: + free(screenmirror); + _screenshot_mutex_unlock(); + return NULL; +} + +API int +efl_util_screenmirror_deinitialize(efl_util_screenmirror_h screenmirror) +{ + efl_util_mirror_buffer *mbuffer; + Eina_List *l; + + _screenshot_mutex_lock(); + + if (!screenmirror || (screenmirror != g_screenmirror)) + { + _screenshot_mutex_unlock(); + _screenshot_mutex_destory(); + return EFL_UTIL_ERROR_INVALID_PARAMETER; + } + + if (screenmirror->mirror_working) + { + fprintf(stderr, "[screenmirror] fail: execute stop before deinit\n"); + _screenshot_mutex_unlock(); + _screenshot_mutex_destory(); + return EFL_UTIL_ERROR_INVALID_OPERATION; + } + + EINA_LIST_FOREACH(screenmirror->buffer_list, l, mbuffer) + { + tbm_surface_destroy(mbuffer->t_surface); + _efl_util_destroy_mirror_buffer(mbuffer); + } + eina_list_free(screenmirror->buffer_list); + + tizen_screenmirror_destroy(screenmirror->tz_screenmirror); + free(screenmirror); + g_screenmirror = NULL; + + _efl_util_wl_screenshooter_deinit(); + + _screenshot_mutex_unlock(); + _screenshot_mutex_destory(); + + return EFL_UTIL_ERROR_NONE; +} + +API int +efl_util_screenmirror_set_handler(efl_util_screenmirror_h screenmirror, + efl_util_screenmirror_handler func, void *data) +{ + _screenshot_mutex_lock(); + + if (!screenmirror || (screenmirror != g_screenmirror) || !func) + { + _screenshot_mutex_unlock(); + return EFL_UTIL_ERROR_INVALID_PARAMETER; + } + screenmirror->user_func = func; + screenmirror->user_data = data; + + _screenshot_mutex_unlock(); + + return EFL_UTIL_ERROR_NONE; +} + +API int +efl_util_screenmirror_start(efl_util_screenmirror_h screenmirror) +{ + int ret = 0; + + _screenshot_mutex_lock(); + + if (!screenmirror || (screenmirror != g_screenmirror)) + { + _screenshot_mutex_unlock(); + return EFL_UTIL_ERROR_INVALID_PARAMETER; + } + else if (!screenmirror->user_func) + { + _screenshot_mutex_unlock(); + return EFL_UTIL_ERROR_SCREENSHOT_EXECUTION_FAIL; + } + else if (screenmirror->mirror_working) + { + _screenshot_mutex_unlock(); + return EFL_UTIL_ERROR_NONE; + } + + screenmirror->cb_start = EINA_FALSE; + screenmirror->mirror_working = EINA_TRUE; + tizen_screenmirror_start(screenmirror->tz_screenmirror); + while (!screenmirror->cb_start && ret != -1) + ret = wl_display_dispatch_queue(_eflutil.wl.dpy, _eflutil.wl.shot.queue); + if (ret == -1) + { + fprintf(stderr, "[screenmirror] fail: tizen_screenmirror_start\n"); + _screenshot_mutex_unlock(); + return EFL_UTIL_ERROR_SCREENSHOT_EXECUTION_FAIL; + } + + ret = pthread_create(&screenmirror->thread, NULL, _efl_util_screenmirror_loop, screenmirror); + if (ret < 0) + fprintf(stderr, "[screenmirror] fail: thread create fail\n"); + + _screenshot_mutex_unlock(); + + return EFL_UTIL_ERROR_NONE; +} + +API int +efl_util_screenmirror_stop(efl_util_screenmirror_h screenmirror) +{ + int ret = 0; + + _screenshot_mutex_lock(); + + if (!screenmirror || (screenmirror != g_screenmirror)) + { + _screenshot_mutex_unlock(); + return EFL_UTIL_ERROR_INVALID_PARAMETER; + } + else if (!screenmirror->mirror_working) + { + _screenshot_mutex_unlock(); + return EFL_UTIL_ERROR_NONE; + } + screenmirror->mirror_working = EINA_FALSE; + pthread_join(screenmirror->thread, NULL); + tizen_screenmirror_stop(screenmirror->tz_screenmirror); + screenmirror->cb_stop = EINA_FALSE; + + while (!screenmirror->cb_stop && ret != -1) + ret = wl_display_dispatch_queue(_eflutil.wl.dpy, _eflutil.wl.shot.queue); + if (ret == -1) + { + fprintf(stderr, "[screenmirror] fail: tizen_screenmirror_stop\n"); + _screenshot_mutex_unlock(); + return EFL_UTIL_ERROR_SCREENSHOT_EXECUTION_FAIL; + } + + _screenshot_mutex_unlock(); + + return EFL_UTIL_ERROR_NONE; +} +/* LCOV_EXCL_STOP */ + struct _efl_util_gesture_h { Eina_Bool init; -- 2.7.4