diff options
-rw-r--r-- | main.c | 475 |
1 files changed, 326 insertions, 149 deletions
@@ -14,6 +14,9 @@ #include <lo/lo.h> +/* + * Macros + */ #define NARRAY(ARRAY) \ (sizeof(ARRAY) / sizeof((ARRAY)[0])) @@ -37,18 +40,45 @@ __FILE__, __LINE__, ##__VA_ARGS__, IMG_GetError()); \ } while (0) +/* + * Default values + */ #define SCREEN_WIDTH 640 #define SCREEN_HEIGHT 480 #define FRAMERATE 20 /* Hz */ -static inline void effect_bg_change(SDL_Color color); +/* + * Declarations + */ +typedef void (*layer_frame_cb_t)(void *data, SDL_Surface *target); +typedef void (*layer_free_cb_t)(void *data); + +static int layer_insert(int pos, const char *name, void *data, + layer_frame_cb_t frame_cb, layer_free_cb_t free_cb); + +static struct layer_image *layer_image_new(const char *file); +static void layer_image_change(struct layer_image *ctx, const char *file); +static void layer_image_frame_cb(void *data, SDL_Surface *target); +static void layer_image_free_cb(void *data); + +static struct layer_video *layer_video_new(const char *file, SDL_Color *key); +static void layer_video_change(struct layer_video *ctx, + const char *file, SDL_Color *key); +static void layer_video_frame_cb(void *data, SDL_Surface *target); +static void layer_video_free_cb(void *data); + +static struct layer_rect *layer_rect_new(SDL_Rect rect, SDL_Color color); +static void layer_rect_change(struct layer_rect *ctx, + SDL_Rect rect, SDL_Color color); +static void layer_rect_frame_cb(void *data, SDL_Surface *target); +static void layer_rect_free_cb(void *data); static SDL_Surface *screen; static void osc_error(int num, const char *msg, const char *path) { - printf("liblo server error %d in path %s: %s\n", num, path, msg); + fprintf(stderr, "liblo server error %d in path %s: %s\n", num, path, msg); } /* catch any incoming messages and display them. returning 1 means that the @@ -72,72 +102,157 @@ osc_generic_handler(const char *path, const char *types, lo_arg **argv, } static int -osc_bg_change(const char *path, const char *types, lo_arg **argv, +osc_image_new(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data __attribute__((unused))) { - effect_bg_change((SDL_Color){(Uint8)argv[0]->i, (Uint8)argv[1]->i, (Uint8)argv[2]->i}); + struct layer_image *ctx = layer_image_new(&argv[2]->s); + + layer_insert(argv[0]->i, &argv[1]->s, ctx, + layer_image_frame_cb, layer_image_free_cb); + return 0; } -static inline int -osc_init(const char *port) +static int +osc_video_new(const char *path, const char *types, lo_arg **argv, + int argc, void *data, + void *user_data __attribute__((unused))) { - lo_server_thread st = lo_server_thread_new(port, osc_error); + struct layer_video *ctx = layer_video_new(&argv[2]->s, NULL); - lo_server_thread_add_method(st, NULL, NULL, osc_generic_handler, NULL); + layer_insert(argv[0]->i, &argv[1]->s, ctx, + layer_video_frame_cb, layer_video_free_cb); - lo_server_thread_add_method(st, "/background/color", "iii", - osc_bg_change, NULL); + return 0; +} - lo_server_thread_start(st); +static int +osc_rect_new(const char *path, const char *types, lo_arg **argv, + int argc, void *data, + void *user_data __attribute__((unused))) +{ + SDL_Rect rect = { + (Sint16)argv[2]->i, (Sint16)argv[3]->i, + (Uint16)argv[4]->i, (Uint16)argv[5]->i + }; + SDL_Color color = {(Uint8)argv[6]->i, (Uint8)argv[7]->i, (Uint8)argv[8]->i}; + + struct layer_rect *ctx = layer_rect_new(rect, color); + + layer_insert(argv[0]->i, &argv[1]->s, ctx, + layer_rect_frame_cb, layer_rect_free_cb); return 0; } -static SDL_Surface *image_surface = NULL; +static inline lo_server +osc_init(const char *port) +{ + lo_server server = lo_server_new(port, osc_error); + + lo_server_add_method(server, NULL, NULL, osc_generic_handler, NULL); + + lo_server_add_method(server, "/layer/image/new", "iss", + osc_image_new, NULL); + lo_server_add_method(server, "/layer/video/new", "iss", + osc_video_new, NULL); + lo_server_add_method(server, "/layer/rect/new", "isiiiiiii", + osc_rect_new, NULL); + + return server; +} + +static inline void +osc_process_events(lo_server server) +{ + while (lo_server_recv_noblock(server, 0)); +} + +/* + * Image layers + */ +struct layer_image { + SDL_Surface *surf; +}; + +static struct layer_image * +layer_image_new(const char *file) +{ + struct layer_image *ctx = malloc(sizeof(struct layer_image)); + + if (ctx) { + memset(ctx, 0, sizeof(*ctx)); + layer_image_change(ctx, file); + } + + return ctx; +} static void -effect_image_change(const char *file) +layer_image_change(struct layer_image *ctx, const char *file) { - if (image_surface != NULL) - SDL_FreeSurface(image_surface); + if (ctx->surf) { + SDL_FreeSurface(ctx->surf); + ctx->surf = NULL; + } - if (file == NULL) { - image_surface = NULL; + if (!file || !*file) return; - } - image_surface = IMG_Load(file); - if (image_surface == NULL) { + ctx->surf = IMG_Load(file); + if (!ctx->surf) { SDL_IMAGE_ERROR("IMG_Load"); exit(EXIT_FAILURE); } - if (image_surface->w != screen->w || image_surface->h != screen->h) { + if (ctx->surf->w != screen->w || ctx->surf->h != screen->h) { SDL_Surface *new; - new = zoomSurface(image_surface, - (double)screen->w/image_surface->w, - (double)screen->h/image_surface->h, + new = zoomSurface(ctx->surf, + (double)screen->w/ctx->surf->w, + (double)screen->h/ctx->surf->h, SMOOTHING_ON); - SDL_FreeSurface(image_surface); - image_surface = new; + SDL_FreeSurface(ctx->surf); + ctx->surf = new; } } -static struct EffectVideoCtx { +static void +layer_image_frame_cb(void *data, SDL_Surface *target) +{ + struct layer_image *ctx = data; + + if (ctx->surf) + SDL_BlitSurface(ctx->surf, NULL, target, NULL); +} + +static void +layer_image_free_cb(void *data) +{ + struct layer_image *ctx = data; + + if (ctx->surf) + SDL_FreeSurface(ctx->surf); + + free(ctx); +} + +/* + * Video layer + */ +struct layer_video { libvlc_instance_t *vlcinst; libvlc_media_player_t *mp; SDL_Surface *surf; SDL_mutex *mutex; -} effect_video_ctx; +}; static void * -effect_video_lock(void *data, void **p_pixels) +layer_video_lock_cb(void *data, void **p_pixels) { - struct EffectVideoCtx *ctx = data; + struct layer_video *ctx = data; SDL_LockMutex(ctx->mutex); SDL_LockSurface(ctx->surf); @@ -147,149 +262,182 @@ effect_video_lock(void *data, void **p_pixels) } static void -effect_video_unlock(void *data, void *id, void *const *p_pixels) +layer_video_unlock_cb(void *data, void *id, void *const *p_pixels) { - struct EffectVideoCtx *ctx = data; + struct layer_video *ctx = data; - SDL_UnlockSurface(ctx->surf); - SDL_UnlockMutex(ctx->mutex); + assert(id == NULL); /* picture identifier, not needed here */ - assert(id == NULL); /* picture identifier, not needed here */ + SDL_UnlockSurface(ctx->surf); + SDL_UnlockMutex(ctx->mutex); } static void -effect_video_display(void *data __attribute__((unused)), void *id) +layer_video_display_cb(void *data __attribute__((unused)), void *id) { /* VLC wants to display the video */ - assert(id == NULL); + assert(id == NULL); /* picture identifier, not needed here */ } -static inline void -effect_video_init(void) +static struct layer_video * +layer_video_new(const char *file, SDL_Color *key) { char const *vlc_argv[] = { - "--no-audio", /* skip any audio track */ - "--no-xlib", /* tell VLC to not use Xlib */ + "--no-audio", /* skip any audio track */ + "--no-xlib" /* tell VLC to not use Xlib */ }; + struct layer_video *ctx = malloc(sizeof(struct layer_video)); + + if (!ctx) + return NULL; + + ctx->surf = SDL_CreateRGBSurface(SDL_SWSURFACE, screen->w, screen->h, + 16, 0x001f, 0x07e0, 0xf800, 0); + ctx->mutex = SDL_CreateMutex(); - effect_video_ctx.surf = SDL_CreateRGBSurface(SDL_SWSURFACE, screen->w, screen->h, - 16, 0x001f, 0x07e0, 0xf800, 0); - effect_video_ctx.mutex = SDL_CreateMutex(); + ctx->vlcinst = libvlc_new(NARRAY(vlc_argv), vlc_argv); + ctx->mp = NULL; - effect_video_ctx.vlcinst = libvlc_new(NARRAY(vlc_argv), vlc_argv); + layer_video_change(ctx, file, key); + + return ctx; } static void -effect_video_change(const char *file, SDL_Color *key) +layer_video_change(struct layer_video *ctx, const char *file, SDL_Color *key) { libvlc_media_t *m; - if (effect_video_ctx.mp != NULL) - libvlc_media_player_release(effect_video_ctx.mp); + if (ctx->mp) { + libvlc_media_player_release(ctx->mp); + ctx->mp = NULL; + } - if (file == NULL) { - effect_video_ctx.mp = NULL; + if (!file || !*file) return; - } - if (key == NULL) - SDL_SetColorKey(effect_video_ctx.surf, 0, 0); - else - SDL_SetColorKey(effect_video_ctx.surf, SDL_SRCCOLORKEY, - SDL_MapRGB(effect_video_ctx.surf->format, + if (key) { + SDL_SetColorKey(ctx->surf, SDL_SRCCOLORKEY, + SDL_MapRGB(ctx->surf->format, key->r, key->g, key->b)); + } else { + SDL_SetColorKey(ctx->surf, 0, 0); + } - m = libvlc_media_new_location(effect_video_ctx.vlcinst, file); - effect_video_ctx.mp = libvlc_media_player_new_from_media(m); + m = libvlc_media_new_location(ctx->vlcinst, file); + ctx->mp = libvlc_media_player_new_from_media(m); libvlc_media_release(m); - libvlc_video_set_callbacks(effect_video_ctx.mp, - effect_video_lock, effect_video_unlock, effect_video_display, - &effect_video_ctx); - libvlc_video_set_format(effect_video_ctx.mp, "RV16", - effect_video_ctx.surf->w, - effect_video_ctx.surf->h, - effect_video_ctx.surf->w*2); - libvlc_media_player_play(effect_video_ctx.mp); + libvlc_video_set_callbacks(ctx->mp, layer_video_lock_cb, + layer_video_unlock_cb, layer_video_display_cb, + ctx); + libvlc_video_set_format(ctx->mp, "RV16", + ctx->surf->w, + ctx->surf->h, + ctx->surf->w*2); + + libvlc_media_player_play(ctx->mp); } -static SDL_Color effect_bg_color = {0, 0, 0}; +static void +layer_video_frame_cb(void *data, SDL_Surface *target) +{ + struct layer_video *ctx = data; -static inline void -effect_bg_change(SDL_Color color) + if (ctx->mp) { + SDL_LockMutex(ctx->mutex); + SDL_BlitSurface(ctx->surf, NULL, target, NULL); + SDL_UnlockMutex(ctx->mutex); + } +} + +static void +layer_video_free_cb(void *data) { - effect_bg_color = color; + struct layer_video *ctx = data; + + if (ctx->mp) + libvlc_media_player_release(ctx->mp); + libvlc_release(ctx->vlcinst); + SDL_DestroyMutex(ctx->mutex); + SDL_FreeSurface(ctx->surf); + + free(ctx); +} + +/* + * Rectangle layer + */ +struct layer_rect { + SDL_Rect rect; + SDL_Color color; +}; + +static struct layer_rect * +layer_rect_new(SDL_Rect rect, SDL_Color color) +{ + struct layer_rect *ctx = malloc(sizeof(struct layer_rect)); + + if (ctx) + layer_rect_change(ctx, rect, color); + + return ctx; +} + +static void +layer_rect_change(struct layer_rect *ctx, SDL_Rect rect, SDL_Color color) +{ + ctx->rect = rect; + ctx->color = color; +} + +static void +layer_rect_frame_cb(void *data, SDL_Surface *target) +{ + struct layer_rect *ctx = data; + SDL_Rect *dstrect = &ctx->rect; + + if (!dstrect->x && !dstrect->y && !dstrect->w && !dstrect->h) + dstrect = NULL; + + SDL_FillRect(target, dstrect, + SDL_MapRGB(target->format, + ctx->color.r, ctx->color.g, ctx->color.b)); +} + +static void +layer_rect_free_cb(void *data) +{ + struct layer_rect *ctx = data; + + free(ctx); } static inline void -process_events(void) +sdl_process_events(void) { SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_KEYDOWN: - if (event.key.keysym.mod & KMOD_LALT) { - switch (event.key.keysym.sym) { - case SDLK_0: - effect_bg_change((SDL_Color){0, 0, 0}); - break; - case SDLK_1: - effect_bg_change((SDL_Color){255, 0, 0}); - break; - case SDLK_2: - effect_bg_change((SDL_Color){0, 255, 0}); - break; - case SDLK_3: - effect_bg_change((SDL_Color){0, 0, 255}); - break; - default: - break; - } - } else if (event.key.keysym.mod & KMOD_RCTRL) { - switch (event.key.keysym.sym) { - case SDLK_0: - effect_video_change(NULL, NULL); - break; - case SDLK_1: - effect_video_change("v4l2://", &(SDL_Color){0, 0, 0}); - break; - case SDLK_2: - effect_video_change("/mnt/data/movies/Godzilla.-.1967.-.Frankenstein.jagt.Godzillas.Sohn.KHPP.avi", - &(SDL_Color){255, 255, 255}); - break; - default: - break; - } - } else { - switch (event.key.keysym.sym) { - case SDLK_F11: - if (!SDL_WM_ToggleFullScreen(screen)) { - SDL_ERROR("SDL_WM_ToggleFullScreen"); - exit(EXIT_FAILURE); - } - break; - - case SDLK_F10: - SDL_ShowCursor(!SDL_ShowCursor(SDL_QUERY)); - break; - - case SDLK_ESCAPE: - exit(EXIT_SUCCESS); - - case SDLK_0: - effect_image_change(NULL); - break; - case SDLK_1: - effect_image_change("image_1.jpg"); - break; - case SDLK_2: - effect_image_change("image_2.png"); - break; - - default: - break; + switch (event.key.keysym.sym) { + case SDLK_F11: + if (!SDL_WM_ToggleFullScreen(screen)) { + SDL_ERROR("SDL_WM_ToggleFullScreen"); + exit(EXIT_FAILURE); } + break; + + case SDLK_F10: + SDL_ShowCursor(!SDL_ShowCursor(SDL_QUERY)); + break; + + case SDLK_ESCAPE: + exit(EXIT_SUCCESS); + + default: + break; } break; @@ -302,12 +450,54 @@ process_events(void) } } +struct layer { + struct layer *next; + + char *name; + + void *data; + layer_frame_cb_t frame_cb; + layer_free_cb_t free_cb; +}; +static struct layer layers_head = {NULL}; + +#define FOREACH_LAYER(VAR) \ + for (struct layer *VAR = layers_head.next; VAR; VAR = VAR->next) + +static int +layer_insert(int pos, const char *name, void *data, + layer_frame_cb_t frame_cb, layer_free_cb_t free_cb) +{ + struct layer *new, *cur; + + new = malloc(sizeof(struct layer)); + if (!new) + return -1; + + new->name = strdup(name); + if (!new->name) { + free(new); + return -1; + } + new->data = data; + new->frame_cb = frame_cb; + new->free_cb = free_cb; + + for (cur = &layers_head; cur->next && pos; cur = cur->next, pos--); + new->next = cur->next; + cur->next = new; + + return 0; +} + int main(int argc, char **argv) { + lo_server osc_server; FPSmanager fpsm; - if (osc_init("7770")) + osc_server = osc_init("7770"); + if (!osc_server) return EXIT_FAILURE; if (SDL_Init(SDL_INIT_VIDEO)) { @@ -328,25 +518,12 @@ main(int argc, char **argv) SDL_initFramerate(&fpsm); SDL_setFramerate(&fpsm, FRAMERATE); - effect_video_init(); - for (;;) { - process_events(); - - SDL_FillRect(screen, NULL, - SDL_MapRGB(screen->format, - effect_bg_color.r, - effect_bg_color.g, - effect_bg_color.b)); - - if (effect_video_ctx.mp != NULL) { - SDL_LockMutex(effect_video_ctx.mutex); - SDL_BlitSurface(effect_video_ctx.surf, NULL, screen, NULL); - SDL_UnlockMutex(effect_video_ctx.mutex); - } + sdl_process_events(); + osc_process_events(osc_server); - if (image_surface != NULL) - SDL_BlitSurface(image_surface, NULL, screen, NULL); + FOREACH_LAYER(cur) + cur->frame_cb(cur->data, screen); SDL_Flip(screen); SDL_framerateDelay(&fpsm); |