emotion: cleanup emotion async loader on file set.
[profile/ivi/emotion.git] / src / lib / emotion_smart.c
1 #include "emotion_private.h"
2 #include "Emotion.h"
3
4 #ifdef HAVE_EIO
5 # include <math.h>
6 # include <Eio.h>
7 #else
8 # ifdef HAVE_XATTR
9 #  include <math.h>
10 #  include <sys/xattr.h>
11 # endif
12 #endif
13
14 #define E_SMART_OBJ_GET(smart, o, type) \
15      { \
16         char *_e_smart_str; \
17         \
18         if (!o) return; \
19         smart = evas_object_smart_data_get(o); \
20         if (!smart) return; \
21         _e_smart_str = (char *)evas_object_type_get(o); \
22         if (!_e_smart_str) return; \
23         if (strcmp(_e_smart_str, type)) return; \
24      }
25
26 #define E_SMART_OBJ_GET_RETURN(smart, o, type, ret) \
27    { \
28       char *_e_smart_str; \
29       \
30       if (!o) return ret; \
31       smart = evas_object_smart_data_get(o); \
32       if (!smart) return ret; \
33       _e_smart_str = (char *)evas_object_type_get(o); \
34       if (!_e_smart_str) return ret; \
35       if (strcmp(_e_smart_str, type)) return ret; \
36    }
37
38 #define DBG(...) EINA_LOG_DOM_DBG(_log_domain, __VA_ARGS__)
39 #define INF(...) EINA_LOG_DOM_INFO(_log_domain, __VA_ARGS__)
40 #define WRN(...) EINA_LOG_DOM_WARN(_log_domain, __VA_ARGS__)
41 #define ERR(...) EINA_LOG_DOM_ERR(_log_domain, __VA_ARGS__)
42 #define CRITICAL(...) EINA_LOG_DOM_CRIT(_log_domain, __VA_ARGS__)
43
44 #define E_OBJ_NAME "emotion_object"
45
46 typedef struct _Smart_Data Smart_Data;
47
48 struct _Smart_Data
49 {
50    EINA_REFCOUNT;
51    Emotion_Video_Module  *module;
52    void                  *video;
53
54    char                  *module_name;
55
56    const char    *file;
57    Evas_Object   *obj;
58    double         ratio;
59    double         pos;
60    double         seek_pos;
61    double         len;
62
63    Ecore_Job     *job;
64
65    unsigned char  play : 1;
66    unsigned char  seek : 1;
67    unsigned char  seeking : 1;
68
69    char *title;
70    struct {
71       char   *info;
72       double  stat;
73    } progress;
74    struct {
75       char *file;
76       int   num;
77    } ref;
78    struct {
79       int button_num;
80       int button;
81    } spu;
82
83 #ifdef HAVE_EIO
84    Eio_File *load_xattr;
85    Eio_File *save_xattr;
86
87    const char *time_seek;
88 #endif
89
90    Emotion_Module_Options module_options;
91 };
92
93 static void _mouse_move(void *data, Evas *ev, Evas_Object *obj, void *event_info);
94 static void _mouse_down(void *data, Evas *ev, Evas_Object *obj, void *event_info);
95 static void _pos_set_job(void *data);
96 static void _pixels_get(void *data, Evas_Object *obj);
97
98 static void _smart_init(void);
99 static void _smart_add(Evas_Object * obj);
100 static void _smart_del(Evas_Object * obj);
101 static void _smart_move(Evas_Object * obj, Evas_Coord x, Evas_Coord y);
102 static void _smart_resize(Evas_Object * obj, Evas_Coord w, Evas_Coord h);
103 static void _smart_show(Evas_Object * obj);
104 static void _smart_hide(Evas_Object * obj);
105 static void _smart_color_set(Evas_Object * obj, int r, int g, int b, int a);
106 static void _smart_clip_set(Evas_Object * obj, Evas_Object * clip);
107 static void _smart_clip_unset(Evas_Object * obj);
108
109 /**********************************/
110 /* Globals for the E Video Object */
111 /**********************************/
112 static Evas_Smart  *smart = NULL;
113 static Eina_Hash *_backends = NULL;
114 static Eina_Array *_modules = NULL;
115 static int _log_domain = -1;
116
117 static const char *_backend_priority[] = {
118   "xine",
119   "gstreamer",
120   "vlc"
121 };
122
123 static const char SIG_FRAME_DECODE[] = "frame_decode";
124 static const char SIG_POSITION_UPDATE[] = "position_update";
125 static const char SIG_LENGTH_CHANGE[] = "length_change";
126 static const char SIG_FRAME_RESIZE[] = "frame_resize";
127 static const char SIG_DECODE_STOP[] = "decode_stop";
128 static const char SIG_PLAYBACK_STARTED[] = "playback_started";
129 static const char SIG_PLAYBACK_FINISHED[] = "playback_finished";
130 static const char SIG_AUDIO_LEVEL_CHANGE[] = "audio_level_change";
131 static const char SIG_CHANNELS_CHANGE[] = "channels_change";
132 static const char SIG_TITLE_CHANGE[] = "title_change";
133 static const char SIG_PROGRESS_CHANGE[] = "progress_change";
134 static const char SIG_REF_CHANGE[] = "ref_change";
135 static const char SIG_BUTTON_NUM_CHANGE[] = "button_num_change";
136 static const char SIG_BUTTON_CHANGE[] = "button_change";
137 static const char SIG_OPEN_DONE[] = "open_done";
138 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
139   {SIG_FRAME_DECODE, ""},
140   {SIG_POSITION_UPDATE, ""},
141   {SIG_LENGTH_CHANGE, ""},
142   {SIG_FRAME_RESIZE, ""},
143   {SIG_DECODE_STOP, ""},
144   {SIG_PLAYBACK_STARTED, ""},
145   {SIG_PLAYBACK_FINISHED, ""},
146   {SIG_AUDIO_LEVEL_CHANGE, ""},
147   {SIG_CHANNELS_CHANGE, ""},
148   {SIG_TITLE_CHANGE, ""},
149   {SIG_PROGRESS_CHANGE, ""},
150   {SIG_REF_CHANGE, ""},
151   {SIG_BUTTON_NUM_CHANGE, ""},
152   {SIG_BUTTON_CHANGE, ""},
153   {SIG_OPEN_DONE, ""},
154   {NULL, NULL}
155 };
156
157 static void
158 _emotion_image_data_zero(Evas_Object *img)
159 {
160    void *data;
161    
162    data = evas_object_image_data_get(img, 1);
163    if (data)
164      {
165         int w, h, sz = 0;
166         Evas_Colorspace cs;
167         
168         evas_object_image_size_get(img, &w, &h);
169         cs = evas_object_image_colorspace_get(img);
170         if (cs == EVAS_COLORSPACE_ARGB8888)
171            sz = w * h * 4;
172         if ((cs == EVAS_COLORSPACE_YCBCR422P601_PL) ||
173             (cs == EVAS_COLORSPACE_YCBCR422P709_PL))
174            sz = h * 2 * sizeof(unsigned char *);
175         if (sz != 0) memset(data, 0, sz);
176      }
177    evas_object_image_data_set(img, data);
178 }
179
180 static void
181 _emotion_module_close(Emotion_Video_Module *mod, void *video)
182 {
183    if (!mod) return;
184    if (mod->plugin->close && video)
185      mod->plugin->close(mod, video);
186    /* FIXME: we can't go dlclosing here as a thread still may be running from
187     * the module - this in theory will leak- but it shouldnt be too bad and
188     * mean that once a module is dlopened() it cant be closed - its refcount
189     * will just keep going up
190     */
191 }
192
193 static void
194 _smart_data_free(Smart_Data *sd)
195 {
196    if (sd->video) sd->module->file_close(sd->video);
197    _emotion_module_close(sd->module, sd->video);
198    evas_object_del(sd->obj);
199    eina_stringshare_del(sd->file);
200    free(sd->module_name);
201    if (sd->job) ecore_job_del(sd->job);
202    free(sd->progress.info);
203    free(sd->ref.file);
204    free(sd);
205
206    ecore_shutdown();
207 }
208
209 EAPI Eina_Bool
210 _emotion_module_register(const char *name, Emotion_Module_Open mod_open, Emotion_Module_Close mod_close)
211 {
212    Eina_Emotion_Plugins *plugin;
213
214    plugin = malloc(sizeof (Eina_Emotion_Plugins));
215    if (!plugin) return EINA_FALSE;
216
217    plugin->open = mod_open;
218    plugin->close = mod_close;
219
220    return eina_hash_add(_backends, name, plugin);
221 }
222
223 EAPI Eina_Bool
224 _emotion_module_unregister(const char *name)
225 {
226    return eina_hash_del(_backends, name, NULL);
227 }
228
229 static const char *
230 _emotion_module_open(const char *name, Evas_Object *obj, Emotion_Video_Module **mod, void **video)
231 {
232    Eina_Emotion_Plugins *plugin;
233    Smart_Data *sd;
234    unsigned int i = 0;
235
236    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
237    if (!_backends)
238      {
239         ERR("No backend loaded");
240         return NULL;
241      }
242
243    if (!name && getenv("EMOTION_ENGINE"))
244      name = getenv("EMOTION_ENGINE");
245
246    /* FIXME: Always look for a working backend. */
247  retry:
248    if (!name || i > 0)
249      name = _backend_priority[i++];
250
251    plugin = eina_hash_find(_backends, name);
252    if (!plugin)
253      {
254         if (i != 0 && i < (sizeof (_backend_priority) / sizeof (char*)))
255           goto retry;
256
257         ERR("No backend loaded");
258         return EINA_FALSE;
259      }
260
261    if (plugin->open(obj, (const Emotion_Video_Module **) mod, video, &(sd->module_options)))
262      {
263         if (*mod)
264           {
265              (*mod)->plugin = plugin;
266              return name;
267           }
268      }
269
270    if (i != 0 && i < (sizeof (_backend_priority) / sizeof (char*)))
271      goto retry;
272
273    ERR("Unable to load module: %s", name);
274
275    return NULL;
276 }
277
278 /*******************************/
279 /* Externally accessible calls */
280 /*******************************/
281
282
283
284 EAPI Evas_Object *
285 emotion_object_add(Evas *evas)
286 {
287    _smart_init();
288    return evas_object_smart_add(evas, smart);
289 }
290
291 EAPI void
292 emotion_object_module_option_set(Evas_Object *obj, const char *opt, const char *val)
293 {
294    Smart_Data *sd;
295
296    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
297    if ((!opt) || (!val)) return;
298    if (!strcmp(opt, "video"))
299      {
300         if (!strcmp(val, "off")) sd->module_options.no_video = EINA_TRUE;
301      }
302    else if (!strcmp(opt, "audio"))
303      {
304         if (!strcmp(val, "off")) sd->module_options.no_audio = EINA_TRUE;
305      }
306 }
307
308 EAPI Eina_Bool
309 emotion_object_init(Evas_Object *obj, const char *module_filename)
310 {
311    Smart_Data *sd;
312    const char *file;
313
314    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
315
316    if ((sd->module_name) && module_filename && (!strcmp(sd->module_name, module_filename)))
317      return EINA_TRUE;
318    free(sd->module_name);
319    sd->module_name = NULL;
320
321    file = sd->file;
322    sd->file = NULL;
323
324    free(sd->title);
325    sd->title = NULL;
326    free(sd->progress.info);
327    sd->progress.info = NULL;
328    sd->progress.stat = 0.0;
329    free(sd->ref.file);
330    sd->ref.file = NULL;
331    sd->ref.num = 0;
332    sd->spu.button_num = 0;
333    sd->spu.button = -1;
334    sd->ratio = 1.0;
335    sd->pos = 0;
336    sd->seek_pos = 0;
337    sd->len = 0;
338
339    _emotion_module_close(sd->module, sd->video);
340    sd->module = NULL;
341    sd->video = NULL;
342
343    module_filename = _emotion_module_open(module_filename, obj, &sd->module, &sd->video);
344    if (!module_filename)
345      return EINA_FALSE;
346
347    sd->module_name = strdup(module_filename);
348
349    if (file)
350      {
351         emotion_object_file_set(obj, file);
352         eina_stringshare_del(file);
353      }
354
355    return EINA_TRUE;
356 }
357
358 EAPI Eina_Bool
359 emotion_object_file_set(Evas_Object *obj, const char *file)
360 {
361    Smart_Data *sd;
362
363    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, EINA_FALSE);
364
365    DBG("file=%s", file);
366    if (!sd->module) return EINA_FALSE;
367
368    if ((file) && (sd->file) && (file == sd->file || !strcmp(file, sd->file))) return EINA_FALSE;
369    if ((file) && (file[0] != 0))
370      {
371         int w, h;
372
373         eina_stringshare_replace(&sd->file, file);
374         sd->module->file_close(sd->video);
375         evas_object_image_data_set(sd->obj, NULL);
376         evas_object_image_size_set(sd->obj, 1, 1);
377         if (!sd->module->file_open(sd->file, obj, sd->video))
378           return EINA_FALSE;
379         sd->module->size_get(sd->video, &w, &h);
380         evas_object_image_size_set(sd->obj, w, h);
381         _emotion_image_data_zero(sd->obj);
382         sd->ratio = sd->module->ratio_get(sd->video);
383         sd->pos = 0.0;
384         if (sd->play) sd->module->play(sd->video, 0.0);
385      }
386    else
387      {
388         if (sd->video && sd->module)
389           {
390              sd->module->file_close(sd->video);
391              evas_object_image_data_set(sd->obj, NULL);
392              evas_object_image_size_set(sd->obj, 1, 1);
393              _emotion_image_data_zero(sd->obj);
394           }
395         eina_stringshare_replace(&sd->file, NULL);
396      }
397
398 #ifdef HAVE_EIO
399    /* Only cancel the load_xattr or we will loose ref to time_seek stringshare */
400    if (sd->load_xattr) eio_file_cancel(sd->load_xattr);
401    sd->load_xattr = NULL;
402 #endif
403
404    return EINA_TRUE;
405 }
406
407 EAPI const char *
408 emotion_object_file_get(const Evas_Object *obj)
409 {
410    Smart_Data *sd;
411
412    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, NULL);
413    return sd->file;
414 }
415
416 EAPI void
417 emotion_object_play_set(Evas_Object *obj, Eina_Bool play)
418 {
419    Smart_Data *sd;
420
421    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
422    DBG("play=%hhu, was=%hhu", play, sd->play);
423    if (play == sd->play) return;
424    if (!sd->module) return;
425    if (!sd->video) return;
426    sd->play = play;
427    if (sd->play) sd->module->play(sd->video, sd->pos);
428    else sd->module->stop(sd->video);
429 }
430
431 EAPI Eina_Bool
432 emotion_object_play_get(const Evas_Object *obj)
433 {
434    Smart_Data *sd;
435
436    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
437    if (!sd->video) return EINA_FALSE;
438
439    return sd->play;
440 }
441
442 EAPI void
443 emotion_object_position_set(Evas_Object *obj, double sec)
444 {
445    Smart_Data *sd;
446
447    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
448    DBG("sec=%f", sec);
449    if (!sd->module) return;
450    if (!sd->video) return;
451    sd->seek_pos = sec;
452    sd->seek = 1;
453    sd->pos = sd->seek_pos;
454    if (sd->job) ecore_job_del(sd->job);
455    sd->job = ecore_job_add(_pos_set_job, obj);
456 }
457
458 EAPI double
459 emotion_object_position_get(const Evas_Object *obj)
460 {
461    Smart_Data *sd;
462
463    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0.0);
464    if (!sd->module) return 0.0;
465    if (!sd->video) return 0.0;
466    if (!sd->module->pos_get) return 0.0;
467    sd->pos = sd->module->pos_get(sd->video);
468    return sd->pos;
469 }
470
471 EAPI Eina_Bool
472 emotion_object_seekable_get(const Evas_Object *obj)
473 {
474    Smart_Data *sd;
475
476    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
477    if (!sd->module) return EINA_FALSE;
478    if (!sd->video) return EINA_FALSE;
479    return sd->module->seekable(sd->video);
480 }
481
482 EAPI Eina_Bool
483 emotion_object_video_handled_get(const Evas_Object *obj)
484 {
485    Smart_Data *sd;
486
487    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
488    if (!sd->module) return EINA_FALSE;
489    if (!sd->video) return EINA_FALSE;
490    return sd->module->video_handled(sd->video);
491 }
492
493 EAPI Eina_Bool
494 emotion_object_audio_handled_get(const Evas_Object *obj)
495 {
496    Smart_Data *sd;
497
498    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
499    if (!sd->module) return EINA_FALSE;
500    if (!sd->video) return EINA_FALSE;
501    return sd->module->audio_handled(sd->video);
502 }
503
504 EAPI double
505 emotion_object_play_length_get(const Evas_Object *obj)
506 {
507    Smart_Data *sd;
508
509    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0.0);
510    if (!sd->module) return 0.0;
511    if (!sd->video) return 0.0;
512    sd->len = sd->module->len_get(sd->video);
513    return sd->len;
514 }
515
516 EAPI void
517 emotion_object_size_get(const Evas_Object *obj, int *iw, int *ih)
518 {
519    Smart_Data *sd;
520
521    if (iw) *iw = 0;
522    if (ih) *ih = 0;
523    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
524    evas_object_image_size_get(sd->obj, iw, ih);
525 }
526
527 /**
528  * Sets whether to use of high-quality image scaling algorithm
529  * of the given video object.
530  *
531  * When enabled, a higher quality video scaling algorithm is used when
532  * scaling videos to sizes other than the source video. This gives
533  * better results but is more computationally expensive.
534  *
535  * @param obj The given video object.
536  * @param smooth Whether to use smooth scale or not.
537  */
538 EAPI void
539 emotion_object_smooth_scale_set(Evas_Object *obj, Eina_Bool smooth)
540 {
541    Smart_Data *sd;
542
543    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
544    evas_object_image_smooth_scale_set(sd->obj, smooth);
545 }
546
547 /**
548  * Gets whether the high-quality image scaling algorithm
549  * of the given video object is used.
550  *
551  * @return Whether the smooth scale is used or not.
552  */
553 EAPI Eina_Bool
554 emotion_object_smooth_scale_get(const Evas_Object *obj)
555 {
556    Smart_Data *sd;
557
558    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
559    return evas_object_image_smooth_scale_get(sd->obj);
560 }
561
562 EAPI double
563 emotion_object_ratio_get(const Evas_Object *obj)
564 {
565    Smart_Data *sd;
566
567    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 1.0);
568    if (!sd->module) return 0.0;
569    if (!sd->video) return 0.0;
570    return sd->ratio;
571 }
572
573 /**
574  * Send a control event to the DVD.
575  */
576 EAPI void
577 emotion_object_event_simple_send(Evas_Object *obj, Emotion_Event ev)
578 {
579    Smart_Data *sd;
580
581    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
582    if (!sd->module) return;
583    if (!sd->video) return;
584    sd->module->event_feed(sd->video, ev);
585 }
586
587 EAPI void
588 emotion_object_audio_volume_set(Evas_Object *obj, double vol)
589 {
590    Smart_Data *sd;
591
592    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
593    DBG("vol=%f", vol);
594    if (!sd->module) return;
595    if (!sd->video) return;
596    sd->module->audio_channel_volume_set(sd->video, vol);
597 }
598
599 EAPI double
600 emotion_object_audio_volume_get(const Evas_Object *obj)
601 {
602    Smart_Data *sd;
603
604    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 1.0);
605    if (!sd->module) return 0.0;
606    if (!sd->video) return 0.0;
607    return sd->module->audio_channel_volume_get(sd->video);
608 }
609
610 EAPI void
611 emotion_object_audio_mute_set(Evas_Object *obj, Eina_Bool mute)
612 {
613    Smart_Data *sd;
614
615    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
616    DBG("mute=%hhu", mute);
617    if (!sd->module) return;
618    if (!sd->video) return;
619    sd->module->audio_channel_mute_set(sd->video, mute);
620 }
621
622 EAPI Eina_Bool
623 emotion_object_audio_mute_get(const Evas_Object *obj)
624 {
625    Smart_Data *sd;
626
627    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
628    if (!sd->module) return EINA_FALSE;
629    if (!sd->video) return EINA_FALSE;
630    return sd->module->audio_channel_mute_get(sd->video);
631 }
632
633 EAPI int
634 emotion_object_audio_channel_count(const Evas_Object *obj)
635 {
636    Smart_Data *sd;
637
638    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
639    if (!sd->module) return 0;
640    if (!sd->video) return 0;
641    return sd->module->audio_channel_count(sd->video);
642 }
643
644 EAPI const char *
645 emotion_object_audio_channel_name_get(const Evas_Object *obj, int channel)
646 {
647    Smart_Data *sd;
648
649    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, NULL);
650    if (!sd->module) return NULL;
651    if (!sd->video) return NULL;
652    return sd->module->audio_channel_name_get(sd->video, channel);
653 }
654
655 EAPI void
656 emotion_object_audio_channel_set(Evas_Object *obj, int channel)
657 {
658    Smart_Data *sd;
659
660    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
661    DBG("channel=%d", channel);
662    if (!sd->module) return;
663    if (!sd->video) return;
664    sd->module->audio_channel_set(sd->video, channel);
665 }
666
667 EAPI int
668 emotion_object_audio_channel_get(const Evas_Object *obj)
669 {
670    Smart_Data *sd;
671
672    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
673    if (!sd->module) return 0;
674    if (!sd->video) return 0;
675    return sd->module->audio_channel_get(sd->video);
676 }
677
678 EAPI void
679 emotion_object_video_mute_set(Evas_Object *obj, Eina_Bool mute)
680 {
681    Smart_Data *sd;
682
683    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
684    DBG("mute=%hhu", mute);
685    if (!sd->module) return;
686    if (!sd->video) return;
687    sd->module->video_channel_mute_set(sd->video, mute);
688 }
689
690 EAPI Eina_Bool
691 emotion_object_video_mute_get(const Evas_Object *obj)
692 {
693    Smart_Data *sd;
694
695    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
696    if (!sd->module) return EINA_FALSE;
697    if (!sd->video) return EINA_FALSE;
698    return sd->module->video_channel_mute_get(sd->video);
699 }
700
701 EAPI int
702 emotion_object_video_channel_count(const Evas_Object *obj)
703 {
704    Smart_Data *sd;
705
706    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
707    if (!sd->module) return EINA_FALSE;
708    if (!sd->video) return EINA_FALSE;
709    return sd->module->video_channel_count(sd->video);
710 }
711
712 EAPI const char *
713 emotion_object_video_channel_name_get(const Evas_Object *obj, int channel)
714 {
715    Smart_Data *sd;
716
717    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, NULL);
718    if (!sd->module) return NULL;
719    if (!sd->video) return NULL;
720    return sd->module->video_channel_name_get(sd->video, channel);
721 }
722
723 EAPI void
724 emotion_object_video_channel_set(Evas_Object *obj, int channel)
725 {
726    Smart_Data *sd;
727
728    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
729    DBG("channel=%d", channel);
730    if (!sd->module) return;
731    if (!sd->video) return;
732    sd->module->video_channel_set(sd->video, channel);
733 }
734
735 EAPI int
736 emotion_object_video_channel_get(const Evas_Object *obj)
737 {
738    Smart_Data *sd;
739
740    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
741    if (!sd->module) return 0;
742    if (!sd->video) return 0;
743    return sd->module->video_channel_get(sd->video);
744 }
745
746 EAPI void
747 emotion_object_spu_mute_set(Evas_Object *obj, Eina_Bool mute)
748 {
749    Smart_Data *sd;
750
751    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
752    DBG("mute=%hhu", mute);
753    if (!sd->module) return;
754    if (!sd->video) return;
755    sd->module->spu_channel_mute_set(sd->video, mute);
756 }
757
758 EAPI Eina_Bool
759 emotion_object_spu_mute_get(const Evas_Object *obj)
760 {
761    Smart_Data *sd;
762
763    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
764    if (!sd->module) return EINA_FALSE;
765    if (!sd->video) return EINA_FALSE;
766    return sd->module->spu_channel_mute_get(sd->video);
767 }
768
769 EAPI int
770 emotion_object_spu_channel_count(const Evas_Object *obj)
771 {
772    Smart_Data *sd;
773
774    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
775    if (!sd->module) return 0;
776    if (!sd->video) return 0;
777    return sd->module->spu_channel_count(sd->video);
778 }
779
780 EAPI const char *
781 emotion_object_spu_channel_name_get(const Evas_Object *obj, int channel)
782 {
783    Smart_Data *sd;
784
785    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, NULL);
786    if (!sd->module) return NULL;
787    if (!sd->video) return NULL;
788    return sd->module->spu_channel_name_get(sd->video, channel);
789 }
790
791 EAPI void
792 emotion_object_spu_channel_set(Evas_Object *obj, int channel)
793 {
794    Smart_Data *sd;
795
796    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
797    DBG("channel=%d", channel);
798    if (!sd->module) return;
799    if (!sd->video) return;
800    sd->module->spu_channel_set(sd->video, channel);
801 }
802
803 EAPI int
804 emotion_object_spu_channel_get(const Evas_Object *obj)
805 {
806    Smart_Data *sd;
807
808    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
809    if (!sd->module) return 0;
810    if (!sd->video) return 0;
811    return sd->module->spu_channel_get(sd->video);
812 }
813
814 EAPI int
815 emotion_object_chapter_count(const Evas_Object *obj)
816 {
817    Smart_Data *sd;
818
819    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
820    if (!sd->module) return 0;
821    if (!sd->video) return 0;
822    return sd->module->chapter_count(sd->video);
823 }
824
825 EAPI void
826 emotion_object_chapter_set(Evas_Object *obj, int chapter)
827 {
828    Smart_Data *sd;
829
830    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
831    DBG("chapter=%d", chapter);
832    if (!sd->module) return;
833    if (!sd->video) return;
834    sd->module->chapter_set(sd->video, chapter);
835 }
836
837 EAPI int
838 emotion_object_chapter_get(const Evas_Object *obj)
839 {
840    Smart_Data *sd;
841
842    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
843    if (!sd->module) return 0;
844    if (!sd->video) return 0;
845    return sd->module->chapter_get(sd->video);
846 }
847
848 EAPI const char *
849 emotion_object_chapter_name_get(const Evas_Object *obj, int chapter)
850 {
851    Smart_Data *sd;
852
853    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, NULL);
854    if (!sd->module) return NULL;
855    if (!sd->video) return NULL;
856    return sd->module->chapter_name_get(sd->video, chapter);
857 }
858
859 EAPI void
860 emotion_object_play_speed_set(Evas_Object *obj, double speed)
861 {
862    Smart_Data *sd;
863
864    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
865    DBG("speed=%f", speed);
866    if (!sd->module) return;
867    if (!sd->video) return;
868    sd->module->speed_set(sd->video, speed);
869 }
870
871 EAPI double
872 emotion_object_play_speed_get(const Evas_Object *obj)
873 {
874    Smart_Data *sd;
875
876    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0.0);
877    if (!sd->module) return 0.0;
878    if (!sd->video) return 0.0;
879    return sd->module->speed_get(sd->video);
880 }
881
882 EAPI void
883 emotion_object_eject(Evas_Object *obj)
884 {
885    Smart_Data *sd;
886
887    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
888    if (!sd->module) return;
889    if (!sd->video) return;
890    sd->module->eject(sd->video);
891 }
892
893 EAPI const char *
894 emotion_object_title_get(const Evas_Object *obj)
895 {
896    Smart_Data *sd;
897
898    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, NULL);
899    return sd->title;
900 }
901
902 EAPI const char *
903 emotion_object_progress_info_get(const Evas_Object *obj)
904 {
905    Smart_Data *sd;
906
907    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, NULL);
908    return sd->progress.info;
909 }
910
911 EAPI double
912 emotion_object_progress_status_get(const Evas_Object *obj)
913 {
914    Smart_Data *sd;
915
916    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0.0);
917    return sd->progress.stat;
918 }
919
920 EAPI const char *
921 emotion_object_ref_file_get(const Evas_Object *obj)
922 {
923    Smart_Data *sd;
924
925    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, NULL);
926    return sd->ref.file;
927 }
928
929 EAPI int
930 emotion_object_ref_num_get(const Evas_Object *obj)
931 {
932    Smart_Data *sd;
933
934    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
935    return sd->ref.num;
936 }
937
938 EAPI int
939 emotion_object_spu_button_count_get(const Evas_Object *obj)
940 {
941    Smart_Data *sd;
942
943    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
944    return sd->spu.button_num;
945 }
946
947 EAPI int
948 emotion_object_spu_button_get(const Evas_Object *obj)
949 {
950    Smart_Data *sd;
951
952    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
953    return sd->spu.button;
954 }
955
956 EAPI const char *
957 emotion_object_meta_info_get(const Evas_Object *obj, Emotion_Meta_Info meta)
958 {
959    Smart_Data *sd;
960
961    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, NULL);
962    if (!sd->module) return NULL;
963    if (!sd->video) return NULL;
964    switch (meta)
965      {
966       case EMOTION_META_INFO_TRACK_TITLE:
967         return sd->module->meta_get(sd->video, META_TRACK_TITLE);
968         break;
969       case EMOTION_META_INFO_TRACK_ARTIST:
970         return sd->module->meta_get(sd->video, META_TRACK_ARTIST);
971         break;
972       case EMOTION_META_INFO_TRACK_ALBUM:
973         return sd->module->meta_get(sd->video, META_TRACK_ALBUM);
974         break;
975       case EMOTION_META_INFO_TRACK_YEAR:
976         return sd->module->meta_get(sd->video, META_TRACK_YEAR);
977         break;
978       case EMOTION_META_INFO_TRACK_GENRE:
979         return sd->module->meta_get(sd->video, META_TRACK_GENRE);
980         break;
981       case EMOTION_META_INFO_TRACK_COMMENT:
982         return sd->module->meta_get(sd->video, META_TRACK_COMMENT);
983         break;
984       case EMOTION_META_INFO_TRACK_DISC_ID:
985         return sd->module->meta_get(sd->video, META_TRACK_DISCID);
986         break;
987       default:
988         break;
989      }
990    return NULL;
991 }
992
993 EAPI void
994 emotion_object_vis_set(Evas_Object *obj, Emotion_Vis visualization)
995 {
996    Smart_Data *sd;
997
998    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
999    DBG("visualization=%d", visualization);
1000    if (!sd->module) return;
1001    if (!sd->video) return;
1002    if (!sd->module->vis_set) return;
1003    sd->module->vis_set(sd->video, visualization);
1004 }
1005
1006 EAPI Emotion_Vis
1007 emotion_object_vis_get(const Evas_Object *obj)
1008 {
1009    Smart_Data *sd;
1010
1011    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, EMOTION_VIS_NONE);
1012    if (!sd->module) return EMOTION_VIS_NONE;
1013    if (!sd->video) return EMOTION_VIS_NONE;
1014    if (!sd->module->vis_get) return EMOTION_VIS_NONE;
1015    return sd->module->vis_get(sd->video);
1016 }
1017
1018 EAPI Eina_Bool
1019 emotion_object_vis_supported(const Evas_Object *obj, Emotion_Vis visualization)
1020 {
1021    Smart_Data *sd;
1022
1023    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
1024    if (!sd->module) return EINA_FALSE;
1025    if (!sd->video) return EINA_FALSE;
1026    if (!sd->module->vis_supported) return EINA_FALSE;
1027    return sd->module->vis_supported(sd->video, visualization);
1028 }
1029
1030 #ifdef HAVE_EIO
1031 static void
1032 _eio_load_xattr_cleanup(Smart_Data *sd, Eio_File *handler)
1033 {
1034    if (handler == sd->load_xattr) sd->load_xattr = NULL;
1035
1036    EINA_REFCOUNT_UNREF(sd)
1037      _smart_data_free(sd);
1038 }
1039
1040 static void
1041 _eio_load_xattr_done(void *data, Eio_File *handler, const char *xattr_data, unsigned int xattr_size)
1042 {
1043    Smart_Data *sd = data;
1044
1045    if (xattr_size < 128 && xattr_data[xattr_size] == '\0')
1046      {
1047         long long int m = 0;
1048         long int e = 0;
1049
1050         eina_convert_atod(xattr_data, xattr_size, &m, &e);
1051         emotion_object_position_set(evas_object_smart_parent_get(sd->obj), ldexp((double)m, e));
1052      }
1053
1054    _eio_load_xattr_cleanup(sd, handler);
1055 }
1056
1057 static void
1058 _eio_load_xattr_error(void *data, Eio_File *handler, int err __UNUSED__)
1059 {
1060    Smart_Data *sd = data;
1061
1062    _eio_load_xattr_cleanup(sd, handler);
1063 }
1064 #endif
1065
1066 EAPI void
1067 emotion_object_last_position_load(Evas_Object *obj)
1068 {
1069    Smart_Data *sd;
1070    const char *tmp;
1071
1072    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
1073    if (!sd->file) return ;
1074
1075    if (!strncmp(sd->file, "file://", 7))
1076      tmp = sd->file + 7;
1077    else if (!strstr(sd->file, "://"))
1078      tmp = sd->file;
1079    else
1080      return ;
1081
1082 #ifdef HAVE_EIO
1083    if (sd->load_xattr) return ;
1084
1085    EINA_REFCOUNT_REF(sd);
1086
1087    sd->load_xattr = eio_file_xattr_get(tmp, "user.e.time_seek", _eio_load_xattr_done, _eio_load_xattr_error, sd);
1088 #else
1089 # ifdef HAVE_XATTR
1090    {
1091       char double_to_string[128];
1092       ssize_t sz;
1093       long long int m = 0;
1094       long int e = 0;
1095
1096       sz = getxattr(tmp, "user.e.time_seek", double_to_string, 128);
1097       if (sz <= 0 || sz > 128 || double_to_string[sz] != '\0')
1098         return ;
1099
1100       eina_convert_atod(double_to_string, 128, &m, &e);
1101       emotion_object_position_set(obj, ldexp((double)m, e));
1102    }
1103 # endif
1104 #endif
1105 }
1106
1107 #ifdef HAVE_EIO
1108 static void
1109 _eio_save_xattr_cleanup(Smart_Data *sd)
1110 {
1111    sd->save_xattr = NULL;
1112    eina_stringshare_del(sd->time_seek);
1113    sd->time_seek = NULL;
1114
1115    EINA_REFCOUNT_UNREF(sd)
1116      _smart_data_free(sd);
1117 }
1118
1119 static void
1120 _eio_save_xattr_done(void *data, Eio_File *handler __UNUSED__)
1121 {
1122    Smart_Data *sd = data;
1123
1124    _eio_save_xattr_cleanup(sd);
1125 }
1126
1127 static void
1128 _eio_save_xattr_error(void *data, Eio_File *handler __UNUSED__, int err __UNUSED__)
1129 {
1130    Smart_Data *sd = data;
1131
1132    _eio_save_xattr_cleanup(sd);
1133 }
1134 #endif
1135
1136 EAPI void
1137 emotion_object_last_position_save(Evas_Object *obj)
1138 {
1139    Smart_Data *sd;
1140    const char *tmp;
1141    char double_to_string[128];
1142
1143    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
1144    if (!sd->file) return ;
1145
1146    if (!strncmp(sd->file, "file://", 7))
1147      tmp = sd->file + 7;
1148    else if (!strstr(sd->file, "://"))
1149      tmp = sd->file;
1150    else
1151      return ;
1152
1153    eina_convert_dtoa(emotion_object_position_get(obj), double_to_string);
1154
1155 #ifdef HAVE_EIO
1156    if (sd->save_xattr) return ;
1157
1158    EINA_REFCOUNT_REF(sd);
1159
1160    sd->time_seek = eina_stringshare_add(double_to_string);
1161    sd->save_xattr = eio_file_xattr_set(tmp, "user.e.time_seek",
1162                                        sd->time_seek, eina_stringshare_strlen(sd->time_seek) + 1, 0,
1163                                        _eio_save_xattr_done, _eio_save_xattr_error, sd);
1164 #else
1165 # ifdef HAVE_XATTR
1166    setxattr(tmp, "user.e.time_seek", double_to_string, strlen(double_to_string), 0);
1167 # endif
1168 #endif
1169 }
1170
1171 EAPI Eina_Bool
1172 emotion_object_extension_can_play_fast_get(const Evas_Object *obj, const char *file)
1173 {
1174    const Smart_Data *sd;
1175
1176    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, 0);
1177    if (!sd->module) return EINA_FALSE;
1178    if (!sd->video) return EINA_FALSE;
1179    if (!sd->module->can_play_get) return EINA_FALSE;
1180    return sd->module->can_play_get(sd->video, file);
1181 }
1182
1183 EAPI Eina_Bool
1184 emotion_object_extension_can_play_get(const Evas_Object *obj, const char *file)
1185 {
1186    const char *tmp;
1187    Eina_Bool result;
1188
1189    tmp = eina_stringshare_add(file);
1190    result = emotion_object_extension_can_play_fast_get(obj, tmp);
1191    eina_stringshare_del(tmp);
1192
1193    return result;
1194 }
1195
1196 EAPI Eina_Bool
1197 emotion_object_extension_may_play_fast_get(const char *file)
1198 {
1199    if (!file) return EINA_FALSE;
1200    return _emotion_object_extension_can_play_generic_get(NULL, file);
1201 }
1202
1203 EAPI Eina_Bool
1204 emotion_object_extension_may_play_get(const char *file)
1205 {
1206    const char *tmp;
1207    Eina_Bool result;
1208
1209    if (!file) return EINA_FALSE;
1210    tmp = eina_stringshare_add(file);
1211    result = emotion_object_extension_may_play_fast_get(tmp);
1212    eina_stringshare_del(tmp);
1213
1214    return result;
1215 }
1216
1217 /*****************************/
1218 /* Utility calls for modules */
1219 /*****************************/
1220
1221 struct ext_match_s
1222 {
1223    unsigned int length;
1224    const char *extension;
1225 };
1226
1227 #define MATCHING(Ext)                           \
1228   { sizeof (Ext), Ext }
1229
1230 static const struct ext_match_s matchs[] =
1231 { /* map extensions to know if it's a emotion playable content for good first-guess tries */
1232    MATCHING(".264"),
1233    MATCHING(".3g2"),
1234    MATCHING(".3gp"),
1235    MATCHING(".3gp2"),
1236    MATCHING(".3gpp"),
1237    MATCHING(".3gpp2"),
1238    MATCHING(".3p2"),
1239    MATCHING(".asf"),
1240    MATCHING(".avi"),
1241    MATCHING(".bdm"),
1242    MATCHING(".bdmv"),
1243    MATCHING(".clpi"),
1244    MATCHING(".clp"),
1245    MATCHING(".fla"),
1246    MATCHING(".flv"),
1247    MATCHING(".m1v"),
1248    MATCHING(".m2v"),
1249    MATCHING(".m2t"),
1250    MATCHING(".m4v"),
1251    MATCHING(".mkv"),
1252    MATCHING(".mov"),
1253    MATCHING(".mp2"),
1254    MATCHING(".mp2ts"),
1255    MATCHING(".mp4"),
1256    MATCHING(".mpe"),
1257    MATCHING(".mpeg"),
1258    MATCHING(".mpg"),
1259    MATCHING(".mpl"),
1260    MATCHING(".mpls"),
1261    MATCHING(".mts"),
1262    MATCHING(".mxf"),
1263    MATCHING(".nut"),
1264    MATCHING(".nuv"),
1265    MATCHING(".ogg"),
1266    MATCHING(".ogm"),
1267    MATCHING(".ogv"),
1268    MATCHING(".rm"),
1269    MATCHING(".rmj"),
1270    MATCHING(".rmm"),
1271    MATCHING(".rms"),
1272    MATCHING(".rmx"),
1273    MATCHING(".rmvb"),
1274    MATCHING(".swf"),
1275    MATCHING(".ts"),
1276    MATCHING(".weba"),
1277    MATCHING(".webm"),
1278    MATCHING(".wmv")
1279 };
1280
1281 EAPI Eina_Bool
1282 _emotion_object_extension_can_play_generic_get(const void *data __UNUSED__, const char *file)
1283 {
1284    unsigned int length;
1285    unsigned int i;
1286
1287    length = eina_stringshare_strlen(file) + 1;
1288    if (length < 5) return EINA_FALSE;
1289
1290    for (i = 0; i < sizeof (matchs) / sizeof (struct ext_match_s); ++i)
1291      {
1292         if (matchs[i].length > length) continue;
1293
1294         if (!strcasecmp(matchs[i].extension,
1295                         file + length - matchs[i].length))
1296           return EINA_TRUE;
1297      }
1298
1299    return EINA_FALSE;
1300 }
1301
1302 EAPI void *
1303 _emotion_video_get(const Evas_Object *obj)
1304 {
1305    Smart_Data *sd;
1306
1307    E_SMART_OBJ_GET_RETURN(sd, obj, E_OBJ_NAME, NULL);
1308    return sd->video;
1309 }
1310
1311 EAPI void
1312 _emotion_frame_new(Evas_Object *obj)
1313 {
1314    Smart_Data *sd;
1315
1316    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
1317 //   printf("pix get set 1 %p\n", sd->obj);
1318    evas_object_image_pixels_dirty_set(sd->obj, 1);
1319    evas_object_smart_callback_call(obj, SIG_FRAME_DECODE, NULL);
1320 }
1321
1322 EAPI void
1323 _emotion_video_pos_update(Evas_Object *obj, double pos, double len)
1324 {
1325    Smart_Data *sd;
1326    int npos = 0, nlen = 0;
1327
1328    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
1329    if (pos != sd->pos) npos = 1;
1330    if (len != sd->len) nlen = 1;
1331    sd->pos = pos;
1332    sd->len = len;
1333    if (npos) evas_object_smart_callback_call(obj, SIG_POSITION_UPDATE, NULL);
1334    if (nlen) evas_object_smart_callback_call(obj, SIG_LENGTH_CHANGE, NULL);
1335 }
1336
1337 EAPI void
1338 _emotion_frame_resize(Evas_Object *obj, int w, int h, double ratio)
1339 {
1340    Smart_Data *sd;
1341    int iw, ih;
1342    double tmp;
1343    int changed = 0;
1344
1345    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
1346    evas_object_image_size_get(sd->obj, &iw, &ih);
1347    if ((w != iw) || (h != ih))
1348      {
1349         evas_object_image_size_set(sd->obj, w, h);
1350         _emotion_image_data_zero(sd->obj);
1351         changed = 1;
1352      }
1353    if (h > 0) tmp  = (double)w / (double)h;
1354    else tmp = 1.0;
1355    if (ratio != tmp) tmp = ratio;
1356    if (tmp != sd->ratio)
1357      {
1358         sd->ratio = tmp;
1359         changed = 1;
1360      }
1361    if (changed)
1362      {
1363         evas_object_size_hint_request_set(obj, w, h);
1364         evas_object_smart_callback_call(obj, SIG_FRAME_RESIZE, NULL);
1365      }
1366 }
1367
1368 EAPI void
1369 _emotion_decode_stop(Evas_Object *obj)
1370 {
1371    Smart_Data *sd;
1372
1373    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
1374    if (sd->play)
1375      {
1376         sd->play = 0;
1377         evas_object_smart_callback_call(obj, SIG_DECODE_STOP, NULL);
1378      }
1379 }
1380
1381 EAPI void
1382 _emotion_open_done(Evas_Object *obj)
1383 {
1384    evas_object_smart_callback_call(obj, SIG_OPEN_DONE, NULL);
1385 }
1386
1387 EAPI void
1388 _emotion_playback_started(Evas_Object *obj)
1389 {
1390    evas_object_smart_callback_call(obj, SIG_PLAYBACK_STARTED, NULL);
1391 }
1392
1393 EAPI void
1394 _emotion_playback_finished(Evas_Object *obj)
1395 {
1396    evas_object_smart_callback_call(obj, SIG_PLAYBACK_FINISHED, NULL);
1397 }
1398
1399 EAPI void
1400 _emotion_audio_level_change(Evas_Object *obj)
1401 {
1402    evas_object_smart_callback_call(obj, SIG_AUDIO_LEVEL_CHANGE, NULL);
1403 }
1404
1405 EAPI void
1406 _emotion_channels_change(Evas_Object *obj)
1407 {
1408    Smart_Data *sd;
1409
1410    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
1411    evas_object_smart_callback_call(obj, SIG_CHANNELS_CHANGE, NULL);
1412 }
1413
1414 EAPI void
1415 _emotion_title_set(Evas_Object *obj, char *title)
1416 {
1417    Smart_Data *sd;
1418
1419    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
1420    free(sd->title);
1421    sd->title = strdup(title);
1422    evas_object_smart_callback_call(obj, SIG_TITLE_CHANGE, NULL);
1423 }
1424
1425 EAPI void
1426 _emotion_progress_set(Evas_Object *obj, char *info, double st)
1427 {
1428    Smart_Data *sd;
1429
1430    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
1431    free(sd->progress.info);
1432    sd->progress.info = strdup(info);
1433    sd->progress.stat = st;
1434    evas_object_smart_callback_call(obj, SIG_PROGRESS_CHANGE, NULL);
1435 }
1436
1437 EAPI void
1438 _emotion_file_ref_set(Evas_Object *obj, const char *file, int num)
1439 {
1440    Smart_Data *sd;
1441
1442    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
1443    free(sd->ref.file);
1444    sd->ref.file = strdup(file);
1445    sd->ref.num = num;
1446    evas_object_smart_callback_call(obj, SIG_REF_CHANGE, NULL);
1447 }
1448
1449 EAPI void
1450 _emotion_spu_button_num_set(Evas_Object *obj, int num)
1451 {
1452    Smart_Data *sd;
1453
1454    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
1455    sd->spu.button_num = num;
1456    evas_object_smart_callback_call(obj, SIG_BUTTON_NUM_CHANGE, NULL);
1457 }
1458
1459 EAPI void
1460 _emotion_spu_button_set(Evas_Object *obj, int button)
1461 {
1462    Smart_Data *sd;
1463
1464    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
1465    sd->spu.button = button;
1466    evas_object_smart_callback_call(obj, SIG_BUTTON_CHANGE, NULL);
1467 }
1468
1469 EAPI void
1470 _emotion_seek_done(Evas_Object *obj)
1471 {
1472    Smart_Data *sd;
1473
1474    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
1475    if (sd->seeking)
1476      {
1477         sd->seeking = 0;
1478         if (sd->seek) emotion_object_position_set(obj, sd->seek_pos);
1479      }
1480 }
1481
1482
1483
1484 /****************************/
1485 /* Internal object routines */
1486 /****************************/
1487
1488 static void
1489 _mouse_move(void *data, Evas *ev __UNUSED__, Evas_Object *obj, void *event_info)
1490 {
1491    Evas_Event_Mouse_Move *e;
1492    Smart_Data *sd;
1493    int x, y, iw, ih;
1494    Evas_Coord ox, oy, ow, oh;
1495
1496    e = event_info;
1497    sd = data;
1498    if (!sd->module) return;
1499    if (!sd->video) return;
1500    evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
1501    evas_object_image_size_get(obj, &iw, &ih);
1502    if ((iw < 1) || (ih < 1)) return;
1503    x = (((int)e->cur.canvas.x - ox) * iw) / ow;
1504    y = (((int)e->cur.canvas.y - oy) * ih) / oh;
1505    sd->module->event_mouse_move_feed(sd->video, x, y);
1506 }
1507
1508 static void
1509 _mouse_down(void *data, Evas *ev __UNUSED__, Evas_Object *obj, void *event_info)
1510 {
1511    Evas_Event_Mouse_Down *e;
1512    Smart_Data *sd;
1513    int x, y, iw, ih;
1514    Evas_Coord ox, oy, ow, oh;
1515
1516    e = event_info;
1517    sd = data;
1518    if (!sd->module) return;
1519    if (!sd->video) return;
1520    evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
1521    evas_object_image_size_get(obj, &iw, &ih);
1522    if ((iw < 1) || (ih < 1)) return;
1523    x = (((int)e->canvas.x - ox) * iw) / ow;
1524    y = (((int)e->canvas.y - oy) * ih) / oh;
1525    sd->module->event_mouse_button_feed(sd->video, 1, x, y);
1526 }
1527
1528 static void
1529 _pos_set_job(void *data)
1530 {
1531    Evas_Object *obj;
1532    Smart_Data *sd;
1533
1534    obj = data;
1535    E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
1536    sd->job = NULL;
1537    if (sd->seeking) return;
1538    if (sd->seek)
1539      {
1540         sd->seeking = 1;
1541         sd->module->pos_set(sd->video, sd->seek_pos);
1542         sd->seek = 0;
1543      }
1544 }
1545
1546 /* called by evas when it needs pixels for the image object */
1547 static void
1548 _pixels_get(void *data, Evas_Object *obj)
1549 {
1550    int iw, ih, w, h;
1551    Smart_Data *sd;
1552    Emotion_Format format;
1553    unsigned char *bgra_data;
1554
1555    sd = data;
1556    evas_object_image_size_get(obj, &iw, &ih);
1557    sd->module->video_data_size_get(sd->video, &w, &h);
1558    w = (w >> 1) << 1;
1559    h = (h >> 1) << 1;
1560    if ((w != iw) || (h != ih))
1561      {
1562         evas_object_image_colorspace_set(obj, EVAS_COLORSPACE_YCBCR422P601_PL);
1563         evas_object_image_alpha_set(obj, 0);
1564         evas_object_image_size_set(obj, w, h);
1565         _emotion_image_data_zero(sd->obj);
1566         iw = w;
1567         ih = h;
1568      }
1569    if ((iw < 1) || (ih < 1))
1570      {
1571 //      printf("pix get set 0 (1)\n");
1572         evas_object_image_pixels_dirty_set(obj, 0);
1573      }
1574    else
1575      {
1576         format = sd->module->format_get(sd->video);
1577         if ((format == EMOTION_FORMAT_YV12) || (format == EMOTION_FORMAT_I420))
1578           {
1579              unsigned char **rows;
1580
1581              evas_object_image_colorspace_set(obj, EVAS_COLORSPACE_YCBCR422P601_PL);
1582              rows = evas_object_image_data_get(obj, 1);
1583              if (rows)
1584                {
1585                   if (sd->module->yuv_rows_get(sd->video, iw, ih,
1586                                                rows,
1587                                                &rows[ih],
1588                                                &rows[ih + (ih / 2)]))
1589                     evas_object_image_data_update_add(obj, 0, 0, iw, ih);
1590                }
1591              evas_object_image_data_set(obj, rows);
1592 //           printf("pix get set 0 (2)\n");
1593              evas_object_image_pixels_dirty_set(obj, 0);
1594           }
1595         else if (format == EMOTION_FORMAT_BGRA)
1596           {
1597              if (sd->module->bgra_data_get(sd->video, &bgra_data))
1598                {
1599                   evas_object_image_data_set(obj, bgra_data);
1600 //                printf("pix get set 0 (3)\n");
1601                   evas_object_image_pixels_dirty_set(obj, 0);
1602                }
1603           }
1604      }
1605 // no need for this because on any new frame decode info from the decoder
1606 // module, the previous "current frame" is released (done) for us anyway
1607 //   sd->module->frame_done(sd->video);
1608
1609 /*
1610    evas_object_image_size_get(obj, &iw, &ih);
1611    sd->module->video_data_size_get(sd->video, &w, &h);
1612    if ((w != iw) || (h != ih))
1613      {
1614         evas_object_image_size_set(obj, w, h);
1615         _emotion_image_data_zero(sd->obj);
1616         iw = w;
1617         ih = h;
1618      }
1619    format = sd->module->format_get(sd->video);
1620    if ((format == EMOTION_FORMAT_YV12) || (format == EMOTION_FORMAT_I420))
1621      {
1622         unsigned char **rows;
1623         Evas_Pixel_Import_Source ps;
1624
1625         ps.format = EVAS_PIXEL_FORMAT_YUV420P_601;
1626         ps.w = iw;
1627         ps.h = ih;
1628
1629         ps.rows = malloc(ps.h * 2 * sizeof(void *));
1630         if (!ps.rows)
1631           {
1632              sd->module->frame_done(sd->video);
1633              return;
1634           }
1635
1636         rows = (unsigned char **)ps.rows;
1637
1638         if (sd->module->yuv_rows_get(sd->video, iw, ih,
1639                                      rows,
1640                                      &rows[ps.h],
1641                                      &rows[ps.h + (ps.h / 2)]))
1642           evas_object_image_pixels_import(obj, &ps);
1643         evas_object_image_pixels_dirty_set(obj, 0);
1644         free(ps.rows);
1645      }
1646    else if (format == EMOTION_FORMAT_BGRA)
1647      {
1648         if (sd->module->bgra_data_get(sd->video, &bgra_data));
1649           {
1650              evas_object_image_data_set(obj, bgra_data);
1651              evas_object_image_pixels_dirty_set(obj, 0);
1652           }
1653      }
1654    sd->module->frame_done(sd->video);
1655  */
1656 }
1657
1658 /*******************************************/
1659 /* Internal smart object required routines */
1660 /*******************************************/
1661 #ifdef EMOTION_STATIC_BUILD_XINE
1662 Eina_Bool xine_module_init(void);
1663 #endif
1664 #ifdef EMOTION_STATIC_BUILD_VLC
1665 Eina_Bool vlc_module_init(void);
1666 #endif
1667 #ifdef EMOTION_STATIC_BUILD_GSTREAMER
1668 Eina_Bool gstreamer_module_init(void);
1669 #endif
1670
1671 static void
1672 _smart_init(void)
1673 {
1674    char *path;
1675
1676    if (smart) return;
1677      {
1678         eina_init();
1679
1680         _log_domain = eina_log_domain_register("emotion", EINA_COLOR_LIGHTCYAN);
1681         if (_log_domain < 0)
1682           {
1683              EINA_LOG_CRIT("Could not register log domain 'emotion'");
1684              eina_shutdown();
1685              return;
1686           }
1687
1688         _backends = eina_hash_string_small_new(free);
1689
1690         _modules = eina_module_list_get(NULL, PACKAGE_LIB_DIR "/emotion/", 0, NULL, NULL);
1691
1692         path = eina_module_environment_path_get("HOME", "/.emotion/");
1693         _modules = eina_module_list_get(_modules, path, 0, NULL, NULL);
1694         if (path) free(path);
1695
1696         path = eina_module_environment_path_get("EMOTION_MODULES_DIR", "/emotion/");
1697         _modules = eina_module_list_get(_modules, path, 0, NULL, NULL);
1698         if (path) free(path);
1699
1700         path = eina_module_symbol_path_get(emotion_object_add, "/emotion/");
1701         _modules = eina_module_list_get(_modules, path, 0, NULL, NULL);
1702         if (path) free(path);
1703
1704         if (!_modules)
1705           {
1706              ERR("No module found!");
1707              return;
1708           }
1709
1710         eina_module_list_load(_modules);
1711
1712         /* Init static module */
1713 #ifdef EMOTION_STATIC_BUILD_XINE
1714         xine_module_init();
1715 #endif
1716 #ifdef EMOTION_STATIC_BUILD_VLC
1717         vlc_module_init();
1718 #endif
1719 #ifdef EMOTION_STATIC_BUILD_GSTREAMER
1720         gstreamer_module_init();
1721 #endif
1722
1723         static Evas_Smart_Class sc =
1724           EVAS_SMART_CLASS_INIT_NAME_VERSION(E_OBJ_NAME);
1725         if (!sc.add)
1726           {
1727              sc.add = _smart_add;
1728              sc.del = _smart_del;
1729              sc.move = _smart_move;
1730              sc.resize = _smart_resize;
1731              sc.show = _smart_show;
1732              sc.hide = _smart_hide;
1733              sc.color_set = _smart_color_set;
1734              sc.clip_set = _smart_clip_set;
1735              sc.clip_unset = _smart_clip_unset;
1736              sc.callbacks = _smart_callbacks;
1737           }
1738         smart = evas_smart_class_new(&sc);
1739      }
1740 }
1741
1742 static void
1743 _smart_add(Evas_Object * obj)
1744 {
1745    Smart_Data *sd;
1746    unsigned int *pixel;
1747
1748    sd = calloc(1, sizeof(Smart_Data));
1749    if (!sd) return;
1750    EINA_REFCOUNT_INIT(sd);
1751    sd->obj = evas_object_image_add(evas_object_evas_get(obj));
1752    evas_object_event_callback_add(sd->obj, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, sd);
1753    evas_object_event_callback_add(sd->obj, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, sd);
1754    evas_object_image_pixels_get_callback_set(sd->obj, _pixels_get, sd);
1755    evas_object_smart_member_add(sd->obj, obj);
1756    sd->ratio = 1.0;
1757    sd->spu.button = -1;
1758    evas_object_image_alpha_set(sd->obj, 0);
1759    pixel = evas_object_image_data_get(sd->obj, 1);
1760    if (pixel)
1761      {
1762         *pixel = 0xff000000;
1763         evas_object_image_data_set(obj, pixel);
1764      }
1765    evas_object_smart_data_set(obj, sd);
1766
1767    ecore_init();
1768 }
1769
1770 static void
1771 _smart_del(Evas_Object * obj)
1772 {
1773    Smart_Data *sd;
1774
1775    sd = evas_object_smart_data_get(obj);
1776    if (!sd) return;
1777    EINA_REFCOUNT_UNREF(sd)
1778      _smart_data_free(sd);
1779 }
1780
1781 static void
1782 _smart_move(Evas_Object * obj, Evas_Coord x, Evas_Coord y)
1783 {
1784    Smart_Data *sd;
1785
1786    sd = evas_object_smart_data_get(obj);
1787    if (!sd) return;
1788    evas_object_move(sd->obj, x, y);
1789 }
1790
1791 static void
1792 _smart_resize(Evas_Object * obj, Evas_Coord w, Evas_Coord h)
1793 {
1794    Smart_Data *sd;
1795
1796    sd = evas_object_smart_data_get(obj);
1797    if (!sd) return;
1798    evas_object_image_fill_set(sd->obj, 0, 0, w, h);
1799    evas_object_resize(sd->obj, w, h);
1800 }
1801
1802 static void
1803 _smart_show(Evas_Object * obj)
1804 {
1805    Smart_Data *sd;
1806
1807    sd = evas_object_smart_data_get(obj);
1808    if (!sd) return;
1809    evas_object_show(sd->obj);
1810
1811 }
1812
1813 static void
1814 _smart_hide(Evas_Object * obj)
1815 {
1816    Smart_Data *sd;
1817
1818    sd = evas_object_smart_data_get(obj);
1819    if (!sd) return;
1820    evas_object_hide(sd->obj);
1821 }
1822
1823 static void
1824 _smart_color_set(Evas_Object * obj, int r, int g, int b, int a)
1825 {
1826    Smart_Data *sd;
1827
1828    sd = evas_object_smart_data_get(obj);
1829    if (!sd) return;
1830    evas_object_color_set(sd->obj, r, g, b, a);
1831 }
1832
1833 static void
1834 _smart_clip_set(Evas_Object * obj, Evas_Object * clip)
1835 {
1836    Smart_Data *sd;
1837
1838    sd = evas_object_smart_data_get(obj);
1839    if (!sd) return;
1840    evas_object_clip_set(sd->obj, clip);
1841 }
1842
1843 static void
1844 _smart_clip_unset(Evas_Object * obj)
1845 {
1846    Smart_Data *sd;
1847
1848    sd = evas_object_smart_data_get(obj);
1849    if (!sd) return;
1850    evas_object_clip_unset(sd->obj);
1851 }
1852
1853 EAPI Evas_Object *
1854 _emotion_image_get(const Evas_Object *obj)
1855 {
1856    Smart_Data *sd;
1857
1858    sd = evas_object_smart_data_get(obj);
1859    if (!sd) return NULL;
1860    return sd->obj;
1861 }