evas: Optimize memory usage on static webp files 64/279564/4 accepted/tizen/unified/20220817.153842 submit/tizen/20220812.051443 submit/tizen/20220816.012857 submit/tizen/20220817.020146
authorMichal Szczecinski <m.szczecinsk@partner.samsung.com>
Thu, 11 Aug 2022 15:09:26 +0000 (17:09 +0200)
committerTaehyub Kim <taehyub.kim@samsung.com>
Fri, 12 Aug 2022 04:45:10 +0000 (13:45 +0900)
To load 4k single webp image, we should use WebPDecodeBGRA api to recude memory usage
because WebPAnim* API Set memory cost is high

Change-Id: I6d43f1610e26df30470dbd280d588f0e13408833

src/modules/evas/image_loaders/webp/evas_image_load_webp.c

index 3125b93..8468345 100644 (file)
@@ -34,8 +34,8 @@ typedef struct _Image_Frame
 
 static Eina_Bool
 evas_image_load_file_check(Eina_File *f, void *map,
-                          unsigned int *w, unsigned int *h, Eina_Bool *alpha,
-                          int *error)
+                           unsigned int *w, unsigned int *h, Eina_Bool *alpha, Eina_Bool *is_animated,
+                           int *error)
 {
    WebPDecoderConfig config;
 
@@ -55,15 +55,16 @@ evas_image_load_file_check(Eina_File *f, void *map,
    *w = config.input.width;
    *h = config.input.height;
    *alpha = config.input.has_alpha;
+   *is_animated = config.input.has_animation;
 
    return EINA_TRUE;
 }
 
 static void *
 evas_image_load_file_open_webp(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
-                              Evas_Image_Load_Opts *opts,
-                              Evas_Image_Animated *animated,
-                              int *error)
+                               Evas_Image_Load_Opts *opts,
+                               Evas_Image_Animated *animated,
+                               int *error)
 {
    Loader_Info *loader = calloc(1, sizeof (Loader_Info));
    if (!loader)
@@ -188,39 +189,20 @@ _is_black(DATA32 *ptr)
 }
 
 static Eina_Bool
-evas_image_load_file_head_webp(void *loader_data,
-                              Evas_Image_Property *prop,
-                              int *error)
+_load_frame_image(void *loader_data,
+                  Evas_Image_Property *prop,
+                  int *error)
 {
    Loader_Info *loader = loader_data;
    Evas_Image_Animated *animated = loader->animated;
    Eina_File *f = loader->f;
-   void *data;
-
-   // For Nine patch
-   const char *filename;
-   unsigned int filename_len = 0;
-
-   *error = EVAS_LOAD_ERROR_NONE;
-
-   data = eina_file_map_all(f, EINA_FILE_RANDOM);
-   loader->map = data;
-
-   if (!evas_image_load_file_check(f, data,
-                                 &(prop->info.w), &(prop->info.h), &(prop->info.alpha),
-                                 error))
-     {
-        ERR("Image File is Invalid");
-        *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
-        return EINA_FALSE;
-     }
 
    // Init WebP Data
    WebPData webp_data;
    WebPDataInit(&webp_data);
 
    // Assign Data
-   webp_data.bytes = data;
+   webp_data.bytes = loader->map;
    webp_data.size = eina_file_size_get(f);
 
    // Set Decode Option
@@ -284,6 +266,40 @@ evas_image_load_file_head_webp(void *loader_data,
         animated->loop_hint = EVAS_IMAGE_ANIMATED_HINT_LOOP;
         animated->frame_count = anim_info.frame_count;
      }
+   else if (anim_info.frame_count == 1)
+     {
+        animated->animated = 0;
+     }
+
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+evas_image_load_file_head_webp(void *loader_data,
+                               Evas_Image_Property *prop,
+                               int *error)
+{
+   Loader_Info *loader = loader_data;
+   Eina_File *f = loader->f;
+   void *data;
+   Eina_Bool animated = EINA_FALSE;
+
+   // For Nine patch
+   const char *filename;
+   unsigned int filename_len = 0;
+
+   *error = EVAS_LOAD_ERROR_NONE;
+
+   data = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+   loader->map = data;
+
+   if (!evas_image_load_file_check(f, data,
+                                   &(prop->info.w), &(prop->info.h), &(prop->info.alpha),
+                                   &(animated), error))
+     {
+        *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+        return EINA_FALSE;
+     }
 
    // Apply Nine patch
    filename = eina_file_filename_get(f);
@@ -298,6 +314,16 @@ evas_image_load_file_head_webp(void *loader_data,
         prop->info.h -= 2;
      }
 
+   // For Animated and Single Nine Patch WebP Image
+   if (animated || prop->need_data)
+      _load_frame_image(loader_data, prop, error);
+   // For Single WebP Image
+   else
+     {
+        loader->animated->animated = EINA_FALSE;
+        loader->animated->frame_count = 1;
+     }
+
    return EINA_TRUE;
 }
 
@@ -381,8 +407,8 @@ evas_image_load_file_head_with_data_webp(void *loader_data,
              ERR("calloc is failed \n");
              return EINA_FALSE;
           }
-        memcpy(pixels2, frame->data, bufferSize);
 
+        memcpy(pixels2, frame->data, bufferSize);
         memset(&prop->content, 0, sizeof (Eina_Rectangle));
 
         // Top line of the image
@@ -537,19 +563,51 @@ evas_image_load_file_head_with_data_webp(void *loader_data,
 
 static Eina_Bool
 evas_image_load_file_data_webp(void *loader_data,
-                              Evas_Image_Property *prop,
-                              void *pixels,
-                              int *error)
+                               Evas_Image_Property *prop,
+                               void *pixels,
+                               int *error)
 {
    Loader_Info *loader = loader_data;
    Evas_Image_Animated *animated = loader->animated;
 
+   if (!animated)
+     return EINA_FALSE;
+
    *error = EVAS_LOAD_ERROR_NONE;
 
    void *surface = NULL;
    int width, height;
    int index = 0;
 
+   // For Single WebP Image
+   if (animated->animated == EINA_FALSE)
+     {
+        void *decoded = NULL;
+        int width = 0;
+        int height = 0;
+
+        surface = pixels;
+
+        decoded = WebPDecodeBGRA(loader->map, eina_file_size_get(loader->f), &width, &height);
+        if (!decoded)
+          {
+             *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+             return EINA_FALSE;
+          }
+
+        if ((int)prop->info.w != width ||
+            (int)prop->info.h != height)
+          {
+             if (decoded) free(decoded);
+             return EINA_FALSE;
+          }
+
+        memcpy(surface, decoded, width * height * 4);
+        prop->info.premul = EINA_TRUE;
+        free(decoded);
+        return EINA_TRUE;
+     }
+
    index = animated->cur_frame;
 
    // Find Cur Frame