From: Seunghun Lee Date: Sun, 22 Mar 2020 03:00:27 +0000 (+0900) Subject: e_output: Add APIs for stream capture to mask canvas with image object. X-Git-Tag: submit/tizen/20200330.060727~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=12c48bcf9cc516815665e64f535b7b81eac0f528;p=platform%2Fupstream%2Fenlightenment.git e_output: Add APIs for stream capture to mask canvas with image object. This patch introduces APIs for masking canvas with image object during stream capture. Namely, these methods are: Eina_Bool e_output_stream_capture_mask_image_file_set(file) Eina_Bool e_output_stream_capture_mask_image_geometry_set(x, y, w, h) Once the image file is given, image object will be created on top of canvas whenever starting stream capture and will be destroyed whenever finishing stream capture. It can be canceled by setting null as file name. Image object will be re-loadeded if the file name changes during stream capture, and will be destroyed if null is given as file name. Change-Id: Id12895e894588c3700aeca52dab1213f57fdc44e --- diff --git a/src/bin/e_output.c b/src/bin/e_output.c index f31a651371..d5b9348317 100644 --- a/src/bin/e_output.c +++ b/src/bin/e_output.c @@ -29,6 +29,7 @@ typedef struct _E_Output_Capture E_Output_Capture; typedef struct _E_Output_Layer E_Output_Layer; +typedef struct _E_Output_Stream_Capture_Mask_Data E_Output_Stream_Capture_Mask_Data; struct _E_Output_Capture { @@ -47,6 +48,14 @@ struct _E_Output_Layer int zpos; }; +struct _E_Output_Stream_Capture_Mask_Data +{ + Evas_Object *eo; + Eina_Stringshare *file; + Eina_Rectangle geometry; + Eina_Bool saved_hwc_deactive; +}; + static int _e_output_hooks_delete = 0; static int _e_output_hooks_walking = 0; @@ -70,10 +79,20 @@ static Eina_Inlist *_e_output_intercept_hooks[] = [E_OUTPUT_INTERCEPT_HOOK_DPMS_OFF] = NULL, }; +/* Use hash mechanism to avoid ABI break. + * It can be widely used like private data for E_Output, if there will be need + * for more use case.*/ +static Eina_Hash *_mask_data_hash = NULL; + static Eina_Bool _e_output_capture(E_Output *output, tbm_surface_h tsurface, Eina_Bool auto_rotate); static void _e_output_vblank_handler(tdm_output *output, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *data); +static E_Output_Stream_Capture_Mask_Data *_e_output_stream_capture_mask_data_get(E_Output *output); +static void _e_output_stream_capture_mask_data_hash_cb_data_free(void *data); +static void _e_output_stream_capture_mask_image_activate(E_Output *output); +static void _e_output_stream_capture_mask_image_deactivate(E_Output *output); + static unsigned int _e_output_aligned_width_get(E_Output *output, tbm_surface_h tsurface) { @@ -1034,14 +1053,16 @@ _e_output_update_fps() EINTERN Eina_Bool e_output_init(void) { - /* nothing */ + _mask_data_hash = + eina_hash_pointer_new(_e_output_stream_capture_mask_data_hash_cb_data_free); + return EINA_TRUE; } EINTERN void e_output_shutdown(void) { - ; + E_FREE_FUNC(_mask_data_hash, eina_hash_free); } static char * @@ -2523,6 +2544,9 @@ e_output_del(E_Output *output) EINA_LIST_FREE(output->info.modes, m) free(m); EINA_LIST_FREE(output->planes, plane) e_plane_free(plane); + + eina_hash_del_by_key(_mask_data_hash, &output); + free(output); } @@ -3859,6 +3883,8 @@ e_output_stream_capture_start(E_Output *output) output->stream_capture.start = EINA_TRUE; + _e_output_stream_capture_mask_image_activate(output); + if (output->stream_capture.possible_tdm_capture) { if (e_output_dpms_get(output)) @@ -3896,6 +3922,8 @@ e_output_stream_capture_stop(E_Output *output) output->stream_capture.start = EINA_FALSE; + _e_output_stream_capture_mask_image_deactivate(output); + if (eina_list_count(output->stream_capture.data) == 0) { if (!output->stream_capture.timer) @@ -4302,3 +4330,176 @@ e_output_property_set(E_Output *output, unsigned int id, output_prop_value value return EINA_TRUE; } + +E_API Eina_Bool +e_output_stream_capture_mask_image_file_set(E_Output *output, const char *file) +{ + E_Output_Stream_Capture_Mask_Data *md; + + EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); + + EOINF("set mask image file for stream capture : %s", output, file); + + md = _e_output_stream_capture_mask_data_get(output); + if (!md) + { + EOERR("failed to get mask data", output); + return EINA_FALSE; + } + + if (eina_streq(md->file, file)) + return EINA_TRUE; + + eina_stringshare_replace(&md->file, file); + + if (output->stream_capture.start) + { + _e_output_stream_capture_mask_image_deactivate(output); + + if (md->file) + _e_output_stream_capture_mask_image_activate(output); + } + + return EINA_TRUE; +} + +E_API Eina_Bool +e_output_stream_capture_mask_image_geometry_set(E_Output *output, int x, int y, int w, int h) +{ + E_Output_Stream_Capture_Mask_Data *md; + + EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(w > 0, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(h > 0, EINA_FALSE); + + EOINF("set geometry of mask image object: %d,%d (%dx%d)", + output, x, y, w, h); + + md = _e_output_stream_capture_mask_data_get(output); + if (!md) + { + EOERR("failed to get mask data", output); + return EINA_FALSE; + } + + EINA_RECTANGLE_SET(&md->geometry, x, y, w, h); + + if (output->stream_capture.start) + { + if (md->eo) + evas_object_geometry_set(md->eo, x, y, w, h); + } + + return EINA_TRUE; +} + +static void +_e_output_stream_capture_mask_data_hash_cb_data_free(void *data) +{ + free(data); +} + +static E_Output_Stream_Capture_Mask_Data * +_e_output_stream_capture_mask_data_get(E_Output *output) +{ + E_Output_Stream_Capture_Mask_Data *md; + + md = eina_hash_find(_mask_data_hash, &output); + if (!md) + { + md = E_NEW(E_Output_Stream_Capture_Mask_Data, 1); + if (!md) + { + EOERR("failed to alloc memory for mask data", output); + return NULL; + } + + md->geometry.w = 1; + md->geometry.h = 1; + + eina_hash_add(_mask_data_hash, &output, md); + } + + return md; +} + +static void +_e_output_stream_capture_mask_image_activate(E_Output *output) +{ + E_Output_Stream_Capture_Mask_Data *md; + Evas_Object *eo; + Evas_Load_Error err; + Eina_Bool hwc_deactive; + + md = eina_hash_find(_mask_data_hash, &output); + if (!md) + { + /* It can be null if any api for mask image is not called. */ + EOINF("not found mask data", output); + return; + } + + if (!md->file) + { + EOINF("no file name for mask image", output); + return; + } + + if (md->eo) + { + EOERR("mask image object is already exist.", output); + return; + } + + eo = evas_object_image_filled_add(e_comp->evas); + + evas_object_image_file_set(eo, md->file, NULL); + err = evas_object_image_load_error_get(eo); + if (err != EVAS_LOAD_ERROR_NONE) + { + EOERR("failed to load image %s : %s", output, + md->file, evas_load_error_str(err)); + evas_object_del(eo); + return; + } + + evas_object_geometry_set(eo, + md->geometry.x, md->geometry.y, + md->geometry.w, md->geometry.h); + + evas_object_pass_events_set(eo, EINA_TRUE); + evas_object_layer_set(eo, EVAS_LAYER_MAX); + evas_object_raise(eo); + evas_object_show(eo); + + md->eo = eo; + + /* Deactive HWC to display mask image on evas. it's saved for restoring. + * + * WARNING: Restoring deactive status won't work as expected if deactive + * status of HWC changes after it. It may cause undefined behavior. */ + hwc_deactive = e_hwc_deactive_get(output->hwc); + if (!hwc_deactive) + e_hwc_deactive_set(output->hwc, EINA_TRUE); + + md->saved_hwc_deactive = hwc_deactive; +} + +static void +_e_output_stream_capture_mask_image_deactivate(E_Output *output) +{ + E_Output_Stream_Capture_Mask_Data *md; + + md = eina_hash_find(_mask_data_hash, &output); + if (!md) + { + EOINF("not found mask data", output); + return; + } + + E_FREE_FUNC(md->eo, evas_object_del); + + /* restore hwc deactive status. */ + if (!md->saved_hwc_deactive) + e_hwc_deactive_set(output->hwc, EINA_FALSE); +} diff --git a/src/bin/e_output.h b/src/bin/e_output.h index c97ea3b5bd..ffa4b84308 100644 --- a/src/bin/e_output.h +++ b/src/bin/e_output.h @@ -232,6 +232,8 @@ EINTERN Eina_Bool e_output_stream_capture_queue(E_Output *output, tbm_su EINTERN Eina_Bool e_output_stream_capture_dequeue(E_Output *output, tbm_surface_h surface); EINTERN Eina_Bool e_output_stream_capture_start(E_Output *output); EINTERN void e_output_stream_capture_stop(E_Output *output); +E_API Eina_Bool e_output_stream_capture_mask_image_file_set(E_Output *output, const char *file); +E_API Eina_Bool e_output_stream_capture_mask_image_geometry_set(E_Output *output, int x, int y, int w, int h); EINTERN const char * e_output_output_id_get(E_Output *output); EINTERN Eina_Bool e_output_external_mode_change(E_Output *output, E_Output_Mode *mode);