diff options
Diffstat (limited to 'src/source.c')
-rw-r--r-- | src/source.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/source.c b/src/source.c new file mode 100644 index 0000000..6203dfe --- /dev/null +++ b/src/source.c @@ -0,0 +1,132 @@ +#include "source.h" +#include "source_private.h" + +#include <pthread.h> +#include <stdlib.h> + +struct imv_source { + /* pointers to implementation's functions */ + const struct imv_source_vtable *vtable; + + /* pointer to implementation data */ + void *private; + + /* Attempted to be locked by load_first_frame or load_next_frame. + * If the mutex can't be locked, the call is aborted. + * Used to prevent the source from having multiple worker threads at once. + * Released by the source before calling the message callback with a result. + */ + pthread_mutex_t busy; + + /* callback function */ + imv_source_callback callback; + /* callback data */ + void *callback_data; +}; + +struct imv_source *imv_source_create(const struct imv_source_vtable *vtable, void *private) +{ + struct imv_source *source = calloc(1, sizeof *source); + source->vtable = vtable; + source->private = private; + pthread_mutex_init(&source->busy, NULL); + return source; +} + +static void *free_thread(void *src) +{ + imv_source_free(src); + return NULL; +} + +void imv_source_async_free(struct imv_source *src) +{ + pthread_t thread; + pthread_create(&thread, NULL, free_thread, src); + pthread_detach(thread); +} + +static void *first_frame_thread(void *src) +{ + imv_source_load_first_frame(src); + return NULL; +} + +void imv_source_async_load_first_frame(struct imv_source *src) +{ + pthread_t thread; + pthread_create(&thread, NULL, first_frame_thread, src); + pthread_detach(thread); +} + +static void *next_frame_thread(void *src) +{ + imv_source_load_next_frame(src); + return NULL; +} +void imv_source_async_load_next_frame(struct imv_source *src) +{ + pthread_t thread; + pthread_create(&thread, NULL, next_frame_thread, src); + pthread_detach(thread); +} + +void imv_source_free(struct imv_source *src) +{ + pthread_mutex_lock(&src->busy); + src->vtable->free(src->private); + pthread_mutex_unlock(&src->busy); + pthread_mutex_destroy(&src->busy); + free(src); +} + +void imv_source_load_first_frame(struct imv_source *src) +{ + if (!src->vtable->load_first_frame) { + return; + } + + if (pthread_mutex_trylock(&src->busy)) { + return; + } + + struct imv_source_message msg = { + .source = src, + .user_data = src->callback_data + }; + + src->vtable->load_first_frame(src->private, &msg.image, &msg.frametime); + + pthread_mutex_unlock(&src->busy); + + src->callback(&msg); +} + +void imv_source_load_next_frame(struct imv_source *src) +{ + if (!src->vtable->load_next_frame) { + return; + } + + if (pthread_mutex_trylock(&src->busy)) { + return; + } + + struct imv_source_message msg = { + .source = src, + .user_data = src->callback_data + }; + + src->vtable->load_next_frame(src->private, &msg.image, &msg.frametime); + + pthread_mutex_unlock(&src->busy); + + src->callback(&msg); +} + +void imv_source_set_callback(struct imv_source *src, imv_source_callback callback, + void *data) +{ + src->callback = callback; + src->callback_data = data; +} |