summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Guillem <thomas@gllm.fr>2015-09-21 23:19:17 +0200
committerCedric BAIL <cedric@osg.samsung.com>2015-09-21 23:19:20 +0200
commitafe6f5c3a1adbfc3f1b8ab828021accc55b29341 (patch)
treef1b14483f3e1d7cded2389e82fc6e64960b92ee1
parent07fbef64371d4d6eaabe2ffad939b1d4b277bd13 (diff)
emotion: add libvlc module
Summary: Everything is implemented except visualization, mouse events and some EMOTION_EVENT. Video can output RGBA, YUY2, YV12 or I420. About the video sink: this emotion module use libvlc callbacks: libvlc_video_set_format_callbacks and libvlc_video_set_callbacks. It may be temporary. Indeed, an other solution is to add an Evas module inside vlc. But this vlc module would need to link with emotion in order to use _emotion_frame_new and _emotion_frame_resize private functions. I didn't succeed to output a frame without these private functions: see https://github.com/tguillem/vlc/commit/15daff4d3fdcd3ca7b485c1f8fabb8c1e1c4138c List of /* FIXME */: - Visualization not implemented since there is no API (for now) in libvlc. - Mouse events not implemented since there is no API (for now) in libvlc. - Some EMOTION_EVENT are not handled. - SIGSEGV in evas_gl_common_texture_nv12_update with EVAS_COLORSPACE_YCBCR420NV12601_PL colorspace. Subscribers: cedric Differential Revision: https://phab.enlightenment.org/D3071 Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
Diffstat (limited to '')
-rw-r--r--configure.ac13
-rw-r--r--m4/emotion_module.m414
-rw-r--r--src/Makefile_Emotion.am29
-rw-r--r--src/lib/emotion/emotion_modules.c14
-rw-r--r--src/modules/emotion/libvlc/emotion_libvlc.c1765
5 files changed, 1835 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 092a86dff2..ab6a0618ce 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4332,6 +4332,17 @@ AC_ARG_ENABLE([v4l2],
4332 ], 4332 ],
4333 [want_v4l2="${efl_lib_optional_eeze}"]) 4333 [want_v4l2="${efl_lib_optional_eeze}"])
4334 4334
4335AC_ARG_ENABLE([libvlc],
4336 [AS_HELP_STRING([--enable-libvlc],[enable libvlc support. @<:@default=disabled@:>@])],
4337 [
4338 if test "x${enableval}" = "xyes" ; then
4339 want_libvlc="yes"
4340 else
4341 want_libvlc="no"
4342 fi
4343 ],
4344 [want_libvlc="no"])
4345
4335### Checks for programs 4346### Checks for programs
4336 4347
4337### Checks for libraries 4348### Checks for libraries
@@ -4354,11 +4365,13 @@ have_gst_xoverlay="no"
4354EMOTION_MODULE([xine], [${want_xine}]) 4365EMOTION_MODULE([xine], [${want_xine}])
4355EMOTION_MODULE([gstreamer], [${want_gstreamer}]) 4366EMOTION_MODULE([gstreamer], [${want_gstreamer}])
4356EMOTION_MODULE([gstreamer1], [${want_gstreamer1}]) 4367EMOTION_MODULE([gstreamer1], [${want_gstreamer1}])
4368EMOTION_MODULE([libvlc], [${want_libvlc}])
4357EMOTION_MODULE([generic], [${want_emotion_generic}]) 4369EMOTION_MODULE([generic], [${want_emotion_generic}])
4358 4370
4359EFL_ADD_FEATURE([EMOTION], [xine]) 4371EFL_ADD_FEATURE([EMOTION], [xine])
4360EFL_ADD_FEATURE([EMOTION], [gstreamer]) 4372EFL_ADD_FEATURE([EMOTION], [gstreamer])
4361EFL_ADD_FEATURE([EMOTION], [gstreamer1]) 4373EFL_ADD_FEATURE([EMOTION], [gstreamer1])
4374EFL_ADD_FEATURE([EMOTION], [libvlc])
4362EFL_ADD_FEATURE([EMOTION], [generic], [${want_emotion_generic}]) 4375EFL_ADD_FEATURE([EMOTION], [generic], [${want_emotion_generic}])
4363 4376
4364EFL_EVAL_PKGS([EMOTION]) 4377EFL_EVAL_PKGS([EMOTION])
diff --git a/m4/emotion_module.m4 b/m4/emotion_module.m4
index 75884e78d4..51ed0da1e3 100644
--- a/m4/emotion_module.m4
+++ b/m4/emotion_module.m4
@@ -58,6 +58,20 @@ AC_DEFUN([EMOTION_MODULE_DEP_CHECK_GSTREAMER1],
58 fi 58 fi
59]) 59])
60 60
61
62dnl use: EMOTION_MODULE_DEP_CHECK_LIBVLC(want_static)
63dnl where want_engine = yes or static
64AC_DEFUN([EMOTION_MODULE_DEP_CHECK_LIBVLC],
65[dnl
66 LIBVLC_VER=3.0
67 requirements="libvlc >= ${LIBVLC_VER}"
68 if test "$1" = "static"; then
69 EFL_DEPEND_PKG([EMOTION], [EMOTION_MODULE_LIBVLC], [${requirements}])
70 else
71 PKG_CHECK_MODULES([EMOTION_MODULE_LIBVLC], [${requirements}])
72 fi
73])
74
61dnl use: EMOTION_MODULE_DEP_CHECK_GENERIC(want_static) 75dnl use: EMOTION_MODULE_DEP_CHECK_GENERIC(want_static)
62dnl where want_engine = yes or static 76dnl where want_engine = yes or static
63AC_DEFUN([EMOTION_MODULE_DEP_CHECK_GENERIC], 77AC_DEFUN([EMOTION_MODULE_DEP_CHECK_GENERIC],
diff --git a/src/Makefile_Emotion.am b/src/Makefile_Emotion.am
index 6b6efca300..f16a4a4c3d 100644
--- a/src/Makefile_Emotion.am
+++ b/src/Makefile_Emotion.am
@@ -157,6 +157,35 @@ modules_emotion_gstreamer1_module_la_LIBTOOLFLAGS = --tag=disable-static
157endif 157endif
158endif 158endif
159 159
160# LibVLC
161EMOTION_LIBVLC_SOURCES =\
162modules/emotion/libvlc/emotion_libvlc.c
163
164if EMOTION_STATIC_BUILD_LIBVLC
165lib_emotion_libemotion_la_SOURCES += $(EMOTION_LIBVLC_SOURCES)
166else
167if EMOTION_BUILD_LIBVLC
168emotionmodulelibvlcdir = $(libdir)/emotion/modules/libvlc/$(MODULE_ARCH)
169emotionmodulelibvlc_LTLIBRARIES = modules/emotion/libvlc/module.la
170
171# Workaround for broken parallel install support in automake (relink issue)
172# http://debbugs.gnu.org/cgi/bugreport.cgi?bug=7328
173install_emotionmodulelibvlcLTLIBRARIES = install-emotionmodulelibvlcLTLIBRARIES
174$(install_emotionmodulelibvlcLTLIBRARIES): install-libLTLIBRARIES
175
176modules_emotion_libvlc_module_la_SOURCES = $(EMOTION_LIBVLC_SOURCES)
177modules_emotion_libvlc_module_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
178@EMOTION_CFLAGS@ \
179@EMOTION_MODULE_LIBVLC_CFLAGS@
180modules_emotion_libvlc_module_la_LIBADD = \
181@USE_EMOTION_LIBS@ \
182@EMOTION_MODULE_LIBVLC_LIBS@
183modules_emotion_libvlc_module_la_DEPENDENCIES = @USE_EMOTION_INTERNAL_LIBS@
184modules_emotion_libvlc_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@
185modules_emotion_libvlc_module_la_LIBTOOLFLAGS = --tag=disable-static
186endif
187endif
188
160# Generic 189# Generic
161EMOTION_GENERIC_SOURCES = \ 190EMOTION_GENERIC_SOURCES = \
162modules/emotion/generic/emotion_generic.h \ 191modules/emotion/generic/emotion_generic.h \
diff --git a/src/lib/emotion/emotion_modules.c b/src/lib/emotion/emotion_modules.c
index 6630096ffc..590a61fc42 100644
--- a/src/lib/emotion/emotion_modules.c
+++ b/src/lib/emotion/emotion_modules.c
@@ -13,6 +13,10 @@ void xine_module_shutdown(void);
13Eina_Bool gstreamer_module_init(void); 13Eina_Bool gstreamer_module_init(void);
14void gstreamer_module_shutdown(void); 14void gstreamer_module_shutdown(void);
15#endif 15#endif
16#ifdef EMOTION_STATIC_BUILD_LIBVLC
17Eina_Bool libvlc_module_init(void);
18void libvlc_module_shutdown(void);
19#endif
16#ifdef EMOTION_STATIC_BUILD_GENERIC 20#ifdef EMOTION_STATIC_BUILD_GENERIC
17Eina_Bool generic_module_init(void); 21Eina_Bool generic_module_init(void);
18void generic_module_shutdown(void); 22void generic_module_shutdown(void);
@@ -79,6 +83,9 @@ _emotion_modules_load(void)
79#ifdef EMOTION_BUILD_XINE 83#ifdef EMOTION_BUILD_XINE
80 "xine", 84 "xine",
81#endif 85#endif
86#ifdef EMOTION_BUILD_LIBVLC
87 "libvlc",
88#endif
82 NULL 89 NULL
83 }; 90 };
84 const char **itr; 91 const char **itr;
@@ -118,6 +125,9 @@ emotion_modules_init(void)
118#if defined(EMOTION_STATIC_BUILD_GSTREAMER) || defined(EMOTION_STATIC_BUILD_GSTREAMER1) 125#if defined(EMOTION_STATIC_BUILD_GSTREAMER) || defined(EMOTION_STATIC_BUILD_GSTREAMER1)
119 gstreamer_module_init(); 126 gstreamer_module_init();
120#endif 127#endif
128#ifdef EMOTION_STATIC_BUILD_LIBVLC
129 libvlc_module_init();
130#endif
121#ifdef EMOTION_STATIC_BUILD_GENERIC 131#ifdef EMOTION_STATIC_BUILD_GENERIC
122 generic_module_init(); 132 generic_module_init();
123#endif 133#endif
@@ -136,6 +146,9 @@ emotion_modules_shutdown(void)
136#if defined(EMOTION_STATIC_BUILD_GSTREAMER) || defined(EMOTION_STATIC_BUILD_GSTREAMER1) 146#if defined(EMOTION_STATIC_BUILD_GSTREAMER) || defined(EMOTION_STATIC_BUILD_GSTREAMER1)
137 gstreamer_module_shutdown(); 147 gstreamer_module_shutdown();
138#endif 148#endif
149#ifdef EMOTION_STATIC_BUILD_LIBVLC
150 libvlc_module_shutdown();
151#endif
139#ifdef EMOTION_STATIC_BUILD_GENERIC 152#ifdef EMOTION_STATIC_BUILD_GENERIC
140 generic_module_shutdown(); 153 generic_module_shutdown();
141#endif 154#endif
@@ -366,6 +379,7 @@ emotion_engine_instance_new(const char *name, Evas_Object *obj, Emotion_Module_O
366 if (!m) m = _find_mod("xine"); 379 if (!m) m = _find_mod("xine");
367 if (!m) m = _find_mod("gstreamer"); 380 if (!m) m = _find_mod("gstreamer");
368 if (!m) m = _find_mod("gstreamer1"); 381 if (!m) m = _find_mod("gstreamer1");
382 if (!m) m = _find_mod("libvlc");
369 if (m) eina_module_load(m); 383 if (m) eina_module_load(m);
370 } 384 }
371 385
diff --git a/src/modules/emotion/libvlc/emotion_libvlc.c b/src/modules/emotion/libvlc/emotion_libvlc.c
new file mode 100644
index 0000000000..2b941f0201
--- /dev/null
+++ b/src/modules/emotion/libvlc/emotion_libvlc.c
@@ -0,0 +1,1765 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include <assert.h>
6
7#include <Eina.h>
8#include <Evas.h>
9#include <Ecore.h>
10
11#include <vlc/vlc.h>
12#include <vlc/libvlc_media.h>
13#include <vlc/libvlc_media_player.h>
14
15#include "emotion_modules.h"
16
17#ifdef DBG
18#undef DBG
19#endif
20#define DBG(...) EINA_LOG_DOM_DBG(_emotion_libvlc_log_domain, __VA_ARGS__)
21
22#ifdef INF
23#undef INF
24#endif
25#define INF(...) EINA_LOG_DOM_INFO(_emotion_libvlc_log_domain, __VA_ARGS__)
26
27#ifdef WRN
28#undef WRN
29#endif
30#define WRN(...) EINA_LOG_DOM_WARN(_emotion_libvlc_log_domain, __VA_ARGS__)
31
32#ifdef ERR
33#undef ERR
34#endif
35#define ERR(...) EINA_LOG_DOM_ERR(_emotion_libvlc_log_domain, __VA_ARGS__)
36
37#ifdef CRI
38#undef CRI
39#endif
40#define CRI(...) EINA_LOG_DOM_CRIT(_emotion_libvlc_log_domain, __VA_ARGS__)
41
42#define SINK_MAX_PLANES 3
43
44static int _emotion_libvlc_log_domain = -1;
45static Eina_Bool debug_fps = EINA_FALSE;
46static libvlc_instance_t *libvlc = NULL;
47
48typedef struct _Emotion_LibVLC Emotion_LibVLC;
49
50static void em_file_close(void *);
51
52struct _Emotion_LibVLC
53{
54 /* Evas object */
55 Evas_Object *obj;
56 Evas_Object *evas_obj;
57 Emotion_Module_Options opt;
58
59 /* libvlc */
60 libvlc_media_t *m;
61 libvlc_media_player_t *mp;
62 unsigned int nb_tracks;
63 libvlc_media_track_t **tracks;
64 int nb_chapters;
65 libvlc_chapter_description_t **chapters;
66 char *subtitle_file;
67 char *metas[META_TRACK_COUNT];
68
69 /* options */
70 int video_mute;
71 int audio_mute;
72 int audio_vol;
73 Emotion_Vis vis;
74
75 /* There can be remaining mainloop callbacks that owns the Emotion_LibVLC
76 * object when em_del is called. Use a ref_count to delete the ev object
77 * when em_del is called and when all callbacks are processed. */
78 unsigned int ref_count;
79
80 /* locks */
81 Eina_Lock lock;
82 Eina_Condition wait;
83 Eina_List *event_list;
84
85 /* stats */
86 double pos;
87 double len;
88 double buffer_cache;
89 Eina_Bool seeking;
90 Eina_Bool started;
91 Eina_Bool invalidate_tracks;
92
93 /* sink, must be locked by ev->lock */
94 struct
95 {
96 int width;
97 int height;
98 Evas_Colorspace colorspace;
99 void *data;
100 Eina_Bool waiting;
101 Eina_Bool is_yuv;
102
103 unsigned int nb_planes;
104 unsigned int lines[SINK_MAX_PLANES];
105 unsigned int pitches[SINK_MAX_PLANES];
106 unsigned int yuv_height[SINK_MAX_PLANES];
107 unsigned char *yuv_data[SINK_MAX_PLANES];
108 unsigned int yuv_planes_order[SINK_MAX_PLANES];
109 } sink;
110};
111
112static const libvlc_event_type_t mp_events[] = {
113 //libvlc_MediaPlayerMediaChanged,
114 //libvlc_MediaPlayerNothingSpecial,
115 //libvlc_MediaPlayerOpening,
116 libvlc_MediaPlayerBuffering,
117 libvlc_MediaPlayerPlaying,
118 //libvlc_MediaPlayerPaused,
119 libvlc_MediaPlayerStopped,
120 libvlc_MediaPlayerForward,
121 //libvlc_MediaPlayerBackward,
122 libvlc_MediaPlayerEndReached,
123 libvlc_MediaPlayerEncounteredError,
124 libvlc_MediaPlayerTimeChanged,
125 //libvlc_MediaPlayerPositionChanged,
126 //libvlc_MediaPlayerSeekableChanged,
127 //libvlc_MediaPlayerPausableChanged,
128 //libvlc_MediaPlayerTitleChanged,
129 //libvlc_MediaPlayerSnapshotTaken,
130 libvlc_MediaPlayerLengthChanged,
131 //libvlc_MediaPlayerVout,
132 //libvlc_MediaPlayerScrambledChanged,
133 libvlc_MediaPlayerESAdded,
134 libvlc_MediaPlayerESDeleted,
135 //libvlc_MediaPlayerESSelected,
136 //libvlc_MediaPlayerCorked,
137 //libvlc_MediaPlayerUncorked,
138 //libvlc_MediaPlayerMuted,
139 //libvlc_MediaPlayerUnmuted,
140 //libvlc_MediaPlayerAudioVolume,
141 //libvlc_MediaPlayerAudioDevice,
142 -1,
143};
144
145static void
146em_del_safe(Emotion_LibVLC *ev)
147{
148 eina_lock_free(&ev->lock);
149 eina_condition_free(&ev->wait);
150 free(ev->subtitle_file);
151 free(ev);
152}
153
154/* Take the ev->lock from a mainloop callback.
155 * Returns false if the ev object is destroyed. */
156static Eina_Bool
157emotion_mainloop_lock(Emotion_LibVLC *ev)
158{
159 eina_lock_take(&ev->lock);
160 _emotion_pending_ecore_end();
161 if (--ev->ref_count == 0)
162 {
163 eina_lock_release(&ev->lock);
164 WRN("callbacks ended, deleting Emotion_LibVLC");
165 em_del_safe(ev);
166 return EINA_FALSE;
167 }
168 return EINA_TRUE;
169}
170
171/* Send a callback to the mainloop */
172static void
173emotion_mainloop_call_locked(Emotion_LibVLC *ev, Ecore_Cb callback)
174{
175 ++ev->ref_count;
176 _emotion_pending_ecore_begin();
177 ecore_main_loop_thread_safe_call_async(callback, ev);
178}
179
180/* Take the ev->lock from a sink mainloop callback.
181 * Returns false if the ev object is destroyed or is there is no evas object. */
182static Eina_Bool
183emotion_mainloop_sink_lock(Emotion_LibVLC *ev)
184{
185 if (emotion_mainloop_lock(ev))
186 {
187 if (!ev->evas_obj)
188 {
189 eina_lock_release(&ev->lock);
190 return EINA_FALSE;
191 }
192 else
193 return EINA_TRUE;
194 }
195 else
196 return EINA_FALSE;
197}
198
199/* Release the ev->lock from a sink mainloop callback and signal that the
200 * callback is processed. */
201static void
202emotion_mainloop_sink_signal_unlock(Emotion_LibVLC *ev)
203{
204 ev->sink.waiting = EINA_FALSE;
205 eina_condition_signal(&ev->wait);
206 eina_lock_release(&ev->lock);
207}
208
209/* Send a sink mainloop callback and wait. */
210static void
211emotion_mainloop_sink_call_wait_locked(Emotion_LibVLC *ev, Ecore_Cb callback)
212{
213 ev->sink.waiting = EINA_TRUE;
214
215 emotion_mainloop_call_locked(ev, callback);
216
217 while (ev->evas_obj && ev->sink.waiting)
218 eina_condition_wait(&ev->wait);
219}
220
221/* Sink mainloop callback, sent by libvlc_video_on_lock. */
222static void
223emotion_mainloop_sink_pic_lock(void *data)
224{
225 Emotion_LibVLC *ev = data;
226 if (!emotion_mainloop_sink_lock(ev)) return;
227
228 ev->sink.data = evas_object_image_data_get(ev->evas_obj, 1);
229
230 emotion_mainloop_sink_signal_unlock(ev);
231}
232
233/* Sink mainloop callback, sent by libvlc_video_on_unlock. */
234static void
235emotion_mainloop_sink_pic_unlock(void *data)
236{
237 Emotion_LibVLC *ev = data;
238
239 if (!emotion_mainloop_sink_lock(ev)) return;
240
241 if (!ev->sink.data)
242 goto end;
243
244 if (ev->sink.is_yuv)
245 {
246 unsigned int i, j;
247 const unsigned char **rows = (const unsigned char **)ev->sink.data;
248
249 for (i = 0; i < ev->sink.nb_planes; ++i)
250 for (j = 0; j < ev->sink.yuv_height[i]; ++j)
251 *(rows++) = &ev->sink.yuv_data[i][j * ev->sink.pitches[i]];
252 }
253 evas_object_image_data_set(ev->evas_obj, ev->sink.data);
254 ev->sink.data = NULL;
255
256end:
257 emotion_mainloop_sink_signal_unlock(ev);
258}
259
260/* Sink mainloop callback, sent by libvlc_video_on_display. */
261static void
262emotion_mainloop_sink_display(void *data)
263{
264 Emotion_LibVLC *ev = data;
265
266 if (!emotion_mainloop_sink_lock(ev)) return;
267
268 evas_object_image_data_update_add(ev->evas_obj, 0, 0, ev->sink.width,
269 ev->sink.height);
270 _emotion_frame_new(ev->obj);
271
272 emotion_mainloop_sink_signal_unlock(ev);
273}
274
275/* Sink mainloop callback, sent by libvlc_video_on_format. */
276static void
277emotion_mainloop_sink_format(void *data)
278{
279 Emotion_LibVLC *ev = data;
280
281 if (!emotion_mainloop_sink_lock(ev)) return;
282
283 evas_object_image_pixels_get_callback_set(ev->evas_obj, NULL, NULL);
284 evas_object_image_alpha_set(ev->evas_obj, 0);
285 evas_object_image_colorspace_set(ev->evas_obj, ev->sink.colorspace);
286 evas_object_image_size_set(ev->evas_obj, ev->sink.width, ev->sink.height);
287 _emotion_frame_resize(ev->obj, ev->sink.width, ev->sink.height,
288 ev->sink.width / (double)ev->sink.height);
289
290 emotion_mainloop_sink_signal_unlock(ev);
291}
292
293/* Process one libvlc event from the mainloop. */
294static void
295emotion_mainloop_event(Emotion_LibVLC *ev, const libvlc_event_t *event)
296{
297 switch (event->type)
298 {
299 case libvlc_MediaPlayerBuffering:
300 ev->buffer_cache = event->u.media_player_buffering.new_cache / 100.0;
301 break;
302
303 case libvlc_MediaPlayerPlaying:
304 if (!ev->started)
305 {
306 _emotion_open_done(ev->obj);
307 _emotion_playback_started(ev->obj);
308 ev->started = EINA_TRUE;
309 }
310 break;
311
312 case libvlc_MediaPlayerStopped:
313 case libvlc_MediaPlayerEndReached:
314 case libvlc_MediaPlayerEncounteredError:
315 _emotion_decode_stop(ev->obj);
316 _emotion_playback_finished(ev->obj);
317 break;
318
319 case libvlc_MediaPlayerTimeChanged:
320 {
321 if (ev->seeking)
322 {
323 _emotion_seek_done(ev->obj);
324 ev->seeking = EINA_FALSE;
325 }
326
327 ev->pos = event->u.media_player_time_changed.new_time / 1000.0;
328 if (ev->pos > 0 && ev->len > 0)
329 _emotion_video_pos_update(ev->obj, ev->pos, ev->len);
330 break;
331 }
332
333 case libvlc_MediaPlayerLengthChanged:
334 ev->len = event->u.media_player_length_changed.new_length / 1000.0;
335 if (ev->pos > 0 && ev->len > 0)
336 _emotion_video_pos_update(ev->obj, ev->pos, ev->len);
337 break;
338
339 case libvlc_MediaPlayerESAdded:
340 case libvlc_MediaPlayerESDeleted:
341 ev->invalidate_tracks = EINA_TRUE;
342 _emotion_channels_change(ev->obj);
343 break;
344 }
345}
346
347/* Mainloop callback, sent by libvlc_on_mp_event. It processes a list of libvlc
348 * event. */
349static void
350emotion_mainloop_event_list(void *data)
351{
352 Emotion_LibVLC *ev = data;
353 Eina_List *event_list;
354 libvlc_event_t *event;
355
356 if (!emotion_mainloop_lock(ev)) return;
357 event_list = ev->event_list;
358 ev->event_list = NULL;
359 eina_lock_release(&ev->lock);
360
361 if (!event_list) return;
362
363 EINA_LIST_FREE(event_list, event)
364 {
365 if (ev->mp)
366 emotion_mainloop_event(ev, event);
367 free(event);
368 }
369}
370
371/* Libvlc callback, see libvlc_video_set_callbacks and libvlc_video_lock_cb. */
372static void *
373libvlc_video_on_lock(void *opaque, void **pixels)
374{
375 Emotion_LibVLC *ev = opaque;
376
377 eina_lock_take(&ev->lock);
378 if (!ev->evas_obj) goto end;
379
380 emotion_mainloop_sink_call_wait_locked(ev, emotion_mainloop_sink_pic_lock);
381end:
382 if (ev->sink.data)
383 {
384 if (ev->sink.is_yuv)
385 {
386 unsigned int i;
387
388 for (i = 0; i < ev->sink.nb_planes; ++i)
389 pixels[i] = ev->sink.yuv_data[ev->sink.yuv_planes_order[i]];
390 }
391 else
392 pixels[0] = ev->sink.data;
393 }
394 eina_lock_release(&ev->lock);
395
396 return NULL;
397}
398
399/* Libvlc callback, see libvlc_video_set_callbacks and libvlc_video_unlock_cb.
400 * */
401static void
402libvlc_video_on_unlock(void *opaque, void *picture EINA_UNUSED,
403 void *const *pixels EINA_UNUSED)
404{
405 Emotion_LibVLC *ev = opaque;
406
407 eina_lock_take(&ev->lock);
408 if (!ev->evas_obj) goto end;
409
410 emotion_mainloop_sink_call_wait_locked(ev, emotion_mainloop_sink_pic_unlock);
411end:
412 eina_lock_release(&ev->lock);
413}
414
415/* Libvlc callback, see libvlc_video_set_callbacks and libvlc_video_display_cb.
416 * */
417static void
418libvlc_video_on_display(void *opaque, void *picture EINA_UNUSED)
419{
420 Emotion_LibVLC *ev = opaque;
421
422 eina_lock_take(&ev->lock);
423 if (!ev->evas_obj) goto end;
424
425 emotion_mainloop_sink_call_wait_locked(ev, emotion_mainloop_sink_display);
426end:
427 eina_lock_release(&ev->lock);
428}
429
430#define ALIGN32(x) (((x) + 31) & ~(31))
431
432/* Libvlc callback, see libvlc_video_set_format_callbacks and
433 * libvlc_video_format_cb. */
434static unsigned int
435libvlc_video_on_format(void **opaque, char *chroma,
436 unsigned int *width, unsigned int *height,
437 unsigned int *pitches,
438 unsigned int *lines)
439{
440 Emotion_LibVLC *ev = *opaque;
441
442 eina_lock_take(&ev->lock);
443 if (!ev->evas_obj) goto end;
444
445 INF("request video format: %s, size: %dx%d", chroma, *width, *height);
446
447 ev->sink.width = *width;
448 ev->sink.height = *height;
449
450 if (!strcmp(chroma, "RV32"))
451 {
452 ev->sink.colorspace = EVAS_COLORSPACE_ARGB8888;
453 ev->sink.nb_planes = 1;
454 ev->sink.lines[0] = ev->sink.height;
455 ev->sink.pitches[0] = ev->sink.width * 4;
456 }
457 /* Not implemented yet */
458#if 0
459 else if (!strcmp(chroma, "RV16"))
460 {
461 ev->sink.colorspace = EVAS_COLORSPACE_RGB565_A5P;
462 ev->sink.nb_planes = 1;
463 ev->sink.lines[0] = ev->sink.height;
464 ev->sink.pitches[0] = ev->sink.width * 2;
465 }
466#endif
467 else
468 {
469 /* YUV */
470
471 unsigned int i;
472
473 /* default planes order */
474 for (i = 0; i < ev->sink.nb_planes; ++i)
475 ev->sink.yuv_planes_order[i] = i;
476
477 if (!strcmp(chroma, "YUY2"))
478 {
479 ev->sink.colorspace = EVAS_COLORSPACE_YCBCR422601_PL;
480 ev->sink.nb_planes = 1;
481 ev->sink.yuv_height[0] = ev->sink.height;
482 ev->sink.pitches[0] = ev->sink.width * 2;
483 }
484 /* FIXME: SIGSEGV in evas_gl_common_texture_nv12_update */
485#if 0
486 else if (!strcmp(chroma, "NV12"))
487 {
488 ev->sink.colorspace = EVAS_COLORSPACE_YCBCR420NV12601_PL;
489 ev->sink.nb_planes = 2;
490 ev->sink.yuv_height[0] = ev->sink.height;
491 ev->sink.pitches[0] = ev->sink.width;
492 ev->sink.yuv_height[1] = ev->sink.height / 2;
493 ev->sink.pitches[1] = ev->sink.width;
494 }
495#endif
496 else
497 {
498 /* YV12 or I420 */
499 if (strcmp(chroma, "YV12") && strcmp(chroma, "I420"))
500 {
501 strcpy(chroma, "I420");
502 INF("native format not available, using: %s", chroma);
503 }
504 ev->sink.colorspace = EVAS_COLORSPACE_YCBCR422P601_PL;
505 ev->sink.nb_planes = 3;
506 ev->sink.yuv_height[0] = ev->sink.height;
507 ev->sink.pitches[0] = ev->sink.width;
508 ev->sink.yuv_height[1] = ev->sink.yuv_height[2] = ev->sink.height / 2;
509 ev->sink.pitches[1] = ev->sink.pitches[2] = ev->sink.width / 2;
510
511 if (!strcmp(chroma, "YV12"))
512 {
513 /* Cb and Cr inverted for YV12 */
514 ev->sink.yuv_planes_order[0] = 0;
515 ev->sink.yuv_planes_order[1] = 2;
516 ev->sink.yuv_planes_order[2] = 1;
517 }
518 }
519
520 assert(ev->sink.nb_planes <= SINK_MAX_PLANES);
521
522 /* Align pitches/lines and alloc planes */
523 for (i = 0; i < ev->sink.nb_planes; ++i)
524 {
525 ev->sink.lines[i] = ALIGN32(ev->sink.yuv_height[i]);
526 ev->sink.pitches[i] = ALIGN32(ev->sink.pitches[i]);
527 ev->sink.yuv_data[i] = malloc(ev->sink.lines[i]
528 * ev->sink.pitches[i]);
529 if (!ev->sink.yuv_data[i])
530 {
531 for (i = 0; i < ev->sink.nb_planes; ++i)
532 {
533 free(ev->sink.yuv_data[i]);
534 ev->sink.lines[i] = 0;
535 ev->sink.pitches[i] = 0;
536 }
537 ev->sink.nb_planes = 0;
538 goto end;
539 }
540 }
541 ev->sink.is_yuv = EINA_TRUE;
542 }
543
544 assert(ev->sink.nb_planes > 0);
545
546 memcpy(lines, ev->sink.lines, ev->sink.nb_planes * sizeof(unsigned int));
547 memcpy(pitches, ev->sink.pitches, ev->sink.nb_planes * sizeof(unsigned int));
548
549 emotion_mainloop_sink_call_wait_locked(ev, emotion_mainloop_sink_format);
550end:
551 eina_lock_release(&ev->lock);
552 return ev->sink.nb_planes;
553}
554
555/* Libvlc callback, see libvlc_event_manager_t. */
556static void
557libvlc_on_mp_event(const libvlc_event_t *event, void *opaque)
558{
559 Emotion_LibVLC *ev = opaque;
560
561 if (eina_main_loop_is())
562 {
563 /* Process the event directly */
564 emotion_mainloop_event(ev, event);
565 }
566 else
567 {
568 /* Add the event to a list of events that will be processed by the
569 * mainloop */
570
571 void *data = malloc(sizeof(libvlc_event_t));
572 if (!data) return;
573 memcpy(data, event, sizeof(libvlc_event_t));
574
575 eina_lock_take(&ev->lock);
576 if (!ev->event_list)
577 emotion_mainloop_call_locked(ev, emotion_mainloop_event_list);
578 ev->event_list = eina_list_append(ev->event_list, data);
579 eina_lock_release(&ev->lock);
580 }
581}
582
583/* Returns true if libvlc mediaplayer is ready to process commands. */
584static Eina_Bool
585libvlc_mp_is_ready(Emotion_LibVLC *ev)
586{
587 libvlc_state_t state;
588
589 if (!ev->mp) return EINA_FALSE;
590 state = libvlc_media_player_get_state(ev->mp);
591 return state == libvlc_Playing || state == libvlc_Paused;
592}
593
594/* Fetch all libvlc tracks. */
595static int
596libvlc_fetch_tracks(Emotion_LibVLC *ev)
597{
598 if (ev->invalidate_tracks)
599 {
600 if (ev->nb_tracks)
601 libvlc_media_tracks_release(ev->tracks, ev->nb_tracks);
602 ev->nb_tracks = libvlc_media_tracks_get(ev->m, &ev->tracks);
603 ev->invalidate_tracks = EINA_FALSE;
604 }
605 return ev->nb_tracks;
606}
607
608/* Get a libvlc tracks from a track_id. */
609static libvlc_media_track_t *
610libvlc_get_track(Emotion_LibVLC *ev, libvlc_track_type_t type, int id)
611{
612 unsigned int i;
613
614 if (!ev->m || id < 0 || type == libvlc_track_unknown) return NULL;
615
616 if (!libvlc_fetch_tracks(ev)) return NULL;
617
618 for (i = 0; i < ev->nb_tracks; ++i)
619 {
620 libvlc_media_track_t *track = ev->tracks[i];
621
622 if (track->i_id == id && track->i_type == type)
623 return track;
624 }
625
626 return NULL;
627}
628
629/* Get the current libvlc video track. */
630static libvlc_media_track_t *
631libvlc_get_current_video_track(Emotion_LibVLC *ev)
632{
633 int id = libvlc_video_get_track(ev->mp);
634 return id >= 0 ? libvlc_get_track(ev, libvlc_track_video, id) : NULL;
635}
636
637/* Get a libvlc video track at a pos.
638 * XXX: Libvlc use a track_id to get and select a track. The first track_id doesn't
639 * necessarily starts with 0. Emotion use a position (that starts with 0) to
640 * get and select a track. */
641static libvlc_media_track_t *
642libvlc_get_track_at_pos(Emotion_LibVLC *ev,
643 int pos, libvlc_track_type_t type)
644{
645 unsigned int i;
646
647 if (!ev->m || pos < 0 || type == libvlc_track_unknown) return NULL;
648
649 if (!libvlc_fetch_tracks(ev)) return NULL;
650
651 for (i = 0; i < ev->nb_tracks; ++i)
652 {
653 libvlc_media_track_t *track = ev->tracks[i];
654
655 if (type == track->i_type && pos-- == 0)
656 return track;
657 }
658
659 return NULL;
660}
661
662/* Get the position of the libvlc track.
663 * See libvlc_get_track_at_pos. */
664static int
665libvlc_get_track_pos(Emotion_LibVLC *ev, int id, libvlc_track_type_t type)
666{
667 unsigned int i;
668 int pos = 0;
669
670 if (!ev->m || id < 0 || type == libvlc_track_unknown) return -1;
671
672 if (!libvlc_fetch_tracks(ev)) return -1;
673
674 for (i = 0; i < ev->nb_tracks; ++i)
675 {
676 libvlc_media_track_t *track = ev->tracks[i];
677
678 if (type == track->i_type)
679 {
680 if (id == track->i_id)
681 return pos;
682 else
683 pos++;
684 }
685 }
686
687 return -1;
688}
689
690static void *
691em_add(const Emotion_Engine *api EINA_UNUSED,
692 Evas_Object *obj,
693 const Emotion_Module_Options *opt)
694{
695 Emotion_LibVLC *ev;
696 ev = calloc(1, sizeof(Emotion_LibVLC));
697 EINA_SAFETY_ON_NULL_RETURN_VAL(ev, NULL);
698
699 ev->obj = obj;
700 ev->opt = *opt;
701 eina_lock_new(&ev->lock);
702 eina_condition_new(&ev->wait, &ev->lock);
703 ev->ref_count = 1;
704 ev->audio_mute = -1;
705 ev->audio_vol = -1;
706
707 return ev;
708}
709
710static void
711em_del(void *video)
712{
713 Emotion_LibVLC *ev = video;
714
715 if (!ev) return;
716
717 em_file_close(video);
718
719 eina_lock_take(&ev->lock);
720 if (--ev->ref_count > 0)
721 {
722 eina_lock_release(&ev->lock);
723 WRN("em_del delayed, some callbacks are still running");
724 }
725 else
726 {
727 eina_lock_release(&ev->lock);
728 em_del_safe(ev);
729 }
730}
731
732static Eina_Bool
733em_file_open(void *video,
734 const char *file)
735{
736 int ret;
737 Emotion_LibVLC *ev = video;
738 libvlc_event_manager_t *event_m;
739
740 if (!file) return EINA_FALSE;
741
742 ev->evas_obj = emotion_object_image_get(ev->obj);
743 if (!ev->evas_obj)
744 {
745 WRN("emotion_object_image_get failed: no video");
746 ev->opt.no_video = EINA_TRUE;
747 }
748
749 ev->invalidate_tracks = true;
750
751 /* Create libvlc_media */
752 ev->m = libvlc_media_new_path(libvlc, file);
753 EINA_SAFETY_ON_NULL_GOTO(ev->m, error);
754
755 if (ev->opt.no_audio)
756 libvlc_media_add_option(ev->m, ":no-audio");
757
758 if (ev->opt.no_video)
759 libvlc_media_add_option(ev->m, ":no-video");
760
761 /* Create libvlc_media_player */
762 ev->mp = libvlc_media_player_new_from_media(ev->m);
763 EINA_SAFETY_ON_NULL_GOTO(ev->mp, error);
764
765 event_m = libvlc_media_player_event_manager(ev->mp);
766 for (int i = 0; mp_events[i] != -1; ++i)
767 libvlc_event_attach(event_m, mp_events[i], libvlc_on_mp_event, ev);
768
769 libvlc_media_player_set_video_title_display(ev->mp,
770 libvlc_position_disable, 0);
771
772 /* Set sink callbacks */
773 if (!ev->opt.no_video)
774 {
775 libvlc_video_set_format_callbacks(ev->mp, libvlc_video_on_format, NULL);
776 libvlc_video_set_callbacks(ev->mp, libvlc_video_on_lock,
777 libvlc_video_on_unlock,
778 libvlc_video_on_display, ev);
779 }
780
781 if (ev->audio_mute != -1)
782 libvlc_audio_set_mute(ev->mp, 1);
783 if (ev->audio_vol != -1)
784 libvlc_audio_set_volume(ev->mp, ev->audio_vol);
785
786 ret = libvlc_media_player_play(ev->mp);
787 EINA_SAFETY_ON_FALSE_GOTO(ret == 0, error);
788
789 return EINA_TRUE;
790error:
791 em_file_close(video);
792 return EINA_FALSE;
793}
794
795static void
796em_file_close(void *video)
797{
798 Emotion_LibVLC *ev = video;
799 unsigned int i;
800
801 if (ev->mp)
802 {
803 libvlc_event_manager_t *event_m;
804
805 event_m = libvlc_media_player_event_manager(ev->mp);
806 for (int i = 0; mp_events[i] != -1; ++i)
807 libvlc_event_detach(event_m, mp_events[i], libvlc_on_mp_event, ev);
808
809 /* Abort libvlc callbacks */
810 eina_lock_take(&ev->lock);
811 ev->evas_obj = NULL;
812 eina_condition_signal(&ev->wait);
813 eina_lock_release(&ev->lock);
814
815 libvlc_media_player_release(ev->mp);
816 ev->mp = NULL;
817
818 if (ev->seeking)
819 {
820 ev->seeking = EINA_FALSE;
821 _emotion_seek_done(ev->obj);
822 }
823 if (ev->sink.data)
824 {
825 /* unlock already locked buffer */
826 evas_object_image_data_set(ev->evas_obj, ev->sink.data);
827 ev->sink.data = NULL;
828 }
829
830 /* free image data */
831 evas_object_image_size_set(ev->evas_obj, 1, 1);
832 evas_object_image_data_set(ev->evas_obj, NULL);
833
834 /* free yuv data */
835 if (ev->sink.is_yuv)
836 {
837 for (i = 0; i < ev->sink.nb_planes; ++i)
838 free(ev->sink.yuv_data[i]);
839 }
840 }
841 if (ev->m)
842 {
843 libvlc_media_release(ev->m);
844 ev->m = NULL;
845 }
846 if (ev->nb_tracks > 0)
847 {
848 libvlc_media_tracks_release(ev->tracks, ev->nb_tracks);
849 ev->nb_tracks = 0;
850 ev->tracks = NULL;
851 }
852 if (ev->nb_chapters > 0)
853 {
854 libvlc_chapter_descriptions_release(ev->chapters, ev->nb_chapters);
855 ev->nb_chapters = 0;
856 ev->chapters = NULL;
857 }
858 for (i = 0; i < META_TRACK_COUNT; ++i)
859 {
860 free(ev->metas[i]);
861 ev->metas[i] = NULL;
862 }
863 if (ev->subtitle_file)
864 {
865 free(ev->subtitle_file);
866 ev->subtitle_file = NULL;
867 }
868 ev->vis = EMOTION_VIS_NONE;
869 ev->started = ev->seeking = ev->invalidate_tracks = EINA_FALSE;
870 ev->pos = ev->len = ev->buffer_cache = 0.0;
871 memset(&ev->sink, 0, sizeof(ev->sink));
872}
873
874static void
875em_play(void *video,
876 double pos EINA_UNUSED)
877{
878 Emotion_LibVLC *ev = video;
879
880 libvlc_media_player_set_pause(ev->mp, false);
881}
882
883static void
884em_stop(void *video)
885{
886 Emotion_LibVLC *ev = video;
887
888 libvlc_media_player_set_pause(ev->mp, true);
889}
890
891static void
892em_size_get(void *video,
893 int *width,
894 int *height)
895{
896 Emotion_LibVLC *ev = video;
897 libvlc_media_track_t *track;
898
899 if (!width || !height) return;
900 *width = 0;
901 *height = 0;
902
903 if (!libvlc_mp_is_ready(ev)) return;
904
905 track = libvlc_get_current_video_track(ev);
906 if (track)
907 {
908 *width = track->video->i_width;
909 *height = track->video->i_height;
910 }
911}
912
913static double
914em_pos_get(void *video)
915{
916 Emotion_LibVLC *ev = video;
917
918 if (!libvlc_mp_is_ready(ev)) return 0.0;
919
920 return ev->pos;
921}
922
923static void
924em_pos_set(void *video,
925 double pos)
926{
927 Emotion_LibVLC *ev = video;
928
929 if (!libvlc_mp_is_ready(ev))
930 {
931 _emotion_seek_done(ev->obj);
932 return;
933 }
934
935 libvlc_media_player_set_time(ev->mp, pos * 1000);
936
937 ev->seeking = EINA_TRUE;
938}
939
940static double
941em_len_get(void *video)
942{
943 Emotion_LibVLC *ev = video;
944
945 if (!libvlc_mp_is_ready(ev)) return 0.0;
946
947 return ev->len;
948}
949
950static double
951em_buffer_size_get(void *video)
952{
953 Emotion_LibVLC *ev = video;
954
955 if (!libvlc_mp_is_ready(ev)) return 0.0;
956
957 return ev->buffer_cache;
958}
959
960static void
961em_fps_num_den_get(Emotion_LibVLC *ev, int *num, int *den)
962{
963 libvlc_media_track_t *track;
964
965 if (!libvlc_mp_is_ready(ev)) return;
966
967 track = libvlc_get_current_video_track(ev);
968 if (track)
969 {
970 if (num)
971 *num = track->video->i_frame_rate_num;
972 if (den)
973 *den = track->video->i_frame_rate_den;
974 }
975}
976
977static int
978em_fps_num_get(void *video)
979{
980 int num = 0;
981
982 em_fps_num_den_get(video, &num, NULL);
983 return num;
984}
985
986static int
987em_fps_den_get(void *video)
988{
989 int den = 0;
990
991 em_fps_num_den_get(video, NULL, &den);
992 return den;
993}
994
995static double
996em_fps_get(void *video)
997{
998 int num = 0, den = 0;
999
1000 em_fps_num_den_get(video, &num, &den);
1001 return num / (double)den;
1002}
1003
1004static void
1005em_vis_set(void *video,
1006 Emotion_Vis vis)
1007{
1008 Emotion_LibVLC *ev = video;
1009
1010 ev->vis = vis;
1011}
1012
1013static Emotion_Vis
1014em_vis_get(void *video)
1015{
1016 Emotion_LibVLC *ev = video;
1017
1018 return ev->vis;
1019}
1020
1021static Eina_Bool
1022em_vis_supported(void *ev EINA_UNUSED, Emotion_Vis vis)
1023{
1024 /* FIXME */
1025 if (vis == EMOTION_VIS_NONE)
1026 return EINA_TRUE;
1027 else
1028 return EINA_FALSE;
1029}
1030
1031static double
1032em_ratio_get(void *video)
1033{
1034 Emotion_LibVLC *ev = video;
1035 libvlc_media_track_t *track;
1036
1037 if (!libvlc_mp_is_ready(ev)) return 0.0;
1038
1039 track = libvlc_get_current_video_track(ev);
1040 if (track)
1041 {
1042 double ratio = track->video->i_sar_num
1043 / (double)track->video->i_sar_den;
1044 return ratio;
1045 }
1046 else
1047 return 0.0;
1048}
1049
1050static int
1051em_video_handled(void *video)
1052{
1053 Emotion_LibVLC *ev = video;
1054
1055 if (!libvlc_mp_is_ready(ev)) return 0.0;
1056
1057 return libvlc_video_get_track_count(ev->mp) > 0;
1058}
1059
1060static int
1061em_audio_handled(void *video)
1062{
1063 Emotion_LibVLC *ev = video;
1064
1065 if (!libvlc_mp_is_ready(ev)) return 0.0;
1066
1067 return libvlc_audio_get_track_count(ev->mp) > 0;
1068}
1069
1070static int
1071em_seekable(void *video)
1072{
1073 Emotion_LibVLC *ev = video;
1074
1075 if (!libvlc_mp_is_ready(ev)) return 0;
1076
1077 return libvlc_media_player_is_seekable(ev->mp);
1078}
1079
1080static void
1081em_frame_done(void *video EINA_UNUSED)
1082{
1083}
1084
1085static Emotion_Format
1086em_format_get(void *video EINA_UNUSED)
1087{
1088 return EMOTION_FORMAT_NONE;
1089}
1090
1091static void
1092em_video_data_size_get(void *video EINA_UNUSED, int *w EINA_UNUSED, int *h EINA_UNUSED)
1093{
1094}
1095
1096static int
1097em_yuv_rows_get(void *video EINA_UNUSED,
1098 int w EINA_UNUSED,
1099 int h EINA_UNUSED,
1100 unsigned char **yrows EINA_UNUSED,
1101 unsigned char **urows EINA_UNUSED,
1102 unsigned char **vrows EINA_UNUSED)
1103{
1104 return 0;
1105}
1106
1107static int
1108em_bgra_data_get(void *video EINA_UNUSED, unsigned char **bgra_data EINA_UNUSED)
1109{
1110 return 0;
1111}
1112
1113static void
1114em_event_feed(void *video, int event)
1115{
1116 Emotion_LibVLC *ev = video;
1117 unsigned int navigate;
1118
1119 if (!libvlc_mp_is_ready(ev)) return;
1120
1121 switch (event)
1122 {
1123 case EMOTION_EVENT_UP:
1124 navigate = libvlc_navigate_up;
1125 break;
1126
1127 case EMOTION_EVENT_DOWN:
1128 navigate = libvlc_navigate_down;
1129 break;
1130
1131 case EMOTION_EVENT_LEFT:
1132 navigate = libvlc_navigate_left;
1133 break;
1134
1135 case EMOTION_EVENT_RIGHT:
1136 navigate = libvlc_navigate_right;
1137 break;
1138
1139 case EMOTION_EVENT_SELECT:
1140 navigate = libvlc_navigate_activate;
1141 break;
1142
1143 /* FIXME */
1144 default:
1145 case EMOTION_EVENT_MENU1:
1146 case EMOTION_EVENT_MENU2:
1147 case EMOTION_EVENT_MENU3:
1148 case EMOTION_EVENT_MENU4:
1149 case EMOTION_EVENT_MENU5:
1150 case EMOTION_EVENT_MENU6:
1151 case EMOTION_EVENT_MENU7:
1152 case EMOTION_EVENT_NEXT:
1153 case EMOTION_EVENT_PREV:
1154 case EMOTION_EVENT_ANGLE_NEXT:
1155 case EMOTION_EVENT_ANGLE_PREV:
1156 case EMOTION_EVENT_FORCE:
1157 case EMOTION_EVENT_0:
1158 case EMOTION_EVENT_1:
1159 case EMOTION_EVENT_2:
1160 case EMOTION_EVENT_3:
1161 case EMOTION_EVENT_4:
1162 case EMOTION_EVENT_5:
1163 case EMOTION_EVENT_6:
1164 case EMOTION_EVENT_7:
1165 case EMOTION_EVENT_8:
1166 case EMOTION_EVENT_9:
1167 case EMOTION_EVENT_10:
1168 return;
1169 }
1170 libvlc_media_player_navigate(ev->mp, navigate);
1171}
1172
1173static void
1174em_event_mouse_button_feed(void *video EINA_UNUSED, int button EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED)
1175{
1176 /* FIXME */
1177}
1178
1179static void
1180em_event_mouse_move_feed(void *video EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED)
1181{
1182 /* FIXME */
1183}
1184
1185static int
1186em_video_channel_count(void *video)
1187{
1188 Emotion_LibVLC *ev = video;
1189
1190 if (!libvlc_mp_is_ready(ev)) return -1;
1191
1192 return libvlc_video_get_track_count(ev->mp);
1193}
1194
1195static void
1196em_video_channel_set(void *video,
1197 int channel)
1198{
1199 Emotion_LibVLC *ev = video;
1200
1201 if (!libvlc_mp_is_ready(ev)) return;
1202
1203 if (channel < 0)
1204 libvlc_video_set_track(ev->mp, -1);
1205 else
1206 {
1207 libvlc_media_track_t *track;
1208 track = libvlc_get_track_at_pos(ev, channel, libvlc_track_video);
1209 if (track)
1210 libvlc_video_set_track(ev->mp, track->i_id);
1211 }
1212}
1213
1214static int
1215em_video_channel_get(void *video)
1216{
1217 Emotion_LibVLC *ev = video;
1218 int id;
1219
1220 if (!libvlc_mp_is_ready(ev)) return -1;
1221
1222 id = libvlc_video_get_track(ev->mp);
1223
1224 return id >= 0 ? libvlc_get_track_pos(ev, id, libvlc_track_video) : -1;
1225}
1226
1227static void
1228em_video_subtitle_file_set(void *video,
1229 const char *filepath)
1230{
1231 Emotion_LibVLC *ev = video;
1232
1233 if (!libvlc_mp_is_ready(ev)) return;
1234
1235 free(ev->subtitle_file);
1236 ev->subtitle_file = filepath ? strdup(filepath) : NULL;
1237 libvlc_video_set_subtitle_file(ev->mp, ev->subtitle_file);
1238}
1239
1240static const char *
1241em_video_subtitle_file_get(void *video)
1242{
1243 Emotion_LibVLC *ev = video;
1244
1245 return ev->subtitle_file;
1246}
1247
1248static const char *
1249em_video_channel_name_get(void *video,
1250 int channel)
1251{
1252 Emotion_LibVLC *ev = video;
1253 libvlc_media_track_t *track;
1254
1255 if (!libvlc_mp_is_ready(ev)) return NULL;
1256
1257 track = libvlc_get_track_at_pos(ev, channel, libvlc_track_video);
1258 if (track)
1259 return track->psz_description;
1260 else
1261 return NULL;
1262}
1263
1264static void
1265em_video_channel_mute_set(void *video,
1266 int mute)
1267{
1268 Emotion_LibVLC *ev = video;
1269
1270 ev->video_mute = mute;
1271}
1272
1273static int
1274em_video_channel_mute_get(void *video)
1275{
1276 Emotion_LibVLC *ev = video;
1277
1278 return ev->video_mute;
1279}
1280
1281static int
1282em_channel_count(int vlc_count)
1283{
1284 /* vlc count the -1 track that deactivate the channel for audio and spu */
1285 return vlc_count > 0 ? vlc_count - 1 : vlc_count;
1286}
1287
1288static int
1289em_audio_channel_count(void *video)
1290{
1291 Emotion_LibVLC *ev = video;
1292
1293 if (!libvlc_mp_is_ready(ev)) return -1;
1294
1295 return em_channel_count(libvlc_audio_get_track_count(ev->mp));
1296}
1297
1298static void
1299em_audio_channel_set(void *video,
1300 int channel)
1301{
1302 Emotion_LibVLC *ev = video;
1303
1304 if (!libvlc_mp_is_ready(ev)) return;
1305
1306 if (channel < 0)
1307 libvlc_audio_set_track(ev->mp, -1);
1308 else
1309 {
1310 libvlc_media_track_t *track;
1311 track = libvlc_get_track_at_pos(ev, channel, libvlc_track_audio);
1312 if (track)
1313 libvlc_audio_set_track(ev->mp, track->i_id);
1314 }
1315}
1316
1317static int
1318em_audio_channel_get(void *video)
1319{
1320 Emotion_LibVLC *ev = video;
1321 int id;
1322
1323 if (!libvlc_mp_is_ready(ev)) return -1;
1324
1325 id = libvlc_audio_get_track(ev->mp);
1326
1327 return id >= 0 ? libvlc_get_track_pos(ev, id, libvlc_track_audio) : -1;
1328}
1329
1330static const char *
1331em_audio_channel_name_get(void *video,
1332 int channel)
1333{
1334 Emotion_LibVLC *ev = video;
1335 libvlc_media_track_t *track;
1336
1337 if (!libvlc_mp_is_ready(ev)) return NULL;
1338
1339 track = libvlc_get_track_at_pos(ev, channel, libvlc_track_audio);
1340 if (track)
1341 return track->psz_description;
1342 else
1343 return NULL;
1344}
1345
1346static void
1347em_audio_channel_mute_set(void *video,
1348 int mute)
1349{
1350 Emotion_LibVLC *ev = video;
1351
1352 ev->audio_mute = mute;
1353
1354 if (!libvlc_mp_is_ready(ev)) return;
1355
1356 libvlc_audio_set_mute(ev->mp, mute);
1357}
1358
1359static int
1360em_audio_channel_mute_get(void *video)
1361{
1362 Emotion_LibVLC *ev = video;
1363
1364 if (!libvlc_mp_is_ready(ev))
1365 return ev->audio_mute;
1366
1367 return libvlc_audio_get_mute(ev->mp);
1368}
1369
1370static void
1371em_audio_channel_volume_set(void *video,
1372 double vol)
1373{
1374 Emotion_LibVLC *ev = video;
1375
1376 if (vol < 0.0)
1377 vol = 0.0;
1378 else if (vol > 1.0)
1379 vol = 1.0;
1380 ev->audio_vol = vol * 100;
1381
1382 if (!libvlc_mp_is_ready(ev)) return;
1383
1384 libvlc_audio_set_volume(ev->mp, ev->audio_vol);
1385}
1386
1387static double
1388em_audio_channel_volume_get(void *video)
1389{
1390 Emotion_LibVLC *ev = video;
1391
1392 if (!libvlc_mp_is_ready(ev))
1393 return ev->audio_vol / 100.0;
1394
1395 return libvlc_audio_get_volume(ev->mp) / 100.0;
1396}
1397
1398static int
1399em_spu_channel_count(void *video)
1400{
1401 Emotion_LibVLC *ev = video;
1402
1403 if (!libvlc_mp_is_ready(ev)) return -1;
1404
1405 return em_channel_count(libvlc_video_get_spu_count(ev->mp));
1406}
1407
1408static void
1409em_spu_channel_set(void *video,
1410 int channel)
1411{
1412 Emotion_LibVLC *ev = video;
1413
1414 if (!libvlc_mp_is_ready(ev)) return;
1415
1416 if (channel < 0)
1417 libvlc_video_set_spu(ev->mp, -1);
1418 else
1419 {
1420 libvlc_media_track_t *track;
1421 track = libvlc_get_track_at_pos(ev, channel, libvlc_track_text);
1422 if (track)
1423 libvlc_video_set_spu(ev->mp, track->i_id);
1424 }
1425}
1426
1427static int
1428em_spu_channel_get(void *video)
1429{
1430 Emotion_LibVLC *ev = video;
1431 int id;
1432
1433 if (!libvlc_mp_is_ready(ev)) return -1;
1434
1435 id = libvlc_video_get_spu(ev->mp);
1436
1437 return id >= 0 ? libvlc_get_track_pos(ev, id, libvlc_track_text) : -1;
1438}
1439
1440static const char *
1441em_spu_channel_name_get(void *video,
1442 int channel)
1443{
1444 Emotion_LibVLC *ev = video;
1445 libvlc_media_track_t *track;
1446
1447 if (!libvlc_mp_is_ready(ev)) return NULL;
1448
1449 track = libvlc_get_track_at_pos(ev, channel, libvlc_track_text);
1450 if (track)
1451 return track->psz_description;
1452 else
1453 return NULL;
1454}
1455
1456static void
1457em_spu_channel_mute_set(void *video EINA_UNUSED, int mute EINA_UNUSED)
1458{
1459}
1460
1461static int
1462em_spu_channel_mute_get(void *video EINA_UNUSED)
1463{
1464 return 0;
1465}
1466
1467static int
1468em_chapter_count(void *video)
1469{
1470 Emotion_LibVLC *ev = video;
1471
1472 if (!libvlc_mp_is_ready(ev)) return 0;
1473
1474 return libvlc_media_player_get_chapter_count(ev->mp);
1475}
1476
1477static void
1478em_chapter_set(void *video, int chapter)
1479{
1480 Emotion_LibVLC *ev = video;
1481
1482 if (!libvlc_mp_is_ready(ev)) return;
1483
1484 libvlc_media_player_set_chapter(ev->mp, chapter);
1485}
1486
1487static int
1488em_chapter_get(void *video)
1489{
1490 Emotion_LibVLC *ev = video;
1491
1492 if (!libvlc_mp_is_ready(ev)) return 0;
1493
1494 return libvlc_media_player_get_chapter(ev->mp);
1495}
1496
1497static const char *
1498em_chapter_name_get(void *video, int chapter)
1499{
1500 Emotion_LibVLC *ev = video;
1501
1502 if (!libvlc_mp_is_ready(ev)) return NULL;
1503
1504 if (ev->nb_chapters == 0)
1505 {
1506 ev->nb_chapters =
1507 libvlc_media_player_get_full_chapter_descriptions(ev->mp,
1508 -1,
1509 &ev->chapters);
1510 if (ev->nb_chapters == 0)
1511 ev->nb_chapters = -1;
1512 }
1513 return chapter < ev->nb_chapters ? ev->chapters[chapter]->psz_name : NULL;
1514}
1515
1516static void
1517em_speed_set(void *video, double speed)
1518{
1519 Emotion_LibVLC *ev = video;
1520
1521 if (!libvlc_mp_is_ready(ev)) return;
1522
1523 libvlc_media_player_set_rate(ev->mp, speed);
1524}
1525
1526static double
1527em_speed_get(void *video)
1528{
1529 Emotion_LibVLC *ev = video;
1530
1531 if (!libvlc_mp_is_ready(ev)) return 1.0;
1532
1533 return libvlc_media_player_get_rate(ev->mp);
1534}
1535
1536static int
1537em_eject(void *video EINA_UNUSED)
1538{
1539 return 1;
1540}
1541
1542static const char *
1543em_meta_get(void *video, int meta)
1544{
1545 Emotion_LibVLC *ev = video;
1546
1547 if (!libvlc_mp_is_ready(ev)) return NULL;
1548
1549 if (meta <= 0 || meta >= META_TRACK_COUNT)
1550 return NULL;
1551
1552 if (ev->metas[meta])
1553 return ev->metas[meta];
1554 else
1555 {
1556 libvlc_meta_t vlc_meta;
1557 switch (meta)
1558 {
1559 case META_TRACK_TITLE:
1560 vlc_meta = libvlc_meta_Title;
1561 break;
1562
1563 case META_TRACK_ARTIST:
1564 vlc_meta = libvlc_meta_Artist;
1565 break;
1566
1567 case META_TRACK_ALBUM:
1568 vlc_meta = libvlc_meta_Album;
1569 break;
1570
1571 case META_TRACK_YEAR:
1572 vlc_meta = libvlc_meta_Date;
1573 break;
1574
1575 case META_TRACK_GENRE:
1576 vlc_meta = libvlc_meta_Genre;
1577 break;
1578
1579 case META_TRACK_COMMENT:
1580 vlc_meta = libvlc_meta_Description;
1581 break;
1582
1583 case META_TRACK_DISCID:
1584 vlc_meta = libvlc_meta_TrackID;
1585 break;
1586
1587 default:
1588 return NULL;
1589 break;
1590 }
1591 ev->metas[meta] = libvlc_media_get_meta(ev->m, vlc_meta);
1592
1593 return ev->metas[meta];
1594 }
1595}
1596
1597static const Emotion_Engine em_engine =
1598{
1599 EMOTION_ENGINE_API_VERSION,
1600 EMOTION_ENGINE_PRIORITY_DEFAULT,
1601 "libvlc",
1602 em_add, /* add */
1603 em_del, /* del */
1604 em_file_open, /* file_open */
1605 em_file_close, /* file_close */
1606 em_play, /* play */
1607 em_stop, /* stop */
1608 em_size_get, /* size_get */
1609 em_pos_set, /* pos_set */
1610 em_len_get, /* len_get */
1611 em_buffer_size_get, /* buffer_size_get */
1612 em_fps_num_get, /* fps_num_get */
1613 em_fps_den_get, /* fps_den_get */
1614 em_fps_get, /* fps_get */
1615 em_pos_get, /* pos_get */
1616 em_vis_set, /* vis_set */
1617 em_vis_get, /* vis_get */
1618 em_vis_supported, /* vis_supported */
1619 em_ratio_get, /* ratio_get */
1620 em_video_handled, /* video_handled */
1621 em_audio_handled, /* audio_handled */
1622 em_seekable, /* seekable */
1623 em_frame_done, /* frame_done */
1624 em_format_get, /* format_get */
1625 em_video_data_size_get, /* video_data_size_get */
1626 em_yuv_rows_get, /* yuv_rows_get */
1627 em_bgra_data_get, /* bgra_data_get */
1628 em_event_feed, /* event_feed */
1629 em_event_mouse_button_feed, /* event_mouse_button_feed */
1630 em_event_mouse_move_feed, /* event_mouse_move_feed */
1631 em_video_channel_count, /* video_channel_count */
1632 em_video_channel_set, /* video_channel_set */
1633 em_video_channel_get, /* video_channel_get */
1634 em_video_subtitle_file_set, /* video_subtitle_file_set */
1635 em_video_subtitle_file_get, /* video_subtitle_file_get */
1636 em_video_channel_name_get, /* video_channel_name_get */
1637 em_video_channel_mute_set, /* video_channel_mute_set */
1638 em_video_channel_mute_get, /* video_channel_mute_get */
1639 em_audio_channel_count, /* audio_channel_count */
1640 em_audio_channel_set, /* audio_channel_set */
1641 em_audio_channel_get, /* audio_channel_get */
1642 em_audio_channel_name_get, /* audio_channel_name_get */
1643 em_audio_channel_mute_set, /* audio_channel_mute_set */
1644 em_audio_channel_mute_get, /* audio_channel_mute_get */
1645 em_audio_channel_volume_set, /* audio_channel_volume_set */
1646 em_audio_channel_volume_get, /* audio_channel_volume_get */
1647 em_spu_channel_count, /* spu_channel_count */
1648 em_spu_channel_set, /* spu_channel_set */
1649 em_spu_channel_get, /* spu_channel_get */
1650 em_spu_channel_name_get, /* spu_channel_name_get */
1651 em_spu_channel_mute_set, /* spu_channel_mute_set */
1652 em_spu_channel_mute_get, /* spu_channel_mute_get */
1653 em_chapter_count, /* chapter_count */
1654 em_chapter_set, /* chapter_set */
1655 em_chapter_get, /* chapter_get */
1656 em_chapter_name_get, /* chapter_name_get */
1657 em_speed_set, /* speed_set */
1658 em_speed_get, /* speed_get */
1659 em_eject, /* eject */
1660 em_meta_get, /* meta_get */
1661 NULL, /* priority_set */
1662 NULL /* priority_get */
1663};
1664
1665void
1666libvlc_log(void *data EINA_UNUSED, int level,
1667 const libvlc_log_t *ctx EINA_UNUSED,
1668 const char *fmt, va_list args)
1669{
1670 Eina_Log_Level eina_log_level;
1671 switch (level)
1672 {
1673 case LIBVLC_DEBUG:
1674 eina_log_level = EINA_LOG_LEVEL_DBG;
1675 break;
1676
1677 case LIBVLC_NOTICE:
1678 eina_log_level = EINA_LOG_LEVEL_INFO;
1679 break;
1680
1681 case LIBVLC_WARNING:
1682 eina_log_level = EINA_LOG_LEVEL_WARN;
1683 break;
1684
1685 case LIBVLC_ERROR:
1686 default:
1687 eina_log_level = EINA_LOG_LEVEL_ERR;
1688 break;
1689 }
1690 eina_log_vprint(_emotion_libvlc_log_domain, eina_log_level,
1691 __FILE__, __FUNCTION__, __LINE__, fmt, args);
1692}
1693
1694Eina_Bool
1695libvlc_module_init(void)
1696{
1697 if (libvlc)
1698 {
1699 return EINA_TRUE;
1700 }
1701
1702 if (getenv("EMOTION_FPS_DEBUG")) debug_fps = EINA_TRUE;
1703
1704 eina_threads_init();
1705 eina_log_threads_enable();
1706 _emotion_libvlc_log_domain = eina_log_domain_register
1707 ("emotion-libvlc", EINA_COLOR_ORANGE);
1708 if (_emotion_libvlc_log_domain < 0)
1709 {
1710 EINA_LOG_CRIT("Could not register log domain 'emotion-libvlc'");
1711 return EINA_FALSE;
1712 }
1713
1714 libvlc = libvlc_new(0, NULL);
1715 if (!libvlc)
1716 {
1717 CRI("could not create libvlc instance");
1718 goto error_register;
1719 }
1720 EINA_LOG_INFO("using libvlc: %s", libvlc_get_version());
1721 libvlc_log_set(libvlc, libvlc_log, NULL);
1722
1723 if (!_emotion_module_register(&em_engine))
1724 {
1725 ERR("Could not register module %p", &em_engine);
1726 goto error_register;
1727 }
1728
1729 return EINA_TRUE;
1730
1731error_register:
1732 if (libvlc)
1733 {
1734 libvlc_release(libvlc);
1735 libvlc = NULL;
1736 }
1737 eina_log_domain_unregister(_emotion_libvlc_log_domain);
1738 _emotion_libvlc_log_domain = -1;
1739 return EINA_FALSE;
1740}
1741
1742void
1743libvlc_module_shutdown(void)
1744{
1745 if (!libvlc)
1746 {
1747 EINA_LOG_ERR("too many libvlc_module_shutdown()");
1748 return;
1749 }
1750
1751 _emotion_module_unregister(&em_engine);
1752
1753 libvlc_release(libvlc);
1754 libvlc = NULL;
1755
1756 eina_log_domain_unregister(_emotion_libvlc_log_domain);
1757 _emotion_libvlc_log_domain = -1;
1758}
1759
1760#ifndef EMOTION_STATIC_BUILD_LIBVLC
1761
1762EINA_MODULE_INIT(libvlc_module_init);
1763EINA_MODULE_SHUTDOWN(libvlc_module_shutdown);
1764
1765#endif