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