From c3ead7852ff4ccb96f3a309a5ddbda2f837997ae Mon Sep 17 00:00:00 2001 From: Martin Pulec Date: Wed, 14 Aug 2013 14:58:59 +0200 Subject: [PATCH] Added control to capture filters --- src/capture_filter.c | 104 +++++++++++++++++++++++++++---------- src/capture_filter.h | 8 ++- src/capture_filter/blank.c | 96 ++++++++++++++++++++++------------ src/capture_filter/every.c | 10 +++- src/control_socket.cpp | 19 +++++-- src/host.c | 8 +-- src/host.h | 3 +- src/main.c | 3 +- src/messaging.h | 5 ++ src/module.c | 2 + src/module.h | 2 + src/utils/list.c | 34 ++++++++++++ src/utils/list.h | 6 +++ src/video_capture.c | 18 +++++-- src/video_capture.h | 4 +- 15 files changed, 245 insertions(+), 77 deletions(-) diff --git a/src/capture_filter.c b/src/capture_filter.c index 6f3896b25..f45aa8365 100644 --- a/src/capture_filter.c +++ b/src/capture_filter.c @@ -53,6 +53,7 @@ #endif /* HAVE_CONFIG_H */ #include "capture_filter.h" +#include "module.h" #include "utils/list.h" #include "video.h" @@ -65,6 +66,7 @@ static struct capture_filter_info *capture_filters[] = { }; struct capture_filter { + struct module mod; struct simple_linked_list *filters; }; @@ -73,7 +75,41 @@ struct capture_filter_instance { void *state; }; -int capture_filter_init(const char *cfg, struct capture_filter **state) +static bool create_filter(struct capture_filter *s, char *cfg) +{ + unsigned int i; + char *options = NULL; + char *filter_name = cfg; + if(strchr(filter_name, ':')) { + options = strchr(filter_name, ':') + 1; + *strchr(filter_name, ':') = '\0'; + } + for(i = 0; i < sizeof(capture_filters) / sizeof(struct capture_filter_info *); ++i) { + if(strcasecmp(capture_filters[i]->name, filter_name) == 0) { + struct capture_filter_instance *instance = + malloc(sizeof(struct capture_filter_instance)); + instance->index = i; + int ret = capture_filters[i]->init(&s->mod, options, &instance->state); + if(ret < 0) { + fprintf(stderr, "Unable to initialize capture filter: %s\n", + filter_name); + } + if(ret != 0) { + return ret; + } + simple_linked_list_append(s->filters, instance); + break; + } + } + if(i == sizeof(capture_filters) / sizeof(struct capture_filter_info *)) { + fprintf(stderr, "Unable to find capture filter: %s\n", + filter_name); + return false; + } + return true; +} + +int capture_filter_init(struct module *parent, const char *cfg, struct capture_filter **state) { struct capture_filter *s = calloc(1, sizeof(struct capture_filter)); char *item, *save_ptr; @@ -83,6 +119,10 @@ int capture_filter_init(const char *cfg, struct capture_filter **state) s->filters = simple_linked_list_init(); + module_init_default(&s->mod); + s->mod.cls = MODULE_CLASS_FILTER; + module_register(&s->mod, parent); + if(cfg) { if(strcasecmp(cfg, "help") == 0) { printf("Available capture filters:\n"); @@ -95,36 +135,10 @@ int capture_filter_init(const char *cfg, struct capture_filter **state) filter_list_str = tmp = strdup(cfg); while((item = strtok_r(filter_list_str, ",", &save_ptr))) { - unsigned int i; char filter_name[128]; - char *options = NULL; strncpy(filter_name, item, sizeof(filter_name)); - if(strchr(filter_name, ':')) { - options = strchr(filter_name, ':') + 1; - *strchr(filter_name, ':') = '\0'; - } - for(i = 0; i < sizeof(capture_filters) / sizeof(struct capture_filter_info *); ++i) { - if(strcasecmp(capture_filters[i]->name, filter_name) == 0) { - struct capture_filter_instance *instance = - malloc(sizeof(struct capture_filter_instance)); - instance->index = i; - int ret = capture_filters[i]->init(options, &instance->state); - if(ret < 0) { - fprintf(stderr, "Unable to initialize capture filter: %s\n", - filter_name); - } - if(ret != 0) { - return ret; - } - simple_linked_list_append(s->filters, instance); - break; - } - } - if(i == sizeof(capture_filters) / sizeof(struct capture_filter_info *)) { - fprintf(stderr, "Unable to find capture filter: %s\n", - filter_name); + if (!create_filter(s, filter_name)) return -1; - } filter_list_str = NULL; } } @@ -148,12 +162,46 @@ void capture_filter_destroy(struct capture_filter *state) simple_linked_list_destroy(s->filters); + module_done(&s->mod); + free(state); } +static void process_message(struct capture_filter *s, struct msg_universal *msg) +{ + if (strncmp("delete ", msg->text, strlen("delete ")) == 0) { + int index = atoi(msg->text + strlen("delete ")); + struct capture_filter_instance *inst = + simple_linked_list_remove_index(s->filters, index); + if (!inst) { + fprintf(stderr, "Unable to remove capture filter index %d.\n", + index); + } else { + printf("Capture filter #%d removed successfully.\n", index); + } + capture_filters[inst->index]->done(inst->state); + } else { + char *fmt = strdup(msg->text); + if (!create_filter(s, fmt)) { + fprintf(stderr, "Cannot create capture filter: %s.\n", + msg->text); + } else { + printf("Capture filter \"%s\" created successfully.\n", + msg->text); + } + free(fmt); + } +} + struct video_frame *capture_filter(struct capture_filter *state, struct video_frame *frame) { struct capture_filter *s = state; + struct message *msg; + while ((msg = check_message(&s->mod))) { + process_message(s, (struct msg_universal *) msg); + free_message(msg); + } + for(void *it = simple_linked_list_it_init(s->filters); it != NULL; ) { diff --git a/src/capture_filter.h b/src/capture_filter.h index c21bca1cc..7066503fd 100644 --- a/src/capture_filter.h +++ b/src/capture_filter.h @@ -53,20 +53,23 @@ extern "C" { #endif +struct module; + struct capture_filter_info { const char *name; - int (*init)(const char *cfg, void **state); + int (*init)(struct module *parent, const char *cfg, void **state); void (*done)(void *state); struct video_frame *(*filter)(void *state, struct video_frame *); }; struct capture_filter; +struct module; struct video_frame; /** * @see display_init */ -int capture_filter_init(const char *cfg, struct capture_filter **state); +int capture_filter_init(struct module *parent, const char *cfg, struct capture_filter **state); void capture_filter_destroy(struct capture_filter *state); struct video_frame *capture_filter(struct capture_filter *state, struct video_frame *frame); @@ -75,3 +78,4 @@ struct video_frame *capture_filter(struct capture_filter *state, struct video_fr #endif #endif /* CAPTURE_FILTER_H_ */ + diff --git a/src/capture_filter/blank.c b/src/capture_filter/blank.c index 2ee9fe4bd..5a8cfab2b 100644 --- a/src/capture_filter/blank.c +++ b/src/capture_filter/blank.c @@ -53,69 +53,88 @@ #endif /* HAVE_CONFIG_H */ #include "capture_filter.h" +#include "messaging.h" +#include "module.h" #include "video.h" #include "video_codec.h" -static int init(const char *cfg, void **state); +static int init(struct module *parent, const char *cfg, void **state); static void done(void *state); static struct video_frame *filter(void *state, struct video_frame *in); struct state_blank { + struct module mod; int x,y, width, height; bool outline; }; -static int init(const char *cfg, void **state) +static bool parse(struct state_blank *s, char *cfg) { int vals[4]; unsigned int counter = 0; - char *cfg_mutable = NULL, *tmp = NULL; - char *item, *save_ptr; bool outline = false; - if(cfg) { - if(strcasecmp(cfg, "help") == 0) { - printf("Blanks specified rectangular area:\n\n"); - printf("blank usage:\n"); - printf("\tblank:x:y:widht:height[:outline]\n"); - printf("\t(all values in pixels)\n"); - return 1; - } - cfg_mutable = tmp = strdup(cfg); - while ((item = strtok_r(cfg_mutable, ":", &save_ptr))) { - vals[counter] = atoi(item); + char *item, *save_ptr; + while ((item = strtok_r(cfg, ":", &save_ptr))) { + vals[counter] = atoi(item); - cfg_mutable = NULL; - counter += 1; - if (counter == sizeof(vals) / sizeof(int)) - break; - } - while ((item = strtok_r(cfg_mutable, ":", &save_ptr))) { - if (strcmp(item, "outline") == 0) { - outline = true; - } else { - fprintf(stderr, "[Blank] Unknown config value: %s\n", - item); - return -1; - } + cfg = NULL; + counter += 1; + if (counter == sizeof(vals) / sizeof(int)) + break; + } + while ((item = strtok_r(cfg, ":", &save_ptr))) { + if (strcmp(item, "outline") == 0) { + outline = true; + } else { + fprintf(stderr, "[Blank] Unknown config value: %s\n", + item); + return false; } } if(counter != sizeof(vals) / sizeof(int)) { fprintf(stderr, "[Blank] Few config values.\n"); - return -1; + return false; } - struct state_blank *s = calloc(1, sizeof(struct state_blank)); - assert(s); + s->x = vals[0]; s->y = vals[1]; s->width = vals[2]; s->height = vals[3]; s->outline = outline; - free(tmp); + return true; +} + +static int init(struct module *parent, const char *cfg, void **state) +{ + if (cfg && strcasecmp(cfg, "help") == 0) { + printf("Blanks specified rectangular area:\n\n"); + printf("blank usage:\n"); + printf("\tblank:x:y:widht:height[:outline]\n"); + printf("\t(all values in pixels)\n"); + return 1; + } + + struct state_blank *s = calloc(1, sizeof(struct state_blank)); + assert(s); + + if (cfg) { + char *tmp = strdup(cfg); + bool ret = parse(s, tmp); + free(tmp); + if (!ret) { + free(s); + return -1; + } + } + + module_init_default(&s->mod); + s->mod.cls = MODULE_CLASS_DATA; + module_register(&s->mod, parent); *state = s; return 0; @@ -123,9 +142,16 @@ static int init(const char *cfg, void **state) static void done(void *state) { + struct state_blank *s = state; + module_done(&s->mod); free(state); } +static void process_message(struct state_blank *s, struct msg_universal *msg) +{ + parse(s, msg->text); +} + /** * @note v210 etc. will be green */ @@ -134,6 +160,12 @@ static struct video_frame *filter(void *state, struct video_frame *in) struct state_blank *s = state; codec_t codec = in->color_spec; + struct message *msg; + while ((msg = check_message(&s->mod))) { + process_message(s, (struct msg_universal *) msg); + free_message(msg); + } + for(int y = s->y; y < s->y + s->height; ++y) { if(y >= (int) in->tiles[0].height) { break; diff --git a/src/capture_filter/every.c b/src/capture_filter/every.c index 013ba8a0a..8a8f27fd9 100644 --- a/src/capture_filter/every.c +++ b/src/capture_filter/every.c @@ -54,12 +54,16 @@ #include "capture_filter.h" +#include "debug.h" + #include "video.h" #include "video_codec.h" #define MAX_TILES 16 -static int init(const char *cfg, void **state); +struct module; + +static int init(struct module *parent, const char *cfg, void **state); static void done(void *state); static struct video_frame *filter(void *state, struct video_frame *in); @@ -77,8 +81,10 @@ static void usage() { printf("Example: every:2 - every second frame will be dropped\n"); } -static int init(const char *cfg, void **state) +static int init(struct module *parent, const char *cfg, void **state) { + UNUSED(parent); + int n; int denom = 1;; if(cfg) { diff --git a/src/control_socket.cpp b/src/control_socket.cpp index ed94fcd45..f402171bd 100644 --- a/src/control_socket.cpp +++ b/src/control_socket.cpp @@ -261,9 +261,11 @@ static int process_msg(struct control_state *s, fd_t client_fd, char *message) { int ret = 0; struct response *resp = NULL; - char path[1024] = { '\0' }; + char path[1024]; char buf[1024]; + memset(path, 0, sizeof(path)); + if(prefix_matches(message, "port ")) { message = suffix(message, "port "); snprintf(path, 1024, "%s[%d]", module_class_name(MODULE_CLASS_PORT), atoi(message)); @@ -358,9 +360,18 @@ static int process_msg(struct control_state *s, fd_t client_fd, char *message) } else if(strcasecmp(message, "bye") == 0) { ret = CONTROL_CLOSE_HANDLE; resp = new_response(RESPONSE_OK, NULL); - } else { - snprintf(buf, sizeof(buf), "(unrecognized control sequence: %s)", message); - resp = new_response(RESPONSE_BAD_REQUEST, strdup(buf)); + } else { // assume message in format "path message" + struct msg_universal *msg = (struct msg_universal *) + new_message(sizeof(struct msg_universal)); + + if (strchr(message, ' ')) { + memcpy(path, message, strchr(message, ' ') - message); + strncpy(msg->text, strchr(message, ' ') + 1, sizeof(path) - 1); + } else { + strncpy(path, message, sizeof(path) - 1); // empty message ?? + } + + resp = send_message(s->root_module, path, (struct message *) msg); } if(!resp) { diff --git a/src/host.c b/src/host.c index 413f880ba..cba260118 100644 --- a/src/host.c +++ b/src/host.c @@ -43,14 +43,16 @@ extern struct vidcap_type *(*vidcap_get_device_details_extrn)(int i); extern void (*display_free_devices_extrn)(void); extern vidcap_id_t (*vidcap_get_null_device_id_extrn)(); extern display_id_t (*display_get_null_device_id_extrn)(); -extern int (*vidcap_init_extrn)(vidcap_id_t id, const struct vidcap_params *, struct vidcap **); +extern int (*vidcap_init_extrn)(struct module *parent, vidcap_id_t id, + const struct vidcap_params *, struct vidcap **); extern int (*display_init_extrn)(display_id_t id, char *fmt, unsigned int flags, struct display **); extern int (*vidcap_get_device_count_extrn)(void); extern int (*display_get_device_count_extrn)(void); extern int (*vidcap_init_devices_extrn)(void); extern int (*display_init_devices_extrn)(void); -int initialize_video_capture(const char *requested_capture, +int initialize_video_capture(struct module *parent, + const char *requested_capture, const struct vidcap_params *params, struct vidcap **state) { @@ -82,7 +84,7 @@ int initialize_video_capture(const char *requested_capture, pthread_mutex_unlock(vidcap_lock); rm_release_shared_lock("VIDCAP_LOCK"); - return vidcap_init_extrn(id, params, state); + return vidcap_init_extrn(parent, id, params, state); } int initialize_video_display(const char *requested_display, diff --git a/src/host.h b/src/host.h index b7c399178..7bcba7890 100644 --- a/src/host.h +++ b/src/host.h @@ -94,10 +94,11 @@ extern bool verbose; // for aggregate.c struct vidcap; struct display; +struct module; int initialize_video_display(const char *requested_display, char *fmt, unsigned int flags, struct display **); -int initialize_video_capture(const char *requested_capture, +int initialize_video_capture(struct module *parent, const char *requested_capture, const struct vidcap_params *params, struct vidcap **); diff --git a/src/main.c b/src/main.c index fa1b0e2bf..5d54e3384 100644 --- a/src/main.c +++ b/src/main.c @@ -1342,7 +1342,8 @@ int main(int argc, char *argv[]) printf("Display initialized-%s\n", uv->requested_display); - ret = initialize_video_capture(vidcap_params[0].driver, &vidcap_params[0], &uv->capture_device); + ret = initialize_video_capture(&root_mod, vidcap_params[0].driver, + &vidcap_params[0], &uv->capture_device); if (ret < 0) { printf("Unable to open capture device: %s\n", vidcap_params[0].driver); diff --git a/src/messaging.h b/src/messaging.h index 359a36020..713c9f774 100644 --- a/src/messaging.h +++ b/src/messaging.h @@ -91,6 +91,11 @@ struct msg_stats { int value; }; +struct msg_universal { + struct message m; + char text[8192]; +}; + struct response *new_response(int status, char *optional_message); typedef struct response *(*msg_callback_t)(struct module *mod, struct message *msg); diff --git a/src/module.c b/src/module.c index cf550d12f..480c3ccbb 100644 --- a/src/module.c +++ b/src/module.c @@ -129,6 +129,8 @@ const char *module_class_name_pairs[] = { [MODULE_CLASS_TX] = "transmit", [MODULE_CLASS_AUDIO] = "audio", [MODULE_CLASS_CONTROL] = "control", + [MODULE_CLASS_CAPTURE] = "capture", + [MODULE_CLASS_FILTER] = "filter", }; const char *module_class_name(enum module_class cls) diff --git a/src/module.h b/src/module.h index 468d4e696..078b3f313 100644 --- a/src/module.h +++ b/src/module.h @@ -72,6 +72,8 @@ enum module_class { MODULE_CLASS_TX, MODULE_CLASS_AUDIO, MODULE_CLASS_CONTROL, + MODULE_CLASS_CAPTURE, + MODULE_CLASS_FILTER, }; struct module; diff --git a/src/utils/list.c b/src/utils/list.c index 8eb671060..206f88bcd 100644 --- a/src/utils/list.c +++ b/src/utils/list.c @@ -88,16 +88,21 @@ void *simple_linked_list_it_next(void **it) int simple_linked_list_remove(struct simple_linked_list *l, void *item) { struct node **child_ptr = &l->head; + struct node *parent = NULL; bool found = false; while(*child_ptr) { if((*child_ptr)->val == item) { struct node *tmp = *child_ptr; *child_ptr = (*child_ptr)->next; + if (l->tail == *child_ptr) { + l->tail = parent; + } free(tmp); found = true; break; } + parent = *child_ptr; child_ptr = &(*child_ptr)->next; } @@ -109,3 +114,32 @@ int simple_linked_list_remove(struct simple_linked_list *l, void *item) } } +void *simple_linked_list_remove_index(struct simple_linked_list *l, int index) +{ + struct node **child_ptr = &l->head; + struct node *parent = NULL; + + for (int i = 0; i < index; ++i) { + if (*child_ptr) { + parent = *child_ptr; + child_ptr = &(*child_ptr)->next; + } else { + return NULL; + } + } + + if (!*child_ptr) + return NULL; + + struct node *tmp = *child_ptr; + void *ret = (*child_ptr)->val; + *child_ptr = (*child_ptr)->next; + if (l->tail == *child_ptr) { + l->tail = parent; + } + free(tmp); + + l->size -= 1; + return ret; +} + diff --git a/src/utils/list.h b/src/utils/list.h index 11ab57de5..6751ac135 100644 --- a/src/utils/list.h +++ b/src/utils/list.h @@ -29,6 +29,12 @@ void *simple_linked_list_it_next(void **it); */ int simple_linked_list_remove(struct simple_linked_list *, void *); +/** + * @retval pointer pointer to removed value + * @retval NULL if not found + */ +void *simple_linked_list_remove_index(struct simple_linked_list *, int index); + #ifdef __cplusplus } #endif diff --git a/src/video_capture.c b/src/video_capture.c index b3dc7508a..d1af9a645 100644 --- a/src/video_capture.c +++ b/src/video_capture.c @@ -60,6 +60,7 @@ #include "capture_filter.h" #include "debug.h" #include "lib_common.h" +#include "module.h" #include "video.h" #include "video_capture.h" #include "video_capture/DirectShowGrabber.h" @@ -89,7 +90,7 @@ void (*vidcap_free_devices_extrn)() = vidcap_free_devices; void (*vidcap_done_extrn)(struct vidcap *) = vidcap_done; vidcap_id_t (*vidcap_get_null_device_id_extrn)(void) = vidcap_get_null_device_id; struct vidcap_type *(*vidcap_get_device_details_extrn)(int index) = vidcap_get_device_details; -int (*vidcap_init_extrn)(vidcap_id_t id, const struct vidcap_params *, struct vidcap **) = vidcap_init; +int (*vidcap_init_extrn)(struct module *mod, vidcap_id_t id, const struct vidcap_params *, struct vidcap **) = vidcap_init; struct video_frame *(*vidcap_grab_extrn)(struct vidcap *state, struct audio_frame **audio) = vidcap_grab; int (*vidcap_get_device_count_extrn)(void) = vidcap_get_device_count; int (*vidcap_init_devices_extrn)(void) = vidcap_init_devices; @@ -102,6 +103,7 @@ int vidcap_init_noerr; /// @brief This struct represents video capture state. struct vidcap { + struct module mod; void *state; ///< state of the created video capture driver int index; ///< index to @ref vidcap_device_table uint32_t magic; ///< For debugging. Conatins @ref VIDCAP_MAGIC @@ -445,7 +447,8 @@ vidcap_id_t vidcap_get_null_device_id(void) * @retval <0 if initialization failed * @retval >0 if initialization was successful but no state was returned (eg. only having shown help). */ -int vidcap_init(vidcap_id_t id, const struct vidcap_params *param, struct vidcap **state) +int vidcap_init(struct module *parent, vidcap_id_t id, const struct vidcap_params *param, + struct vidcap **state) { unsigned int i; @@ -467,14 +470,22 @@ int vidcap_init(vidcap_id_t id, const struct vidcap_params *param, struct vidcap free(d); return 1; } - int ret = capture_filter_init(param->requested_capture_filter, &d->capture_filter); + + module_init_default(&d->mod); + d->mod.cls = MODULE_CLASS_CAPTURE; + module_register(&d->mod, parent); + + int ret = capture_filter_init(&d->mod, param->requested_capture_filter, + &d->capture_filter); if(ret != 0) { fprintf(stderr, "Unable to initialize capture filter: %s.\n", param->requested_capture_filter); + module_done(&d->mod); return ret; } *state = d; + return 0; } } @@ -489,6 +500,7 @@ void vidcap_done(struct vidcap *state) assert(state->magic == VIDCAP_MAGIC); vidcap_device_table[state->index].func_done(state->state); capture_filter_destroy(state->capture_filter); + module_done(&state->mod); free(state); } diff --git a/src/video_capture.h b/src/video_capture.h index 66192cdd7..33b3e751b 100644 --- a/src/video_capture.h +++ b/src/video_capture.h @@ -130,9 +130,11 @@ int vidcap_get_device_count(void); struct vidcap_type *vidcap_get_device_details(int index); vidcap_id_t vidcap_get_null_device_id(void); +struct module; struct vidcap; -int vidcap_init(vidcap_id_t id, const struct vidcap_params *param, struct vidcap **); +int vidcap_init(struct module *parent, vidcap_id_t id, + const struct vidcap_params *param, struct vidcap **); void vidcap_done(struct vidcap *state); struct video_frame *vidcap_grab(struct vidcap *state, struct audio_frame **audio);