emotion/generic: Postpone setting some options to after open_done.
[profile/ivi/emotion.git] / src / modules / generic / emotion_generic.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4 #include <sys/mman.h>
5 #include <sys/stat.h>
6 #include <sys/time.h>
7 #include <sys/types.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include <Eina.h>
11 #include <Evas.h>
12
13 #include "Emotion.h"
14 #include "emotion_private.h"
15 #include "emotion_generic.h"
16
17 static Eina_Prefix *pfx = NULL;
18
19 static int _emotion_generic_log_domain = -1;
20 #define DBG(...) EINA_LOG_DOM_DBG(_emotion_generic_log_domain, __VA_ARGS__)
21 #define INF(...) EINA_LOG_DOM_INFO(_emotion_generic_log_domain, __VA_ARGS__)
22 #define WRN(...) EINA_LOG_DOM_WARN(_emotion_generic_log_domain, __VA_ARGS__)
23 #define ERR(...) EINA_LOG_DOM_ERR(_emotion_generic_log_domain, __VA_ARGS__)
24 #define CRITICAL(...) EINA_LOG_DOM_CRIT(_emotion_generic_log_domain, __VA_ARGS__)
25
26
27 struct _default_players {
28    const char *name;
29    const char *cmdline;
30 };
31
32 static struct _default_players players[] = {
33 #ifdef EMOTION_BUILD_GENERIC_VLC
34        { "vlc", "em_generic_vlc" },
35 #endif
36        { NULL, NULL }
37 };
38
39 static const char *
40 _get_player(const char *name)
41 {
42    const char *selected_name = NULL;
43    const char *libdir = eina_prefix_lib_get(pfx);
44    static char buf[PATH_MAX];
45    int i;
46
47    if (name)
48      {
49         for (i = 0; players[i].name; i++)
50           {
51              if (!strcmp(players[i].name, name))
52                {
53                   selected_name = players[i].cmdline;
54                   break;
55                }
56           }
57      }
58
59    if ((!selected_name) && (name))
60      selected_name = name;
61
62    if (selected_name)
63      {
64         const char *cmd;
65
66         if (selected_name[0] == '/') cmd = selected_name;
67         else
68           {
69              snprintf(buf, sizeof(buf), "%s/emotion/utils/%s",
70                       libdir, selected_name);
71              cmd = buf;
72           }
73
74         DBG("Try generic player '%s'", cmd);
75         if (access(cmd, R_OK | X_OK) == 0)
76           {
77              INF("Using generic player '%s'", cmd);
78              return cmd;
79           }
80      }
81
82    for (i = 0; players[i].name; i++)
83      {
84         snprintf(buf, sizeof(buf), "%s/emotion/utils/%s",
85                  libdir, players[i].cmdline);
86         DBG("Try generic player '%s'", buf);
87         if (access(buf, R_OK | X_OK) == 0)
88           {
89              INF("Using fallback player '%s'", buf);
90              return buf;
91           }
92      }
93
94    ERR("no generic player found, given name='%s'", name ? name : "");
95    return NULL;
96 }
97
98 static void
99 _player_send_cmd(Emotion_Generic_Video *ev, int cmd)
100 {
101    if (cmd >= EM_CMD_LAST)
102      {
103         ERR("invalid command to player.");
104         return;
105      }
106    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    vs->frame_drop = 0;
177    sem_init(&vs->lock, 1, 1);
178    ev->frame.frames[0] = (unsigned char *)vs + sizeof(*vs);
179    ev->frame.frames[1] = (unsigned char *)vs + sizeof(*vs) + vs->height * vs->width * vs->pitch;
180    ev->frame.frames[2] = (unsigned char *)vs + sizeof(*vs) + 2 * vs->height * vs->width * vs->pitch;
181
182    if (ev->shared)
183      munmap(ev->shared, ev->shared->size);
184    ev->shared = vs;
185
186    return EINA_TRUE;
187 }
188
189 static void
190 _player_new_frame(Emotion_Generic_Video *ev)
191 {
192    if (!ev->file_ready)
193      return;
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_helper_str_read(Emotion_Generic_Video *ev, const char **pstr)
502 {
503    int len;
504    char buf[PATH_MAX];
505    if (_player_str_read(ev, buf, &len))
506      *pstr = eina_stringshare_add_length(buf, len);
507 }
508
509 static void
510 _player_meta_info_free(Emotion_Generic_Video *ev)
511 {
512    eina_stringshare_replace(&ev->meta.title, NULL);
513    eina_stringshare_replace(&ev->meta.artist, NULL);
514    eina_stringshare_replace(&ev->meta.album, NULL);
515    eina_stringshare_replace(&ev->meta.year, NULL);
516    eina_stringshare_replace(&ev->meta.genre, NULL);
517    eina_stringshare_replace(&ev->meta.comment, NULL);
518    eina_stringshare_replace(&ev->meta.disc_id, NULL);
519    eina_stringshare_replace(&ev->meta.count, NULL);
520 }
521
522 static void
523 _player_meta_info_read(Emotion_Generic_Video *ev)
524 {
525    INF("Receiving meta info:");
526    _player_meta_info_free(ev);
527    _player_helper_str_read(ev, &ev->meta.title);
528    _player_helper_str_read(ev, &ev->meta.artist);
529    _player_helper_str_read(ev, &ev->meta.album);
530    _player_helper_str_read(ev, &ev->meta.year);
531    _player_helper_str_read(ev, &ev->meta.genre);
532    _player_helper_str_read(ev, &ev->meta.comment);
533    _player_helper_str_read(ev, &ev->meta.disc_id);
534    _player_helper_str_read(ev, &ev->meta.count);
535    INF("title: '%s'", ev->meta.title);
536    INF("artist: '%s'", ev->meta.artist);
537    INF("album: '%s'", ev->meta.album);
538    INF("year: '%s'", ev->meta.year);
539    INF("genre: '%s'", ev->meta.genre);
540    INF("comment: '%s'", ev->meta.comment);
541    INF("disc_id: '%s'", ev->meta.disc_id);
542    INF("count: '%s'", ev->meta.count);
543 }
544
545 static void
546 _player_file_closed(Emotion_Generic_Video *ev)
547 {
548    INF("Closed previous file.");
549    sem_destroy(&ev->shared->lock);
550
551    ev->closing = EINA_FALSE;
552
553    if (ev->opening)
554      _file_open(ev);
555 }
556
557 static void
558 _player_open_done(Emotion_Generic_Video *ev)
559 {
560    int success;
561
562    _player_int_read(ev, &success);
563    shm_unlink(ev->shmname);
564
565    if (ev->file_changed)
566      {
567         _file_open(ev);
568         ev->file_changed = EINA_FALSE;
569         return;
570      }
571
572    ev->opening = EINA_FALSE;
573    if (!success)
574      {
575         ERR("Could not open file.");
576         return;
577      }
578
579    ev->file_ready = EINA_TRUE;
580
581    _emotion_open_done(ev->obj);
582
583    if (ev->play)
584      {
585         _player_send_cmd(ev, EM_CMD_PLAY);
586         _player_send_float(ev, ev->pos);
587      }
588
589    _player_send_cmd(ev, EM_CMD_VOLUME_SET);
590    _player_send_float(ev, ev->volume);
591
592    _player_send_cmd(ev, EM_CMD_SPEED_SET);
593    _player_send_float(ev, ev->speed);
594
595    int mute = ev->audio_mute;
596    _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET);
597    _player_send_int(ev, mute);
598
599    mute = ev->video_mute;
600    _player_send_cmd(ev, EM_CMD_VIDEO_MUTE_SET);
601    _player_send_int(ev, mute);
602
603    mute = ev->spu_mute;
604    _player_send_cmd(ev, EM_CMD_SPU_MUTE_SET);
605    _player_send_int(ev, mute);
606
607    INF("Open done");
608 }
609
610 static void
611 _player_read_cmd(Emotion_Generic_Video *ev)
612 {
613    int type;
614
615    if (!_player_int_read(ev, &type))
616      {
617         ERR("could not read command\n");
618         return;
619      }
620
621    switch (type) {
622       case EM_RESULT_INIT:
623          _player_ready(ev);
624          break;
625       case EM_RESULT_FRAME_NEW:
626          _player_new_frame(ev);
627          break;
628       case EM_RESULT_FILE_SET:
629          _player_file_set_done(ev);
630          break;
631       case EM_RESULT_FILE_SET_DONE:
632          _player_open_done(ev);
633          break;
634       case EM_RESULT_FILE_CLOSE:
635          _player_file_closed(ev);
636          break;
637       case EM_RESULT_PLAYBACK_STOPPED:
638          _emotion_playback_finished(ev->obj);
639          break;
640       case EM_RESULT_FRAME_SIZE:
641          _player_frame_resize(ev);
642          break;
643       case EM_RESULT_LENGTH_CHANGED:
644          _player_length_changed(ev);
645          break;
646       case EM_RESULT_POSITION_CHANGED:
647          _player_position_changed(ev);
648          break;
649       case EM_RESULT_SEEKABLE_CHANGED:
650          _player_seekable_changed(ev);
651          break;
652       case EM_RESULT_AUDIO_TRACK_INFO:
653          _player_audio_tracks_info(ev);
654          break;
655       case EM_RESULT_VIDEO_TRACK_INFO:
656          _player_video_tracks_info(ev);
657          break;
658       case EM_RESULT_SPU_TRACK_INFO:
659          _player_spu_tracks_info(ev);
660          break;
661       case EM_RESULT_META_INFO:
662          _player_meta_info_read(ev);
663          break;
664       default:
665          WRN("received wrong command: %d", type);
666    };
667 }
668
669 static Eina_Bool
670 _player_cmd_handler_cb(void *data, Ecore_Fd_Handler *fd_handler)
671 {
672    Emotion_Generic_Video *ev = data;
673
674    if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
675      {
676         ERR("an error occurred on fd_read %d.", ev->fd_read);
677         return ECORE_CALLBACK_CANCEL;
678      }
679
680    _player_read_cmd(ev);
681
682    return ECORE_CALLBACK_RENEW;
683 }
684
685 static Eina_Bool
686 _player_data_cb(void *data, int type __UNUSED__, void *event)
687 {
688    Ecore_Exe_Event_Data *ev = event;
689    Emotion_Generic_Video *evideo = data;
690    int i;
691
692    if (ev->exe != evideo->player.exe)
693      {
694         ERR("slave != ev->exe");
695         return ECORE_CALLBACK_DONE;
696      }
697
698    for (i = 0; ev->lines[i].line; i++)
699      INF("received input from player: \"%s\"", ev->lines[i].line);
700
701    return ECORE_CALLBACK_DONE;
702 }
703
704 static Eina_Bool
705 _player_add_cb(void *data, int type __UNUSED__, void *event)
706 {
707    Ecore_Exe_Event_Add *event_add = event;
708    Ecore_Exe *player = event_add->exe;
709    Emotion_Generic_Video *ev = data;
710
711    if (ev->player.exe != player)
712      {
713         ERR("ev->player != player.");
714         return ECORE_CALLBACK_DONE;
715      }
716
717    _player_send_cmd(ev, EM_CMD_INIT);
718    _player_send_str(ev, ev->shmname, EINA_TRUE);
719
720    return ECORE_CALLBACK_DONE;
721 }
722
723 static Eina_Bool
724 _player_del_cb(void *data, int type __UNUSED__, void *event __UNUSED__)
725 {
726    Emotion_Generic_Video *ev = data;
727    ERR("player died.");
728
729    ev->player.exe = NULL;
730    ev->ready = EINA_FALSE;
731    ev->file_ready = EINA_FALSE;
732    ecore_main_fd_handler_del(ev->fd_handler);
733    close(ev->fd_read);
734    close(ev->fd_write);
735    ev->fd_read = -1;
736    ev->fd_write = -1;
737    _emotion_decode_stop(ev->obj);
738
739    return ECORE_CALLBACK_DONE;
740 }
741
742 static Eina_Bool
743 _player_exec(Emotion_Generic_Video *ev)
744 {
745    int pipe_out[2];
746    int pipe_in[2];
747    char buf[PATH_MAX];
748
749    if (pipe(pipe_out) == -1)
750      {
751         ERR("could not create pipe for communication emotion -> player: %s", strerror(errno));
752         return EINA_FALSE;
753      }
754
755    if (pipe(pipe_in) == -1)
756      {
757         ERR("could not create pipe for communication player -> emotion: %s", strerror(errno));
758         close(pipe_out[0]);
759         close(pipe_out[1]);
760         return EINA_FALSE;
761      }
762
763    snprintf(buf, sizeof(buf), "%s %d %d\n", ev->cmdline, pipe_out[0], pipe_in[1]);
764
765    ev->player.exe = ecore_exe_pipe_run(
766       buf,
767       ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE |
768       ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_NOT_LEADER,
769       ev);
770
771    INF("created pipe emotion -> player: %d -> %d\n", pipe_out[1], pipe_out[0]);
772    INF("created pipe player -> emotion: %d -> %d\n", pipe_in[1], pipe_in[0]);
773
774    close(pipe_in[1]);
775    close(pipe_out[0]);
776
777    if (!ev->player.exe)
778      {
779         close(pipe_in[0]);
780         close(pipe_out[1]);
781         return EINA_FALSE;
782      }
783
784    ev->fd_read = pipe_in[0];
785    ev->fd_write = pipe_out[1];
786
787    ev->fd_handler = ecore_main_fd_handler_add(
788       ev->fd_read, ECORE_FD_READ | ECORE_FD_ERROR, _player_cmd_handler_cb, ev,
789       NULL, NULL);
790
791    return EINA_TRUE;
792 }
793
794 static Eina_Bool
795 _fork_and_exec(Evas_Object *obj, Emotion_Generic_Video *ev)
796 {
797    char shmname[256];
798    struct timeval tv;
799
800    gettimeofday(&tv, NULL);
801    snprintf(shmname, sizeof(shmname), "/em-generic-shm_%d_%d",
802             (int)tv.tv_sec, (int)tv.tv_usec);
803
804    ev->shmname = eina_stringshare_add(shmname);
805
806    ev->player_add = ecore_event_handler_add(
807       ECORE_EXE_EVENT_ADD, _player_add_cb, ev);
808    ev->player_del = ecore_event_handler_add(
809       ECORE_EXE_EVENT_DEL, _player_del_cb, ev);
810    ev->player_data = ecore_event_handler_add(
811       ECORE_EXE_EVENT_DATA, _player_data_cb, ev);
812
813
814    if (!_player_exec(ev))
815      {
816         ERR("could not start player.");
817         return EINA_FALSE;
818      }
819
820    ev->initializing = EINA_TRUE;
821
822    return EINA_TRUE;
823 }
824
825 static unsigned char
826 em_init(Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt)
827 {
828    Emotion_Generic_Video *ev;
829    const char *player;
830
831    if (!emotion_video) return 0;
832    player = _get_player(opt ? opt->player : NULL);
833    if (!player) return 0;
834
835    ev = (Emotion_Generic_Video *)calloc(1, sizeof(*ev));
836    if (!ev) return 0;
837
838    ev->fd_read = -1;
839    ev->fd_write = -1;
840    ev->speed = 1.0;
841    ev->volume = 0.5;
842    ev->audio_mute = EINA_FALSE;
843
844    ev->obj = obj;
845    ev->cmdline = eina_stringshare_add(player);
846    *emotion_video = ev;
847
848    return _fork_and_exec(obj, ev);
849 }
850
851 static int
852 em_shutdown(void *data)
853 {
854    Emotion_Generic_Video *ev = data;
855
856    if (!ev) return 0;
857
858    if (ev->player.exe)
859      {
860         ecore_exe_terminate(ev->player.exe);
861         ecore_exe_free(ev->player.exe);
862         ev->player.exe = NULL;
863      }
864
865    if (ev->shared)
866      munmap(ev->shared, ev->shared->size);
867
868    if (ev->fd_read >= 0)
869      close(ev->fd_read);
870    if (ev->fd_write >= 0)
871      close(ev->fd_write);
872    if (ev->fd_handler)
873      ecore_main_fd_handler_del(ev->fd_handler);
874
875    eina_stringshare_del(ev->cmdline);
876    eina_stringshare_del(ev->shmname);
877
878    ecore_event_handler_del(ev->player_add);
879    ecore_event_handler_del(ev->player_data);
880    ecore_event_handler_del(ev->player_del);
881
882    return 1;
883 }
884
885 static unsigned char
886 em_file_open(const char *file, Evas_Object *obj __UNUSED__, void *data)
887 {
888    Emotion_Generic_Video *ev = data;
889    INF("file set: %s", file);
890    if (!ev) return 0;
891
892    eina_stringshare_replace(&ev->filename, file);
893
894    ev->pos = 0;
895    ev->w = 0;
896    ev->h = 0;
897    ev->ratio = 1;
898    ev->len = 0;
899
900    if (ev->ready && ev->opening)
901      {
902         INF("file changed while opening.");
903         ev->file_changed = EINA_TRUE;
904         return 1;
905      }
906
907    ev->opening = EINA_TRUE;
908
909    if (!ev->closing)
910      _file_open(ev);
911
912    return 1;
913 }
914
915 static void
916 em_file_close(void *data)
917 {
918    Emotion_Generic_Video *ev = data;
919
920    if (!ev || !ev->filename) return;
921
922    INF("file close: %s", ev->filename);
923
924    eina_stringshare_replace(&ev->filename, NULL);
925
926    ev->file_ready = EINA_FALSE;
927    _audio_channels_free(ev);
928    _video_channels_free(ev);
929    _spu_channels_free(ev);
930    _player_meta_info_free(ev);
931
932    if (ev->opening)
933      return;
934
935    _player_send_cmd(ev, EM_CMD_FILE_CLOSE);
936    ev->closing = EINA_TRUE;
937 }
938
939 static Emotion_Format
940 em_format_get(void *ef __UNUSED__)
941 {
942    return EMOTION_FORMAT_BGRA;
943 }
944
945 static void
946 em_video_data_size_get(void *data, int *w, int *h)
947 {
948    Emotion_Generic_Video *ev = data;
949
950    if (!ev) return;
951    if (w) *w = ev->w;
952    if (h) *h = ev->h;
953 }
954
955 static void
956 em_play(void *data, double pos)
957 {
958    Emotion_Generic_Video *ev = data;
959
960    if (!ev)
961      return;
962
963    ev->play = EINA_TRUE;
964    INF("play: %0.3f", pos);
965
966    if (ev->initializing || ev->opening)
967      return;
968
969    if (ev->ready)
970      {
971         _player_send_cmd(ev, EM_CMD_PLAY);
972         _player_send_float(ev, ev->pos);
973         return;
974      }
975
976    if (!_player_exec(ev))
977      ERR("could not start player.");
978 }
979
980 static void
981 em_stop(void *data)
982 {
983    Emotion_Generic_Video *ev = data;
984
985    if (!ev)
986      return;
987
988    ev->play = EINA_FALSE;
989
990    if (!ev->file_ready)
991      return;
992
993    _player_send_cmd(ev, EM_CMD_STOP);
994    _emotion_decode_stop(ev->obj);
995 }
996
997 static void
998 em_size_get(void *data, int *w, int *h)
999 {
1000    Emotion_Generic_Video *ev = data;
1001    if (w) *w = ev->w;
1002    if (h) *h = ev->h;
1003 }
1004
1005 static void
1006 em_pos_set(void *data, double pos)
1007 {
1008    Emotion_Generic_Video *ev = data;
1009    float position = pos;
1010
1011    if (!ev->file_ready)
1012      return;
1013
1014    _player_send_cmd(ev, EM_CMD_POSITION_SET);
1015    _player_send_float(ev, position);
1016    _emotion_seek_done(ev->obj);
1017 }
1018
1019 static double
1020 em_len_get(void *data)
1021 {
1022    Emotion_Generic_Video *ev = data;
1023    return ev->len;
1024 }
1025
1026 static int
1027 em_fps_num_get(void *data)
1028 {
1029    Emotion_Generic_Video *ev = data;
1030    return (int)(ev->fps * 1000.0);
1031 }
1032
1033 static int
1034 em_fps_den_get(void *ef __UNUSED__)
1035 {
1036    return 1000;
1037 }
1038
1039 static double
1040 em_fps_get(void *data)
1041 {
1042    Emotion_Generic_Video *ev = data;
1043    return ev->fps;
1044 }
1045
1046 static double
1047 em_pos_get(void *data)
1048 {
1049    Emotion_Generic_Video *ev = data;
1050    return ev->pos;
1051 }
1052
1053 static void
1054 em_vis_set(void *ef __UNUSED__, Emotion_Vis vis __UNUSED__)
1055 {
1056 }
1057
1058 static Emotion_Vis
1059 em_vis_get(void *data)
1060 {
1061    Emotion_Generic_Video *ev = data;
1062    return ev->vis;
1063 }
1064
1065 static Eina_Bool
1066 em_vis_supported(void *ef __UNUSED__, Emotion_Vis vis __UNUSED__)
1067 {
1068    return EINA_FALSE;
1069 }
1070
1071 static double
1072 em_ratio_get(void *data)
1073 {
1074    Emotion_Generic_Video *ev = data;
1075    return ev->ratio;
1076 }
1077
1078 static int em_video_handled(void *ef __UNUSED__)
1079 {
1080    fprintf(stderr, "video handled!\n");
1081    return 1;
1082 }
1083
1084 static int em_audio_handled(void *ef __UNUSED__)
1085 {
1086    fprintf(stderr, "audio handled!\n");
1087    return 1;
1088 }
1089
1090 static int em_seekable(void *data)
1091 {
1092    Emotion_Generic_Video *ev = data;
1093    return ev->seekable;
1094 }
1095
1096 static void em_frame_done(void *ef __UNUSED__)
1097 {
1098 }
1099
1100 static int
1101 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__)
1102 {
1103    return 0;
1104 }
1105
1106 static int
1107 em_bgra_data_get(void *data, unsigned char **bgra_data)
1108 {
1109    Emotion_Generic_Video *ev = data;
1110
1111    if (!ev || !ev->file_ready)
1112      return;
1113
1114    // lock frame here
1115    sem_wait(&ev->shared->lock);
1116
1117    // send current frame to emotion
1118    if (ev->shared->frame.emotion != ev->shared->frame.last)
1119      {
1120         ev->shared->frame.next = ev->shared->frame.emotion;
1121         ev->shared->frame.emotion = ev->shared->frame.last;
1122      }
1123    *bgra_data = ev->frame.frames[ev->shared->frame.emotion];
1124
1125    if (ev->shared->frame_drop > 1)
1126      WRN("dropped frames: %d", ev->shared->frame_drop - 1);
1127    ev->shared->frame_drop = 0;
1128
1129    // unlock frame here
1130    sem_post(&ev->shared->lock);
1131    ev->drop = 0;
1132
1133    return 1;
1134 }
1135
1136 static void
1137 em_event_feed(void *ef __UNUSED__, int event __UNUSED__)
1138 {
1139 }
1140
1141 static void
1142 em_event_mouse_button_feed(void *ef __UNUSED__, int button __UNUSED__, int x __UNUSED__, int y __UNUSED__)
1143 {
1144 }
1145
1146 static void
1147 em_event_mouse_move_feed(void *ef __UNUSED__, int x __UNUSED__, int y __UNUSED__)
1148 {
1149 }
1150
1151 static int
1152 em_video_channel_count(void *data)
1153 {
1154    Emotion_Generic_Video *ev = data;
1155    return ev->video_channels_count;
1156 }
1157
1158 static void
1159 em_video_channel_set(void *data, int channel)
1160 {
1161    Emotion_Generic_Video *ev = data;
1162
1163    if (channel < 0 || channel >= ev->video_channels_count)
1164      {
1165         WRN("video channel out of range.");
1166         return;
1167      }
1168
1169    _player_send_cmd(ev, EM_CMD_VIDEO_TRACK_SET);
1170    _player_send_int(ev, ev->video_channels[channel].id);
1171    ev->video_channel_current = channel;
1172 }
1173
1174 static int
1175 em_video_channel_get(void *data)
1176 {
1177    Emotion_Generic_Video *ev = data;
1178    return ev->video_channel_current;
1179 }
1180
1181 static const char *
1182 em_video_channel_name_get(void *data, int channel)
1183 {
1184    Emotion_Generic_Video *ev = data;
1185
1186    if (channel < 0 || channel >= ev->video_channels_count)
1187      {
1188         WRN("video channel out of range.");
1189         return NULL;
1190      }
1191
1192    return ev->video_channels[channel].name;
1193 }
1194
1195 static void
1196 em_video_channel_mute_set(void *data, int mute)
1197 {
1198    Emotion_Generic_Video *ev = data;
1199
1200    ev->video_mute = !!mute;
1201
1202    if (!ev || !ev->file_ready)
1203      return;
1204
1205    _player_send_cmd(ev, EM_CMD_VIDEO_MUTE_SET);
1206    _player_send_int(ev, mute);
1207 }
1208
1209 static int
1210 em_video_channel_mute_get(void *data)
1211 {
1212    Emotion_Generic_Video *ev = data;
1213    return ev->video_mute;
1214 }
1215
1216 static int
1217 em_audio_channel_count(void *data)
1218 {
1219    Emotion_Generic_Video *ev = data;
1220    return ev->audio_channels_count;
1221 }
1222
1223 static void
1224 em_audio_channel_set(void *data, int channel)
1225 {
1226    Emotion_Generic_Video *ev = data;
1227
1228    if (channel < 0 || channel >= ev->audio_channels_count)
1229      {
1230         WRN("audio channel out of range.");
1231         return;
1232      }
1233
1234    _player_send_cmd(ev, EM_CMD_AUDIO_TRACK_SET);
1235    _player_send_int(ev, ev->audio_channels[channel].id);
1236    ev->audio_channel_current = channel;
1237 }
1238
1239 static int
1240 em_audio_channel_get(void *data)
1241 {
1242    Emotion_Generic_Video *ev = data;
1243    return ev->audio_channel_current;
1244 }
1245
1246 static const char *
1247 em_audio_channel_name_get(void *data, int channel)
1248 {
1249    Emotion_Generic_Video *ev = data;
1250
1251    if (channel < 0 || channel >= ev->audio_channels_count)
1252      {
1253         WRN("audio channel out of range.");
1254         return NULL;
1255      }
1256
1257    return ev->audio_channels[channel].name;
1258 }
1259
1260 static void
1261 em_audio_channel_mute_set(void *data, int mute)
1262 {
1263    Emotion_Generic_Video *ev = data;
1264
1265    ev->audio_mute = !!mute;
1266
1267    if (!ev || !ev->file_ready)
1268      return;
1269
1270    _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET);
1271    _player_send_int(ev, mute);
1272 }
1273
1274 static int
1275 em_audio_channel_mute_get(void *data)
1276 {
1277    Emotion_Generic_Video *ev = data;
1278    return ev->audio_mute;
1279 }
1280
1281 static void
1282 em_audio_channel_volume_set(void *data, double vol)
1283 {
1284    Emotion_Generic_Video *ev = data;
1285
1286    if (vol > 1.0) vol = 1.0;
1287    if (vol < 0.0) vol = 0.0;
1288
1289    ev->volume = vol;
1290
1291    if (!ev || !ev->file_ready)
1292      return;
1293
1294    _player_send_cmd(ev, EM_CMD_VOLUME_SET);
1295    _player_send_float(ev, ev->volume);
1296 }
1297
1298 static double
1299 em_audio_channel_volume_get(void *data)
1300 {
1301    Emotion_Generic_Video *ev = data;
1302    return ev->volume;
1303 }
1304
1305 static int
1306 em_spu_channel_count(void *data)
1307 {
1308    Emotion_Generic_Video *ev = data;
1309    return ev->spu_channels_count;
1310 }
1311
1312 static void
1313 em_spu_channel_set(void *data, int channel)
1314 {
1315    Emotion_Generic_Video *ev = data;
1316
1317    if (channel < 0 || channel >= ev->spu_channels_count)
1318      {
1319         WRN("spu channel out of range.");
1320         return;
1321      }
1322
1323    _player_send_cmd(ev, EM_CMD_SPU_TRACK_SET);
1324    _player_send_int(ev, ev->spu_channels[channel].id);
1325    ev->spu_channel_current = channel;
1326 }
1327
1328 static int
1329 em_spu_channel_get(void *data)
1330 {
1331    Emotion_Generic_Video *ev = data;
1332    return ev->spu_channel_current;
1333 }
1334
1335 static const char *
1336 em_spu_channel_name_get(void *data, int channel)
1337 {
1338    Emotion_Generic_Video *ev = data;
1339
1340    if (channel < 0 || channel >= ev->spu_channels_count)
1341      {
1342         WRN("spu channel out of range.");
1343         return NULL;
1344      }
1345
1346    return ev->spu_channels[channel].name;
1347 }
1348
1349 static void
1350 em_spu_channel_mute_set(void *data, int mute)
1351 {
1352    Emotion_Generic_Video *ev = data;
1353
1354    ev->spu_mute = !!mute;
1355
1356    if (!ev || !ev->file_ready)
1357      return;
1358
1359    _player_send_cmd(ev, EM_CMD_SPU_MUTE_SET);
1360    _player_send_int(ev, mute);
1361 }
1362
1363 static int
1364 em_spu_channel_mute_get(void *data)
1365 {
1366    Emotion_Generic_Video *ev = data;
1367    return ev->spu_mute;
1368 }
1369
1370 static int
1371 em_chapter_count(void *ef __UNUSED__)
1372 {
1373    int num = 0;
1374    return num;
1375 }
1376
1377 static void
1378 em_chapter_set(void *ef __UNUSED__, int chapter __UNUSED__)
1379 {
1380 }
1381
1382 static int
1383 em_chapter_get(void *ef __UNUSED__)
1384 {
1385    int num = 0;
1386    return num;
1387 }
1388
1389 static const char *
1390 em_chapter_name_get(void *ef __UNUSED__, int chapter __UNUSED__)
1391 {
1392    return NULL;
1393 }
1394
1395 static void
1396 em_speed_set(void *data, double speed)
1397 {
1398    Emotion_Generic_Video *ev = data;
1399    float rate = speed;
1400    ev->speed = rate;
1401
1402    if (!ev || !ev->file_ready)
1403      return;
1404
1405    _player_send_cmd(ev, EM_CMD_SPEED_SET);
1406    _player_send_float(ev, rate);
1407 }
1408
1409 static double
1410 em_speed_get(void *data)
1411 {
1412    Emotion_Generic_Video *ev = data;
1413    return (double)ev->speed;
1414 }
1415
1416 static int
1417 em_eject(void *ef __UNUSED__)
1418 {
1419    return 1;
1420 }
1421
1422 static const char *
1423 em_meta_get(void *data, int meta)
1424 {
1425    Emotion_Generic_Video *ev = data;
1426
1427    switch (meta) {
1428       case EMOTION_META_INFO_TRACK_TITLE:
1429          return ev->meta.title;
1430       case EMOTION_META_INFO_TRACK_ARTIST:
1431          return ev->meta.artist;
1432       case EMOTION_META_INFO_TRACK_ALBUM:
1433          return ev->meta.album;
1434       case EMOTION_META_INFO_TRACK_YEAR:
1435          return ev->meta.year;
1436       case EMOTION_META_INFO_TRACK_GENRE:
1437          return ev->meta.genre;
1438       case EMOTION_META_INFO_TRACK_COMMENT:
1439          return ev->meta.comment;
1440       case EMOTION_META_INFO_TRACK_DISC_ID:
1441          return ev->meta.disc_id;
1442       case EMOTION_META_INFO_TRACK_COUNT:
1443          return ev->meta.count;
1444    }
1445
1446    return NULL;
1447 }
1448
1449 static Emotion_Video_Module em_module =
1450 {
1451    em_init, /* init */
1452    em_shutdown, /* shutdown */
1453    em_file_open, /* file_open */
1454    em_file_close, /* file_close */
1455    em_play, /* play */
1456    em_stop, /* stop */
1457    em_size_get, /* size_get */
1458    em_pos_set, /* pos_set */
1459    em_len_get, /* len_get */
1460    em_fps_num_get, /* fps_num_get */
1461    em_fps_den_get, /* fps_den_get */
1462    em_fps_get, /* fps_get */
1463    em_pos_get, /* pos_get */
1464    em_vis_set, /* vis_set */
1465    em_vis_get, /* vis_get */
1466    em_vis_supported, /* vis_supported */
1467    em_ratio_get, /* ratio_get */
1468    em_video_handled, /* video_handled */
1469    em_audio_handled, /* audio_handled */
1470    em_seekable, /* seekable */
1471    em_frame_done, /* frame_done */
1472    em_format_get, /* format_get */
1473    em_video_data_size_get, /* video_data_size_get */
1474    em_yuv_rows_get, /* yuv_rows_get */
1475    em_bgra_data_get, /* bgra_data_get */
1476    em_event_feed, /* event_feed */
1477    em_event_mouse_button_feed, /* event_mouse_button_feed */
1478    em_event_mouse_move_feed, /* event_mouse_move_feed */
1479    em_video_channel_count, /* video_channel_count */
1480    em_video_channel_set, /* video_channel_set */
1481    em_video_channel_get, /* video_channel_get */
1482    em_video_channel_name_get, /* video_channel_name_get */
1483    em_video_channel_mute_set, /* video_channel_mute_set */
1484    em_video_channel_mute_get, /* video_channel_mute_get */
1485    em_audio_channel_count, /* audio_channel_count */
1486    em_audio_channel_set, /* audio_channel_set */
1487    em_audio_channel_get, /* audio_channel_get */
1488    em_audio_channel_name_get, /* audio_channel_name_get */
1489    em_audio_channel_mute_set, /* audio_channel_mute_set */
1490    em_audio_channel_mute_get, /* audio_channel_mute_get */
1491    em_audio_channel_volume_set, /* audio_channel_volume_set */
1492    em_audio_channel_volume_get, /* audio_channel_volume_get */
1493    em_spu_channel_count, /* spu_channel_count */
1494    em_spu_channel_set, /* spu_channel_set */
1495    em_spu_channel_get, /* spu_channel_get */
1496    em_spu_channel_name_get, /* spu_channel_name_get */
1497    em_spu_channel_mute_set, /* spu_channel_mute_set */
1498    em_spu_channel_mute_get, /* spu_channel_mute_get */
1499    em_chapter_count, /* chapter_count */
1500    em_chapter_set, /* chapter_set */
1501    em_chapter_get, /* chapter_get */
1502    em_chapter_name_get, /* chapter_name_get */
1503    em_speed_set, /* speed_set */
1504    em_speed_get, /* speed_get */
1505    em_eject, /* eject */
1506    em_meta_get, /* meta_get */
1507    NULL /* handle */
1508 };
1509
1510 static Eina_Bool
1511 module_open(Evas_Object *obj, const Emotion_Video_Module **module, void **video, Emotion_Module_Options *opt)
1512 {
1513    if (!module) {
1514         return EINA_FALSE;
1515    }
1516
1517    if (_emotion_generic_log_domain < 0)
1518      {
1519         eina_threads_init();
1520         eina_log_threads_enable();
1521         _emotion_generic_log_domain = eina_log_domain_register
1522           ("emotion-generic", EINA_COLOR_LIGHTCYAN);
1523         if (_emotion_generic_log_domain < 0)
1524           {
1525              EINA_LOG_CRIT("Could not register log domain 'emotion-generic'");
1526              return EINA_FALSE;
1527           }
1528      }
1529
1530
1531    if (!em_module.init(obj, video, opt))        {
1532         return EINA_FALSE;
1533    }
1534
1535    *module = &em_module;
1536
1537    return EINA_TRUE;
1538 }
1539
1540 static void module_close(Emotion_Video_Module *module __UNUSED__, void *video)
1541 {
1542         em_module.shutdown(video);
1543 }
1544
1545
1546 Eina_Bool
1547 generic_module_init(void)
1548 {
1549    if (!pfx)
1550      {
1551         pfx = eina_prefix_new(NULL, emotion_object_add,
1552                               "EMOTION", "emotion", NULL,
1553                               PACKAGE_BIN_DIR,
1554                               PACKAGE_LIB_DIR,
1555                               PACKAGE_DATA_DIR,
1556                               "");
1557         if (!pfx) return EINA_FALSE;
1558      }
1559    return _emotion_module_register("generic", module_open, module_close);
1560 }
1561
1562 static void
1563 generic_module_shutdown(void)
1564 {
1565    if (pfx)
1566      {
1567         eina_prefix_free(pfx);
1568         pfx = NULL;
1569      }
1570    _emotion_module_unregister("generic");
1571 }
1572
1573 #ifndef EMOTION_STATIC_BUILD_GENERIC
1574
1575 EINA_MODULE_INIT(generic_module_init);
1576 EINA_MODULE_SHUTDOWN(generic_module_shutdown);
1577
1578 #endif
1579