17 #include <sys/prctl.h>
22 #include <Emotion_Generic_Plugin.h>
25 EM_THREAD_POSITION_CHANGED,
26 EM_THREAD_PLAYBACK_STARTED,
27 EM_THREAD_PLAYBACK_STOPPED,
32 Emotion_Generic_Video_Shared *vs;
33 Emotion_Generic_Video_Frame vf;
34 libvlc_instance_t *libvlc;
36 libvlc_media_player_t *mp;
37 libvlc_event_manager_t *event_mgr;
38 libvlc_event_manager_t *mevent_mgr;
43 int fd_read; // read commands from theads here
44 int fd_write; // write commands from threads here
45 int em_read; // read commands from emotion here
46 int em_write; // write commands to emotion here
53 static pthread_mutex_t _mutex_fd = PTHREAD_MUTEX_INITIALIZER;
56 _em_read_safe(int fd, void *buf, ssize_t size)
68 r = read(fd, p, todo);
78 if (errno == EINTR || errno == EAGAIN)
82 fprintf(stderr, "could not read from fd %d: %s",
93 _em_write_safe(int fd, const void *buf, ssize_t size)
105 r = write(fd, p, todo);
115 if (errno == EINTR || errno == EAGAIN)
119 fprintf(stderr, "could not write to fd %d: %s",
120 fd, strerror(errno));
130 _em_str_read(int fd, char **str)
136 r = _em_read_safe(fd, &size, sizeof(size));
149 r = _em_read_safe(fd, buf, size);
161 _em_cmd_read(struct _App *app)
164 _em_read_safe(app->em_read, &cmd, sizeof(cmd));
170 _send_cmd_start(struct _App *app, int cmd)
172 pthread_mutex_lock(&_mutex_fd);
173 _em_write_safe(app->em_write, &cmd, sizeof(cmd));
177 _send_cmd_finish(struct _App *app __UNUSED__)
179 pthread_mutex_unlock(&_mutex_fd);
183 _send_cmd(struct _App *app, int cmd)
185 _send_cmd_start(app, cmd);
186 _send_cmd_finish(app);
190 _send_cmd_str(struct _App *app, const char *str)
194 len = strlen(str) + 1;
197 _em_write_safe(app->em_write, &len, sizeof(len));
198 _em_write_safe(app->em_write, str, len);
201 #define SEND_CMD_PARAM(app, i) \
202 _em_write_safe((app)->em_write, &(i), sizeof((i)));
205 _send_resize(struct _App *app, int width, int height)
207 _send_cmd_start(app, EM_RESULT_FRAME_SIZE);
208 SEND_CMD_PARAM(app, width);
209 SEND_CMD_PARAM(app, height);
210 _send_cmd_finish(app);
214 _send_length_changed(struct _App *app, const struct libvlc_event_t *ev)
216 float length = ev->u.media_player_length_changed.new_length;
219 _send_cmd_start(app, EM_RESULT_LENGTH_CHANGED);
220 SEND_CMD_PARAM(app, length);
221 _send_cmd_finish(app);
225 _send_time_changed(struct _App *app, const struct libvlc_event_t *ev)
227 float new_time = ev->u.media_player_time_changed.new_time;
229 if (app->vs->frame_drop > 1)
231 _send_cmd_start(app, EM_RESULT_POSITION_CHANGED);
232 SEND_CMD_PARAM(app, new_time);
233 _send_cmd_finish(app);
237 _send_seekable_changed(struct _App *app, const struct libvlc_event_t *ev)
239 int seekable = ev->u.media_player_seekable_changed.new_seekable;
240 _send_cmd_start(app, EM_RESULT_SEEKABLE_CHANGED);
241 SEND_CMD_PARAM(app, seekable);
242 _send_cmd_finish(app);
246 _lock(void *data, void **pixels)
248 struct _App *app = data;
251 *pixels = app->vf.frames[app->vs->frame.player];
255 return NULL; // picture identifier, not needed here
259 _unlock(void *data __UNUSED__, void *id __UNUSED__, void *const *pixels __UNUSED__)
264 _display(void *data, void *id __UNUSED__)
266 struct _App *app = data;
270 sem_wait(&app->vs->lock);
271 app->vs->frame.last = app->vs->frame.player;
272 app->vs->frame.player = app->vs->frame.next;
273 app->vs->frame.next = app->vs->frame.last;
274 if (!app->vs->frame_drop++)
275 _send_cmd(app, EM_RESULT_FRAME_NEW);
276 sem_post(&app->vs->lock);
280 _tmp_lock(void *data, void **pixels)
282 struct _App *app = data;
283 *pixels = app->tmpbuffer;
288 _tmp_unlock(void *data __UNUSED__, void *id __UNUSED__, void *const *pixels __UNUSED__)
293 _tmp_display(void *data __UNUSED__, void *id __UNUSED__)
298 _play(struct _App *app)
305 _em_read_safe(app->em_read, &pos, sizeof(pos));
309 libvlc_media_player_set_pause(app->mp, 0);
313 libvlc_time_t new_time = pos * 1000;
314 libvlc_media_player_set_time(app->mp, new_time);
315 libvlc_media_player_play(app->mp);
321 _stop(struct _App *app)
324 libvlc_media_player_set_pause(app->mp, 1);
328 _send_file_closed(struct _App *app)
331 emotion_generic_shm_free(app->vs);
332 _send_cmd(app, EM_RESULT_FILE_CLOSE);
336 _send_file_set(struct _App *app)
339 _send_cmd(app, EM_RESULT_FILE_SET);
342 _send_file_closed(app);
346 _event_cb(const struct libvlc_event_t *ev, void *data)
348 struct _App *app = data;
352 case libvlc_MediaPlayerTimeChanged:
353 _send_time_changed(app, ev);
355 case libvlc_MediaPlayerPositionChanged:
356 thread_event = EM_THREAD_POSITION_CHANGED;
357 write(app->fd_write, &thread_event, sizeof(thread_event));
359 case libvlc_MediaPlayerLengthChanged:
360 _send_length_changed(app, ev);
362 case libvlc_MediaPlayerSeekableChanged:
363 _send_seekable_changed(app, ev);
365 case libvlc_MediaPlayerPlaying:
366 _send_resize(app, app->w, app->h);
367 thread_event = EM_THREAD_PLAYBACK_STARTED;
368 write(app->fd_write, &thread_event, sizeof(thread_event));
370 case libvlc_MediaPlayerStopped:
373 case libvlc_MediaPlayerEndReached:
374 thread_event = EM_THREAD_PLAYBACK_STOPPED;
375 write(app->fd_write, &thread_event, sizeof(thread_event));
381 _file_set(struct _App *app)
385 libvlc_media_release(app->m);
386 libvlc_media_player_release(app->mp);
390 _em_str_read(app->em_read, &app->filename);
392 app->m = libvlc_media_new_path(app->libvlc, app->filename);
395 fprintf(stderr, "could not open path: \"%s\"\n", app->filename);
399 app->mp = libvlc_media_player_new_from_media(app->m);
402 fprintf(stderr, "could not create new player from media.\n");
407 libvlc_video_set_format(app->mp, "RV32", DEFAULTWIDTH, DEFAULTHEIGHT, DEFAULTWIDTH * 4);
408 libvlc_video_set_callbacks(app->mp, _tmp_lock, _tmp_unlock, _tmp_display, app);
409 app->event_mgr = libvlc_media_player_event_manager(app->mp);
410 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPositionChanged,
412 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerStopped,
415 app->mevent_mgr = libvlc_media_event_manager(app->m);
417 app->tmpbuffer = malloc(sizeof(char) * DEFAULTWIDTH * DEFAULTHEIGHT * 4);
418 libvlc_audio_set_mute(app->mp, 1);
419 libvlc_media_player_play(app->mp);
423 _position_set(struct _App *app)
429 _em_read_safe(app->em_read, &position, sizeof(position));
431 libvlc_time_t new_time = position * 1000;
432 libvlc_media_player_set_time(app->mp, new_time);
436 _speed_set(struct _App *app)
443 _em_read_safe(app->em_read, &rate, sizeof(rate));
445 libvlc_media_player_set_rate(app->mp, rate);
449 _mute_set(struct _App *app)
456 _em_read_safe(app->em_read, &mute, sizeof(mute));
458 libvlc_audio_set_mute(app->mp, mute);
462 _volume_set(struct _App *app)
470 _em_read_safe(app->em_read, &volume, sizeof(volume));
473 libvlc_audio_set_volume(app->mp, vol);
477 _spu_track_set(struct _App *app)
481 _em_read_safe(app->em_read, &track, sizeof(track));
483 libvlc_video_set_spu(app->mp, track);
487 _audio_track_set(struct _App *app)
491 _em_read_safe(app->em_read, &track, sizeof(track));
493 libvlc_audio_set_track(app->mp, track);
497 _video_track_set(struct _App *app)
501 _em_read_safe(app->em_read, &track, sizeof(track));
503 libvlc_video_set_track(app->mp, track);
507 _file_set_done(struct _App *app)
513 r = emotion_generic_shm_get(app->shmname, &app->vs, &app->vf);
517 libvlc_media_release(app->m);
518 libvlc_media_player_release(app->mp);
519 app->filename = NULL;
522 _send_cmd_start(app, EM_RESULT_FILE_SET_DONE);
523 SEND_CMD_PARAM(app, r);
524 _send_cmd_finish(app);
526 app->w = app->vs->width;
527 app->h = app->vs->height;
528 libvlc_video_set_format(app->mp, "RV32", app->w, app->h, app->w * 4);
529 libvlc_video_set_callbacks(app->mp, _lock, _unlock, _display, app);
532 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPlaying,
534 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerTimeChanged,
536 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerLengthChanged,
538 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerSeekableChanged,
540 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerEndReached,
543 libvlc_audio_set_mute(app->mp, 0);
545 _send_cmd_start(app, EM_RESULT_FILE_SET_DONE);
546 SEND_CMD_PARAM(app, r);
547 _send_cmd_finish(app);
551 _file_close(struct _App *app)
555 goto release_resources;
557 if (libvlc_media_player_get_state(app->mp) != libvlc_Playing)
559 _send_file_closed(app);
566 libvlc_media_player_stop(app->mp);
571 libvlc_media_release(app->m);
572 libvlc_media_player_release(app->mp);
573 free(app->tmpbuffer);
578 _process_emotion_commands(struct _App *app)
580 int cmd = _em_cmd_read(app);
582 case EM_CMD_FILE_SET:
585 case EM_CMD_FILE_SET_DONE:
588 case EM_CMD_FILE_CLOSE:
597 case EM_CMD_POSITION_SET:
600 case EM_CMD_SPEED_SET:
603 case EM_CMD_AUDIO_MUTE_SET:
606 case EM_CMD_VOLUME_SET:
609 case EM_CMD_SPU_TRACK_SET:
612 case EM_CMD_AUDIO_TRACK_SET:
613 _audio_track_set(app);
615 case EM_CMD_VIDEO_TRACK_SET:
616 _video_track_set(app);
622 _send_track_info(struct _App *app, int cmd, int current, int count, libvlc_track_description_t *desc)
624 _send_cmd_start(app, cmd);
625 SEND_CMD_PARAM(app, current);
626 SEND_CMD_PARAM(app, count);
629 int tid = desc->i_id;
630 const char *name = desc->psz_name;
631 SEND_CMD_PARAM(app, tid);
632 _send_cmd_str(app, name);
635 _send_cmd_finish(app);
639 _send_all_track_info(struct _App *app)
641 int track_count, current;
642 libvlc_track_description_t *desc;
644 current = libvlc_audio_get_track(app->mp);
645 track_count = libvlc_audio_get_track_count(app->mp);
646 desc = libvlc_audio_get_track_description(app->mp);
648 _send_track_info(app, EM_RESULT_AUDIO_TRACK_INFO,
649 current, track_count, desc);
651 current = libvlc_video_get_track(app->mp);
652 track_count = libvlc_video_get_track_count(app->mp);
653 desc = libvlc_video_get_track_description(app->mp);
655 _send_track_info(app, EM_RESULT_VIDEO_TRACK_INFO,
656 current, track_count, desc);
658 current = libvlc_video_get_spu(app->mp);
659 track_count = libvlc_video_get_spu_count(app->mp);
660 desc = libvlc_video_get_spu_description(app->mp);
662 _send_track_info(app, EM_RESULT_SPU_TRACK_INFO,
663 current, track_count, desc);
667 _send_all_meta_info(struct _App *app)
671 _send_cmd_start(app, EM_RESULT_META_INFO);
674 * Will send in this order: title, artist, album, year,
675 * genre, comments, disc id and track count.
677 meta = libvlc_media_get_meta(app->m, libvlc_meta_Title);
678 _send_cmd_str(app, meta);
679 meta = libvlc_media_get_meta(app->m, libvlc_meta_Artist);
680 _send_cmd_str(app, meta);
681 meta = libvlc_media_get_meta(app->m, libvlc_meta_Album);
682 _send_cmd_str(app, meta);
683 meta = libvlc_media_get_meta(app->m, libvlc_meta_Date);
684 _send_cmd_str(app, meta);
685 meta = libvlc_media_get_meta(app->m, libvlc_meta_Genre);
686 _send_cmd_str(app, meta);
687 meta = NULL; // sending empty comments
688 _send_cmd_str(app, meta);
689 meta = NULL; // sending empty disc id
690 _send_cmd_str(app, meta);
691 meta = libvlc_media_get_meta(app->m, libvlc_meta_TrackNumber);
692 _send_cmd_str(app, meta);
693 _send_cmd_finish(app);
697 _position_changed(struct _App *app)
702 /* sending size info only once */
705 r = libvlc_video_get_size(app->mp, 0, &w, &h);
714 _send_resize(app, w, h);
718 /* sending audio track info */
719 _send_all_track_info(app);
721 /* sending meta info */
722 _send_all_meta_info(app);
725 libvlc_media_player_stop(app->mp);
729 _process_thread_events(struct _App *app)
734 size = read(app->fd_read, &event, sizeof(event));
735 if (size != sizeof(event))
737 fprintf(stderr, "player: problem when reading thread event. size = %zd\n", size);
742 case EM_THREAD_POSITION_CHANGED:
743 _position_changed(app);
745 case EM_THREAD_PLAYBACK_STARTED:
746 _send_cmd(app, EM_RESULT_PLAYBACK_STARTED);
748 case EM_THREAD_PLAYBACK_STOPPED:
750 _send_cmd(app, EM_RESULT_PLAYBACK_STOPPED);
756 main(int argc, const char *argv[])
759 struct pollfd fds[3];
760 int tpipe[2]; // pipe for comunicating events from threads
761 char cwidth[64], cheight[64], cpitch[64], chroma[64];
763 const char *vlc_argv[] =
780 fprintf(stderr, "player: missing paramters.\n");
781 fprintf(stderr, "syntax:\n\t%s <fd read> <fd write>\n", argv[0]);
785 app.em_read = atoi(argv[1]);
786 app.em_write = atoi(argv[2]);
788 int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);
789 snprintf(cwidth, sizeof(cwidth), "%d", DEFAULTWIDTH);
790 snprintf(cheight, sizeof(cheight), "%d", DEFAULTHEIGHT);
791 snprintf(cpitch, sizeof(cpitch), "%d", DEFAULTWIDTH * 4);
792 snprintf(chroma, sizeof(chroma), "RV32");
795 * Naughty xattr in emotion uses ecore_thread to run its thing, this
796 * may leave emotion's reference count high and it won't kill us...
797 * letting us play the video in the background. not good.
799 * prctl(PR_SET_PDEATHSIG) is a linux only thing. Need to find ways
800 * to do it on other platforms. Until then leave it breaking on
801 * such platforms so people port it instead of ignoring.
803 prctl(PR_SET_PDEATHSIG, SIGHUP);
805 app.libvlc = libvlc_new(vlc_argc, vlc_argv);
815 if (_em_cmd_read(&app) != EM_CMD_INIT)
817 fprintf(stderr, "player: wrong init command!\n");
822 _em_read_safe(app.em_read, &size, sizeof(size));
823 _em_read_safe(app.em_read, buf, size);
824 app.shmname = strdup(buf);
826 _send_cmd(&app, EM_RESULT_INIT);
829 app.fd_read = tpipe[0];
830 app.fd_write = tpipe[1];
831 fds[0].fd = app.em_read;
832 fds[0].events = POLLIN;
833 fds[1].fd = app.fd_read;
834 fds[1].events = POLLIN;
835 fds[2].fd = STDERR_FILENO;
842 r = poll(fds, 3, -1);
848 "emotion_generic_vlc: an error ocurred on poll(): %s\n",
853 if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL))
855 fputs("emotion_generic_vlc: error communicating with stdin\n",
859 if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL))
861 fputs("emotion_generic_vlc: error communicating with thread\n",
866 if (fds[0].revents & POLLIN)
867 _process_emotion_commands(&app);
868 if (fds[1].revents & POLLIN)
869 _process_thread_events(&app);
870 if (fds[2].revents & (POLLERR | POLLHUP | POLLNVAL))
874 libvlc_release(app.libvlc);
879 #undef SEND_CMD_PARAM