diff options
author | Harry Jeffery <harry@exec64.co.uk> | 2019-08-30 00:40:29 +0100 |
---|---|---|
committer | Harry Jeffery <harry@exec64.co.uk> | 2019-08-30 00:40:29 +0100 |
commit | 8b2aaf102f76921721209459eea10bed2094a730 (patch) | |
tree | 6942c0e840252e8832aa0a8276435045525a40b4 /src/backend_freeimage.c | |
parent | 4c0123bb3b449a2ea45b3e831db725d853bb03a1 (diff) | |
download | imv-8b2aaf102f76921721209459eea10bed2094a730.tar.gz |
source: Refactor out common async logic
Diffstat (limited to 'src/backend_freeimage.c')
-rw-r--r-- | src/backend_freeimage.c | 207 |
1 files changed, 77 insertions, 130 deletions
diff --git a/src/backend_freeimage.c b/src/backend_freeimage.c index bdddff2..f3b8d7e 100644 --- a/src/backend_freeimage.c +++ b/src/backend_freeimage.c @@ -1,28 +1,35 @@ #include "backend.h" -#include "source.h" +#include "bitmap.h" +#include "image.h" #include "log.h" - -#include <assert.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> +#include "source.h" +#include "source_private.h" #include <FreeImage.h> +#include <stdlib.h> struct private { + char *path; FIMEMORY *memory; FREE_IMAGE_FORMAT format; FIMULTIBITMAP *multibitmap; FIBITMAP *last_frame; + int num_frames; + int next_frame; + int width; + int height; }; -static void source_free(struct imv_source *src) +static void free_private(void *raw_private) { - pthread_mutex_lock(&src->busy); - free(src->name); - src->name = NULL; + if (!raw_private) { + return; + } + + struct private *private = raw_private; - struct private *private = src->private; + free(private->path); + private->path = NULL; if (private->memory) { FreeImage_CloseMemory(private->memory); @@ -40,11 +47,6 @@ static void source_free(struct imv_source *src) } free(private); - src->private = NULL; - - pthread_mutex_unlock(&src->busy); - pthread_mutex_destroy(&src->busy); - free(src); } static struct imv_image *to_image(FIBITMAP *in_bmp) @@ -95,55 +97,20 @@ static FIBITMAP *normalise_bitmap(FIBITMAP *input) return output; } -static void report_error(struct imv_source *src, const char *error) +static void first_frame(void *raw_private, struct imv_image **image, int *frametime) { - imv_log(IMV_ERROR, "freeimage: %s\n", error); - - assert(src->callback); - - struct imv_source_message msg; - msg.source = src; - msg.user_data = src->user_data; - msg.image = NULL; - msg.error = error; + *image = NULL; + *frametime = 0; - pthread_mutex_unlock(&src->busy); - src->callback(&msg); -} - -static void send_bitmap(struct imv_source *src, FIBITMAP *fibitmap, int frametime) -{ - imv_log(IMV_DEBUG, "freeimage: returning bitmap\n"); - assert(src->callback); - - struct imv_source_message msg; - msg.source = src; - msg.user_data = src->user_data; - msg.image = to_image(fibitmap); - msg.frametime = frametime; - msg.error = NULL; - - pthread_mutex_unlock(&src->busy); - src->callback(&msg); -} - -static void *first_frame(struct imv_source *src) -{ - /* Don't run if this source is already active */ - if (pthread_mutex_trylock(&src->busy)) { - return NULL; - } imv_log(IMV_DEBUG, "freeimage: first_frame called\n"); FIBITMAP *bmp = NULL; - struct private *private = src->private; - - int frametime = 0; + struct private *private = raw_private; if (private->format == FIF_GIF) { - if (src->name) { - private->multibitmap = FreeImage_OpenMultiBitmap(FIF_GIF, src->name, + if (private->path) { + private->multibitmap = FreeImage_OpenMultiBitmap(FIF_GIF, private->path, /* don't create file */ 0, /* read only */ 1, /* keep in memory */ 1, @@ -153,110 +120,109 @@ static void *first_frame(struct imv_source *src) private->memory, /* flags */ GIF_LOAD256); } else { - report_error(src, "src->name and private->memory both NULL"); - return NULL; + imv_log(IMV_ERROR, "private->path and private->memory both NULL"); + return; } if (!private->multibitmap) { - report_error(src, "first frame already loaded"); - return NULL; + imv_log(IMV_ERROR, "first frame already loaded"); + return; } FIBITMAP *frame = FreeImage_LockPage(private->multibitmap, 0); - src->num_frames = FreeImage_GetPageCount(private->multibitmap); + private->num_frames = FreeImage_GetPageCount(private->multibitmap); /* Get duration of first frame */ FITAG *tag = NULL; FreeImage_GetMetadata(FIMD_ANIMATION, frame, "FrameTime", &tag); - if(FreeImage_GetTagValue(tag)) { - frametime = *(int*)FreeImage_GetTagValue(tag); + if (FreeImage_GetTagValue(tag)) { + *frametime = *(int*)FreeImage_GetTagValue(tag); } else { - frametime = 100; /* default value for gifs */ + *frametime = 100; /* default value for gifs */ } bmp = FreeImage_ConvertTo24Bits(frame); FreeImage_UnlockPage(private->multibitmap, frame, 0); } else { /* not a gif */ - src->num_frames = 1; + private->num_frames = 1; int flags = (private->format == FIF_JPEG) ? JPEG_EXIFROTATE : 0; FIBITMAP *fibitmap = NULL; - if (src->name) { - fibitmap = FreeImage_Load(private->format, src->name, flags); + if (private->path) { + fibitmap = FreeImage_Load(private->format, private->path, flags); } else if (private->memory) { fibitmap = FreeImage_LoadFromMemory(private->format, private->memory, flags); } if (!fibitmap) { - report_error(src, "FreeImage_Load returned NULL"); - return NULL; + imv_log(IMV_ERROR, "FreeImage_Load returned NULL"); + return; } bmp = normalise_bitmap(fibitmap); } - src->width = FreeImage_GetWidth(bmp); - src->height = FreeImage_GetHeight(bmp); + private->width = FreeImage_GetWidth(bmp); + private->height = FreeImage_GetHeight(bmp); private->last_frame = bmp; - send_bitmap(src, bmp, frametime); - return NULL; + private->next_frame = 1 % private->num_frames; + + *image = to_image(bmp); } -static void *next_frame(struct imv_source *src) +static void next_frame(void *raw_private, struct imv_image **image, int *frametime) { - /* Don't run if this source is already active */ - if (pthread_mutex_trylock(&src->busy)) { - return NULL; - } + *image = NULL; + *frametime = 0; + + struct private *private = raw_private; - struct private *private = src->private; - if (src->num_frames == 1) { - send_bitmap(src, private->last_frame, 0); - return NULL; + if (private->num_frames == 1) { + *image = to_image(private->last_frame); + return; } FITAG *tag = NULL; char disposal_method = 0; - int frametime = 0; short top = 0; short left = 0; - FIBITMAP *frame = FreeImage_LockPage(private->multibitmap, src->next_frame); + FIBITMAP *frame = FreeImage_LockPage(private->multibitmap, private->next_frame); FIBITMAP *frame32 = FreeImage_ConvertTo32Bits(frame); /* First frame is always going to use the raw frame */ - if(src->next_frame > 0) { + if (private->next_frame > 0) { FreeImage_GetMetadata(FIMD_ANIMATION, frame, "DisposalMethod", &tag); - if(FreeImage_GetTagValue(tag)) { + if (FreeImage_GetTagValue(tag)) { disposal_method = *(char*)FreeImage_GetTagValue(tag); } } FreeImage_GetMetadata(FIMD_ANIMATION, frame, "FrameLeft", &tag); - if(FreeImage_GetTagValue(tag)) { + if (FreeImage_GetTagValue(tag)) { left = *(short*)FreeImage_GetTagValue(tag); } FreeImage_GetMetadata(FIMD_ANIMATION, frame, "FrameTop", &tag); - if(FreeImage_GetTagValue(tag)) { + if (FreeImage_GetTagValue(tag)) { top = *(short*)FreeImage_GetTagValue(tag); } FreeImage_GetMetadata(FIMD_ANIMATION, frame, "FrameTime", &tag); - if(FreeImage_GetTagValue(tag)) { - frametime = *(int*)FreeImage_GetTagValue(tag); + if (FreeImage_GetTagValue(tag)) { + *frametime = *(int*)FreeImage_GetTagValue(tag); } /* some gifs don't provide a frame time at all */ - if(frametime == 0) { - frametime = 100; + if (*frametime == 0) { + *frametime = 100; } FreeImage_UnlockPage(private->multibitmap, frame, 0); /* If this frame is inset, we need to expand it for compositing */ - if(src->width != (int)FreeImage_GetWidth(frame32) || - src->height != (int)FreeImage_GetHeight(frame32)) { - FIBITMAP *expanded = FreeImage_Allocate(src->width, src->height, 32, 0,0,0); + if (private->width != (int)FreeImage_GetWidth(frame32) || + private->height != (int)FreeImage_GetHeight(frame32)) { + FIBITMAP *expanded = FreeImage_Allocate(private->width, private->height, 32, 0,0,0); FreeImage_Paste(expanded, frame32, left, top, 255); FreeImage_Unload(frame32); frame32 = expanded; @@ -265,7 +231,7 @@ static void *next_frame(struct imv_source *src) switch(disposal_method) { case 0: /* nothing specified, fall through to compositing */ case 1: /* composite over previous frame */ - if(private->last_frame && src->next_frame > 0) { + if (private->last_frame && private->next_frame > 0) { FIBITMAP *bg_frame = FreeImage_ConvertTo24Bits(private->last_frame); FreeImage_Unload(private->last_frame); FIBITMAP *comp = FreeImage_Composite(frame32, 1, NULL, bg_frame); @@ -281,25 +247,30 @@ static void *next_frame(struct imv_source *src) } break; case 2: /* TODO - set to background, composite over that */ - if(private->last_frame) { + if (private->last_frame) { FreeImage_Unload(private->last_frame); } private->last_frame = frame32; break; case 3: /* TODO - restore to previous content */ - if(private->last_frame) { + if (private->last_frame) { FreeImage_Unload(private->last_frame); } private->last_frame = frame32; break; } - src->next_frame = (src->next_frame + 1) % src->num_frames; + private->next_frame = (private->next_frame + 1) % private->num_frames; - send_bitmap(src, private->last_frame, frametime); - return NULL; + *image = to_image(private->last_frame); } +static const struct imv_source_vtable vtable = { + .load_first_frame = first_frame, + .load_next_frame = next_frame, + .free = free_private +}; + static enum backend_result open_path(const char *path, struct imv_source **src) { imv_log(IMV_DEBUG, "freeimage: open_path(%s)\n", path); @@ -312,21 +283,9 @@ static enum backend_result open_path(const char *path, struct imv_source **src) struct private *private = calloc(1, sizeof(struct private)); private->format = fmt; + private->path = strdup(path); - struct imv_source *source = calloc(1, sizeof *source); - source->name = strdup(path); - source->width = 0; - source->height = 0; - source->num_frames = 0; - pthread_mutex_init(&source->busy, NULL); - source->load_first_frame = &first_frame; - source->load_next_frame = &next_frame; - source->free = &source_free; - source->callback = NULL; - source->user_data = NULL; - source->private = private; - *src = source; - + *src = imv_source_create(&vtable, private); return BACKEND_SUCCESS; } @@ -344,21 +303,9 @@ static enum backend_result open_memory(void *data, size_t len, struct imv_source struct private *private = calloc(1, sizeof(struct private)); private->format = fmt; private->memory = fmem; + private->path = NULL; - struct imv_source *source = calloc(1, sizeof *source); - source->name = NULL; - source->width = 0; - source->height = 0; - source->num_frames = 0; - pthread_mutex_init(&source->busy, NULL); - source->load_first_frame = &first_frame; - source->load_next_frame = &next_frame; - source->free = &source_free; - source->callback = NULL; - source->user_data = NULL; - source->private = private; - *src = source; - + *src = imv_source_create(&vtable, private); return BACKEND_SUCCESS; } |