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