aboutsummaryrefslogtreecommitdiff
path: root/src/backend_libjpeg.c
diff options
context:
space:
mode:
authorHarry Jeffery <harry@exec64.co.uk>2019-01-31 21:40:28 +0000
committerHarry Jeffery <harry@exec64.co.uk>2019-01-31 22:04:48 +0000
commitbd3504c58025499b5fd0f845d7af19bbcca315b9 (patch)
tree73ad091ab607b44f140f2a5462f9ab67afc7af94 /src/backend_libjpeg.c
parentc46924345fc0ef7574e864127c164d72c1fd3011 (diff)
downloadimv-bd3504c58025499b5fd0f845d7af19bbcca315b9.tar.gz
Add libjpeg-turbo backend
Diffstat (limited to 'src/backend_libjpeg.c')
-rw-r--r--src/backend_libjpeg.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/backend_libjpeg.c b/src/backend_libjpeg.c
new file mode 100644
index 0000000..acbd6b3
--- /dev/null
+++ b/src/backend_libjpeg.c
@@ -0,0 +1,181 @@
+#include "backend_libjpeg.h"
+#include "backend.h"
+#include "source.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef IMV_BACKEND_LIBJPEG
+
+#include <turbojpeg.h>
+
+struct private {
+ int fd;
+ void *data;
+ size_t len;
+ tjhandle jpeg;
+};
+
+static void source_free(struct imv_source *src)
+{
+ free(src->name);
+ src->name = NULL;
+
+ struct private *private = src->private;
+ tjDestroy(private->jpeg);
+ munmap(private->data, private->len);
+ private->data = NULL;
+ close(private->fd);
+
+ free(src->private);
+ src->private = NULL;
+
+ free(src);
+}
+
+static struct imv_bitmap *to_imv_bitmap(int width, int height, void *bitmap)
+{
+ struct imv_bitmap *bmp = malloc(sizeof(struct imv_bitmap));
+ bmp->width = width;
+ bmp->height = height;
+ bmp->format = IMV_ABGR;
+ bmp->data = bitmap;
+ return bmp;
+}
+
+static void report_error(struct imv_source *src)
+{
+ if (!src->callback) {
+ fprintf(stderr, "imv_source(%s) has no callback configured. "
+ "Discarding error.\n", src->name);
+ return;
+ }
+
+ struct imv_source_message msg;
+ msg.source = src;
+ msg.user_data = src->user_data;
+ msg.bitmap = NULL;
+ msg.error = "Internal error";
+
+ src->callback(&msg);
+}
+
+static void send_bitmap(struct imv_source *src, void *bitmap)
+{
+ if (!src->callback) {
+ fprintf(stderr, "imv_source(%s) has no callback configured. "
+ "Discarding result.\n", src->name);
+ return;
+ }
+
+ struct imv_source_message msg;
+ msg.source = src;
+ msg.user_data = src->user_data;
+ msg.bitmap = to_imv_bitmap(src->width, src->height, bitmap);
+ msg.frametime = 0;
+ msg.error = NULL;
+
+ src->callback(&msg);
+}
+
+static void load_image(struct imv_source *src)
+{
+ struct private *private = src->private;
+
+ void *bitmap = malloc(src->height * src->width * 4);
+ int rcode = tjDecompress2(private->jpeg, private->data, private->len,
+ bitmap, src->width, 0, src->height, TJPF_RGBA, TJFLAG_FASTDCT);
+
+ if (!rcode) {
+ send_bitmap(src, bitmap);
+ } else {
+ free(bitmap);
+ report_error(src);
+ return;
+ }
+}
+
+static enum backend_result open_path(const char *path, struct imv_source **src)
+{
+ struct private private;
+
+ private.fd = open(path, O_RDONLY);
+ if (private.fd < 0) {
+ return BACKEND_BAD_PATH;
+ }
+
+ off_t len = lseek(private.fd, 0, SEEK_END);
+ if (len < 0) {
+ close(private.fd);
+ return BACKEND_BAD_PATH;
+ }
+
+ private.len = len;
+
+ private.data = mmap(NULL, private.len, PROT_READ, MAP_PRIVATE, private.fd, 0);
+ if (!private.data) {
+ close(private.fd);
+ return BACKEND_BAD_PATH;
+ }
+
+ private.jpeg = tjInitDecompress();
+ if (!private.jpeg) {
+ munmap(private.data, private.len);
+ close(private.fd);
+ return BACKEND_UNSUPPORTED;
+ }
+
+ int width, height;
+ int rcode = tjDecompressHeader(private.jpeg, private.data, private.len,
+ &width, &height);
+ if (rcode) {
+ tjDestroy(private.jpeg);
+ munmap(private.data, private.len);
+ close(private.fd);
+ return BACKEND_UNSUPPORTED;
+ }
+
+ struct imv_source *source = calloc(1, sizeof(struct imv_source));
+ source->name = strdup(path);
+ source->width = width;
+ source->height = height;
+ source->num_frames = 1;
+ source->next_frame = 1;
+ source->load_first_frame = &load_image;
+ source->load_next_frame = NULL;
+ source->free = &source_free;
+ source->callback = NULL;
+ source->user_data = NULL;
+ source->private = malloc(sizeof private);
+ memcpy(source->private, &private, sizeof private);
+
+ *src = source;
+ return BACKEND_SUCCESS;
+}
+
+const struct imv_backend libjpeg_backend = {
+ .name = "libjpeg-turbo",
+ .description = "Fast JPEG codec based on libjpeg. "
+ "This software is based in part on the work "
+ "of the Independent JPEG Group.",
+ .website = "https://libjpeg-turbo.org/",
+ .license = "The Modified BSD License",
+ .open_path = &open_path,
+};
+
+const struct imv_backend *imv_backend_libjpeg(void)
+{
+ return &libjpeg_backend;
+}
+
+#else
+
+const struct imv_backend *imv_backend_libjpeg(void)
+{
+ return NULL;
+}
+
+#endif