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