emotion/generic - Use pipes instead of stdin/stdout for communication.
[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    sem_init(&vs->lock, 1, 1);
177    ev->frame.frames[0] = (unsigned char *)vs + sizeof(*vs);
178    ev->frame.frames[1] = (unsigned char *)vs + sizeof(*vs) + vs->height * vs->width * vs->pitch;
179    ev->frame.frames[2] = (unsigned char *)vs + sizeof(*vs) + 2 * vs->height * vs->width * vs->pitch;
180
181    if (ev->shared)
182      munmap(ev->shared, ev->shared->size);
183    ev->shared = vs;
184
185    return EINA_TRUE;
186 }
187
188 static void
189 _player_new_frame(Emotion_Generic_Video *ev)
190 {
191    if (!ev->drop++)
192      _emotion_frame_new(ev->obj);
193 }
194
195 static void
196 _player_file_set_done(Emotion_Generic_Video *ev)
197 {
198    if (!_create_shm_data(ev, ev->shmname))
199      {
200         ERR("could not create shared memory.");
201         return;
202      }
203    _player_send_cmd(ev, EM_CMD_FILE_SET_DONE);
204 }
205
206 static void
207 _file_open(Emotion_Generic_Video *ev)
208 {
209    INF("Opening file: %s", ev->filename);
210    ev->w = DEFAULTWIDTH;
211    ev->h = DEFAULTHEIGHT;
212    ev->ratio = (double)DEFAULTWIDTH / DEFAULTHEIGHT;
213    ev->speed = 1.0;
214    ev->len = 0;
215    ev->drop = 0;
216
217    if (!ev->ready)
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_ready(Emotion_Generic_Video *ev)
225 {
226    INF("received: player ready.");
227
228    ev->initializing = EINA_FALSE;
229    ev->ready = EINA_TRUE;
230
231    if (!ev->filename)
232      return;
233
234    _file_open(ev);
235 }
236
237 static int
238 _em_read_safe(int fd, void *buf, ssize_t size)
239 {
240    ssize_t todo;
241    char *p;
242
243    todo = size;
244    p = buf;
245
246    while (todo > 0)
247      {
248         ssize_t r;
249
250         r = read(fd, p, todo);
251         if (r > 0)
252           {
253              todo -= r;
254              p += r;
255           }
256         else if (r == 0)
257           return 0;
258         else
259           {
260              if (errno == EINTR || errno == EAGAIN)
261                continue;
262              else
263                {
264                   ERR("could not read from fd %d: %s", fd, strerror(errno));
265                   return 0;
266                }
267           }
268      }
269
270    return 1;
271 }
272
273 static Eina_Bool
274 _player_int_read(Emotion_Generic_Video *ev, int *i)
275 {
276    int n;
277    n = _em_read_safe(ev->fd_read, i, sizeof(*i));
278    if (n <= 0)
279      {
280         ERR("could not read int from fd_read %d\n", ev->fd_read);
281         return EINA_FALSE;
282      }
283
284    return EINA_TRUE;
285 }
286
287 static Eina_Bool
288 _player_float_read(Emotion_Generic_Video *ev, float *f)
289 {
290    int n;
291    n = _em_read_safe(ev->fd_read, f, sizeof(*f));
292    if (n <= 0)
293      {
294         ERR("could not read float from fd_read %d\n", ev->fd_read);
295         return EINA_FALSE;
296      }
297
298    return EINA_TRUE;
299 }
300
301 static Eina_Bool
302 _player_str_read(Emotion_Generic_Video *ev, char *str, int *len)
303 {
304    int n;
305
306    if (!_player_int_read(ev, len))
307      return EINA_FALSE;
308
309    n = _em_read_safe(ev->fd_read, str, *len);
310    if (n <= 0)
311      {
312         ERR("could not read string from fd_read %d\n", ev->fd_read);
313         return EINA_FALSE;
314      }
315
316    return EINA_TRUE;
317 }
318
319 static void
320 _player_frame_resize(Emotion_Generic_Video *ev)
321 {
322    int w, h;
323    _player_int_read(ev, &w);
324    _player_int_read(ev, &h);
325
326    INF("received frame resize: %dx%d", w, h);
327    ev->w = w;
328    ev->h = h;
329    ev->ratio = (float)w / h;
330
331    if (ev->opening)
332      return;
333
334    _emotion_frame_resize(ev->obj, ev->w, ev->h, ev->ratio);
335 }
336
337 static void
338 _player_length_changed(Emotion_Generic_Video *ev)
339 {
340    float length;
341    _player_float_read(ev, &length);
342
343    INF("received length changed: %0.3f", length);
344
345    ev->len = length;
346    _emotion_video_pos_update(ev->obj, ev->pos, ev->len);
347 }
348
349 static void
350 _player_position_changed(Emotion_Generic_Video *ev)
351 {
352    float position;
353    _player_float_read(ev, &position);
354
355    INF("received position changed: %0.3f", position);
356
357    ev->pos = position;
358    _emotion_video_pos_update(ev->obj, ev->pos, ev->len);
359
360    if (ev->len == 0)
361      return;
362
363    float progress = ev->pos / ev->len;
364    char buf[16];
365    snprintf(buf, sizeof(buf), "%0.1f%%", progress * 100);
366
367    _emotion_progress_set(ev->obj, buf, progress);
368 }
369
370 static void
371 _player_seekable_changed(Emotion_Generic_Video *ev)
372 {
373    int seekable;
374    _player_int_read(ev, &seekable);
375
376    INF("received seekable changed: %d", seekable);
377
378    seekable = !!seekable;
379
380    ev->seekable = seekable;
381 }
382
383 static void
384 _player_volume(Emotion_Generic_Video *ev)
385 {
386    float vol, oldvol;
387    _player_float_read(ev, &vol);
388
389    INF("received volume: %0.3f", vol);
390
391    oldvol = ev->volume;
392    ev->volume = vol;
393    if (vol != oldvol && !ev->opening)
394      _emotion_audio_level_change(ev->obj);
395 }
396
397 static void
398 _player_audio_mute(Emotion_Generic_Video *ev)
399 {
400    int mute;
401    _player_int_read(ev, &mute);
402
403    INF("received audio mute: %d", mute);
404
405    ev->audio_mute = !!mute;
406 }
407
408 static void
409 _audio_channels_free(Emotion_Generic_Video *ev)
410 {
411    int i;
412    for (i = 0; i < ev->audio_channels_count; i++)
413      eina_stringshare_del(ev->audio_channels[i].name);
414    free(ev->audio_channels);
415    ev->audio_channels_count = 0;
416 }
417
418 static void
419 _player_audio_tracks_info(Emotion_Generic_Video *ev)
420 {
421    int track_current, tracks_count;
422    int i;
423
424    if (ev->audio_channels_count)
425      _audio_channels_free(ev);
426
427    _player_int_read(ev, &track_current);
428    _player_int_read(ev, &tracks_count);
429    INF("video with %d audio tracks (current = %d):", tracks_count, track_current);
430    ev->audio_channels = calloc(
431       tracks_count, sizeof(Emotion_Generic_Audio_Channel));
432    ev->audio_channels_count = tracks_count;
433    ev->audio_channel_current = track_current;
434    for (i = 0; i < tracks_count; i++)
435      {
436         int tid, len;
437         char buf[PATH_MAX];
438         _player_int_read(ev, &tid);
439         _player_str_read(ev, buf, &len);
440         ev->audio_channels[i].id = tid;
441         ev->audio_channels[i].name = eina_stringshare_add_length(buf, len);
442         INF("\t%d: %s", tid, buf);
443      }
444 }
445
446 static void
447 _player_file_closed(Emotion_Generic_Video *ev)
448 {
449    INF("Closed previous file.");
450    sem_destroy(&ev->shared->lock);
451
452    ev->closing = EINA_FALSE;
453
454    if (ev->opening)
455      _file_open(ev);
456 }
457
458 static void
459 _player_open_done(Emotion_Generic_Video *ev)
460 {
461    int success;
462
463    ev->opening = EINA_FALSE;
464    _player_int_read(ev, &success);
465
466    shm_unlink(ev->shmname);
467    if (!success)
468      {
469         ERR("Could not open file.");
470         return;
471      }
472
473    _emotion_open_done(ev->obj);
474
475    if (ev->play)
476      {
477         _player_send_cmd(ev, EM_CMD_PLAY);
478         _player_send_float(ev, ev->pos);
479      }
480
481    INF("Open done");
482 }
483
484 static void
485 _player_read_cmd(Emotion_Generic_Video *ev)
486 {
487    int type;
488
489    if (!_player_int_read(ev, &type))
490      {
491         ERR("could not read command\n");
492         return;
493      }
494
495    switch (type) {
496       case EM_RESULT_INIT:
497          _player_ready(ev);
498          break;
499       case EM_RESULT_FRAME_NEW:
500          _player_new_frame(ev);
501          break;
502       case EM_RESULT_FILE_SET:
503          _player_file_set_done(ev);
504          break;
505       case EM_RESULT_FILE_SET_DONE:
506          _player_open_done(ev);
507          break;
508       case EM_RESULT_FILE_CLOSE:
509          _player_file_closed(ev);
510          break;
511       case EM_RESULT_PLAYBACK_STOPPED:
512          _emotion_playback_finished(ev->obj);
513          break;
514       case EM_RESULT_FRAME_SIZE:
515          _player_frame_resize(ev);
516          break;
517       case EM_RESULT_LENGTH_CHANGED:
518          _player_length_changed(ev);
519          break;
520       case EM_RESULT_POSITION_CHANGED:
521          _player_position_changed(ev);
522          break;
523       case EM_RESULT_SEEKABLE_CHANGED:
524          _player_seekable_changed(ev);
525          break;
526       case EM_RESULT_AUDIO_TRACK_INFO:
527          _player_audio_tracks_info(ev);
528          break;
529       default:
530          WRN("received wrong command: %d", type);
531    };
532 }
533
534 static Eina_Bool
535 _player_cmd_handler_cb(void *data, Ecore_Fd_Handler *fd_handler)
536 {
537    Emotion_Generic_Video *ev = data;
538
539    if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
540      {
541         ERR("an error occurred on fd_read %d.", ev->fd_read);
542         return ECORE_CALLBACK_CANCEL;
543      }
544
545    _player_read_cmd(ev);
546
547    return ECORE_CALLBACK_RENEW;
548 }
549
550 static Eina_Bool
551 _player_data_cb(void *data, int type __UNUSED__, void *event)
552 {
553    Ecore_Exe_Event_Data *ev = event;
554    Emotion_Generic_Video *evideo = data;
555    int i;
556
557    if (ev->exe != evideo->player.exe)
558      {
559         ERR("slave != ev->exe");
560         return ECORE_CALLBACK_DONE;
561      }
562
563    if (ev->size < 4)
564      {
565         ERR("invalid command: missing bytes.");
566         return ECORE_CALLBACK_DONE;
567      }
568
569    for (i = 0; ev->lines[i].line; i++)
570      INF("received input from player: \"%s\"", ev->lines[i].line);
571
572    return ECORE_CALLBACK_DONE;
573 }
574
575 static Eina_Bool
576 _player_add_cb(void *data, int type __UNUSED__, void *event)
577 {
578    Ecore_Exe_Event_Add *event_add = event;
579    Ecore_Exe *player = event_add->exe;
580    Emotion_Generic_Video *ev = data;
581
582    if (ev->player.exe != player)
583      {
584         ERR("ev->player != player.");
585         return ECORE_CALLBACK_DONE;
586      }
587
588    _player_send_cmd(ev, EM_CMD_INIT);
589    _player_send_str(ev, ev->shmname, EINA_TRUE);
590
591    return ECORE_CALLBACK_DONE;
592 }
593
594 static Eina_Bool
595 _player_del_cb(void *data, int type __UNUSED__, void *event __UNUSED__)
596 {
597    Emotion_Generic_Video *ev = data;
598    ERR("player died.");
599
600    ev->player.exe = NULL;
601    ev->ready = EINA_FALSE;
602    ecore_main_fd_handler_del(ev->fd_handler);
603    close(ev->fd_read);
604    close(ev->fd_write);
605    ev->fd_read = -1;
606    ev->fd_write = -1;
607    _emotion_decode_stop(ev->obj);
608
609    return ECORE_CALLBACK_DONE;
610 }
611
612 static Eina_Bool
613 _player_exec(Emotion_Generic_Video *ev)
614 {
615    int pipe_out[2];
616    int pipe_in[2];
617    char buf[PATH_MAX];
618
619    if (pipe(pipe_out) == -1)
620      {
621         ERR("could not create pipe for communication emotion -> player: %s", strerror(errno));
622         return EINA_FALSE;
623      }
624
625    if (pipe(pipe_in) == -1)
626      {
627         ERR("could not create pipe for communication player -> emotion: %s", strerror(errno));
628         close(pipe_out[0]);
629         close(pipe_out[1]);
630         return EINA_FALSE;
631      }
632
633    snprintf(buf, sizeof(buf), "%s %d %d\n", ev->cmdline, pipe_out[0], pipe_in[1]);
634
635    ev->player.exe = ecore_exe_pipe_run(
636       buf,
637       ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE |
638       ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_NOT_LEADER,
639       ev);
640
641    INF("created pipe emotion -> player: %d -> %d\n", pipe_out[1], pipe_out[0]);
642    INF("created pipe player -> emotion: %d -> %d\n", pipe_in[1], pipe_in[0]);
643
644    close(pipe_in[1]);
645    close(pipe_out[0]);
646
647    if (!ev->player.exe)
648      {
649         close(pipe_in[0]);
650         close(pipe_out[1]);
651         return EINA_FALSE;
652      }
653
654    ev->fd_read = pipe_in[0];
655    ev->fd_write = pipe_out[1];
656
657    ev->fd_handler = ecore_main_fd_handler_add(
658       ev->fd_read, ECORE_FD_READ | ECORE_FD_ERROR, _player_cmd_handler_cb, ev,
659       NULL, NULL);
660
661    return EINA_TRUE;
662 }
663
664 static Eina_Bool
665 _fork_and_exec(Evas_Object *obj, Emotion_Generic_Video *ev)
666 {
667    char shmname[256];
668    struct timeval tv;
669
670    gettimeofday(&tv, NULL);
671    snprintf(shmname, sizeof(shmname), "/em-generic-shm_%d_%d",
672             (int)tv.tv_sec, (int)tv.tv_usec);
673
674    ev->shmname = eina_stringshare_add(shmname);
675
676    ev->player_add = ecore_event_handler_add(
677       ECORE_EXE_EVENT_ADD, _player_add_cb, ev);
678    ev->player_del = ecore_event_handler_add(
679       ECORE_EXE_EVENT_DEL, _player_del_cb, ev);
680    ev->player_data = ecore_event_handler_add(
681       ECORE_EXE_EVENT_DATA, _player_data_cb, ev);
682
683
684    if (!_player_exec(ev))
685      {
686         ERR("could not start player.");
687         return EINA_FALSE;
688      }
689
690    ev->initializing = EINA_TRUE;
691
692    return EINA_TRUE;
693 }
694
695 static unsigned char
696 em_init(Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt)
697 {
698    Emotion_Generic_Video *ev;
699    const char *player;
700
701    if (!emotion_video) return 0;
702    player = _get_player(opt ? opt->player : NULL);
703    if (!player) return 0;
704
705    ev = (Emotion_Generic_Video *)calloc(1, sizeof(*ev));
706    if (!ev) return 0;
707
708    ev->fd_read = -1;
709    ev->fd_write = -1;
710    ev->speed = 1.0;
711    ev->volume = 0.5;
712    ev->audio_mute = EINA_FALSE;
713
714    ev->obj = obj;
715    ev->cmdline = eina_stringshare_add(player);
716    *emotion_video = ev;
717
718    return _fork_and_exec(obj, ev);
719 }
720
721 static int
722 em_shutdown(void *data)
723 {
724    Emotion_Generic_Video *ev = data;
725
726    if (!ev) return 0;
727
728    if (ev->player.exe)
729      {
730         ecore_exe_terminate(ev->player.exe);
731         ecore_exe_free(ev->player.exe);
732         ev->player.exe = NULL;
733      }
734
735    if (ev->shared)
736      munmap(ev->shared, ev->shared->size);
737
738    if (ev->fd_read >= 0)
739      close(ev->fd_read);
740    if (ev->fd_write >= 0)
741      close(ev->fd_write);
742    if (ev->fd_handler)
743      ecore_main_fd_handler_del(ev->fd_handler);
744
745    _audio_channels_free(ev);
746
747    eina_stringshare_del(ev->cmdline);
748    eina_stringshare_del(ev->shmname);
749
750    ecore_event_handler_del(ev->player_add);
751    ecore_event_handler_del(ev->player_data);
752    ecore_event_handler_del(ev->player_del);
753
754    return 1;
755 }
756
757 static unsigned char
758 em_file_open(const char *file, Evas_Object *obj __UNUSED__, void *data)
759 {
760    Emotion_Generic_Video *ev = data;
761    INF("file set: %s", file);
762    if (!ev) return 0;
763
764    ev->pos = 0;
765    ev->opening = EINA_TRUE;
766
767    eina_stringshare_replace(&ev->filename, file);
768
769    if (!ev->closing)
770      _file_open(ev);
771
772    return 1;
773 }
774
775 static void
776 em_file_close(void *data)
777 {
778    Emotion_Generic_Video *ev = data;
779
780    if (!ev) return;
781    INF("file close: %s", ev->filename);
782
783    if (!ev->filename)
784      return;
785
786    _player_send_cmd(ev, EM_CMD_FILE_CLOSE);
787    ev->closing = EINA_TRUE;
788 }
789
790 static Emotion_Format
791 em_format_get(void *ef __UNUSED__)
792 {
793    return EMOTION_FORMAT_BGRA;
794 }
795
796 static void
797 em_video_data_size_get(void *data, int *w, int *h)
798 {
799    Emotion_Generic_Video *ev = data;
800
801    if (!ev) return;
802    if (w) *w = ev->w;
803    if (h) *h = ev->h;
804 }
805
806 static void
807 em_play(void *data, double pos)
808 {
809    Emotion_Generic_Video *ev = data;
810
811    if (!ev)
812      return;
813
814    ev->play = EINA_TRUE;
815    INF("play: %0.3f", pos);
816
817    if (ev->initializing || ev->opening)
818      return;
819
820    if (ev->ready)
821      {
822         _player_send_cmd(ev, EM_CMD_PLAY);
823         _player_send_float(ev, ev->pos);
824         return;
825      }
826
827    if (!_player_exec(ev))
828      ERR("could not start player.");
829 }
830
831 static void
832 em_stop(void *data)
833 {
834    Emotion_Generic_Video *ev = data;
835
836    if (!ev)
837      return;
838
839    ev->play = EINA_FALSE;
840
841    if (!ev->ready)
842      return;
843
844    _player_send_cmd(ev, EM_CMD_STOP);
845    _emotion_decode_stop(ev->obj);
846 }
847
848 static void
849 em_size_get(void *data, int *w, int *h)
850 {
851    Emotion_Generic_Video *ev = data;
852    if(w) *w = ev->w;
853    if(h) *h = ev->h;
854 }
855
856 static void
857 em_pos_set(void *data, double pos)
858 {
859    Emotion_Generic_Video *ev = data;
860    float position = pos;
861    _player_send_cmd(ev, EM_CMD_POSITION_SET);
862    _player_send_float(ev, position);
863    _emotion_seek_done(ev->obj);
864 }
865
866 static double
867 em_len_get(void *data)
868 {
869    Emotion_Generic_Video *ev = data;
870    return ev->len;
871 }
872
873 static int
874 em_fps_num_get(void *data)
875 {
876    Emotion_Generic_Video *ev = data;
877    return (int)(ev->fps * 1000.0);
878 }
879
880 static int
881 em_fps_den_get(void *ef __UNUSED__)
882 {
883    return 1000;
884 }
885
886 static double
887 em_fps_get(void *data)
888 {
889    Emotion_Generic_Video *ev = data;
890    return ev->fps;
891 }
892
893 static double
894 em_pos_get(void *data)
895 {
896    Emotion_Generic_Video *ev = data;
897    return ev->pos;
898 }
899
900 static void
901 em_vis_set(void *ef __UNUSED__, Emotion_Vis vis __UNUSED__)
902 {
903 }
904
905 static Emotion_Vis
906 em_vis_get(void *data)
907 {
908    Emotion_Generic_Video *ev = data;
909    return ev->vis;
910 }
911
912 static Eina_Bool
913 em_vis_supported(void *ef __UNUSED__, Emotion_Vis vis __UNUSED__)
914 {
915    return EINA_FALSE;
916 }
917
918 static double
919 em_ratio_get(void *data)
920 {
921    Emotion_Generic_Video *ev = data;
922    return ev->ratio;
923 }
924
925 static int em_video_handled(void *ef __UNUSED__)
926 {
927    fprintf(stderr, "video handled!\n");
928    return 1;
929 }
930
931 static int em_audio_handled(void *ef __UNUSED__)
932 {
933    fprintf(stderr, "audio handled!\n");
934    return 1;
935 }
936
937 static int em_seekable(void *data)
938 {
939    Emotion_Generic_Video *ev = data;
940    return ev->seekable;
941 }
942
943 static void em_frame_done(void *ef __UNUSED__)
944 {
945 }
946
947 static int
948 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__)
949 {
950    return 0;
951 }
952
953 static int
954 em_bgra_data_get(void *data, unsigned char **bgra_data)
955 {
956    Emotion_Generic_Video *ev = data;
957
958    if (!ev || ev->opening || ev->closing)
959      return 0;
960
961    // lock frame here
962    sem_wait(&ev->shared->lock);
963
964    // send current frame to emotion
965    if (ev->shared->frame.emotion != ev->shared->frame.last)
966      {
967         ev->shared->frame.next = ev->shared->frame.emotion;
968         ev->shared->frame.emotion = ev->shared->frame.last;
969      }
970    *bgra_data = ev->frame.frames[ev->shared->frame.emotion];
971
972    // unlock frame here
973    sem_post(&ev->shared->lock);
974    ev->drop = 0;
975
976    return 1;
977 }
978
979 static void
980 em_event_feed(void *ef __UNUSED__, int event __UNUSED__)
981 {
982 }
983
984 static void
985 em_event_mouse_button_feed(void *ef __UNUSED__, int button __UNUSED__, int x __UNUSED__, int y __UNUSED__)
986 {
987 }
988
989 static void
990 em_event_mouse_move_feed(void *ef __UNUSED__, int x __UNUSED__, int y __UNUSED__)
991 {
992 }
993
994 static int
995 em_video_channel_count(void *ef __UNUSED__)
996 {
997    int ret  = 0;
998    return ret;
999 }
1000
1001 static void
1002 em_video_channel_set(void *ef __UNUSED__, int channel __UNUSED__)
1003 {
1004 }
1005
1006 static int
1007 em_video_channel_get(void *ef __UNUSED__)
1008 {
1009    return 1;
1010 }
1011
1012 static const char *
1013 em_video_channel_name_get(void *ef __UNUSED__, int channel __UNUSED__)
1014 {
1015    return NULL;
1016 }
1017
1018 static void
1019 em_video_channel_mute_set(void *ef __UNUSED__, int mute __UNUSED__)
1020 {
1021 }
1022
1023 static int
1024 em_video_channel_mute_get(void *data)
1025 {
1026    Emotion_Generic_Video *ev = data;
1027    return ev->video_mute;
1028 }
1029
1030 static int
1031 em_audio_channel_count(void *data)
1032 {
1033    Emotion_Generic_Video *ev = data;
1034    return ev->audio_channels_count;
1035 }
1036
1037 static void
1038 em_audio_channel_set(void *data, int channel)
1039 {
1040    Emotion_Generic_Video *ev = data;
1041    int i;
1042
1043    for (i = 0; i < ev->audio_channels_count; i++)
1044      {
1045         if (ev->audio_channels[i].id == channel)
1046           {
1047              _player_send_cmd(ev, EM_CMD_AUDIO_TRACK_SET);
1048              _player_send_int(ev, channel);
1049              break;
1050           }
1051      }
1052 }
1053
1054 static int
1055 em_audio_channel_get(void *data)
1056 {
1057    Emotion_Generic_Video *ev = data;
1058    return ev->audio_channel_current;
1059 }
1060
1061 static const char *
1062 em_audio_channel_name_get(void *data, int channel)
1063 {
1064    Emotion_Generic_Video *ev = data;
1065    int i;
1066
1067    for (i = 0; i < ev->audio_channels_count; i++)
1068      {
1069         if (ev->audio_channels[i].id == channel)
1070           return ev->audio_channels[i].name;
1071      }
1072
1073    return NULL;
1074 }
1075
1076 static void
1077 em_audio_channel_mute_set(void *data, int mute)
1078 {
1079    Emotion_Generic_Video *ev = data;
1080    _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET);
1081    _player_send_int(ev, mute);
1082    ev->audio_mute = !!mute;
1083 }
1084
1085 static int
1086 em_audio_channel_mute_get(void *data)
1087 {
1088    Emotion_Generic_Video *ev = data;
1089    return ev->audio_mute;
1090 }
1091
1092 static void
1093 em_audio_channel_volume_set(void *data, double vol)
1094 {
1095    Emotion_Generic_Video *ev = data;
1096    float fvol;
1097
1098    if (vol > 1.0) vol = 1.0;
1099    if (vol < 0.0) vol = 0.0;
1100
1101    fvol = vol;
1102    _player_send_cmd(ev, EM_CMD_VOLUME_SET);
1103    _player_send_float(ev, fvol);
1104
1105    ev->volume = vol;
1106 }
1107
1108 static double
1109 em_audio_channel_volume_get(void *data)
1110 {
1111    Emotion_Generic_Video *ev = data;
1112    return ev->volume;
1113 }
1114
1115 static int
1116 em_spu_channel_count(void *ef __UNUSED__)
1117 {
1118    return 0;
1119 }
1120
1121 static void
1122 em_spu_channel_set(void *ef __UNUSED__, int channel __UNUSED__)
1123 {
1124 }
1125
1126 static int
1127 em_spu_channel_get(void *ef __UNUSED__)
1128 {
1129    int num = 0;
1130    return num;
1131 }
1132
1133 static const char *
1134 em_spu_channel_name_get(void *ef __UNUSED__, int channel __UNUSED__)
1135 {
1136    return NULL;
1137 }
1138
1139 static void
1140 em_spu_channel_mute_set(void *ef __UNUSED__, int mute __UNUSED__)
1141 {
1142    return;
1143 }
1144
1145 static int
1146 em_spu_channel_mute_get(void *ef __UNUSED__)
1147 {
1148    return 0;
1149 }
1150
1151 static int
1152 em_chapter_count(void *ef __UNUSED__)
1153 {
1154    int num = 0;
1155    return num;
1156 }
1157
1158 static void
1159 em_chapter_set(void *ef __UNUSED__, int chapter __UNUSED__)
1160 {
1161 }
1162
1163 static int
1164 em_chapter_get(void *ef __UNUSED__)
1165 {
1166    int num = 0;
1167    return num;
1168 }
1169
1170 static const char *
1171 em_chapter_name_get(void *ef __UNUSED__, int chapter __UNUSED__)
1172 {
1173    return NULL;
1174 }
1175
1176 static void
1177 em_speed_set(void *data, double speed)
1178 {
1179    Emotion_Generic_Video *ev = data;
1180    float rate = speed;
1181
1182    _player_send_cmd(ev, EM_CMD_SPEED_SET);
1183    _player_send_float(ev, rate);
1184
1185    ev->speed = rate;
1186 }
1187
1188 static double
1189 em_speed_get(void *data)
1190 {
1191    Emotion_Generic_Video *ev = data;
1192    return (double)ev->speed;
1193 }
1194
1195 static int
1196 em_eject(void *ef __UNUSED__)
1197 {
1198    return 1;
1199 }
1200
1201 static const char *
1202 em_meta_get(void *ef __UNUSED__, int meta __UNUSED__)
1203 {
1204    char * meta_data = NULL;
1205    return meta_data;
1206 }
1207
1208 static Emotion_Video_Module em_module =
1209 {
1210    em_init, /* init */
1211    em_shutdown, /* shutdown */
1212    em_file_open, /* file_open */
1213    em_file_close, /* file_close */
1214    em_play, /* play */
1215    em_stop, /* stop */
1216    em_size_get, /* size_get */
1217    em_pos_set, /* pos_set */
1218    em_len_get, /* len_get */
1219    em_fps_num_get, /* fps_num_get */
1220    em_fps_den_get, /* fps_den_get */
1221    em_fps_get, /* fps_get */
1222    em_pos_get, /* pos_get */
1223    em_vis_set, /* vis_set */
1224    em_vis_get, /* vis_get */
1225    em_vis_supported, /* vis_supported */
1226    em_ratio_get, /* ratio_get */
1227    em_video_handled, /* video_handled */
1228    em_audio_handled, /* audio_handled */
1229    em_seekable, /* seekable */
1230    em_frame_done, /* frame_done */
1231    em_format_get, /* format_get */
1232    em_video_data_size_get, /* video_data_size_get */
1233    em_yuv_rows_get, /* yuv_rows_get */
1234    em_bgra_data_get, /* bgra_data_get */
1235    em_event_feed, /* event_feed */
1236    em_event_mouse_button_feed, /* event_mouse_button_feed */
1237    em_event_mouse_move_feed, /* event_mouse_move_feed */
1238    em_video_channel_count, /* video_channel_count */
1239    em_video_channel_set, /* video_channel_set */
1240    em_video_channel_get, /* video_channel_get */
1241    em_video_channel_name_get, /* video_channel_name_get */
1242    em_video_channel_mute_set, /* video_channel_mute_set */
1243    em_video_channel_mute_get, /* video_channel_mute_get */
1244    em_audio_channel_count, /* audio_channel_count */
1245    em_audio_channel_set, /* audio_channel_set */
1246    em_audio_channel_get, /* audio_channel_get */
1247    em_audio_channel_name_get, /* audio_channel_name_get */
1248    em_audio_channel_mute_set, /* audio_channel_mute_set */
1249    em_audio_channel_mute_get, /* audio_channel_mute_get */
1250    em_audio_channel_volume_set, /* audio_channel_volume_set */
1251    em_audio_channel_volume_get, /* audio_channel_volume_get */
1252    em_spu_channel_count, /* spu_channel_count */
1253    em_spu_channel_set, /* spu_channel_set */
1254    em_spu_channel_get, /* spu_channel_get */
1255    em_spu_channel_name_get, /* spu_channel_name_get */
1256    em_spu_channel_mute_set, /* spu_channel_mute_set */
1257    em_spu_channel_mute_get, /* spu_channel_mute_get */
1258    em_chapter_count, /* chapter_count */
1259    em_chapter_set, /* chapter_set */
1260    em_chapter_get, /* chapter_get */
1261    em_chapter_name_get, /* chapter_name_get */
1262    em_speed_set, /* speed_set */
1263    em_speed_get, /* speed_get */
1264    em_eject, /* eject */
1265    em_meta_get, /* meta_get */
1266    NULL /* handle */
1267 };
1268
1269 static Eina_Bool
1270 module_open(Evas_Object *obj, const Emotion_Video_Module **module, void **video, Emotion_Module_Options *opt)
1271 {
1272    if (!module) {
1273         return EINA_FALSE;
1274    }
1275
1276    if (_emotion_generic_log_domain < 0)
1277      {
1278         eina_threads_init();
1279         eina_log_threads_enable();
1280         _emotion_generic_log_domain = eina_log_domain_register
1281           ("emotion-generic", EINA_COLOR_LIGHTCYAN);
1282         if (_emotion_generic_log_domain < 0)
1283           {
1284              EINA_LOG_CRIT("Could not register log domain 'emotion-generic'");
1285              return EINA_FALSE;
1286           }
1287      }
1288
1289
1290    if (!em_module.init(obj, video, opt))        {
1291         return EINA_FALSE;
1292    }
1293
1294    *module = &em_module;
1295
1296    return EINA_TRUE;
1297 }
1298
1299 static void module_close(Emotion_Video_Module *module __UNUSED__, void *video)
1300 {
1301         em_module.shutdown(video);
1302 }
1303
1304
1305 Eina_Bool
1306 generic_module_init(void)
1307 {
1308    if (!pfx)
1309      {
1310         pfx = eina_prefix_new(NULL, emotion_object_add,
1311                               "EMOTION", "emotion", NULL,
1312                               PACKAGE_BIN_DIR,
1313                               PACKAGE_LIB_DIR,
1314                               PACKAGE_DATA_DIR,
1315                               "");
1316         if (!pfx) return EINA_FALSE;
1317      }
1318    return _emotion_module_register("generic", module_open, module_close);
1319 }
1320
1321 static void
1322 generic_module_shutdown(void)
1323 {
1324    if (pfx)
1325      {
1326         eina_prefix_free(pfx);
1327         pfx = NULL;
1328      }
1329    _emotion_module_unregister("generic");
1330 }
1331
1332 #ifndef EMOTION_STATIC_BUILD_GENERIC
1333
1334 EINA_MODULE_INIT(generic_module_init);
1335 EINA_MODULE_SHUTDOWN(generic_module_shutdown);
1336
1337 #endif
1338