emotion/generic: Non-blocking event reading from player.
[profile/ivi/emotion.git] / src / modules / generic / emotion_generic.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4 #include <sys/mman.h>
5 #include <sys/stat.h>
6 #include <sys/time.h>
7 #include <sys/types.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include <Eina.h>
11 #include <Evas.h>
12
13 #include "Emotion.h"
14 #include "emotion_private.h"
15 #include "emotion_generic.h"
16
17 static Eina_Prefix *pfx = NULL;
18
19 static int _emotion_generic_log_domain = -1;
20 #define DBG(...) EINA_LOG_DOM_DBG(_emotion_generic_log_domain, __VA_ARGS__)
21 #define INF(...) EINA_LOG_DOM_INFO(_emotion_generic_log_domain, __VA_ARGS__)
22 #define WRN(...) EINA_LOG_DOM_WARN(_emotion_generic_log_domain, __VA_ARGS__)
23 #define ERR(...) EINA_LOG_DOM_ERR(_emotion_generic_log_domain, __VA_ARGS__)
24 #define CRITICAL(...) EINA_LOG_DOM_CRIT(_emotion_generic_log_domain, __VA_ARGS__)
25
26
27 struct _default_players {
28    const char *name;
29    const char *cmdline;
30 };
31
32 static struct _default_players players[] = {
33 #ifdef EMOTION_BUILD_GENERIC_VLC
34        { "vlc", "em_generic_vlc" },
35 #endif
36        { NULL, NULL }
37 };
38
39 static const char *
40 _get_player(const char *name)
41 {
42    const char *selected_name = NULL;
43    const char *libdir = eina_prefix_lib_get(pfx);
44    static char buf[PATH_MAX];
45    int i;
46
47    if (name)
48      {
49         for (i = 0; players[i].name; i++)
50           {
51              if (!strcmp(players[i].name, name))
52                {
53                   selected_name = players[i].cmdline;
54                   break;
55                }
56           }
57      }
58
59    if ((!selected_name) && (name))
60      selected_name = name;
61
62    if (selected_name)
63      {
64         const char *cmd;
65
66         if (selected_name[0] == '/') cmd = selected_name;
67         else
68           {
69              snprintf(buf, sizeof(buf), "%s/emotion/utils/%s",
70                       libdir, selected_name);
71              cmd = buf;
72           }
73
74         DBG("Try generic player '%s'", cmd);
75         if (access(cmd, R_OK | X_OK) == 0)
76           {
77              INF("Using generic player '%s'", cmd);
78              return cmd;
79           }
80      }
81
82    for (i = 0; players[i].name; i++)
83      {
84         snprintf(buf, sizeof(buf), "%s/emotion/utils/%s",
85                  libdir, players[i].cmdline);
86         DBG("Try generic player '%s'", buf);
87         if (access(buf, R_OK | X_OK) == 0)
88           {
89              INF("Using fallback player '%s'", buf);
90              return buf;
91           }
92      }
93
94    ERR("no generic player found, given name='%s'", name ? name : "");
95    return NULL;
96 }
97
98 static void
99 _player_send_cmd(Emotion_Generic_Video *ev, int cmd)
100 {
101    if (cmd >= EM_CMD_LAST)
102      {
103         ERR("invalid command to player.");
104         return;
105      }
106    write(ev->fd_write, &cmd, sizeof(cmd));
107 }
108
109 static void
110 _player_send_int(Emotion_Generic_Video *ev, int number)
111 {
112    write(ev->fd_write, &number, sizeof(number));
113 }
114
115 static void
116 _player_send_float(Emotion_Generic_Video *ev, float number)
117 {
118    write(ev->fd_write, &number, sizeof(number));
119 }
120
121 static void
122 _player_send_str(Emotion_Generic_Video *ev, const char *str, Eina_Bool stringshared)
123 {
124    int len;
125
126    if (stringshared)
127      len = eina_stringshare_strlen(str) + 1;
128    else
129      len = strlen(str) + 1;
130    write(ev->fd_write, &len, sizeof(len));
131    write(ev->fd_write, str, len);
132 }
133
134 static Eina_Bool
135 _create_shm_data(Emotion_Generic_Video *ev, const char *shmname)
136 {
137    int shmfd;
138    int npages;
139    size_t size;
140    Emotion_Generic_Video_Shared *vs;
141
142    shmfd = shm_open(shmname, O_CREAT | O_RDWR | O_TRUNC, 0777);
143    if (shmfd == -1)
144      {
145         ERR("player: could not open shm: %s", shmname);
146         ERR("player: %s", strerror(errno));
147         return 0;
148      }
149    size = 3 * (ev->w * ev->h * DEFAULTPITCH) + sizeof(*vs);
150
151    npages = (int)(size / getpagesize()) + 1;
152    size = npages * getpagesize();
153
154    if (ftruncate(shmfd, size))
155      {
156         ERR("error when allocating shared memory (size = %zd): "
157             "%s", size, strerror(errno));
158         shm_unlink(shmname);
159         return EINA_FALSE;
160      }
161    vs = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0);
162    if (vs == MAP_FAILED)
163      {
164         ERR("error when mapping shared memory.\n");
165         return EINA_FALSE;
166      }
167
168    vs->size = size;
169    vs->width = ev->w;
170    vs->height = ev->h;
171    vs->pitch = DEFAULTPITCH;
172    vs->frame.emotion = 0;
173    vs->frame.player = 1;
174    vs->frame.last = 2;
175    vs->frame.next = 2;
176    vs->frame_drop = 0;
177    sem_init(&vs->lock, 1, 1);
178    ev->frame.frames[0] = (unsigned char *)vs + sizeof(*vs);
179    ev->frame.frames[1] = (unsigned char *)vs + sizeof(*vs) + vs->height * vs->width * vs->pitch;
180    ev->frame.frames[2] = (unsigned char *)vs + sizeof(*vs) + 2 * vs->height * vs->width * vs->pitch;
181
182    if (ev->shared)
183      munmap(ev->shared, ev->shared->size);
184    ev->shared = vs;
185
186    return EINA_TRUE;
187 }
188
189 static void
190 _player_new_frame(Emotion_Generic_Video *ev)
191 {
192    if (!ev->file_ready)
193      return;
194    _emotion_frame_new(ev->obj);
195 }
196
197 static void
198 _file_open(Emotion_Generic_Video *ev)
199 {
200    INF("Opening file: %s", ev->filename);
201    ev->drop = 0;
202
203    if (!ev->ready || !ev->filename)
204      return;
205    _player_send_cmd(ev, EM_CMD_FILE_SET);
206    _player_send_str(ev, ev->filename, EINA_TRUE);
207 }
208
209 static void
210 _player_file_set_done(Emotion_Generic_Video *ev)
211 {
212    if (ev->file_changed)
213      {
214         _file_open(ev);
215         ev->file_changed = EINA_FALSE;
216         return;
217      }
218
219    if (!_create_shm_data(ev, ev->shmname))
220      {
221         ERR("could not create shared memory.");
222         return;
223      }
224    _player_send_cmd(ev, EM_CMD_FILE_SET_DONE);
225 }
226
227 static void
228 _player_ready(Emotion_Generic_Video *ev)
229 {
230    INF("received: player ready.");
231
232    ev->initializing = EINA_FALSE;
233    ev->ready = EINA_TRUE;
234
235    if (!ev->filename)
236      return;
237
238    _file_open(ev);
239 }
240
241 static int
242 _em_read_safe(int fd, void *buf, ssize_t size)
243 {
244    ssize_t todo;
245    char *p;
246
247    todo = size;
248    p = buf;
249
250    while (todo > 0)
251      {
252         ssize_t r;
253
254         r = read(fd, p, todo);
255         if (r > 0)
256           {
257              todo -= r;
258              p += r;
259           }
260         else if (r == 0)
261           return 0;
262         else
263           {
264              if (errno == EINTR || errno == EAGAIN)
265                return size - todo;
266              else
267                {
268                   ERR("could not read from fd %d: %s", fd, strerror(errno));
269                   return -1;
270                }
271           }
272      }
273
274    return size;
275 }
276
277 static Eina_Bool
278 _player_cmd_param_read(Emotion_Generic_Video *ev, void *param, size_t size)
279 {
280    ssize_t done, todo, i;
281
282    /* When a parameter must be read, we cannot make sure it will be entirely
283     * available. Thus we store the bytes that could be read in a temp buffer,
284     * and when more data is read we try to complete the buffer and finally use
285     * the read value.
286     */
287    if (!ev->cmd.tmp)
288      {
289         ev->cmd.tmp = malloc(size);
290         ev->cmd.i = 0;
291         ev->cmd.total = size;
292      }
293
294    todo = ev->cmd.total - ev->cmd.i;
295    i = ev->cmd.i;
296    done = read(ev->fd_read, &ev->cmd.tmp[i], todo);
297
298    if (done < 0 &&  errno != EINTR && errno != EAGAIN)
299      {
300         if (ev->cmd.tmp)
301           {
302              free(ev->cmd.tmp);
303              ev->cmd.tmp = NULL;
304           }
305         ERR("problem when reading parameter from pipe.");
306         ev->cmd.type = -1;
307         return EINA_FALSE;
308      }
309
310    if (done == todo)
311      {
312         memcpy(param, ev->cmd.tmp, size);
313         free(ev->cmd.tmp);
314         ev->cmd.tmp = NULL;
315         return EINA_TRUE;
316      }
317
318    if (done > 0)
319      ev->cmd.i += done;
320
321    return EINA_FALSE;
322 }
323
324 static Eina_Bool
325 _player_int_read(Emotion_Generic_Video *ev, int *i)
326 {
327    int n;
328    n = _em_read_safe(ev->fd_read, i, sizeof(*i));
329    if (n <= 0)
330      {
331         ERR("could not read int from fd_read %d\n", ev->fd_read);
332         return EINA_FALSE;
333      }
334
335    return EINA_TRUE;
336 }
337
338 static Eina_Bool
339 _player_str_read(Emotion_Generic_Video *ev, char *str, int *len)
340 {
341    int n;
342
343    if (!_player_int_read(ev, len))
344      return EINA_FALSE;
345
346    n = _em_read_safe(ev->fd_read, str, *len);
347    if (n <= 0)
348      {
349         ERR("could not read string from fd_read %d\n", ev->fd_read);
350         return EINA_FALSE;
351      }
352
353    return EINA_TRUE;
354 }
355
356 static void
357 _player_frame_resize(Emotion_Generic_Video *ev)
358 {
359    int w, h;
360
361    w = ev->cmd.param.size.width;
362    h = ev->cmd.param.size.height;
363
364    INF("received frame resize: %dx%d", w, h);
365    ev->w = w;
366    ev->h = h;
367    ev->ratio = (float)w / h;
368
369    if (ev->opening)
370      return;
371
372    _emotion_frame_resize(ev->obj, ev->w, ev->h, ev->ratio);
373 }
374
375 static void
376 _player_length_changed(Emotion_Generic_Video *ev)
377 {
378    float length = ev->cmd.param.f_num;
379
380    INF("received length changed: %0.3f", length);
381
382    ev->len = length;
383    _emotion_video_pos_update(ev->obj, ev->pos, ev->len);
384 }
385
386 static void
387 _player_position_changed(Emotion_Generic_Video *ev)
388 {
389    float position = ev->cmd.param.f_num;
390
391    INF("received position changed: %0.3f", position);
392
393    ev->pos = position;
394    _emotion_video_pos_update(ev->obj, ev->pos, ev->len);
395
396    if (ev->len == 0)
397      return;
398
399    float progress = ev->pos / ev->len;
400    char buf[16];
401    snprintf(buf, sizeof(buf), "%0.1f%%", progress * 100);
402
403    _emotion_progress_set(ev->obj, buf, progress);
404 }
405
406 static void
407 _player_seekable_changed(Emotion_Generic_Video *ev)
408 {
409    int seekable = ev->cmd.param.i_num;
410
411    INF("received seekable changed: %d", seekable);
412
413    seekable = !!seekable;
414
415    ev->seekable = seekable;
416 }
417
418 static void
419 _player_volume(Emotion_Generic_Video *ev)
420 {
421    float vol, oldvol;
422    _player_float_read(ev, &vol);
423
424    INF("received volume: %0.3f", vol);
425
426    oldvol = ev->volume;
427    ev->volume = vol;
428    if (vol != oldvol && !ev->opening)
429      _emotion_audio_level_change(ev->obj);
430 }
431
432 static void
433 _audio_channels_free(Emotion_Generic_Video *ev)
434 {
435    int i;
436    for (i = 0; i < ev->audio_channels_count; i++)
437      eina_stringshare_del(ev->audio_channels[i].name);
438    free(ev->audio_channels);
439    ev->audio_channels_count = 0;
440 }
441
442 static void
443 _video_channels_free(Emotion_Generic_Video *ev)
444 {
445    int i;
446    for (i = 0; i < ev->video_channels_count; i++)
447      eina_stringshare_del(ev->video_channels[i].name);
448    free(ev->video_channels);
449    ev->video_channels_count = 0;
450 }
451
452 static void
453 _spu_channels_free(Emotion_Generic_Video *ev)
454 {
455    int i;
456    for (i = 0; i < ev->spu_channels_count; i++)
457      eina_stringshare_del(ev->spu_channels[i].name);
458    free(ev->spu_channels);
459    ev->spu_channels_count = 0;
460 }
461
462 static void
463 _player_tracks_info(Emotion_Generic_Video *ev, Emotion_Generic_Channel **channels, int *count, int *current)
464 {
465    Emotion_Generic_Channel *pchannels;
466    int i;
467
468    _player_int_read(ev, current);
469    _player_int_read(ev, count);
470
471    INF("number of tracks: %d (current = %d):", *count, *current);
472    pchannels = calloc(*count, sizeof(Emotion_Generic_Channel));
473    for (i = 0; i < *count; i++)
474      {
475         int tid, len;
476         char buf[PATH_MAX];
477         _player_int_read(ev, &tid);
478         _player_str_read(ev, buf, &len);
479         pchannels[i].id = tid;
480         pchannels[i].name = eina_stringshare_add_length(buf, len);
481         INF("\tchannel %d: %s", tid, buf);
482      }
483
484    *channels = pchannels;
485 }
486
487 static void
488 _player_audio_tracks_info(Emotion_Generic_Video *ev)
489 {
490    INF("Receiving audio channels:");
491    if (ev->audio_channels_count)
492      _audio_channels_free(ev);
493
494    _player_tracks_info(ev, &ev->audio_channels, &ev->audio_channels_count,
495                        &ev->audio_channel_current);
496 }
497
498 static void
499 _player_video_tracks_info(Emotion_Generic_Video *ev)
500 {
501    INF("Receiving video channels:");
502    if (ev->video_channels_count)
503      _video_channels_free(ev);
504
505    _player_tracks_info(ev, &ev->video_channels, &ev->video_channels_count,
506                        &ev->video_channel_current);
507 }
508
509 static void
510 _player_spu_tracks_info(Emotion_Generic_Video *ev)
511 {
512    INF("Receiving spu channels:");
513    if (ev->spu_channels_count)
514      _spu_channels_free(ev);
515
516    _player_tracks_info(ev, &ev->spu_channels, &ev->spu_channels_count,
517                        &ev->spu_channel_current);
518 }
519
520 static void
521 _player_helper_str_read(Emotion_Generic_Video *ev, const char **pstr)
522 {
523    int len;
524    char buf[PATH_MAX];
525    if (_player_str_read(ev, buf, &len))
526      *pstr = eina_stringshare_add_length(buf, len);
527 }
528
529 static void
530 _player_meta_info_free(Emotion_Generic_Video *ev)
531 {
532    eina_stringshare_replace(&ev->meta.title, NULL);
533    eina_stringshare_replace(&ev->meta.artist, NULL);
534    eina_stringshare_replace(&ev->meta.album, NULL);
535    eina_stringshare_replace(&ev->meta.year, NULL);
536    eina_stringshare_replace(&ev->meta.genre, NULL);
537    eina_stringshare_replace(&ev->meta.comment, NULL);
538    eina_stringshare_replace(&ev->meta.disc_id, NULL);
539    eina_stringshare_replace(&ev->meta.count, NULL);
540 }
541
542 static void
543 _player_meta_info_read(Emotion_Generic_Video *ev)
544 {
545    INF("Receiving meta info:");
546    _player_meta_info_free(ev);
547    _player_helper_str_read(ev, &ev->meta.title);
548    _player_helper_str_read(ev, &ev->meta.artist);
549    _player_helper_str_read(ev, &ev->meta.album);
550    _player_helper_str_read(ev, &ev->meta.year);
551    _player_helper_str_read(ev, &ev->meta.genre);
552    _player_helper_str_read(ev, &ev->meta.comment);
553    _player_helper_str_read(ev, &ev->meta.disc_id);
554    _player_helper_str_read(ev, &ev->meta.count);
555    INF("title: '%s'", ev->meta.title);
556    INF("artist: '%s'", ev->meta.artist);
557    INF("album: '%s'", ev->meta.album);
558    INF("year: '%s'", ev->meta.year);
559    INF("genre: '%s'", ev->meta.genre);
560    INF("comment: '%s'", ev->meta.comment);
561    INF("disc_id: '%s'", ev->meta.disc_id);
562    INF("count: '%s'", ev->meta.count);
563 }
564
565 static void
566 _player_file_closed(Emotion_Generic_Video *ev)
567 {
568    INF("Closed previous file.");
569    sem_destroy(&ev->shared->lock);
570
571    ev->closing = EINA_FALSE;
572
573    if (ev->opening)
574      _file_open(ev);
575 }
576
577 static void
578 _player_open_done(Emotion_Generic_Video *ev)
579 {
580    int success;
581
582    success = ev->cmd.param.i_num;
583    shm_unlink(ev->shmname);
584
585    if (ev->file_changed)
586      {
587         _file_open(ev);
588         ev->file_changed = EINA_FALSE;
589         return;
590      }
591
592    ev->opening = EINA_FALSE;
593    if (!success)
594      {
595         ERR("Could not open file.");
596         return;
597      }
598
599    ev->file_ready = EINA_TRUE;
600
601    _emotion_open_done(ev->obj);
602
603    if (ev->play)
604      {
605         _player_send_cmd(ev, EM_CMD_PLAY);
606         _player_send_float(ev, ev->pos);
607      }
608
609    _player_send_cmd(ev, EM_CMD_VOLUME_SET);
610    _player_send_float(ev, ev->volume);
611
612    _player_send_cmd(ev, EM_CMD_SPEED_SET);
613    _player_send_float(ev, ev->speed);
614
615    int mute = ev->audio_mute;
616    _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET);
617    _player_send_int(ev, mute);
618
619    mute = ev->video_mute;
620    _player_send_cmd(ev, EM_CMD_VIDEO_MUTE_SET);
621    _player_send_int(ev, mute);
622
623    mute = ev->spu_mute;
624    _player_send_cmd(ev, EM_CMD_SPU_MUTE_SET);
625    _player_send_int(ev, mute);
626
627    INF("Open done");
628 }
629
630 static void
631 _player_cmd_process(Emotion_Generic_Video *ev)
632 {
633    switch (ev->cmd.type) {
634       case EM_RESULT_INIT:
635          _player_ready(ev);
636          break;
637       case EM_RESULT_FRAME_NEW:
638          _player_new_frame(ev);
639          break;
640       case EM_RESULT_FILE_SET:
641          _player_file_set_done(ev);
642          break;
643       case EM_RESULT_FILE_SET_DONE:
644          _player_open_done(ev);
645          break;
646       case EM_RESULT_FILE_CLOSE:
647          _player_file_closed(ev);
648          break;
649       case EM_RESULT_PLAYBACK_STOPPED:
650          _emotion_playback_finished(ev->obj);
651          break;
652       case EM_RESULT_FRAME_SIZE:
653          _player_frame_resize(ev);
654          break;
655       case EM_RESULT_LENGTH_CHANGED:
656          _player_length_changed(ev);
657          break;
658       case EM_RESULT_POSITION_CHANGED:
659          _player_position_changed(ev);
660          break;
661       case EM_RESULT_SEEKABLE_CHANGED:
662          _player_seekable_changed(ev);
663          break;
664       case EM_RESULT_AUDIO_TRACK_INFO:
665          _player_audio_tracks_info(ev);
666          break;
667       case EM_RESULT_VIDEO_TRACK_INFO:
668          _player_video_tracks_info(ev);
669          break;
670       case EM_RESULT_SPU_TRACK_INFO:
671          _player_spu_tracks_info(ev);
672          break;
673       case EM_RESULT_META_INFO:
674          _player_meta_info_read(ev);
675          break;
676       default:
677          WRN("received wrong command: %d", ev->cmd.type);
678    }
679
680    ev->cmd.type = -1;
681 }
682
683 static void
684 _player_cmd_single_int_process(Emotion_Generic_Video *ev)
685 {
686    if (!_player_cmd_param_read(ev, &ev->cmd.param.i_num, sizeof(ev->cmd.param.i_num)))
687      return;
688
689    _player_cmd_process(ev);
690 }
691
692 static void
693 _player_cmd_single_float_process(Emotion_Generic_Video *ev)
694 {
695    if (!_player_cmd_param_read(ev, &ev->cmd.param.f_num, sizeof(ev->cmd.param.f_num)))
696      return;
697
698    _player_cmd_process(ev);
699 }
700
701 static void
702 _player_cmd_double_int_process(Emotion_Generic_Video *ev)
703 {
704    int param;
705
706    if (ev->cmd.num_params == 0)
707      {
708         ev->cmd.num_params = 2;
709         ev->cmd.cur_param = 0;
710         ev->cmd.param.size.width = 0;
711         ev->cmd.param.size.height = 0;
712      }
713
714    if (!_player_cmd_param_read(ev, &param, sizeof(param)))
715      return;
716
717    if (ev->cmd.cur_param == 0)
718      ev->cmd.param.size.width = param;
719    else
720      ev->cmd.param.size.height = param;
721
722    ev->cmd.cur_param++;
723    if (ev->cmd.cur_param == ev->cmd.num_params)
724      _player_cmd_process(ev);
725 }
726
727 static void
728 _player_cmd_read(Emotion_Generic_Video *ev)
729 {
730    if (ev->cmd.type < 0)
731      {
732         if (!_player_cmd_param_read(ev, &ev->cmd.type, sizeof(ev->cmd.type)))
733           return;
734         else
735           ev->cmd.num_params = 0;
736      }
737
738    switch (ev->cmd.type) {
739       case EM_RESULT_INIT:
740       case EM_RESULT_FILE_SET:
741       case EM_RESULT_PLAYBACK_STOPPED:
742       case EM_RESULT_FILE_CLOSE:
743       case EM_RESULT_FRAME_NEW:
744          _player_cmd_process(ev);
745          break;
746       case EM_RESULT_FILE_SET_DONE:
747       case EM_RESULT_SEEKABLE_CHANGED:
748          _player_cmd_single_int_process(ev);
749          break;
750       case EM_RESULT_LENGTH_CHANGED:
751       case EM_RESULT_POSITION_CHANGED:
752          _player_cmd_single_float_process(ev);
753          break;
754       case EM_RESULT_FRAME_SIZE:
755          _player_cmd_double_int_process(ev);
756          break;
757
758       default:
759          WRN("received wrong command: %d", ev->cmd.type);
760          ev->cmd.type = -1;
761    }
762 }
763
764 static Eina_Bool
765 _player_cmd_handler_cb(void *data, Ecore_Fd_Handler *fd_handler)
766 {
767    Emotion_Generic_Video *ev = data;
768
769    if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
770      {
771         ERR("an error occurred on fd_read %d.", ev->fd_read);
772         return ECORE_CALLBACK_CANCEL;
773      }
774
775    _player_cmd_read(ev);
776
777    return ECORE_CALLBACK_RENEW;
778 }
779
780 static Eina_Bool
781 _player_data_cb(void *data, int type __UNUSED__, void *event)
782 {
783    Ecore_Exe_Event_Data *ev = event;
784    Emotion_Generic_Video *evideo = data;
785    int i;
786
787    if (ev->exe != evideo->player.exe)
788      {
789         ERR("slave != ev->exe");
790         return ECORE_CALLBACK_DONE;
791      }
792
793    for (i = 0; ev->lines[i].line; i++)
794      INF("received input from player: \"%s\"", ev->lines[i].line);
795
796    return ECORE_CALLBACK_DONE;
797 }
798
799 static Eina_Bool
800 _player_add_cb(void *data, int type __UNUSED__, void *event)
801 {
802    Ecore_Exe_Event_Add *event_add = event;
803    Ecore_Exe *player = event_add->exe;
804    Emotion_Generic_Video *ev = data;
805
806    if (ev->player.exe != player)
807      {
808         ERR("ev->player != player.");
809         return ECORE_CALLBACK_DONE;
810      }
811
812    _player_send_cmd(ev, EM_CMD_INIT);
813    _player_send_str(ev, ev->shmname, EINA_TRUE);
814
815    return ECORE_CALLBACK_DONE;
816 }
817
818 static Eina_Bool
819 _player_del_cb(void *data, int type __UNUSED__, void *event __UNUSED__)
820 {
821    Emotion_Generic_Video *ev = data;
822    ERR("player died.");
823
824    ev->player.exe = NULL;
825    ev->ready = EINA_FALSE;
826    ev->file_ready = EINA_FALSE;
827    ecore_main_fd_handler_del(ev->fd_handler);
828    close(ev->fd_read);
829    close(ev->fd_write);
830    ev->fd_read = -1;
831    ev->fd_write = -1;
832    _emotion_decode_stop(ev->obj);
833
834    return ECORE_CALLBACK_DONE;
835 }
836
837 static Eina_Bool
838 _player_exec(Emotion_Generic_Video *ev)
839 {
840    int pipe_out[2];
841    int pipe_in[2];
842    char buf[PATH_MAX];
843
844    if (pipe(pipe_out) == -1)
845      {
846         ERR("could not create pipe for communication emotion -> player: %s", strerror(errno));
847         return EINA_FALSE;
848      }
849
850    if (pipe(pipe_in) == -1)
851      {
852         ERR("could not create pipe for communication player -> emotion: %s", strerror(errno));
853         close(pipe_out[0]);
854         close(pipe_out[1]);
855         return EINA_FALSE;
856      }
857
858    snprintf(buf, sizeof(buf), "%s %d %d\n", ev->cmdline, pipe_out[0], pipe_in[1]);
859
860    ev->player.exe = ecore_exe_pipe_run(
861       buf,
862       ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE |
863       ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_NOT_LEADER,
864       ev);
865
866    INF("created pipe emotion -> player: %d -> %d\n", pipe_out[1], pipe_out[0]);
867    INF("created pipe player -> emotion: %d -> %d\n", pipe_in[1], pipe_in[0]);
868
869    close(pipe_in[1]);
870    close(pipe_out[0]);
871
872    if (!ev->player.exe)
873      {
874         close(pipe_in[0]);
875         close(pipe_out[1]);
876         return EINA_FALSE;
877      }
878
879    ev->fd_read = pipe_in[0];
880    ev->fd_write = pipe_out[1];
881
882    ev->fd_handler = ecore_main_fd_handler_add(
883       ev->fd_read, ECORE_FD_READ | ECORE_FD_ERROR, _player_cmd_handler_cb, ev,
884       NULL, NULL);
885
886    return EINA_TRUE;
887 }
888
889 static Eina_Bool
890 _fork_and_exec(Evas_Object *obj, Emotion_Generic_Video *ev)
891 {
892    char shmname[256];
893    struct timeval tv;
894
895    gettimeofday(&tv, NULL);
896    snprintf(shmname, sizeof(shmname), "/em-generic-shm_%d_%d",
897             (int)tv.tv_sec, (int)tv.tv_usec);
898
899    ev->shmname = eina_stringshare_add(shmname);
900
901    ev->player_add = ecore_event_handler_add(
902       ECORE_EXE_EVENT_ADD, _player_add_cb, ev);
903    ev->player_del = ecore_event_handler_add(
904       ECORE_EXE_EVENT_DEL, _player_del_cb, ev);
905    ev->player_data = ecore_event_handler_add(
906       ECORE_EXE_EVENT_DATA, _player_data_cb, ev);
907
908
909    if (!_player_exec(ev))
910      {
911         ERR("could not start player.");
912         return EINA_FALSE;
913      }
914
915    ev->initializing = EINA_TRUE;
916
917    return EINA_TRUE;
918 }
919
920 static unsigned char
921 em_init(Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt)
922 {
923    Emotion_Generic_Video *ev;
924    const char *player;
925
926    if (!emotion_video) return 0;
927    player = _get_player(opt ? opt->player : NULL);
928    if (!player) return 0;
929
930    ev = (Emotion_Generic_Video *)calloc(1, sizeof(*ev));
931    if (!ev) return 0;
932
933    ev->fd_read = -1;
934    ev->fd_write = -1;
935    ev->speed = 1.0;
936    ev->volume = 0.5;
937    ev->audio_mute = EINA_FALSE;
938    ev->cmd.type = -1;
939
940    ev->obj = obj;
941    ev->cmdline = eina_stringshare_add(player);
942    *emotion_video = ev;
943
944    return _fork_and_exec(obj, ev);
945 }
946
947 static int
948 em_shutdown(void *data)
949 {
950    Emotion_Generic_Video *ev = data;
951
952    if (!ev) return 0;
953
954    if (ev->player.exe)
955      {
956         ecore_exe_terminate(ev->player.exe);
957         ecore_exe_free(ev->player.exe);
958         ev->player.exe = NULL;
959      }
960
961    if (ev->shared)
962      munmap(ev->shared, ev->shared->size);
963
964    if (ev->fd_read >= 0)
965      close(ev->fd_read);
966    if (ev->fd_write >= 0)
967      close(ev->fd_write);
968    if (ev->fd_handler)
969      ecore_main_fd_handler_del(ev->fd_handler);
970
971    eina_stringshare_del(ev->cmdline);
972    eina_stringshare_del(ev->shmname);
973
974    ecore_event_handler_del(ev->player_add);
975    ecore_event_handler_del(ev->player_data);
976    ecore_event_handler_del(ev->player_del);
977
978    return 1;
979 }
980
981 static unsigned char
982 em_file_open(const char *file, Evas_Object *obj __UNUSED__, void *data)
983 {
984    Emotion_Generic_Video *ev = data;
985    INF("file set: %s", file);
986    if (!ev) return 0;
987
988    eina_stringshare_replace(&ev->filename, file);
989
990    ev->pos = 0;
991    ev->w = 0;
992    ev->h = 0;
993    ev->ratio = 1;
994    ev->len = 0;
995
996    if (ev->ready && ev->opening)
997      {
998         INF("file changed while opening.");
999         ev->file_changed = EINA_TRUE;
1000         return 1;
1001      }
1002
1003    ev->opening = EINA_TRUE;
1004
1005    if (!ev->closing)
1006      _file_open(ev);
1007
1008    return 1;
1009 }
1010
1011 static void
1012 em_file_close(void *data)
1013 {
1014    Emotion_Generic_Video *ev = data;
1015
1016    if (!ev || !ev->filename) return;
1017
1018    INF("file close: %s", ev->filename);
1019
1020    eina_stringshare_replace(&ev->filename, NULL);
1021
1022    ev->file_ready = EINA_FALSE;
1023    _audio_channels_free(ev);
1024    _video_channels_free(ev);
1025    _spu_channels_free(ev);
1026    _player_meta_info_free(ev);
1027
1028    if (ev->opening)
1029      return;
1030
1031    _player_send_cmd(ev, EM_CMD_FILE_CLOSE);
1032    ev->closing = EINA_TRUE;
1033 }
1034
1035 static Emotion_Format
1036 em_format_get(void *ef __UNUSED__)
1037 {
1038    return EMOTION_FORMAT_BGRA;
1039 }
1040
1041 static void
1042 em_video_data_size_get(void *data, int *w, int *h)
1043 {
1044    Emotion_Generic_Video *ev = data;
1045
1046    if (!ev) return;
1047    if (w) *w = ev->w;
1048    if (h) *h = ev->h;
1049 }
1050
1051 static void
1052 em_play(void *data, double pos)
1053 {
1054    Emotion_Generic_Video *ev = data;
1055
1056    if (!ev)
1057      return;
1058
1059    ev->play = EINA_TRUE;
1060    INF("play: %0.3f", pos);
1061
1062    if (ev->initializing || ev->opening)
1063      return;
1064
1065    if (ev->ready)
1066      {
1067         _player_send_cmd(ev, EM_CMD_PLAY);
1068         _player_send_float(ev, ev->pos);
1069         return;
1070      }
1071
1072    if (!_player_exec(ev))
1073      ERR("could not start player.");
1074 }
1075
1076 static void
1077 em_stop(void *data)
1078 {
1079    Emotion_Generic_Video *ev = data;
1080
1081    if (!ev)
1082      return;
1083
1084    ev->play = EINA_FALSE;
1085
1086    if (!ev->file_ready)
1087      return;
1088
1089    _player_send_cmd(ev, EM_CMD_STOP);
1090    _emotion_decode_stop(ev->obj);
1091 }
1092
1093 static void
1094 em_size_get(void *data, int *w, int *h)
1095 {
1096    Emotion_Generic_Video *ev = data;
1097    if (w) *w = ev->w;
1098    if (h) *h = ev->h;
1099 }
1100
1101 static void
1102 em_pos_set(void *data, double pos)
1103 {
1104    Emotion_Generic_Video *ev = data;
1105    float position = pos;
1106
1107    if (!ev->file_ready)
1108      return;
1109
1110    _player_send_cmd(ev, EM_CMD_POSITION_SET);
1111    _player_send_float(ev, position);
1112    _emotion_seek_done(ev->obj);
1113 }
1114
1115 static double
1116 em_len_get(void *data)
1117 {
1118    Emotion_Generic_Video *ev = data;
1119    return ev->len;
1120 }
1121
1122 static int
1123 em_fps_num_get(void *data)
1124 {
1125    Emotion_Generic_Video *ev = data;
1126    return (int)(ev->fps * 1000.0);
1127 }
1128
1129 static int
1130 em_fps_den_get(void *ef __UNUSED__)
1131 {
1132    return 1000;
1133 }
1134
1135 static double
1136 em_fps_get(void *data)
1137 {
1138    Emotion_Generic_Video *ev = data;
1139    return ev->fps;
1140 }
1141
1142 static double
1143 em_pos_get(void *data)
1144 {
1145    Emotion_Generic_Video *ev = data;
1146    return ev->pos;
1147 }
1148
1149 static void
1150 em_vis_set(void *ef __UNUSED__, Emotion_Vis vis __UNUSED__)
1151 {
1152 }
1153
1154 static Emotion_Vis
1155 em_vis_get(void *data)
1156 {
1157    Emotion_Generic_Video *ev = data;
1158    return ev->vis;
1159 }
1160
1161 static Eina_Bool
1162 em_vis_supported(void *ef __UNUSED__, Emotion_Vis vis __UNUSED__)
1163 {
1164    return EINA_FALSE;
1165 }
1166
1167 static double
1168 em_ratio_get(void *data)
1169 {
1170    Emotion_Generic_Video *ev = data;
1171    return ev->ratio;
1172 }
1173
1174 static int em_video_handled(void *ef __UNUSED__)
1175 {
1176    fprintf(stderr, "video handled!\n");
1177    return 1;
1178 }
1179
1180 static int em_audio_handled(void *ef __UNUSED__)
1181 {
1182    fprintf(stderr, "audio handled!\n");
1183    return 1;
1184 }
1185
1186 static int em_seekable(void *data)
1187 {
1188    Emotion_Generic_Video *ev = data;
1189    return ev->seekable;
1190 }
1191
1192 static void em_frame_done(void *ef __UNUSED__)
1193 {
1194 }
1195
1196 static int
1197 em_yuv_rows_get(void *data __UNUSED__, int w __UNUSED__, int h __UNUSED__, unsigned char **yrows __UNUSED__, unsigned char **urows __UNUSED__, unsigned char **vrows __UNUSED__)
1198 {
1199    return 0;
1200 }
1201
1202 static int
1203 em_bgra_data_get(void *data, unsigned char **bgra_data)
1204 {
1205    Emotion_Generic_Video *ev = data;
1206
1207    if (!ev || !ev->file_ready)
1208      return;
1209
1210    // lock frame here
1211    sem_wait(&ev->shared->lock);
1212
1213    // send current frame to emotion
1214    if (ev->shared->frame.emotion != ev->shared->frame.last)
1215      {
1216         ev->shared->frame.next = ev->shared->frame.emotion;
1217         ev->shared->frame.emotion = ev->shared->frame.last;
1218      }
1219    *bgra_data = ev->frame.frames[ev->shared->frame.emotion];
1220
1221    if (ev->shared->frame_drop > 1)
1222      WRN("dropped frames: %d", ev->shared->frame_drop - 1);
1223    ev->shared->frame_drop = 0;
1224
1225    // unlock frame here
1226    sem_post(&ev->shared->lock);
1227    ev->drop = 0;
1228
1229    return 1;
1230 }
1231
1232 static void
1233 em_event_feed(void *ef __UNUSED__, int event __UNUSED__)
1234 {
1235 }
1236
1237 static void
1238 em_event_mouse_button_feed(void *ef __UNUSED__, int button __UNUSED__, int x __UNUSED__, int y __UNUSED__)
1239 {
1240 }
1241
1242 static void
1243 em_event_mouse_move_feed(void *ef __UNUSED__, int x __UNUSED__, int y __UNUSED__)
1244 {
1245 }
1246
1247 static int
1248 em_video_channel_count(void *data)
1249 {
1250    Emotion_Generic_Video *ev = data;
1251    return ev->video_channels_count;
1252 }
1253
1254 static void
1255 em_video_channel_set(void *data, int channel)
1256 {
1257    Emotion_Generic_Video *ev = data;
1258
1259    if (channel < 0 || channel >= ev->video_channels_count)
1260      {
1261         WRN("video channel out of range.");
1262         return;
1263      }
1264
1265    _player_send_cmd(ev, EM_CMD_VIDEO_TRACK_SET);
1266    _player_send_int(ev, ev->video_channels[channel].id);
1267    ev->video_channel_current = channel;
1268 }
1269
1270 static int
1271 em_video_channel_get(void *data)
1272 {
1273    Emotion_Generic_Video *ev = data;
1274    return ev->video_channel_current;
1275 }
1276
1277 static const char *
1278 em_video_channel_name_get(void *data, int channel)
1279 {
1280    Emotion_Generic_Video *ev = data;
1281
1282    if (channel < 0 || channel >= ev->video_channels_count)
1283      {
1284         WRN("video channel out of range.");
1285         return NULL;
1286      }
1287
1288    return ev->video_channels[channel].name;
1289 }
1290
1291 static void
1292 em_video_channel_mute_set(void *data, int mute)
1293 {
1294    Emotion_Generic_Video *ev = data;
1295
1296    ev->video_mute = !!mute;
1297
1298    if (!ev || !ev->file_ready)
1299      return;
1300
1301    _player_send_cmd(ev, EM_CMD_VIDEO_MUTE_SET);
1302    _player_send_int(ev, mute);
1303 }
1304
1305 static int
1306 em_video_channel_mute_get(void *data)
1307 {
1308    Emotion_Generic_Video *ev = data;
1309    return ev->video_mute;
1310 }
1311
1312 static int
1313 em_audio_channel_count(void *data)
1314 {
1315    Emotion_Generic_Video *ev = data;
1316    return ev->audio_channels_count;
1317 }
1318
1319 static void
1320 em_audio_channel_set(void *data, int channel)
1321 {
1322    Emotion_Generic_Video *ev = data;
1323
1324    if (channel < 0 || channel >= ev->audio_channels_count)
1325      {
1326         WRN("audio channel out of range.");
1327         return;
1328      }
1329
1330    _player_send_cmd(ev, EM_CMD_AUDIO_TRACK_SET);
1331    _player_send_int(ev, ev->audio_channels[channel].id);
1332    ev->audio_channel_current = channel;
1333 }
1334
1335 static int
1336 em_audio_channel_get(void *data)
1337 {
1338    Emotion_Generic_Video *ev = data;
1339    return ev->audio_channel_current;
1340 }
1341
1342 static const char *
1343 em_audio_channel_name_get(void *data, int channel)
1344 {
1345    Emotion_Generic_Video *ev = data;
1346
1347    if (channel < 0 || channel >= ev->audio_channels_count)
1348      {
1349         WRN("audio channel out of range.");
1350         return NULL;
1351      }
1352
1353    return ev->audio_channels[channel].name;
1354 }
1355
1356 static void
1357 em_audio_channel_mute_set(void *data, int mute)
1358 {
1359    Emotion_Generic_Video *ev = data;
1360
1361    ev->audio_mute = !!mute;
1362
1363    if (!ev || !ev->file_ready)
1364      return;
1365
1366    _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET);
1367    _player_send_int(ev, mute);
1368 }
1369
1370 static int
1371 em_audio_channel_mute_get(void *data)
1372 {
1373    Emotion_Generic_Video *ev = data;
1374    return ev->audio_mute;
1375 }
1376
1377 static void
1378 em_audio_channel_volume_set(void *data, double vol)
1379 {
1380    Emotion_Generic_Video *ev = data;
1381
1382    if (vol > 1.0) vol = 1.0;
1383    if (vol < 0.0) vol = 0.0;
1384
1385    ev->volume = vol;
1386
1387    if (!ev || !ev->file_ready)
1388      return;
1389
1390    _player_send_cmd(ev, EM_CMD_VOLUME_SET);
1391    _player_send_float(ev, ev->volume);
1392 }
1393
1394 static double
1395 em_audio_channel_volume_get(void *data)
1396 {
1397    Emotion_Generic_Video *ev = data;
1398    return ev->volume;
1399 }
1400
1401 static int
1402 em_spu_channel_count(void *data)
1403 {
1404    Emotion_Generic_Video *ev = data;
1405    return ev->spu_channels_count;
1406 }
1407
1408 static void
1409 em_spu_channel_set(void *data, int channel)
1410 {
1411    Emotion_Generic_Video *ev = data;
1412
1413    if (channel < 0 || channel >= ev->spu_channels_count)
1414      {
1415         WRN("spu channel out of range.");
1416         return;
1417      }
1418
1419    _player_send_cmd(ev, EM_CMD_SPU_TRACK_SET);
1420    _player_send_int(ev, ev->spu_channels[channel].id);
1421    ev->spu_channel_current = channel;
1422 }
1423
1424 static int
1425 em_spu_channel_get(void *data)
1426 {
1427    Emotion_Generic_Video *ev = data;
1428    return ev->spu_channel_current;
1429 }
1430
1431 static const char *
1432 em_spu_channel_name_get(void *data, int channel)
1433 {
1434    Emotion_Generic_Video *ev = data;
1435
1436    if (channel < 0 || channel >= ev->spu_channels_count)
1437      {
1438         WRN("spu channel out of range.");
1439         return NULL;
1440      }
1441
1442    return ev->spu_channels[channel].name;
1443 }
1444
1445 static void
1446 em_spu_channel_mute_set(void *data, int mute)
1447 {
1448    Emotion_Generic_Video *ev = data;
1449
1450    ev->spu_mute = !!mute;
1451
1452    if (!ev || !ev->file_ready)
1453      return;
1454
1455    _player_send_cmd(ev, EM_CMD_SPU_MUTE_SET);
1456    _player_send_int(ev, mute);
1457 }
1458
1459 static int
1460 em_spu_channel_mute_get(void *data)
1461 {
1462    Emotion_Generic_Video *ev = data;
1463    return ev->spu_mute;
1464 }
1465
1466 static int
1467 em_chapter_count(void *ef __UNUSED__)
1468 {
1469    int num = 0;
1470    return num;
1471 }
1472
1473 static void
1474 em_chapter_set(void *ef __UNUSED__, int chapter __UNUSED__)
1475 {
1476 }
1477
1478 static int
1479 em_chapter_get(void *ef __UNUSED__)
1480 {
1481    int num = 0;
1482    return num;
1483 }
1484
1485 static const char *
1486 em_chapter_name_get(void *ef __UNUSED__, int chapter __UNUSED__)
1487 {
1488    return NULL;
1489 }
1490
1491 static void
1492 em_speed_set(void *data, double speed)
1493 {
1494    Emotion_Generic_Video *ev = data;
1495    float rate = speed;
1496    ev->speed = rate;
1497
1498    if (!ev || !ev->file_ready)
1499      return;
1500
1501    _player_send_cmd(ev, EM_CMD_SPEED_SET);
1502    _player_send_float(ev, rate);
1503 }
1504
1505 static double
1506 em_speed_get(void *data)
1507 {
1508    Emotion_Generic_Video *ev = data;
1509    return (double)ev->speed;
1510 }
1511
1512 static int
1513 em_eject(void *ef __UNUSED__)
1514 {
1515    return 1;
1516 }
1517
1518 static const char *
1519 em_meta_get(void *data, int meta)
1520 {
1521    Emotion_Generic_Video *ev = data;
1522
1523    switch (meta) {
1524       case EMOTION_META_INFO_TRACK_TITLE:
1525          return ev->meta.title;
1526       case EMOTION_META_INFO_TRACK_ARTIST:
1527          return ev->meta.artist;
1528       case EMOTION_META_INFO_TRACK_ALBUM:
1529          return ev->meta.album;
1530       case EMOTION_META_INFO_TRACK_YEAR:
1531          return ev->meta.year;
1532       case EMOTION_META_INFO_TRACK_GENRE:
1533          return ev->meta.genre;
1534       case EMOTION_META_INFO_TRACK_COMMENT:
1535          return ev->meta.comment;
1536       case EMOTION_META_INFO_TRACK_DISC_ID:
1537          return ev->meta.disc_id;
1538       case EMOTION_META_INFO_TRACK_COUNT:
1539          return ev->meta.count;
1540    }
1541
1542    return NULL;
1543 }
1544
1545 static Emotion_Video_Module em_module =
1546 {
1547    em_init, /* init */
1548    em_shutdown, /* shutdown */
1549    em_file_open, /* file_open */
1550    em_file_close, /* file_close */
1551    em_play, /* play */
1552    em_stop, /* stop */
1553    em_size_get, /* size_get */
1554    em_pos_set, /* pos_set */
1555    em_len_get, /* len_get */
1556    em_fps_num_get, /* fps_num_get */
1557    em_fps_den_get, /* fps_den_get */
1558    em_fps_get, /* fps_get */
1559    em_pos_get, /* pos_get */
1560    em_vis_set, /* vis_set */
1561    em_vis_get, /* vis_get */
1562    em_vis_supported, /* vis_supported */
1563    em_ratio_get, /* ratio_get */
1564    em_video_handled, /* video_handled */
1565    em_audio_handled, /* audio_handled */
1566    em_seekable, /* seekable */
1567    em_frame_done, /* frame_done */
1568    em_format_get, /* format_get */
1569    em_video_data_size_get, /* video_data_size_get */
1570    em_yuv_rows_get, /* yuv_rows_get */
1571    em_bgra_data_get, /* bgra_data_get */
1572    em_event_feed, /* event_feed */
1573    em_event_mouse_button_feed, /* event_mouse_button_feed */
1574    em_event_mouse_move_feed, /* event_mouse_move_feed */
1575    em_video_channel_count, /* video_channel_count */
1576    em_video_channel_set, /* video_channel_set */
1577    em_video_channel_get, /* video_channel_get */
1578    em_video_channel_name_get, /* video_channel_name_get */
1579    em_video_channel_mute_set, /* video_channel_mute_set */
1580    em_video_channel_mute_get, /* video_channel_mute_get */
1581    em_audio_channel_count, /* audio_channel_count */
1582    em_audio_channel_set, /* audio_channel_set */
1583    em_audio_channel_get, /* audio_channel_get */
1584    em_audio_channel_name_get, /* audio_channel_name_get */
1585    em_audio_channel_mute_set, /* audio_channel_mute_set */
1586    em_audio_channel_mute_get, /* audio_channel_mute_get */
1587    em_audio_channel_volume_set, /* audio_channel_volume_set */
1588    em_audio_channel_volume_get, /* audio_channel_volume_get */
1589    em_spu_channel_count, /* spu_channel_count */
1590    em_spu_channel_set, /* spu_channel_set */
1591    em_spu_channel_get, /* spu_channel_get */
1592    em_spu_channel_name_get, /* spu_channel_name_get */
1593    em_spu_channel_mute_set, /* spu_channel_mute_set */
1594    em_spu_channel_mute_get, /* spu_channel_mute_get */
1595    em_chapter_count, /* chapter_count */
1596    em_chapter_set, /* chapter_set */
1597    em_chapter_get, /* chapter_get */
1598    em_chapter_name_get, /* chapter_name_get */
1599    em_speed_set, /* speed_set */
1600    em_speed_get, /* speed_get */
1601    em_eject, /* eject */
1602    em_meta_get, /* meta_get */
1603    NULL /* handle */
1604 };
1605
1606 static Eina_Bool
1607 module_open(Evas_Object *obj, const Emotion_Video_Module **module, void **video, Emotion_Module_Options *opt)
1608 {
1609    if (!module) {
1610         return EINA_FALSE;
1611    }
1612
1613    if (_emotion_generic_log_domain < 0)
1614      {
1615         eina_threads_init();
1616         eina_log_threads_enable();
1617         _emotion_generic_log_domain = eina_log_domain_register
1618           ("emotion-generic", EINA_COLOR_LIGHTCYAN);
1619         if (_emotion_generic_log_domain < 0)
1620           {
1621              EINA_LOG_CRIT("Could not register log domain 'emotion-generic'");
1622              return EINA_FALSE;
1623           }
1624      }
1625
1626
1627    if (!em_module.init(obj, video, opt))        {
1628         return EINA_FALSE;
1629    }
1630
1631    *module = &em_module;
1632
1633    return EINA_TRUE;
1634 }
1635
1636 static void module_close(Emotion_Video_Module *module __UNUSED__, void *video)
1637 {
1638         em_module.shutdown(video);
1639 }
1640
1641
1642 Eina_Bool
1643 generic_module_init(void)
1644 {
1645    if (!pfx)
1646      {
1647         pfx = eina_prefix_new(NULL, emotion_object_add,
1648                               "EMOTION", "emotion", NULL,
1649                               PACKAGE_BIN_DIR,
1650                               PACKAGE_LIB_DIR,
1651                               PACKAGE_DATA_DIR,
1652                               "");
1653         if (!pfx) return EINA_FALSE;
1654      }
1655    return _emotion_module_register("generic", module_open, module_close);
1656 }
1657
1658 static void
1659 generic_module_shutdown(void)
1660 {
1661    if (pfx)
1662      {
1663         eina_prefix_free(pfx);
1664         pfx = NULL;
1665      }
1666    _emotion_module_unregister("generic");
1667 }
1668
1669 #ifndef EMOTION_STATIC_BUILD_GENERIC
1670
1671 EINA_MODULE_INIT(generic_module_init);
1672 EINA_MODULE_SHUTDOWN(generic_module_shutdown);
1673
1674 #endif
1675