add video thumbnails on timeline/dragable/seeker at the bottom

these thumbnails are generated in the bg by rage_thumb and will appear
once generated (or already found cached). it'll generate new thumbs if
modified dates are equal or newer on tthe src vs the thumbnail cache.
the caches store 160xN thumbs (keep aspect) with 70% lossy jpeg
quality in an eet file with one thumb per 10 second interval. so it
has limited accuracy.
This commit is contained in:
Carsten Haitzler 2014-08-04 17:15:30 +09:00
parent 848b3af260
commit 706e4948d7
13 changed files with 712 additions and 45 deletions

3
TODO
View File

@ -1,6 +1,5 @@
* volume status display when changed (slider/image/percentage) * volume status display when changed (slider/image/percentage)
* emotion engine selection options (gui) * emotion engine selection options (gui)
* timeline thumbnails on position slider
* right click control panel (ala terminology - need elm config ui code) * right click control panel (ala terminology - need elm config ui code)
* about display/popup (from panel?) * about display/popup (from panel?)
* mouse wheel for forward/rewind and/or prev/next and/or volume up/down * mouse wheel for forward/rewind and/or prev/next and/or volume up/down
@ -13,4 +12,4 @@
* show busy anim until opened cb or failure * show busy anim until opened cb or failure
* add button/control top-left next to audio to do fullscreen/normal toggle * add button/control top-left next to audio to do fullscreen/normal toggle
* detect letterboxing and auto-crop * detect letterboxing and auto-crop
* thumbnail picker show all thumbs for video in a grid to select position

View File

