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