Add generic player backend (with vlc player).
[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 struct _default_players {
18    const char *name;
19    const char *cmdline;
20 };
21
22 int _emotion_generic_log_domain = -1;
23
24 static struct _default_players players[] = {
25        { "vlc", "em_generic_vlc" },
26        { NULL, NULL }
27 };
28
29 static const char *
30 _get_player(const char *name)
31 {
32    int i;
33
34    if (!name)
35      return players[0].cmdline;
36
37    for (i = 0; players[i].name; i++)
38      {
39         if (!strcmp(players[i].name, name))
40           return players[i].cmdline;
41      }
42
43    return name;
44 }
45
46 static void
47 _player_send_cmd(Emotion_Generic_Video *ev, int cmd)
48 {
49    if (cmd >= EM_CMD_LAST)
50      {
51         ERR("invalid command to player.");
52         return;
53      }
54    ecore_exe_send(ev->player.exe, &cmd, sizeof(cmd));
55 }
56
57 static void
58 _player_send_int(Emotion_Generic_Video *ev, int number)
59 {
60    ecore_exe_send(ev->player.exe, &number, sizeof(number));
61 }
62
63 static void
64 _player_send_float(Emotion_Generic_Video *ev, float number)
65 {
66    ecore_exe_send(ev->player.exe, &number, sizeof(number));
67 }
68
69 static void
70 _player_send_str(Emotion_Generic_Video *ev, const char *str, Eina_Bool stringshared)
71 {
72    int len;
73
74    if (stringshared)
75      len = eina_stringshare_strlen(str) + 1;
76    else
77      len = strlen(str) + 1;
78    ecore_exe_send(ev->player.exe, &len, sizeof(len));
79    ecore_exe_send(ev->player.exe, str, len);
80 }
81
82 static Eina_Bool
83 _create_shm_data(Emotion_Generic_Video *ev, const char *shmname)
84 {
85    int shmfd;
86    int npages;
87    size_t size;
88    Emotion_Generic_Video_Shared *vs;
89
90    shmfd = shm_open(shmname, O_CREAT | O_RDWR | O_TRUNC, 0777);
91    size = 3 * (ev->w * ev->h * DEFAULTPITCH) + sizeof(*vs);
92
93    npages = (int)(size / getpagesize()) + 1;
94    size = npages * getpagesize();
95    char *buf = malloc(size);
96
97    if (ftruncate(shmfd, size))
98      {
99         ERR("error when allocating shared memory (size = %zd): "
100             "%s", size, strerror(errno));
101         return EINA_FALSE;
102      }
103    vs = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0);
104    if (vs == MAP_FAILED)
105      {
106         ERR("error when mapping shared memory.\n");
107         return EINA_FALSE;
108      }
109
110    memcmp(vs, buf, size);
111
112    vs->size = size;
113    vs->width = ev->w;
114    vs->height = ev->h;
115    vs->pitch = DEFAULTPITCH;
116    vs->frame.emotion = 0;
117    vs->frame.player = 1;
118    vs->frame.last = 2;
119    vs->frame.next = 2;
120    sem_init(&vs->lock, 1, 1);
121    ev->frame.frames[0] = (char *)vs + sizeof(*vs);
122    ev->frame.frames[1] = (char *)vs + sizeof(*vs) + vs->height * vs->width * vs->pitch;
123    ev->frame.frames[2] = (char *)vs + sizeof(*vs) + 2 * vs->height * vs->width * vs->pitch;
124
125    if (ev->shared)
126      munmap(ev->shared, ev->shared->size);
127    ev->shared = vs;
128
129    return EINA_TRUE;
130 }
131
132 static void
133 _player_new_frame(Emotion_Generic_Video *ev)
134 {
135    if (!ev->drop++)
136      _emotion_frame_new(ev->obj);
137 }
138
139 static void
140 _player_file_set_done(Emotion_Generic_Video *ev)
141 {
142    if (!_create_shm_data(ev, ev->shmname))
143      {
144         ERR("could not create shared memory.");
145         return;
146      }
147    _player_send_cmd(ev, EM_CMD_FILE_SET_DONE);
148 }
149
150 static void
151 _file_open(Emotion_Generic_Video *ev)
152 {
153    INF("Opening file: %s", ev->filename);
154    ev->w = DEFAULTWIDTH;
155    ev->h = DEFAULTHEIGHT;
156    ev->ratio = (double)DEFAULTWIDTH / DEFAULTHEIGHT;
157    ev->speed = 1.0;
158    ev->len = 0;
159    ev->drop = 0;
160
161    if (!ev->ready)
162      return;
163    _player_send_cmd(ev, EM_CMD_FILE_SET);
164    _player_send_str(ev, ev->filename, EINA_TRUE);
165 }
166
167 static void
168 _player_ready(Emotion_Generic_Video *ev)
169 {
170    INF("received: player ready.");
171
172    ev->initializing = EINA_FALSE;
173    ev->ready = EINA_TRUE;
174
175    if (!ev->filename)
176      return;
177
178    _file_open(ev);
179 }
180
181 #define RCV_CMD_PARAM(src, param) \
182    memcpy(&(param), (src), sizeof((param))); \
183    (src) = (char *)(src) + sizeof((param));
184
185 #define RCV_CMD_STR(src, buf, len) \
186    RCV_CMD_PARAM((src), (len)); \
187    memcpy((buf), (src), (len)); \
188    (src) = (char *)(src) + len;
189
190 static int
191 _player_int_read(Emotion_Generic_Video *ev, void **data)
192 {
193    int number;
194    memcpy(&number, *data, sizeof(number));
195    *data = (char *)(*data) + sizeof(number);
196
197    return number;
198 }
199
200 static void
201 _player_frame_resize(Emotion_Generic_Video *ev, void *line)
202 {
203    int w, h;
204    RCV_CMD_PARAM(line, w);
205    RCV_CMD_PARAM(line, h);
206
207    INF("received frame resize: %dx%d", w, h);
208    ev->w = w;
209    ev->h = h;
210    ev->ratio = (float)w / h;
211
212    if (ev->opening)
213      return;
214
215    _emotion_frame_resize(ev->obj, ev->w, ev->h, ev->ratio);
216 }
217
218 static void
219 _player_length_changed(Emotion_Generic_Video *ev, void *line)
220 {
221    float length;
222    RCV_CMD_PARAM(line, length);
223
224    INF("received length changed: %0.3f", length);
225
226    ev->len = length;
227    _emotion_video_pos_update(ev->obj, ev->pos, ev->len);
228 }
229
230 static void
231 _player_position_changed(Emotion_Generic_Video *ev, void *line)
232 {
233    float position;
234    RCV_CMD_PARAM(line, position);
235
236    INF("received position changed: %0.3f", position);
237
238    ev->pos = position;
239    _emotion_video_pos_update(ev->obj, ev->pos, ev->len);
240
241    if (ev->len == 0)
242      return;
243
244    float progress = ev->pos / ev->len;
245    char buf[16];
246    snprintf(buf, sizeof(buf), "%0.1f%%", progress * 100);
247
248    _emotion_progress_set(ev->obj, buf, progress);
249 }
250
251 static void
252 _player_seekable_changed(Emotion_Generic_Video *ev, void *line)
253 {
254    int seekable;
255    RCV_CMD_PARAM(line, seekable);
256
257    INF("received seekable changed: %d", seekable);
258
259    seekable = !!seekable;
260
261    ev->seekable = seekable;
262 }
263
264 static void
265 _player_volume(Emotion_Generic_Video *ev, void *line)
266 {
267    float vol, oldvol;
268    RCV_CMD_PARAM(line, vol);
269
270    INF("received volume: %0.3f", vol);
271
272    oldvol = ev->volume;
273    ev->volume = vol;
274    if (vol != oldvol && !ev->opening)
275      _emotion_audio_level_change(ev->obj);
276 }
277
278 static void
279 _player_audio_mute(Emotion_Generic_Video *ev, void *line)
280 {
281    int mute;
282    RCV_CMD_PARAM(line, mute);
283
284    INF("received audio mute: %d", mute);
285
286    ev->audio_mute = !!mute;
287 }
288
289 static void
290 _audio_channels_free(Emotion_Generic_Video *ev)
291 {
292    int i;
293    for (i = 0; i < ev->audio_channels_count; i++)
294      eina_stringshare_del(ev->audio_channels[i].name);
295    free(ev->audio_channels);
296    ev->audio_channels_count = 0;
297 }
298
299 static void
300 _player_audio_tracks_info(Emotion_Generic_Video *ev, void *line)
301 {
302    int track_current, tracks_count;
303    int i;
304
305    if (ev->audio_channels_count)
306      _audio_channels_free(ev);
307
308    RCV_CMD_PARAM(line, track_current);
309    RCV_CMD_PARAM(line, tracks_count);
310    INF("video with %d audio tracks (current = %d):", tracks_count, track_current);
311    ev->audio_channels = calloc(
312       tracks_count, sizeof(Emotion_Generic_Audio_Channel));
313    ev->audio_channels_count = tracks_count;
314    ev->audio_channel_current = track_current;
315    for (i = 0; i < tracks_count; i++)
316      {
317         int tid, len;
318         char buf[PATH_MAX];
319         RCV_CMD_PARAM(line, tid);
320         RCV_CMD_STR(line, buf, len);
321         ev->audio_channels[i].id = tid;
322         ev->audio_channels[i].name = eina_stringshare_add_length(buf, len);
323         INF("\t%d: %s", tid, buf);
324      }
325 }
326
327 static void
328 _player_file_closed(Emotion_Generic_Video *ev)
329 {
330    INF("Closed previous file.");
331    sem_destroy(&ev->shared->lock);
332
333    ev->closing = EINA_FALSE;
334
335    if (ev->opening)
336      _file_open(ev);
337 }
338
339 static void
340 _player_open_done(Emotion_Generic_Video *ev)
341 {
342    ev->opening = EINA_FALSE;
343    shm_unlink(ev->shmname);
344    _emotion_open_done(ev->obj);
345
346    if (ev->play)
347      {
348         _player_send_cmd(ev, EM_CMD_PLAY);
349         _player_send_float(ev, ev->pos);
350      }
351
352    INF("Open done");
353 }
354
355 static void
356 _player_read_cmd(Emotion_Generic_Video *ev, void *line, int size)
357 {
358    int type;
359    RCV_CMD_PARAM(line, type);
360
361    switch (type) {
362       case EM_RESULT_INIT:
363          _player_ready(ev);
364          break;
365       case EM_RESULT_FRAME_NEW:
366          _player_new_frame(ev);
367          break;
368       case EM_RESULT_FILE_SET:
369          _player_file_set_done(ev);
370          break;
371       case EM_RESULT_FILE_SET_DONE:
372          _player_open_done(ev);
373          break;
374       case EM_RESULT_FILE_CLOSE:
375          _player_file_closed(ev);
376          break;
377       case EM_RESULT_PLAYBACK_STOPPED:
378          _emotion_playback_finished(ev->obj);
379          break;
380       case EM_RESULT_FRAME_SIZE:
381          _player_frame_resize(ev, line);
382          break;
383       case EM_RESULT_LENGTH_CHANGED:
384          _player_length_changed(ev, line);
385          break;
386       case EM_RESULT_POSITION_CHANGED:
387          _player_position_changed(ev, line);
388          break;
389       case EM_RESULT_SEEKABLE_CHANGED:
390          _player_seekable_changed(ev, line);
391          break;
392       case EM_RESULT_AUDIO_TRACK_INFO:
393          _player_audio_tracks_info(ev, line);
394          break;
395       default:
396          WRN("received wrong command: %d", type);
397    };
398 }
399
400 #undef RCV_CMD_PARAM
401
402 static Eina_Bool
403 _player_data_cb(void *data, int type __UNUSED__, void *event)
404 {
405    Ecore_Exe_Event_Data *ev = event;
406    Emotion_Generic_Video *evideo = data;
407    int psize;
408    char *pdata;
409    int i;
410
411    if (ev->exe != evideo->player.exe)
412      {
413         ERR("slave != ev->exe");
414         return ECORE_CALLBACK_DONE;
415      }
416
417    if (ev->size < 4)
418      {
419         ERR("invalid command: missing bytes.");
420         return ECORE_CALLBACK_DONE;
421      }
422
423    for (i = 0; ev->lines[i].line; i++)
424      _player_read_cmd(evideo, ev->lines[i].line, ev->lines[i].size);
425
426    return ECORE_CALLBACK_DONE;
427 }
428
429 static Eina_Bool
430 _player_add_cb(void *data, int type __UNUSED__, void *event)
431 {
432    Ecore_Exe_Event_Add *event_add = event;
433    Ecore_Exe *player = event_add->exe;
434    Emotion_Generic_Video *ev = data;
435
436    if (ev->player.exe != player)
437      {
438         ERR("ev->player != player.");
439         return ECORE_CALLBACK_DONE;
440      }
441
442    _player_send_cmd(ev, EM_CMD_INIT);
443    _player_send_str(ev, ev->shmname, EINA_TRUE);
444
445    return ECORE_CALLBACK_DONE;
446 }
447
448 static Eina_Bool
449 _player_del_cb(void *data, int type __UNUSED__, void *event)
450 {
451    Ecore_Exe_Event_Del *event_del = event;
452    Ecore_Exe *player = event_del->exe;
453    Emotion_Generic_Video *ev = data;
454    ERR("player died.");
455
456    ev->player.exe = NULL;
457    ev->ready = EINA_FALSE;
458    _emotion_decode_stop(ev->obj);
459
460    return ECORE_CALLBACK_DONE;
461 }
462
463 static Eina_Bool
464 _fork_and_exec(Evas_Object *obj, Emotion_Generic_Video *ev)
465 {
466    char shmname[256];
467    struct timeval tv;
468
469    gettimeofday(&tv, NULL);
470    snprintf(shmname, sizeof(shmname), "/em-generic-shm_%d_%d",
471             (int)tv.tv_sec, (int)tv.tv_usec);
472
473    ev->shmname = eina_stringshare_add(shmname);
474
475    ev->player_add = ecore_event_handler_add(
476       ECORE_EXE_EVENT_ADD, _player_add_cb, ev);
477    ev->player_del = ecore_event_handler_add(
478       ECORE_EXE_EVENT_DEL, _player_del_cb, ev);
479    ev->player_data = ecore_event_handler_add(
480       ECORE_EXE_EVENT_DATA, _player_data_cb, ev);
481
482    ev->player.exe = ecore_exe_pipe_run(
483       ev->cmdline,
484       ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE |
485       ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_NOT_LEADER,
486       ev);
487
488    if (!ev->player.exe)
489      {
490         ERR("could not start player.");
491         return EINA_FALSE;
492      }
493
494    ev->initializing = EINA_TRUE;
495
496    return EINA_TRUE;
497 }
498
499 static unsigned char
500 em_init(Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt)
501 {
502    Emotion_Generic_Video *ev;
503
504    if (!emotion_video) return 0;
505
506    ev = (Emotion_Generic_Video *)calloc(1, sizeof(*ev));
507    if (!ev) return 0;
508
509    ev->speed = 1.0;
510    ev->volume = 0.5;
511    ev->audio_mute = EINA_FALSE;
512
513    ev->obj = obj;
514    ev->cmdline = eina_stringshare_add(_get_player(opt->player));
515    *emotion_video = ev;
516
517    return _fork_and_exec(obj, ev);
518 }
519
520 static int
521 em_shutdown(void *data)
522 {
523    Emotion_Generic_Video *ev = data;
524
525    if (!ev) return 0;
526
527    if (ev->player.exe)
528      {
529         ecore_exe_terminate(ev->player.exe);
530         ecore_exe_free(ev->player.exe);
531         ev->player.exe = NULL;
532      }
533
534    if (ev->shared)
535      munmap(ev->shared, ev->shared->size);
536
537    _audio_channels_free(ev);
538
539    eina_stringshare_del(ev->cmdline);
540    eina_stringshare_del(ev->shmname);
541
542    ecore_event_handler_del(ev->player_add);
543    ecore_event_handler_del(ev->player_data);
544    ecore_event_handler_del(ev->player_del);
545
546    return 1;
547 }
548
549 static unsigned char
550 em_file_open(const char *file, Evas_Object *obj, void *data)
551 {
552    Emotion_Generic_Video *ev = data;
553    INF("file set: %s", file);
554    if (!ev) return 0;
555
556    ev->pos = 0;
557    ev->opening = EINA_TRUE;
558
559    eina_stringshare_replace(&ev->filename, file);
560
561    if (!ev->closing)
562      _file_open(ev);
563
564    return 1;
565 }
566
567 static void
568 em_file_close(void *data)
569 {
570    Emotion_Generic_Video *ev = data;
571
572    if (!ev) return;
573    INF("file close: %s", ev->filename);
574
575    if (!ev->filename)
576      return;
577
578    _player_send_cmd(ev, EM_CMD_FILE_CLOSE);
579    ev->closing = EINA_TRUE;
580 }
581
582 static Emotion_Format
583 em_format_get(void *ef)
584 {
585    return EMOTION_FORMAT_BGRA;
586 }
587
588 static void
589 em_video_data_size_get(void *data, int *w, int *h)
590 {
591    Emotion_Generic_Video *ev = data;
592
593    if (!ev) return;
594    if (w) *w = ev->w;
595    if (h) *h = ev->h;
596 }
597
598 static void
599 em_play(void *data, double pos)
600 {
601    Emotion_Generic_Video *ev = data;
602
603    if (!ev)
604      return;
605
606    ev->play = EINA_TRUE;
607    INF("play: %0.3f", pos);
608
609    if (ev->initializing || ev->opening)
610      return;
611
612    if (ev->ready)
613      {
614         _player_send_cmd(ev, EM_CMD_PLAY);
615         _player_send_float(ev, ev->pos);
616         return;
617      }
618
619    ev->player.exe = ecore_exe_pipe_run(
620       ev->cmdline,
621       ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE |
622       ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_NOT_LEADER,
623       ev);
624
625    if (!ev->player.exe)
626      ERR("could not start player.");
627 }
628
629 static void
630 em_stop(void *data)
631 {
632    Emotion_Generic_Video *ev = data;
633
634    if (!ev)
635      return;
636
637    ev->play = EINA_FALSE;
638
639    if (!ev->ready)
640      return;
641
642    _player_send_cmd(ev, EM_CMD_STOP);
643    _emotion_decode_stop(ev->obj);
644 }
645
646 static void
647 em_size_get(void *data, int *w, int *h)
648 {
649    Emotion_Generic_Video *ev = data;
650    if(w) *w = ev->w;
651    if(h) *h = ev->h;
652 }
653
654 static void
655 em_pos_set(void *data, double pos)
656 {
657    Emotion_Generic_Video *ev = data;
658    float position = pos;
659    _player_send_cmd(ev, EM_CMD_POSITION_SET);
660    _player_send_float(ev, position);
661    _emotion_seek_done(ev->obj);
662 }
663
664 static double
665 em_len_get(void *data)
666 {
667    Emotion_Generic_Video *ev = data;
668    return ev->len;
669 }
670
671 static int
672 em_fps_num_get(void *data)
673 {
674    Emotion_Generic_Video *ev = data;
675    return (int)(ev->fps * 1000.0);
676 }
677
678 static int
679 em_fps_den_get(void *ef)
680 {
681    return 1000;
682 }
683
684 static double
685 em_fps_get(void *data)
686 {
687    Emotion_Generic_Video *ev = data;
688    return ev->fps;
689 }
690
691 static double
692 em_pos_get(void *data)
693 {
694    Emotion_Generic_Video *ev = data;
695    return ev->pos;
696 }
697
698 static void
699 em_vis_set(void *ef, Emotion_Vis vis)
700 {
701 }
702
703 static Emotion_Vis
704 em_vis_get(void *data)
705 {
706    Emotion_Generic_Video *ev = data;
707    return ev->vis;
708 }
709
710 static Eina_Bool
711 em_vis_supported(void *ef, Emotion_Vis vis)
712 {
713    return EINA_FALSE;
714 }
715
716 static double
717 em_ratio_get(void *data)
718 {
719    Emotion_Generic_Video *ev = data;
720    return ev->ratio;
721 }
722
723 static int em_video_handled(void *ef)
724 {
725    fprintf(stderr, "video handled!\n");
726    return 1;
727 }
728
729 static int em_audio_handled(void *ef)
730 {
731    fprintf(stderr, "audio handled!\n");
732    return 1;
733 }
734
735 static int em_seekable(void *data)
736 {
737    Emotion_Generic_Video *ev = data;
738    return ev->seekable;
739 }
740
741 static void em_frame_done(void *ef)
742 {
743 }
744
745 static int
746 em_yuv_rows_get(void *data, int w, int h, unsigned char **yrows, unsigned char **urows, unsigned char **vrows)
747 {
748    Emotion_Generic_Video *ev;
749    volatile Emotion_Generic_Video_Shared *vs;
750    return 0;
751 }
752
753 static int
754 em_bgra_data_get(void *data, unsigned char **bgra_data)
755 {
756    Emotion_Generic_Video *ev = data;
757
758    if (!ev || ev->opening || ev->closing)
759      return 0;
760
761    // lock frame here
762    sem_wait(&ev->shared->lock);
763
764    // send current frame to emotion
765    if (ev->shared->frame.emotion != ev->shared->frame.last)
766      {
767         ev->shared->frame.next = ev->shared->frame.emotion;
768         ev->shared->frame.emotion = ev->shared->frame.last;
769      }
770    *bgra_data = ev->frame.frames[ev->shared->frame.emotion];
771
772    // unlock frame here
773    sem_post(&ev->shared->lock);
774    ev->drop = 0;
775
776    return 1;
777 }
778
779 static void
780 em_event_feed(void *ef, int event)
781 {
782 }
783
784 static void
785 em_event_mouse_button_feed(void *ef, int button, int x, int y)
786 {
787 }
788
789 static void
790 em_event_mouse_move_feed(void *ef, int x, int y)
791 {
792 }
793
794 static int
795 em_video_channel_count(void *ef)
796 {
797    int ret  = 0;
798    return ret;
799 }
800
801 static void
802 em_video_channel_set(void *ef, int channel)
803 {
804 }
805
806 static int
807 em_video_channel_get(void *ef)
808 {
809    return 1;
810 }
811
812 static const char *
813 em_video_channel_name_get(void *ef, int channel)
814 {
815    return NULL;
816 }
817
818 static void
819 em_video_channel_mute_set(void *ef, int mute)
820 {
821 }
822
823 static int
824 em_video_channel_mute_get(void *data)
825 {
826    Emotion_Generic_Video *ev = data;
827    return ev->video_mute;
828 }
829
830 static int
831 em_audio_channel_count(void *data)
832 {
833    Emotion_Generic_Video *ev = data;
834    return ev->audio_channels_count;
835 }
836
837 static void
838 em_audio_channel_set(void *data, int channel)
839 {
840    Emotion_Generic_Video *ev = data;
841    int i;
842
843    for (i = 0; i < ev->audio_channels_count; i++)
844      {
845         if (ev->audio_channels[i].id == channel)
846           {
847              _player_send_cmd(ev, EM_CMD_AUDIO_TRACK_SET);
848              _player_send_int(ev, channel);
849              break;
850           }
851      }
852 }
853
854 static int
855 em_audio_channel_get(void *data)
856 {
857    Emotion_Generic_Video *ev = data;
858    return ev->audio_channel_current;
859 }
860
861 static const char *
862 em_audio_channel_name_get(void *data, int channel)
863 {
864    Emotion_Generic_Video *ev = data;
865    int i;
866
867    for (i = 0; i < ev->audio_channels_count; i++)
868      {
869         if (ev->audio_channels[i].id == channel)
870           return ev->audio_channels[i].name;
871      }
872
873    return NULL;
874 }
875
876 static void
877 em_audio_channel_mute_set(void *data, int mute)
878 {
879    Emotion_Generic_Video *ev = data;
880    _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET);
881    _player_send_int(ev, mute);
882    ev->audio_mute = !!mute;
883 }
884
885 static int
886 em_audio_channel_mute_get(void *data)
887 {
888    Emotion_Generic_Video *ev = data;
889    return ev->audio_mute;
890 }
891
892 static void
893 em_audio_channel_volume_set(void *data, double vol)
894 {
895    Emotion_Generic_Video *ev = data;
896    float fvol;
897
898    if (vol > 1.0) vol = 1.0;
899    if (vol < 0.0) vol = 0.0;
900
901    fvol = vol;
902    _player_send_cmd(ev, EM_CMD_VOLUME_SET);
903    _player_send_float(ev, fvol);
904
905    ev->volume = vol;
906 }
907
908 static double
909 em_audio_channel_volume_get(void *data)
910 {
911    Emotion_Generic_Video *ev = data;
912    return ev->volume;
913 }
914
915 static int
916 em_spu_channel_count(void *ef)
917 {
918    return 0;
919 }
920
921 static void
922 em_spu_channel_set(void *ef, int channel)
923 {
924 }
925
926 static int
927 em_spu_channel_get(void *ef)
928 {
929    int num = 0;
930    return num;
931 }
932
933 static const char *
934 em_spu_channel_name_get(void *ef, int channel)
935 {
936    return NULL;
937 }
938
939 static void
940 em_spu_channel_mute_set(void *ef, int mute)
941 {
942    return;
943 }
944
945 static int
946 em_spu_channel_mute_get(void *ef)
947 {
948    return 0;
949 }
950
951 static int
952 em_chapter_count(void *ef)
953 {
954    int num = 0;
955    return num;
956 }
957
958 static void
959 em_chapter_set(void *ef, int chapter)
960 {
961 }
962
963 static int
964 em_chapter_get(void *ef)
965 {
966    int num = 0;
967    return num;
968 }
969
970 static const char *
971 em_chapter_name_get(void *ef, int chapter)
972 {
973    return NULL;
974 }
975
976 static void
977 em_speed_set(void *data, double speed)
978 {
979    Emotion_Generic_Video *ev = data;
980    float rate = speed;
981
982    _player_send_cmd(ev, EM_CMD_SPEED_SET);
983    _player_send_float(ev, rate);
984
985    ev->speed = rate;
986 }
987
988 static double
989 em_speed_get(void *data)
990 {
991    Emotion_Generic_Video *ev = data;
992    return (double)ev->speed;
993 }
994
995 static int
996 em_eject(void *ef)
997 {
998    return 1;
999 }
1000
1001 static const char *
1002 em_meta_get(void *ef, int meta)
1003 {
1004    char * meta_data = NULL;
1005    return meta_data;
1006 }
1007
1008 static Emotion_Video_Module em_module =
1009 {
1010    em_init, /* init */
1011    em_shutdown, /* shutdown */
1012    em_file_open, /* file_open */
1013    em_file_close, /* file_close */
1014    em_play, /* play */
1015    em_stop, /* stop */
1016    em_size_get, /* size_get */
1017    em_pos_set, /* pos_set */
1018    em_len_get, /* len_get */
1019    em_fps_num_get, /* fps_num_get */
1020    em_fps_den_get, /* fps_den_get */
1021    em_fps_get, /* fps_get */
1022    em_pos_get, /* pos_get */
1023    em_vis_set, /* vis_set */
1024    em_vis_get, /* vis_get */
1025    em_vis_supported, /* vis_supported */
1026    em_ratio_get, /* ratio_get */
1027    em_video_handled, /* video_handled */
1028    em_audio_handled, /* audio_handled */
1029    em_seekable, /* seekable */
1030    em_frame_done, /* frame_done */
1031    em_format_get, /* format_get */
1032    em_video_data_size_get, /* video_data_size_get */
1033    em_yuv_rows_get, /* yuv_rows_get */
1034    em_bgra_data_get, /* bgra_data_get */
1035    em_event_feed, /* event_feed */
1036    em_event_mouse_button_feed, /* event_mouse_button_feed */
1037    em_event_mouse_move_feed, /* event_mouse_move_feed */
1038    em_video_channel_count, /* video_channel_count */
1039    em_video_channel_set, /* video_channel_set */
1040    em_video_channel_get, /* video_channel_get */
1041    em_video_channel_name_get, /* video_channel_name_get */
1042    em_video_channel_mute_set, /* video_channel_mute_set */
1043    em_video_channel_mute_get, /* video_channel_mute_get */
1044    em_audio_channel_count, /* audio_channel_count */
1045    em_audio_channel_set, /* audio_channel_set */
1046    em_audio_channel_get, /* audio_channel_get */
1047    em_audio_channel_name_get, /* audio_channel_name_get */
1048    em_audio_channel_mute_set, /* audio_channel_mute_set */
1049    em_audio_channel_mute_get, /* audio_channel_mute_get */
1050    em_audio_channel_volume_set, /* audio_channel_volume_set */
1051    em_audio_channel_volume_get, /* audio_channel_volume_get */
1052    em_spu_channel_count, /* spu_channel_count */
1053    em_spu_channel_set, /* spu_channel_set */
1054    em_spu_channel_get, /* spu_channel_get */
1055    em_spu_channel_name_get, /* spu_channel_name_get */
1056    em_spu_channel_mute_set, /* spu_channel_mute_set */
1057    em_spu_channel_mute_get, /* spu_channel_mute_get */
1058    em_chapter_count, /* chapter_count */
1059    em_chapter_set, /* chapter_set */
1060    em_chapter_get, /* chapter_get */
1061    em_chapter_name_get, /* chapter_name_get */
1062    em_speed_set, /* speed_set */
1063    em_speed_get, /* speed_get */
1064    em_eject, /* eject */
1065    em_meta_get, /* meta_get */
1066    NULL /* handle */
1067 };
1068
1069 static Eina_Bool
1070 module_open(Evas_Object *obj, const Emotion_Video_Module **module, void **video, Emotion_Module_Options *opt)
1071 {
1072    if (!module) {
1073         return EINA_FALSE;
1074    }
1075
1076    if (_emotion_generic_log_domain < 0)
1077      {
1078         eina_threads_init();
1079         eina_log_threads_enable();
1080         _emotion_generic_log_domain = eina_log_domain_register
1081           ("emotion-generic", EINA_COLOR_LIGHTCYAN);
1082         if (_emotion_generic_log_domain < 0)
1083           {
1084              EINA_LOG_CRIT("Could not register log domain 'emotion-generic'");
1085              return EINA_FALSE;
1086           }
1087      }
1088
1089
1090    if (!em_module.init(obj, video, opt))        {
1091         return EINA_FALSE;
1092    }
1093
1094    *module = &em_module;
1095
1096    return EINA_TRUE;
1097 }
1098
1099 static void module_close(Emotion_Video_Module *module, void *video)
1100 {
1101         em_module.shutdown(video);
1102 }
1103
1104
1105 Eina_Bool
1106 generic_module_init(void)
1107 {
1108    return _emotion_module_register("generic", module_open, module_close);
1109 }
1110
1111 void
1112 generic_module_shutdown(void)
1113 {
1114    _emotion_module_unregister("generic");
1115 }
1116
1117 #ifndef EMOTION_STATIC_BUILD_GENERIC
1118
1119 EINA_MODULE_INIT(generic_module_init);
1120 EINA_MODULE_SHUTDOWN(generic_module_shutdown);
1121
1122 #endif
1123