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