14 #include "emotion_private.h"
15 #include "emotion_generic.h"
17 static Eina_Prefix *pfx = NULL;
19 struct _default_players {
24 int _emotion_generic_log_domain = -1;
26 static struct _default_players players[] = {
27 #ifdef EMOTION_BUILD_VLC
28 { "vlc", "em_generic_vlc" },
34 _get_player(const char *name)
36 const char *selected_name = NULL;
37 const char *libdir = eina_prefix_lib_get(pfx);
38 static char buf[PATH_MAX];
43 for (i = 0; players[i].name; i++)
45 if (!strcmp(players[i].name, name))
47 selected_name = players[i].cmdline;
53 if ((!selected_name) && (name))
60 if (selected_name[0] == '/') cmd = selected_name;
63 snprintf(buf, sizeof(buf), "%s/emotion/utils/%s",
64 libdir, selected_name);
68 DBG("Try generic player '%s'", cmd);
69 if (access(cmd, R_OK | X_OK) == 0)
71 INF("Using generic player '%s'", cmd);
76 for (i = 0; players[i].name; i++)
78 snprintf(buf, sizeof(buf), "%s/emotion/utils/%s",
79 libdir, players[i].cmdline);
80 DBG("Try generic player '%s'", buf);
81 if (access(buf, R_OK | X_OK) == 0)
83 INF("Using fallback player '%s'", buf);
88 ERR("no generic player found, given name='%s'", name ? name : "");
93 _player_send_cmd(Emotion_Generic_Video *ev, int cmd)
95 if (cmd >= EM_CMD_LAST)
97 ERR("invalid command to player.");
100 ecore_exe_send(ev->player.exe, &cmd, sizeof(cmd));
104 _player_send_int(Emotion_Generic_Video *ev, int number)
106 ecore_exe_send(ev->player.exe, &number, sizeof(number));
110 _player_send_float(Emotion_Generic_Video *ev, float number)
112 ecore_exe_send(ev->player.exe, &number, sizeof(number));
116 _player_send_str(Emotion_Generic_Video *ev, const char *str, Eina_Bool stringshared)
121 len = eina_stringshare_strlen(str) + 1;
123 len = strlen(str) + 1;
124 ecore_exe_send(ev->player.exe, &len, sizeof(len));
125 ecore_exe_send(ev->player.exe, str, len);
129 _create_shm_data(Emotion_Generic_Video *ev, const char *shmname)
134 Emotion_Generic_Video_Shared *vs;
136 shmfd = shm_open(shmname, O_CREAT | O_RDWR | O_TRUNC, 0777);
137 size = 3 * (ev->w * ev->h * DEFAULTPITCH) + sizeof(*vs);
139 npages = (int)(size / getpagesize()) + 1;
140 size = npages * getpagesize();
141 char *buf = malloc(size);
143 if (ftruncate(shmfd, size))
145 ERR("error when allocating shared memory (size = %zd): "
146 "%s", size, strerror(errno));
149 vs = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0);
150 if (vs == MAP_FAILED)
152 ERR("error when mapping shared memory.\n");
156 memcmp(vs, buf, size);
161 vs->pitch = DEFAULTPITCH;
162 vs->frame.emotion = 0;
163 vs->frame.player = 1;
166 sem_init(&vs->lock, 1, 1);
167 ev->frame.frames[0] = (char *)vs + sizeof(*vs);
168 ev->frame.frames[1] = (char *)vs + sizeof(*vs) + vs->height * vs->width * vs->pitch;
169 ev->frame.frames[2] = (char *)vs + sizeof(*vs) + 2 * vs->height * vs->width * vs->pitch;
172 munmap(ev->shared, ev->shared->size);
179 _player_new_frame(Emotion_Generic_Video *ev)
182 _emotion_frame_new(ev->obj);
186 _player_file_set_done(Emotion_Generic_Video *ev)
188 if (!_create_shm_data(ev, ev->shmname))
190 ERR("could not create shared memory.");
193 _player_send_cmd(ev, EM_CMD_FILE_SET_DONE);
197 _file_open(Emotion_Generic_Video *ev)
199 INF("Opening file: %s", ev->filename);
200 ev->w = DEFAULTWIDTH;
201 ev->h = DEFAULTHEIGHT;
202 ev->ratio = (double)DEFAULTWIDTH / DEFAULTHEIGHT;
209 _player_send_cmd(ev, EM_CMD_FILE_SET);
210 _player_send_str(ev, ev->filename, EINA_TRUE);
214 _player_ready(Emotion_Generic_Video *ev)
216 INF("received: player ready.");
218 ev->initializing = EINA_FALSE;
219 ev->ready = EINA_TRUE;
227 #define RCV_CMD_PARAM(src, param) \
228 memcpy(&(param), (src), sizeof((param))); \
229 (src) = (char *)(src) + sizeof((param));
231 #define RCV_CMD_STR(src, buf, len) \
232 RCV_CMD_PARAM((src), (len)); \
233 memcpy((buf), (src), (len)); \
234 (src) = (char *)(src) + len;
237 _player_int_read(Emotion_Generic_Video *ev, void **data)
240 memcpy(&number, *data, sizeof(number));
241 *data = (char *)(*data) + sizeof(number);
247 _player_frame_resize(Emotion_Generic_Video *ev, void *line)
250 RCV_CMD_PARAM(line, w);
251 RCV_CMD_PARAM(line, h);
253 INF("received frame resize: %dx%d", w, h);
256 ev->ratio = (float)w / h;
261 _emotion_frame_resize(ev->obj, ev->w, ev->h, ev->ratio);
265 _player_length_changed(Emotion_Generic_Video *ev, void *line)
268 RCV_CMD_PARAM(line, length);
270 INF("received length changed: %0.3f", length);
273 _emotion_video_pos_update(ev->obj, ev->pos, ev->len);
277 _player_position_changed(Emotion_Generic_Video *ev, void *line)
280 RCV_CMD_PARAM(line, position);
282 INF("received position changed: %0.3f", position);
285 _emotion_video_pos_update(ev->obj, ev->pos, ev->len);
290 float progress = ev->pos / ev->len;
292 snprintf(buf, sizeof(buf), "%0.1f%%", progress * 100);
294 _emotion_progress_set(ev->obj, buf, progress);
298 _player_seekable_changed(Emotion_Generic_Video *ev, void *line)
301 RCV_CMD_PARAM(line, seekable);
303 INF("received seekable changed: %d", seekable);
305 seekable = !!seekable;
307 ev->seekable = seekable;
311 _player_volume(Emotion_Generic_Video *ev, void *line)
314 RCV_CMD_PARAM(line, vol);
316 INF("received volume: %0.3f", vol);
320 if (vol != oldvol && !ev->opening)
321 _emotion_audio_level_change(ev->obj);
325 _player_audio_mute(Emotion_Generic_Video *ev, void *line)
328 RCV_CMD_PARAM(line, mute);
330 INF("received audio mute: %d", mute);
332 ev->audio_mute = !!mute;
336 _audio_channels_free(Emotion_Generic_Video *ev)
339 for (i = 0; i < ev->audio_channels_count; i++)
340 eina_stringshare_del(ev->audio_channels[i].name);
341 free(ev->audio_channels);
342 ev->audio_channels_count = 0;
346 _player_audio_tracks_info(Emotion_Generic_Video *ev, void *line)
348 int track_current, tracks_count;
351 if (ev->audio_channels_count)
352 _audio_channels_free(ev);
354 RCV_CMD_PARAM(line, track_current);
355 RCV_CMD_PARAM(line, tracks_count);
356 INF("video with %d audio tracks (current = %d):", tracks_count, track_current);
357 ev->audio_channels = calloc(
358 tracks_count, sizeof(Emotion_Generic_Audio_Channel));
359 ev->audio_channels_count = tracks_count;
360 ev->audio_channel_current = track_current;
361 for (i = 0; i < tracks_count; i++)
365 RCV_CMD_PARAM(line, tid);
366 RCV_CMD_STR(line, buf, len);
367 ev->audio_channels[i].id = tid;
368 ev->audio_channels[i].name = eina_stringshare_add_length(buf, len);
369 INF("\t%d: %s", tid, buf);
374 _player_file_closed(Emotion_Generic_Video *ev)
376 INF("Closed previous file.");
377 sem_destroy(&ev->shared->lock);
379 ev->closing = EINA_FALSE;
386 _player_open_done(Emotion_Generic_Video *ev)
388 ev->opening = EINA_FALSE;
389 shm_unlink(ev->shmname);
390 _emotion_open_done(ev->obj);
394 _player_send_cmd(ev, EM_CMD_PLAY);
395 _player_send_float(ev, ev->pos);
402 _player_read_cmd(Emotion_Generic_Video *ev, void *line, int size)
405 RCV_CMD_PARAM(line, type);
411 case EM_RESULT_FRAME_NEW:
412 _player_new_frame(ev);
414 case EM_RESULT_FILE_SET:
415 _player_file_set_done(ev);
417 case EM_RESULT_FILE_SET_DONE:
418 _player_open_done(ev);
420 case EM_RESULT_FILE_CLOSE:
421 _player_file_closed(ev);
423 case EM_RESULT_PLAYBACK_STOPPED:
424 _emotion_playback_finished(ev->obj);
426 case EM_RESULT_FRAME_SIZE:
427 _player_frame_resize(ev, line);
429 case EM_RESULT_LENGTH_CHANGED:
430 _player_length_changed(ev, line);
432 case EM_RESULT_POSITION_CHANGED:
433 _player_position_changed(ev, line);
435 case EM_RESULT_SEEKABLE_CHANGED:
436 _player_seekable_changed(ev, line);
438 case EM_RESULT_AUDIO_TRACK_INFO:
439 _player_audio_tracks_info(ev, line);
442 WRN("received wrong command: %d", type);
449 _player_data_cb(void *data, int type __UNUSED__, void *event)
451 Ecore_Exe_Event_Data *ev = event;
452 Emotion_Generic_Video *evideo = data;
457 if (ev->exe != evideo->player.exe)
459 ERR("slave != ev->exe");
460 return ECORE_CALLBACK_DONE;
465 ERR("invalid command: missing bytes.");
466 return ECORE_CALLBACK_DONE;
469 for (i = 0; ev->lines[i].line; i++)
470 _player_read_cmd(evideo, ev->lines[i].line, ev->lines[i].size);
472 return ECORE_CALLBACK_DONE;
476 _player_add_cb(void *data, int type __UNUSED__, void *event)
478 Ecore_Exe_Event_Add *event_add = event;
479 Ecore_Exe *player = event_add->exe;
480 Emotion_Generic_Video *ev = data;
482 if (ev->player.exe != player)
484 ERR("ev->player != player.");
485 return ECORE_CALLBACK_DONE;
488 _player_send_cmd(ev, EM_CMD_INIT);
489 _player_send_str(ev, ev->shmname, EINA_TRUE);
491 return ECORE_CALLBACK_DONE;
495 _player_del_cb(void *data, int type __UNUSED__, void *event)
497 Ecore_Exe_Event_Del *event_del = event;
498 Ecore_Exe *player = event_del->exe;
499 Emotion_Generic_Video *ev = data;
502 ev->player.exe = NULL;
503 ev->ready = EINA_FALSE;
504 _emotion_decode_stop(ev->obj);
506 return ECORE_CALLBACK_DONE;
510 _fork_and_exec(Evas_Object *obj, Emotion_Generic_Video *ev)
515 gettimeofday(&tv, NULL);
516 snprintf(shmname, sizeof(shmname), "/em-generic-shm_%d_%d",
517 (int)tv.tv_sec, (int)tv.tv_usec);
519 ev->shmname = eina_stringshare_add(shmname);
521 ev->player_add = ecore_event_handler_add(
522 ECORE_EXE_EVENT_ADD, _player_add_cb, ev);
523 ev->player_del = ecore_event_handler_add(
524 ECORE_EXE_EVENT_DEL, _player_del_cb, ev);
525 ev->player_data = ecore_event_handler_add(
526 ECORE_EXE_EVENT_DATA, _player_data_cb, ev);
528 ev->player.exe = ecore_exe_pipe_run(
530 ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE |
531 ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_NOT_LEADER,
536 ERR("could not start player.");
540 ev->initializing = EINA_TRUE;
546 em_init(Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt)
548 Emotion_Generic_Video *ev;
551 if (!emotion_video) return 0;
552 player = _get_player(opt ? opt->player : NULL);
553 if (!player) return 0;
555 ev = (Emotion_Generic_Video *)calloc(1, sizeof(*ev));
560 ev->audio_mute = EINA_FALSE;
563 ev->cmdline = eina_stringshare_add(player);
566 return _fork_and_exec(obj, ev);
570 em_shutdown(void *data)
572 Emotion_Generic_Video *ev = data;
578 ecore_exe_terminate(ev->player.exe);
579 ecore_exe_free(ev->player.exe);
580 ev->player.exe = NULL;
584 munmap(ev->shared, ev->shared->size);
586 _audio_channels_free(ev);
588 eina_stringshare_del(ev->cmdline);
589 eina_stringshare_del(ev->shmname);
591 ecore_event_handler_del(ev->player_add);
592 ecore_event_handler_del(ev->player_data);
593 ecore_event_handler_del(ev->player_del);
599 em_file_open(const char *file, Evas_Object *obj, void *data)
601 Emotion_Generic_Video *ev = data;
602 INF("file set: %s", file);
606 ev->opening = EINA_TRUE;
608 eina_stringshare_replace(&ev->filename, file);
617 em_file_close(void *data)
619 Emotion_Generic_Video *ev = data;
622 INF("file close: %s", ev->filename);
627 _player_send_cmd(ev, EM_CMD_FILE_CLOSE);
628 ev->closing = EINA_TRUE;
631 static Emotion_Format
632 em_format_get(void *ef)
634 return EMOTION_FORMAT_BGRA;
638 em_video_data_size_get(void *data, int *w, int *h)
640 Emotion_Generic_Video *ev = data;
648 em_play(void *data, double pos)
650 Emotion_Generic_Video *ev = data;
655 ev->play = EINA_TRUE;
656 INF("play: %0.3f", pos);
658 if (ev->initializing || ev->opening)
663 _player_send_cmd(ev, EM_CMD_PLAY);
664 _player_send_float(ev, ev->pos);
668 ev->player.exe = ecore_exe_pipe_run(
670 ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE |
671 ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_NOT_LEADER,
675 ERR("could not start player.");
681 Emotion_Generic_Video *ev = data;
686 ev->play = EINA_FALSE;
691 _player_send_cmd(ev, EM_CMD_STOP);
692 _emotion_decode_stop(ev->obj);
696 em_size_get(void *data, int *w, int *h)
698 Emotion_Generic_Video *ev = data;
704 em_pos_set(void *data, double pos)
706 Emotion_Generic_Video *ev = data;
707 float position = pos;
708 _player_send_cmd(ev, EM_CMD_POSITION_SET);
709 _player_send_float(ev, position);
710 _emotion_seek_done(ev->obj);
714 em_len_get(void *data)
716 Emotion_Generic_Video *ev = data;
721 em_fps_num_get(void *data)
723 Emotion_Generic_Video *ev = data;
724 return (int)(ev->fps * 1000.0);
728 em_fps_den_get(void *ef)
734 em_fps_get(void *data)
736 Emotion_Generic_Video *ev = data;
741 em_pos_get(void *data)
743 Emotion_Generic_Video *ev = data;
748 em_vis_set(void *ef, Emotion_Vis vis)
753 em_vis_get(void *data)
755 Emotion_Generic_Video *ev = data;
760 em_vis_supported(void *ef, Emotion_Vis vis)
766 em_ratio_get(void *data)
768 Emotion_Generic_Video *ev = data;
772 static int em_video_handled(void *ef)
774 fprintf(stderr, "video handled!\n");
778 static int em_audio_handled(void *ef)
780 fprintf(stderr, "audio handled!\n");
784 static int em_seekable(void *data)
786 Emotion_Generic_Video *ev = data;
790 static void em_frame_done(void *ef)
795 em_yuv_rows_get(void *data, int w, int h, unsigned char **yrows, unsigned char **urows, unsigned char **vrows)
797 Emotion_Generic_Video *ev;
798 volatile Emotion_Generic_Video_Shared *vs;
803 em_bgra_data_get(void *data, unsigned char **bgra_data)
805 Emotion_Generic_Video *ev = data;
807 if (!ev || ev->opening || ev->closing)
811 sem_wait(&ev->shared->lock);
813 // send current frame to emotion
814 if (ev->shared->frame.emotion != ev->shared->frame.last)
816 ev->shared->frame.next = ev->shared->frame.emotion;
817 ev->shared->frame.emotion = ev->shared->frame.last;
819 *bgra_data = ev->frame.frames[ev->shared->frame.emotion];
822 sem_post(&ev->shared->lock);
829 em_event_feed(void *ef, int event)
834 em_event_mouse_button_feed(void *ef, int button, int x, int y)
839 em_event_mouse_move_feed(void *ef, int x, int y)
844 em_video_channel_count(void *ef)
851 em_video_channel_set(void *ef, int channel)
856 em_video_channel_get(void *ef)
862 em_video_channel_name_get(void *ef, int channel)
868 em_video_channel_mute_set(void *ef, int mute)
873 em_video_channel_mute_get(void *data)
875 Emotion_Generic_Video *ev = data;
876 return ev->video_mute;
880 em_audio_channel_count(void *data)
882 Emotion_Generic_Video *ev = data;
883 return ev->audio_channels_count;
887 em_audio_channel_set(void *data, int channel)
889 Emotion_Generic_Video *ev = data;
892 for (i = 0; i < ev->audio_channels_count; i++)
894 if (ev->audio_channels[i].id == channel)
896 _player_send_cmd(ev, EM_CMD_AUDIO_TRACK_SET);
897 _player_send_int(ev, channel);
904 em_audio_channel_get(void *data)
906 Emotion_Generic_Video *ev = data;
907 return ev->audio_channel_current;
911 em_audio_channel_name_get(void *data, int channel)
913 Emotion_Generic_Video *ev = data;
916 for (i = 0; i < ev->audio_channels_count; i++)
918 if (ev->audio_channels[i].id == channel)
919 return ev->audio_channels[i].name;
926 em_audio_channel_mute_set(void *data, int mute)
928 Emotion_Generic_Video *ev = data;
929 _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET);
930 _player_send_int(ev, mute);
931 ev->audio_mute = !!mute;
935 em_audio_channel_mute_get(void *data)
937 Emotion_Generic_Video *ev = data;
938 return ev->audio_mute;
942 em_audio_channel_volume_set(void *data, double vol)
944 Emotion_Generic_Video *ev = data;
947 if (vol > 1.0) vol = 1.0;
948 if (vol < 0.0) vol = 0.0;
951 _player_send_cmd(ev, EM_CMD_VOLUME_SET);
952 _player_send_float(ev, fvol);
958 em_audio_channel_volume_get(void *data)
960 Emotion_Generic_Video *ev = data;
965 em_spu_channel_count(void *ef)
971 em_spu_channel_set(void *ef, int channel)
976 em_spu_channel_get(void *ef)
983 em_spu_channel_name_get(void *ef, int channel)
989 em_spu_channel_mute_set(void *ef, int mute)
995 em_spu_channel_mute_get(void *ef)
1001 em_chapter_count(void *ef)
1008 em_chapter_set(void *ef, int chapter)
1013 em_chapter_get(void *ef)
1020 em_chapter_name_get(void *ef, int chapter)
1026 em_speed_set(void *data, double speed)
1028 Emotion_Generic_Video *ev = data;
1031 _player_send_cmd(ev, EM_CMD_SPEED_SET);
1032 _player_send_float(ev, rate);
1038 em_speed_get(void *data)
1040 Emotion_Generic_Video *ev = data;
1041 return (double)ev->speed;
1051 em_meta_get(void *ef, int meta)
1053 char * meta_data = NULL;
1057 static Emotion_Video_Module em_module =
1060 em_shutdown, /* shutdown */
1061 em_file_open, /* file_open */
1062 em_file_close, /* file_close */
1065 em_size_get, /* size_get */
1066 em_pos_set, /* pos_set */
1067 em_len_get, /* len_get */
1068 em_fps_num_get, /* fps_num_get */
1069 em_fps_den_get, /* fps_den_get */
1070 em_fps_get, /* fps_get */
1071 em_pos_get, /* pos_get */
1072 em_vis_set, /* vis_set */
1073 em_vis_get, /* vis_get */
1074 em_vis_supported, /* vis_supported */
1075 em_ratio_get, /* ratio_get */
1076 em_video_handled, /* video_handled */
1077 em_audio_handled, /* audio_handled */
1078 em_seekable, /* seekable */
1079 em_frame_done, /* frame_done */
1080 em_format_get, /* format_get */
1081 em_video_data_size_get, /* video_data_size_get */
1082 em_yuv_rows_get, /* yuv_rows_get */
1083 em_bgra_data_get, /* bgra_data_get */
1084 em_event_feed, /* event_feed */
1085 em_event_mouse_button_feed, /* event_mouse_button_feed */
1086 em_event_mouse_move_feed, /* event_mouse_move_feed */
1087 em_video_channel_count, /* video_channel_count */
1088 em_video_channel_set, /* video_channel_set */
1089 em_video_channel_get, /* video_channel_get */
1090 em_video_channel_name_get, /* video_channel_name_get */
1091 em_video_channel_mute_set, /* video_channel_mute_set */
1092 em_video_channel_mute_get, /* video_channel_mute_get */
1093 em_audio_channel_count, /* audio_channel_count */
1094 em_audio_channel_set, /* audio_channel_set */
1095 em_audio_channel_get, /* audio_channel_get */
1096 em_audio_channel_name_get, /* audio_channel_name_get */
1097 em_audio_channel_mute_set, /* audio_channel_mute_set */
1098 em_audio_channel_mute_get, /* audio_channel_mute_get */
1099 em_audio_channel_volume_set, /* audio_channel_volume_set */
1100 em_audio_channel_volume_get, /* audio_channel_volume_get */
1101 em_spu_channel_count, /* spu_channel_count */
1102 em_spu_channel_set, /* spu_channel_set */
1103 em_spu_channel_get, /* spu_channel_get */
1104 em_spu_channel_name_get, /* spu_channel_name_get */
1105 em_spu_channel_mute_set, /* spu_channel_mute_set */
1106 em_spu_channel_mute_get, /* spu_channel_mute_get */
1107 em_chapter_count, /* chapter_count */
1108 em_chapter_set, /* chapter_set */
1109 em_chapter_get, /* chapter_get */
1110 em_chapter_name_get, /* chapter_name_get */
1111 em_speed_set, /* speed_set */
1112 em_speed_get, /* speed_get */
1113 em_eject, /* eject */
1114 em_meta_get, /* meta_get */
1119 module_open(Evas_Object *obj, const Emotion_Video_Module **module, void **video, Emotion_Module_Options *opt)
1125 if (_emotion_generic_log_domain < 0)
1127 eina_threads_init();
1128 eina_log_threads_enable();
1129 _emotion_generic_log_domain = eina_log_domain_register
1130 ("emotion-generic", EINA_COLOR_LIGHTCYAN);
1131 if (_emotion_generic_log_domain < 0)
1133 EINA_LOG_CRIT("Could not register log domain 'emotion-generic'");
1139 if (!em_module.init(obj, video, opt)) {
1143 *module = &em_module;
1148 static void module_close(Emotion_Video_Module *module, void *video)
1150 em_module.shutdown(video);
1155 generic_module_init(void)
1159 pfx = eina_prefix_new(NULL, emotion_object_add,
1160 "EMOTION", "emotion", "AUTHORS",
1165 if (!pfx) return EINA_FALSE;
1167 return _emotion_module_register("generic", module_open, module_close);
1171 generic_module_shutdown(void)
1175 eina_prefix_free(pfx);
1178 _emotion_module_unregister("generic");
1181 #ifndef EMOTION_STATIC_BUILD_GENERIC
1183 EINA_MODULE_INIT(generic_module_init);
1184 EINA_MODULE_SHUTDOWN(generic_module_shutdown);