aboutsummaryrefslogtreecommitdiff
path: root/src/backend_freeimage.c
diff options
context:
space:
mode:
authorHarry Jeffery <harry@exec64.co.uk>2019-08-30 00:40:29 +0100
committerHarry Jeffery <harry@exec64.co.uk>2019-08-30 00:40:29 +0100
commit8b2aaf102f76921721209459eea10bed2094a730 (patch)
tree6942c0e840252e8832aa0a8276435045525a40b4 /src/backend_freeimage.c
parent4c0123bb3b449a2ea45b3e831db725d853bb03a1 (diff)
downloadimv-8b2aaf102f76921721209459eea10bed2094a730.tar.gz
source: Refactor out common async logic
Diffstat (limited to 'src/backend_freeimage.c')
-rw-r--r--src/backend_freeimage.c207
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;
}