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