1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #include <stdio.h>
6 
7 #include <avif/avif.h>
8 
9 #include "Evas_Loader.h"
10 #include "evas_common_private.h"
11 
12 typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
13 struct _Evas_Loader_Internal
14 {
15    Eina_File *f;
16    Evas_Image_Load_Opts *opts;
17    Evas_Image_Animated *animated;
18    avifDecoder *decoder;
19    double duration;
20 };
21 
22 static int _evas_loader_avif_log_dom = -1;
23 
24 #ifdef ERR
25 # undef ERR
26 #endif
27 #define ERR(...) EINA_LOG_DOM_ERR(_evas_loader_avif_log_dom, __VA_ARGS__)
28 
29 #ifdef WRN
30 # undef WRN
31 #endif
32 #define WRN(...) EINA_LOG_DOM_WARN(_evas_loader_avif_log_dom, __VA_ARGS__)
33 
34 #ifdef INF
35 # undef INF
36 #endif
37 #define INF(...) EINA_LOG_DOM_INFO(_evas_loader_avif_log_dom, __VA_ARGS__)
38 
39 static Eina_Bool
evas_image_load_file_head_avif_internal(Evas_Loader_Internal * loader,Emile_Image_Property * prop,void * map,size_t length,int * error)40 evas_image_load_file_head_avif_internal(Evas_Loader_Internal *loader,
41                                         Emile_Image_Property *prop,
42                                         void *map, size_t length,
43                                         int *error)
44 {
45    Evas_Image_Animated *animated;
46    avifROData raw;
47    avifDecoder *decoder;
48    avifResult res;
49    Eina_Bool ret;
50 
51    animated = loader->animated;
52 
53    ret = EINA_FALSE;
54    prop->w = 0;
55    prop->h = 0;
56    prop->alpha = EINA_FALSE;
57 
58    raw.size = length;
59    raw.data = (const uint8_t *)map;
60 
61    decoder = avifDecoderCreate();
62    if (!decoder)
63      {
64         *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
65         return ret;
66      }
67 
68    res = avifDecoderParse(decoder, &raw);
69    if (res != AVIF_RESULT_OK)
70      {
71         ERR("avif file format invalid");
72         *error = EVAS_LOAD_ERROR_GENERIC;
73         goto destroy_decoder;
74      }
75 
76    if (decoder->imageCount < 1)
77      {
78         ERR("avif file format invalid");
79         *error = EVAS_LOAD_ERROR_GENERIC;
80         goto destroy_decoder;
81      }
82 
83    res = avifDecoderNextImage(decoder);
84    if (res != AVIF_RESULT_OK)
85      {
86         ERR("avif file format invalid");
87         *error = EVAS_LOAD_ERROR_GENERIC;
88         goto destroy_decoder;
89      }
90 
91    prop->w = decoder->image->width;
92    prop->h = decoder->image->height;
93 
94    /* if size is invalid, we exit */
95    if ((prop->w < 1) || (prop->h < 1) ||
96        (prop->w > IMG_MAX_SIZE) || (prop->h > IMG_MAX_SIZE) ||
97        IMG_TOO_BIG(prop->w, prop->h))
98      {
99         if (IMG_TOO_BIG(prop->w, prop->h))
100           *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
101         else
102           *error= EVAS_LOAD_ERROR_GENERIC;
103         goto destroy_decoder;
104      }
105 
106    prop->alpha = !!decoder->image->alphaPlane;
107 
108    if (decoder->imageCount > 1)
109      {
110         animated->loop_hint = EVAS_IMAGE_ANIMATED_HINT_NONE;
111         animated->frame_count = decoder->imageCount;
112         animated->loop_count = 1;
113         animated->animated = EINA_TRUE;
114         loader->duration = decoder->duration / decoder->imageCount;
115      }
116 
117    *error = EVAS_LOAD_ERROR_NONE;
118    ret = EINA_TRUE;
119 
120  destroy_decoder:
121    avifDecoderDestroy(decoder);
122 
123    return ret;
124 }
125 
126 static Eina_Bool
evas_image_load_file_data_avif_internal(Evas_Loader_Internal * loader,void * pixels,void * map,size_t length,int * error)127 evas_image_load_file_data_avif_internal(Evas_Loader_Internal *loader,
128                                         void *pixels,
129                                         void *map, size_t length,
130                                         int *error)
131 {
132    avifRGBImage rgb;
133    avifDecoder *decoder;
134    avifResult res;
135    Evas_Image_Animated *animated;
136    Eina_Bool ret;
137 
138    ret = EINA_FALSE;
139 
140    /* FIXME: create decoder in evas_image_load_file_data_avif instead ? */
141    decoder = loader->decoder;
142    if (!decoder)
143      {
144         avifROData raw;
145         decoder = avifDecoderCreate();
146         if (!decoder)
147           {
148              *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
149              return EINA_FALSE;
150           }
151 
152         raw.size = length;
153         raw.data = (const uint8_t *)map;
154 
155         res = avifDecoderParse(decoder, &raw);
156         if (res != AVIF_RESULT_OK)
157           {
158              *error = EVAS_LOAD_ERROR_GENERIC;
159              goto on_error;
160           }
161 
162         loader->decoder = decoder;
163      }
164 
165    animated = loader->animated;
166    if (animated->animated)
167      {
168         /* FIXME: next image instead ? */
169         res = avifDecoderNthImage(decoder, animated->cur_frame + 1);
170         if (res != AVIF_RESULT_OK)
171           {
172              *error = EVAS_LOAD_ERROR_GENERIC;
173              goto on_error;
174           }
175      }
176    else
177      {
178         res = avifDecoderNextImage(decoder);
179         if (res != AVIF_RESULT_OK)
180           {
181              *error = EVAS_LOAD_ERROR_GENERIC;
182              goto on_error;
183           }
184      }
185 
186    avifRGBImageSetDefaults(&rgb, decoder->image);
187 #ifdef WORDS_BIGENDIAN
188    rgb.format = AVIF_RGB_FORMAT_ARGB;
189 #else
190    rgb.format = AVIF_RGB_FORMAT_BGRA;
191 #endif
192    rgb.depth = 8;
193    rgb.pixels = pixels;
194    rgb.rowBytes = 4 * decoder->image->width;
195 
196    avifImageYUVToRGB(decoder->image, &rgb);
197 
198    *error = EVAS_LOAD_ERROR_NONE;
199 
200    ret = EINA_TRUE;
201 
202  on_error:
203 
204    return ret;
205 }
206 
207 static void *
evas_image_load_file_open_avif(Eina_File * f,Eina_Stringshare * key EINA_UNUSED,Evas_Image_Load_Opts * opts,Evas_Image_Animated * animated,int * error)208 evas_image_load_file_open_avif(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
209 			       Evas_Image_Load_Opts *opts,
210 			       Evas_Image_Animated *animated,
211 			       int *error)
212 {
213    Evas_Loader_Internal *loader;
214 
215    loader = calloc(1, sizeof (Evas_Loader_Internal));
216    if (!loader)
217      {
218         *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
219         return NULL;
220      }
221 
222    loader->f = f;
223    loader->opts = opts;
224    loader->animated = animated;
225 
226    return loader;
227 }
228 
229 static void
evas_image_load_file_close_avif(void * loader_data)230 evas_image_load_file_close_avif(void *loader_data)
231 {
232    Evas_Loader_Internal *loader;
233 
234    loader = loader_data;
235    avifDecoderDestroy(loader->decoder);
236    free(loader_data);
237 }
238 
239 static Eina_Bool
evas_image_load_file_head_avif(void * loader_data,Evas_Image_Property * prop,int * error)240 evas_image_load_file_head_avif(void *loader_data,
241                                Evas_Image_Property *prop,
242                                int *error)
243 {
244    Evas_Loader_Internal *loader = loader_data;
245    Eina_File *f;
246    void *map;
247    Eina_Bool val;
248 
249    f = loader->f;
250 
251    map = eina_file_map_all(f, EINA_FILE_RANDOM);
252    if (!map)
253      {
254 	*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
255         return EINA_FALSE;
256      }
257 
258    val = evas_image_load_file_head_avif_internal(loader,
259                                                  (Emile_Image_Property *)prop,
260                                                  map, eina_file_size_get(f),
261                                                  error);
262 
263    eina_file_map_free(f, map);
264 
265    return val;
266 }
267 
268 static Eina_Bool
evas_image_load_file_data_avif(void * loader_data,Evas_Image_Property * prop EINA_UNUSED,void * pixels,int * error)269 evas_image_load_file_data_avif(void *loader_data,
270                                Evas_Image_Property *prop EINA_UNUSED,
271 			       void *pixels,
272 			       int *error)
273 {
274    Evas_Loader_Internal *loader;
275    Eina_File *f;
276    void *map;
277    Eina_Bool val = EINA_FALSE;
278 
279    loader = (Evas_Loader_Internal *)loader_data;
280    f = loader->f;
281 
282    map = eina_file_map_all(f, EINA_FILE_WILLNEED);
283    if (!map)
284      {
285         *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
286         goto on_error;
287      }
288 
289    val = evas_image_load_file_data_avif_internal(loader,
290                                                  pixels,
291                                                  map, eina_file_size_get(f),
292                                                  error);
293 
294    eina_file_map_free(f, map);
295 
296  on_error:
297    return val;
298 }
299 
300 static double
evas_image_load_frame_duration_avif(void * loader_data,int start_frame,int frame_num)301 evas_image_load_frame_duration_avif(void *loader_data,
302                                     int start_frame,
303                                     int frame_num)
304 {
305    Evas_Loader_Internal *loader;
306    Evas_Image_Animated *animated;
307 
308    loader = (Evas_Loader_Internal *)loader_data;
309    animated = loader->animated;
310 
311    if (!animated->animated)
312      return -1.0;
313 
314    if (frame_num < 0)
315      return -1.0;
316 
317    if ((start_frame + frame_num) > animated->frame_count)
318      return -1.0;
319 
320    if (frame_num < 1)
321      frame_num = 1;
322 
323    return loader->duration;
324 }
325 
326 static Evas_Image_Load_Func evas_image_load_avif_func =
327 {
328    EVAS_IMAGE_LOAD_VERSION,
329    evas_image_load_file_open_avif,
330    evas_image_load_file_close_avif,
331    evas_image_load_file_head_avif,
332    NULL,
333    evas_image_load_file_data_avif,
334    evas_image_load_frame_duration_avif,
335    EINA_TRUE,
336    EINA_TRUE
337 };
338 
339 static int
module_open(Evas_Module * em)340 module_open(Evas_Module *em)
341 {
342    if (!em) return 0;
343 
344    _evas_loader_avif_log_dom = eina_log_domain_register("evas-avif", EINA_COLOR_BLUE);
345    if (_evas_loader_avif_log_dom < 0)
346      {
347         EINA_LOG_ERR("Can not create a module log domain.");
348         return 0;
349      }
350 
351    em->functions = (void *)(&evas_image_load_avif_func);
352 
353    return 1;
354 }
355 
356 static void
module_close(Evas_Module * em EINA_UNUSED)357 module_close(Evas_Module *em EINA_UNUSED)
358 {
359    if (_evas_loader_avif_log_dom >= 0)
360      {
361         eina_log_domain_unregister(_evas_loader_avif_log_dom);
362         _evas_loader_avif_log_dom = -1;
363      }
364 }
365 
366 static Evas_Module_Api evas_modapi =
367 {
368    EVAS_MODULE_API_VERSION,
369    "avif",
370    "none",
371    {
372      module_open,
373      module_close
374    }
375 };
376 
377 EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, avif);
378 
379 #ifndef EVAS_STATIC_BUILD_AVIF
380 EVAS_EINA_MODULE_DEFINE(image_loader, avif);
381 #endif
382 
383