summaryrefslogtreecommitdiff
path: root/src/generic
diff options
context:
space:
mode:
authorCedric BAIL <cedric@osg.samsung.com>2016-06-01 11:32:15 -0700
committerTom Hacohen <tom@stosb.com>2016-06-02 11:35:05 +0100
commit36f15d761a2d39fc81c38a9db7b13d1d571ef453 (patch)
treed2e5da2b9b7d7974c59a23ad866b49632c1809a9 /src/generic
parente649307d92325862f1f5fdad5c8e94cfd0cd2f71 (diff)
emotion: integrate generic legacy vlc support in the build system.
Diffstat (limited to 'src/generic')
-rw-r--r--src/generic/emotion/vlc/emotion_generic_vlc.c790
1 files changed, 790 insertions, 0 deletions
diff --git a/src/generic/emotion/vlc/emotion_generic_vlc.c b/src/generic/emotion/vlc/emotion_generic_vlc.c
new file mode 100644
index 0000000..456509e
--- /dev/null
+++ b/src/generic/emotion/vlc/emotion_generic_vlc.c
@@ -0,0 +1,790 @@
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 <signal.h>
18
19#include <vlc/vlc.h>
20
21#include <Emotion_Generic_Plugin.h>
22#include <Eina.h>
23#include <Ecore.h>
24
25static int _em_vlc_log_dom = -1;
26#define ERR(...) EINA_LOG_DOM_ERR(_em_vlc_log_dom, __VA_ARGS__)
27#define DBG(...) EINA_LOG_DOM_DBG(_em_vlc_log_dom, __VA_ARGS__)
28#define INF(...) EINA_LOG_DOM_INFO(_em_vlc_log_dom, __VA_ARGS__)
29#define WRN(...) EINA_LOG_DOM_WARN(_em_vlc_log_dom, __VA_ARGS__)
30#define CRIT(...) EINA_LOG_DOM_CRIT(_em_vlc_log_dom, __VA_ARGS__)
31
32
33typedef struct _App App;
34struct _App {
35 Emotion_Generic_Video_Shared *vs;
36 Emotion_Generic_Video_Frame vf;
37
38 libvlc_instance_t *libvlc;
39 libvlc_media_t *m;
40 libvlc_media_player_t *mp;
41 libvlc_event_manager_t *event_mgr;
42
43 Ecore_Pipe *fd_read; // read commands from emotion here
44 Ecore_Pipe *fd_write; // write commands for emotion here
45 Eina_Lock cmd_mutex;// lock used to send just one command at a time
46 int last_order; // current command received from emotion
47
48 char *filename;
49 char *subtitle_path;
50 char *shmname;
51 unsigned w, h;
52 int volume;
53 Eina_Bool audio_muted;
54
55 Eina_Bool opening;
56 Eina_Bool closing;
57 Eina_Bool playing;
58 Eina_Bool inited;
59};
60
61static void _player_setup(App *app);
62
63
64/* Utilities to send commands back to emotion */
65#define SEND_CMD_PARAM(app, i) \
66 if ((app)->fd_write) \
67 if (!ecore_pipe_write((app)->fd_write, &(i), sizeof((i)))) \
68 ecore_main_loop_quit();
69
70static void
71_send_cmd(App *app, int cmd)
72{
73 if (!app->fd_write)
74 return;
75
76 eina_lock_take(&app->cmd_mutex); /* LOCK HERE */
77
78 if (!ecore_pipe_write(app->fd_write, &cmd, sizeof(cmd)))
79 ecore_main_loop_quit();
80}
81
82static void
83_send_cmd_str(App *app, const char *str)
84{
85 int len;
86
87 len = str ? strlen(str) + 1 : 0;
88 if (app->fd_write)
89 if (!ecore_pipe_write(app->fd_write, &len, sizeof(len)))
90 ecore_main_loop_quit();
91 if (app->fd_write)
92 if (!ecore_pipe_write(app->fd_write, str, len))
93 ecore_main_loop_quit();
94}
95
96static void
97_send_cmd_finish(App *app)
98{
99 eina_lock_release(&app->cmd_mutex); /* UNLOCK HERE */
100}
101
102/* Commands sent to the emotion pipe */
103static void
104_send_file_closed(App *app)
105{
106 _send_cmd(app, EM_RESULT_FILE_CLOSE);
107 _send_cmd_finish(app);
108}
109
110static void
111_send_time_changed(App *app)
112{
113 float new_time;
114
115 if (app->vs->frame_drop > 1)
116 return;
117
118 new_time = libvlc_media_player_get_time(app->mp);
119 new_time /= 1000;
120 _send_cmd(app, EM_RESULT_POSITION_CHANGED);
121 SEND_CMD_PARAM(app, new_time);
122 _send_cmd_finish(app);
123}
124
125static void
126_send_resize(App *app, int width, int height)
127{
128 _send_cmd(app, EM_RESULT_FRAME_SIZE);
129 SEND_CMD_PARAM(app, width);
130 SEND_CMD_PARAM(app, height);
131 _send_cmd_finish(app);
132}
133
134static void
135_send_track_info(App *app, int cmd, int current, int count, libvlc_track_description_t *desc)
136{
137 _send_cmd(app, cmd);
138 SEND_CMD_PARAM(app, current);
139 SEND_CMD_PARAM(app, count);
140 while (desc)
141 {
142 int tid = desc->i_id;
143 const char *name = desc->psz_name;
144 SEND_CMD_PARAM(app, tid);
145 _send_cmd_str(app, name);
146 desc = desc->p_next;
147 }
148 _send_cmd_finish(app);
149}
150
151static void
152_send_all_track_info(App *app)
153{
154 int track_count, current;
155 libvlc_track_description_t *desc;
156
157 current = libvlc_audio_get_track(app->mp);
158 track_count = libvlc_audio_get_track_count(app->mp);
159 desc = libvlc_audio_get_track_description(app->mp);
160
161 _send_track_info(app, EM_RESULT_AUDIO_TRACK_INFO,
162 current, track_count, desc);
163
164 current = libvlc_video_get_track(app->mp);
165 track_count = libvlc_video_get_track_count(app->mp);
166 desc = libvlc_video_get_track_description(app->mp);
167
168 _send_track_info(app, EM_RESULT_VIDEO_TRACK_INFO,
169 current, track_count, desc);
170
171 current = libvlc_video_get_spu(app->mp);
172 track_count = libvlc_video_get_spu_count(app->mp);
173 desc = libvlc_video_get_spu_description(app->mp);
174
175 _send_track_info(app, EM_RESULT_SPU_TRACK_INFO,
176 current, track_count, desc);
177}
178
179static void
180_send_all_meta_info(App *app)
181{
182 const char *meta;
183
184 _send_cmd(app, EM_RESULT_META_INFO);
185
186 /*
187 * Will send in this order: title, artist, album, year,
188 * genre, comments, disc id and track count.
189 */
190 meta = libvlc_media_get_meta(app->m, libvlc_meta_Title);
191 _send_cmd_str(app, meta);
192 meta = libvlc_media_get_meta(app->m, libvlc_meta_Artist);
193 _send_cmd_str(app, meta);
194 meta = libvlc_media_get_meta(app->m, libvlc_meta_Album);
195 _send_cmd_str(app, meta);
196 meta = libvlc_media_get_meta(app->m, libvlc_meta_Date);
197 _send_cmd_str(app, meta);
198 meta = libvlc_media_get_meta(app->m, libvlc_meta_Genre);
199 _send_cmd_str(app, meta);
200 meta = NULL; // sending empty comments
201 _send_cmd_str(app, meta);
202 meta = NULL; // sending empty disc id
203 _send_cmd_str(app, meta);
204 meta = libvlc_media_get_meta(app->m, libvlc_meta_TrackNumber);
205 _send_cmd_str(app, meta);
206
207 _send_cmd_finish(app);
208}
209
210static void
211_send_length_changed(App *app)
212{
213 float length = libvlc_media_player_get_length(app->mp);
214
215 length /= 1000;
216 _send_cmd(app, EM_RESULT_LENGTH_CHANGED);
217 SEND_CMD_PARAM(app, length);
218 _send_cmd_finish(app);
219}
220
221static void
222_send_seekable_changed(App *app, const struct libvlc_event_t *ev)
223{
224 int seekable = ev->u.media_player_seekable_changed.new_seekable;
225
226 _send_cmd(app, EM_RESULT_SEEKABLE_CHANGED);
227 SEND_CMD_PARAM(app, seekable);
228 _send_cmd_finish(app);
229}
230
231static void
232_send_playback_started(App *app)
233{
234 _send_cmd(app, EM_RESULT_PLAYBACK_STARTED);
235 _send_cmd_finish(app);
236}
237
238static void
239_send_playback_stopped(App *app)
240{
241 _send_cmd(app, EM_RESULT_PLAYBACK_STOPPED);
242 _send_cmd_finish(app);
243}
244
245static void
246_send_init(App *app)
247{
248 _send_cmd(app, EM_RESULT_INIT);
249 _send_cmd_finish(app);
250}
251
252static void
253_send_file_set(App *app)
254{
255 _send_cmd(app, EM_RESULT_FILE_SET);
256 _send_cmd_finish(app);
257}
258
259static void
260_send_file_set_done(App *app, int success)
261{
262 _send_cmd(app, EM_RESULT_FILE_SET_DONE);
263 SEND_CMD_PARAM(app, success);
264 _send_cmd_finish(app);
265}
266
267
268/* VLC events and callbacks */
269static void
270_event_cb(const struct libvlc_event_t *ev, void *data)
271{
272 App *app = data;
273
274 ecore_thread_main_loop_begin();
275 switch (ev->type)
276 {
277 case libvlc_MediaPlayerTimeChanged:
278 // DBG("libvlc_MediaPlayerTimeChanged");
279 _send_time_changed(app);
280 break;
281 case libvlc_MediaPlayerLengthChanged:
282 DBG("libvlc_MediaPlayerLengthChanged");
283 _send_length_changed(app);
284 break;
285 case libvlc_MediaPlayerSeekableChanged:
286 DBG("libvlc_MediaPlayerSeekableChanged");
287 _send_seekable_changed(app, ev);
288 break;
289 case libvlc_MediaPlayerPlaying:
290 DBG("libvlc_MediaPlayerPlaying");
291 libvlc_audio_set_volume(app->mp, app->volume);
292 libvlc_audio_set_mute(app->mp, app->audio_muted);
293 _send_playback_started(app);
294 break;
295 case libvlc_MediaPlayerStopped:
296 DBG("libvlc_MediaPlayerStopped");
297 _send_playback_stopped(app);
298 if (app->closing)
299 {
300 free(app->filename);
301 app->filename = NULL;
302 free(app->subtitle_path);
303 app->subtitle_path = NULL;
304 libvlc_media_release(app->m);
305 app->m = NULL;
306 libvlc_media_player_release(app->mp);
307 app->mp = NULL;
308 emotion_generic_shm_free(app->vs);
309 app->playing = EINA_FALSE;
310 app->closing = EINA_FALSE;
311 _send_file_closed(app);
312 }
313 break;
314 case libvlc_MediaPlayerEndReached:
315 DBG("libvlc_MediaPlayerEndReached");
316 app->playing = EINA_FALSE;
317 /* vlc had released the media_playere here, we create a new one */
318 app->mp = libvlc_media_player_new_from_media(app->m);
319 _player_setup(app);
320 _send_playback_stopped(app);
321 break;
322 }
323 ecore_thread_main_loop_end();
324}
325
326static void
327_tmp_playing_event_cb(const struct libvlc_event_t *ev, void *data)
328{
329 App *app = data;
330
331 if (ev->type != libvlc_MediaPlayerPlaying)
332 return;
333
334 /* pause and stop listening the temporary event */
335 libvlc_event_detach(app->event_mgr,libvlc_MediaPlayerPlaying,
336 _tmp_playing_event_cb, app);
337 libvlc_media_player_set_pause(app->mp, 1);
338
339 /* sending size info */
340 libvlc_video_get_size(app->mp, 0, &app->w, &app->h);
341 _send_resize(app, app->w, app->h);
342
343 /* sending total lenght */
344 _send_length_changed(app);
345
346 /* sending audio track info */
347 _send_all_track_info(app);
348
349 /* sending meta info */
350 _send_all_meta_info(app);
351
352 /* ok, we are done! Now let emotion create the shmem for us */
353 _send_file_set(app);
354}
355
356static void *
357_lock(void *data, void **pixels)
358{
359 App *app = data;
360
361 if (app->playing)
362 *pixels = app->vf.frames[app->vs->frame.player];
363 else
364 *pixels = NULL;
365
366 return NULL; // picture identifier, not needed here
367}
368
369static void
370_unlock(void *data EINA_UNUSED, void *id EINA_UNUSED, void *const *pixels EINA_UNUSED)
371{
372}
373
374static void
375_display(void *data, void *id EINA_UNUSED)
376{
377 App *app = data;
378
379 if (!app->playing)
380 return;
381
382 eina_semaphore_lock(&app->vs->lock);
383 app->vs->frame.last = app->vs->frame.player;
384 app->vs->frame.player = app->vs->frame.next;
385 app->vs->frame.next = app->vs->frame.last;
386 if (!app->vs->frame_drop++)
387 {
388 _send_cmd(app, EM_RESULT_FRAME_NEW);
389 _send_cmd_finish(app);
390 }
391 eina_semaphore_release(&app->vs->lock, 1);
392}
393
394static void
395_player_setup(App *app)
396{
397
398 libvlc_video_set_format(app->mp, "RV32", app->w, app->h, app->w * 4);
399 libvlc_video_set_callbacks(app->mp, _lock, _unlock, _display, app);
400
401 app->event_mgr = libvlc_media_player_event_manager(app->mp);
402 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPlaying,
403 _event_cb, app);
404 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerTimeChanged,
405 _event_cb, app);
406 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerLengthChanged,
407 _event_cb, app);
408 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerSeekableChanged,
409 _event_cb, app);
410 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerEndReached,
411 _event_cb, app);
412 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerStopped,
413 _event_cb, app);
414}
415
416/* Commands received from the emotion pipe */
417static void
418_file_set(App *app)
419{
420 DBG("Path: %s", app->filename);
421 app->m = libvlc_media_new_path(app->libvlc, app->filename);
422 if (!app->m)
423 {
424 ERR("could not open path: \"%s\"", app->filename);
425 return;
426 }
427
428 app->mp = libvlc_media_player_new_from_media(app->m);
429 if (!app->mp)
430 {
431 ERR("could not create new player from media.");
432 return;
433 }
434
435 app->opening = EINA_TRUE;
436
437 /* Here we start playing and connect a temporary callback to know when
438 * the file is parsed and ready to be played for real.
439 */
440 app->event_mgr = libvlc_media_player_event_manager(app->mp);
441 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPlaying,
442 _tmp_playing_event_cb, app);
443
444 libvlc_media_player_play(app->mp);
445}
446
447static void
448_file_set_done(App *app)
449{
450 int r;
451
452 DBG("Path: %s", app->filename);
453 app->opening = EINA_FALSE;
454
455 r = emotion_generic_shm_get(app->shmname, &app->vs, &app->vf);
456 if (!r)
457 {
458 free(app->filename);
459 libvlc_media_release(app->m);
460 libvlc_media_player_release(app->mp);
461 app->filename = NULL;
462 app->m = NULL;
463 app->mp = NULL;
464 }
465 else
466 {
467 _player_setup(app);
468 }
469
470 _send_file_set_done(app, r);
471}
472
473static void
474_file_close(App *app)
475{
476 DBG("closing file");
477
478 if (!app->mp)
479 return;
480
481 app->closing = EINA_TRUE;
482 libvlc_media_player_stop(app->mp);
483}
484
485static void
486_stop(App *app)
487{
488 DBG("Stop");
489 if (app->mp)
490 libvlc_media_player_set_pause(app->mp, 1);
491}
492
493static void
494_play(App *app, float pos)
495{
496 DBG("Play at %.3f", pos);
497
498 if (!app->mp)
499 return;
500
501 if (app->playing)
502 {
503 libvlc_media_player_set_pause(app->mp, 0);
504 }
505 else
506 {
507 libvlc_time_t new_time = pos * 1000;
508 libvlc_media_player_set_time(app->mp, new_time);
509 libvlc_media_player_play(app->mp);
510
511 if (app->subtitle_path)
512 libvlc_video_set_subtitle_file(app->mp, app->subtitle_path);
513
514 app->playing = EINA_TRUE;
515 }
516}
517
518static void
519_position_set(App *app, float position)
520{
521 libvlc_time_t new_time;
522
523 DBG("Position set %.3f", position);
524 if (!app->mp)
525 return;
526
527 new_time = position * 1000;
528 libvlc_media_player_set_time(app->mp, new_time);
529
530 if (libvlc_media_player_get_state(app->mp) == libvlc_Paused)
531 _send_time_changed(app);
532}
533
534static void
535_speed_set(App *app, float rate)
536{
537 DBG("Speed set %.3f", rate);
538 if (!app->mp)
539 return;
540
541 libvlc_media_player_set_rate(app->mp, rate);
542}
543
544static void
545_mute_set(App *app, int mute)
546{
547 DBG("Mute %d", mute);
548 if (!app->mp)
549 return;
550
551 app->audio_muted = mute;
552 libvlc_audio_set_mute(app->mp, mute);
553}
554
555static void
556_volume_set(App *app, float volume)
557{
558 DBG("Volume set %.2f", volume);
559 if (!app->mp)
560 return;
561
562 app->volume = volume * 100;
563 libvlc_audio_set_volume(app->mp, app->volume);
564}
565
566static void
567_spu_track_set(App *app, int track)
568{
569 DBG("SPU track %d", track);
570 libvlc_video_set_spu(app->mp, track);
571}
572
573static void
574_audio_track_set(App *app, int track)
575{
576 DBG("Audio track %d", track);
577 libvlc_audio_set_track(app->mp, track);
578}
579
580static void
581_video_track_set(App *app, int track)
582{
583 DBG("Video Track %d", track);
584 libvlc_video_set_track(app->mp, track);
585}
586
587static void
588_remote_command(void *data, void *buffer, unsigned int nbyte)
589{
590 App *app = data;
591
592 if (nbyte == 0)
593 {
594 ecore_main_loop_quit();
595 return ;
596 }
597
598 if (app->last_order == EM_CMD_LAST)
599 {
600 if (nbyte != sizeof (int))
601 {
602 ERR("didn't receive a valid command from emotion (%i) !", nbyte);
603 ecore_main_loop_quit();
604 return ;
605 }
606
607 app->last_order = *((int*) buffer);
608
609 if (!app->inited &&
610 app->last_order != EM_CMD_INIT)
611 {
612 ERR("wrong init command!");
613 ecore_main_loop_quit();
614 return ;
615 }
616
617 switch (app->last_order)
618 {
619 case EM_CMD_FILE_SET:
620 if (app->opening)
621 {
622 libvlc_media_release(app->m);
623 libvlc_media_player_release(app->mp);
624 free(app->filename);
625 app->opening = EINA_FALSE;
626 }
627 break;
628 case EM_CMD_FILE_SET_DONE:
629 _file_set_done(app);
630 app->last_order = EM_CMD_LAST;
631 break;
632 case EM_CMD_FILE_CLOSE:
633 _file_close(app);
634 app->last_order = EM_CMD_LAST;
635 break;
636 case EM_CMD_STOP:
637 _stop(app);
638 app->last_order = EM_CMD_LAST;
639 break;
640 }
641 }
642 else
643 {
644 switch (app->last_order)
645 {
646 case EM_CMD_INIT:
647 app->shmname = strdup(buffer);
648 app->inited = EINA_TRUE;
649 _send_init(app);
650 break;
651 case EM_CMD_FILE_SET:
652 app->filename = strdup(buffer);
653 _file_set(app);
654 break;
655 case EM_CMD_SUBTITLE_SET:
656 app->subtitle_path = strdup(buffer);
657 break;
658 case EM_CMD_PLAY:
659 _play(app, *(float*) buffer);
660 break;
661 case EM_CMD_POSITION_SET:
662 _position_set(app, *(float*) buffer);
663 break;
664 case EM_CMD_SPEED_SET:
665 _speed_set(app, *(float*) buffer);
666 break;
667 case EM_CMD_AUDIO_MUTE_SET:
668 _mute_set(app, *(int*) buffer);
669 break;
670 case EM_CMD_VOLUME_SET:
671 _volume_set(app, *(float*) buffer);
672 break;
673 case EM_CMD_SPU_TRACK_SET:
674 _spu_track_set(app, *(int*) buffer);
675 break;
676 case EM_CMD_AUDIO_TRACK_SET:
677 _audio_track_set(app, *(int*) buffer);
678 break;
679 case EM_CMD_VIDEO_TRACK_SET:
680 _video_track_set(app, *(int*) buffer);
681 break;
682 }
683 app->last_order = EM_CMD_LAST;
684 }
685}
686
687static void
688_dummy(void *data EINA_UNUSED, void *buffer EINA_UNUSED, unsigned int nbyte EINA_UNUSED)
689{
690 /* This function is useless for the pipe we use to send message back
691 to emotion, but still needed */
692}
693
694/* Main */
695static Eina_Bool
696exit_func(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED)
697{
698 DBG("Quit signal received !");
699 ecore_main_loop_quit();
700 return EINA_TRUE;
701}
702
703int
704main(int argc, const char *argv[])
705{
706 App app;
707 Ecore_Event_Handler *hld;
708 int vlc_argc;
709
710 const char *vlc_argv[] =
711 {
712 "--quiet",
713 "--intf", "dummy", /* no interface */
714 "--vout", "dummy", /* we don't want video (output) */
715 "--no-video-title-show", /* nor the filename displayed */
716 "--no-sub-autodetect-file", /* we don't want automatic subtitles */
717 "--no-stats", /* no stats */
718 "--no-inhibit", /* we don't want interfaces */
719 "--no-disable-screensaver", /* we don't want interfaces */
720// XXX: causes newer vlcs to segv!
721// "--codec", "avcodec",
722// XXX: disable this just in case
723// "--demux", "avformat"
724 };
725 vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);
726
727 memset(&app, 0, sizeof(app));
728 if (!eina_init())
729 {
730 EINA_LOG_CRIT("Can't initialize generic vlc player, eina failed.");
731 return -1;
732 }
733
734 _em_vlc_log_dom = eina_log_domain_register("emotion_generic_vlc",
735 EINA_COLOR_CYAN);
736 if (_em_vlc_log_dom < 0)
737 {
738 EINA_LOG_CRIT("Unable to register emotion_generic_vlc log domain.");
739 goto error;
740 }
741
742 if (!eina_log_domain_level_check(_em_vlc_log_dom, EINA_LOG_LEVEL_WARN))
743 eina_log_domain_level_set("emotion_generic_vlc", EINA_LOG_LEVEL_WARN);
744
745 if (argc < 3)
746 {
747 ERR("missing parameters.");
748 ERR("syntax:\n\t%s <fd read> <fd write>", argv[0]);
749 goto error;
750 }
751
752 ecore_init();
753
754 eina_lock_new(&app.cmd_mutex);
755
756 app.fd_read = ecore_pipe_full_add(_remote_command, &app,
757 atoi(argv[1]), -1, EINA_FALSE, EINA_FALSE);
758 app.fd_write = ecore_pipe_full_add(_dummy, NULL,
759 -1, atoi(argv[2]), EINA_FALSE, EINA_FALSE);
760
761 hld = ecore_event_handler_add(ECORE_EVENT_SIGNAL_HUP, exit_func, NULL);
762
763 app.libvlc = libvlc_new(vlc_argc, vlc_argv);
764 app.mp = NULL;
765 app.filename = NULL;
766 app.subtitle_path = NULL;
767 app.w = 0;
768 app.h = 0;
769 app.opening = EINA_FALSE;
770 app.playing = EINA_FALSE;
771 app.inited = EINA_FALSE;
772 app.last_order = EM_CMD_LAST;
773
774 ecore_main_loop_begin();
775
776 libvlc_release(app.libvlc);
777 ecore_pipe_del(app.fd_read);
778 ecore_pipe_del(app.fd_write);
779 ecore_event_handler_del(hld);
780 eina_lock_free(&app.cmd_mutex);
781
782 ecore_shutdown();
783 eina_shutdown();
784 return 0;
785
786 error:
787 eina_shutdown();
788 return -1;
789}
790#undef SEND_CMD_PARAM