1e2d139535ae2f3877a72795d7b3298da279a892
[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 /* hmmm. no _emotion_progress_set() is for "buffering" progress.
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
347 static void
348 _player_seekable_changed(Emotion_Generic_Video *ev)
349 {
350    int seekable = ev->cmd.param.i_num;
351
352    INF("received seekable changed: %d", seekable);
353
354    seekable = !!seekable;
355
356    ev->seekable = seekable;
357 }
358
359 static void
360 _audio_channels_free(Emotion_Generic_Video *ev)
361 {
362    int i;
363    for (i = 0; i < ev->audio_channels_count; i++)
364      eina_stringshare_del(ev->audio_channels[i].name);
365    free(ev->audio_channels);
366    ev->audio_channels_count = 0;
367 }
368
369 static void
370 _video_channels_free(Emotion_Generic_Video *ev)
371 {
372    int i;
373    for (i = 0; i < ev->video_channels_count; i++)
374      eina_stringshare_del(ev->video_channels[i].name);
375    free(ev->video_channels);
376    ev->video_channels_count = 0;
377 }
378
379 static void
380 _spu_channels_free(Emotion_Generic_Video *ev)
381 {
382    int i;
383    for (i = 0; i < ev->spu_channels_count; i++)
384      eina_stringshare_del(ev->spu_channels[i].name);
385    free(ev->spu_channels);
386    ev->spu_channels_count = 0;
387 }
388
389 static void
390 _player_tracks_info(Emotion_Generic_Video *ev, Emotion_Generic_Channel **channels, int *count, int *current)
391 {
392    Emotion_Generic_Channel *pchannels;
393    int i;
394
395    *count = ev->cmd.param.track.total;
396    *current = ev->cmd.param.track.current;
397    pchannels = ev->cmd.param.track.channels;
398
399    INF("number of tracks: %d (current = %d):", *count, *current);
400    for (i = 0; i < *count; i++)
401      {
402         INF("\tchannel %d: %s", pchannels[i].id, pchannels[i].name);
403      }
404
405    *channels = pchannels;
406 }
407
408 static void
409 _player_audio_tracks_info(Emotion_Generic_Video *ev)
410 {
411    INF("Receiving audio channels:");
412    if (ev->audio_channels_count)
413      _audio_channels_free(ev);
414
415    _player_tracks_info(ev, &ev->audio_channels, &ev->audio_channels_count,
416                        &ev->audio_channel_current);
417 }
418
419 static void
420 _player_video_tracks_info(Emotion_Generic_Video *ev)
421 {
422    INF("Receiving video channels:");
423    if (ev->video_channels_count)
424      _video_channels_free(ev);
425
426    _player_tracks_info(ev, &ev->video_channels, &ev->video_channels_count,
427                        &ev->video_channel_current);
428 }
429
430 static void
431 _player_spu_tracks_info(Emotion_Generic_Video *ev)
432 {
433    INF("Receiving spu channels:");
434    if (ev->spu_channels_count)
435      _spu_channels_free(ev);
436
437    _player_tracks_info(ev, &ev->spu_channels, &ev->spu_channels_count,
438                        &ev->spu_channel_current);
439 }
440
441 static void
442 _player_meta_info_free(Emotion_Generic_Video *ev)
443 {
444    eina_stringshare_replace(&ev->meta.title, NULL);
445    eina_stringshare_replace(&ev->meta.artist, NULL);
446    eina_stringshare_replace(&ev->meta.album, NULL);
447    eina_stringshare_replace(&ev->meta.year, NULL);
448    eina_stringshare_replace(&ev->meta.genre, NULL);
449    eina_stringshare_replace(&ev->meta.comment, NULL);
450    eina_stringshare_replace(&ev->meta.disc_id, NULL);
451    eina_stringshare_replace(&ev->meta.count, NULL);
452 }
453
454 static void
455 _player_meta_info_read(Emotion_Generic_Video *ev)
456 {
457    INF("Receiving meta info:");
458    _player_meta_info_free(ev);
459    ev->meta.title = ev->cmd.param.meta.title;
460    ev->meta.artist = ev->cmd.param.meta.artist;
461    ev->meta.album = ev->cmd.param.meta.album;
462    ev->meta.year = ev->cmd.param.meta.year;
463    ev->meta.genre = ev->cmd.param.meta.genre;
464    ev->meta.comment = ev->cmd.param.meta.comment;
465    ev->meta.disc_id = ev->cmd.param.meta.disc_id;
466    ev->meta.count = ev->cmd.param.meta.count;
467    INF("title: '%s'", ev->meta.title);
468    INF("artist: '%s'", ev->meta.artist);
469    INF("album: '%s'", ev->meta.album);
470    INF("year: '%s'", ev->meta.year);
471    INF("genre: '%s'", ev->meta.genre);
472    INF("comment: '%s'", ev->meta.comment);
473    INF("disc_id: '%s'", ev->meta.disc_id);
474    INF("count: '%s'", ev->meta.count);
475 }
476
477 static void
478 _player_file_closed(Emotion_Generic_Video *ev)
479 {
480    INF("Closed previous file.");
481    eina_semaphore_free(&ev->shared->lock);
482    ev->closing = EINA_FALSE;
483
484    if (ev->opening)
485      _file_open(ev);
486 }
487
488 static void
489 _player_open_done(Emotion_Generic_Video *ev)
490 {
491    int success;
492
493    success = ev->cmd.param.i_num;
494    shm_unlink(ev->shmname);
495
496    if (ev->file_changed)
497      {
498         _file_open(ev);
499         ev->file_changed = EINA_FALSE;
500         return;
501      }
502
503    ev->opening = EINA_FALSE;
504    if (!success)
505      {
506         ERR("Could not open file.");
507         return;
508      }
509
510    ev->file_ready = EINA_TRUE;
511
512    _emotion_open_done(ev->obj);
513
514    if (ev->play)
515      {
516         _player_send_cmd(ev, EM_CMD_PLAY);
517         _player_send_float(ev, ev->pos);
518      }
519
520    _player_send_cmd(ev, EM_CMD_VOLUME_SET);
521    _player_send_float(ev, ev->volume);
522
523    _player_send_cmd(ev, EM_CMD_SPEED_SET);
524    _player_send_float(ev, ev->speed);
525
526    int mute = ev->audio_mute;
527    _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET);
528    _player_send_int(ev, mute);
529
530    mute = ev->video_mute;
531    _player_send_cmd(ev, EM_CMD_VIDEO_MUTE_SET);
532    _player_send_int(ev, mute);
533
534    mute = ev->spu_mute;
535    _player_send_cmd(ev, EM_CMD_SPU_MUTE_SET);
536    _player_send_int(ev, mute);
537
538    INF("Open done");
539 }
540
541 static void
542 _player_cmd_process(Emotion_Generic_Video *ev)
543 {
544    switch (ev->cmd.type) {
545       case EM_RESULT_INIT:
546          _player_ready(ev);
547          break;
548       case EM_RESULT_FRAME_NEW:
549          _player_new_frame(ev);
550          break;
551       case EM_RESULT_FILE_SET:
552          _player_file_set_done(ev);
553          break;
554       case EM_RESULT_FILE_SET_DONE:
555          _player_open_done(ev);
556          break;
557       case EM_RESULT_FILE_CLOSE:
558          _player_file_closed(ev);
559          break;
560       case EM_RESULT_PLAYBACK_STOPPED:
561          _emotion_playback_finished(ev->obj);
562          break;
563       case EM_RESULT_FRAME_SIZE:
564          _player_frame_resize(ev);
565          break;
566       case EM_RESULT_LENGTH_CHANGED:
567          _player_length_changed(ev);
568          break;
569       case EM_RESULT_POSITION_CHANGED:
570          _player_position_changed(ev);
571          break;
572       case EM_RESULT_SEEKABLE_CHANGED:
573          _player_seekable_changed(ev);
574          break;
575       case EM_RESULT_AUDIO_TRACK_INFO:
576          _player_audio_tracks_info(ev);
577          break;
578       case EM_RESULT_VIDEO_TRACK_INFO:
579          _player_video_tracks_info(ev);
580          break;
581       case EM_RESULT_SPU_TRACK_INFO:
582          _player_spu_tracks_info(ev);
583          break;
584       case EM_RESULT_META_INFO:
585          _player_meta_info_read(ev);
586          break;
587       default:
588          WRN("received wrong command: %d", ev->cmd.type);
589    }
590
591    ev->cmd.type = -1;
592 }
593
594 static void
595 _player_cmd_single_int_process(Emotion_Generic_Video *ev)
596 {
597    if (!_player_cmd_param_read(ev, &ev->cmd.param.i_num, sizeof(ev->cmd.param.i_num)))
598      return;
599
600    _player_cmd_process(ev);
601 }
602
603 static void
604 _player_cmd_single_float_process(Emotion_Generic_Video *ev)
605 {
606    if (!_player_cmd_param_read(ev, &ev->cmd.param.f_num, sizeof(ev->cmd.param.f_num)))
607      return;
608
609    _player_cmd_process(ev);
610 }
611
612 static void
613 _player_cmd_double_int_process(Emotion_Generic_Video *ev)
614 {
615    int param;
616
617    if (ev->cmd.num_params == 0)
618      {
619         ev->cmd.num_params = 2;
620         ev->cmd.cur_param = 0;
621         ev->cmd.param.size.width = 0;
622         ev->cmd.param.size.height = 0;
623      }
624
625    if (!_player_cmd_param_read(ev, &param, sizeof(param)))
626      return;
627
628    if (ev->cmd.cur_param == 0)
629      ev->cmd.param.size.width = param;
630    else
631      ev->cmd.param.size.height = param;
632
633    ev->cmd.cur_param++;
634    if (ev->cmd.cur_param == ev->cmd.num_params)
635      _player_cmd_process(ev);
636 }
637
638 static void
639 _player_cmd_track_info(Emotion_Generic_Video *ev)
640 {
641    int param;
642    int i;
643
644    if (ev->cmd.num_params == 0)
645      {
646         ev->cmd.cur_param = 0;
647         ev->cmd.num_params = 2;
648         ev->cmd.param.track.channels = NULL;
649         ev->cmd.s_len = -1;
650      }
651
652    while (ev->cmd.cur_param < 2)
653      {
654         if (!_player_cmd_param_read(ev, &param, sizeof(param)))
655           return;
656
657         if (ev->cmd.cur_param == 0)
658           ev->cmd.param.track.current = param;
659         else
660           {
661              ev->cmd.param.track.total = param;
662              ev->cmd.num_params += param * 2;
663              ev->cmd.param.track.channels =
664                 calloc(param, sizeof(*ev->cmd.param.track.channels));
665           }
666         ev->cmd.cur_param++;
667      }
668
669    if (ev->cmd.cur_param == ev->cmd.num_params)
670      {
671         _player_cmd_process(ev);
672         return;
673      }
674
675    i = (ev->cmd.cur_param - 2) / 2;
676    if ((ev->cmd.cur_param % 2) == 0) // reading track id
677      {
678         if (!_player_cmd_param_read(ev, &param, sizeof(param)))
679           return;
680         ev->cmd.param.track.channels[i].id = param;
681         ev->cmd.cur_param++;
682      }
683    else // reading track name
684      {
685         char buf[PATH_MAX];
686
687         if (ev->cmd.s_len == -1)
688           {
689              if (!_player_cmd_param_read(ev, &param, sizeof(param)))
690                return;
691              ev->cmd.s_len = param;
692           }
693
694         if (!_player_cmd_param_read(ev, buf, ev->cmd.s_len))
695           return;
696         ev->cmd.param.track.channels[i].name = 
697            eina_stringshare_add_length(buf, ev->cmd.s_len);
698         ev->cmd.cur_param++;
699         ev->cmd.s_len = -1;
700      }
701
702    if (ev->cmd.cur_param == ev->cmd.num_params)
703      _player_cmd_process(ev);
704 }
705
706 static void
707 _player_cmd_meta_info(Emotion_Generic_Video *ev)
708 {
709    int param;
710    const char *info;
711    char buf[PATH_MAX];
712
713    if (ev->cmd.num_params == 0)
714      {
715         ev->cmd.cur_param = 0;
716         ev->cmd.num_params = 8;
717         ev->cmd.param.meta.title = NULL;
718         ev->cmd.param.meta.artist = NULL;
719         ev->cmd.param.meta.album = NULL;
720         ev->cmd.param.meta.year = NULL;
721         ev->cmd.param.meta.genre = NULL;
722         ev->cmd.param.meta.comment = NULL;
723         ev->cmd.param.meta.disc_id = NULL;
724         ev->cmd.param.meta.count = NULL;
725         ev->cmd.s_len = -1;
726      }
727
728    if (ev->cmd.s_len == -1)
729      {
730         if (!_player_cmd_param_read(ev, &param, sizeof(param)))
731           return;
732         ev->cmd.s_len = param;
733      }
734
735    if (!_player_cmd_param_read(ev, buf, ev->cmd.s_len))
736      return;
737
738    info = eina_stringshare_add_length(buf, ev->cmd.s_len);
739    ev->cmd.s_len = -1;
740
741    if (ev->cmd.cur_param == 0)
742      ev->cmd.param.meta.title = info;
743    else if (ev->cmd.cur_param == 1)
744      ev->cmd.param.meta.artist = info;
745    else if (ev->cmd.cur_param == 2)
746      ev->cmd.param.meta.album = info;
747    else if (ev->cmd.cur_param == 3)
748      ev->cmd.param.meta.year = info;
749    else if (ev->cmd.cur_param == 4)
750      ev->cmd.param.meta.genre = info;
751    else if (ev->cmd.cur_param == 5)
752      ev->cmd.param.meta.comment = info;
753    else if (ev->cmd.cur_param == 6)
754      ev->cmd.param.meta.disc_id = info;
755    else if (ev->cmd.cur_param == 7)
756      ev->cmd.param.meta.count = info;
757
758    ev->cmd.cur_param++;
759
760    if (ev->cmd.cur_param == 8)
761      _player_cmd_process(ev);
762 }
763
764 static void
765 _player_cmd_read(Emotion_Generic_Video *ev)
766 {
767    if (ev->cmd.type < 0)
768      {
769         if (!_player_cmd_param_read(ev, &ev->cmd.type, sizeof(ev->cmd.type)))
770           return;
771         ev->cmd.num_params = 0;
772      }
773
774    switch (ev->cmd.type) {
775       case EM_RESULT_INIT:
776       case EM_RESULT_FILE_SET:
777       case EM_RESULT_PLAYBACK_STOPPED:
778       case EM_RESULT_FILE_CLOSE:
779       case EM_RESULT_FRAME_NEW:
780          _player_cmd_process(ev);
781          break;
782       case EM_RESULT_FILE_SET_DONE:
783       case EM_RESULT_SEEKABLE_CHANGED:
784          _player_cmd_single_int_process(ev);
785          break;
786       case EM_RESULT_LENGTH_CHANGED:
787       case EM_RESULT_POSITION_CHANGED:
788          _player_cmd_single_float_process(ev);
789          break;
790       case EM_RESULT_FRAME_SIZE:
791          _player_cmd_double_int_process(ev);
792          break;
793       case EM_RESULT_AUDIO_TRACK_INFO:
794       case EM_RESULT_VIDEO_TRACK_INFO:
795       case EM_RESULT_SPU_TRACK_INFO:
796          _player_cmd_track_info(ev);
797          break;
798       case EM_RESULT_META_INFO:
799          _player_cmd_meta_info(ev);
800          break;
801
802       default:
803          WRN("received wrong command: %d", ev->cmd.type);
804          ev->cmd.type = -1;
805    }
806 }
807
808 static Eina_Bool
809 _player_cmd_handler_cb(void *data, Ecore_Fd_Handler *fd_handler)
810 {
811    Emotion_Generic_Video *ev = data;
812
813    if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
814      {
815         ERR("an error occurred on fd_read %d.", ev->fd_read);
816         return ECORE_CALLBACK_CANCEL;
817      }
818
819    _player_cmd_read(ev);
820
821    return ECORE_CALLBACK_RENEW;
822 }
823
824 static Eina_Bool
825 _player_data_cb(void *data, int type __UNUSED__, void *event)
826 {
827    Ecore_Exe_Event_Data *ev = event;
828    Emotion_Generic_Video *evideo = data;
829    int i;
830
831    if (ev->exe != evideo->player.exe)
832      {
833         ERR("slave != ev->exe");
834         return ECORE_CALLBACK_DONE;
835      }
836
837    for (i = 0; ev->lines[i].line; i++)
838      INF("received input from player: \"%s\"", ev->lines[i].line);
839
840    return ECORE_CALLBACK_DONE;
841 }
842
843 static Eina_Bool
844 _player_add_cb(void *data, int type __UNUSED__, void *event)
845 {
846    Ecore_Exe_Event_Add *event_add = event;
847    Ecore_Exe *player = event_add->exe;
848    Emotion_Generic_Video *ev = data;
849
850    if (ev->player.exe != player)
851      {
852         ERR("ev->player != player.");
853         return ECORE_CALLBACK_DONE;
854      }
855
856    _player_send_cmd(ev, EM_CMD_INIT);
857    _player_send_str(ev, ev->shmname, EINA_TRUE);
858
859    return ECORE_CALLBACK_DONE;
860 }
861
862 static Eina_Bool
863 _player_del_cb(void *data, int type __UNUSED__, void *event __UNUSED__)
864 {
865    Emotion_Generic_Video *ev = data;
866    ERR("player died.");
867
868    ev->player.exe = NULL;
869    ev->ready = EINA_FALSE;
870    ev->file_ready = EINA_FALSE;
871    ecore_main_fd_handler_del(ev->fd_handler);
872    close(ev->fd_read);
873    close(ev->fd_write);
874    ev->fd_read = -1;
875    ev->fd_write = -1;
876    _emotion_decode_stop(ev->obj);
877
878    return ECORE_CALLBACK_DONE;
879 }
880
881 static Eina_Bool
882 _player_exec(Emotion_Generic_Video *ev)
883 {
884    int pipe_out[2];
885    int pipe_in[2];
886    char buf[PATH_MAX];
887
888    if (pipe(pipe_out) == -1)
889      {
890         ERR("could not create pipe for communication emotion -> player: %s", strerror(errno));
891         return EINA_FALSE;
892      }
893
894    if (pipe(pipe_in) == -1)
895      {
896         ERR("could not create pipe for communication player -> emotion: %s", strerror(errno));
897         close(pipe_out[0]);
898         close(pipe_out[1]);
899         return EINA_FALSE;
900      }
901
902    snprintf(buf, sizeof(buf), "%s %d %d\n", ev->cmdline, pipe_out[0], pipe_in[1]);
903
904    ev->player.exe = ecore_exe_pipe_run(
905       buf,
906       ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE |
907       ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_NOT_LEADER,
908       ev);
909
910    INF("created pipe emotion -> player: %d -> %d", pipe_out[1], pipe_out[0]);
911    INF("created pipe player -> emotion: %d -> %d", pipe_in[1], pipe_in[0]);
912
913    close(pipe_in[1]);
914    close(pipe_out[0]);
915
916    if (!ev->player.exe)
917      {
918         close(pipe_in[0]);
919         close(pipe_out[1]);
920         return EINA_FALSE;
921      }
922
923    ev->fd_read = pipe_in[0];
924    ev->fd_write = pipe_out[1];
925
926    ev->fd_handler = ecore_main_fd_handler_add(
927       ev->fd_read, ECORE_FD_READ | ECORE_FD_ERROR, _player_cmd_handler_cb, ev,
928       NULL, NULL);
929
930    return EINA_TRUE;
931 }
932
933 static Eina_Bool
934 _fork_and_exec(Evas_Object *obj __UNUSED__, Emotion_Generic_Video *ev)
935 {
936    char shmname[256];
937    struct timeval tv;
938
939    gettimeofday(&tv, NULL);
940    snprintf(shmname, sizeof(shmname), "/em-generic-shm_%d_%d",
941             (int)tv.tv_sec, (int)tv.tv_usec);
942
943    ev->shmname = eina_stringshare_add(shmname);
944
945    ev->player_add = ecore_event_handler_add(
946       ECORE_EXE_EVENT_ADD, _player_add_cb, ev);
947    ev->player_del = ecore_event_handler_add(
948       ECORE_EXE_EVENT_DEL, _player_del_cb, ev);
949    ev->player_data = ecore_event_handler_add(
950       ECORE_EXE_EVENT_DATA, _player_data_cb, ev);
951
952
953    if (!_player_exec(ev))
954      {
955         ERR("could not start player.");
956         return EINA_FALSE;
957      }
958
959    ev->initializing = EINA_TRUE;
960
961    return EINA_TRUE;
962 }
963
964 static unsigned char
965 em_init(Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt)
966 {
967    Emotion_Generic_Video *ev;
968    const char *player;
969
970    if (!emotion_video) return 0;
971    player = _get_player(opt ? opt->player : NULL);
972    if (!player) return 0;
973
974    ev = (Emotion_Generic_Video *)calloc(1, sizeof(*ev));
975    if (!ev) return 0;
976
977    ev->fd_read = -1;
978    ev->fd_write = -1;
979    ev->speed = 1.0;
980    ev->volume = 0.5;
981    ev->audio_mute = EINA_FALSE;
982    ev->cmd.type = -1;
983
984    ev->obj = obj;
985    ev->cmdline = eina_stringshare_add(player);
986    *emotion_video = ev;
987
988    return _fork_and_exec(obj, ev);
989 }
990
991 static int
992 em_shutdown(void *data)
993 {
994    Emotion_Generic_Video *ev = data;
995
996    if (!ev) return 0;
997
998    if (ev->player.exe)
999      {
1000         ecore_exe_terminate(ev->player.exe);
1001         ecore_exe_free(ev->player.exe);
1002         ev->player.exe = NULL;
1003      }
1004
1005    if (ev->shared)
1006      munmap(ev->shared, ev->shared->size);
1007
1008    if (ev->fd_read >= 0)
1009      close(ev->fd_read);
1010    if (ev->fd_write >= 0)
1011      close(ev->fd_write);
1012    if (ev->fd_handler)
1013      ecore_main_fd_handler_del(ev->fd_handler);
1014
1015    eina_stringshare_del(ev->cmdline);
1016    eina_stringshare_del(ev->shmname);
1017
1018    ecore_event_handler_del(ev->player_add);
1019    ecore_event_handler_del(ev->player_data);
1020    ecore_event_handler_del(ev->player_del);
1021
1022    return 1;
1023 }
1024
1025 static unsigned char
1026 em_file_open(const char *file, Evas_Object *obj __UNUSED__, void *data)
1027 {
1028    Emotion_Generic_Video *ev = data;
1029    INF("file set: %s", file);
1030    if (!ev) return 0;
1031
1032    eina_stringshare_replace(&ev->filename, file);
1033
1034    ev->pos = 0;
1035    ev->w = 0;
1036    ev->h = 0;
1037    ev->ratio = 1;
1038    ev->len = 0;
1039
1040    if (ev->ready && ev->opening)
1041      {
1042         INF("file changed while opening.");
1043         ev->file_changed = EINA_TRUE;
1044         return 1;
1045      }
1046
1047    ev->opening = EINA_TRUE;
1048
1049    if (!ev->closing)
1050      _file_open(ev);
1051
1052    return 1;
1053 }
1054
1055 static void
1056 em_file_close(void *data)
1057 {
1058    Emotion_Generic_Video *ev = data;
1059
1060    if (!ev || !ev->filename) return;
1061
1062    INF("file close: %s", ev->filename);
1063
1064    eina_stringshare_replace(&ev->filename, NULL);
1065
1066    ev->file_ready = EINA_FALSE;
1067    _audio_channels_free(ev);
1068    _video_channels_free(ev);
1069    _spu_channels_free(ev);
1070    _player_meta_info_free(ev);
1071
1072    if (ev->opening)
1073      return;
1074
1075    _player_send_cmd(ev, EM_CMD_FILE_CLOSE);
1076    ev->closing = EINA_TRUE;
1077 }
1078
1079 static Emotion_Format
1080 em_format_get(void *ef __UNUSED__)
1081 {
1082    return EMOTION_FORMAT_BGRA;
1083 }
1084
1085 static void
1086 em_video_data_size_get(void *data, int *w, int *h)
1087 {
1088    Emotion_Generic_Video *ev = data;
1089
1090    if (!ev) return;
1091    if (w) *w = ev->w;
1092    if (h) *h = ev->h;
1093 }
1094
1095 static void
1096 em_play(void *data, double pos)
1097 {
1098    Emotion_Generic_Video *ev = data;
1099
1100    if (!ev)
1101      return;
1102
1103    ev->play = EINA_TRUE;
1104    INF("play: %0.3f", pos);
1105
1106    if (ev->initializing || ev->opening)
1107      return;
1108
1109    if (ev->ready)
1110      {
1111         _player_send_cmd(ev, EM_CMD_PLAY);
1112         _player_send_float(ev, ev->pos);
1113         return;
1114      }
1115
1116    if (!_player_exec(ev))
1117      ERR("could not start player.");
1118 }
1119
1120 static void
1121 em_stop(void *data)
1122 {
1123    Emotion_Generic_Video *ev = data;
1124
1125    if (!ev)
1126      return;
1127
1128    ev->play = EINA_FALSE;
1129
1130    if (!ev->file_ready)
1131      return;
1132
1133    _player_send_cmd(ev, EM_CMD_STOP);
1134    _emotion_decode_stop(ev->obj);
1135 }
1136
1137 static void
1138 em_size_get(void *data, int *w, int *h)
1139 {
1140    Emotion_Generic_Video *ev = data;
1141    if (w) *w = ev->w;
1142    if (h) *h = ev->h;
1143 }
1144
1145 static void
1146 em_pos_set(void *data, double pos)
1147 {
1148    Emotion_Generic_Video *ev = data;
1149    float position = pos;
1150
1151    if (!ev->file_ready)
1152      return;
1153
1154    _player_send_cmd(ev, EM_CMD_POSITION_SET);
1155    _player_send_float(ev, position);
1156    _emotion_seek_done(ev->obj);
1157 }
1158
1159 static double
1160 em_len_get(void *data)
1161 {
1162    Emotion_Generic_Video *ev = data;
1163    return ev->len;
1164 }
1165
1166 static double
1167 em_buffer_size_get(void *data)
1168 {
1169    Emotion_Generic_Video *ev = data;
1170    return 1.0;
1171    ev = NULL;
1172 }
1173
1174 static int
1175 em_fps_num_get(void *data)
1176 {
1177    Emotion_Generic_Video *ev = data;
1178    return (int)(ev->fps * 1000.0);
1179 }
1180
1181 static int
1182 em_fps_den_get(void *ef __UNUSED__)
1183 {
1184    return 1000;
1185 }
1186
1187 static double
1188 em_fps_get(void *data)
1189 {
1190    Emotion_Generic_Video *ev = data;
1191    return ev->fps;
1192 }
1193
1194 static double
1195 em_pos_get(void *data)
1196 {
1197    Emotion_Generic_Video *ev = data;
1198    return ev->pos;
1199 }
1200
1201 static void
1202 em_vis_set(void *ef __UNUSED__, Emotion_Vis vis __UNUSED__)
1203 {
1204 }
1205
1206 static Emotion_Vis
1207 em_vis_get(void *data)
1208 {
1209    Emotion_Generic_Video *ev = data;
1210    return ev->vis;
1211 }
1212
1213 static Eina_Bool
1214 em_vis_supported(void *ef __UNUSED__, Emotion_Vis vis __UNUSED__)
1215 {
1216    return EINA_FALSE;
1217 }
1218
1219 static double
1220 em_ratio_get(void *data)
1221 {
1222    Emotion_Generic_Video *ev = data;
1223    return ev->ratio;
1224 }
1225
1226 static int em_video_handled(void *ef __UNUSED__)
1227 {
1228    fprintf(stderr, "video handled!\n");
1229    return 1;
1230 }
1231
1232 static int em_audio_handled(void *ef __UNUSED__)
1233 {
1234    fprintf(stderr, "audio handled!\n");
1235    return 1;
1236 }
1237
1238 static int em_seekable(void *data)
1239 {
1240    Emotion_Generic_Video *ev = data;
1241    return ev->seekable;
1242 }
1243
1244 static void em_frame_done(void *ef __UNUSED__)
1245 {
1246 }
1247
1248 static int
1249 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__)
1250 {
1251    return 0;
1252 }
1253
1254 static int
1255 em_bgra_data_get(void *data, unsigned char **bgra_data)
1256 {
1257    Emotion_Generic_Video *ev = data;
1258
1259    if (!ev || !ev->file_ready)
1260      return 0;
1261
1262    // lock frame here
1263    if (!eina_semaphore_lock(&ev->shared->lock))
1264      return 0;
1265
1266    // send current frame to emotion
1267    if (ev->shared->frame.emotion != ev->shared->frame.last)
1268      {
1269         ev->shared->frame.next = ev->shared->frame.emotion;
1270         ev->shared->frame.emotion = ev->shared->frame.last;
1271      }
1272    *bgra_data = ev->frame.frames[ev->shared->frame.emotion];
1273
1274    if (ev->shared->frame_drop > 1)
1275      WRN("dropped frames: %d", ev->shared->frame_drop - 1);
1276    ev->shared->frame_drop = 0;
1277
1278    // unlock frame here
1279    eina_semaphore_release(&ev->shared->lock, 1);
1280    ev->drop = 0;
1281
1282    return 1;
1283 }
1284
1285 static void
1286 em_event_feed(void *ef __UNUSED__, int event __UNUSED__)
1287 {
1288 }
1289
1290 static void
1291 em_event_mouse_button_feed(void *ef __UNUSED__, int button __UNUSED__, int x __UNUSED__, int y __UNUSED__)
1292 {
1293 }
1294
1295 static void
1296 em_event_mouse_move_feed(void *ef __UNUSED__, int x __UNUSED__, int y __UNUSED__)
1297 {
1298 }
1299
1300 static int
1301 em_video_channel_count(void *data)
1302 {
1303    Emotion_Generic_Video *ev = data;
1304    return ev->video_channels_count;
1305 }
1306
1307 static void
1308 em_video_channel_set(void *data, int channel)
1309 {
1310    Emotion_Generic_Video *ev = data;
1311
1312    if (channel < 0 || channel >= ev->video_channels_count)
1313      {
1314         WRN("video channel out of range.");
1315         return;
1316      }
1317
1318    _player_send_cmd(ev, EM_CMD_VIDEO_TRACK_SET);
1319    _player_send_int(ev, ev->video_channels[channel].id);
1320    ev->video_channel_current = channel;
1321 }
1322
1323 static int
1324 em_video_channel_get(void *data)
1325 {
1326    Emotion_Generic_Video *ev = data;
1327    return ev->video_channel_current;
1328 }
1329
1330 static const char *
1331 em_video_channel_name_get(void *data, int channel)
1332 {
1333    Emotion_Generic_Video *ev = data;
1334
1335    if (channel < 0 || channel >= ev->video_channels_count)
1336      {
1337         WRN("video channel out of range.");
1338         return NULL;
1339      }
1340
1341    return ev->video_channels[channel].name;
1342 }
1343
1344 static void
1345 em_video_channel_mute_set(void *data, int mute)
1346 {
1347    Emotion_Generic_Video *ev = data;
1348
1349    ev->video_mute = !!mute;
1350
1351    if (!ev || !ev->file_ready)
1352      return;
1353
1354    _player_send_cmd(ev, EM_CMD_VIDEO_MUTE_SET);
1355    _player_send_int(ev, mute);
1356 }
1357
1358 static int
1359 em_video_channel_mute_get(void *data)
1360 {
1361    Emotion_Generic_Video *ev = data;
1362    return ev->video_mute;
1363 }
1364
1365 static int
1366 em_audio_channel_count(void *data)
1367 {
1368    Emotion_Generic_Video *ev = data;
1369    return ev->audio_channels_count;
1370 }
1371
1372 static void
1373 em_audio_channel_set(void *data, int channel)
1374 {
1375    Emotion_Generic_Video *ev = data;
1376
1377    if (channel < 0 || channel >= ev->audio_channels_count)
1378      {
1379         WRN("audio channel out of range.");
1380         return;
1381      }
1382
1383    _player_send_cmd(ev, EM_CMD_AUDIO_TRACK_SET);
1384    _player_send_int(ev, ev->audio_channels[channel].id);
1385    ev->audio_channel_current = channel;
1386 }
1387
1388 static int
1389 em_audio_channel_get(void *data)
1390 {
1391    Emotion_Generic_Video *ev = data;
1392    return ev->audio_channel_current;
1393 }
1394
1395 static const char *
1396 em_audio_channel_name_get(void *data, int channel)
1397 {
1398    Emotion_Generic_Video *ev = data;
1399
1400    if (channel < 0 || channel >= ev->audio_channels_count)
1401      {
1402         WRN("audio channel out of range.");
1403         return NULL;
1404      }
1405
1406    return ev->audio_channels[channel].name;
1407 }
1408
1409 static void
1410 em_audio_channel_mute_set(void *data, int mute)
1411 {
1412    Emotion_Generic_Video *ev = data;
1413
1414    ev->audio_mute = !!mute;
1415
1416    if (!ev || !ev->file_ready)
1417      return;
1418
1419    _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET);
1420    _player_send_int(ev, mute);
1421 }
1422
1423 static int
1424 em_audio_channel_mute_get(void *data)
1425 {
1426    Emotion_Generic_Video *ev = data;
1427    return ev->audio_mute;
1428 }
1429
1430 static void
1431 em_audio_channel_volume_set(void *data, double vol)
1432 {
1433    Emotion_Generic_Video *ev = data;
1434
1435    if (vol > 1.0) vol = 1.0;
1436    if (vol < 0.0) vol = 0.0;
1437
1438    ev->volume = vol;
1439
1440    if (!ev || !ev->file_ready)
1441      return;
1442
1443    _player_send_cmd(ev, EM_CMD_VOLUME_SET);
1444    _player_send_float(ev, ev->volume);
1445 }
1446
1447 static double
1448 em_audio_channel_volume_get(void *data)
1449 {
1450    Emotion_Generic_Video *ev = data;
1451    return ev->volume;
1452 }
1453
1454 static int
1455 em_spu_channel_count(void *data)
1456 {
1457    Emotion_Generic_Video *ev = data;
1458    return ev->spu_channels_count;
1459 }
1460
1461 static void
1462 em_spu_channel_set(void *data, int channel)
1463 {
1464    Emotion_Generic_Video *ev = data;
1465
1466    if (channel < 0 || channel >= ev->spu_channels_count)
1467      {
1468         WRN("spu channel out of range.");
1469         return;
1470      }
1471
1472    _player_send_cmd(ev, EM_CMD_SPU_TRACK_SET);
1473    _player_send_int(ev, ev->spu_channels[channel].id);
1474    ev->spu_channel_current = channel;
1475 }
1476
1477 static int
1478 em_spu_channel_get(void *data)
1479 {
1480    Emotion_Generic_Video *ev = data;
1481    return ev->spu_channel_current;
1482 }
1483
1484 static const char *
1485 em_spu_channel_name_get(void *data, int channel)
1486 {
1487    Emotion_Generic_Video *ev = data;
1488
1489    if (channel < 0 || channel >= ev->spu_channels_count)
1490      {
1491         WRN("spu channel out of range.");
1492         return NULL;
1493      }
1494
1495    return ev->spu_channels[channel].name;
1496 }
1497
1498 static void
1499 em_spu_channel_mute_set(void *data, int mute)
1500 {
1501    Emotion_Generic_Video *ev = data;
1502
1503    ev->spu_mute = !!mute;
1504
1505    if (!ev || !ev->file_ready)
1506      return;
1507
1508    _player_send_cmd(ev, EM_CMD_SPU_MUTE_SET);
1509    _player_send_int(ev, mute);
1510 }
1511
1512 static int
1513 em_spu_channel_mute_get(void *data)
1514 {
1515    Emotion_Generic_Video *ev = data;
1516    return ev->spu_mute;
1517 }
1518
1519 static int
1520 em_chapter_count(void *ef __UNUSED__)
1521 {
1522    int num = 0;
1523    return num;
1524 }
1525
1526 static void
1527 em_chapter_set(void *ef __UNUSED__, int chapter __UNUSED__)
1528 {
1529 }
1530
1531 static int
1532 em_chapter_get(void *ef __UNUSED__)
1533 {
1534    int num = 0;
1535    return num;
1536 }
1537
1538 static const char *
1539 em_chapter_name_get(void *ef __UNUSED__, int chapter __UNUSED__)
1540 {
1541    return NULL;
1542 }
1543
1544 static void
1545 em_speed_set(void *data, double speed)
1546 {
1547    Emotion_Generic_Video *ev = data;
1548    float rate = speed;
1549    ev->speed = rate;
1550
1551    if (!ev || !ev->file_ready)
1552      return;
1553
1554    _player_send_cmd(ev, EM_CMD_SPEED_SET);
1555    _player_send_float(ev, rate);
1556 }
1557
1558 static double
1559 em_speed_get(void *data)
1560 {
1561    Emotion_Generic_Video *ev = data;
1562    return (double)ev->speed;
1563 }
1564
1565 static int
1566 em_eject(void *ef __UNUSED__)
1567 {
1568    return 1;
1569 }
1570
1571 static const char *
1572 em_meta_get(void *data, int meta)
1573 {
1574    Emotion_Generic_Video *ev = data;
1575
1576    switch (meta) {
1577       case EMOTION_META_INFO_TRACK_TITLE:
1578          return ev->meta.title;
1579       case EMOTION_META_INFO_TRACK_ARTIST:
1580          return ev->meta.artist;
1581       case EMOTION_META_INFO_TRACK_ALBUM:
1582          return ev->meta.album;
1583       case EMOTION_META_INFO_TRACK_YEAR:
1584          return ev->meta.year;
1585       case EMOTION_META_INFO_TRACK_GENRE:
1586          return ev->meta.genre;
1587       case EMOTION_META_INFO_TRACK_COMMENT:
1588          return ev->meta.comment;
1589       case EMOTION_META_INFO_TRACK_DISC_ID:
1590          return ev->meta.disc_id;
1591       case EMOTION_META_INFO_TRACK_COUNT:
1592          return ev->meta.count;
1593    }
1594
1595    return NULL;
1596 }
1597
1598 static Emotion_Video_Module em_module =
1599 {
1600    em_init, /* init */
1601    em_shutdown, /* shutdown */
1602    em_file_open, /* file_open */
1603    em_file_close, /* file_close */
1604    em_play, /* play */
1605    em_stop, /* stop */
1606    em_size_get, /* size_get */
1607    em_pos_set, /* pos_set */
1608    em_len_get, /* len_get */
1609    em_buffer_size_get, /* buffer_size_get */
1610    em_fps_num_get, /* fps_num_get */
1611    em_fps_den_get, /* fps_den_get */
1612    em_fps_get, /* fps_get */
1613    em_pos_get, /* pos_get */
1614    em_vis_set, /* vis_set */
1615    em_vis_get, /* vis_get */
1616    em_vis_supported, /* vis_supported */
1617    em_ratio_get, /* ratio_get */
1618    em_video_handled, /* video_handled */
1619    em_audio_handled, /* audio_handled */
1620    em_seekable, /* seekable */
1621    em_frame_done, /* frame_done */
1622    em_format_get, /* format_get */
1623    em_video_data_size_get, /* video_data_size_get */
1624    em_yuv_rows_get, /* yuv_rows_get */
1625    em_bgra_data_get, /* bgra_data_get */
1626    em_event_feed, /* event_feed */
1627    em_event_mouse_button_feed, /* event_mouse_button_feed */
1628    em_event_mouse_move_feed, /* event_mouse_move_feed */
1629    em_video_channel_count, /* video_channel_count */
1630    em_video_channel_set, /* video_channel_set */
1631    em_video_channel_get, /* video_channel_get */
1632    em_video_channel_name_get, /* video_channel_name_get */
1633    em_video_channel_mute_set, /* video_channel_mute_set */
1634    em_video_channel_mute_get, /* video_channel_mute_get */
1635    em_audio_channel_count, /* audio_channel_count */
1636    em_audio_channel_set, /* audio_channel_set */
1637    em_audio_channel_get, /* audio_channel_get */
1638    em_audio_channel_name_get, /* audio_channel_name_get */
1639    em_audio_channel_mute_set, /* audio_channel_mute_set */
1640    em_audio_channel_mute_get, /* audio_channel_mute_get */
1641    em_audio_channel_volume_set, /* audio_channel_volume_set */
1642    em_audio_channel_volume_get, /* audio_channel_volume_get */
1643    em_spu_channel_count, /* spu_channel_count */
1644    em_spu_channel_set, /* spu_channel_set */
1645    em_spu_channel_get, /* spu_channel_get */
1646    em_spu_channel_name_get, /* spu_channel_name_get */
1647    em_spu_channel_mute_set, /* spu_channel_mute_set */
1648    em_spu_channel_mute_get, /* spu_channel_mute_get */
1649    em_chapter_count, /* chapter_count */
1650    em_chapter_set, /* chapter_set */
1651    em_chapter_get, /* chapter_get */
1652    em_chapter_name_get, /* chapter_name_get */
1653    em_speed_set, /* speed_set */
1654    em_speed_get, /* speed_get */
1655    em_eject, /* eject */
1656    em_meta_get, /* meta_get */
1657    NULL, /* priority_set */
1658    NULL, /* priority_get */
1659    NULL /* handle */
1660 };
1661
1662 static Eina_Bool
1663 module_open(Evas_Object *obj, const Emotion_Video_Module **module, void **video, Emotion_Module_Options *opt)
1664 {
1665    if (!module) {
1666         return EINA_FALSE;
1667    }
1668
1669    if (_emotion_generic_log_domain < 0)
1670      {
1671         eina_threads_init();
1672         eina_log_threads_enable();
1673         _emotion_generic_log_domain = eina_log_domain_register
1674           ("emotion-generic", EINA_COLOR_LIGHTCYAN);
1675         if (_emotion_generic_log_domain < 0)
1676           {
1677              EINA_LOG_CRIT("Could not register log domain 'emotion-generic'");
1678              return EINA_FALSE;
1679           }
1680      }
1681
1682
1683    if (!em_module.init(obj, video, opt))        {
1684         return EINA_FALSE;
1685    }
1686
1687    *module = &em_module;
1688
1689    return EINA_TRUE;
1690 }
1691
1692 static void module_close(Emotion_Video_Module *module __UNUSED__, void *video)
1693 {
1694         em_module.shutdown(video);
1695 }
1696
1697
1698 Eina_Bool
1699 generic_module_init(void)
1700 {
1701    if (!pfx)
1702      {
1703         pfx = eina_prefix_new(NULL, emotion_object_add,
1704                               "EMOTION", "emotion", NULL,
1705                               PACKAGE_BIN_DIR,
1706                               PACKAGE_LIB_DIR,
1707                               PACKAGE_DATA_DIR,
1708                               "");
1709         if (!pfx) return EINA_FALSE;
1710      }
1711    return _emotion_module_register("generic", module_open, module_close);
1712 }
1713
1714 static void
1715 generic_module_shutdown(void)
1716 {
1717    if (pfx)
1718      {
1719         eina_prefix_free(pfx);
1720         pfx = NULL;
1721      }
1722    _emotion_module_unregister("generic");
1723 }
1724
1725 #ifndef EMOTION_STATIC_BUILD_GENERIC
1726
1727 EINA_MODULE_INIT(generic_module_init);
1728 EINA_MODULE_SHUTDOWN(generic_module_shutdown);
1729
1730 #endif
1731