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