17 #include <sys/prctl.h>
21 #include <Emotion_Generic_Plugin.h>
24 EM_THREAD_POSITION_CHANGED,
29 Emotion_Generic_Video_Shared *vs;
30 Emotion_Generic_Video_Frame vf;
31 libvlc_instance_t *libvlc;
33 libvlc_media_player_t *mp;
34 libvlc_event_manager_t *event_mgr;
35 libvlc_event_manager_t *mevent_mgr;
39 int fd_read; // read commands from theads here
40 int fd_write; // write commands from threads here
41 int em_read; // read commands from emotion here
42 int em_write; // write commands to emotion here
49 static pthread_mutex_t _mutex_fd = PTHREAD_MUTEX_INITIALIZER;
52 _em_read_safe(int fd, void *buf, ssize_t size)
64 r = read(fd, p, todo);
74 if (errno == EINTR || errno == EAGAIN)
78 fprintf(stderr, "could not read from fd %d: %s",
89 _em_write_safe(int fd, const void *buf, ssize_t size)
101 r = write(fd, p, todo);
111 if (errno == EINTR || errno == EAGAIN)
115 fprintf(stderr, "could not write to fd %d: %s",
116 fd, strerror(errno));
126 _em_str_read(int fd, char **str)
132 r = _em_read_safe(fd, &size, sizeof(size));
145 r = _em_read_safe(fd, buf, size);
157 _em_cmd_read(struct _App *app)
160 _em_read_safe(app->em_read, &cmd, sizeof(cmd));
166 _send_cmd_start(struct _App *app, int cmd)
168 pthread_mutex_lock(&_mutex_fd);
169 _em_write_safe(app->em_write, &cmd, sizeof(cmd));
173 _send_cmd_finish(struct _App *app)
175 pthread_mutex_unlock(&_mutex_fd);
179 _send_cmd(struct _App *app, int cmd)
181 _send_cmd_start(app, cmd);
182 _send_cmd_finish(app);
186 _send_cmd_str(struct _App *app, const char *str)
189 len = strlen(str) + 1;
190 _em_write_safe(app->em_write, &len, sizeof(len));
191 _em_write_safe(app->em_write, str, len);
194 #define SEND_CMD_PARAM(app, i) \
195 _em_write_safe((app)->em_write, &(i), sizeof((i)));
198 _send_resize(struct _App *app, int width, int height)
200 _send_cmd_start(app, EM_RESULT_FRAME_SIZE);
201 SEND_CMD_PARAM(app, width);
202 SEND_CMD_PARAM(app, height);
203 _send_cmd_finish(app);
207 _send_length_changed(struct _App *app, const struct libvlc_event_t *ev)
209 float length = ev->u.media_player_length_changed.new_length;
212 fprintf(stderr, "length changed: %0.3f\n", length);
213 _send_cmd_start(app, EM_RESULT_LENGTH_CHANGED);
214 SEND_CMD_PARAM(app, length);
215 _send_cmd_finish(app);
219 _send_time_changed(struct _App *app, const struct libvlc_event_t *ev)
221 float new_time = ev->u.media_player_time_changed.new_time;
223 _send_cmd_start(app, EM_RESULT_POSITION_CHANGED);
224 SEND_CMD_PARAM(app, new_time);
225 _send_cmd_finish(app);
229 _send_seekable_changed(struct _App *app, const struct libvlc_event_t *ev)
231 int seekable = ev->u.media_player_seekable_changed.new_seekable;
232 _send_cmd_start(app, EM_RESULT_SEEKABLE_CHANGED);
233 SEND_CMD_PARAM(app, seekable);
234 _send_cmd_finish(app);
238 _lock(void *data, void **pixels)
240 struct _App *app = data;
243 *pixels = app->vf.frames[app->vs->frame.player];
247 return NULL; // picture identifier, not needed here
251 _unlock(void *data, void *id, void *const *pixels)
253 struct _App *app = data;
258 sem_wait(&app->vs->lock);
259 app->vs->frame.last = app->vs->frame.player;
260 app->vs->frame.player = app->vs->frame.next;
261 app->vs->frame.next = app->vs->frame.last;
263 sem_post(&app->vs->lock);
267 _display(void *data, void *id)
269 struct _App *app = data;
273 _send_cmd(app, EM_RESULT_FRAME_NEW);
277 _tmp_lock(void *data, void **pixels)
284 _tmp_unlock(void *data, void *id, void *const *pixels)
289 _tmp_display(void *data, void *id)
294 _play(struct _App *app)
301 _em_read_safe(app->em_read, &pos, sizeof(pos));
305 libvlc_media_player_set_pause(app->mp, 0);
309 libvlc_time_t new_time = pos * 1000;
310 libvlc_media_player_play(app->mp);
311 libvlc_media_player_set_time(app->mp, new_time);
317 _stop(struct _App *app)
320 libvlc_media_player_set_pause(app->mp, 1);
324 _send_file_closed(struct _App *app)
327 emotion_generic_shm_free(app->vs);
328 _send_cmd(app, EM_RESULT_FILE_CLOSE);
332 _send_file_set(struct _App *app)
335 _send_cmd(app, EM_RESULT_FILE_SET);
338 _send_file_closed(app);
342 _event_cb(const struct libvlc_event_t *ev, void *data)
344 struct _App *app = data;
348 case libvlc_MediaPlayerTimeChanged:
349 _send_time_changed(app, ev);
351 case libvlc_MediaPlayerPositionChanged:
352 thread_event = EM_THREAD_POSITION_CHANGED;
353 write(app->fd_write, &thread_event, sizeof(thread_event));
355 case libvlc_MediaPlayerLengthChanged:
356 _send_length_changed(app, ev);
358 case libvlc_MediaPlayerSeekableChanged:
359 _send_seekable_changed(app, ev);
361 case libvlc_MediaPlayerPlaying:
362 _send_resize(app, app->w, app->h);
364 case libvlc_MediaPlayerStopped:
367 case libvlc_MediaPlayerEndReached:
368 _send_cmd(app, EM_RESULT_PLAYBACK_STOPPED);
374 _file_set(struct _App *app)
378 libvlc_media_release(app->m);
379 libvlc_media_player_release(app->mp);
383 _em_str_read(app->em_read, &app->filename);
385 app->m = libvlc_media_new_path(app->libvlc, app->filename);
388 fprintf(stderr, "could not open path: \"%s\"\n", app->filename);
391 app->mp = libvlc_media_player_new_from_media(app->m);
395 fprintf(stderr, "could not create new player from media.\n");
400 libvlc_video_set_format(app->mp, "RV32", DEFAULTWIDTH, DEFAULTHEIGHT, DEFAULTWIDTH * 4);
401 libvlc_video_set_callbacks(app->mp, _tmp_lock, _tmp_unlock, _tmp_display, NULL);
402 app->event_mgr = libvlc_media_player_event_manager(app->mp);
403 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPositionChanged,
405 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerStopped,
408 app->mevent_mgr = libvlc_media_event_manager(app->m);
410 libvlc_audio_set_mute(app->mp, 1);
411 libvlc_media_player_play(app->mp);
415 _position_set(struct _App *app)
421 _em_read_safe(app->em_read, &position, sizeof(position));
423 libvlc_time_t new_time = position * 1000;
424 libvlc_media_player_set_time(app->mp, new_time);
428 _speed_set(struct _App *app)
435 _em_read_safe(app->em_read, &rate, sizeof(rate));
437 libvlc_media_player_set_rate(app->mp, rate);
441 _mute_set(struct _App *app)
448 _em_read_safe(app->em_read, &mute, sizeof(mute));
450 libvlc_audio_set_mute(app->mp, mute);
454 _volume_set(struct _App *app)
462 _em_read_safe(app->em_read, &volume, sizeof(volume));
465 libvlc_audio_set_volume(app->mp, vol);
469 _audio_track_set(struct _App *app)
473 _em_read_safe(app->em_read, &track, sizeof(track));
475 libvlc_audio_set_track(app->mp, track);
479 _file_set_done(struct _App *app)
485 r = emotion_generic_shm_get(app->shmname, &app->vs, &app->vf);
489 libvlc_media_release(app->m);
490 libvlc_media_player_release(app->mp);
491 app->filename = NULL;
494 _send_cmd_start(app, EM_RESULT_FILE_SET_DONE);
495 SEND_CMD_PARAM(app, r);
496 _send_cmd_finish(app);
498 app->w = app->vs->width;
499 app->h = app->vs->height;
500 libvlc_video_set_format(app->mp, "RV32", app->w, app->h, app->w * 4);
501 libvlc_video_set_callbacks(app->mp, _lock, _unlock, _display, app);
504 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPlaying,
506 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerTimeChanged,
508 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerLengthChanged,
510 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerSeekableChanged,
513 libvlc_audio_set_mute(app->mp, 0);
515 _send_cmd_start(app, EM_RESULT_FILE_SET_DONE);
516 SEND_CMD_PARAM(app, r);
517 _send_cmd_finish(app);
521 _file_close(struct _App *app)
525 goto release_resources;
527 if (libvlc_media_player_get_state(app->mp) != libvlc_Playing)
529 _send_file_closed(app);
536 libvlc_media_player_stop(app->mp);
541 libvlc_media_release(app->m);
542 libvlc_media_player_release(app->mp);
547 _process_emotion_commands(struct _App *app)
549 int cmd = _em_cmd_read(app);
551 case EM_CMD_FILE_SET:
554 case EM_CMD_FILE_SET_DONE:
557 case EM_CMD_FILE_CLOSE:
566 case EM_CMD_POSITION_SET:
569 case EM_CMD_SPEED_SET:
572 case EM_CMD_AUDIO_MUTE_SET:
575 case EM_CMD_VOLUME_SET:
578 case EM_CMD_AUDIO_TRACK_SET:
579 _audio_track_set(app);
585 _send_track_info(struct _App *app)
587 int track_count, current;
588 libvlc_track_description_t *desc;
590 current = libvlc_audio_get_track(app->mp);
591 track_count = libvlc_audio_get_track_count(app->mp);
592 desc = libvlc_audio_get_track_description(app->mp);
594 _send_cmd_start(app, EM_RESULT_AUDIO_TRACK_INFO);
595 SEND_CMD_PARAM(app, current);
596 SEND_CMD_PARAM(app, track_count);
599 int tid = desc->i_id;
600 const char *name = desc->psz_name;
601 SEND_CMD_PARAM(app, tid);
602 _send_cmd_str(app, name);
605 _send_cmd_finish(app);
609 _position_changed(struct _App *app)
614 /* sending size info only once */
616 r = libvlc_video_get_size(app->mp, 0, &w, &h);
619 _send_resize(app, w, h);
621 /* sending audio track info */
622 // _send_track_info(app);
624 libvlc_media_player_stop(app->mp);
628 _process_thread_events(struct _App *app)
633 size = read(app->fd_read, &event, sizeof(event));
634 if (size != sizeof(event))
636 fprintf(stderr, "player: problem when reading thread event. size = %zd\n", size);
641 case EM_THREAD_POSITION_CHANGED:
642 _position_changed(app);
648 main(int argc, const char *argv[])
651 Emotion_Generic_Video_Shared *vs;
652 struct pollfd fds[3];
653 int tpipe[2]; // pipe for comunicating events from threads
655 char cwidth[64], cheight[64], cpitch[64], chroma[64];
657 const char *vlc_argv[] =
674 fprintf(stderr, "player: missing paramters.\n");
675 fprintf(stderr, "syntax:\n\t%s <fd read> <fd write>\n", argv[0]);
679 app.em_read = atoi(argv[1]);
680 app.em_write = atoi(argv[2]);
682 fprintf(stderr, "reading commands from fd: %d, writing on fd: %d\n", app.em_read, app.em_write);
684 int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);
685 snprintf(cwidth, sizeof(cwidth), "%d", DEFAULTWIDTH);
686 snprintf(cheight, sizeof(cheight), "%d", DEFAULTHEIGHT);
687 snprintf(cpitch, sizeof(cpitch), "%d", DEFAULTWIDTH * 4);
688 snprintf(chroma, sizeof(chroma), "RV32");
691 * Naughty xattr in emotion uses ecore_thread to run its thing, this
692 * may leave emotion's reference count high and it won't kill us...
693 * letting us play the video in the background. not good.
695 * prctl(PR_SET_PDEATHSIG) is a linux only thing. Need to find ways
696 * to do it on other platforms. Until then leave it breaking on
697 * such platforms so people port it instead of ignoring.
699 prctl(PR_SET_PDEATHSIG, SIGHUP);
701 app.libvlc = libvlc_new(vlc_argc, vlc_argv);
711 if (_em_cmd_read(&app) != EM_CMD_INIT)
713 fprintf(stderr, "player: wrong init command!\n");
718 _em_read_safe(app.em_read, &size, sizeof(size));
719 _em_read_safe(app.em_read, buf, size);
720 app.shmname = strdup(buf);
722 _send_cmd(&app, EM_RESULT_INIT);
725 app.fd_read = tpipe[0];
726 app.fd_write = tpipe[1];
727 fds[0].fd = app.em_read;
728 fds[0].events = POLLIN;
729 fds[1].fd = app.fd_read;
730 fds[1].events = POLLIN;
731 fds[2].fd = STDERR_FILENO;
738 r = poll(fds, 3, -1);
744 "emotion_generic_vlc: an error ocurred on poll(): %s\n",
749 if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL))
751 fputs("emotion_generic_vlc: error communicating with stdin\n",
755 if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL))
757 fputs("emotion_generic_vlc: error communicating with thread\n",
762 if (fds[0].revents & POLLIN)
763 _process_emotion_commands(&app);
764 if (fds[1].revents & POLLIN)
765 _process_thread_events(&app);
766 if (fds[2].revents & (POLLERR | POLLHUP | POLLNVAL))
770 libvlc_release(app.libvlc);
775 #undef SEND_CMD_PARAM