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