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