From 89b7a6be806d4d4b44e9f15a92fe8359fbd48e2e Mon Sep 17 00:00:00 2001 From: Rafael Antognolli Date: Fri, 17 Apr 2009 23:33:45 +0000 Subject: [PATCH] Added support to plugins. Now it's possible to implement new plugins that generate thumbnails from file formats that evas doesn't. SVN revision: 40156 --- legacy/ethumb/configure.ac | 19 ++ legacy/ethumb/m4/ac-modules.m4 | 8 +- legacy/ethumb/src/Makefile.am | 2 +- legacy/ethumb/src/bin/ethumb.c | 20 ++- legacy/ethumb/src/lib/Ethumb.c | 314 ++++++++++++++++++++++++++++----- legacy/ethumb/src/lib/Ethumb.h | 24 ++- 6 files changed, 332 insertions(+), 55 deletions(-) diff --git a/legacy/ethumb/configure.ac b/legacy/ethumb/configure.ac index a799e6e5a3..6822d4e10a 100644 --- a/legacy/ethumb/configure.ac +++ b/legacy/ethumb/configure.ac @@ -34,6 +34,11 @@ AC_DEFINE_UNQUOTED(THEMESDIR, ["$THEMESDIR"], [Where frame theme files are insta AS_AC_EXPAND(SYSCONFDIR, $sysconfdir) AC_DEFINE_UNQUOTED(SYSCONFDIR, ["$SYSCONFDIR"], [Where system configuration is stored]) +pluginsdir="${libdir}/ethumb/plugins" +AC_SUBST(pluginsdir) +AS_AC_EXPAND(PLUGINSDIR, $pluginsdir) +AC_DEFINE_UNQUOTED(PLUGINSDIR, ["$PLUGINSDIR"], [Where plugins are installed.]) + PKG_CHECK_MODULES(EINA, [eina-0]) PKG_CHECK_MODULES(EVAS, [evas]) PKG_CHECK_MODULES(ECORE, [ecore]) @@ -43,6 +48,18 @@ PKG_CHECK_MODULES(EDJE, [edje]) requirement_ethumb="eina-0 evas ecore ecore-evas ecore-file edje" +AM_CONDITIONAL(HAVE_EMOTION, false) +define([CHECK_MODULE_EMOTION], +[ + AC_ETH_CHECK_PKG(EMOTION, emotion, [], [EMOTION=false]) +]) + +AC_ETH_OPTIONAL_MODULE([emotion], true, [CHECK_MODULE_EMOTION]) + +if $USE_MODULE_EMOTION ; then + requirement_ethumb="$requirement_ethumb emotion" +fi + AC_SUBST(requirement_ethumb) AC_OUTPUT([ @@ -51,6 +68,8 @@ Makefile src/Makefile src/bin/Makefile src/lib/Makefile +src/plugins/Makefile +src/plugins/emotion/Makefile data/Makefile data/frames/Makefile m4/Makefile diff --git a/legacy/ethumb/m4/ac-modules.m4 b/legacy/ethumb/m4/ac-modules.m4 index c35e0a4219..ea77bdd365 100644 --- a/legacy/ethumb/m4/ac-modules.m4 +++ b/legacy/ethumb/m4/ac-modules.m4 @@ -22,7 +22,7 @@ define([_XTERM_COLORS], fi ]) -dnl AC_TCS_CHECK_PKG(name, lib [>= version], [action-if, [action-not]]) +dnl AC_ETH_CHECK_PKG(name, lib [>= version], [action-if, [action-not]]) dnl improved version of PKG_CHECK_MODULES, it does the same checking dnl and defines HAVE_[name]=yes/no and also exports dnl [name]_CFLAGS and [name]_LIBS. @@ -38,7 +38,7 @@ dnl - [name]_CFLAGS: if HAVE_[name]=yes dnl - [name]_LIBS: if HAVE_[name]=yes dnl - [name]_VERSION: if HAVE_[name]=yes dnl -AC_DEFUN([AC_TCS_CHECK_PKG], +AC_DEFUN([AC_ETH_CHECK_PKG], [ # ---------------------------------------------------------------------- # BEGIN: Check library with pkg-config: $1 (pkg-config=$2) @@ -69,7 +69,7 @@ AC_DEFUN([AC_TCS_CHECK_PKG], # ---------------------------------------------------------------------- ]) -dnl AC_TCS_OPTIONAL_MODULE(name, [initial-status, [check-if-enabled]]) +dnl AC_ETH_OPTIONAL_MODULE(name, [initial-status, [check-if-enabled]]) dnl Defines configure argument ---[name] to enable an dnl optional module called 'name'. dnl @@ -94,7 +94,7 @@ dnl Provides: dnl - USE_MODULE_[name]=true|false [make, shell] dnl - USE_MODULE_[name]=1 if enabled [config.h] dnl -AC_DEFUN([AC_TCS_OPTIONAL_MODULE], +AC_DEFUN([AC_ETH_OPTIONAL_MODULE], [ # ---------------------------------------------------------------------- # BEGIN: Check for optional module: $1 (default: $2) diff --git a/legacy/ethumb/src/Makefile.am b/legacy/ethumb/src/Makefile.am index a8590b2f0d..e55545e4cf 100644 --- a/legacy/ethumb/src/Makefile.am +++ b/legacy/ethumb/src/Makefile.am @@ -1,3 +1,3 @@ MAINTAINERCLEANFILES = Makefile.in -SUBDIRS = lib bin +SUBDIRS = lib bin plugins diff --git a/legacy/ethumb/src/bin/ethumb.c b/legacy/ethumb/src/bin/ethumb.c index 71ccd6bf9d..63164ebb12 100644 --- a/legacy/ethumb/src/bin/ethumb.c +++ b/legacy/ethumb/src/bin/ethumb.c @@ -28,6 +28,7 @@ #include #include #include +#include const char *aspect_opt[] = { "keep", "ignore", "crop", NULL }; const char *format_opt[] = { "png", "jpg", NULL }; @@ -115,6 +116,8 @@ const Ecore_Getopt optdesc = { "file:group:swallow_part", _ethumb_getopt_callback_frame_parse, NULL), ECORE_GETOPT_STORE_STR ('k', "key", "key inside eet file to read image from."), + ECORE_GETOPT_STORE_DOUBLE + ('v', "video_time", "time of video frame to use as thumbnail."), ECORE_GETOPT_LICENSE('L', "license"), ECORE_GETOPT_COPYRIGHT('C', "copyright"), ECORE_GETOPT_VERSION('V', "version"), @@ -123,6 +126,12 @@ const Ecore_Getopt optdesc = { } }; +static void +_finished_thumb(Ethumb_File *ef, void *data) +{ + ecore_main_loop_quit(); +} + int main(int argc, char *argv[]) { @@ -139,11 +148,13 @@ main(int argc, char *argv[]) struct frame frame = {NULL}; const char *thumb_path = NULL; const char *thumb_key = NULL; + double video_time = 0; int arg_index; int i; int r = 1; ethumb_init(); + ecore_init(); Ecore_Getopt_Value values[] = { ECORE_GETOPT_VALUE_PTR_CAST(geometry), @@ -153,6 +164,7 @@ main(int argc, char *argv[]) ECORE_GETOPT_VALUE_STR(category), ECORE_GETOPT_VALUE_PTR_CAST(frame), ECORE_GETOPT_VALUE_STR(src_key), + ECORE_GETOPT_VALUE_DOUBLE(video_time), ECORE_GETOPT_VALUE_BOOL(quit_option), ECORE_GETOPT_VALUE_BOOL(quit_option), ECORE_GETOPT_VALUE_BOOL(quit_option), @@ -198,6 +210,8 @@ main(int argc, char *argv[]) eina_stringshare_del(frame.group); eina_stringshare_del(frame.swallow); } + if (video_time > 0) + ethumb_video_time_set(e, video_time); if (r && arg_index < argc) ef = ethumb_file_new(e, argv[arg_index++], src_key); @@ -209,12 +223,16 @@ main(int argc, char *argv[]) if (ef) { ethumb_file_thumb_path_set(ef, thumb_path, thumb_key); - ethumb_file_generate(ef); + r = ethumb_file_generate(ef, _finished_thumb, NULL); } + if (r) + ecore_main_loop_begin(); + ethumb_file_free(ef); ethumb_free(e); + ecore_shutdown(); ethumb_shutdown(); return !r; diff --git a/legacy/ethumb/src/lib/Ethumb.c b/legacy/ethumb/src/lib/Ethumb.c index 25d408f9b8..9545c734e6 100644 --- a/legacy/ethumb/src/lib/Ethumb.c +++ b/legacy/ethumb/src/lib/Ethumb.c @@ -25,12 +25,16 @@ #endif #include #include "Ethumb.h" +#include "Ethumb_Plugin.h" #include #include #include #include #include #include +#include +#include +#include #include "md5.h" #ifndef PATH_MAX @@ -49,6 +53,12 @@ #define WRN(...) EINA_ERROR_PWARN(__VA_ARGS__) #define ERR(...) EINA_ERROR_PERR(__VA_ARGS__) +struct _Ethumb_Plugin_Object +{ + Ethumb_Plugin *plugin; + void *dl_handle; +}; + static int initcount = 0; static const char *_home_thumb_dir = NULL; static const char *_thumb_category_normal = NULL; @@ -57,6 +67,95 @@ static const char *_thumb_category_large = NULL; static const int THUMB_SIZE_NORMAL = 128; static const int THUMB_SIZE_LARGE = 256; +static Eina_Hash *_plugins_ext = NULL; +static Eina_List *_plugins = NULL; + +static struct _Ethumb_Plugin_Object * +_ethumb_plugin_load(const char *path) +{ + char *errmsg; + struct _Ethumb_Plugin_Object *p; + Ethumb_Plugin *(*init)(void); + + p = calloc(1, sizeof(struct _Ethumb_Plugin_Object)); + + p->dl_handle = dlopen(path, RTLD_NOW | RTLD_LOCAL); + errmsg = dlerror(); + if (errmsg) + { + ERR("could not dlopen() %s\n", errmsg); + return NULL; + } + + init = dlsym(p->dl_handle, "ethumb_plugin_init"); + errmsg = dlerror(); + if (errmsg) + { + ERR("could not find plugin entry point %s\n", errmsg); + return NULL; + } + + p->plugin = init(); + if (!p->plugin) + { + ERR("plugin \"%s\" failed to init.\n", path); + return NULL; + } + + return p; +} + +static void +_ethumb_plugins_load(void) +{ + DIR *dir; + struct dirent *de; + char plugin_path[PATH_MAX]; + struct _Ethumb_Plugin_Object *p; + + _plugins_ext = eina_hash_string_small_new(NULL); + EINA_SAFETY_ON_NULL_RETURN(_plugins_ext); + + dir = opendir(PLUGINSDIR); + EINA_SAFETY_ON_NULL_RETURN(dir); + + while ((de = readdir(dir))) + { + const char **ext; + if (strncmp(de->d_name + strlen(de->d_name) - 3, ".so", 3)) + continue; + snprintf(plugin_path, 1024, "%s/%s", PLUGINSDIR, de->d_name); + p = _ethumb_plugin_load(plugin_path); + if (!p) + { + ERR("couldn't load plugin '%s'\n", plugin_path); + continue; + } + for (ext = p->plugin->extensions; *ext; ext++) + eina_hash_add(_plugins_ext, *ext, p->plugin); + + _plugins = eina_list_append(_plugins, p); + } +} + +static void +_ethumb_plugins_unload(void) +{ + Eina_List *l; + + eina_hash_free(_plugins_ext); + _plugins_ext = NULL; + + l = _plugins; + for (l = _plugins; l; l = l->next) + { + struct _Ethumb_Plugin_Object *p = l->data; + p->plugin->shutdown(p->plugin); + dlclose(p->dl_handle); + free(p); + } +} + EAPI int ethumb_init(void) { @@ -67,6 +166,8 @@ ethumb_init(void) return ++initcount; eina_stringshare_init(); + eina_list_init(); + eina_hash_init(); evas_init(); ecore_init(); ecore_evas_init(); @@ -79,6 +180,7 @@ ethumb_init(void) _thumb_category_normal = eina_stringshare_add("normal"); _thumb_category_large = eina_stringshare_add("large"); + _ethumb_plugins_load(); return ++initcount; } @@ -88,10 +190,13 @@ ethumb_shutdown(void) initcount--; if (initcount == 0) { + _ethumb_plugins_unload(); eina_stringshare_del(_home_thumb_dir); eina_stringshare_del(_thumb_category_normal); eina_stringshare_del(_thumb_category_large); eina_stringshare_shutdown(); + eina_list_shutdown(); + eina_hash_shutdown(); evas_shutdown(); ecore_shutdown(); ecore_evas_shutdown(); @@ -194,6 +299,8 @@ ethumb_free(Ethumb *ethumb) ecore_evas_free(ethumb->ee); eina_stringshare_del(ethumb->thumb_dir); eina_stringshare_del(ethumb->category); + if (ethumb->finished_idler) + ecore_idler_del(ethumb->finished_idler); free(ethumb); } @@ -385,6 +492,14 @@ ethumb_thumb_category_get(Ethumb *e) return e->category; } +EAPI void +ethumb_video_time_set(Ethumb *e, float time) +{ + EINA_SAFETY_ON_NULL_RETURN(e); + + e->video.time = time; +} + EAPI Ethumb_File * ethumb_file_new(Ethumb *e, const char *path, const char *key) { @@ -581,8 +696,8 @@ ethumb_file_thumb_path_get(Ethumb_File *ef) return ef->thumb_path; } -static void -_ethumb_calculate_aspect(Ethumb *e, int iw, int ih, int *w, int *h) +void +ethumb_calculate_aspect(Ethumb *e, int iw, int ih, int *w, int *h) { *w = e->tw; *h = e->th; @@ -596,8 +711,8 @@ _ethumb_calculate_aspect(Ethumb *e, int iw, int ih, int *w, int *h) } } -static void -_ethumb_calculate_fill(Ethumb *e, int iw, int ih, int *fx, int *fy, int *fw, int *fh) +void +ethumb_calculate_fill(Ethumb *e, int iw, int ih, int *fx, int *fy, int *fw, int *fh) { *fw = e->tw; *fh = e->th; @@ -623,6 +738,111 @@ _ethumb_calculate_fill(Ethumb *e, int iw, int ih, int *fx, int *fy, int *fw, int } } +static int +_ethumb_plugin_generate(Ethumb_File *ef) +{ + const char *ext; + Ethumb_Plugin *plugin; + Ethumb *e; + int r; + + ext = strrchr(ef->src_path, '.'); + if (!ext) + { + ERR("could not get extension for file \"%s\"\n", ef->src_path); + return 0; + } + + plugin = eina_hash_find(_plugins_ext, ext + 1); + if (!plugin) + { + DBG("no plugin for extension: \"%s\"\n", ext + 1); + return 0; + } + + e = ef->ethumb; + if (e->frame) + evas_object_hide(e->frame->edje); + else + evas_object_hide(e->img); + + r = plugin->generate_thumb(ef); + + return r; +} + +int +ethumb_plugin_image_resize(Ethumb_File *ef, int w, int h) +{ + Ethumb *eth; + Evas_Object *img; + + eth = ef->ethumb; + img = eth->img; + + if (eth->frame) + { + edje_extern_object_min_size_set(img, w, h); + edje_extern_object_max_size_set(img, w, h); + edje_object_calc_force(eth->frame->edje); + evas_object_move(eth->frame->edje, 0, 0); + evas_object_resize(eth->frame->edje, w, h); + } + else + { + evas_object_move(img, 0, 0); + evas_object_resize(img, w, h); + } + + evas_object_image_size_set(eth->o, w, h); + ecore_evas_resize(eth->sub_ee, w, h); + + ef->w = w; + ef->h = h; + + return 1; +} + +int +ethumb_image_save(Ethumb_File *ef) +{ + int r; + char *dname; + Ethumb *eth = ef->ethumb; + + evas_damage_rectangle_add(eth->sub_e, 0, 0, ef->w, ef->h); + evas_render(eth->sub_e); + + if (!ef->thumb_path) + _ethumb_file_generate_path(ef); + + if (!ef->thumb_path) + { + ERR("could not create file path...\n"); + return 0; + } + + dname = ecore_file_dir_get(ef->thumb_path); + r = ecore_file_mkpath(dname); + free(dname); + if (!r) + { + ERR("could not create directory '%s'\n", dname); + return 0; + } + + r = evas_object_image_save(eth->o, ef->thumb_path, ef->thumb_key, + "quality=85"); + + if (!r) + { + ERR("could not save image.\n"); + return 0; + } + + return 1; +} + static int _ethumb_image_load(Ethumb_File *ef) { @@ -658,7 +878,7 @@ _ethumb_image_load(Ethumb_File *ef) if ((w <= 0) || (h <= 0)) return 0; - _ethumb_calculate_aspect(eth, w, h, &ww, &hh); + ethumb_calculate_aspect(eth, w, h, &ww, &hh); if (eth->frame) { @@ -674,28 +894,64 @@ _ethumb_image_load(Ethumb_File *ef) evas_object_resize(img, ww, hh); } - _ethumb_calculate_fill(eth, w, h, &fx, &fy, &fw, &fh); + ethumb_calculate_fill(eth, w, h, &fx, &fy, &fw, &fh); evas_object_image_fill_set(img, fx, fy, fw, fh); evas_object_image_size_set(eth->o, ww, hh); ecore_evas_resize(eth->sub_ee, ww, hh); - evas_damage_rectangle_add(eth->sub_e, 0, 0, ww, hh); - ef->w = ww; ef->h = hh; return 1; } -EAPI int -ethumb_file_generate(Ethumb_File *ef) +static int +_ethumb_finished_idler_cb(void *data) +{ + Ethumb_File *ef = data; + Ethumb *e = ef->ethumb; + + e->finished_cb(ef, e->cb_data); + e->finished_idler = NULL; + e->finished_cb = NULL; + e->cb_data = NULL; + + return 0; +} + +void +ethumb_finished_callback_call(Ethumb_File *ef) +{ + Ethumb *e = ef->ethumb; + + if (e->finished_idler) + ecore_idler_del(e->finished_idler); + e->finished_idler = ecore_idler_add(_ethumb_finished_idler_cb, ef); +} + +EAPI int +ethumb_file_generate(Ethumb_File *ef, ethumb_generate_callback_t finished_cb, void *data) { - Ethumb *eth; int r; - char *dname; + Ethumb *e; EINA_SAFETY_ON_NULL_RETURN_VAL(ef, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(finished_cb, 0); + + e = ef->ethumb; + + if (e->finished_idler) + { + ERR("thumbnail generation already in progress.\n"); + return 0; + } + e->finished_cb = finished_cb; + e->cb_data = data; + + r = _ethumb_plugin_generate(ef); + if (r) + return r; if (!_ethumb_image_load(ef)) { @@ -703,35 +959,9 @@ ethumb_file_generate(Ethumb_File *ef) return 0; } - eth = ef->ethumb; - evas_render(eth->sub_e); + r = ethumb_image_save(ef); + if (r && finished_cb) + ethumb_finished_callback_call(ef); - if (!ef->thumb_path) - _ethumb_file_generate_path(ef); - - if (!ef->thumb_path) - { - ERR("could not create file path...\n"); - return 0; - } - - dname = ecore_file_dir_get(ef->thumb_path); - r = ecore_file_mkpath(dname); - free(dname); - if (!r) - { - ERR("could not create directory '%s'\n", dname); - return 0; - } - - r = evas_object_image_save(eth->o, ef->thumb_path, ef->thumb_key, - "quality=85"); - - if (!r) - { - ERR("could not save image.\n"); - return 0; - } - - return 1; + return r; } diff --git a/legacy/ethumb/src/lib/Ethumb.h b/legacy/ethumb/src/lib/Ethumb.h index 79404a5fdc..0eb1d425d3 100644 --- a/legacy/ethumb/src/lib/Ethumb.h +++ b/legacy/ethumb/src/lib/Ethumb.h @@ -31,6 +31,7 @@ #endif /* ! _WIN32 */ #endif /* EAPI */ +#include #include #include @@ -63,6 +64,11 @@ enum _Ethumb_Thumb_Aspect typedef enum _Ethumb_Thumb_Aspect Ethumb_Thumb_Aspect; +typedef struct _Ethumb_Frame Ethumb_Frame; +typedef struct _Ethumb Ethumb; +typedef struct _Ethumb_File Ethumb_File; +typedef void (*ethumb_generate_callback_t)(Ethumb_File *ef, void *data); + struct _Ethumb_Frame { const char *file; @@ -71,8 +77,6 @@ struct _Ethumb_Frame Evas_Object *edje; }; -typedef struct _Ethumb_Frame Ethumb_Frame; - struct _Ethumb { const char *thumb_dir; @@ -81,14 +85,20 @@ struct _Ethumb int format; int aspect; float crop_x, crop_y; + struct + { + double time; + } video; Ethumb_Frame *frame; Ecore_Evas *ee, *sub_ee; Evas *e, *sub_e; Evas_Object *o, *img; + Evas_Object *plugin_img; + Ecore_Idler *finished_idler; + ethumb_generate_callback_t finished_cb; + void *cb_data; }; -typedef struct _Ethumb Ethumb; - struct _Ethumb_File { Ethumb *ethumb; @@ -99,8 +109,6 @@ struct _Ethumb_File int w, h; }; -typedef struct _Ethumb_File Ethumb_File; - EAPI int ethumb_init(void); EAPI int ethumb_shutdown(void); @@ -130,11 +138,13 @@ EAPI const char * ethumb_thumb_dir_path_get(Ethumb *e) EINA_WARN_UNUSED_RESULT E EAPI void ethumb_thumb_category_set(Ethumb *e, const char *category) EINA_ARG_NONNULL(1); EAPI const char * ethumb_thumb_category_get(Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; +EAPI void ethumb_video_time_set(Ethumb *e, float time) EINA_ARG_NONNULL(1); + EAPI Ethumb_File * ethumb_file_new(Ethumb *e, const char *path, const char *key) EINA_MALLOC EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2); EAPI void ethumb_file_free(Ethumb_File *ef); EAPI void ethumb_file_thumb_path_set(Ethumb_File *ef, const char *path, const char *key) EINA_ARG_NONNULL(1); EAPI const char * ethumb_file_thumb_path_get(Ethumb_File *ef) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; -EAPI int ethumb_file_generate(Ethumb_File *ef) EINA_ARG_NONNULL(1); +EAPI int ethumb_file_generate(Ethumb_File *ef, ethumb_generate_callback_t finished_cb, void *data) EINA_ARG_NONNULL(1, 2); #ifdef __cplusplus }