improve heif loader: * efl coding style * faster head callback * faster copy of image data

Summary: and minor fix of some values in avif loader

Test Plan: entice still can read heif

Reviewers: raster

Subscribers: cedric, #reviewers, #committers

Tags: #efl

Differential Revision: https://phab.enlightenment.org/D12257
This commit is contained in:
Vincent Torri 2021-04-09 21:09:05 +01:00 committed by Carsten Haitzler (Rasterman)
parent 012d3cf797
commit 77a3b908ed
2 changed files with 252 additions and 180 deletions

View File

@ -355,8 +355,8 @@ static Evas_Image_Load_Func evas_image_load_avif_func =
NULL, NULL,
evas_image_load_file_data_avif, evas_image_load_file_data_avif,
evas_image_load_frame_duration_avif, evas_image_load_frame_duration_avif,
EINA_TRUE, EINA_FALSE,
EINA_TRUE EINA_FALSE
}; };
static int static int

View File

@ -1,28 +1,19 @@
#define _XOPEN_SOURCE 600
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <config.h> # include <config.h>
#endif #endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#include <libheif/heif.h> #include <libheif/heif.h>
#include "Evas_Loader.h"
#include "evas_common_private.h" #include "evas_common_private.h"
#include "evas_private.h"
typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
struct _Evas_Loader_Internal
{
Eina_File *f;
Evas_Image_Load_Opts *opts;
struct heif_context* ctx;
};
static int _evas_loader_heif_log_dom = -1; static int _evas_loader_heif_log_dom = -1;
@ -36,170 +27,159 @@ static int _evas_loader_heif_log_dom = -1;
#endif #endif
#define INF(...) EINA_LOG_DOM_INFO(_evas_loader_heif_log_dom, __VA_ARGS__) #define INF(...) EINA_LOG_DOM_INFO(_evas_loader_heif_log_dom, __VA_ARGS__)
static void *
evas_image_load_file_open_heif(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
Evas_Image_Load_Opts *opts EINA_UNUSED,
Evas_Image_Animated *animated EINA_UNUSED,
int *error EINA_UNUSED)
{
return f;
}
static void
evas_image_load_file_close_heif(void *loader_data EINA_UNUSED)
{
}
static Eina_Bool static Eina_Bool
evas_image_load_file_head_heif(void *loader_data, evas_image_load_file_head_heif_internal(Evas_Loader_Internal *loader EINA_UNUSED,
Emile_Image_Property *prop, Emile_Image_Property *prop,
int *error) void *map, size_t length,
int *error)
{ {
Eina_File *f = loader_data; struct heif_context *ctx;
void *map; struct heif_image_handle *handle;
size_t length;
struct heif_error err; struct heif_error err;
struct heif_context* hc = NULL; Eina_Bool ret;
struct heif_image_handle* hdl = NULL;
struct heif_image* img = NULL;
Eina_Bool r = EINA_FALSE;
*error = EVAS_LOAD_ERROR_NONE; ret = EINA_FALSE;
map = eina_file_map_all(f, EINA_FILE_RANDOM);
length = eina_file_size_get(f);
// init prop struct with some default null values
prop->w = 0; prop->w = 0;
prop->h = 0; prop->h = 0;
prop->alpha = EINA_FALSE;
if (!map || length < 1) /* heif file must have a 12 bytes long header */
if ((length < 12) ||
(heif_check_filetype(map, length) == heif_filetype_no))
{ {
*error = EVAS_LOAD_ERROR_CORRUPT_FILE; INF("HEIF header invalid");
goto on_error; *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
return ret;
} }
hc = heif_context_alloc(); ctx = heif_context_alloc();
if (!hc) { if (!ctx)
INF("cannot allocate heif_context"); {
*error = EVAS_LOAD_ERROR_CORRUPT_FILE; INF("cannot allocate heif_context");
goto on_error; *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return ret;
}
err = heif_context_read_from_memory_without_copy(ctx, map, length, NULL);
if (err.code != heif_error_Ok)
{
INF("%s", err.message);
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
goto free_ctx;
} }
err = heif_context_read_from_memory_without_copy(hc, map, length, NULL); err = heif_context_get_primary_image_handle(ctx, &handle);
if (err.code != heif_error_Ok) { if (err.code != heif_error_Ok)
INF("%s", err.message); {
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; INF("%s", err.message);
goto on_error; *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
} goto free_ctx;
}
err = heif_context_get_primary_image_handle(hc, &hdl); prop->w = heif_image_handle_get_width(handle);
if (err.code != heif_error_Ok) { prop->h = heif_image_handle_get_height(handle);
INF("%s", err.message);
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
goto on_error;
}
int has_alpha = heif_image_handle_has_alpha_channel(hdl); /* if size is invalid, we exit */
if ((prop->w < 1) || (prop->h < 1) ||
(prop->w > IMG_MAX_SIZE) || (prop->h > IMG_MAX_SIZE) ||
IMG_TOO_BIG(prop->w, prop->h))
{
if (IMG_TOO_BIG(prop->w, prop->h))
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
else
*error= EVAS_LOAD_ERROR_GENERIC;
goto release_handle;
}
err = heif_decode_image(hdl, &img, heif_colorspace_RGB, prop->alpha = !!heif_image_handle_has_alpha_channel(handle);
has_alpha ? heif_chroma_interleaved_RGBA : heif_chroma_interleaved_RGB,
NULL);
if (err.code != heif_error_Ok) {
INF("%s", err.message);
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
goto on_error;
}
prop->w = heif_image_get_width(img, heif_channel_interleaved); *error = EVAS_LOAD_ERROR_NONE;
prop->h = heif_image_get_height(img, heif_channel_interleaved); ret = EINA_TRUE;
if (has_alpha != 3)
prop->alpha = 1;
r = EINA_TRUE; release_handle:
heif_image_handle_release(handle);
free_ctx:
heif_context_free(ctx);
on_error: return ret;
if (img) {
heif_image_release(img);
}
if (hdl) {
heif_image_handle_release(hdl);
}
if (hc) {
heif_context_free(hc);
}
eina_file_map_free(f, map);
return r;
} }
static Eina_Bool static Eina_Bool
evas_image_load_file_data_heif(void *loader_data, evas_image_load_file_data_heif_internal(Evas_Loader_Internal *loader,
Emile_Image_Property *prop, Emile_Image_Property *prop,
void *pixels, void *pixels,
int *error) void *map, size_t length,
int *error)
{ {
Eina_File *f = loader_data; struct heif_context *ctx;
struct heif_image_handle *handle;
void *map; struct heif_image *img;
size_t length;
struct heif_error err; struct heif_error err;
struct heif_context* hc = NULL; const unsigned char *data;
struct heif_image_handle* hdl = NULL; unsigned char *dd;
struct heif_image* img = NULL; unsigned char *ds;
unsigned int x, y; int stride;
int stride, bps = 3; unsigned int x;
const uint8_t* data; unsigned int y;
uint8_t* dd = (uint8_t*)pixels, *ds = NULL; Eina_Bool ret;
Eina_Bool result = EINA_FALSE;
map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL); ret = EINA_FALSE;
length = eina_file_size_get(f);
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
if (!map || length < 1)
goto on_error;
*error = EVAS_LOAD_ERROR_GENERIC; ctx = loader->ctx;
result = EINA_FALSE; if (!ctx)
{
ctx = heif_context_alloc();
if (!ctx)
{
INF("cannot allocate heif_context");
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return ret;
}
hc = heif_context_alloc(); err = heif_context_read_from_memory_without_copy(ctx,
if (!hc) { map, length, NULL);
INF("cannot allocate heif_context"); if (err.code != heif_error_Ok)
*error = EVAS_LOAD_ERROR_CORRUPT_FILE; {
goto on_error; INF("%s", err.message);
} *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
heif_context_free(ctx);
return ret;
}
err = heif_context_read_from_memory_without_copy(hc, map, length, NULL); err = heif_context_get_primary_image_handle(ctx, &handle);
if (err.code != heif_error_Ok) { if (err.code != heif_error_Ok)
INF("%s", err.message); {
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; INF("%s", err.message);
goto on_error; *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
} heif_image_handle_release(handle);
heif_context_free(ctx);
return ret;
}
err = heif_context_get_primary_image_handle(hc, &hdl); loader->ctx = ctx;
if (err.code != heif_error_Ok) { }
INF("%s", err.message);
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
goto on_error;
}
err = heif_decode_image(hdl, &img, heif_colorspace_RGB, err = heif_decode_image(handle, &img, heif_colorspace_RGB,
prop->alpha ? heif_chroma_interleaved_RGBA : heif_chroma_interleaved_RGB, prop->alpha ? heif_chroma_interleaved_RGBA
: heif_chroma_interleaved_RGB,
NULL); NULL);
if (err.code != heif_error_Ok) {
INF("%s", err.message); if (err.code != heif_error_Ok)
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; {
goto on_error; INF("%s", err.message);
} *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
if (prop->alpha) bps = 4; goto on_error;
}
data = heif_image_get_plane_readonly(img, heif_channel_interleaved, &stride); data = heif_image_get_plane_readonly(img, heif_channel_interleaved, &stride);
ds = (uint8_t*)data;
for (y = 0; y < prop->h; y++) dd = (unsigned char *)pixels;
for (x = 0; x < prop->w; x++) ds = (unsigned char *)data;
{ if (!prop->alpha)
if (bps == 3) {
for (y = 0; y < prop->h; y++)
{
for (x = 0; x < prop->w; x++)
{ {
dd[3] = 0xff; dd[3] = 0xff;
dd[0] = ds[2]; dd[0] = ds[2];
@ -208,7 +188,13 @@ evas_image_load_file_data_heif(void *loader_data,
ds+=3; ds+=3;
dd+=4; dd+=4;
} }
else }
}
else
{
for (y = 0; y < prop->h; y++)
{
for (x = 0; x < prop->w; x++)
{ {
dd[0] = ds[2]; dd[0] = ds[2];
dd[1] = ds[1]; dd[1] = ds[1];
@ -217,50 +203,135 @@ evas_image_load_file_data_heif(void *loader_data,
ds+=4; ds+=4;
dd+=4; dd+=4;
} }
} }
result = EINA_TRUE; }
ret = EINA_TRUE;
*error = EVAS_LOAD_ERROR_NONE; *error = EVAS_LOAD_ERROR_NONE;
prop->premul = EINA_TRUE; prop->premul = EINA_TRUE;
on_error: on_error:
return ret;
}
if (map) eina_file_map_free(f, map);
if (img) { static void *
// Do not free the image here when we pass it to gdk-pixbuf, as its memory will still be used by gdk-pixbuf. evas_image_load_file_open_heif(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
heif_image_release(img); Evas_Image_Load_Opts *opts,
} Evas_Image_Animated *animated EINA_UNUSED,
int *error)
{
Evas_Loader_Internal *loader;
if (hdl) { loader = calloc(1, sizeof (Evas_Loader_Internal));
heif_image_handle_release(hdl); if (!loader)
} {
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
return NULL;
}
if (hc) { loader->f = f;
heif_context_free(hc); loader->opts = opts;
}
return result; return loader;
}
static void
evas_image_load_file_close_heif(void *loader_data)
{
Evas_Loader_Internal *loader;
loader = loader_data;
/*
* in case _head() fails (because the file is not an heif one),
* loader is not filled and loader->ctx is NULL
*/
if (loader->ctx)
heif_context_free(loader->ctx);
free(loader_data);
}
static Eina_Bool
evas_image_load_file_head_heif(void *loader_data,
Evas_Image_Property *prop,
int *error)
{
Evas_Loader_Internal *loader = loader_data;
Eina_File *f;
void *map;
Eina_Bool val;
f = loader->f;
map = eina_file_map_all(f, EINA_FILE_RANDOM);
if (!map)
{
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
return EINA_FALSE;
}
val = evas_image_load_file_head_heif_internal(loader,
(Emile_Image_Property *)prop,
map, eina_file_size_get(f),
error);
eina_file_map_free(f, map);
return val;
}
static Eina_Bool
evas_image_load_file_data_heif(void *loader_data,
Evas_Image_Property *prop,
void *pixels,
int *error)
{
Evas_Loader_Internal *loader;
Eina_File *f;
void *map;
Eina_Bool val = EINA_FALSE;
loader = (Evas_Loader_Internal *)loader_data;
f = loader->f;
map = eina_file_map_all(f, EINA_FILE_WILLNEED);
if (!map)
{
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
goto on_error;
}
val = evas_image_load_file_data_heif_internal(loader,
(Emile_Image_Property *)prop,
pixels,
map, eina_file_size_get(f),
error);
eina_file_map_free(f, map);
on_error:
return val;
} }
static const Evas_Image_Load_Func evas_image_load_heif_func = { static const Evas_Image_Load_Func evas_image_load_heif_func = {
EVAS_IMAGE_LOAD_VERSION, EVAS_IMAGE_LOAD_VERSION,
evas_image_load_file_open_heif, evas_image_load_file_open_heif,
evas_image_load_file_close_heif, evas_image_load_file_close_heif,
(void*) evas_image_load_file_head_heif, evas_image_load_file_head_heif,
NULL, NULL,
(void*) evas_image_load_file_data_heif, evas_image_load_file_data_heif,
NULL, NULL,
EINA_TRUE, EINA_FALSE,
EINA_FALSE EINA_FALSE
}; };
static int static int
module_open(Evas_Module *em) module_open(Evas_Module *em)
{ {
if (!em) return 0; if (!em) return 0;
_evas_loader_heif_log_dom = eina_log_domain_register
("evas-heif", EVAS_DEFAULT_LOG_COLOR); _evas_loader_heif_log_dom = eina_log_domain_register("evas-heif", EVAS_DEFAULT_LOG_COLOR);
if (_evas_loader_heif_log_dom < 0) if (_evas_loader_heif_log_dom < 0)
{ {
EINA_LOG_ERR("Can not create a module log domain."); EINA_LOG_ERR("Can not create a module log domain.");
@ -268,6 +339,7 @@ module_open(Evas_Module *em)
} }
em->functions = (void *)(&evas_image_load_heif_func); em->functions = (void *)(&evas_image_load_heif_func);
return 1; return 1;
} }