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