17 #include <sys/prctl.h>
22 #include <Emotion_Generic_Plugin.h>
25 EM_THREAD_POSITION_CHANGED,
30 Emotion_Generic_Video_Shared *vs;
31 Emotion_Generic_Video_Frame vf;
32 libvlc_instance_t *libvlc;
34 libvlc_media_player_t *mp;
35 libvlc_event_manager_t *event_mgr;
36 libvlc_event_manager_t *mevent_mgr;
41 int fd_read; // read commands from theads here
42 int fd_write; // write commands from threads here
43 int em_read; // read commands from emotion here
44 int em_write; // write commands to emotion here
51 static pthread_mutex_t _mutex_fd = PTHREAD_MUTEX_INITIALIZER;
54 _em_read_safe(int fd, void *buf, ssize_t size)
66 r = read(fd, p, todo);
76 if (errno == EINTR || errno == EAGAIN)
80 fprintf(stderr, "could not read from fd %d: %s",
91 _em_write_safe(int fd, const void *buf, ssize_t size)
103 r = write(fd, p, todo);
113 if (errno == EINTR || errno == EAGAIN)
117 fprintf(stderr, "could not write to fd %d: %s",
118 fd, strerror(errno));
128 _em_str_read(int fd, char **str)
134 r = _em_read_safe(fd, &size, sizeof(size));
147 r = _em_read_safe(fd, buf, size);
159 _em_cmd_read(struct _App *app)
162 _em_read_safe(app->em_read, &cmd, sizeof(cmd));
168 _send_cmd_start(struct _App *app, int cmd)
170 pthread_mutex_lock(&_mutex_fd);
171 _em_write_safe(app->em_write, &cmd, sizeof(cmd));
175 _send_cmd_finish(struct _App *app __UNUSED__)
177 pthread_mutex_unlock(&_mutex_fd);
181 _send_cmd(struct _App *app, int cmd)
183 _send_cmd_start(app, cmd);
184 _send_cmd_finish(app);
188 _send_cmd_str(struct _App *app, const char *str)
192 len = strlen(str) + 1;
195 _em_write_safe(app->em_write, &len, sizeof(len));
196 _em_write_safe(app->em_write, str, len);
199 #define SEND_CMD_PARAM(app, i) \
200 _em_write_safe((app)->em_write, &(i), sizeof((i)));
203 _send_resize(struct _App *app, int width, int height)
205 _send_cmd_start(app, EM_RESULT_FRAME_SIZE);
206 SEND_CMD_PARAM(app, width);
207 SEND_CMD_PARAM(app, height);
208 _send_cmd_finish(app);
212 _send_length_changed(struct _App *app, const struct libvlc_event_t *ev)
214 float length = ev->u.media_player_length_changed.new_length;
217 fprintf(stderr, "length changed: %0.3f\n", length);
218 _send_cmd_start(app, EM_RESULT_LENGTH_CHANGED);
219 SEND_CMD_PARAM(app, length);
220 _send_cmd_finish(app);
224 _send_time_changed(struct _App *app, const struct libvlc_event_t *ev)
226 float new_time = ev->u.media_player_time_changed.new_time;
228 if (app->vs->frame_drop > 1)
230 _send_cmd_start(app, EM_RESULT_POSITION_CHANGED);
231 SEND_CMD_PARAM(app, new_time);
232 _send_cmd_finish(app);
236 _send_seekable_changed(struct _App *app, const struct libvlc_event_t *ev)
238 int seekable = ev->u.media_player_seekable_changed.new_seekable;
239 _send_cmd_start(app, EM_RESULT_SEEKABLE_CHANGED);
240 SEND_CMD_PARAM(app, seekable);
241 _send_cmd_finish(app);
245 _lock(void *data, void **pixels)
247 struct _App *app = data;
250 *pixels = app->vf.frames[app->vs->frame.player];
254 return NULL; // picture identifier, not needed here
258 _unlock(void *data __UNUSED__, void *id __UNUSED__, void *const *pixels __UNUSED__)
263 _display(void *data, void *id __UNUSED__)
265 struct _App *app = data;
269 sem_wait(&app->vs->lock);
270 app->vs->frame.last = app->vs->frame.player;
271 app->vs->frame.player = app->vs->frame.next;
272 app->vs->frame.next = app->vs->frame.last;
273 if (!app->vs->frame_drop++)
274 _send_cmd(app, EM_RESULT_FRAME_NEW);
275 sem_post(&app->vs->lock);
279 _tmp_lock(void *data, void **pixels)
281 struct _App *app = data;
282 *pixels = app->tmpbuffer;
287 _tmp_unlock(void *data __UNUSED__, void *id __UNUSED__, void *const *pixels __UNUSED__)
292 _tmp_display(void *data __UNUSED__, void *id __UNUSED__)
297 _play(struct _App *app)
304 _em_read_safe(app->em_read, &pos, sizeof(pos));
308 libvlc_media_player_set_pause(app->mp, 0);
312 libvlc_time_t new_time = pos * 1000;
313 libvlc_media_player_play(app->mp);
314 libvlc_media_player_set_time(app->mp, new_time);
320 _stop(struct _App *app)
323 libvlc_media_player_set_pause(app->mp, 1);
327 _send_file_closed(struct _App *app)
330 emotion_generic_shm_free(app->vs);
331 _send_cmd(app, EM_RESULT_FILE_CLOSE);
335 _send_file_set(struct _App *app)
338 _send_cmd(app, EM_RESULT_FILE_SET);
341 _send_file_closed(app);
345 _event_cb(const struct libvlc_event_t *ev, void *data)
347 struct _App *app = data;
351 case libvlc_MediaPlayerTimeChanged:
352 _send_time_changed(app, ev);
354 case libvlc_MediaPlayerPositionChanged:
355 thread_event = EM_THREAD_POSITION_CHANGED;
356 write(app->fd_write, &thread_event, sizeof(thread_event));
358 case libvlc_MediaPlayerLengthChanged:
359 _send_length_changed(app, ev);
361 case libvlc_MediaPlayerSeekableChanged:
362 _send_seekable_changed(app, ev);
364 case libvlc_MediaPlayerPlaying:
365 _send_resize(app, app->w, app->h);
367 case libvlc_MediaPlayerStopped:
370 case libvlc_MediaPlayerEndReached:
371 _send_cmd(app, EM_RESULT_PLAYBACK_STOPPED);
377 _file_set(struct _App *app)
381 libvlc_media_release(app->m);
382 libvlc_media_player_release(app->mp);
386 _em_str_read(app->em_read, &app->filename);
388 app->m = libvlc_media_new_path(app->libvlc, app->filename);
391 fprintf(stderr, "could not open path: \"%s\"\n", app->filename);
394 app->mp = libvlc_media_player_new_from_media(app->m);
398 fprintf(stderr, "could not create new player from media.\n");
403 libvlc_video_set_format(app->mp, "RV32", DEFAULTWIDTH, DEFAULTHEIGHT, DEFAULTWIDTH * 4);
404 libvlc_video_set_callbacks(app->mp, _tmp_lock, _tmp_unlock, _tmp_display, app);
405 app->event_mgr = libvlc_media_player_event_manager(app->mp);
406 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPositionChanged,
408 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerStopped,
411 app->mevent_mgr = libvlc_media_event_manager(app->m);
413 app->tmpbuffer = malloc(sizeof(char) * DEFAULTWIDTH * DEFAULTHEIGHT * 4);
414 libvlc_audio_set_mute(app->mp, 1);
415 libvlc_media_player_play(app->mp);
419 _position_set(struct _App *app)
425 _em_read_safe(app->em_read, &position, sizeof(position));
427 libvlc_time_t new_time = position * 1000;
428 libvlc_media_player_set_time(app->mp, new_time);
432 _speed_set(struct _App *app)
439 _em_read_safe(app->em_read, &rate, sizeof(rate));
441 libvlc_media_player_set_rate(app->mp, rate);
445 _mute_set(struct _App *app)
452 _em_read_safe(app->em_read, &mute, sizeof(mute));
454 libvlc_audio_set_mute(app->mp, mute);
458 _volume_set(struct _App *app)
466 _em_read_safe(app->em_read, &volume, sizeof(volume));
469 libvlc_audio_set_volume(app->mp, vol);
473 _audio_track_set(struct _App *app)
477 _em_read_safe(app->em_read, &track, sizeof(track));
479 libvlc_audio_set_track(app->mp, track);
483 _video_track_set(struct _App *app)
487 _em_read_safe(app->em_read, &track, sizeof(track));
489 libvlc_video_set_track(app->mp, track);
493 _file_set_done(struct _App *app)
499 r = emotion_generic_shm_get(app->shmname, &app->vs, &app->vf);
503 libvlc_media_release(app->m);
504 libvlc_media_player_release(app->mp);
505 app->filename = NULL;
508 _send_cmd_start(app, EM_RESULT_FILE_SET_DONE);
509 SEND_CMD_PARAM(app, r);
510 _send_cmd_finish(app);
512 app->w = app->vs->width;
513 app->h = app->vs->height;
514 libvlc_video_set_format(app->mp, "RV32", app->w, app->h, app->w * 4);
515 libvlc_video_set_callbacks(app->mp, _lock, _unlock, _display, app);
518 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPlaying,
520 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerTimeChanged,
522 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerLengthChanged,
524 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerSeekableChanged,
527 libvlc_audio_set_mute(app->mp, 0);
529 _send_cmd_start(app, EM_RESULT_FILE_SET_DONE);
530 SEND_CMD_PARAM(app, r);
531 _send_cmd_finish(app);
535 _file_close(struct _App *app)
539 goto release_resources;
541 if (libvlc_media_player_get_state(app->mp) != libvlc_Playing)
543 _send_file_closed(app);
550 libvlc_media_player_stop(app->mp);
555 libvlc_media_release(app->m);
556 libvlc_media_player_release(app->mp);
557 free(app->tmpbuffer);
562 _process_emotion_commands(struct _App *app)
564 int cmd = _em_cmd_read(app);
566 case EM_CMD_FILE_SET:
569 case EM_CMD_FILE_SET_DONE:
572 case EM_CMD_FILE_CLOSE:
581 case EM_CMD_POSITION_SET:
584 case EM_CMD_SPEED_SET:
587 case EM_CMD_AUDIO_MUTE_SET:
590 case EM_CMD_VOLUME_SET:
593 case EM_CMD_AUDIO_TRACK_SET:
594 _audio_track_set(app);
596 case EM_CMD_VIDEO_TRACK_SET:
597 _video_track_set(app);
603 _send_track_info(struct _App *app, int cmd, int current, int count, libvlc_track_description_t *desc)
605 _send_cmd_start(app, cmd);
606 SEND_CMD_PARAM(app, current);
607 SEND_CMD_PARAM(app, count);
610 int tid = desc->i_id;
611 const char *name = desc->psz_name;
612 SEND_CMD_PARAM(app, tid);
613 _send_cmd_str(app, name);
616 _send_cmd_finish(app);
620 _send_all_track_info(struct _App *app)
622 int track_count, current;
623 libvlc_track_description_t *desc;
625 current = libvlc_audio_get_track(app->mp);
626 track_count = libvlc_audio_get_track_count(app->mp);
627 desc = libvlc_audio_get_track_description(app->mp);
629 _send_track_info(app, EM_RESULT_AUDIO_TRACK_INFO,
630 current, track_count, desc);
632 current = libvlc_video_get_track(app->mp);
633 track_count = libvlc_video_get_track_count(app->mp);
634 desc = libvlc_video_get_track_description(app->mp);
636 _send_track_info(app, EM_RESULT_VIDEO_TRACK_INFO,
637 current, track_count, desc);
639 current = libvlc_video_get_spu(app->mp);
640 track_count = libvlc_video_get_spu_count(app->mp);
641 desc = libvlc_video_get_spu_description(app->mp);
643 _send_track_info(app, EM_RESULT_SPU_TRACK_INFO,
644 current, track_count, desc);
648 _send_all_meta_info(struct _App *app)
652 _send_cmd_start(app, EM_RESULT_META_INFO);
655 * Will send in this order: title, artist, album, year,
656 * genre, comments, disc id and track count.
658 meta = libvlc_media_get_meta(app->m, libvlc_meta_Title);
659 _send_cmd_str(app, meta);
660 meta = libvlc_media_get_meta(app->m, libvlc_meta_Artist);
661 _send_cmd_str(app, meta);
662 meta = libvlc_media_get_meta(app->m, libvlc_meta_Album);
663 _send_cmd_str(app, meta);
664 meta = libvlc_media_get_meta(app->m, libvlc_meta_Date);
665 _send_cmd_str(app, meta);
666 meta = libvlc_media_get_meta(app->m, libvlc_meta_Genre);
667 _send_cmd_str(app, meta);
668 meta = NULL; // sending empty comments
669 _send_cmd_str(app, meta);
670 meta = NULL; // sending empty disc id
671 _send_cmd_str(app, meta);
672 meta = libvlc_media_get_meta(app->m, libvlc_meta_TrackNumber);
673 _send_cmd_str(app, meta);
674 _send_cmd_finish(app);
678 _position_changed(struct _App *app)
683 /* sending size info only once */
686 r = libvlc_video_get_size(app->mp, 0, &w, &h);
689 _send_resize(app, w, h);
691 /* sending audio track info */
692 _send_all_track_info(app);
694 /* sending meta info */
695 _send_all_meta_info(app);
697 libvlc_media_player_stop(app->mp);
701 _process_thread_events(struct _App *app)
706 size = read(app->fd_read, &event, sizeof(event));
707 if (size != sizeof(event))
709 fprintf(stderr, "player: problem when reading thread event. size = %zd\n", size);
714 case EM_THREAD_POSITION_CHANGED:
715 _position_changed(app);
721 main(int argc, const char *argv[])
724 struct pollfd fds[3];
725 int tpipe[2]; // pipe for comunicating events from threads
726 char cwidth[64], cheight[64], cpitch[64], chroma[64];
728 const char *vlc_argv[] =
745 fprintf(stderr, "player: missing paramters.\n");
746 fprintf(stderr, "syntax:\n\t%s <fd read> <fd write>\n", argv[0]);
750 app.em_read = atoi(argv[1]);
751 app.em_write = atoi(argv[2]);
753 fprintf(stderr, "reading commands from fd: %d, writing on fd: %d\n", app.em_read, app.em_write);
755 int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);
756 snprintf(cwidth, sizeof(cwidth), "%d", DEFAULTWIDTH);
757 snprintf(cheight, sizeof(cheight), "%d", DEFAULTHEIGHT);
758 snprintf(cpitch, sizeof(cpitch), "%d", DEFAULTWIDTH * 4);
759 snprintf(chroma, sizeof(chroma), "RV32");
762 * Naughty xattr in emotion uses ecore_thread to run its thing, this
763 * may leave emotion's reference count high and it won't kill us...
764 * letting us play the video in the background. not good.
766 * prctl(PR_SET_PDEATHSIG) is a linux only thing. Need to find ways
767 * to do it on other platforms. Until then leave it breaking on
768 * such platforms so people port it instead of ignoring.
770 prctl(PR_SET_PDEATHSIG, SIGHUP);
772 app.libvlc = libvlc_new(vlc_argc, vlc_argv);
782 if (_em_cmd_read(&app) != EM_CMD_INIT)
784 fprintf(stderr, "player: wrong init command!\n");
789 _em_read_safe(app.em_read, &size, sizeof(size));
790 _em_read_safe(app.em_read, buf, size);
791 app.shmname = strdup(buf);
793 _send_cmd(&app, EM_RESULT_INIT);
796 app.fd_read = tpipe[0];
797 app.fd_write = tpipe[1];
798 fds[0].fd = app.em_read;
799 fds[0].events = POLLIN;
800 fds[1].fd = app.fd_read;
801 fds[1].events = POLLIN;
802 fds[2].fd = STDERR_FILENO;
809 r = poll(fds, 3, -1);
815 "emotion_generic_vlc: an error ocurred on poll(): %s\n",
820 if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL))
822 fputs("emotion_generic_vlc: error communicating with stdin\n",
826 if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL))
828 fputs("emotion_generic_vlc: error communicating with thread\n",
833 if (fds[0].revents & POLLIN)
834 _process_emotion_commands(&app);
835 if (fds[1].revents & POLLIN)
836 _process_thread_events(&app);
837 if (fds[2].revents & (POLLERR | POLLHUP | POLLNVAL))
841 libvlc_release(app.libvlc);
846 #undef SEND_CMD_PARAM