summaryrefslogtreecommitdiff
path: root/legacy/emotion/src/generic_players/vlc/emotion_generic_vlc.c
diff options
context:
space:
mode:
authorRafael Antognolli <antognolli@gmail.com>2011-09-01 19:04:15 +0000
committerRafael Antognolli <antognolli@gmail.com>2011-09-01 19:04:15 +0000
commita7ae4566b8f911676009a04c4411e3aff87b2abc (patch)
tree261efdbc88edb53e245597502549bb5a96b36df6 /legacy/emotion/src/generic_players/vlc/emotion_generic_vlc.c
parent1cacec0d415ce520ae49197e31efd16ffd37a4c4 (diff)
Add generic player backend (with vlc player).
This generic player backend executes a separate player in another process. It receives the bytes to be drawn on the emotion object through a shared memory, and communicates with the player through a pipe, using the player standard input/output. The player must communicate with emotion using the defined commands specified in the Emotion_Generic_Plugin.h. It doesn't need to link against emotion, just include this file for easier implementation. This implementation was sponsored by Zodiac Aerospace. SVN revision: 63062
Diffstat (limited to '')
-rw-r--r--legacy/emotion/src/generic_players/vlc/emotion_generic_vlc.c700
1 files changed, 700 insertions, 0 deletions
diff --git a/legacy/emotion/src/generic_players/vlc/emotion_generic_vlc.c b/legacy/emotion/src/generic_players/vlc/emotion_generic_vlc.c
new file mode 100644
index 0000000000..773bbe9b7a
--- /dev/null
+++ b/legacy/emotion/src/generic_players/vlc/emotion_generic_vlc.c
@@ -0,0 +1,700 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include <errno.h>
6#include <limits.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <unistd.h>
10#include <string.h>
11#include <sys/mman.h>
12#include <sys/stat.h>
13#include <fcntl.h>
14#include <pthread.h>
15#include <poll.h>
16
17#include <vlc/vlc.h>
18#include <Emotion_Generic_Plugin.h>
19
20enum _Thread_Events {
21 EM_THREAD_POSITION_CHANGED,
22 EM_THREAD_LAST
23};
24
25struct _App {
26 Emotion_Generic_Video_Shared *vs;
27 Emotion_Generic_Video_Frame vf;
28 libvlc_instance_t *libvlc;
29 libvlc_media_t *m;
30 libvlc_media_player_t *mp;
31 libvlc_event_manager_t *event_mgr;
32 libvlc_event_manager_t *mevent_mgr;
33 char *filename;
34 char *shmname;
35 int w, h;
36 int fd_read;
37 int fd_write;
38 int size_sent;
39 int opening;
40 int closing;
41 int playing;
42};
43
44static pthread_mutex_t _mutex_fd = PTHREAD_MUTEX_INITIALIZER;
45
46int
47_em_read_safe(int fd, void *buf, ssize_t size)
48{
49 ssize_t todo;
50 char *p;
51
52 todo = size;
53 p = buf;
54
55 while (todo > 0)
56 {
57 ssize_t r;
58
59 r = read(fd, p, todo);
60 if (r > 0)
61 {
62 todo -= r;
63 p += r;
64 }
65 else if (r == 0)
66 return 0;
67 else
68 {
69 if (errno == EINTR || errno == EAGAIN)
70 continue;
71 else
72 {
73 fprintf(stderr, "could not read from fd %d: %s",
74 fd, strerror(errno));
75 return 0;
76 }
77 }
78 }
79
80 return 1;
81}
82
83int
84_em_write_safe(int fd, const void *buf, ssize_t size)
85{
86 ssize_t todo;
87 const char *p;
88
89 todo = size;
90 p = buf;
91
92 while (todo > 0)
93 {
94 ssize_t r;
95
96 r = write(fd, p, todo);
97 if (r > 0)
98 {
99 todo -= r;
100 p += r;
101 }
102 else if (r == 0)
103 return 0;
104 else
105 {
106 if (errno == EINTR || errno == EAGAIN)
107 continue;
108 else
109 {
110 fprintf(stderr, "could not write to fd %d: %s",
111 fd, strerror(errno));
112 return 0;
113 }
114 }
115 }
116
117 return 1;
118}
119
120static int
121_em_str_read(char **str)
122{
123 int size;
124 int r;
125 char buf[PATH_MAX];
126
127 r = _em_read_safe(STDIN_FILENO, &size, sizeof(size));
128 if (!r)
129 {
130 *str = NULL;
131 return 0;
132 }
133
134 if (!size)
135 {
136 *str = NULL;
137 return 1;
138 }
139
140 r = _em_read_safe(STDIN_FILENO, buf, size);
141 if (!r)
142 {
143 *str = NULL;
144 return 0;
145 }
146
147 *str = strdup(buf);
148 return 1;
149}
150
151static int
152_em_cmd_read(void)
153{
154 int cmd;
155 _em_read_safe(STDIN_FILENO, &cmd, sizeof(cmd));
156
157 return cmd;
158}
159
160static void
161_send_cmd_start(int cmd)
162{
163 pthread_mutex_lock(&_mutex_fd);
164 _em_write_safe(STDOUT_FILENO, &cmd, sizeof(cmd));
165}
166
167static void
168_send_cmd_finish(void)
169{
170 static const char c = '\n';
171 _em_write_safe(STDOUT_FILENO, &c, sizeof(c));
172 pthread_mutex_unlock(&_mutex_fd);
173}
174
175static void
176_send_cmd(int cmd)
177{
178 _send_cmd_start(cmd);
179 _send_cmd_finish();
180}
181
182static void
183_send_cmd_str(const char *str)
184{
185 int len;
186 len = strlen(str) + 1;
187 _em_write_safe(STDOUT_FILENO, &len, sizeof(len));
188 _em_write_safe(STDOUT_FILENO, str, len);
189}
190
191#define SEND_CMD_PARAM(i) \
192 _em_write_safe(STDOUT_FILENO, &(i), sizeof((i)));
193
194static void
195_send_resize(int width, int height)
196{
197 _send_cmd_start(EM_RESULT_FRAME_SIZE);
198 SEND_CMD_PARAM(width);
199 SEND_CMD_PARAM(height);
200 _send_cmd_finish();
201}
202
203static void
204_send_length_changed(const struct libvlc_event_t *ev)
205{
206 float length = ev->u.media_player_length_changed.new_length;
207 length /= 1000;
208
209 fprintf(stderr, "length changed: %0.3f\n", length);
210 _send_cmd_start(EM_RESULT_LENGTH_CHANGED);
211 SEND_CMD_PARAM(length);
212 _send_cmd_finish();
213}
214
215static void
216_send_time_changed(const struct libvlc_event_t *ev)
217{
218 float new_time = ev->u.media_player_time_changed.new_time;
219 new_time /= 1000;
220 _send_cmd_start(EM_RESULT_POSITION_CHANGED);
221 SEND_CMD_PARAM(new_time);
222 _send_cmd_finish();
223}
224
225static void
226_send_seekable_changed(const struct libvlc_event_t *ev)
227{
228 int seekable = ev->u.media_player_seekable_changed.new_seekable;
229 _send_cmd_start(EM_RESULT_SEEKABLE_CHANGED);
230 SEND_CMD_PARAM(seekable);
231 _send_cmd_finish();
232}
233
234static void *
235_lock(void *data, void **pixels)
236{
237 struct _App *app = data;
238
239 if (app->playing)
240 *pixels = app->vf.frames[app->vs->frame.player];
241 else
242 *pixels = NULL;
243
244 return NULL; // picture identifier, not needed here
245}
246
247static void
248_unlock(void *data, void *id, void *const *pixels)
249{
250 struct _App *app = data;
251
252 if (!app->playing)
253 return;
254
255 sem_wait(&app->vs->lock);
256 app->vs->frame.last = app->vs->frame.player;
257 app->vs->frame.player = app->vs->frame.next;
258 app->vs->frame.next = app->vs->frame.last;
259
260 sem_post(&app->vs->lock);
261}
262
263static void
264_display(void *data, void *id)
265{
266 struct _App *app = data;
267 if (!app->playing)
268 return;
269
270 _send_cmd(EM_RESULT_FRAME_NEW);
271}
272
273static void *
274_tmp_lock(void *data, void **pixels)
275{
276 *pixels = NULL;
277 return NULL;
278}
279
280static void
281_tmp_unlock(void *data, void *id, void *const *pixels)
282{
283}
284
285static void
286_tmp_display(void *data, void *id)
287{
288}
289
290static void
291_play(struct _App *app)
292{
293 float pos;
294
295 if (!app->mp)
296 return;
297
298 _em_read_safe(STDIN_FILENO, &pos, sizeof(pos));
299
300 if (app->playing)
301 {
302 libvlc_media_player_set_pause(app->mp, 0);
303 }
304 else
305 {
306 libvlc_time_t new_time = pos * 1000;
307 libvlc_media_player_play(app->mp);
308 libvlc_media_player_set_time(app->mp, new_time);
309 app->playing = 1;
310 }
311}
312
313static void
314_stop(struct _App *app)
315{
316 if (app->mp)
317 libvlc_media_player_set_pause(app->mp, 1);
318}
319
320static void
321_send_file_closed(struct _App *app)
322{
323 app->closing = 0;
324 emotion_generic_shm_free(app->vs);
325 _send_cmd(EM_RESULT_FILE_CLOSE);
326}
327
328static void
329_send_file_set(struct _App *app)
330{
331 if (app->opening)
332 _send_cmd(EM_RESULT_FILE_SET);
333
334 if (app->closing)
335 _send_file_closed(app);
336}
337
338static void
339_event_cb(const struct libvlc_event_t *ev, void *data)
340{
341 struct _App *app = data;
342 int thread_event;
343
344 switch (ev->type) {
345 case libvlc_MediaPlayerTimeChanged:
346 _send_time_changed(ev);
347 break;
348 case libvlc_MediaPlayerPositionChanged:
349 thread_event = EM_THREAD_POSITION_CHANGED;
350 write(app->fd_write, &thread_event, sizeof(thread_event));
351 break;
352 case libvlc_MediaPlayerLengthChanged:
353 _send_length_changed(ev);
354 break;
355 case libvlc_MediaPlayerSeekableChanged:
356 _send_seekable_changed(ev);
357 break;
358 case libvlc_MediaPlayerPlaying:
359 _send_resize(app->w, app->h);
360 break;
361 case libvlc_MediaPlayerStopped:
362 _send_file_set(app);
363 break;
364 case libvlc_MediaPlayerEndReached:
365 _send_cmd(EM_RESULT_PLAYBACK_STOPPED);
366 break;
367 }
368}
369
370static void
371_file_set(struct _App *app)
372{
373 _em_str_read(&app->filename);
374
375 app->m = libvlc_media_new_path(app->libvlc, app->filename);
376 if (!app->m)
377 {
378 fprintf(stderr, "could not open path: \"%s\"\n", app->filename);
379 return;
380 }
381 app->mp = libvlc_media_player_new_from_media(app->m);
382
383 if (!app->mp)
384 {
385 fprintf(stderr, "could not create new player from media.\n");
386 return;
387 }
388
389 app->opening = 1;
390 libvlc_video_set_format(app->mp, "RV32", DEFAULTWIDTH, DEFAULTHEIGHT, DEFAULTWIDTH * 4);
391 libvlc_video_set_callbacks(app->mp, _tmp_lock, _tmp_unlock, _tmp_display, NULL);
392 app->event_mgr = libvlc_media_player_event_manager(app->mp);
393 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPositionChanged,
394 _event_cb, app);
395 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerStopped,
396 _event_cb, app);
397
398 app->mevent_mgr = libvlc_media_event_manager(app->m);
399
400 libvlc_audio_set_mute(app->mp, 1);
401 libvlc_media_player_play(app->mp);
402}
403
404static void
405_position_set(struct _App *app)
406{
407 if (!app->mp)
408 return;
409
410 float position;
411 _em_read_safe(STDIN_FILENO, &position, sizeof(position));
412
413 libvlc_time_t new_time = position * 1000;
414 libvlc_media_player_set_time(app->mp, new_time);
415}
416
417static void
418_speed_set(struct _App *app)
419{
420 float rate;
421
422 if (!app->mp)
423 return;
424
425 _em_read_safe(STDIN_FILENO, &rate, sizeof(rate));
426
427 libvlc_media_player_set_rate(app->mp, rate);
428}
429
430static void
431_mute_set(struct _App *app)
432{
433 int mute;
434
435 if (!app->mp)
436 return;
437
438 _em_read_safe(STDIN_FILENO, &mute, sizeof(mute));
439
440 libvlc_audio_set_mute(app->mp, mute);
441}
442
443static void
444_volume_set(struct _App *app)
445{
446 float volume;
447 int vol;
448
449 if (!app->mp)
450 return;
451
452 _em_read_safe(STDIN_FILENO, &volume, sizeof(volume));
453 vol = volume * 100;
454
455 libvlc_audio_set_volume(app->mp, vol);
456}
457
458static void
459_audio_track_set(struct _App *app)
460{
461 int track;
462
463 _em_read_safe(STDIN_FILENO, &track, sizeof(track));
464
465 libvlc_audio_set_track(app->mp, track);
466}
467
468static void
469_file_set_done(struct _App *app)
470{
471 emotion_generic_shm_get(app->shmname, &app->vs, &app->vf);
472 app->w = app->vs->width;
473 app->h = app->vs->height;
474 libvlc_video_set_format(app->mp, "RV32", app->w, app->h, app->w * 4);
475 libvlc_video_set_callbacks(app->mp, _lock, _unlock, _display, app);
476 app->opening = 0;
477
478
479 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPlaying,
480 _event_cb, app);
481 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerTimeChanged,
482 _event_cb, app);
483 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerLengthChanged,
484 _event_cb, app);
485 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerSeekableChanged,
486 _event_cb, app);
487
488 libvlc_audio_set_mute(app->mp, 0);
489 _send_cmd(EM_RESULT_FILE_SET_DONE);
490}
491
492static void
493_file_close(struct _App *app)
494{
495 app->playing = 0;
496 if (libvlc_media_player_get_state(app->mp) != libvlc_Playing)
497 {
498 _send_file_closed(app);
499 return;
500 }
501
502 app->closing = 1;
503 libvlc_media_player_stop(app->mp);
504 if (app->filename)
505 free(app->filename);
506 if (app->mp)
507 {
508 libvlc_media_release(app->m);
509 libvlc_media_player_release(app->mp);
510 }
511}
512
513static void
514_process_emotion_commands(struct _App *app)
515{
516 int cmd = _em_cmd_read();
517 switch (cmd) {
518 case EM_CMD_FILE_SET:
519 _file_set(app);
520 break;
521 case EM_CMD_FILE_SET_DONE:
522 _file_set_done(app);
523 break;
524 case EM_CMD_FILE_CLOSE:
525 _file_close(app);
526 break;
527 case EM_CMD_PLAY:
528 _play(app);
529 break;
530 case EM_CMD_STOP:
531 _stop(app);
532 break;
533 case EM_CMD_POSITION_SET:
534 _position_set(app);
535 break;
536 case EM_CMD_SPEED_SET:
537 _speed_set(app);
538 break;
539 case EM_CMD_AUDIO_MUTE_SET:
540 _mute_set(app);
541 break;
542 case EM_CMD_VOLUME_SET:
543 _volume_set(app);
544 break;
545 case EM_CMD_AUDIO_TRACK_SET:
546 _audio_track_set(app);
547 break;
548 };
549}
550
551static void
552_send_track_info(libvlc_media_player_t *mp)
553{
554 int track_count, current;
555 libvlc_track_description_t *desc;
556
557 current = libvlc_audio_get_track(mp);
558 track_count = libvlc_audio_get_track_count(mp);
559 desc = libvlc_audio_get_track_description(mp);
560
561 _send_cmd_start(EM_RESULT_AUDIO_TRACK_INFO);
562 SEND_CMD_PARAM(current);
563 SEND_CMD_PARAM(track_count);
564 while (desc)
565 {
566 int tid = desc->i_id;
567 const char *name = desc->psz_name;
568 SEND_CMD_PARAM(tid);
569 _send_cmd_str(name);
570 desc = desc->p_next;
571 }
572 _send_cmd_finish();
573}
574
575static void
576_position_changed(struct _App *app)
577{
578 if (!app->opening)
579 return;
580
581 /* sending size info only once */
582 int r, w, h;
583 r = libvlc_video_get_size(app->mp, 0, &w, &h);
584 if (r < 0)
585 return;
586 _send_resize(w, h);
587
588 /* sending audio track info */
589 // _send_track_info(app->mp);
590
591 libvlc_media_player_stop(app->mp);
592}
593
594static void
595_process_thread_events(struct _App *app)
596{
597 int event;
598 size_t size;
599
600 size = read(app->fd_read, &event, sizeof(event));
601 if (size != sizeof(event))
602 {
603 fprintf(stderr, "player: problem when reading thread event. size = %zd\n", size);
604 return;
605 }
606
607 switch (event) {
608 case EM_THREAD_POSITION_CHANGED:
609 _position_changed(app);
610 break;
611 }
612}
613
614int
615main(int argc, const char *argv[])
616{
617 struct _App app;
618 Emotion_Generic_Video_Shared *vs;
619 struct pollfd fds[2]; // watching on 2 file descriptors
620 int tpipe[2]; // pipe for comunicating events from threads
621 char shmname[256];
622 char cwidth[64], cheight[64], cpitch[64], chroma[64];
623 char buf[64];
624 const char *vlc_argv[] =
625 {
626 "--quiet",
627 "--vout",
628 "vmem",
629 "--vmem-width",
630 cwidth,
631 "--vmem-height",
632 cheight,
633 "--vmem-pitch",
634 cpitch,
635 "--vmem-chroma",
636 chroma
637 };
638
639 int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);
640 snprintf(cwidth, sizeof(cwidth), "%d", DEFAULTWIDTH);
641 snprintf(cheight, sizeof(cheight), "%d", DEFAULTHEIGHT);
642 snprintf(cpitch, sizeof(cpitch), "%d", DEFAULTWIDTH * 4);
643 snprintf(chroma, sizeof(chroma), "RV32");
644
645 app.libvlc = libvlc_new(vlc_argc, vlc_argv);
646 app.mp = NULL;
647 app.filename = NULL;
648 app.w = 0;
649 app.h = 0;
650 app.size_sent = 0;
651 app.opening = 0;
652 app.playing = 0;
653 app.closing = 0;
654
655 if (_em_cmd_read() != EM_CMD_INIT)
656 {
657 fprintf(stderr, "player: wrong init command!\n");
658 return -1;
659 }
660
661 int size;
662 _em_read_safe(STDIN_FILENO, &size, sizeof(size));
663 _em_read_safe(STDIN_FILENO, buf, size);
664 app.shmname = strdup(buf);
665
666 _send_cmd(EM_RESULT_INIT);
667
668 pipe(tpipe);
669 app.fd_read = tpipe[0];
670 app.fd_write = tpipe[1];
671 fds[0].fd = STDIN_FILENO;
672 fds[0].events = POLLIN;
673 fds[1].fd = app.fd_read;
674 fds[1].events = POLLIN;
675
676 while (1)
677 {
678 int r;
679
680 r = poll(fds, 2, 30);
681 if (r == 0)
682 continue;
683 else if (r < 0)
684 {
685 fprintf(stderr, "an error ocurred on poll().\n");
686 break;
687 }
688
689 if (fds[0].revents & POLLIN)
690 _process_emotion_commands(&app);
691 if (fds[1].revents & POLLIN)
692 _process_thread_events(&app);
693 }
694
695 libvlc_release(app.libvlc);
696
697
698 return 0;
699}
700#undef SEND_CMD_PARAM