rage/src/bin/videothumb.c

389 lines
10 KiB
C

#include <Elementary.h>
#include "videothumb.h"
#include "sha1.h"
typedef struct _Videothumb Videothumb;
struct _Videothumb
{
Evas_Object_Smart_Clipped_Data __clipped_data;
Evas_Object *o_img;
Ecore_Exe *thumb_exe;
Ecore_Event_Handler *exe_handler;
const char *file;
const char *realfile;
char *realpath;
double pos;
unsigned int realpos;
int iw, ih;
Evas_Coord w, h;
Eina_Bool seen : 1;
};
static Evas_Smart *_smart = NULL;
static Evas_Smart_Class _parent_sc = EVAS_SMART_CLASS_INIT_NULL;
static Eina_List *busy_thumbs = NULL;
static Eina_List *vidthumbs = NULL;
static Eina_Bool
_busy_add(const char *file)
{
Eina_List *l;
const char *s;
EINA_LIST_FOREACH(busy_thumbs, l, s)
{
if (!strcmp(file, s)) return EINA_FALSE;
}
busy_thumbs = eina_list_append(busy_thumbs, eina_stringshare_add(file));
return EINA_TRUE;
}
static Eina_Bool
_busy_del(const char *file)
{
Eina_List *l;
const char *s;
EINA_LIST_FOREACH(busy_thumbs, l, s)
{
if (!strcmp(file, s))
{
eina_stringshare_del(s);
busy_thumbs = eina_list_remove_list(busy_thumbs, l);
return EINA_TRUE;
}
}
return EINA_FALSE;
}
static void
_thumb_update(Evas_Object *obj)
{
Videothumb *sd = evas_object_smart_data_get(obj);
char buf[PATH_MAX];
if (!sd) return;
snprintf(buf, sizeof(buf), "%u", sd->realpos);
evas_object_image_file_set(sd->o_img, NULL, NULL);
evas_object_image_file_set(sd->o_img, sd->realfile, buf);
evas_object_image_size_get(sd->o_img, &(sd->iw), &(sd->ih));
if ((sd->iw <= 0) || (sd->ih <= 0))
{
evas_object_del(sd->o_img);
sd->o_img = NULL;
evas_object_smart_callback_call(obj, "failed", NULL);
}
else
{
evas_object_image_preload(sd->o_img, EINA_FALSE);
evas_object_smart_callback_call(obj, "loaded", NULL);
}
}
static void
_thumb_match_update(Evas_Object *obj, const char *file)
{
Videothumb *sd = evas_object_smart_data_get(obj);
if (!sd) return;
if (!strcmp(sd->realpath, file)) _thumb_update(obj);
}
static Eina_Bool
_cb_thumb_exe(void *data, int type EINA_UNUSED, void *event)
{
Ecore_Exe_Event_Del *ev;
Videothumb *sd = evas_object_smart_data_get(data);
if (!sd) return EINA_TRUE;
ev = event;
if (ev->exe == sd->thumb_exe)
{
Eina_List *l;
Evas_Object *o;
_busy_del(sd->realpath);
EINA_LIST_FOREACH(vidthumbs, l, o)
{
_thumb_match_update(o, sd->realpath);
}
if ((sd->iw <= 0) || (sd->ih <= 0))
{
if (sd->exe_handler)
{
ecore_event_handler_del(sd->exe_handler);
sd->exe_handler = NULL;
}
}
sd->thumb_exe = NULL;
return EINA_FALSE;
}
return EINA_TRUE;
}
static void
_cb_preload(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *info EINA_UNUSED)
{
Videothumb *sd = evas_object_smart_data_get(data);
if (!sd) return;
evas_object_show(sd->o_img);
evas_object_smart_callback_call(data, "data", NULL);
}
static void
_videothumb_image_load(Evas_Object *obj)
{
Videothumb *sd = evas_object_smart_data_get(obj);
char buf_base[PATH_MAX];
char buf_file[PATH_MAX];
char buf[PATH_MAX];
char *s;
const char *libdir;
unsigned char sum[20];
if (!sd) return;
if (!sd->file) return;
sd->o_img = evas_object_image_filled_add(evas_object_evas_get(obj));
evas_object_smart_member_add(sd->o_img, obj);
if (!sha1((unsigned char *)sd->realpath, strlen(sd->realpath), sum)) return;
snprintf(buf_base, sizeof(buf_base), "%s/rage/thumb/%02x",
efreet_cache_home_get(), sum[0]);
snprintf(buf_file, sizeof(buf_base),
"%s/%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
"%02x%02x%02x%02x%02x%02x%02x%02x.eet",
buf_base,
sum[1], sum[2], sum[3],
sum[4], sum[5], sum[6], sum[7],
sum[8], sum[9], sum[10], sum[11],
sum[12], sum[13], sum[14], sum[15],
sum[16], sum[17], sum[18], sum[19]);
if (sd->realfile) eina_stringshare_del(sd->realfile);
sd->realfile = eina_stringshare_add(buf_file);
sd->realpos = (((unsigned int)(sd->pos * 1000.0)) / 10000) * 10000;
snprintf(buf, sizeof(buf), "%u", sd->realpos);
evas_object_event_callback_add(sd->o_img,
EVAS_CALLBACK_IMAGE_PRELOADED,
_cb_preload, obj);
evas_object_image_file_set(sd->o_img, sd->realfile, buf);
evas_object_image_size_get(sd->o_img, &(sd->iw), &(sd->ih));
if (sd->iw > 0)
{
Eina_Bool ok = EINA_FALSE;
struct stat st1, st2;
if (stat(sd->realpath, &st1) == 0)
{
if (stat(sd->realfile, &st2) == 0)
{
if (st1.st_mtime < st2.st_mtime) ok = EINA_TRUE;
}
}
if (ok)
{
evas_object_image_preload(sd->o_img, EINA_FALSE);
return;
}
}
if (!_busy_add(sd->realpath)) return;
ecore_exe_run_priority_set(10);
if (sd->thumb_exe)
{
ecore_exe_free(sd->thumb_exe);
sd->thumb_exe = NULL;
}
s = ecore_file_escape_name(sd->realpath);
if (s)
{
libdir = elm_app_lib_dir_get();
if (libdir)
{
if (!sd->exe_handler)
sd->exe_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
_cb_thumb_exe, obj);
snprintf(buf, sizeof(buf),
"%s/rage/utils/rage_thumb %s 10000 >& /dev/null",
libdir, s);
sd->thumb_exe = ecore_exe_pipe_run(buf,
ECORE_EXE_TERM_WITH_PARENT |
ECORE_EXE_NOT_LEADER,
obj);
}
}
}
static void
_videothumb_eval(Evas_Object *obj, Eina_Bool force)
{
Videothumb *sd = evas_object_smart_data_get(obj);
Evas_Coord ox, oy, ow, oh, vw, vh;
Eina_Bool seen = EINA_FALSE;
if (!sd) return;
evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
evas_output_viewport_get(evas_object_evas_get(obj), NULL, NULL, &vw, &vh);
// XXX: not listening to canvas resizes! :(
if (ELM_RECTS_INTERSECT(ox, oy, ow, oh, 0, 0, vw, vh)) seen = EINA_TRUE;
// XXX: fix - wrokaround and always visible
seen = EINA_TRUE;
if (force)
{
sd->seen = seen;
if (sd->o_img)
{
evas_object_del(sd->o_img);
sd->o_img = NULL;
}
_videothumb_image_load(obj);
evas_object_move(sd->o_img, ox, oy);
evas_object_resize(sd->o_img, ow, oh);
}
else
{
if (seen != sd->seen)
{
sd->seen = seen;
if (sd->seen)
{
if (sd->o_img)
{
evas_object_del(sd->o_img);
sd->o_img = NULL;
}
_videothumb_image_load(obj);
evas_object_move(sd->o_img, ox, oy);
evas_object_resize(sd->o_img, ow, oh);
}
else
{
if (sd->o_img)
{
evas_object_del(sd->o_img);
sd->o_img = NULL;
}
}
}
}
}
static void
_smart_add(Evas_Object *obj)
{
Videothumb *sd;
sd = calloc(1, sizeof(Videothumb));
EINA_SAFETY_ON_NULL_RETURN(sd);
evas_object_smart_data_set(obj, sd);
_parent_sc.add(obj);
}
static void
_smart_del(Evas_Object *obj)
{
Videothumb *sd = evas_object_smart_data_get(obj);
if (!sd) return;
vidthumbs = eina_list_remove(vidthumbs, obj);
if (sd->file) eina_stringshare_del(sd->file);
if (sd->realfile) eina_stringshare_del(sd->realfile);
if (sd->realpath) free(sd->realpath);
if (sd->o_img) evas_object_del(sd->o_img);
if (sd->thumb_exe) ecore_exe_free(sd->thumb_exe);
if (sd->exe_handler) ecore_event_handler_del(sd->exe_handler);
_parent_sc.del(obj);
}
static void
_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
{
Videothumb *sd = evas_object_smart_data_get(obj);
Evas_Coord ox, oy, ow, oh;
if (!sd) return;
evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
if ((ow == w) && (oh == h)) return;
evas_object_smart_changed(obj);
}
static void
_smart_calculate(Evas_Object *obj)
{
Videothumb *sd = evas_object_smart_data_get(obj);
Evas_Coord ox, oy, ow, oh;
if (!sd) return;
evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
sd->w = ow;
sd->h = oh;
_videothumb_eval(obj, EINA_FALSE);
if (sd->o_img)
{
evas_object_move(sd->o_img, ox, oy);
evas_object_resize(sd->o_img, ow, oh);
}
}
static void
_smart_move(Evas_Object *obj, Evas_Coord x EINA_UNUSED, Evas_Coord y EINA_UNUSED)
{
Videothumb *sd = evas_object_smart_data_get(obj);
if (!sd) return;
evas_object_smart_changed(obj);
}
static void
_smart_init(void)
{
static Evas_Smart_Class sc;
evas_object_smart_clipped_smart_set(&_parent_sc);
sc = _parent_sc;
sc.name = "videothumb";
sc.version = EVAS_SMART_CLASS_VERSION;
sc.add = _smart_add;
sc.del = _smart_del;
sc.resize = _smart_resize;
sc.move = _smart_move;
sc.calculate = _smart_calculate;
_smart = evas_smart_class_new(&sc);
}
Evas_Object *
videothumb_add(Evas_Object *parent)
{
Evas *e;
Evas_Object *obj;
EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
e = evas_object_evas_get(parent);
if (!e) return NULL;
if (!_smart) _smart_init();
obj = evas_object_smart_add(e, _smart);
vidthumbs = eina_list_prepend(vidthumbs, obj);
return obj;
}
void
videothumb_file_set(Evas_Object *obj, const char *file, double pos)
{
Videothumb *sd = evas_object_smart_data_get(obj);
if (!sd) return;
if ((sd->file == file) && (sd->pos == pos)) return;
if (sd->file) eina_stringshare_del(sd->file);
sd->file = eina_stringshare_add(file);
sd->realpath = ecore_file_realpath(sd->file);
sd->pos = pos;
_videothumb_eval(obj, EINA_TRUE);
}
void
videothumb_size_get(Evas_Object *obj, int *w, int *h)
{
Videothumb *sd = evas_object_smart_data_get(obj);
*w = 1;
*h = 1;
if (!sd) return;
*w = sd->iw;
*h = sd->ih;
}