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