e_output: Add APIs for stream capture to mask canvas with image object. 71/228571/5
authorSeunghun Lee <shiin.lee@samsung.com>
Sun, 22 Mar 2020 03:00:27 +0000 (12:00 +0900)
committerSeunghun Lee <shiin.lee@samsung.com>
Thu, 26 Mar 2020 01:26:45 +0000 (01:26 +0000)
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

src/bin/e_output.c
src/bin/e_output.h

index f31a65137134b78734fb67c8eda1bcbe7e030e17..d5b9348317ee9636df2f096e5847f177829971e5 100644 (file)
@@ -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);
+}
index c97ea3b5bd6c7d2f1e9f80f80437362af0f0a2b6..ffa4b84308db139e3b3ba03d04e8721f2c1f0388 100644 (file)
@@ -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);