Emotion generic: check if player is the expected on _player_del_cb
[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         INF("ev->player != player.");
853         return ECORE_CALLBACK_PASS_ON;
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    Ecore_Exe_Event_Del *event_del = event;
866    Ecore_Exe *player = event_del->exe;
867    Emotion_Generic_Video *ev = data;
868
869    if (ev->player.exe != player)
870      {
871         INF("ev->player != player.");
872         return ECORE_CALLBACK_PASS_ON;
873      }
874
875    ERR("player died.");
876
877    ev->player.exe = NULL;
878    ev->ready = EINA_FALSE;
879    ev->file_ready = EINA_FALSE;
880    ecore_main_fd_handler_del(ev->fd_handler);
881    close(ev->fd_read);
882    close(ev->fd_write);
883    ev->fd_read = -1;
884    ev->fd_write = -1;
885    _emotion_decode_stop(ev->obj);
886
887    return ECORE_CALLBACK_DONE;
888 }
889
890 static Eina_Bool
891 _player_exec(Emotion_Generic_Video *ev)
892 {
893    int pipe_out[2];
894    int pipe_in[2];
895    char buf[PATH_MAX];
896
897    if (pipe(pipe_out) == -1)
898      {
899         ERR("could not create pipe for communication emotion -> player: %s", strerror(errno));
900         return EINA_FALSE;
901      }
902
903    if (pipe(pipe_in) == -1)
904      {
905         ERR("could not create pipe for communication player -> emotion: %s", strerror(errno));
906         close(pipe_out[0]);
907         close(pipe_out[1]);
908         return EINA_FALSE;
909      }
910
911    snprintf(buf, sizeof(buf), "%s %d %d\n", ev->cmdline, pipe_out[0], pipe_in[1]);
912
913    ev->player.exe = ecore_exe_pipe_run(
914       buf,
915       ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE |
916       ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_NOT_LEADER,
917       ev);
918
919    INF("created pipe emotion -> player: %d -> %d", pipe_out[1], pipe_out[0]);
920    INF("created pipe player -> emotion: %d -> %d", pipe_in[1], pipe_in[0]);
921
922    close(pipe_in[1]);
923    close(pipe_out[0]);
924
925    if (!ev->player.exe)
926      {
927         close(pipe_in[0]);
928         close(pipe_out[1]);
929         return EINA_FALSE;
930      }
931
932    ev->fd_read = pipe_in[0];
933    ev->fd_write = pipe_out[1];
934
935    ev->fd_handler = ecore_main_fd_handler_add(
936       ev->fd_read, ECORE_FD_READ | ECORE_FD_ERROR, _player_cmd_handler_cb, ev,
937       NULL, NULL);
938
939    return EINA_TRUE;
940 }
941
942 static Eina_Bool
943 _fork_and_exec(Evas_Object *obj __UNUSED__, Emotion_Generic_Video *ev)
944 {
945    char shmname[256];
946    struct timeval tv;
947
948    gettimeofday(&tv, NULL);
949    snprintf(shmname, sizeof(shmname), "/em-generic-shm_%d_%d",
950             (int)tv.tv_sec, (int)tv.tv_usec);
951
952    ev->shmname = eina_stringshare_add(shmname);
953
954    ev->player_add = ecore_event_handler_add(
955       ECORE_EXE_EVENT_ADD, _player_add_cb, ev);
956    ev->player_del = ecore_event_handler_add(
957       ECORE_EXE_EVENT_DEL, _player_del_cb, ev);
958    ev->player_data = ecore_event_handler_add(
959       ECORE_EXE_EVENT_DATA, _player_data_cb, ev);
960
961
962    if (!_player_exec(ev))
963      {
964         ERR("could not start player.");
965         return EINA_FALSE;
966      }
967
968    ev->initializing = EINA_TRUE;
969
970    return EINA_TRUE;
971 }
972
973 static unsigned char
974 em_init(Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt)
975 {
976    Emotion_Generic_Video *ev;
977    const char *player;
978
979    if (!emotion_video) return 0;
980    player = _get_player(opt ? opt->player : NULL);
981    if (!player) return 0;
982
983    ev = (Emotion_Generic_Video *)calloc(1, sizeof(*ev));
984    if (!ev) return 0;
985
986    ev->fd_read = -1;
987    ev->fd_write = -1;
988    ev->speed = 1.0;
989    ev->volume = 0.5;
990    ev->audio_mute = EINA_FALSE;
991    ev->cmd.type = -1;
992
993    ev->obj = obj;
994    ev->cmdline = eina_stringshare_add(player);
995    *emotion_video = ev;
996
997    return _fork_and_exec(obj, ev);
998 }
999
1000 static int
1001 em_shutdown(void *data)
1002 {
1003    Emotion_Generic_Video *ev = data;
1004
1005    if (!ev) return 0;
1006
1007    if (ev->player.exe)
1008      {
1009         ecore_exe_terminate(ev->player.exe);
1010         ecore_exe_free(ev->player.exe);
1011         ev->player.exe = NULL;
1012      }
1013
1014    if (ev->shared)
1015      munmap(ev->shared, ev->shared->size);
1016
1017    if (ev->fd_read >= 0)
1018      close(ev->fd_read);
1019    if (ev->fd_write >= 0)
1020      close(ev->fd_write);
1021    if (ev->fd_handler)
1022      ecore_main_fd_handler_del(ev->fd_handler);
1023
1024    eina_stringshare_del(ev->cmdline);
1025    eina_stringshare_del(ev->shmname);
1026
1027    ecore_event_handler_del(ev->player_add);
1028    ecore_event_handler_del(ev->player_data);
1029    ecore_event_handler_del(ev->player_del);
1030
1031    return 1;
1032 }
1033
1034 static unsigned char
1035 em_file_open(const char *file, Evas_Object *obj __UNUSED__, void *data)
1036 {
1037    Emotion_Generic_Video *ev = data;
1038    INF("file set: %s", file);
1039    if (!ev) return 0;
1040
1041    eina_stringshare_replace(&ev->filename, file);
1042
1043    ev->pos = 0;
1044    ev->w = 0;
1045    ev->h = 0;
1046    ev->ratio = 1;
1047    ev->len = 0;
1048
1049    if (ev->ready && ev->opening)
1050      {
1051         INF("file changed while opening.");
1052         ev->file_changed = EINA_TRUE;
1053         return 1;
1054      }
1055
1056    ev->opening = EINA_TRUE;
1057
1058    if (!ev->closing)
1059      _file_open(ev);
1060
1061    return 1;
1062 }
1063
1064 static void
1065 em_file_close(void *data)
1066 {
1067    Emotion_Generic_Video *ev = data;
1068
1069    if (!ev || !ev->filename) return;
1070
1071    INF("file close: %s", ev->filename);
1072
1073    eina_stringshare_replace(&ev->filename, NULL);
1074
1075    ev->file_ready = EINA_FALSE;
1076    _audio_channels_free(ev);
1077    _video_channels_free(ev);
1078    _spu_channels_free(ev);
1079    _player_meta_info_free(ev);
1080
1081    if (ev->opening)
1082      return;
1083
1084    _player_send_cmd(ev, EM_CMD_FILE_CLOSE);
1085    ev->closing = EINA_TRUE;
1086 }
1087
1088 static Emotion_Format
1089 em_format_get(void *ef __UNUSED__)
1090 {
1091    return EMOTION_FORMAT_BGRA;
1092 }
1093
1094 static void
1095 em_video_data_size_get(void *data, int *w, int *h)
1096 {
1097    Emotion_Generic_Video *ev = data;
1098
1099    if (!ev) return;
1100    if (w) *w = ev->w;
1101    if (h) *h = ev->h;
1102 }
1103
1104 static void
1105 em_play(void *data, double pos)
1106 {
1107    Emotion_Generic_Video *ev = data;
1108
1109    if (!ev)
1110      return;
1111
1112    ev->play = EINA_TRUE;
1113    INF("play: %0.3f", pos);
1114
1115    if (ev->initializing || ev->opening)
1116      return;
1117
1118    if (ev->ready)
1119      {
1120         _player_send_cmd(ev, EM_CMD_PLAY);
1121         _player_send_float(ev, ev->pos);
1122         return;
1123      }
1124
1125    if (!_player_exec(ev))
1126      ERR("could not start player.");
1127 }
1128
1129 static void
1130 em_stop(void *data)
1131 {
1132    Emotion_Generic_Video *ev = data;
1133
1134    if (!ev)
1135      return;
1136
1137    ev->play = EINA_FALSE;
1138
1139    if (!ev->file_ready)
1140      return;
1141
1142    _player_send_cmd(ev, EM_CMD_STOP);
1143    _emotion_decode_stop(ev->obj);
1144 }
1145
1146 static void
1147 em_size_get(void *data, int *w, int *h)
1148 {
1149    Emotion_Generic_Video *ev = data;
1150    if (w) *w = ev->w;
1151    if (h) *h = ev->h;
1152 }
1153
1154 static void
1155 em_pos_set(void *data, double pos)
1156 {
1157    Emotion_Generic_Video *ev = data;
1158    float position = pos;
1159
1160    if (!ev->file_ready)
1161      return;
1162
1163    _player_send_cmd(ev, EM_CMD_POSITION_SET);
1164    _player_send_float(ev, position);
1165    _emotion_seek_done(ev->obj);
1166 }
1167
1168 static double
1169 em_len_get(void *data)
1170 {
1171    Emotion_Generic_Video *ev = data;
1172    return ev->len;
1173 }
1174
1175 static double
1176 em_buffer_size_get(void *data __UNUSED__)
1177 {
1178    return 1.0;
1179 }
1180
1181 static int
1182 em_fps_num_get(void *data)
1183 {
1184    Emotion_Generic_Video *ev = data;
1185    return (int)(ev->fps * 1000.0);
1186 }
1187
1188 static int
1189 em_fps_den_get(void *ef __UNUSED__)
1190 {
1191    return 1000;
1192 }
1193
1194 static double
1195 em_fps_get(void *data)
1196 {
1197    Emotion_Generic_Video *ev = data;
1198    return ev->fps;
1199 }
1200
1201 static double
1202 em_pos_get(void *data)
1203 {
1204    Emotion_Generic_Video *ev = data;
1205    return ev->pos;
1206 }
1207
1208 static void
1209 em_vis_set(void *ef __UNUSED__, Emotion_Vis vis __UNUSED__)
1210 {
1211 }
1212
1213 static Emotion_Vis
1214 em_vis_get(void *data)
1215 {
1216    Emotion_Generic_Video *ev = data;
1217    return ev->vis;
1218 }
1219
1220 static Eina_Bool
1221 em_vis_supported(void *ef __UNUSED__, Emotion_Vis vis __UNUSED__)
1222 {
1223    return EINA_FALSE;
1224 }
1225
1226 static double
1227 em_ratio_get(void *data)
1228 {
1229    Emotion_Generic_Video *ev = data;
1230    return ev->ratio;
1231 }
1232
1233 static int em_video_handled(void *ef __UNUSED__)
1234 {
1235    fprintf(stderr, "video handled!\n");
1236    return 1;
1237 }
1238
1239 static int em_audio_handled(void *ef __UNUSED__)
1240 {
1241    fprintf(stderr, "audio handled!\n");
1242    return 1;
1243 }
1244
1245 static int em_seekable(void *data)
1246 {
1247    Emotion_Generic_Video *ev = data;
1248    return ev->seekable;
1249 }
1250
1251 static void em_frame_done(void *ef __UNUSED__)
1252 {
1253 }
1254
1255 static int
1256 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__)
1257 {
1258    return 0;
1259 }
1260
1261 static int
1262 em_bgra_data_get(void *data, unsigned char **bgra_data)
1263 {
1264    Emotion_Generic_Video *ev = data;
1265
1266    if (!ev || !ev->file_ready)
1267      return 0;
1268
1269    // lock frame here
1270    if (!eina_semaphore_lock(&ev->shared->lock))
1271      return 0;
1272
1273    // send current frame to emotion
1274    if (ev->shared->frame.emotion != ev->shared->frame.last)
1275      {
1276         ev->shared->frame.next = ev->shared->frame.emotion;
1277         ev->shared->frame.emotion = ev->shared->frame.last;
1278      }
1279    *bgra_data = ev->frame.frames[ev->shared->frame.emotion];
1280
1281    if (ev->shared->frame_drop > 1)
1282      WRN("dropped frames: %d", ev->shared->frame_drop - 1);
1283    ev->shared->frame_drop = 0;
1284
1285    // unlock frame here
1286    eina_semaphore_release(&ev->shared->lock, 1);
1287    ev->drop = 0;
1288
1289    return 1;
1290 }
1291
1292 static void
1293 em_event_feed(void *ef __UNUSED__, int event __UNUSED__)
1294 {
1295 }
1296
1297 static void
1298 em_event_mouse_button_feed(void *ef __UNUSED__, int button __UNUSED__, int x __UNUSED__, int y __UNUSED__)
1299 {
1300 }
1301
1302 static void
1303 em_event_mouse_move_feed(void *ef __UNUSED__, int x __UNUSED__, int y __UNUSED__)
1304 {
1305 }
1306
1307 static int
1308 em_video_channel_count(void *data)
1309 {
1310    Emotion_Generic_Video *ev = data;
1311    return ev->video_channels_count;
1312 }
1313
1314 static void
1315 em_video_channel_set(void *data, int channel)
1316 {
1317    Emotion_Generic_Video *ev = data;
1318
1319    if (channel < 0 || channel >= ev->video_channels_count)
1320      {
1321         WRN("video channel out of range.");
1322         return;
1323      }
1324
1325    _player_send_cmd(ev, EM_CMD_VIDEO_TRACK_SET);
1326    _player_send_int(ev, ev->video_channels[channel].id);
1327    ev->video_channel_current = channel;
1328 }
1329
1330 static int
1331 em_video_channel_get(void *data)
1332 {
1333    Emotion_Generic_Video *ev = data;
1334    return ev->video_channel_current;
1335 }
1336
1337 static const char *
1338 em_video_channel_name_get(void *data, int channel)
1339 {
1340    Emotion_Generic_Video *ev = data;
1341
1342    if (channel < 0 || channel >= ev->video_channels_count)
1343      {
1344         WRN("video channel out of range.");
1345         return NULL;
1346      }
1347
1348    return ev->video_channels[channel].name;
1349 }
1350
1351 static void
1352 em_video_channel_mute_set(void *data, int mute)
1353 {
1354    Emotion_Generic_Video *ev = data;
1355
1356    ev->video_mute = !!mute;
1357
1358    if (!ev || !ev->file_ready)
1359      return;
1360
1361    _player_send_cmd(ev, EM_CMD_VIDEO_MUTE_SET);
1362    _player_send_int(ev, mute);
1363 }
1364
1365 static int
1366 em_video_channel_mute_get(void *data)
1367 {
1368    Emotion_Generic_Video *ev = data;
1369    return ev->video_mute;
1370 }
1371
1372 static int
1373 em_audio_channel_count(void *data)
1374 {
1375    Emotion_Generic_Video *ev = data;
1376    return ev->audio_channels_count;
1377 }
1378
1379 static void
1380 em_audio_channel_set(void *data, int channel)
1381 {
1382    Emotion_Generic_Video *ev = data;
1383
1384    if (channel < 0 || channel >= ev->audio_channels_count)
1385      {
1386         WRN("audio channel out of range.");
1387         return;
1388      }
1389
1390    _player_send_cmd(ev, EM_CMD_AUDIO_TRACK_SET);
1391    _player_send_int(ev, ev->audio_channels[channel].id);
1392    ev->audio_channel_current = channel;
1393 }
1394
1395 static int
1396 em_audio_channel_get(void *data)
1397 {
1398    Emotion_Generic_Video *ev = data;
1399    return ev->audio_channel_current;
1400 }
1401
1402 static const char *
1403 em_audio_channel_name_get(void *data, int channel)
1404 {
1405    Emotion_Generic_Video *ev = data;
1406
1407    if (channel < 0 || channel >= ev->audio_channels_count)
1408      {
1409         WRN("audio channel out of range.");
1410         return NULL;
1411      }
1412
1413    return ev->audio_channels[channel].name;
1414 }
1415
1416 static void
1417 em_audio_channel_mute_set(void *data, int mute)
1418 {
1419    Emotion_Generic_Video *ev = data;
1420
1421    ev->audio_mute = !!mute;
1422
1423    if (!ev || !ev->file_ready)
1424      return;
1425
1426    _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET);
1427    _player_send_int(ev, mute);
1428 }
1429
1430 static int
1431 em_audio_channel_mute_get(void *data)
1432 {
1433    Emotion_Generic_Video *ev = data;
1434    return ev->audio_mute;
1435 }
1436
1437 static void
1438 em_audio_channel_volume_set(void *data, double vol)
1439 {
1440    Emotion_Generic_Video *ev = data;
1441
1442    if (vol > 1.0) vol = 1.0;
1443    if (vol < 0.0) vol = 0.0;
1444
1445    ev->volume = vol;
1446
1447    if (!ev || !ev->file_ready)
1448      return;
1449
1450    _player_send_cmd(ev, EM_CMD_VOLUME_SET);
1451    _player_send_float(ev, ev->volume);
1452 }
1453
1454 static double
1455 em_audio_channel_volume_get(void *data)
1456 {
1457    Emotion_Generic_Video *ev = data;
1458    return ev->volume;
1459 }
1460
1461 static int
1462 em_spu_channel_count(void *data)
1463 {
1464    Emotion_Generic_Video *ev = data;
1465    return ev->spu_channels_count;
1466 }
1467
1468 static void
1469 em_spu_channel_set(void *data, int channel)
1470 {
1471    Emotion_Generic_Video *ev = data;
1472
1473    if (channel < 0 || channel >= ev->spu_channels_count)
1474      {
1475         WRN("spu channel out of range.");
1476         return;
1477      }
1478
1479    _player_send_cmd(ev, EM_CMD_SPU_TRACK_SET);
1480    _player_send_int(ev, ev->spu_channels[channel].id);
1481    ev->spu_channel_current = channel;
1482 }
1483
1484 static int
1485 em_spu_channel_get(void *data)
1486 {
1487    Emotion_Generic_Video *ev = data;
1488    return ev->spu_channel_current;
1489 }
1490
1491 static const char *
1492 em_spu_channel_name_get(void *data, int channel)
1493 {
1494    Emotion_Generic_Video *ev = data;
1495
1496    if (channel < 0 || channel >= ev->spu_channels_count)
1497      {
1498         WRN("spu channel out of range.");
1499         return NULL;
1500      }
1501
1502    return ev->spu_channels[channel].name;
1503 }
1504
1505 static void
1506 em_spu_channel_mute_set(void *data, int mute)
1507 {
1508    Emotion_Generic_Video *ev = data;
1509
1510    ev->spu_mute = !!mute;
1511
1512    if (!ev || !ev->file_ready)
1513      return;
1514
1515    _player_send_cmd(ev, EM_CMD_SPU_MUTE_SET);
1516    _player_send_int(ev, mute);
1517 }
1518
1519 static int
1520 em_spu_channel_mute_get(void *data)
1521 {
1522    Emotion_Generic_Video *ev = data;
1523    return ev->spu_mute;
1524 }
1525
1526 static int
1527 em_chapter_count(void *ef __UNUSED__)
1528 {
1529    int num = 0;
1530    return num;
1531 }
1532
1533 static void
1534 em_chapter_set(void *ef __UNUSED__, int chapter __UNUSED__)
1535 {
1536 }
1537
1538 static int
1539 em_chapter_get(void *ef __UNUSED__)
1540 {
1541    int num = 0;
1542    return num;
1543 }
1544
1545 static const char *
1546 em_chapter_name_get(void *ef __UNUSED__, int chapter __UNUSED__)
1547 {
1548    return NULL;
1549 }
1550
1551 static void
1552 em_speed_set(void *data, double speed)
1553 {
1554    Emotion_Generic_Video *ev = data;
1555    float rate = speed;
1556    ev->speed = rate;
1557
1558    if (!ev || !ev->file_ready)
1559      return;
1560
1561    _player_send_cmd(ev, EM_CMD_SPEED_SET);
1562    _player_send_float(ev, rate);
1563 }
1564
1565 static double
1566 em_speed_get(void *data)
1567 {
1568    Emotion_Generic_Video *ev = data;
1569    return (double)ev->speed;
1570 }
1571
1572 static int
1573 em_eject(void *ef __UNUSED__)
1574 {
1575    return 1;
1576 }
1577
1578 static const char *
1579 em_meta_get(void *data, int meta)
1580 {
1581    Emotion_Generic_Video *ev = data;
1582
1583    switch (meta) {
1584       case EMOTION_META_INFO_TRACK_TITLE:
1585          return ev->meta.title;
1586       case EMOTION_META_INFO_TRACK_ARTIST:
1587          return ev->meta.artist;
1588       case EMOTION_META_INFO_TRACK_ALBUM:
1589          return ev->meta.album;
1590       case EMOTION_META_INFO_TRACK_YEAR:
1591          return ev->meta.year;
1592       case EMOTION_META_INFO_TRACK_GENRE:
1593          return ev->meta.genre;
1594       case EMOTION_META_INFO_TRACK_COMMENT:
1595          return ev->meta.comment;
1596       case EMOTION_META_INFO_TRACK_DISC_ID:
1597          return ev->meta.disc_id;
1598       case EMOTION_META_INFO_TRACK_COUNT:
1599          return ev->meta.count;
1600    }
1601
1602    return NULL;
1603 }
1604
1605 static Emotion_Video_Module em_module =
1606 {
1607    em_init, /* init */
1608    em_shutdown, /* shutdown */
1609    em_file_open, /* file_open */
1610    em_file_close, /* file_close */
1611    em_play, /* play */
1612    em_stop, /* stop */
1613    em_size_get, /* size_get */
1614    em_pos_set, /* pos_set */
1615    em_len_get, /* len_get */
1616    em_buffer_size_get, /* buffer_size_get */
1617    em_fps_num_get, /* fps_num_get */
1618    em_fps_den_get, /* fps_den_get */
1619    em_fps_get, /* fps_get */
1620    em_pos_get, /* pos_get */
1621    em_vis_set, /* vis_set */
1622    em_vis_get, /* vis_get */
1623    em_vis_supported, /* vis_supported */
1624    em_ratio_get, /* ratio_get */
1625    em_video_handled, /* video_handled */
1626    em_audio_handled, /* audio_handled */
1627    em_seekable, /* seekable */
1628    em_frame_done, /* frame_done */
1629    em_format_get, /* format_get */
1630    em_video_data_size_get, /* video_data_size_get */
1631    em_yuv_rows_get, /* yuv_rows_get */
1632    em_bgra_data_get, /* bgra_data_get */
1633    em_event_feed, /* event_feed */
1634    em_event_mouse_button_feed, /* event_mouse_button_feed */
1635    em_event_mouse_move_feed, /* event_mouse_move_feed */
1636    em_video_channel_count, /* video_channel_count */
1637    em_video_channel_set, /* video_channel_set */
1638    em_video_channel_get, /* video_channel_get */
1639    em_video_channel_name_get, /* video_channel_name_get */
1640    em_video_channel_mute_set, /* video_channel_mute_set */
1641    em_video_channel_mute_get, /* video_channel_mute_get */
1642    em_audio_channel_count, /* audio_channel_count */
1643    em_audio_channel_set, /* audio_channel_set */
1644    em_audio_channel_get, /* audio_channel_get */
1645    em_audio_channel_name_get, /* audio_channel_name_get */
1646    em_audio_channel_mute_set, /* audio_channel_mute_set */
1647    em_audio_channel_mute_get, /* audio_channel_mute_get */
1648    em_audio_channel_volume_set, /* audio_channel_volume_set */
1649    em_audio_channel_volume_get, /* audio_channel_volume_get */
1650    em_spu_channel_count, /* spu_channel_count */
1651    em_spu_channel_set, /* spu_channel_set */
1652    em_spu_channel_get, /* spu_channel_get */
1653    em_spu_channel_name_get, /* spu_channel_name_get */
1654    em_spu_channel_mute_set, /* spu_channel_mute_set */
1655    em_spu_channel_mute_get, /* spu_channel_mute_get */
1656    em_chapter_count, /* chapter_count */
1657    em_chapter_set, /* chapter_set */
1658    em_chapter_get, /* chapter_get */
1659    em_chapter_name_get, /* chapter_name_get */
1660    em_speed_set, /* speed_set */
1661    em_speed_get, /* speed_get */
1662    em_eject, /* eject */
1663    em_meta_get, /* meta_get */
1664    NULL, /* priority_set */
1665    NULL, /* priority_get */
1666    NULL /* handle */
1667 };
1668
1669 static Eina_Bool
1670 module_open(Evas_Object *obj, const Emotion_Video_Module **module, void **video, Emotion_Module_Options *opt)
1671 {
1672    if (!module) {
1673         return EINA_FALSE;
1674    }
1675
1676    if (_emotion_generic_log_domain < 0)
1677      {
1678         eina_threads_init();
1679         eina_log_threads_enable();
1680         _emotion_generic_log_domain = eina_log_domain_register
1681           ("emotion-generic", EINA_COLOR_LIGHTCYAN);
1682         if (_emotion_generic_log_domain < 0)
1683           {
1684              EINA_LOG_CRIT("Could not register log domain 'emotion-generic'");
1685              return EINA_FALSE;
1686           }
1687      }
1688
1689
1690    if (!em_module.init(obj, video, opt))        {
1691         return EINA_FALSE;
1692    }
1693
1694    *module = &em_module;
1695
1696    return EINA_TRUE;
1697 }
1698
1699 static void module_close(Emotion_Video_Module *module __UNUSED__, void *video)
1700 {
1701         em_module.shutdown(video);
1702 }
1703
1704
1705 Eina_Bool
1706 generic_module_init(void)
1707 {
1708    if (!pfx)
1709      {
1710         pfx = eina_prefix_new(NULL, emotion_object_add,
1711                               "EMOTION", "emotion", NULL,
1712                               PACKAGE_BIN_DIR,
1713                               PACKAGE_LIB_DIR,
1714                               PACKAGE_DATA_DIR,
1715                               "");
1716         if (!pfx) return EINA_FALSE;
1717      }
1718    return _emotion_module_register("generic", module_open, module_close);
1719 }
1720
1721 static void
1722 generic_module_shutdown(void)
1723 {
1724    if (pfx)
1725      {
1726         eina_prefix_free(pfx);
1727         pfx = NULL;
1728      }
1729    _emotion_module_unregister("generic");
1730 }
1731
1732 #ifndef EMOTION_STATIC_BUILD_GENERIC
1733
1734 EINA_MODULE_INIT(generic_module_init);
1735 EINA_MODULE_SHUTDOWN(generic_module_shutdown);
1736
1737 #endif
1738