diff --git a/src/lib/emotion/Emotion_Module.h b/src/lib/emotion/Emotion_Module.h index 56c987237c..0ece2c1d9c 100644 --- a/src/lib/emotion/Emotion_Module.h +++ b/src/lib/emotion/Emotion_Module.h @@ -13,13 +13,10 @@ #define META_TRACK_COUNT 8 typedef enum _Emotion_Format Emotion_Format; -typedef struct _Emotion_Video_Module Emotion_Video_Module; +typedef struct _Emotion_Engine Emotion_Engine; typedef struct _Emotion_Module_Options Emotion_Module_Options; typedef struct _Eina_Emotion_Plugins Eina_Emotion_Plugins; -typedef Eina_Bool (*Emotion_Module_Open)(Evas_Object *, const Emotion_Video_Module **, void **, Emotion_Module_Options *); -typedef void (*Emotion_Module_Close)(Emotion_Video_Module *module, void *); - enum _Emotion_Format { EMOTION_FORMAT_NONE, @@ -31,20 +28,23 @@ enum _Emotion_Format struct _Emotion_Module_Options { - const char *player; Eina_Bool no_video : 1; Eina_Bool no_audio : 1; }; -struct _Eina_Emotion_Plugins +struct _Emotion_Engine { - Emotion_Module_Open open; - Emotion_Module_Close close; -}; +#define EMOTION_ENGINE_API_VERSION (1U) + unsigned version; -struct _Emotion_Video_Module -{ - unsigned char (*file_open) (const char *file, Evas_Object *obj, void *video); +#define EMOTION_ENGINE_PRIORITY_DEFAULT (50) + int priority; /* default priority, may be overwritten by user. Try to keep from 0-100. */ + + const char *name; + void *(*add)(const Emotion_Engine *api, Evas_Object *obj, const Emotion_Module_Options *opts); + void (*del)(void *ef); + + Eina_Bool (*file_open) (void *ef, const char *file); void (*file_close) (void *ef); void (*play) (void *ef, double pos); void (*stop) (void *ef); @@ -129,7 +129,7 @@ EAPI void _emotion_pending_object_unref(void); EAPI const char *emotion_webcam_custom_get(const char *device); -EAPI Eina_Bool _emotion_module_register(const char *name, Emotion_Module_Open open, Emotion_Module_Close close); -EAPI Eina_Bool _emotion_module_unregister(const char *name); +EAPI Eina_Bool _emotion_module_register(const Emotion_Engine *api); +EAPI Eina_Bool _emotion_module_unregister(const Emotion_Engine *api); #endif diff --git a/src/lib/emotion/emotion_modules.c b/src/lib/emotion/emotion_modules.c index 3e8a18a320..95ac2b3c91 100644 --- a/src/lib/emotion/emotion_modules.c +++ b/src/lib/emotion/emotion_modules.c @@ -17,9 +17,37 @@ Eina_Bool generic_module_init(void); void generic_module_shutdown(void); #endif -static Eina_Hash *_emotion_backends = NULL; +typedef struct _Emotion_Engine_Registry_Entry +{ + const Emotion_Engine *engine; + int priority; +} Emotion_Engine_Registry_Entry; + +static Eina_List *_emotion_engine_registry = NULL; static Eina_Array *_emotion_modules = NULL; +static void +_emotion_engine_registry_entry_free(Emotion_Engine_Registry_Entry *re) +{ + free(re); +} + +static int +_emotion_engine_registry_entry_cmp(const void *pa, const void *pb) +{ + const Emotion_Engine_Registry_Entry *a = pa, *b = pb; + int r = a->priority - b->priority; + + if (r == 0) + r = a->engine->priority - b->engine->priority; + + if (r == 0) + /* guarantee some order to ease debug */ + r = strcmp(a->engine->name, b->engine->name); + + return r; +} + static void _emotion_modules_load(void) { @@ -80,9 +108,6 @@ emotion_modules_init(void) { int static_modules = 0; - _emotion_backends = eina_hash_string_small_new(free); - EINA_SAFETY_ON_NULL_RETURN_VAL(_emotion_backends, EINA_FALSE); - _emotion_modules_load(); /* Init static module */ @@ -101,12 +126,20 @@ emotion_modules_init(void) else if (_emotion_modules) eina_module_list_load(_emotion_modules); + if (!_emotion_engine_registry) + ERR("Couldn't find any emotion engine."); + return EINA_TRUE; } void emotion_modules_shutdown(void) { + Emotion_Engine_Registry_Entry *re; + + EINA_LIST_FREE(_emotion_engine_registry, re) + _emotion_engine_registry_entry_free(re); + #ifdef EMOTION_STATIC_BUILD_XINE xine_module_shutdown(); #endif @@ -123,39 +156,74 @@ emotion_modules_shutdown(void) eina_array_free(_emotion_modules); _emotion_modules = NULL; } - - eina_hash_free(_emotion_backends); - _emotion_backends = NULL; } EAPI Eina_Bool -_emotion_module_register(const char *name, Emotion_Module_Open mod_open, Emotion_Module_Close mod_close) +_emotion_module_register(const Emotion_Engine *api) { - Eina_Emotion_Plugins *plugin; + Emotion_Engine_Registry_Entry *re; - plugin = malloc(sizeof (Eina_Emotion_Plugins)); - EINA_SAFETY_ON_NULL_RETURN_VAL(plugin, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(api, EINA_FALSE); - plugin->open = mod_open; - plugin->close = mod_close; + if (api->version != EMOTION_ENGINE_API_VERSION) + { + ERR("Module '%p' uses api version=%u while %u was expected", + api, api->version, EMOTION_ENGINE_API_VERSION); + return EINA_FALSE; + } - INF("register module=%s, open=%p, close=%p", name, mod_open, mod_close); - return eina_hash_add(_emotion_backends, name, plugin); + EINA_SAFETY_ON_NULL_RETURN_VAL(api->name, EINA_FALSE); + + INF("register name=%s, version=%u, priority=%d, api=%p", + api->name, api->version, api->priority, api); + + re = calloc(1, sizeof(Emotion_Engine_Registry_Entry)); + EINA_SAFETY_ON_NULL_RETURN_VAL(re, EINA_FALSE); + + re->engine = api; + re->priority = api->priority; // TODO: use user-priority from file as weel. + + _emotion_engine_registry = eina_list_sorted_insert + (_emotion_engine_registry, _emotion_engine_registry_entry_cmp, re); + + return EINA_TRUE; } EAPI Eina_Bool -_emotion_module_unregister(const char *name) +_emotion_module_unregister(const Emotion_Engine *api) { - INF("unregister module=%s", name); - return eina_hash_del_by_key(_emotion_backends, name); + Eina_List *n; + Emotion_Engine_Registry_Entry *re; + + EINA_SAFETY_ON_NULL_RETURN_VAL(api, EINA_FALSE); + if (api->version != EMOTION_ENGINE_API_VERSION) + { + ERR("Module '%p' uses api version=%u while %u was expected", + api, api->version, EMOTION_ENGINE_API_VERSION); + return EINA_FALSE; + } + + INF("unregister name=%s, api=%p", api->name, api); + + EINA_LIST_FOREACH(_emotion_engine_registry, n, re) + { + if (re->engine == api) + { + _emotion_engine_registry_entry_free(re); + _emotion_engine_registry = eina_list_remove_list + (_emotion_engine_registry, n); + return EINA_TRUE; + } + } + + ERR("module not registered name=%s, api=%p", api->name, api); + return EINA_FALSE; } struct _Emotion_Engine_Instance { - Eina_Emotion_Plugins *plugin; - Emotion_Video_Module *api; + const Emotion_Engine *api; Evas_Object *obj; - char *name; void *data; }; @@ -192,66 +260,81 @@ struct _Emotion_Engine_Instance while (0) -static const char *_backend_priority[] = { - "gstreamer", - "xine", - "generic" -}; +static const Emotion_Engine * +_emotion_engine_registry_find(const char *name) +{ + const Eina_List *n; + const Emotion_Engine_Registry_Entry *re; + EINA_LIST_FOREACH(_emotion_engine_registry, n, re) + { + if (strcmp(re->engine->name, name) == 0) + return re->engine; + } + return NULL; +} + +static Emotion_Engine_Instance * +_emotion_engine_instance_new(const Emotion_Engine *engine, Evas_Object *obj, void *data) +{ + Emotion_Engine_Instance *inst = calloc(1, sizeof(Emotion_Engine_Instance)); + EINA_SAFETY_ON_NULL_GOTO(inst, error); + inst->api = engine; + inst->obj = obj; + inst->data = data; + return inst; + + error: + engine->del(data); + return NULL; +} Emotion_Engine_Instance * emotion_engine_instance_new(const char *name, Evas_Object *obj, Emotion_Module_Options *opts) { - // TODO: rewrite - Eina_Emotion_Plugins *plugin; - unsigned int i = 0; - Emotion_Video_Module *mod = NULL; - void *data = NULL; + const Eina_List *n; + const Emotion_Engine_Registry_Entry *re; + const Emotion_Engine *engine; + void *data; - if (!_emotion_backends) - { - ERR("No backend loaded"); - return NULL; - } - - if (!name && getenv("EMOTION_ENGINE")) + if ((!name) && getenv("EMOTION_ENGINE")) { name = getenv("EMOTION_ENGINE"); DBG("using EMOTION_ENGINE=%s", name); } - /* FIXME: Always look for a working backend. */ - retry: - if (!name || i > 0) - name = _backend_priority[i++]; - - plugin = eina_hash_find(_emotion_backends, name); - DBG("try engine=%s, plugin=%p", name, plugin); - if (!plugin) + if (name) { - if (i != 0 && i < (sizeof (_backend_priority) / sizeof (char*))) - goto retry; + engine = _emotion_engine_registry_find(name); + if (!engine) + ERR("Couldn't find requested engine: %s. Try fallback", name); + else + { + data = engine->add(engine, obj, opts); + if (data) + { + INF("Using requested engine %s, data=%p", name, data); + return _emotion_engine_instance_new(engine, obj, data); + } - ERR("No backend loaded"); - return NULL; + ERR("Requested engine '%s' could not be used. Try fallback", name); + } } - if (plugin->open(obj, (const Emotion_Video_Module **) &mod, &data, opts)) + EINA_LIST_FOREACH(_emotion_engine_registry, n, re) { - Emotion_Engine_Instance *inst = calloc(1, sizeof(Emotion_Engine_Instance)); - INF("opened %s, mod=%p, video=%p", name, mod, data); - inst->plugin = plugin; - inst->api = mod; - inst->obj = obj; - inst->data = data; - inst->name = strdup(name); - return inst; + engine = re->engine; + DBG("Trying engine %s, priority=%d (%d)", + engine->name, re->priority, engine->priority); + + data = engine->add(engine, obj, opts); + if (data) + { + INF("Using fallback engine %s, data=%p", engine->name, data); + return _emotion_engine_instance_new(engine, obj, data); + } } - if (i != 0 && i < (sizeof (_backend_priority) / sizeof (char*))) - goto retry; - - ERR("Unable to load module: %s", name); - + ERR("No engine worked"); return NULL; } @@ -259,7 +342,7 @@ void emotion_engine_instance_del(Emotion_Engine_Instance *inst) { EINA_SAFETY_ON_NULL_RETURN(inst); - inst->plugin->close(inst->api, inst->data); // TODO: weird api + inst->api->del(inst->data); } Eina_Bool @@ -268,7 +351,7 @@ emotion_engine_instance_name_equal(const Emotion_Engine_Instance *inst, const ch /* these are valid, no safety macros here */ if (!name) return EINA_FALSE; if (!inst) return EINA_FALSE; - return strcmp(name, inst->name) == 0; + return strcmp(name, inst->api->name) == 0; } void * @@ -278,11 +361,11 @@ emotion_engine_instance_data_get(const Emotion_Engine_Instance *inst) return inst->data; } -unsigned char +Eina_Bool emotion_engine_instance_file_open(Emotion_Engine_Instance *inst, const char *file) { EMOTION_ENGINE_INSTANCE_CHECK(inst, file_open, EINA_FALSE); - return inst->api->file_open(file, inst->obj, inst->data); // TODO: weird api + return inst->api->file_open(inst->data, file); } void diff --git a/src/lib/emotion/emotion_private.h b/src/lib/emotion/emotion_private.h index 597e3fb7ab..93419f6d5e 100644 --- a/src/lib/emotion/emotion_private.h +++ b/src/lib/emotion/emotion_private.h @@ -30,7 +30,7 @@ void emotion_engine_instance_del(Emotion_Engine_Instance *in Eina_Bool emotion_engine_instance_name_equal(const Emotion_Engine_Instance *inst, const char *name); void *emotion_engine_instance_data_get(const Emotion_Engine_Instance *inst); -unsigned char emotion_engine_instance_file_open(Emotion_Engine_Instance *inst, const char *file); +Eina_Bool emotion_engine_instance_file_open(Emotion_Engine_Instance *inst, const char *file); void emotion_engine_instance_file_close(Emotion_Engine_Instance *inst); void emotion_engine_instance_play(Emotion_Engine_Instance *inst, double pos); void emotion_engine_instance_stop(Emotion_Engine_Instance *inst); diff --git a/src/lib/emotion/emotion_smart.c b/src/lib/emotion/emotion_smart.c index a91ff3fe7f..5cfa0e56b8 100644 --- a/src/lib/emotion/emotion_smart.c +++ b/src/lib/emotion/emotion_smart.c @@ -280,9 +280,30 @@ emotion_object_module_option_set(Evas_Object *obj, const char *opt, const char * E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME); if ((!opt) || (!val)) return; - // TODO remove me - if (!strcmp(opt, "player")) - eina_stringshare_replace(&sd->module_options.player, val); + if (strcmp(opt, "video") == 0) + { + if (strcmp(val, "off") == 0) + sd->module_options.no_video = EINA_TRUE; + else if (strcmp(val, "on") == 0) + sd->module_options.no_video = EINA_FALSE; + else + sd->module_options.no_video = !!atoi(val); + + ERR("Deprecated. Use emotion_object_video_mute_set()"); + } + else if (strcmp(opt, "audio") == 0) + { + if (strcmp(val, "off") == 0) + sd->module_options.no_audio = EINA_TRUE; + else if (strcmp(val, "on") == 0) + sd->module_options.no_audio = EINA_FALSE; + else + sd->module_options.no_audio = !!atoi(val); + + ERR("Deprecated. Use emotion_object_audio_mute_set()"); + } + else + ERR("Unsupported %s=%s", opt, val); } EAPI Eina_Bool diff --git a/src/modules/emotion/generic/emotion_generic.c b/src/modules/emotion/generic/emotion_generic.c index 58a4f01c8a..b30faa61f7 100644 --- a/src/modules/emotion/generic/emotion_generic.c +++ b/src/modules/emotion/generic/emotion_generic.c @@ -18,6 +18,8 @@ #include "emotion_generic.h" static Eina_Prefix *pfx = NULL; +static Eina_List *_generic_players = NULL; +static int _emotion_init_count = 0; static int _emotion_generic_log_domain = -1; #ifdef DBG @@ -46,18 +48,6 @@ static int _emotion_generic_log_domain = -1; #define CRITICAL(...) EINA_LOG_DOM_CRIT(_emotion_generic_log_domain, __VA_ARGS__) -struct _default_players { - const char *name; - const char *cmdline; -}; - -static struct _default_players players[] = { -#ifdef EMOTION_BUILD_GENERIC_VLC - { "vlc", "em_generic_vlc" }, -#endif - { NULL, NULL } -}; - static Eina_Bool _fork_and_exec(Emotion_Generic_Video *ev); static void em_partial_shutdown(Emotion_Generic_Video *ev); @@ -71,65 +61,6 @@ _player_restart(void *data) return EINA_FALSE; } -static const char * -_get_player(const char *name) -{ - const char *selected_name = NULL; - const char *libdir = eina_prefix_lib_get(pfx); - static char buf[PATH_MAX]; - int i; - - if (name) - { - for (i = 0; players[i].name; i++) - { - if (!strcmp(players[i].name, name)) - { - selected_name = players[i].cmdline; - break; - } - } - } - - if ((!selected_name) && (name)) - selected_name = name; - - if (selected_name) - { - const char *cmd; - - if (selected_name[0] == '/') cmd = selected_name; - else - { - snprintf(buf, sizeof(buf), "%s/emotion/utils/" MODULE_ARCH "/%s", - libdir, selected_name); - cmd = buf; - } - - DBG("Try generic player '%s'", cmd); - if (access(cmd, R_OK | X_OK) == 0) - { - INF("Using generic player '%s'", cmd); - return cmd; - } - } - - for (i = 0; players[i].name; i++) - { - snprintf(buf, sizeof(buf), "%s/emotion/utils/" MODULE_ARCH "/%s", - libdir, players[i].cmdline); - DBG("Try generic player '%s'", buf); - if (access(buf, R_OK | X_OK) == 0) - { - INF("Using fallback player '%s'", buf); - return buf; - } - } - - ERR("no generic player found, given name='%s'", name ? name : ""); - return NULL; -} - static void _player_send_cmd(Emotion_Generic_Video *ev, int cmd) { @@ -966,7 +897,7 @@ _player_exec(Emotion_Generic_Video *ev) return EINA_FALSE; } - snprintf(buf, sizeof(buf), "%s %d %d\n", ev->cmdline, pipe_out[0], pipe_in[1]); + snprintf(buf, sizeof(buf), "%s %d %d\n", ev->engine->path, pipe_out[0], pipe_in[1]); ev->player.exe = ecore_exe_pipe_run( buf, @@ -1027,18 +958,13 @@ _fork_and_exec(Emotion_Generic_Video *ev) return EINA_TRUE; } -static unsigned char -em_init(Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt) +static void * +em_add(const Emotion_Engine *api, Evas_Object *obj, const Emotion_Module_Options *opt EINA_UNUSED) { Emotion_Generic_Video *ev; - const char *player; - if (!emotion_video) return 0; - player = _get_player(opt ? opt->player : NULL); - if (!player) return 0; - - ev = (Emotion_Generic_Video *)calloc(1, sizeof(*ev)); - if (!ev) return 0; + ev = calloc(1, sizeof(*ev)); + EINA_SAFETY_ON_NULL_RETURN_VAL(ev, NULL); ev->fd_read = -1; ev->fd_write = -1; @@ -1048,10 +974,15 @@ em_init(Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt) ev->cmd.type = -1; ev->obj = obj; - ev->cmdline = eina_stringshare_add(player); - *emotion_video = ev; + ev->engine = (Emotion_Engine_Generic *)api; - return _fork_and_exec(ev); + if (!_fork_and_exec(ev)) + { + free(ev); + return NULL; + } + + return ev; } static void @@ -1092,23 +1023,18 @@ em_partial_shutdown(Emotion_Generic_Video *ev) ev->player_restart = NULL; } -static int -em_shutdown(void *data) +static void +em_del(void *data) { Emotion_Generic_Video *ev = data; - if (!ev) return 0; - - eina_stringshare_del(ev->cmdline); eina_stringshare_del(ev->shmname); em_partial_shutdown(ev); - - return 1; } static unsigned char -em_file_open(const char *file, Evas_Object *obj EINA_UNUSED, void *data) +em_file_open(void *data, const char *file) { Emotion_Generic_Video *ev = data; INF("file set: %s", file); @@ -1700,8 +1626,13 @@ em_meta_get(void *data, int meta) return NULL; } -static const Emotion_Video_Module em_module = +static const Emotion_Engine em_template_engine = { + EMOTION_ENGINE_API_VERSION, + EMOTION_ENGINE_PRIORITY_DEFAULT, + "generic", + em_add, /* add */ + em_del, /* del */ em_file_open, /* file_open */ em_file_close, /* file_close */ em_play, /* play */ @@ -1763,64 +1694,181 @@ static const Emotion_Video_Module em_module = NULL /* priority_get */ }; -static Eina_Bool -module_open(Evas_Object *obj, const Emotion_Video_Module **module, void **video, Emotion_Module_Options *opt) +static void +_player_entry_add(const Eina_File_Direct_Info *info) { - if (!module) { - return EINA_FALSE; - } + Emotion_Engine_Generic *eg; + const char *name; + char *endptr; + int priority; - if (_emotion_generic_log_domain < 0) + name = info->path + info->name_start; + + priority = strtol(name, &endptr, 10); + if (endptr == name) + priority = EMOTION_ENGINE_PRIORITY_DEFAULT; + else { - eina_threads_init(); - eina_log_threads_enable(); - _emotion_generic_log_domain = eina_log_domain_register - ("emotion-generic", EINA_COLOR_LIGHTCYAN); - if (_emotion_generic_log_domain < 0) - { - EINA_LOG_CRIT("Could not register log domain 'emotion-generic'"); - return EINA_FALSE; - } + if ((*endptr == '-') || (*endptr == '_')) + endptr++; + name = endptr; } + if (*name == '\0') + { + ERR("Invalid generic player: %s", info->path); + return; + } - if (!em_init(obj, video, opt)) { - return EINA_FALSE; - } + eg = malloc(sizeof(Emotion_Engine_Generic)); + EINA_SAFETY_ON_NULL_RETURN(eg); - *module = &em_module; + /* inherit template */ + memcpy(&(eg->engine), &em_template_engine, sizeof(em_template_engine)); - return EINA_TRUE; + eg->path = strdup(info->path); + EINA_SAFETY_ON_NULL_GOTO(eg->path, error_path); + + eg->engine.name = strdup(name); + EINA_SAFETY_ON_NULL_GOTO(eg->engine.name, error_name); + + eg->engine.priority = priority; + + DBG("Add player name=%s, priority=%d, path=%s", + eg->engine.name, eg->engine.priority, eg->path); + _generic_players = eina_list_append(_generic_players, eg); + + return; + + error_name: + free(eg->path); + error_path: + free(eg); } -static void module_close(Emotion_Video_Module *module EINA_UNUSED, void *video) +static void +_player_entry_free(Emotion_Engine_Generic *eg) { - em_shutdown(video); + free(eg->path); + free((void *)eg->engine.name); + free(eg); } +static void _players_all_from(const char *path) +{ + const Eina_File_Direct_Info *info; + int count = 0; + Eina_Iterator *itr = eina_file_direct_ls(path); + if (!itr) goto end;; + EINA_ITERATOR_FOREACH(itr, info) + { + if (access(info->path, R_OK | X_OK) == 0) + { + _player_entry_add(info); + count++; + } + } + eina_iterator_free(itr); + + end: + if (count == 0) + DBG("No generic players at %s", path); +} + +static void +_players_load(void) +{ + char buf[PATH_MAX]; + const char *homedir = getenv("HOME"); + + if (homedir) + { + eina_str_join(buf, sizeof(buf), '/', + homedir, + ".emotion/generic_players/" MODULE_ARCH); + _players_all_from(buf); + } + + eina_str_join(buf, sizeof(buf), '/', + eina_prefix_lib_get(pfx), + "emotion/generic_players/" MODULE_ARCH); + _players_all_from(buf); + + if (!_generic_players) + ERR("no generic players available"); + else + { + const Eina_List *n; + const Emotion_Engine_Generic *eg; + INF("Found %d generic players", eina_list_count(_generic_players)); + EINA_LIST_FOREACH(_generic_players, n, eg) + _emotion_module_register(&(eg->engine)); + } +} Eina_Bool generic_module_init(void) { - if (pfx) return EINA_TRUE; + if (_emotion_init_count > 0) + { + _emotion_init_count++; + return EINA_TRUE; + } + + _emotion_generic_log_domain = eina_log_domain_register + ("emotion-generic", EINA_COLOR_LIGHTCYAN); + if (_emotion_generic_log_domain < 0) + { + EINA_LOG_CRIT("Could not register log domain 'emotion-generic'"); + return EINA_FALSE; + } pfx = eina_prefix_new(NULL, emotion_init, "EMOTION", "emotion", "checkme", PACKAGE_BIN_DIR, PACKAGE_LIB_DIR, PACKAGE_DATA_DIR, PACKAGE_DATA_DIR); - if (!pfx) return EINA_FALSE; - return _emotion_module_register("generic", module_open, module_close); + if (!pfx) + { + CRITICAL("Could not get prefix for emotion"); + eina_log_domain_unregister(_emotion_generic_log_domain); + _emotion_generic_log_domain = -1; + return EINA_FALSE; + } + + _players_load(); + + _emotion_init_count = 1; + return EINA_TRUE; } void generic_module_shutdown(void) { - if (!pfx) return; + Emotion_Engine_Generic *eg; + + if (_emotion_init_count > 1) + { + _emotion_init_count--; + return; + } + else if (_emotion_init_count == 0) + { + EINA_LOG_ERR("too many generic_module_shutdown()"); + return; + } + _emotion_init_count = 0; + + EINA_LIST_FREE(_generic_players, eg) + { + _emotion_module_unregister(&(eg->engine)); + _player_entry_free(eg); + } + + eina_log_domain_unregister(_emotion_generic_log_domain); + _emotion_generic_log_domain = -1; eina_prefix_free(pfx); pfx = NULL; - - _emotion_module_unregister("generic"); } #ifndef EMOTION_STATIC_BUILD_GENERIC diff --git a/src/modules/emotion/generic/emotion_generic.h b/src/modules/emotion/generic/emotion_generic.h index 864abb3f41..1536a0e9f9 100644 --- a/src/modules/emotion/generic/emotion_generic.h +++ b/src/modules/emotion/generic/emotion_generic.h @@ -58,10 +58,16 @@ struct _Emotion_Generic_Cmd_Buffer } param; }; +typedef struct _Emotion_Engine_Generic +{ + Emotion_Engine engine; + char *path; +} Emotion_Engine_Generic; + /* emotion/generic main structure */ struct _Emotion_Generic_Video { - const char *cmdline; + const Emotion_Engine_Generic *engine; const char *shmname; Emotion_Generic_Player player; diff --git a/src/modules/emotion/gstreamer/emotion_alloc.c b/src/modules/emotion/gstreamer/emotion_alloc.c index b7eecd43ab..c4aae047b7 100644 --- a/src/modules/emotion/gstreamer/emotion_alloc.c +++ b/src/modules/emotion/gstreamer/emotion_alloc.c @@ -51,7 +51,7 @@ emotion_gstreamer_buffer_free(Emotion_Gstreamer_Buffer *send) if (send->ev->in == send->ev->out && send->ev->threads == NULL && send->ev->delete_me) - em_shutdown(send->ev); + send->ev->api->del(send->ev); gst_buffer_unref(send->frame); free(send); @@ -83,7 +83,7 @@ emotion_gstreamer_message_free(Emotion_Gstreamer_Message *send) if (send->ev->in == send->ev->out && send->ev->threads == NULL && send->ev->delete_me) - em_shutdown(send->ev); + send->ev->api->del(send->ev); gst_message_unref(send->msg); free(send); diff --git a/src/modules/emotion/gstreamer/emotion_gstreamer.c b/src/modules/emotion/gstreamer/emotion_gstreamer.c index 31f319e009..e48d8f098f 100644 --- a/src/modules/emotion/gstreamer/emotion_gstreamer.c +++ b/src/modules/emotion/gstreamer/emotion_gstreamer.c @@ -33,173 +33,12 @@ Eina_Bool debug_fps = EINA_FALSE; Eina_Bool _ecore_x_available = EINA_FALSE; static Ecore_Idler *restart_idler; +static int _emotion_init_count = 0; /* Callbacks to get the eos */ static void _for_each_tag (GstTagList const* list, gchar const* tag, void *data); static void _free_metadata (Emotion_Gstreamer_Metadata *m); -/* Interface */ - -static unsigned char em_init (Evas_Object *obj, - void **emotion_video, - Emotion_Module_Options *opt); - -static unsigned char em_file_open (const char *file, - Evas_Object *obj, - void *video); - -static void em_file_close (void *video); - -static void em_play (void *video, - double pos); - -static void em_stop (void *video); - -static void em_size_get (void *video, - int *width, - int *height); - -static void em_pos_set (void *video, - double pos); - - -static double em_len_get (void *video); - -static double em_buffer_size_get (void *video); - -static int em_fps_num_get (void *video); - -static int em_fps_den_get (void *video); - -static double em_fps_get (void *video); - -static double em_pos_get (void *video); - -static void em_vis_set (void *video, - Emotion_Vis vis); - -static Emotion_Vis em_vis_get (void *video); - -static Eina_Bool em_vis_supported (void *video, - Emotion_Vis vis); - -static double em_ratio_get (void *video); - -static int em_video_handled (void *video); - -static int em_audio_handled (void *video); - -static int em_seekable (void *video); - -static void em_frame_done (void *video); - -static Emotion_Format em_format_get (void *video); - -static void em_video_data_size_get (void *video, - int *w, - int *h); - -static int em_yuv_rows_get (void *video, - int w, - int h, - unsigned char **yrows, - unsigned char **urows, - unsigned char **vrows); - -static int em_bgra_data_get (void *video, - unsigned char **bgra_data); - -static void em_event_feed (void *video, - int event); - -static void em_event_mouse_button_feed (void *video, - int button, - int x, - int y); - -static void em_event_mouse_move_feed (void *video, - int x, - int y); - -static int em_video_channel_count (void *video); - -static void em_video_channel_set (void *video, - int channel); - -static int em_video_channel_get (void *video); - -static void em_video_subtitle_file_set (void *video, - const char *filepath); - -static const char *em_video_subtitle_file_get (void *video); - -static const char *em_video_channel_name_get (void *video, - int channel); - -static void em_video_channel_mute_set (void *video, - int mute); - -static int em_video_channel_mute_get (void *video); - -static int em_audio_channel_count (void *video); - -static void em_audio_channel_set (void *video, - int channel); - -static int em_audio_channel_get (void *video); - -static const char *em_audio_channel_name_get (void *video, - int channel); - -static void em_audio_channel_mute_set (void *video, - int mute); - -static int em_audio_channel_mute_get (void *video); - -static void em_audio_channel_volume_set (void *video, - double vol); - -static double em_audio_channel_volume_get (void *video); - -static int em_spu_channel_count (void *video); - -static void em_spu_channel_set (void *video, - int channel); - -static int em_spu_channel_get (void *video); - -static const char *em_spu_channel_name_get (void *video, - int channel); - -static void em_spu_channel_mute_set (void *video, - int mute); - -static int em_spu_channel_mute_get (void *video); - -static int em_chapter_count (void *video); - -static void em_chapter_set (void *video, - int chapter); - -static int em_chapter_get (void *video); - -static const char *em_chapter_name_get (void *video, - int chapter); - -static void em_speed_set (void *video, - double speed); - -static double em_speed_get (void *video); - -static int em_eject (void *video); - -static const char *em_meta_get (void *video, - int meta); - -static void em_priority_set (void *video, - Eina_Bool pri); -static Eina_Bool em_priority_get (void *video); - static GstBusSyncReply _eos_sync_fct(GstBus *bus, GstMessage *message, gpointer data); @@ -208,68 +47,6 @@ static Eina_Bool _em_restart_stream(void *data); /* Module interface */ -static const Emotion_Video_Module em_module = -{ - em_file_open, /* file_open */ - em_file_close, /* file_close */ - em_play, /* play */ - em_stop, /* stop */ - em_size_get, /* size_get */ - em_pos_set, /* pos_set */ - em_len_get, /* len_get */ - em_buffer_size_get, /* buffer_size_get */ - em_fps_num_get, /* fps_num_get */ - em_fps_den_get, /* fps_den_get */ - em_fps_get, /* fps_get */ - em_pos_get, /* pos_get */ - em_vis_set, /* vis_set */ - em_vis_get, /* vis_get */ - em_vis_supported, /* vis_supported */ - em_ratio_get, /* ratio_get */ - em_video_handled, /* video_handled */ - em_audio_handled, /* audio_handled */ - em_seekable, /* seekable */ - em_frame_done, /* frame_done */ - em_format_get, /* format_get */ - em_video_data_size_get, /* video_data_size_get */ - em_yuv_rows_get, /* yuv_rows_get */ - em_bgra_data_get, /* bgra_data_get */ - em_event_feed, /* event_feed */ - em_event_mouse_button_feed, /* event_mouse_button_feed */ - em_event_mouse_move_feed, /* event_mouse_move_feed */ - em_video_channel_count, /* video_channel_count */ - em_video_channel_set, /* video_channel_set */ - em_video_channel_get, /* video_channel_get */ - em_video_subtitle_file_set, /* video_subtitle_file_set */ - em_video_subtitle_file_get, /* video_subtitle_file_get */ - em_video_channel_name_get, /* video_channel_name_get */ - em_video_channel_mute_set, /* video_channel_mute_set */ - em_video_channel_mute_get, /* video_channel_mute_get */ - em_audio_channel_count, /* audio_channel_count */ - em_audio_channel_set, /* audio_channel_set */ - em_audio_channel_get, /* audio_channel_get */ - em_audio_channel_name_get, /* audio_channel_name_get */ - em_audio_channel_mute_set, /* audio_channel_mute_set */ - em_audio_channel_mute_get, /* audio_channel_mute_get */ - em_audio_channel_volume_set, /* audio_channel_volume_set */ - em_audio_channel_volume_get, /* audio_channel_volume_get */ - em_spu_channel_count, /* spu_channel_count */ - em_spu_channel_set, /* spu_channel_set */ - em_spu_channel_get, /* spu_channel_get */ - em_spu_channel_name_get, /* spu_channel_name_get */ - em_spu_channel_mute_set, /* spu_channel_mute_set */ - em_spu_channel_mute_get, /* spu_channel_mute_get */ - em_chapter_count, /* chapter_count */ - em_chapter_set, /* chapter_set */ - em_chapter_get, /* chapter_get */ - em_chapter_name_get, /* chapter_name_get */ - em_speed_set, /* speed_set */ - em_speed_get, /* speed_get */ - em_eject, /* eject */ - em_meta_get, /* meta_get */ - em_priority_set, /* priority_set */ - em_priority_get /* priority_get */ -}; static int priority_overide = 0; @@ -340,44 +117,6 @@ emotion_visualization_element_name_get(Emotion_Vis visualisation) } } -static unsigned char -em_init(Evas_Object *obj, - void **emotion_video, - Emotion_Module_Options *opt EINA_UNUSED) -{ - Emotion_Gstreamer_Video *ev; - GError *error; - - if (!emotion_video) - return 0; - - ev = calloc(1, sizeof(Emotion_Gstreamer_Video)); - if (!ev) return 0; - - ev->obj = obj; - - /* Initialization of gstreamer */ - if (!gst_init_check(NULL, NULL, &error)) - goto failure; - - /* Default values */ - ev->ratio = 1.0; - ev->vis = EMOTION_VIS_NONE; - ev->volume = 0.8; - ev->play_started = 0; - ev->delete_me = EINA_FALSE; - ev->threads = NULL; - - *emotion_video = ev; - - return 1; - -failure: - free(ev); - - return 0; -} - static void em_cleanup(Emotion_Gstreamer_Video *ev) { @@ -455,14 +194,10 @@ em_cleanup(Emotion_Gstreamer_Video *ev) free(vstream); } -int -em_shutdown(void *video) +static void +em_del(void *video) { - Emotion_Gstreamer_Video *ev; - - ev = (Emotion_Gstreamer_Video *)video; - if (!ev) - return 0; + Emotion_Gstreamer_Video *ev = video; if (ev->threads) { @@ -472,34 +207,28 @@ em_shutdown(void *video) ecore_thread_cancel(t); ev->delete_me = EINA_TRUE; - return EINA_FALSE; + return; } if (ev->in != ev->out) { ev->delete_me = EINA_TRUE; - return EINA_FALSE; + return; } em_cleanup(ev); free(ev); - - return 1; } - -static unsigned char -em_file_open(const char *file, - Evas_Object *obj, - void *video) +static Eina_Bool +em_file_open(void *video, + const char *file) { - Emotion_Gstreamer_Video *ev; + Emotion_Gstreamer_Video *ev = video; Eina_Strbuf *sbuf = NULL; const char *uri; - ev = (Emotion_Gstreamer_Video *)video; - if (!file) return EINA_FALSE; if (strstr(file, "://") == NULL) { @@ -529,7 +258,7 @@ em_file_open(const char *file, uri = sbuf ? eina_strbuf_string_get(sbuf) : file; DBG("setting file to '%s'", uri); - ev->pipeline = gstreamer_video_sink_new(ev, obj, uri); + ev->pipeline = gstreamer_video_sink_new(ev, ev->obj, uri); if (sbuf) eina_strbuf_free(sbuf); if (!ev->pipeline) @@ -544,9 +273,6 @@ em_file_open(const char *file, gst_bus_set_sync_handler(ev->eos_bus, _eos_sync_fct, ev); - /* Evas Object */ - ev->obj = obj; - ev->position = 0.0; return 1; @@ -1334,54 +1060,17 @@ _ecore_event_x_destroy(void *data EINA_UNUSED, int type EINA_UNUSED, void *event return EINA_TRUE; } -#endif -static Eina_Bool -module_open(Evas_Object *obj, - const Emotion_Video_Module **module, - void **video, - Emotion_Module_Options *opt) +static void +gstreamer_ecore_x_check(void) { -#ifdef HAVE_ECORE_X Ecore_X_Window *roots; int num; -#endif - if (!module) - return EINA_FALSE; - - if (_emotion_gstreamer_log_domain < 0) - { - eina_threads_init(); - eina_log_threads_enable(); - _emotion_gstreamer_log_domain = eina_log_domain_register - ("emotion-gstreamer", EINA_COLOR_LIGHTCYAN); - if (_emotion_gstreamer_log_domain < 0) - { - EINA_LOG_CRIT("Could not register log domain 'emotion-gstreamer'"); - return EINA_FALSE; - } - } - - if (!em_init(obj, video, opt)) - return EINA_FALSE; - -#ifdef HAVE_ECORE_X ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DESTROY, _ecore_event_x_destroy, NULL); -#endif - - if (getenv("EMOTION_FPS_DEBUG")) debug_fps = EINA_TRUE; - - eina_threads_init(); - -#ifdef HAVE_ECORE_X - if (ecore_x_init(NULL) > 0) - { - _ecore_x_available = EINA_TRUE; - } /* Check if the window manager is able to handle our special Xv window. */ - roots = _ecore_x_available ? ecore_x_window_root_list(&num) : NULL; + roots = ecore_x_window_root_list(&num); if (roots && num > 0) { Ecore_X_Window win, twin; @@ -1425,39 +1114,138 @@ module_open(Evas_Object *obj, } } free(roots); +} #endif - *module = &em_module; - return EINA_TRUE; -} - -static void -module_close(Emotion_Video_Module *module EINA_UNUSED, - void *video) +static void * +em_add(const Emotion_Engine *api, + Evas_Object *obj, + const Emotion_Module_Options *opt EINA_UNUSED) { - em_shutdown(video); + Emotion_Gstreamer_Video *ev; -#ifdef HAVE_ECORE_X - if (_ecore_x_available) - { - ecore_x_shutdown(); - } -#endif + ev = calloc(1, sizeof(Emotion_Gstreamer_Video)); + EINA_SAFETY_ON_NULL_RETURN_VAL(ev, NULL); - eina_threads_shutdown(); + ev->api = api; + ev->obj = obj; + + /* Default values */ + ev->ratio = 1.0; + ev->vis = EMOTION_VIS_NONE; + ev->volume = 0.8; + ev->play_started = 0; + ev->delete_me = EINA_FALSE; + ev->threads = NULL; + + return ev; } +static const Emotion_Engine em_engine = +{ + EMOTION_ENGINE_API_VERSION, + EMOTION_ENGINE_PRIORITY_DEFAULT, + "gstreamer", + em_add, /* add */ + em_del, /* del */ + em_file_open, /* file_open */ + em_file_close, /* file_close */ + em_play, /* play */ + em_stop, /* stop */ + em_size_get, /* size_get */ + em_pos_set, /* pos_set */ + em_len_get, /* len_get */ + em_buffer_size_get, /* buffer_size_get */ + em_fps_num_get, /* fps_num_get */ + em_fps_den_get, /* fps_den_get */ + em_fps_get, /* fps_get */ + em_pos_get, /* pos_get */ + em_vis_set, /* vis_set */ + em_vis_get, /* vis_get */ + em_vis_supported, /* vis_supported */ + em_ratio_get, /* ratio_get */ + em_video_handled, /* video_handled */ + em_audio_handled, /* audio_handled */ + em_seekable, /* seekable */ + em_frame_done, /* frame_done */ + em_format_get, /* format_get */ + em_video_data_size_get, /* video_data_size_get */ + em_yuv_rows_get, /* yuv_rows_get */ + em_bgra_data_get, /* bgra_data_get */ + em_event_feed, /* event_feed */ + em_event_mouse_button_feed, /* event_mouse_button_feed */ + em_event_mouse_move_feed, /* event_mouse_move_feed */ + em_video_channel_count, /* video_channel_count */ + em_video_channel_set, /* video_channel_set */ + em_video_channel_get, /* video_channel_get */ + em_video_subtitle_file_set, /* video_subtitle_file_set */ + em_video_subtitle_file_get, /* video_subtitle_file_get */ + em_video_channel_name_get, /* video_channel_name_get */ + em_video_channel_mute_set, /* video_channel_mute_set */ + em_video_channel_mute_get, /* video_channel_mute_get */ + em_audio_channel_count, /* audio_channel_count */ + em_audio_channel_set, /* audio_channel_set */ + em_audio_channel_get, /* audio_channel_get */ + em_audio_channel_name_get, /* audio_channel_name_get */ + em_audio_channel_mute_set, /* audio_channel_mute_set */ + em_audio_channel_mute_get, /* audio_channel_mute_get */ + em_audio_channel_volume_set, /* audio_channel_volume_set */ + em_audio_channel_volume_get, /* audio_channel_volume_get */ + em_spu_channel_count, /* spu_channel_count */ + em_spu_channel_set, /* spu_channel_set */ + em_spu_channel_get, /* spu_channel_get */ + em_spu_channel_name_get, /* spu_channel_name_get */ + em_spu_channel_mute_set, /* spu_channel_mute_set */ + em_spu_channel_mute_get, /* spu_channel_mute_get */ + em_chapter_count, /* chapter_count */ + em_chapter_set, /* chapter_set */ + em_chapter_get, /* chapter_get */ + em_chapter_name_get, /* chapter_name_get */ + em_speed_set, /* speed_set */ + em_speed_get, /* speed_get */ + em_eject, /* eject */ + em_meta_get, /* meta_get */ + em_priority_set, /* priority_set */ + em_priority_get /* priority_get */ +}; + Eina_Bool gstreamer_module_init(void) { GError *error; + if (_emotion_init_count > 0) + { + _emotion_init_count++; + return EINA_TRUE; + } + + if (getenv("EMOTION_FPS_DEBUG")) debug_fps = EINA_TRUE; + + eina_threads_init(); + eina_log_threads_enable(); + _emotion_gstreamer_log_domain = eina_log_domain_register + ("emotion-gstreamer", EINA_COLOR_LIGHTCYAN); + if (_emotion_gstreamer_log_domain < 0) + { + EINA_LOG_CRIT("Could not register log domain 'emotion-gstreamer'"); + return EINA_FALSE; + } + if (!gst_init_check(0, NULL, &error)) { EINA_LOG_CRIT("Could not init GStreamer"); - return EINA_FALSE; + goto error_gst_init; } +#ifdef HAVE_ECORE_X + if (ecore_x_init(NULL) > 0) + { + _ecore_x_available = EINA_TRUE; + gstreamer_ecore_x_check(); + } +#endif + if (gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR, "emotion-sink", "video sink plugin for Emotion", @@ -1469,16 +1257,66 @@ gstreamer_module_init(void) "http://www.enlightenment.org/") == FALSE) { EINA_LOG_CRIT("Could not load static gstreamer video sink for Emotion."); - return EINA_FALSE; + goto error_gst_plugin; } - return _emotion_module_register("gstreamer", module_open, module_close); + if (!_emotion_module_register(&em_engine)) + { + ERR("Could not register module %p", &em_engine); + goto error_register; + } + + _emotion_init_count = 1; + return EINA_TRUE; + + error_register: + error_gst_plugin: +#ifdef HAVE_ECORE_X + if (_ecore_x_available) + { + ecore_x_shutdown(); + _ecore_x_available = EINA_FALSE; + window_manager_video = EINA_FALSE; + } +#endif + + gst_deinit(); + + error_gst_init: + eina_log_domain_unregister(_emotion_gstreamer_log_domain); + _emotion_gstreamer_log_domain = -1; + + return EINA_FALSE; } void gstreamer_module_shutdown(void) { - _emotion_module_unregister("gstreamer"); + if (_emotion_init_count > 1) + { + _emotion_init_count--; + return; + } + else if (_emotion_init_count == 0) + { + EINA_LOG_ERR("too many gstreamer_module_shutdown()"); + return; + } + _emotion_init_count = 0; + + _emotion_module_unregister(&em_engine); + +#ifdef HAVE_ECORE_X + if (_ecore_x_available) + { + ecore_x_shutdown(); + _ecore_x_available = EINA_FALSE; + window_manager_video = EINA_FALSE; + } +#endif + + eina_log_domain_unregister(_emotion_gstreamer_log_domain); + _emotion_gstreamer_log_domain = -1; gst_deinit(); } diff --git a/src/modules/emotion/gstreamer/emotion_gstreamer.h b/src/modules/emotion/gstreamer/emotion_gstreamer.h index 18f6b6cb28..f7f62233bb 100644 --- a/src/modules/emotion/gstreamer/emotion_gstreamer.h +++ b/src/modules/emotion/gstreamer/emotion_gstreamer.h @@ -1,6 +1,8 @@ #ifndef __EMOTION_GSTREAMER_H__ #define __EMOTION_GSTREAMER_H__ +#include "Emotion_Module.h" + typedef void (*Evas_Video_Convert_Cb)(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, @@ -49,6 +51,8 @@ struct _Emotion_Gstreamer_Metadata struct _Emotion_Gstreamer_Video { + const Emotion_Engine *api; + /* Gstreamer elements */ GstElement *pipeline; GstElement *sink; @@ -260,8 +264,6 @@ void emotion_gstreamer_message_free(Emotion_Gstreamer_Message *send); Eina_Bool _emotion_gstreamer_video_pipeline_parse(Emotion_Gstreamer_Video *ev, Eina_Bool force); -int em_shutdown(void *video); - typedef struct _ColorSpace_FourCC_Convertion ColorSpace_FourCC_Convertion; typedef struct _ColorSpace_Format_Convertion ColorSpace_Format_Convertion; diff --git a/src/modules/emotion/gstreamer/emotion_sink.c b/src/modules/emotion/gstreamer/emotion_sink.c index 755d48ae10..2e776d2751 100644 --- a/src/modules/emotion/gstreamer/emotion_sink.c +++ b/src/modules/emotion/gstreamer/emotion_sink.c @@ -848,7 +848,7 @@ _emotion_gstreamer_cancel(void *data, Ecore_Thread *thread) if (getenv("EMOTION_GSTREAMER_DOT")) GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(ev->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, getenv("EMOTION_GSTREAMER_DOT")); if (ev->in == ev->out && ev->delete_me) - em_shutdown(ev); + ev->api->del(ev); } static void @@ -867,7 +867,7 @@ _emotion_gstreamer_end(void *data, Ecore_Thread *thread) if (getenv("EMOTION_GSTREAMER_DOT")) GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(ev->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, getenv("EMOTION_GSTREAMER_DOT")); if (ev->in == ev->out && ev->delete_me) - em_shutdown(ev); + ev->api->del(ev); else _emotion_gstreamer_video_pipeline_parse(data, EINA_TRUE); } diff --git a/src/modules/emotion/xine/emotion_xine.c b/src/modules/emotion/xine/emotion_xine.c index b09db03fc0..a3389bc6bd 100644 --- a/src/modules/emotion/xine/emotion_xine.c +++ b/src/modules/emotion/xine/emotion_xine.c @@ -10,63 +10,7 @@ #include "emotion_xine.h" int _emotion_xine_log_domain = -1; - -/* module api */ -static unsigned char em_init (Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt); -static int em_shutdown (void *ef); -static unsigned char em_file_open (const char *file, Evas_Object *obj, void *ef); -static void em_file_close (void *ef); -static void em_play (void *ef, double pos); -static void em_stop (void *ef); -static void em_size_get (void *ef, int *w, int *h); -static void em_pos_set (void *ef, double pos); -static double em_buffer_size_get (void *ef); -static double em_len_get (void *ef); -static int em_fps_num_get (void *ef); -static int em_fps_den_get (void *ef); -static double em_fps_get (void *ef); -static double em_pos_get (void *ef); -static void em_vis_set (void *ef, Emotion_Vis vis); -static Emotion_Vis em_vis_get (void *ef); -static Eina_Bool em_vis_supported (void *ef, Emotion_Vis vis); -static double em_ratio_get (void *ef); -static int em_seekable (void *ef); -static void em_frame_done (void *ef); -static Emotion_Format em_format_get (void *ef); -static void em_video_data_size_get (void *ef, int *w, int *h); -static int em_yuv_rows_get (void *ef, int w, int h, unsigned char **yrows, unsigned char **urows, unsigned char **vrows); -static int em_bgra_data_get (void *ef, unsigned char **bgra_data); -static void em_event_feed (void *ef, int event); -static void em_event_mouse_button_feed (void *ef, int button, int x, int y); -static void em_event_mouse_move_feed (void *ef, int x, int y); -static int em_video_channel_count (void *ef); -static void em_video_channel_set (void *ef, int channel); -static int em_video_channel_get (void *ef); -static const char *em_video_channel_name_get (void *ef, int channel); -static void em_video_channel_mute_set (void *ef, int mute); -static int em_video_channel_mute_get (void *ef); -static int em_audio_channel_count (void *ef); -static void em_audio_channel_set (void *ef, int channel); -static int em_audio_channel_get (void *ef); -static const char *em_audio_channel_name_get (void *ef, int channel); -static void em_audio_channel_mute_set (void *ef, int mute); -static int em_audio_channel_mute_get (void *ef); -static void em_audio_channel_volume_set(void *ef, double vol); -static double em_audio_channel_volume_get(void *ef); -static int em_spu_channel_count (void *ef); -static void em_spu_channel_set (void *ef, int channel); -static int em_spu_channel_get (void *ef); -static const char *em_spu_channel_name_get (void *ef, int channel); -static void em_spu_channel_mute_set (void *ef, int mute); -static int em_spu_channel_mute_get (void *ef); -static int em_chapter_count (void *ef); -static void em_chapter_set (void *ef, int chapter); -static int em_chapter_get (void *ef); -static const char *em_chapter_name_get (void *ef, int chapter); -static void em_speed_set (void *ef, double speed); -static double em_speed_get (void *ef); -static int em_eject (void *ef); -static const char *em_meta_get (void *ef, int meta); +static int _emotion_init_count = 0; /* internal util calls */ static void *_em_slave (void *par); @@ -81,6 +25,8 @@ static void _em_get_pos_len (Emotion_Xine_Video *ev); extern plugin_info_t emotion_xine_plugin_info[]; +static void em_frame_done(void *ef); + /* this is a slave controller thread for the xine module - libxine loves * to deadlock, internally stall and otherwise have unpredictable behavior * if we use the main process thread for many things - so a lot will be @@ -369,18 +315,18 @@ _em_slave_event(void *data, int type, void *arg) if (write(ev->fd_slave_write, buf, sizeof(buf)) < 0) perror("write"); } -static unsigned char -em_init(Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt) +static void * +em_add(const Emotion_Engine *api EINA_UNUSED, + Evas_Object *obj, + const Emotion_Module_Options *opt) { Emotion_Xine_Video *ev; int fds[2]; - - if (!emotion_video) return 0; - + ev = calloc(1, sizeof(Emotion_Xine_Video)); - if (!ev) return 0; + EINA_SAFETY_ON_NULL_RETURN_VAL(ev, NULL); ev->obj = obj; - + if (pipe(fds) == 0) { ev->fd_read = fds[0]; @@ -427,17 +373,15 @@ em_init(Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt) _em_slave_event(ev, 1, NULL); ev->buffer = 1.0; - - *emotion_video = ev; - return 1; + + return ev; } -static int -em_shutdown(void *ef) +static void +em_del(void *ef) { - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; + Emotion_Xine_Video *ev = ef; + ev->closing = 1; ev->delete_me = 1; DBG("del fds %p", ev); @@ -450,22 +394,18 @@ em_shutdown(void *ef) ecore_animator_del(ev->anim); ev->anim = NULL; } - + ev->closing = 1; _em_slave_event(ev, 3, NULL); DBG("done %p", ev); - return 1; } -static unsigned char -em_file_open(const char *file, Evas_Object *obj EINA_UNUSED, void *ef) +static Eina_Bool +em_file_open(void *ef, const char *file) { - Emotion_Xine_Video *ev; - - ev = (Emotion_Xine_Video *)ef; - if (!ev) return 0; + Emotion_Xine_Video *ev = ef; _em_slave_event(ev, 2, strdup(file)); - return 1; + return EINA_TRUE; } static void @@ -1533,8 +1473,13 @@ _em_get_pos_len(Emotion_Xine_Video *ev) pthread_mutex_unlock(&(ev->get_pos_len_mutex)); } -static const Emotion_Video_Module em_module = +static const Emotion_Engine em_engine = { + EMOTION_ENGINE_API_VERSION, + EMOTION_ENGINE_PRIORITY_DEFAULT, + "xine", + em_add, /* add */ + em_del, /* del */ em_file_open, /* file_open */ em_file_close, /* file_close */ em_play, /* play */ @@ -1596,48 +1541,56 @@ static const Emotion_Video_Module em_module = NULL /* priority_get */ }; -static Eina_Bool -module_open(Evas_Object *obj, const Emotion_Video_Module **module, void **video, Emotion_Module_Options *opt) -{ - if (!module) - return EINA_FALSE; - - if (_emotion_xine_log_domain < 0) - { - eina_threads_init(); - eina_log_threads_enable(); - _emotion_xine_log_domain = eina_log_domain_register - ("emotion-xine", EINA_COLOR_LIGHTCYAN); - if (_emotion_xine_log_domain < 0) - { - EINA_LOG_CRIT("Could not register log domain 'emotion-xine'"); - return EINA_FALSE; - } - } - - if (!em_init(obj, video, opt)) - return EINA_FALSE; - - *module = &em_module; - return EINA_TRUE; -} - -static void -module_close(Emotion_Video_Module *module EINA_UNUSED, void *video) -{ - em_shutdown(video); -} - Eina_Bool xine_module_init(void) { - return _emotion_module_register("xine", module_open, module_close); + if (_emotion_init_count > 0) + { + _emotion_init_count++; + return EINA_TRUE; + } + + eina_threads_init(); + eina_log_threads_enable(); + _emotion_xine_log_domain = eina_log_domain_register + ("emotion-xine", EINA_COLOR_LIGHTCYAN); + if (_emotion_xine_log_domain < 0) + { + EINA_LOG_CRIT("Could not register log domain 'emotion-xine'"); + return EINA_FALSE; + } + + if (!_emotion_module_register(&em_engine)) + { + CRITICAL("Could not register module %p", &em_engine); + eina_log_domain_unregister(_emotion_xine_log_domain); + _emotion_xine_log_domain = -1; + return EINA_FALSE; + } + + _emotion_init_count = 1; + return EINA_TRUE; } void xine_module_shutdown(void) { - _emotion_module_unregister("xine"); + if (_emotion_init_count > 1) + { + _emotion_init_count--; + return; + } + else if (_emotion_init_count == 0) + { + EINA_LOG_ERR("too many xine_module_shutdown()"); + return; + } + _emotion_init_count = 0; + + _emotion_module_unregister(&em_engine); + + eina_log_domain_unregister(_emotion_xine_log_domain); + _emotion_xine_log_domain = -1; } #ifndef EMOTION_STATIC_BUILD_XINE