@ -35,6 +35,10 @@ collections {
images.image: "horizontal_separated_bar_small_glow.png" COMP; images.image: "horizontal_separated_bar_small_glow.png" COMP;
images.image: "vgrad_shadow_bi.png" COMP; images.image: "vgrad_shadow_bi.png" COMP;
images.image: "win_shadow.png" COMP;
images.image: "bg_shine.png" COMP;
images.image: "bg_glint.png" COMP;
set { name: "pos_indicator"; set { name: "pos_indicator";
image { image: "pos_indicator_big.png" COMP; size: 32 28 99999 99999; } image { image: "pos_indicator_big.png" COMP; size: 32 28 99999 99999; }
image { image: "pos_indicator.png" COMP; size: 0 0 31 27; } image { image: "pos_indicator.png" COMP; size: 0 0 31 27; }
@ -61,6 +65,7 @@ collections {
script { script {
public pos_visible; public pos_visible;
public pos_timer; public pos_timer;
public drag_is_down;
public pos_timeout(val) { public pos_timeout(val) {
set_int(pos_visible, 0); set_int(pos_visible, 0);
@ -1261,6 +1266,212 @@ collections {
} }
} }
part { name: "dragover_master"; type: RECT;
clip_to: "posclip";
description { state: "default" 0.0;
visible: 1;
}
description { state: "novideo" 0.0;
visible: 0;
}
}
program {
signal: "state,novideo"; source: "rage";
action: STATE_SET "novideo" 0.0;
target: "dragover_master";
}
program {
signal: "state,video"; source: "rage";
action: STATE_SET "default" 0.0;
target: "dragover_master";
}
part { name: "dragover_active"; type: RECT;
clip_to: "dragover_master";
description { state: "default" 0.0;
color: 255 255 255 0;
visible: 0;
}
description { state: "visible" 0.0;
visible: 1;
color: 255 255 255 255;
}
}
part { name: "dragover_event"; type: RECT; repeat_events: 1;
clip_to: "posclip";
description { state: "default" 0.0;
rel1.to_x: "bar_bg";
rel1.to_y: "posevent";
rel2.to_x: "bar_bg";
color: 0 0 0 0;
fixed: 1 1;
}
}
program {
signal: "mouse,in"; source: "dragover_event";
action: STATE_SET "visible" 0.0;
transition: SINUSOIDAL 0.5;
target: "dragover_active";
}
program {
signal: "mouse,out"; source: "dragover_event";
action: STATE_SET "default" 0.0;
transition: SINUSOIDAL 1.0;
target: "dragover_active";
}
part { name: "dragover"; type: SPACER;
description { state: "default" 0.0;
rel1.to: "dragover_event";
rel1.relative: 0.5 0.0;
rel2.to: "dragover_event";
rel2.relative: 0.5 0.0;
fixed: 1 1;
}
}
part { name: "dragshadow"; mouse_events: 0;
clip_to: "dragover_active";
description { state: "default" 0.0;
fixed: 1 1;
rel1.to: "rage.dragable.content";
rel2.to: "rage.dragable.content";
image.normal: "win_shadow.png";
image.border: 14 14 14 14;
image.middle: 0;
rel1.offset: -7 -3;
rel2.offset: 6 11;
fill.smooth: 0;
}
}
part { name: "dragover_fill"; mouse_events: 0;
clip_to: "dragover_active";
description { state: "default" 0.0;
fixed: 1 1;
image.normal: "pm_fill.png";
fill {
size.relative: 0.0 0.0;
size.offset: 64 64;
}
rel1.to: "rage.dragable.content";
rel2.to: "rage.dragable.content";
}
}
part { name: "rage.dragable.content"; type: SWALLOW;
clip_to: "dragover_active";
description { state: "default" 0.0;
rel1.to: "dragover";
rel2.to: "dragover";
align: 0.5 1.0;
fixed: 1 1;
}
}
part { name: "dragover_clip"; type: RECT;
clip_to: "dragover_active";
description { state: "default" 0.0;
rel1.to: "rage.dragable.content";
rel2.to: "rage.dragable.content";
fixed: 1 1;
}
}
part { name: "dragover_glintclip"; type: RECT;
clip_to: "dragover_active";
description { state: "default" 0.0;
rel1.to: "dragover_clip";
rel2.to: "dragover_clip";
rel1.offset: 0 -10;
}
}
part { name: "shine"; mouse_events: 0;
clip_to: "dragover_clip";
description { state: "default" 0.0;
image.normal: "bg_shine.png";
fill.smooth: 0;
rel1.to: "dragover_clip";
rel2.to: "dragover_clip";
align: 0.5 0.0;
aspect: (255/120) (255/120);
aspect_preference: HORIZONTAL;
}
}
part { name: "glint"; mouse_events: 0;
clip_to: "dragover_glintclip";
description { state: "default" 0.0;
fixed: 1 1;
min: 79 5;
max: 79 5;
rel1 {
relative: 0.0 0.0;
offset: 0 0;
to: "dragover_clip";
}
rel2 {
relative: 1.0 0.0;
offset: -1 0;
to: "dragover_clip";
}
image.normal: "bg_glint.png";
}
}
part { name: "dragover_bevel2";
clip_to: "dragover_active";
description { state: "default" 0.0;
image.normal: "bg_bevel.png";
image.border: 1 1 1 1;
image.middle: 0;
fill.smooth: 0;
rel1.to: "rage.dragable.content";
rel2.to: "rage.dragable.content";
}
}
program { name: "dragmove";
signal: "mouse,move"; source: "dragover_event";
script {
new mx, my, x, y, w, h;
new Float:pos, Float:px, Float:pw;
get_mouse(mx, my);
get_geometry(PART:"dragover_event", x, y, w, h);
x = mx - x;
y = my - y;
px = x;
pw = w;
if (w > 0) pos = px / pw;
else pos = 0.5;
custom_state(PART:"dragover", "default", 0.0);
set_state_val(PART:"dragover", STATE_REL1, pos, 0.0);
set_state_val(PART:"dragover", STATE_REL2, pos, 0.0);
set_state(PART:"dragover", "custom", 0.0);
send_message(MSG_FLOAT, 13, pos);
if (get_int(drag_is_down) == 1)
send_message(MSG_FLOAT, 10, pos);
}
}
program { name: "dragdown";
signal: "mouse,down,1"; source: "dragover_event";
script {
new mx, my, x, y, w, h;
new Float:pos, Float:px, Float:pw;
set_int(drag_is_down, 1);
get_mouse(mx, my);
get_geometry(PART:"dragover_event", x, y, w, h);
x = mx - x;
y = my - y;
px = x;
pw = w;
if (w > 0) pos = px / pw;
else pos = 0.5;
custom_state(PART:"dragover", "default", 0.0);
set_state_val(PART:"dragover", STATE_REL1, pos, 0.0);
set_state_val(PART:"dragover", STATE_REL2, pos, 0.0);
set_state(PART:"dragover", "custom", 0.0);
send_message(MSG_FLOAT, 10, pos);
}
}
program { name: "dragup";
signal: "mouse,up,1"; source: "dragover_event";
script {
set_int(drag_is_down, 0);
}
}
part { name: "event"; type: RECT; repeat_events: 1; part { name: "event"; type: RECT; repeat_events: 1;
description { state: "default" 0.0; description { state: "default" 0.0;
color: 0 0 0 0; color: 0 0 0 0;

View File

@ -20,7 +20,8 @@ winvid.c winvid.h \
win.c win.h \ win.c win.h \
winlist.c winlist.h \ winlist.c winlist.h \
config.c config.h \ config.c config.h \
sha1.c sha1.h sha1.c sha1.h \
videothumb.c videothumb.h
internal_bindir = $(libdir)/rage/utils internal_bindir = $(libdir)/rage/utils
internal_bin_PROGRAMS = rage_thumb internal_bin_PROGRAMS = rage_thumb

View File

@ -9,8 +9,7 @@ void
key_handle(Evas_Object *win, Evas_Event_Key_Down *ev) key_handle(Evas_Object *win, Evas_Event_Key_Down *ev)
{ {
Inf *inf = evas_object_data_get(win, "inf"); Inf *inf = evas_object_data_get(win, "inf");
printf("%s | %s\n", ev->key, ev->keyname);
if ((!strcmp(ev->key, "Left")) || if ((!strcmp(ev->key, "Left")) ||
(!strcmp(ev->key, "bracketleft"))) (!strcmp(ev->key, "bracketleft")))
{ {
@ -20,7 +19,7 @@ key_handle(Evas_Object *win, Evas_Event_Key_Down *ev)
else else
{ {
double pos = video_position_get(inf->vid); double pos = video_position_get(inf->vid);
if (!inf->last_action_rwind) if (!inf->last_action_rwind)
{ {
double t = ecore_time_get(); double t = ecore_time_get();
@ -161,7 +160,7 @@ key_handle(Evas_Object *win, Evas_Event_Key_Down *ev)
else if (!strcmp(ev->keyname, "n")) else if (!strcmp(ev->keyname, "n"))
{ {
int w, h; int w, h;
video_ratio_size_get(inf->vid, &w, &h); video_ratio_size_get(inf->vid, &w, &h);
if ((w > 1) && (h > 1)) evas_object_resize(win, w, h); if ((w > 1) && (h > 1)) evas_object_resize(win, w, h);
} }

View File

@ -32,7 +32,8 @@ elm_main(int argc, char **argv)
int i; int i;
Inf *inf; Inf *inf;
Config *config; Config *config;
elm_need_efreet();
config_init(); config_init();
config = config_get(); config = config_get();
for (i = 1; i < argc; i++) for (i = 1; i < argc; i++)
@ -62,7 +63,7 @@ elm_main(int argc, char **argv)
else else
list = eina_list_append(list, eina_stringshare_add(argv[i])); list = eina_list_append(list, eina_stringshare_add(argv[i]));
} }
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
elm_app_compile_bin_dir_set(PACKAGE_BIN_DIR); elm_app_compile_bin_dir_set(PACKAGE_BIN_DIR);
elm_app_compile_data_dir_set(PACKAGE_DATA_DIR); elm_app_compile_data_dir_set(PACKAGE_DATA_DIR);
@ -78,11 +79,11 @@ elm_main(int argc, char **argv)
win = win_add(); win = win_add();
evas_object_event_callback_add(win, EVAS_CALLBACK_RESIZE, _cb_resize, NULL); evas_object_event_callback_add(win, EVAS_CALLBACK_RESIZE, _cb_resize, NULL);
evas_object_resize(win, 320, 200); evas_object_resize(win, 320, 200);
win_video_init(win); win_video_init(win);
win_video_file_list_set(win, list); win_video_file_list_set(win, list);
EINA_LIST_FREE(list, f) eina_stringshare_del(f); EINA_LIST_FREE(list, f) eina_stringshare_del(f);
inf = evas_object_data_get(win, "inf"); inf = evas_object_data_get(win, "inf");
if (argc <= 1) if (argc <= 1)
{ {
@ -94,7 +95,7 @@ elm_main(int argc, char **argv)
{ {
inf->show_timeout = ecore_timer_add(10.0, _cb_show_timeout, win); inf->show_timeout = ecore_timer_add(10.0, _cb_show_timeout, win);
} }
elm_run(); elm_run();
config_shutdown(); config_shutdown();

View File

@ -63,7 +63,6 @@ elm_main(int argc, char **argv)
char key[128]; char key[128];
snprintf(key, sizeof(key), "%i", pos); snprintf(key, sizeof(key), "%i", pos);
pos += incr;
evas_object_image_file_set(vidimage, argv[1], key); evas_object_image_file_set(vidimage, argv[1], key);
evas_object_image_size_get(vidimage, &iw, &ih); evas_object_image_size_get(vidimage, &iw, &ih);
if ((iw <= 0) || (ih <= 0)) break; if ((iw <= 0) || (ih <= 0)) break;
@ -75,10 +74,10 @@ elm_main(int argc, char **argv)
elm_win_render(subwin); elm_win_render(subwin);
pixels = evas_object_image_data_get(image, EINA_FALSE); pixels = evas_object_image_data_get(image, EINA_FALSE);
if (pixels) if (pixels)
{ eet_data_image_write(ef, key, pixels, w, h,
eet_data_image_write(ef, key, pixels, w, h, 0, 0, 70, EET_IMAGE_JPEG);
0, 0, 70, EET_IMAGE_JPEG); else
} exit(6);
evas_object_image_data_set(image, pixels); evas_object_image_data_set(image, pixels);
} }
eet_close(ef); eet_close(ef);

View File

@ -472,6 +472,14 @@ video_file_set(Evas_Object *obj, const char *file)
video_position_set(obj, 0.0); video_position_set(obj, 0.0);
} }
const char *
video_file_get(Evas_Object *obj)
{
Video *sd = evas_object_smart_data_get(obj);
if (!sd) return NULL;
return sd->file;
}
void void
video_mute_set(Evas_Object *obj, Eina_Bool mute) video_mute_set(Evas_Object *obj, Eina_Bool mute)
{ {

View File

@ -5,6 +5,7 @@
Evas_Object *video_add(Evas_Object *parent); Evas_Object *video_add(Evas_Object *parent);
void video_file_set(Evas_Object *obj, const char *file); void video_file_set(Evas_Object *obj, const char *file);
const char *video_file_get(Evas_Object *obj);
void video_mute_set(Evas_Object *obj, Eina_Bool mute); void video_mute_set(Evas_Object *obj, Eina_Bool mute);
Eina_Bool video_mute_get(Evas_Object *obj); Eina_Bool video_mute_get(Evas_Object *obj);
void video_play_set(Evas_Object *obj, Eina_Bool play); void video_play_set(Evas_Object *obj, Eina_Bool play);

382
src/bin/videothumb.c Normal file
View File

@ -0,0 +1,382 @@
#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;
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->file, 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->file);
EINA_LIST_FOREACH(vidthumbs, l, o) _thumb_match_update(o, sd->file);
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->file, strlen(sd->file), 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->file, &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->file)) 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->file);
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->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->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;
}

8
src/bin/videothumb.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _VIDEOTHUMB_H__
#define _VIDEOTHUMB_H__ 1
Evas_Object *videothumb_add(Evas_Object *parent);
void videothumb_file_set(Evas_Object *obj, const char *file, double pos);
void videothumb_size_get(Evas_Object *obj, int *w, int *h);
#endif

View File

@ -138,7 +138,7 @@ win_do_next(Evas_Object *win)
{ {
double pos = video_position_get(inf->vid); double pos = video_position_get(inf->vid);
double len = video_length_get(inf->vid); double len = video_length_get(inf->vid);
if ((len - pos) > 5.0) if ((len - pos) > 5.0)
{ {
video_position_set(inf->vid, len - 5.0); video_position_set(inf->vid, len - 5.0);
@ -198,7 +198,7 @@ win_video_prev(Evas_Object *win)
{ {
Inf *inf = evas_object_data_get(win, "inf"); Inf *inf = evas_object_data_get(win, "inf");
Eina_List *l; Eina_List *l;
if (!inf->file_list) return; if (!inf->file_list) return;
if (!inf->file_cur) l = eina_list_last(inf->file_list); if (!inf->file_cur) l = eina_list_last(inf->file_list);
else l = inf->file_cur->prev; else l = inf->file_cur->prev;
@ -213,7 +213,7 @@ win_video_first(Evas_Object *win)
{ {
Inf *inf = evas_object_data_get(win, "inf"); Inf *inf = evas_object_data_get(win, "inf");
Eina_List *l; Eina_List *l;
if (!inf->file_list) return; if (!inf->file_list) return;
l = inf->file_list; l = inf->file_list;
inf->file_cur = l; inf->file_cur = l;
@ -226,7 +226,7 @@ win_video_last(Evas_Object *win)
{ {
Inf *inf = evas_object_data_get(win, "inf"); Inf *inf = evas_object_data_get(win, "inf");
Eina_List *l; Eina_List *l;
if (!inf->file_list) return; if (!inf->file_list) return;
l = eina_list_last(inf->file_list); l = eina_list_last(inf->file_list);
if (!l) return; if (!l) return;
@ -240,7 +240,7 @@ win_video_have_next(Evas_Object *win)
{ {
Inf *inf = evas_object_data_get(win, "inf"); Inf *inf = evas_object_data_get(win, "inf");
Eina_List *l; Eina_List *l;
if (!inf->file_list) return EINA_FALSE; if (!inf->file_list) return EINA_FALSE;
if (!inf->file_cur) return EINA_FALSE; if (!inf->file_cur) return EINA_FALSE;
else l = inf->file_cur->next; else l = inf->file_cur->next;
@ -253,7 +253,7 @@ win_video_have_prev(Evas_Object *win)
{ {
Inf *inf = evas_object_data_get(win, "inf"); Inf *inf = evas_object_data_get(win, "inf");
Eina_List *l; Eina_List *l;
if (!inf->file_list) return EINA_FALSE; if (!inf->file_list) return EINA_FALSE;
if (!inf->file_cur) return EINA_FALSE; if (!inf->file_cur) return EINA_FALSE;
else l = inf->file_cur->prev; else l = inf->file_cur->prev;
@ -269,19 +269,19 @@ win_add(void)
Inf *inf = calloc(1, sizeof(Inf)); Inf *inf = calloc(1, sizeof(Inf));
if (!inf) return NULL; if (!inf) return NULL;
win = elm_win_add(NULL, "Rage", ELM_WIN_BASIC); win = elm_win_add(NULL, "Rage", ELM_WIN_BASIC);
if (!win) return NULL; if (!win) return NULL;
elm_win_title_set(win, "Rage"); elm_win_title_set(win, "Rage");
elm_win_autodel_set(win, EINA_TRUE); elm_win_autodel_set(win, EINA_TRUE);
evas_object_data_set(win, "inf", inf); evas_object_data_set(win, "inf", inf);
evas_object_event_callback_add(win, EVAS_CALLBACK_DEL, _cb_win_del, NULL); evas_object_event_callback_add(win, EVAS_CALLBACK_DEL, _cb_win_del, NULL);
evas_object_smart_callback_add(win, "fullscreen", _cb_fullscreen, NULL); evas_object_smart_callback_add(win, "fullscreen", _cb_fullscreen, NULL);
evas_object_smart_callback_add(win, "unfullscreen", _cb_unfullscreen, NULL); evas_object_smart_callback_add(win, "unfullscreen", _cb_unfullscreen, NULL);
evas_object_smart_callback_add(win, "normal", _cb_unfullscreen, NULL); evas_object_smart_callback_add(win, "normal", _cb_unfullscreen, NULL);
o = evas_object_image_add(evas_object_evas_get(win)); o = evas_object_image_add(evas_object_evas_get(win));
snprintf(buf, sizeof(buf), "%s/images/rage.png", elm_app_data_dir_get()); snprintf(buf, sizeof(buf), "%s/images/rage.png", elm_app_data_dir_get());
evas_object_image_file_set(o, buf, NULL); evas_object_image_file_set(o, buf, NULL);
@ -295,7 +295,7 @@ win_add(void)
evas_object_show(o); evas_object_show(o);
inf->lay = o; inf->lay = o;
controls_init(win, o); controls_init(win, o);
o = evas_object_rectangle_add(evas_object_evas_get(win)); o = evas_object_rectangle_add(evas_object_evas_get(win));
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_win_resize_object_add(win, o); elm_win_resize_object_add(win, o);
@ -334,7 +334,7 @@ win_title_update(Evas_Object *win)
Inf *inf = evas_object_data_get(win, "inf"); Inf *inf = evas_object_data_get(win, "inf");
const char *file, *s; const char *file, *s;
char buf[4096]; char buf[4096];
if (!inf->file_cur) if (!inf->file_cur)
{ {
elm_win_title_set(win, "Rage"); elm_win_title_set(win, "Rage");
@ -393,7 +393,7 @@ win_aspect_adjust(Evas_Object *win)
{ {
Inf *inf = evas_object_data_get(win, "inf"); Inf *inf = evas_object_data_get(win, "inf");
int w = 1, h = 1; int w = 1, h = 1;
video_ratio_size_get(inf->vid, &w, &h); video_ratio_size_get(inf->vid, &w, &h);
if (inf->zoom_mode == 1) if (inf->zoom_mode == 1)
evas_object_size_hint_aspect_set(inf->vid, EVAS_ASPECT_CONTROL_NEITHER, evas_object_size_hint_aspect_set(inf->vid, EVAS_ASPECT_CONTROL_NEITHER,
@ -415,6 +415,6 @@ void
win_frame_decode(Evas_Object *win) win_frame_decode(Evas_Object *win)
{ {
Inf *inf = evas_object_data_get(win, "inf"); Inf *inf = evas_object_data_get(win, "inf");
controls_update(inf->lay, inf->vid); controls_update(inf->lay, inf->vid);
} }

View File

@ -5,7 +5,7 @@ typedef struct _Inf Inf;
struct _Inf struct _Inf
{ {
Evas_Object *vid, *lay, *event, *event2, *glayer; Evas_Object *vid, *lay, *event, *event2, *glayer, *vidthumb;
Eina_List *file_list, *file_cur; Eina_List *file_list, *file_cur;
Ecore_Job *next_job; Ecore_Job *next_job;
Ecore_Timer *show_timeout; Ecore_Timer *show_timeout;

View File

@ -4,6 +4,7 @@
#include "video.h" #include "video.h"
#include "winlist.h" #include "winlist.h"
#include "winvid.h" #include "winvid.h"
#include "videothumb.h"
static void static void
_cb_resize(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) _cb_resize(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
@ -30,7 +31,6 @@ static void
_cb_stop(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) _cb_stop(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
{ {
Inf *inf = evas_object_data_get(data, "inf"); Inf *inf = evas_object_data_get(data, "inf");
printf("stop\n");
if (win_video_have_next(data)) if (win_video_have_next(data))
{ {
if (inf->next_job) ecore_job_del(inf->next_job); if (inf->next_job) ecore_job_del(inf->next_job);
@ -42,7 +42,6 @@ _cb_stop(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
static void static void
_cb_opened(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) _cb_opened(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
{ {
printf("opened\n");
win_aspect_adjust(data); win_aspect_adjust(data);
win_frame_decode(data); win_frame_decode(data);
win_title_update(data); win_title_update(data);
@ -51,7 +50,6 @@ _cb_opened(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
static void static void
_cb_length(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) _cb_length(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
{ {
printf("len\n");
win_frame_decode(data); win_frame_decode(data);
win_title_update(data); win_title_update(data);
} }
@ -59,21 +57,18 @@ _cb_length(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
static void static void
_cb_title(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) _cb_title(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
{ {
printf("title\n");
win_title_update(data); win_title_update(data);
} }
static void static void
_cb_audio(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) _cb_audio(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
{ {
printf("audio\n");
win_title_update(data); win_title_update(data);
} }
static void static void
_cb_channels(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) _cb_channels(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
{ {
printf("channels\n");
win_title_update(data); win_title_update(data);
} }
@ -81,7 +76,6 @@ static void
_cb_play_start(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) _cb_play_start(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
{ {
Inf *inf = evas_object_data_get(data, "inf"); Inf *inf = evas_object_data_get(data, "inf");
printf("play start\n");
win_aspect_adjust(data); win_aspect_adjust(data);
win_frame_decode(data); win_frame_decode(data);
win_title_update(data); win_title_update(data);
@ -92,7 +86,6 @@ static void
_cb_play_finish(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) _cb_play_finish(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
{ {
Inf *inf = evas_object_data_get(data, "inf"); Inf *inf = evas_object_data_get(data, "inf");
printf("play finish\n");
if (!inf->playing) win_show(data, 160, 160); if (!inf->playing) win_show(data, 160, 160);
inf->playing = EINA_FALSE; inf->playing = EINA_FALSE;
} }
@ -100,23 +93,75 @@ _cb_play_finish(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSE
static void static void
_cb_button_num(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) _cb_button_num(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
{ {
printf("button num\n");
win_title_update(data); win_title_update(data);
} }
static void static void
_cb_button(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) _cb_button(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
{ {
printf("button\n");
win_title_update(data); win_title_update(data);
} }
static void
_cb_vidthumb_loaded(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
{
Inf *inf = evas_object_data_get(data, "inf");
if (!inf) return;
}
static void
_cb_vidthumb_failed(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
{
Inf *inf = evas_object_data_get(data, "inf");
if (!inf) return;
}
static void
_cb_vidthumb_data(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
{
int w, h;
Inf *inf = evas_object_data_get(data, "inf");
if (!inf) return;
videothumb_size_get(inf->vidthumb, &w, &h);
w = ((double)w * elm_config_scale_get()) / 2.0;
h = ((double)h * elm_config_scale_get()) / 2.0;
evas_object_size_hint_min_set(inf->vidthumb, w, h);
}
static void
_cb_layout_message(void *data, Evas_Object *obj EINA_UNUSED, Edje_Message_Type type, int id, void *msg)
{
Inf *inf = evas_object_data_get(data, "inf");
if (!inf) return;
if (type == EDJE_MESSAGE_FLOAT)
{
if (id == 10)
{
Edje_Message_Float *m = msg;
double len = video_length_get(inf->vid);
video_position_set(inf->vid, len * m->val);
}
else if (id == 13)
{
Edje_Message_Float *m = msg;
double len = video_length_get(inf->vid);
videothumb_file_set(inf->vidthumb, video_file_get(inf->vid),
len * m->val);
}
}
}
void void
win_video_init(Evas_Object *win) win_video_init(Evas_Object *win)
{ {
Inf *inf = evas_object_data_get(win, "inf"); Inf *inf = evas_object_data_get(win, "inf");
Evas_Object *o; Evas_Object *o;
Evas_Coord sz;
o = video_add(win); o = video_add(win);
video_fill_set(o, EINA_TRUE); video_fill_set(o, EINA_TRUE);
inf->vid = o; inf->vid = o;
@ -134,6 +179,19 @@ win_video_init(Evas_Object *win)
evas_object_smart_callback_add(o, "button", _cb_button, win); evas_object_smart_callback_add(o, "button", _cb_button, win);
elm_object_part_content_set(inf->lay, "rage.content", o); elm_object_part_content_set(inf->lay, "rage.content", o);
evas_object_show(o); evas_object_show(o);
o = videothumb_add(win);
inf->vidthumb = o;
evas_object_smart_callback_add(o, "loaded", _cb_vidthumb_loaded, win);
evas_object_smart_callback_add(o, "failed", _cb_vidthumb_failed, win);
evas_object_smart_callback_add(o, "data", _cb_vidthumb_data, win);
sz = 80;
sz = (double)sz * elm_config_scale_get();
evas_object_size_hint_min_set(o, sz, sz);
elm_object_part_content_set(inf->lay, "rage.dragable.content", o);
evas_object_show(o);
edje_object_message_handler_set(elm_layout_edje_get(inf->lay),
_cb_layout_message, win);
} }
void void
@ -142,7 +200,7 @@ win_video_file_list_set(Evas_Object *win, Eina_List *list)
Inf *inf = evas_object_data_get(win, "inf"); Inf *inf = evas_object_data_get(win, "inf");
Eina_List *l, *list2 = NULL; Eina_List *l, *list2 = NULL;
const char *f; const char *f;
EINA_LIST_FOREACH(list, l, f) EINA_LIST_FOREACH(list, l, f)
{ {
list2 = eina_list_append(list2, eina_stringshare_add(f)); list2 = eina_list_append(list2, eina_stringshare_add(f));
@ -155,7 +213,7 @@ void
win_video_insert(Evas_Object *win, const char *file) win_video_insert(Evas_Object *win, const char *file)
{ {
Inf *inf = evas_object_data_get(win, "inf"); Inf *inf = evas_object_data_get(win, "inf");
inf->file_list = eina_list_append_relative_list inf->file_list = eina_list_append_relative_list
(inf->file_list, eina_stringshare_add(file), inf->file_cur); (inf->file_list, eina_stringshare_add(file), inf->file_cur);
evas_object_data_set(win, "file_list", inf->file_list); evas_object_data_set(win, "file_list", inf->file_list);