summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2020-03-03 20:38:58 +0000
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2020-03-08 12:36:01 +0000
commit075bab83c4288b5de20f6acfc6b0459656ea85e0 (patch)
tree4932d355352761d3cde0d4f3750defb7034bc65d
parent0dcbc26a5a974c76d5db5c6c59652f1ae7c4fb9f (diff)
remove vlc, gst-0.10, xine deps, modules as they are broken
they dont work. easier to remove than fix, so... remove :) only gst 1.x supported now.
-rwxr-xr-x.ci/ci-configure.sh11
-rwxr-xr-x.ci/ubuntu-bionic-install-deps.sh2
-rw-r--r--meson.build3
-rw-r--r--meson_options.txt16
-rw-r--r--src/generic/emotion/meson.build8
-rw-r--r--src/generic/emotion/vlc/emotion_generic_vlc.c789
-rw-r--r--src/generic/emotion/vlc/meson.build8
-rw-r--r--src/generic/evas/meson.build10
-rw-r--r--src/modules/emotion/generic/Emotion_Generic_Plugin.h148
-rw-r--r--src/modules/emotion/generic/README79
-rw-r--r--src/modules/emotion/generic/emotion_generic.c1908
-rw-r--r--src/modules/emotion/generic/emotion_generic.h123
-rw-r--r--src/modules/emotion/generic/meson.build24
-rw-r--r--src/modules/emotion/libvlc/emotion_libvlc.c1555
-rw-r--r--src/modules/emotion/libvlc/meson.build14
-rw-r--r--src/modules/emotion/meson.build12
-rw-r--r--src/modules/emotion/xine/emotion_xine.c1707
-rw-r--r--src/modules/emotion/xine/emotion_xine.h118
-rw-r--r--src/modules/emotion/xine/emotion_xine_vo_out.c766
-rw-r--r--src/modules/emotion/xine/meson.build16
20 files changed, 14 insertions, 7303 deletions
diff --git a/.ci/ci-configure.sh b/.ci/ci-configure.sh
index 773e536aa1..cd7f9eb889 100755
--- a/.ci/ci-configure.sh
+++ b/.ci/ci-configure.sh
@@ -13,12 +13,11 @@ if [ "$DISTRO" != "" ] ; then
13 13
14 # TODO: 14 # TODO:
15 # - No libelogind package in fedora 30 repo 15 # - No libelogind package in fedora 30 repo
16 # - RPM fusion repo for xine and libvlc
17 # - Ibus 16 # - Ibus
18 ENABLED_LINUX_COPTS=" -Dfb=true -Dsdl=true -Dbuffer=true -Dbuild-id=travis-build \ 17 ENABLED_LINUX_COPTS=" -Dfb=true -Dsdl=true -Dbuffer=true -Dbuild-id=travis-build \
19 -Ddebug-threads=true -Dglib=true -Dg-mainloop=true -Dxpresent=true -Dxinput22=true \ 18 -Ddebug-threads=true -Dglib=true -Dg-mainloop=true -Dxpresent=true -Dxinput22=true \
20 -Devas-loaders-disabler=json -Decore-imf-loaders-disabler= -Demotion-loaders-disabler=libvlc,xine \ 19 -Devas-loaders-disabler=json -Decore-imf-loaders-disabler= \
21 -Demotion-generic-loaders-disabler=vlc -Dharfbuzz=true -Dpixman=true -Dhyphen=true \ 20 -Dharfbuzz=true -Dpixman=true -Dhyphen=true \
22 -Dvnc-server=true -Dbindings=luajit,cxx,mono -Delogind=false -Dinstall-eo-files=true -Dphysics=true" 21 -Dvnc-server=true -Dbindings=luajit,cxx,mono -Delogind=false -Dinstall-eo-files=true -Dphysics=true"
23 22
24 # Enabled png, jpeg evas loader for in tree edje file builds 23 # Enabled png, jpeg evas loader for in tree edje file builds
@@ -27,8 +26,8 @@ if [ "$DISTRO" != "" ] ; then
27 -Dcrypto=gnutls -Dglib=false -Dgstreamer=false -Dsystemd=false -Dpulseaudio=false \ 26 -Dcrypto=gnutls -Dglib=false -Dgstreamer=false -Dsystemd=false -Dpulseaudio=false \
28 -Dnetwork-backend=connman -Dxinput2=false -Dtslib=false \ 27 -Dnetwork-backend=connman -Dxinput2=false -Dtslib=false \
29 -Devas-loaders-disabler=gst,pdf,ps,raw,svg,xcf,bmp,dds,eet,generic,gif,ico,jp2k,json,pmaps,psd,tga,tgv,tiff,wbmp,webp,xpm \ 28 -Devas-loaders-disabler=gst,pdf,ps,raw,svg,xcf,bmp,dds,eet,generic,gif,ico,jp2k,json,pmaps,psd,tga,tgv,tiff,wbmp,webp,xpm \
30 -Decore-imf-loaders-disabler=xim,ibus,scim -Demotion-loaders-disabler=gstreamer1,libvlc,xine \ 29 -Decore-imf-loaders-disabler=xim,ibus,scim \
31 -Demotion-generic-loaders-disabler=vlc -Dfribidi=false -Dfontconfig=false \ 30 -Dfribidi=false -Dfontconfig=false \
32 -Dedje-sound-and-video=false -Dembedded-lz4=false -Dlibmount=false -Dv4l2=false \ 31 -Dedje-sound-and-video=false -Dembedded-lz4=false -Dlibmount=false -Dv4l2=false \
33 -Delua=true -Dnls=false -Dbindings= -Dlua-interpreter=luajit -Dnative-arch-optimization=false" 32 -Delua=true -Dnls=false -Dbindings= -Dlua-interpreter=luajit -Dnative-arch-optimization=false"
34 #evas_filter_parser.c:(.text+0xc59): undefined reference to `lua_getglobal' with interpreter lua 33 #evas_filter_parser.c:(.text+0xc59): undefined reference to `lua_getglobal' with interpreter lua
@@ -98,7 +97,7 @@ elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
98 export PKG_CONFIG_PATH="/usr/local/opt/openssl/lib/pkgconfig:/usr/local/Cellar/libffi/$LIBFFI_VER/lib/pkgconfig" 97 export PKG_CONFIG_PATH="/usr/local/opt/openssl/lib/pkgconfig:/usr/local/Cellar/libffi/$LIBFFI_VER/lib/pkgconfig"
99 export CC="ccache gcc" 98 export CC="ccache gcc"
100 travis_fold meson meson 99 travis_fold meson meson
101 mkdir build && meson build -Dopengl=full -Decore-imf-loaders-disabler=scim,ibus -Dx11=false -Davahi=false -Deeze=false -Dsystemd=false -Dnls=false -Dcocoa=true -Demotion-loaders-disabler=gstreamer1,libvlc,xine 100 mkdir build && meson build -Dopengl=full -Decore-imf-loaders-disabler=scim,ibus -Dx11=false -Davahi=false -Deeze=false -Dsystemd=false -Dnls=false -Dcocoa=true -Dgstreamer=false
102 travis_endfold meson 101 travis_endfold meson
103else 102else
104 travis_fold meson meson 103 travis_fold meson meson
diff --git a/.ci/ubuntu-bionic-install-deps.sh b/.ci/ubuntu-bionic-install-deps.sh
index 998e74b084..9eefa7d7fc 100755
--- a/.ci/ubuntu-bionic-install-deps.sh
+++ b/.ci/ubuntu-bionic-install-deps.sh
@@ -1,4 +1,4 @@
1#!/bin/sh 1#!/bin/sh
2sudo apt-get update -y 2sudo apt-get update -y
3sudo apt-get install -y build-essential autoconf automake autopoint doxygen check luajit libharfbuzz-dev libpng-dev libudev-dev libwebp-dev libssl-dev libluajit-5.1-dev libfribidi-dev libcogl-gles2-dev libgif-dev libtiff5-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libdbus-1-dev libmount-dev libblkid-dev libpulse-dev libxrandr-dev libxtst-dev libxcursor-dev libxcomposite-dev libxinerama-dev libxkbfile-dev libbullet-dev libvlc-dev libsndfile1-dev libraw-dev libspectre-dev libpoppler-cpp-dev libpam0g-dev liblz4-dev faenza-icon-theme gettext git imagemagick libasound2-dev libbluetooth-dev libfontconfig1-dev libfreetype6-dev libibus-1.0-dev libiconv-hook-dev libjpeg-dev libjpeg-turbo8-dev libpoppler-dev libpoppler-private-dev libproxy-dev librsvg2-dev libscim-dev libsystemd-dev libtool libudisks2-dev libunibreak-dev libxcb-keysyms1-dev libxine2-dev libxss-dev linux-tools-common libcurl4-openssl-dev systemd ccache git binutils-gold python3-pip ninja-build dbus-x11 libavahi-client-dev python3-setuptools libopenjp2-7-dev 3sudo apt-get install -y build-essential autoconf automake autopoint doxygen check luajit libharfbuzz-dev libpng-dev libudev-dev libwebp-dev libssl-dev libluajit-5.1-dev libfribidi-dev libcogl-gles2-dev libgif-dev libtiff5-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libdbus-1-dev libmount-dev libblkid-dev libpulse-dev libxrandr-dev libxtst-dev libxcursor-dev libxcomposite-dev libxinerama-dev libxkbfile-dev libbullet-dev libsndfile1-dev libraw-dev libspectre-dev libpoppler-cpp-dev libpam0g-dev liblz4-dev faenza-icon-theme gettext git imagemagick libasound2-dev libbluetooth-dev libfontconfig1-dev libfreetype6-dev libibus-1.0-dev libiconv-hook-dev libjpeg-dev libjpeg-turbo8-dev libpoppler-dev libpoppler-private-dev libproxy-dev librsvg2-dev libscim-dev libsystemd-dev libtool libudisks2-dev libunibreak-dev libxcb-keysyms1-dev libxss-dev linux-tools-common libcurl4-openssl-dev systemd ccache git binutils-gold python3-pip ninja-build dbus-x11 libavahi-client-dev python3-setuptools libopenjp2-7-dev
4sudo pip3 install meson 4sudo pip3 install meson
diff --git a/meson.build b/meson.build
index fb77c43570..256256d8a8 100644
--- a/meson.build
+++ b/meson.build
@@ -456,9 +456,6 @@ endforeach
456subdir(join_paths('src', 'bin', 'efl')) 456subdir(join_paths('src', 'bin', 'efl'))
457 457
458subdir(join_paths('src', 'generic', 'evas')) 458subdir(join_paths('src', 'generic', 'evas'))
459if sys_windows == false
460 subdir(join_paths('src', 'generic', 'emotion'))
461endif
462subdir('cmakeconfig') 459subdir('cmakeconfig')
463subdir(join_paths('src', 'bindings')) 460subdir(join_paths('src', 'bindings'))
464subdir(join_paths('src', 'edje_external')) 461subdir(join_paths('src', 'edje_external'))
diff --git a/meson_options.txt b/meson_options.txt
index 2c6d138981..0907aff980 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -122,7 +122,7 @@ option('g-mainloop',
122option('gstreamer', 122option('gstreamer',
123 type : 'boolean', 123 type : 'boolean',
124 value : true, 124 value : true,
125 description : 'GStreamer 1.0+ support in efl' 125 description : 'GStreamer support in efl'
126) 126)
127 127
128option('systemd', 128option('systemd',
@@ -200,20 +200,6 @@ option('ecore-imf-loaders-disabler',
200 value : ['ibus'] 200 value : ['ibus']
201) 201)
202 202
203option('emotion-loaders-disabler',
204 type : 'array',
205 description : 'List of video back-ends to disable in efl',
206 choices : ['gstreamer1', 'libvlc', 'xine'],
207 value : ['libvlc', 'xine']
208)
209
210option('emotion-generic-loaders-disabler',
211 type : 'array',
212 description : 'List of out-of-process generic binary video loaders to disable in efl',
213 choices : ['vlc'],
214 value : ['vlc']
215)
216
217option('harfbuzz', 203option('harfbuzz',
218 type : 'boolean', 204 type : 'boolean',
219 value : true, 205 value : true,
diff --git a/src/generic/emotion/meson.build b/src/generic/emotion/meson.build
deleted file mode 100644
index 58cd5294aa..0000000000
--- a/src/generic/emotion/meson.build
+++ /dev/null
@@ -1,8 +0,0 @@
1generic_loaders = ['vlc']
2
3foreach loader : generic_loaders
4 if get_option('emotion-generic-loaders-disabler').contains(loader) == false
5 subdir(loader)
6 endif
7endforeach
8
diff --git a/src/generic/emotion/vlc/emotion_generic_vlc.c b/src/generic/emotion/vlc/emotion_generic_vlc.c
deleted file mode 100644
index dcfcbe9e8c..0000000000
--- a/src/generic/emotion/vlc/emotion_generic_vlc.c
+++ /dev/null
@@ -1,789 +0,0 @@
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/stat.h>
12#include <fcntl.h>
13#include <pthread.h>
14#include <poll.h>
15
16#include <signal.h>
17
18#include <vlc/vlc.h>
19
20#include <Emotion_Generic_Plugin.h>
21#include <Eina.h>
22#include <Ecore.h>
23
24static int _em_vlc_log_dom = -1;
25#define ERR(...) EINA_LOG_DOM_ERR(_em_vlc_log_dom, __VA_ARGS__)
26#define DBG(...) EINA_LOG_DOM_DBG(_em_vlc_log_dom, __VA_ARGS__)
27#define INF(...) EINA_LOG_DOM_INFO(_em_vlc_log_dom, __VA_ARGS__)
28#define WRN(...) EINA_LOG_DOM_WARN(_em_vlc_log_dom, __VA_ARGS__)
29#define CRIT(...) EINA_LOG_DOM_CRIT(_em_vlc_log_dom, __VA_ARGS__)
30
31
32typedef struct _App App;
33struct _App {
34 Emotion_Generic_Video_Shared *vs;
35 Emotion_Generic_Video_Frame vf;
36
37 libvlc_instance_t *libvlc;
38 libvlc_media_t *m;
39 libvlc_media_player_t *mp;
40 libvlc_event_manager_t *event_mgr;
41
42 Ecore_Pipe *fd_read; // read commands from emotion here
43 Ecore_Pipe *fd_write; // write commands for emotion here
44 Eina_Lock cmd_mutex;// lock used to send just one command at a time
45 int last_order; // current command received from emotion
46
47 char *filename;
48 char *subtitle_path;
49 char *shmname;
50 unsigned w, h;
51 int volume;
52 Eina_Bool audio_muted;
53
54 Eina_Bool opening;
55 Eina_Bool closing;
56 Eina_Bool playing;
57 Eina_Bool inited;
58};
59
60static void _player_setup(App *app);
61
62
63/* Utilities to send commands back to emotion */
64#define SEND_CMD_PARAM(app, i) \
65 if ((app)->fd_write) \
66 if (!ecore_pipe_write((app)->fd_write, &(i), sizeof((i)))) \
67 ecore_main_loop_quit();
68
69static void
70_send_cmd(App *app, int cmd)
71{
72 if (!app->fd_write)
73 return;
74
75 eina_lock_take(&app->cmd_mutex); /* LOCK HERE */
76
77 if (!ecore_pipe_write(app->fd_write, &cmd, sizeof(cmd)))
78 ecore_main_loop_quit();
79}
80
81static void
82_send_cmd_str(App *app, const char *str)
83{
84 int len;
85
86 len = str ? strlen(str) + 1 : 0;
87 if (app->fd_write)
88 if (!ecore_pipe_write(app->fd_write, &len, sizeof(len)))
89 ecore_main_loop_quit();
90 if (app->fd_write)
91 if (!ecore_pipe_write(app->fd_write, str, len))
92 ecore_main_loop_quit();
93}
94
95static void
96_send_cmd_finish(App *app)
97{
98 eina_lock_release(&app->cmd_mutex); /* UNLOCK HERE */
99}
100
101/* Commands sent to the emotion pipe */
102static void
103_send_file_closed(App *app)
104{
105 _send_cmd(app, EM_RESULT_FILE_CLOSE);
106 _send_cmd_finish(app);
107}
108
109static void
110_send_time_changed(App *app)
111{
112 float new_time;
113
114 if (app->vs->frame_drop > 1)
115 return;
116
117 new_time = libvlc_media_player_get_time(app->mp);
118 new_time /= 1000;
119 _send_cmd(app, EM_RESULT_POSITION_CHANGED);
120 SEND_CMD_PARAM(app, new_time);
121 _send_cmd_finish(app);
122}
123
124static void
125_send_resize(App *app, int width, int height)
126{
127 _send_cmd(app, EM_RESULT_FRAME_SIZE);
128 SEND_CMD_PARAM(app, width);
129 SEND_CMD_PARAM(app, height);
130 _send_cmd_finish(app);
131}
132
133static void
134_send_track_info(App *app, int cmd, int current, int count, libvlc_track_description_t *desc)
135{
136 _send_cmd(app, cmd);
137 SEND_CMD_PARAM(app, current);
138 SEND_CMD_PARAM(app, count);
139 while (desc)
140 {
141 int tid = desc->i_id;
142 const char *name = desc->psz_name;
143 SEND_CMD_PARAM(app, tid);
144 _send_cmd_str(app, name);
145 desc = desc->p_next;
146 }
147 _send_cmd_finish(app);
148}
149
150static void
151_send_all_track_info(App *app)
152{
153 int track_count, current;
154 libvlc_track_description_t *desc;
155
156 current = libvlc_audio_get_track(app->mp);
157 track_count = libvlc_audio_get_track_count(app->mp);
158 desc = libvlc_audio_get_track_description(app->mp);
159
160 _send_track_info(app, EM_RESULT_AUDIO_TRACK_INFO,
161 current, track_count, desc);
162
163 current = libvlc_video_get_track(app->mp);
164 track_count = libvlc_video_get_track_count(app->mp);
165 desc = libvlc_video_get_track_description(app->mp);
166
167 _send_track_info(app, EM_RESULT_VIDEO_TRACK_INFO,
168 current, track_count, desc);
169
170 current = libvlc_video_get_spu(app->mp);
171 track_count = libvlc_video_get_spu_count(app->mp);
172 desc = libvlc_video_get_spu_description(app->mp);
173
174 _send_track_info(app, EM_RESULT_SPU_TRACK_INFO,
175 current, track_count, desc);
176}
177
178static void
179_send_all_meta_info(App *app)
180{
181 const char *meta;
182
183 _send_cmd(app, EM_RESULT_META_INFO);
184
185 /*
186 * Will send in this order: title, artist, album, year,
187 * genre, comments, disc id and track count.
188 */
189 meta = libvlc_media_get_meta(app->m, libvlc_meta_Title);
190 _send_cmd_str(app, meta);
191 meta = libvlc_media_get_meta(app->m, libvlc_meta_Artist);
192 _send_cmd_str(app, meta);
193 meta = libvlc_media_get_meta(app->m, libvlc_meta_Album);
194 _send_cmd_str(app, meta);
195 meta = libvlc_media_get_meta(app->m, libvlc_meta_Date);
196 _send_cmd_str(app, meta);
197 meta = libvlc_media_get_meta(app->m, libvlc_meta_Genre);
198 _send_cmd_str(app, meta);
199 meta = NULL; // sending empty comments
200 _send_cmd_str(app, meta);
201 meta = NULL; // sending empty disc id
202 _send_cmd_str(app, meta);
203 meta = libvlc_media_get_meta(app->m, libvlc_meta_TrackNumber);
204 _send_cmd_str(app, meta);
205
206 _send_cmd_finish(app);
207}
208
209static void
210_send_length_changed(App *app)
211{
212 float length = libvlc_media_player_get_length(app->mp);
213
214 length /= 1000;
215 _send_cmd(app, EM_RESULT_LENGTH_CHANGED);
216 SEND_CMD_PARAM(app, length);
217 _send_cmd_finish(app);
218}
219
220static void
221_send_seekable_changed(App *app, const struct libvlc_event_t *ev)
222{
223 int seekable = ev->u.media_player_seekable_changed.new_seekable;
224
225 _send_cmd(app, EM_RESULT_SEEKABLE_CHANGED);
226 SEND_CMD_PARAM(app, seekable);
227 _send_cmd_finish(app);
228}
229
230static void
231_send_playback_started(App *app)
232{
233 _send_cmd(app, EM_RESULT_PLAYBACK_STARTED);
234 _send_cmd_finish(app);
235}
236
237static void
238_send_playback_stopped(App *app)
239{
240 _send_cmd(app, EM_RESULT_PLAYBACK_STOPPED);
241 _send_cmd_finish(app);
242}
243
244static void
245_send_init(App *app)
246{
247 _send_cmd(app, EM_RESULT_INIT);
248 _send_cmd_finish(app);
249}
250
251static void
252_send_file_set(App *app)
253{
254 _send_cmd(app, EM_RESULT_FILE_SET);
255 _send_cmd_finish(app);
256}
257
258static void
259_send_file_set_done(App *app, int success)
260{
261 _send_cmd(app, EM_RESULT_FILE_SET_DONE);
262 SEND_CMD_PARAM(app, success);
263 _send_cmd_finish(app);
264}
265
266
267/* VLC events and callbacks */
268static void
269_event_cb(const struct libvlc_event_t *ev, void *data)
270{
271 App *app = data;
272
273 ecore_thread_main_loop_begin();
274 switch (ev->type)
275 {
276 case libvlc_MediaPlayerTimeChanged:
277 // DBG("libvlc_MediaPlayerTimeChanged");
278 _send_time_changed(app);
279 break;
280 case libvlc_MediaPlayerLengthChanged:
281 DBG("libvlc_MediaPlayerLengthChanged");
282 _send_length_changed(app);
283 break;
284 case libvlc_MediaPlayerSeekableChanged:
285 DBG("libvlc_MediaPlayerSeekableChanged");
286 _send_seekable_changed(app, ev);
287 break;
288 case libvlc_MediaPlayerPlaying:
289 DBG("libvlc_MediaPlayerPlaying");
290 libvlc_audio_set_volume(app->mp, app->volume);
291 libvlc_audio_set_mute(app->mp, app->audio_muted);
292 _send_playback_started(app);
293 break;
294 case libvlc_MediaPlayerStopped:
295 DBG("libvlc_MediaPlayerStopped");
296 _send_playback_stopped(app);
297 if (app->closing)
298 {
299 free(app->filename);
300 app->filename = NULL;
301 free(app->subtitle_path);
302 app->subtitle_path = NULL;
303 libvlc_media_release(app->m);
304 app->m = NULL;
305 libvlc_media_player_release(app->mp);
306 app->mp = NULL;
307 emotion_generic_shm_free(app->vs);
308 app->playing = EINA_FALSE;
309 app->closing = EINA_FALSE;
310 _send_file_closed(app);
311 }
312 break;
313 case libvlc_MediaPlayerEndReached:
314 DBG("libvlc_MediaPlayerEndReached");
315 app->playing = EINA_FALSE;
316 /* vlc had released the media_playere here, we create a new one */
317 app->mp = libvlc_media_player_new_from_media(app->m);
318 _player_setup(app);
319 _send_playback_stopped(app);
320 break;
321 }
322 ecore_thread_main_loop_end();
323}
324
325static void
326_tmp_playing_event_cb(const struct libvlc_event_t *ev, void *data)
327{
328 App *app = data;
329
330 if (ev->type != libvlc_MediaPlayerPlaying)
331 return;
332
333 /* pause and stop listening the temporary event */
334 libvlc_event_detach(app->event_mgr,libvlc_MediaPlayerPlaying,
335 _tmp_playing_event_cb, app);
336 libvlc_media_player_set_pause(app->mp, 1);
337
338 /* sending size info */
339 libvlc_video_get_size(app->mp, 0, &app->w, &app->h);
340 _send_resize(app, app->w, app->h);
341
342 /* sending total lenght */
343 _send_length_changed(app);
344
345 /* sending audio track info */
346 _send_all_track_info(app);
347
348 /* sending meta info */
349 _send_all_meta_info(app);
350
351 /* ok, we are done! Now let emotion create the shmem for us */
352 _send_file_set(app);
353}
354
355static void *
356_lock(void *data, void **pixels)
357{
358 App *app = data;
359
360 if (app->playing)
361 *pixels = app->vf.frames[app->vs->frame.player];
362 else
363 *pixels = NULL;
364
365 return NULL; // picture identifier, not needed here
366}
367
368static void
369_unlock(void *data EINA_UNUSED, void *id EINA_UNUSED, void *const *pixels EINA_UNUSED)
370{
371}
372
373static void
374_display(void *data, void *id EINA_UNUSED)
375{
376 App *app = data;
377
378 if (!app->playing)
379 return;
380
381 eina_semaphore_lock(&app->vs->lock);
382 app->vs->frame.last = app->vs->frame.player;
383 app->vs->frame.player = app->vs->frame.next;
384 app->vs->frame.next = app->vs->frame.last;
385 if (!app->vs->frame_drop++)
386 {
387 _send_cmd(app, EM_RESULT_FRAME_NEW);
388 _send_cmd_finish(app);
389 }
390 eina_semaphore_release(&app->vs->lock, 1);
391}
392
393static void
394_player_setup(App *app)
395{
396
397 libvlc_video_set_format(app->mp, "RV32", app->w, app->h, app->w * 4);
398 libvlc_video_set_callbacks(app->mp, _lock, _unlock, _display, app);
399
400 app->event_mgr = libvlc_media_player_event_manager(app->mp);
401 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPlaying,
402 _event_cb, app);
403 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerTimeChanged,
404 _event_cb, app);
405 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerLengthChanged,
406 _event_cb, app);
407 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerSeekableChanged,
408 _event_cb, app);
409 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerEndReached,
410 _event_cb, app);
411 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerStopped,
412 _event_cb, app);
413}
414
415/* Commands received from the emotion pipe */
416static void
417_file_set(App *app)
418{
419 DBG("Path: %s", app->filename);
420 app->m = libvlc_media_new_path(app->libvlc, app->filename);
421 if (!app->m)
422 {
423 ERR("could not open path: \"%s\"", app->filename);
424 return;
425 }
426
427 app->mp = libvlc_media_player_new_from_media(app->m);
428 if (!app->mp)
429 {
430 ERR("could not create new player from media.");
431 return;
432 }
433
434 app->opening = EINA_TRUE;
435
436 /* Here we start playing and connect a temporary callback to know when
437 * the file is parsed and ready to be played for real.
438 */
439 app->event_mgr = libvlc_media_player_event_manager(app->mp);
440 libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPlaying,
441 _tmp_playing_event_cb, app);
442
443 libvlc_media_player_play(app->mp);
444}
445
446static void
447_file_set_done(App *app)
448{
449 int r;
450
451 DBG("Path: %s", app->filename);
452 app->opening = EINA_FALSE;
453
454 r = emotion_generic_shm_get(app->shmname, &app->vs, &app->vf);
455 if (!r)
456 {
457 free(app->filename);
458 libvlc_media_release(app->m);
459 libvlc_media_player_release(app->mp);
460 app->filename = NULL;
461 app->m = NULL;
462 app->mp = NULL;
463 }
464 else
465 {
466 _player_setup(app);
467 }
468
469 _send_file_set_done(app, r);
470}
471
472static void
473_file_close(App *app)
474{
475 DBG("closing file");
476
477 if (!app->mp)
478 return;
479
480 app->closing = EINA_TRUE;
481 libvlc_media_player_stop(app->mp);
482}
483
484static void
485_stop(App *app)
486{
487 DBG("Stop");
488 if (app->mp)
489 libvlc_media_player_set_pause(app->mp, 1);
490}
491
492static void
493_play(App *app, float pos)
494{
495 DBG("Play at %.3f", pos);
496
497 if (!app->mp)
498 return;
499
500 if (app->playing)
501 {
502 libvlc_media_player_set_pause(app->mp, 0);
503 }
504 else
505 {
506 libvlc_time_t new_time = pos * 1000;
507 libvlc_media_player_set_time(app->mp, new_time);
508 libvlc_media_player_play(app->mp);
509
510 if (app->subtitle_path)
511 libvlc_video_set_subtitle_file(app->mp, app->subtitle_path);
512
513 app->playing = EINA_TRUE;
514 }
515}
516
517static void
518_position_set(App *app, float position)
519{
520 libvlc_time_t new_time;
521
522 DBG("Position set %.3f", position);
523 if (!app->mp)
524 return;
525
526 new_time = position * 1000;
527 libvlc_media_player_set_time(app->mp, new_time);
528
529 if (libvlc_media_player_get_state(app->mp) == libvlc_Paused)
530 _send_time_changed(app);
531}
532
533static void
534_speed_set(App *app, float rate)
535{
536 DBG("Speed set %.3f", rate);
537 if (!app->mp)
538 return;
539
540 libvlc_media_player_set_rate(app->mp, rate);
541}
542
543static void
544_mute_set(App *app, int mute)
545{
546 DBG("Mute %d", mute);
547 if (!app->mp)
548 return;
549
550 app->audio_muted = mute;
551 libvlc_audio_set_mute(app->mp, mute);
552}
553
554static void
555_volume_set(App *app, float volume)
556{
557 DBG("Volume set %.2f", volume);
558 if (!app->mp)
559 return;
560
561 app->volume = volume * 100;
562 libvlc_audio_set_volume(app->mp, app->volume);
563}
564
565static void
566_spu_track_set(App *app, int track)
567{
568 DBG("SPU track %d", track);
569 libvlc_video_set_spu(app->mp, track);
570}
571
572static void
573_audio_track_set(App *app, int track)
574{
575 DBG("Audio track %d", track);
576 libvlc_audio_set_track(app->mp, track);
577}
578
579static void
580_video_track_set(App *app, int track)
581{
582 DBG("Video Track %d", track);
583 libvlc_video_set_track(app->mp, track);
584}
585
586static void
587_remote_command(void *data, void *buffer, unsigned int nbyte)
588{
589 App *app = data;
590
591 if (nbyte == 0)
592 {
593 ecore_main_loop_quit();
594 return ;
595 }
596
597 if (app->last_order == EM_CMD_LAST)
598 {
599 if (nbyte != sizeof (int))
600 {
601 ERR("didn't receive a valid command from emotion (%i) !", nbyte);
602 ecore_main_loop_quit();
603 return ;
604 }
605
606 app->last_order = *((int*) buffer);
607
608 if (!app->inited &&
609 app->last_order != EM_CMD_INIT)
610 {
611 ERR("wrong init command!");
612 ecore_main_loop_quit();
613 return ;
614 }
615
616 switch (app->last_order)
617 {
618 case EM_CMD_FILE_SET:
619 if (app->opening)
620 {
621 libvlc_media_release(app->m);
622 libvlc_media_player_release(app->mp);
623 free(app->filename);
624 app->opening = EINA_FALSE;
625 }
626 break;
627 case EM_CMD_FILE_SET_DONE:
628 _file_set_done(app);
629 app->last_order = EM_CMD_LAST;
630 break;
631 case EM_CMD_FILE_CLOSE:
632 _file_close(app);
633 app->last_order = EM_CMD_LAST;
634 break;
635 case EM_CMD_STOP:
636 _stop(app);
637 app->last_order = EM_CMD_LAST;
638 break;
639 }
640 }
641 else
642 {
643 switch (app->last_order)
644 {
645 case EM_CMD_INIT:
646 app->shmname = strdup(buffer);
647 app->inited = EINA_TRUE;
648 _send_init(app);
649 break;
650 case EM_CMD_FILE_SET:
651 app->filename = strdup(buffer);
652 _file_set(app);
653 break;
654 case EM_CMD_SUBTITLE_SET:
655 app->subtitle_path = strdup(buffer);
656 break;
657 case EM_CMD_PLAY:
658 _play(app, *(float*) buffer);
659 break;
660 case EM_CMD_POSITION_SET:
661 _position_set(app, *(float*) buffer);
662 break;
663 case EM_CMD_SPEED_SET:
664 _speed_set(app, *(float*) buffer);
665 break;
666 case EM_CMD_AUDIO_MUTE_SET:
667 _mute_set(app, *(int*) buffer);
668 break;
669 case EM_CMD_VOLUME_SET:
670 _volume_set(app, *(float*) buffer);
671 break;
672 case EM_CMD_SPU_TRACK_SET:
673 _spu_track_set(app, *(int*) buffer);
674 break;
675 case EM_CMD_AUDIO_TRACK_SET:
676 _audio_track_set(app, *(int*) buffer);
677 break;
678 case EM_CMD_VIDEO_TRACK_SET:
679 _video_track_set(app, *(int*) buffer);
680 break;
681 }
682 app->last_order = EM_CMD_LAST;
683 }
684}
685
686static void
687_dummy(void *data EINA_UNUSED, void *buffer EINA_UNUSED, unsigned int nbyte EINA_UNUSED)
688{
689 /* This function is useless for the pipe we use to send message back
690 to emotion, but still needed */
691}
692
693/* Main */
694static Eina_Bool
695exit_func(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev EINA_UNUSED)
696{
697 DBG("Quit signal received !");
698 ecore_main_loop_quit();
699 return EINA_TRUE;
700}
701
702int
703main(int argc, const char *argv[])
704{
705 App app;
706 Ecore_Event_Handler *hld;
707 int vlc_argc;
708
709 const char *vlc_argv[] =
710 {
711 "--quiet",
712 "--intf", "dummy", /* no interface */
713 "--vout", "dummy", /* we don't want video (output) */
714 "--no-video-title-show", /* nor the filename displayed */
715 "--no-sub-autodetect-file", /* we don't want automatic subtitles */
716 "--no-stats", /* no stats */
717 "--no-inhibit", /* we don't want interfaces */
718 "--no-disable-screensaver", /* we don't want interfaces */
719// XXX: causes newer vlcs to segv!
720// "--codec", "avcodec",
721// XXX: disable this just in case
722// "--demux", "avformat"
723 };
724 vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);
725
726 memset(&app, 0, sizeof(app));
727 if (!eina_init())
728 {
729 EINA_LOG_CRIT("Can't initialize generic vlc player, eina failed.");
730 return -1;
731 }
732
733 _em_vlc_log_dom = eina_log_domain_register("emotion_generic_vlc",
734 EINA_COLOR_CYAN);
735 if (_em_vlc_log_dom < 0)
736 {
737 EINA_LOG_CRIT("Unable to register emotion_generic_vlc log domain.");
738 goto error;
739 }
740
741 if (!eina_log_domain_level_check(_em_vlc_log_dom, EINA_LOG_LEVEL_WARN))
742 eina_log_domain_level_set("emotion_generic_vlc", EINA_LOG_LEVEL_WARN);
743
744 if (argc < 3)
745 {
746 ERR("missing parameters.");
747 ERR("syntax:\n\t%s <fd read> <fd write>", argv[0]);
748 goto error;
749 }
750
751 ecore_init();
752
753 eina_lock_new(&app.cmd_mutex);
754
755 app.fd_read = ecore_pipe_full_add(_remote_command, &app,
756 atoi(argv[1]), -1, EINA_FALSE, EINA_FALSE);
757 app.fd_write = ecore_pipe_full_add(_dummy, NULL,
758 -1, atoi(argv[2]), EINA_FALSE, EINA_FALSE);
759
760 hld = ecore_event_handler_add(ECORE_EVENT_SIGNAL_HUP, exit_func, NULL);
761
762 app.libvlc = libvlc_new(vlc_argc, vlc_argv);
763 app.mp = NULL;
764 app.filename = NULL;
765 app.subtitle_path = NULL;
766 app.w = 0;
767 app.h = 0;
768 app.opening = EINA_FALSE;
769 app.playing = EINA_FALSE;
770 app.inited = EINA_FALSE;
771 app.last_order = EM_CMD_LAST;
772
773 ecore_main_loop_begin();
774
775 libvlc_release(app.libvlc);
776 ecore_pipe_del(app.fd_read);
777 ecore_pipe_del(app.fd_write);
778 ecore_event_handler_del(hld);
779 eina_lock_free(&app.cmd_mutex);
780
781 ecore_shutdown();
782 eina_shutdown();
783 return 0;
784
785 error:
786 eina_shutdown();
787 return -1;
788}
789#undef SEND_CMD_PARAM
diff --git a/src/generic/emotion/vlc/meson.build b/src/generic/emotion/vlc/meson.build
deleted file mode 100644
index b21f4a16df..0000000000
--- a/src/generic/emotion/vlc/meson.build
+++ /dev/null
@@ -1,8 +0,0 @@
1vlc = dependency('libvlc')
2
3executable('vlc',
4 'emotion_generic_vlc.c',
5 dependencies: [emotion_generic, eina, ecore, rt, vlc],
6 install: true,
7 install_dir: join_paths(dir_lib, 'emotion', 'generic_players', version_name)
8)
diff --git a/src/generic/evas/meson.build b/src/generic/evas/meson.build
index 2e5b58ae4c..e651b8b16a 100644
--- a/src/generic/evas/meson.build
+++ b/src/generic/evas/meson.build
@@ -1,8 +1,8 @@
1generic_loaders = ['gst', 'pdf', 1generic_loaders = [ 'pdf', 'ps', 'raw', 'rsvg', 'xcf' ]
2'ps', 2
3'raw', 3if get_option('gstreamer') == true
4'rsvg', 4 generic_loaders += [ 'gst' ]
5'xcf'] 5endif
6 6
7generic_src = [] 7generic_src = []
8generic_deps = [] 8generic_deps = []
diff --git a/src/modules/emotion/generic/Emotion_Generic_Plugin.h b/src/modules/emotion/generic/Emotion_Generic_Plugin.h
deleted file mode 100644
index 96b69f6421..0000000000
--- a/src/modules/emotion/generic/Emotion_Generic_Plugin.h
+++ /dev/null
@@ -1,148 +0,0 @@
1#ifndef EMOTION_GENERIC_PLUGIN_H
2#define EMOTION_GENERIC_PLUGIN_H
3
4#include <stdlib.h>
5#include <unistd.h>
6#include <sys/mman.h>
7#include <sys/stat.h>
8#include <fcntl.h>
9
10#include <Eina.h>
11
12#define DEFAULTWIDTH 320
13#define DEFAULTHEIGHT 240
14#define DEFAULTPITCH 4
15
16typedef enum _Emotion_Generic_Cmd Emotion_Generic_Cmd;
17typedef enum _Emotion_Generic_Result Emotion_Generic_Result;
18typedef struct _Emotion_Generic_Video_Frame Emotion_Generic_Video_Frame;
19typedef struct _Emotion_Generic_Video_Shared Emotion_Generic_Video_Shared;
20
21enum _Emotion_Generic_Cmd
22{
23 EM_CMD_INIT = 0, // 0 param: shared memory identifier (string)
24 EM_CMD_PLAY, // 1 param: position (float)
25 EM_CMD_STOP, // 2 param: none
26 EM_CMD_FILE_SET, // 3 param: filename (string)
27 EM_CMD_FILE_SET_DONE, // 4 param: none
28 EM_CMD_FILE_CLOSE, // 5 param: none
29 EM_CMD_POSITION_SET, // 6 param: position (float)
30 EM_CMD_SPEED_SET, // 7 param: speed (float)
31 EM_CMD_AUDIO_MUTE_SET, // 8 param: muted (int)
32 EM_CMD_VIDEO_MUTE_SET, // 9 param: muted (int)
33 EM_CMD_SPU_MUTE_SET, // 10 param: muted (int)
34 EM_CMD_VOLUME_SET, // 11 param: volume (float)
35 EM_CMD_AUDIO_TRACK_SET, // 12 param: track id (int)
36 EM_CMD_VIDEO_TRACK_SET, // 13 param: track id (int)
37 EM_CMD_SPU_TRACK_SET, // 14 param: track id (int)
38 EM_CMD_SUBTITLE_SET, // 15 param: subtitle filename (string)
39 EM_CMD_LAST
40};
41
42enum _Emotion_Generic_Result
43{
44 EM_RESULT_INIT = 0, // param: none
45 EM_RESULT_FILE_SET, // param: none
46 EM_RESULT_FILE_SET_DONE, // param: success (int)
47 EM_RESULT_PLAYBACK_STARTED, // param: none
48 EM_RESULT_PLAYBACK_STOPPED, // param: none
49 EM_RESULT_FILE_CLOSE, // param: none
50 EM_RESULT_FRAME_NEW, // param: none
51 EM_RESULT_FRAME_SIZE, // param: int, int (width, height)
52 EM_RESULT_LENGTH_CHANGED, // param: float
53 EM_RESULT_POSITION_CHANGED, // param: float
54 EM_RESULT_SEEKABLE_CHANGED, // param: int
55 EM_RESULT_AUDIO_TRACK_INFO, // param: current track, track count, track_id, track_name, track_id2, track_name2, ...
56 EM_RESULT_VIDEO_TRACK_INFO, // param: current track, track count, track_id, track_name, track_id2, track_name2, ...
57 EM_RESULT_SPU_TRACK_INFO, // param: current spu, spu count, spu_id, spu_name, spu_id2, spu_name2, ...
58 // (int, int, int, string, int, string, ...)
59 EM_RESULT_META_INFO, // param: title, artist, album, year, genre, comments, disc id, count (all int)
60 EM_RESULT_LAST
61};
62
63/* structure for frames 2 buffers to keep integrity */
64struct _Emotion_Generic_Video_Frame
65{
66 unsigned char *frames[3];
67};
68
69/* structure for frames 2 buffers to keep integrity */
70struct _Emotion_Generic_Video_Shared
71{
72 int size;
73 int width;
74 int height;
75 int pitch;
76 /**
77 * - "emotion" is the frame from where the Emotion process is reading pixels.
78 * The player shouldn't touch this frame.
79 * - "player" is the frame where the slave process is writing pixels.
80 * The emotion process shouldn't touch this frame.
81 * - "last" is the last frame that was rendered by the player. Emotion will
82 * use this frame the next time it will fetch pixels to Evas.
83 * - "next" is the unused frame. The player currently using the "player"
84 * should, after finishing this frame, set "last" to "player", and "player"
85 * to "next", and finally "next" to "last" so this operation can be done
86 * many times in case that Emotion does not request pixels fast enough.
87 */
88 struct {
89 int emotion;
90 int player;
91 int last;
92 int next;
93 } frame;
94 Eina_Semaphore lock;
95 int frame_drop;
96};
97
98static inline int
99emotion_generic_shm_get(const char *shmname, Emotion_Generic_Video_Shared **vs, Emotion_Generic_Video_Frame *vf)
100{
101 int shmfd = -1;
102 int size;
103 Emotion_Generic_Video_Shared *t_vs;
104
105 shmfd = shm_open(shmname, O_RDWR, 0700);
106 if (shmfd == -1)
107 {
108 fprintf(stderr, "player: could not open shm: %s: %s\n",
109 shmname, strerror(errno));
110 return 0;
111 }
112
113 t_vs = mmap(NULL, sizeof(*t_vs), PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0);
114 if (t_vs == MAP_FAILED)
115 {
116 fprintf(stderr, "player: could not map shared memory: %s\n",
117 strerror(errno));
118 close(shmfd);
119 return 0;
120 }
121 size = t_vs->size;
122 munmap(t_vs, sizeof(*t_vs));
123 t_vs = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0);
124 if (t_vs == MAP_FAILED)
125 {
126 fprintf(stderr, "player: could not map shared memory: %s\n",
127 strerror(errno));
128 close(shmfd);
129 return 0;
130 }
131 close(shmfd);
132
133 vf->frames[0] = (unsigned char *)t_vs + sizeof(*t_vs);
134 vf->frames[1] = (unsigned char *)t_vs + sizeof(*t_vs) + t_vs->height * t_vs->width * t_vs->pitch;
135 vf->frames[2] = (unsigned char *)t_vs + sizeof(*t_vs) + 2 * t_vs->height * t_vs->width * t_vs->pitch;
136
137 *vs = t_vs;
138
139 return 1;
140}
141
142static inline void
143emotion_generic_shm_free(Emotion_Generic_Video_Shared *vs)
144{
145 munmap(vs, vs->size);
146}
147
148#endif // EMOTION_GENERIC_PLUGIN_H
diff --git a/src/modules/emotion/generic/README b/src/modules/emotion/generic/README
deleted file mode 100644
index c2a028de5d..0000000000
--- a/src/modules/emotion/generic/README
+++ /dev/null
@@ -1,79 +0,0 @@
1Generic - emotion backend
2=========================
3
4This generic player backend executes a separate player in another
5process. It receives the bytes to be drawn on the emotion object through
6a shared memory, and communicates with the player through a pipe, using
7the player standard input/output.
8
9The player must communicate with emotion using the defined commands
10specified in the Emotion_Generic_Plugin.h. It doesn't need to link
11against emotion, just include this file for easier implementation.
12
13
14How does it work?
15=================
16
17When the module is initialized for an emotion object, it starts another process
18that runs the specified player. The player command line is specified using:
19
20 emotion_object_module_option_set(object, "player", <command>);
21
22A player using libvlc is being provided now, and the generic module internally
23checks if the command given was "vlc", in which case it will use this provided
24vlc player.
25
26When a file is set to this object, it will send the file name to the player, and
27expect an answer that will tell that the player already decoded a bit of the
28file, and the video size is already set on the module, so it can allocate a
29shared memory with correct size.
30
31The module then allocates the memory, sends a message to the player and expect
32an answer. After this last answer, the "open_done" signal is sent and the module
33knows that it is ready for playing. Commands sent before the module being ready
34are now applied (and play is resumed if necessary).
35
36During this setup stage, info about the file set will be stored in the module,
37so commands like meta data get, length get and so will be available to sync
38calls like emotion_object_play_length_get();
39
40If the player dies for any reason, a "decode_stop" signal is sent (should change
41to something more like an error signal), and if play is called again, it will be
42restarted. The playback should start from the same point it was before the
43player crashed, if the player supports seek on the current media format).
44
45TODO
46====
47
48 - Provide better description for commands;
49 - Explain in details the communication emotion <-> player;
50 - Make more common functions for players;
51 - (maybe) add support for named pipes, so we don't rely on standard in/out
52 for communication;
53 - Add a detection on the player to know that the emotion process died (so it
54 can just exit);
55 - shmname should contain the child pid too;
56 - better names for commands, maybe add namespace everywhere;
57
58
59questions
60=========
61
62 - Using semaphores to lock the critical region between process, and pthread
63 mutexes for the threads inside the player. Should move to only one type
64 (semphores or mutexes)?
65 - There are 2 inline functions insde Emotion_Generic_Plugin.h to make it easier
66 for the player to get the shared memory correctly. Any problem with this?
67 Would be good to add more functions/macros to make common tasks like
68 parsing commands there too?
69 - Should move players to another project (outside of emotion)?
70
71
72problems
73========
74 - file_set has some critical time when file is not set yet when we can't call
75 some functions (I think only another file_set now);
76 - communication player -> emotion depends on '\n' to delimitate commands, will
77 remove this soon (fix this urgently!);
78 - need to implement missing APIs;
79
diff --git a/src/modules/emotion/generic/emotion_generic.c b/src/modules/emotion/generic/emotion_generic.c
deleted file mode 100644
index 601e9e2d92..0000000000
--- a/src/modules/emotion/generic/emotion_generic.c
+++ /dev/null
@@ -1,1908 +0,0 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include <sys/mman.h>
6#include <sys/stat.h>
7#include <sys/time.h>
8#include <sys/types.h>
9#include <fcntl.h>
10#include <unistd.h>
11#include <errno.h>
12
13#include <Eina.h>
14#include <Evas.h>
15#include <Ecore.h>
16
17#include "emotion_modules.h"
18#include "emotion_generic.h"
19
20static Eina_Prefix *pfx = NULL;
21static Eina_List *_generic_players = NULL;
22static int _emotion_init_count = 0;
23
24static int _emotion_generic_log_domain = -1;
25#ifdef DBG
26#undef DBG
27#endif
28#define DBG(...) EINA_LOG_DOM_DBG(_emotion_generic_log_domain, __VA_ARGS__)
29
30#ifdef INF
31#undef INF
32#endif
33#define INF(...) EINA_LOG_DOM_INFO(_emotion_generic_log_domain, __VA_ARGS__)
34
35#ifdef WRN
36#undef WRN
37#endif
38#define WRN(...) EINA_LOG_DOM_WARN(_emotion_generic_log_domain, __VA_ARGS__)
39
40#ifdef ERR
41#undef ERR
42#endif
43#define ERR(...) EINA_LOG_DOM_ERR(_emotion_generic_log_domain, __VA_ARGS__)
44
45#ifdef CRI
46#undef CRI
47#endif
48#define CRI(...) EINA_LOG_DOM_CRIT(_emotion_generic_log_domain, __VA_ARGS__)
49
50
51static Eina_Bool _fork_and_exec(Emotion_Generic_Video *ev);
52static void em_partial_shutdown(Emotion_Generic_Video *ev);
53
54
55static void
56_player_send_cmd(Emotion_Generic_Video *ev, int cmd)
57{
58 if (cmd >= EM_CMD_LAST)
59 {
60 ERR("invalid command to player.");
61 return;
62 }
63 if (!ev->fd_write)
64 {
65 ERR("you should wait for emotion to be ready to take action.");
66 return;
67 }
68 ecore_pipe_write(ev->fd_write, &cmd, sizeof(cmd));
69}
70
71static void
72_player_send_int(Emotion_Generic_Video *ev, int number)
73{
74 if (!ev->fd_write)
75 {
76 ERR("you should wait for emotion to be ready to take action.");
77 return;
78 }
79 ecore_pipe_write(ev->fd_write, &number, sizeof(number));
80}
81
82static void
83_player_send_float(Emotion_Generic_Video *ev, float number)
84{
85 if (!ev->fd_write)
86 {
87 ERR("you should wait for emotion to be ready to take action.");
88 return;
89 }
90 ecore_pipe_write(ev->fd_write, &number, sizeof(number));
91}
92
93static void
94_player_send_str(Emotion_Generic_Video *ev, const char *str, Eina_Bool stringshared)
95{
96 int len;
97
98 if (stringshared)
99 len = str ? eina_stringshare_strlen(str) + 1 : 0;
100 else
101 len = str ? strlen(str) + 1 : 0;
102
103 if (str)
104 ecore_pipe_write(ev->fd_write, str, len);
105}
106
107static Eina_Bool
108_create_shm_data(Emotion_Generic_Video *ev, const char *shmname)
109{
110 int shmfd;
111 int npages;
112 size_t size;
113 Emotion_Generic_Video_Shared *vs;
114
115 shmfd = shm_open(shmname, O_CREAT | O_RDWR | O_TRUNC, 0700);
116 if (shmfd == -1)
117 {
118 ERR("player: could not create shm %s: %s", shmname, strerror(errno));
119 return 0;
120 }
121 size = 3 * (ev->w * ev->h * DEFAULTPITCH) + sizeof(*vs);
122
123 npages = (int)(size / getpagesize()) + 1;
124 size = npages * getpagesize();
125
126 if (ftruncate(shmfd, size))
127 {
128 ERR("error when allocating shared memory (size = %zd): "
129 "%s", size, strerror(errno));
130 close(shmfd);
131 shm_unlink(shmname);
132 return EINA_FALSE;
133 }
134 vs = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0);
135 if (vs == MAP_FAILED)
136 {
137 ERR("error when mapping shared memory: %s", strerror(errno));
138 close(shmfd);
139 shm_unlink(shmname);
140 return EINA_FALSE;
141 }
142 close(shmfd);
143
144 vs->size = size;
145 vs->width = ev->w;
146 vs->height = ev->h;
147 vs->pitch = DEFAULTPITCH;
148 vs->frame.emotion = 0;
149 vs->frame.player = 1;
150 vs->frame.last = 2;
151 vs->frame.next = 2;
152 vs->frame_drop = 0;
153 if (!eina_semaphore_new(&vs->lock, 1))
154 {
155 ERR("can not create semaphore");
156 munmap(vs, size);
157 shm_unlink(shmname);
158 return EINA_FALSE;
159 }
160 ev->frame.frames[0] = (unsigned char *)vs + sizeof(*vs);
161 ev->frame.frames[1] = (unsigned char *)vs + sizeof(*vs) + vs->height * vs->width * vs->pitch;
162 ev->frame.frames[2] = (unsigned char *)vs + sizeof(*vs) + 2 * vs->height * vs->width * vs->pitch;
163
164 if (ev->shared)
165 munmap(ev->shared, ev->shared->size);
166 ev->shared = vs;
167
168 return EINA_TRUE;
169}
170
171static void
172_player_new_frame(Emotion_Generic_Video *ev)
173{
174 if (!ev->file_ready)
175 return;
176 _emotion_frame_new(ev->obj);
177}
178
179static void
180_file_open(Emotion_Generic_Video *ev)
181{
182 INF("Opening file: %s", ev->filename);
183 ev->drop = 0;
184
185 if (!ev->ready || !ev->filename)
186 return;
187 _player_send_cmd(ev, EM_CMD_FILE_SET);
188 _player_send_str(ev, ev->filename, EINA_TRUE);
189}
190
191static void
192_player_file_set_done(Emotion_Generic_Video *ev)
193{
194 if (ev->file_changed)
195 {
196 _file_open(ev);
197 ev->file_changed = EINA_FALSE;
198 return;
199 }
200
201 if (!_create_shm_data(ev, ev->shmname))
202 {
203 ERR("could not create shared memory.");
204 return;
205 }
206 _player_send_cmd(ev, EM_CMD_FILE_SET_DONE);
207}
208
209static void
210_player_ready(Emotion_Generic_Video *ev)
211{
212 INF("received: player ready.");
213
214 ev->initializing = EINA_FALSE;
215 ev->ready = EINA_TRUE;
216
217 if (!ev->filename)
218 return;
219
220 _file_open(ev);
221}
222
223static Eina_Bool
224_player_cmd_param_read(Emotion_Generic_Video *ev, void *param, size_t size)
225{
226 ssize_t done, todo, i;
227
228 /* When a parameter must be read, we cannot make sure it will be entirely
229 * available. Thus we store the bytes that could be read in a temp buffer,
230 * and when more data is read we try to complete the buffer and finally use
231 * the read value.
232 */
233 if (!ev->cmd.tmp)
234 {
235 ev->cmd.tmp = malloc(size);
236 ev->cmd.i = 0;
237 ev->cmd.total = size;
238 }
239
240 todo = ev->cmd.total - ev->cmd.i;
241 i = ev->cmd.i;
242
243 done = (ev->offset + todo > ev->length) ? ev->length - ev->offset : todo;
244 memcpy(&ev->cmd.tmp[i], &ev->buffer[ev->offset], done);
245 ev->offset += done;
246
247 if (done == todo)
248 {
249 memcpy(param, ev->cmd.tmp, size);
250 free(ev->cmd.tmp);
251 ev->cmd.tmp = NULL;
252 return EINA_TRUE;
253 }
254
255 if (done > 0)
256 ev->cmd.i += done;
257
258 return EINA_FALSE;
259}
260
261static void
262_player_frame_resize(Emotion_Generic_Video *ev)
263{
264 int w, h;
265
266 w = ev->cmd.param.size.width;
267 h = ev->cmd.param.size.height;
268
269 INF("received frame resize: %dx%d", w, h);
270 ev->w = w;
271 ev->h = h;
272 ev->ratio = (float)w / h;
273
274 _emotion_frame_resize(ev->obj, ev->w, ev->h, ev->ratio);
275}
276
277static void
278_player_length_changed(Emotion_Generic_Video *ev)
279{
280 float length = ev->cmd.param.f_num;
281
282 INF("received length changed: %0.3f", length);
283
284 ev->len = length;
285 _emotion_video_pos_update(ev->obj, ev->pos, ev->len);
286}
287
288static void
289_player_position_changed(Emotion_Generic_Video *ev)
290{
291 float position = ev->cmd.param.f_num;
292
293 // INF("received position changed: %0.3f", position);
294
295 ev->pos = position;
296 _emotion_video_pos_update(ev->obj, ev->pos, ev->len);
297/* hmmm. no _emotion_progress_set() is for "buffering" progress.
298 if (ev->len == 0)
299 return;
300
301 float progress = ev->pos / ev->len;
302 char buf[16];
303 snprintf(buf, sizeof(buf), "%0.1f%%", progress * 100);
304
305 _emotion_progress_set(ev->obj, buf, progress);
306 */
307}
308
309static void
310_player_seekable_changed(Emotion_Generic_Video *ev)
311{
312 int seekable = ev->cmd.param.i_num;
313
314 INF("received seekable changed: %d", seekable);
315
316 seekable = !!seekable;
317
318 ev->seekable = seekable;
319}
320
321static void
322_audio_channels_free(Emotion_Generic_Video *ev)
323{
324 int i;
325 for (i = 0; i < ev->audio_channels_count; i++)
326 eina_stringshare_del(ev->audio_channels[i].name);
327 free(ev->audio_channels);
328 ev->audio_channels = NULL;
329 ev->audio_channels_count = 0;
330}
331
332static void
333_video_channels_free(Emotion_Generic_Video *ev)
334{
335 int i;
336 for (i = 0; i < ev->video_channels_count; i++)
337 eina_stringshare_del(ev->video_channels[i].name);
338 free(ev->video_channels);
339 ev->video_channels = NULL;
340 ev->video_channels_count = 0;
341}
342
343static void
344_spu_channels_free(Emotion_Generic_Video *ev)
345{
346 int i;
347 for (i = 0; i < ev->spu_channels_count; i++)
348 eina_stringshare_del(ev->spu_channels[i].name);
349 free(ev->spu_channels);
350 ev->spu_channels = NULL;
351 ev->spu_channels_count = 0;
352}
353
354static void
355_player_tracks_info(Emotion_Generic_Video *ev, Emotion_Generic_Channel **channels, int *count, int *current)
356{
357 Emotion_Generic_Channel *pchannels;
358 int i;
359
360 *count = ev->cmd.param.track.total;
361 *current = ev->cmd.param.track.current;
362 pchannels = ev->cmd.param.track.channels;
363
364 INF("number of tracks: %d (current = %d):", *count, *current);
365 for (i = 0; i < *count; i++)
366 {
367 INF("\tchannel %d: %s", pchannels[i].id, pchannels[i].name);
368 }
369
370 *channels = pchannels;
371}
372
373static void
374_player_audio_tracks_info(Emotion_Generic_Video *ev)
375{
376 INF("Receiving audio channels:");
377 if (ev->audio_channels_count)
378 _audio_channels_free(ev);
379
380 _player_tracks_info(ev, &ev->audio_channels, &ev->audio_channels_count,
381 &ev->audio_channel_current);
382}
383
384static void
385_player_video_tracks_info(Emotion_Generic_Video *ev)
386{
387 INF("Receiving video channels:");
388 if (ev->video_channels_count)
389 _video_channels_free(ev);
390
391 _player_tracks_info(ev, &ev->video_channels, &ev->video_channels_count,
392 &ev->video_channel_current);
393}
394
395static void
396_player_spu_tracks_info(Emotion_Generic_Video *ev)
397{
398 INF("Receiving spu channels:");
399 if (ev->spu_channels_count)
400 _spu_channels_free(ev);
401
402 _player_tracks_info(ev, &ev->spu_channels, &ev->spu_channels_count,
403 &ev->spu_channel_current);
404}
405
406static void
407_player_meta_info_free(Emotion_Generic_Video *ev)
408{
409 eina_stringshare_replace(&ev->meta.title, NULL);
410 eina_stringshare_replace(&ev->meta.artist, NULL);
411 eina_stringshare_replace(&ev->meta.album, NULL);
412 eina_stringshare_replace(&ev->meta.year, NULL);
413 eina_stringshare_replace(&ev->meta.genre, NULL);
414 eina_stringshare_replace(&ev->meta.comment, NULL);
415 eina_stringshare_replace(&ev->meta.disc_id, NULL);
416 eina_stringshare_replace(&ev->meta.count, NULL);
417}
418
419static void
420_player_meta_info_read(Emotion_Generic_Video *ev)
421{
422 INF("Receiving meta info:");
423 _player_meta_info_free(ev);
424 ev->meta.title = ev->cmd.param.meta.title;
425 ev->meta.artist = ev->cmd.param.meta.artist;
426 ev->meta.album = ev->cmd.param.meta.album;
427 ev->meta.year = ev->cmd.param.meta.year;
428 ev->meta.genre = ev->cmd.param.meta.genre;
429 ev->meta.comment = ev->cmd.param.meta.comment;
430 ev->meta.disc_id = ev->cmd.param.meta.disc_id;
431 ev->meta.count = ev->cmd.param.meta.count;
432 INF("title: '%s'", ev->meta.title);
433 INF("artist: '%s'", ev->meta.artist);
434 INF("album: '%s'", ev->meta.album);
435 INF("year: '%s'", ev->meta.year);
436 INF("genre: '%s'", ev->meta.genre);
437 INF("comment: '%s'", ev->meta.comment);
438 INF("disc_id: '%s'", ev->meta.disc_id);
439 INF("count: '%s'", ev->meta.count);
440}
441
442static void
443_player_file_closed(Emotion_Generic_Video *ev)
444{
445 INF("Closed previous file.");
446 eina_semaphore_free(&ev->shared->lock);
447 ev->closing = EINA_FALSE;
448
449 if (ev->opening)
450 _file_open(ev);
451}
452
453static void
454_player_open_done(Emotion_Generic_Video *ev)
455{
456 int success;
457
458 success = ev->cmd.param.i_num;
459 shm_unlink(ev->shmname);
460
461 if (ev->file_changed)
462 {
463 _file_open(ev);
464 ev->file_changed = EINA_FALSE;
465 return;
466 }
467
468 ev->opening = EINA_FALSE;
469 if (!success)
470 {
471 ERR("Could not open file.");
472 return;
473 }
474
475 ev->file_ready = EINA_TRUE;
476
477 _emotion_open_done(ev->obj);
478
479 _player_send_cmd(ev, EM_CMD_VOLUME_SET);
480 _player_send_float(ev, ev->volume);
481
482 _player_send_cmd(ev, EM_CMD_SPEED_SET);
483 _player_send_float(ev, ev->speed);
484
485 int mute = ev->audio_mute;
486 _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET);
487 _player_send_int(ev, mute);
488
489 mute = ev->video_mute;
490 _player_send_cmd(ev, EM_CMD_VIDEO_MUTE_SET);
491 _player_send_int(ev, mute);
492
493 mute = ev->spu_mute;
494 _player_send_cmd(ev, EM_CMD_SPU_MUTE_SET);
495 _player_send_int(ev, mute);
496
497 if (ev->play)
498 {
499 _player_send_cmd(ev, EM_CMD_PLAY);
500 _player_send_float(ev, ev->pos);
501 }
502
503 INF("Open done");
504}
505
506static void
507_player_cmd_process(Emotion_Generic_Video *ev)
508{
509 switch (ev->cmd.type) {
510 case EM_RESULT_INIT:
511 _player_ready(ev);
512 break;
513 case EM_RESULT_FRAME_NEW:
514 _player_new_frame(ev);
515 break;
516 case EM_RESULT_FILE_SET:
517 _player_file_set_done(ev);
518 break;
519 case EM_RESULT_FILE_SET_DONE:
520 _player_open_done(ev);
521 break;
522 case EM_RESULT_FILE_CLOSE:
523 _player_file_closed(ev);
524 break;
525 case EM_RESULT_PLAYBACK_STARTED:
526 _emotion_playback_started(ev->obj);
527 break;
528 case EM_RESULT_PLAYBACK_STOPPED:
529 ev->play = 0;
530 _emotion_playback_finished(ev->obj);
531 _emotion_decode_stop(ev->obj);
532 break;
533 case EM_RESULT_FRAME_SIZE:
534 _player_frame_resize(ev);
535 break;
536 case EM_RESULT_LENGTH_CHANGED:
537 _player_length_changed(ev);
538 break;
539 case EM_RESULT_POSITION_CHANGED:
540 _player_position_changed(ev);
541 break;
542 case EM_RESULT_SEEKABLE_CHANGED:
543 _player_seekable_changed(ev);
544 break;
545 case EM_RESULT_AUDIO_TRACK_INFO:
546 _player_audio_tracks_info(ev);
547 break;
548 case EM_RESULT_VIDEO_TRACK_INFO:
549 _player_video_tracks_info(ev);
550 break;
551 case EM_RESULT_SPU_TRACK_INFO:
552 _player_spu_tracks_info(ev);
553 break;
554 case EM_RESULT_META_INFO:
555 _player_meta_info_read(ev);
556 break;
557 default:
558 WRN("received wrong command: %d", ev->cmd.type);
559 }
560
561 ev->cmd.type = -1;
562}
563
564static void
565_player_cmd_single_int_process(Emotion_Generic_Video *ev)
566{
567 if (!_player_cmd_param_read(ev, &ev->cmd.param.i_num, sizeof(ev->cmd.param.i_num)))
568 return;
569
570 _player_cmd_process(ev);
571}
572
573static void
574_player_cmd_single_float_process(Emotion_Generic_Video *ev)
575{
576 if (!_player_cmd_param_read(ev, &ev->cmd.param.f_num, sizeof(ev->cmd.param.f_num)))
577 return;
578
579 _player_cmd_process(ev);
580}
581
582static void
583_player_cmd_double_int_process(Emotion_Generic_Video *ev)
584{
585 int param;
586
587 if (ev->cmd.num_params == 0)
588 {
589 ev->cmd.num_params = 2;
590 ev->cmd.cur_param = 0;
591 ev->cmd.param.size.width = 0;
592 ev->cmd.param.size.height = 0;
593 }
594
595 if (!_player_cmd_param_read(ev, &param, sizeof(param)))
596 return;
597
598 if (ev->cmd.cur_param == 0)
599 ev->cmd.param.size.width = param;
600 else
601 ev->cmd.param.size.height = param;
602
603 ev->cmd.cur_param++;
604 if (ev->cmd.cur_param == ev->cmd.num_params)
605 _player_cmd_process(ev);
606}
607
608static void
609_player_cmd_track_info(Emotion_Generic_Video *ev)
610{
611 int param;
612 int i;
613
614 if (ev->cmd.num_params == 0)
615 {
616 ev->cmd.cur_param = 0;
617 ev->cmd.num_params = 2;
618 ev->cmd.param.track.channels = NULL;
619 ev->cmd.s_len = -1;
620 }
621
622 while (ev->cmd.cur_param < 2)
623 {
624 if (!_player_cmd_param_read(ev, &param, sizeof(param)))
625 return;
626
627 if (ev->cmd.cur_param == 0)
628 ev->cmd.param.track.current = param;
629 else
630 {
631 ev->cmd.param.track.total = param;
632 ev->cmd.num_params += param * 2;
633 ev->cmd.param.track.channels =
634 calloc(param, sizeof(*ev->cmd.param.track.channels));
635 }
636 ev->cmd.cur_param++;
637 }
638
639 if (ev->cmd.cur_param == ev->cmd.num_params)
640 {
641 _player_cmd_process(ev);
642 return;
643 }
644
645 i = (ev->cmd.cur_param - 2) / 2;
646 if ((ev->cmd.cur_param % 2) == 0) // reading track id
647 {
648 if (!_player_cmd_param_read(ev, &param, sizeof(param)))
649 return;
650 ev->cmd.param.track.channels[i].id = param;
651 ev->cmd.cur_param++;
652 }
653 else // reading track name
654 {
655 char buf[PATH_MAX];
656
657 if (ev->cmd.s_len == -1)
658 {
659 if (!_player_cmd_param_read(ev, &param, sizeof(param)))
660 return;
661 ev->cmd.s_len = param;
662 }
663
664 if (!_player_cmd_param_read(ev, buf, ev->cmd.s_len))
665 return;
666 ev->cmd.param.track.channels[i].name =
667 eina_stringshare_add_length(buf, ev->cmd.s_len);
668 ev->cmd.cur_param++;
669 ev->cmd.s_len = -1;
670 }
671
672 if (ev->cmd.cur_param == ev->cmd.num_params)
673 _player_cmd_process(ev);
674}
675
676static void
677_player_cmd_meta_info(Emotion_Generic_Video *ev)
678{
679 int param;
680 const char *info;
681 char buf[PATH_MAX];
682
683 if (ev->cmd.num_params == 0)
684 {
685 ev->cmd.cur_param = 0;
686 ev->cmd.num_params = 8;
687 ev->cmd.param.meta.title = NULL;
688 ev->cmd.param.meta.artist = NULL;
689 ev->cmd.param.meta.album = NULL;
690 ev->cmd.param.meta.year = NULL;
691 ev->cmd.param.meta.genre = NULL;
692 ev->cmd.param.meta.comment = NULL;
693 ev->cmd.param.meta.disc_id = NULL;
694 ev->cmd.param.meta.count = NULL;
695 ev->cmd.s_len = -1;
696 }
697
698 if (ev->cmd.s_len == -1)
699 {
700 if (!_player_cmd_param_read(ev, &param, sizeof(param)))
701 return;
702 ev->cmd.s_len = param;
703 }
704
705 if (!_player_cmd_param_read(ev, buf, ev->cmd.s_len))
706 return;
707
708 info = eina_stringshare_add_length(buf, ev->cmd.s_len);
709 ev->cmd.s_len = -1;
710
711 if (ev->cmd.cur_param == 0)
712 ev->cmd.param.meta.title = info;
713 else if (ev->cmd.cur_param == 1)
714 ev->cmd.param.meta.artist = info;
715 else if (ev->cmd.cur_param == 2)
716 ev->cmd.param.meta.album = info;
717 else if (ev->cmd.cur_param == 3)
718 ev->cmd.param.meta.year = info;
719 else if (ev->cmd.cur_param == 4)
720 ev->cmd.param.meta.genre = info;
721 else if (ev->cmd.cur_param == 5)
722 ev->cmd.param.meta.comment = info;
723 else if (ev->cmd.cur_param == 6)
724 ev->cmd.param.meta.disc_id = info;
725 else if (ev->cmd.cur_param == 7)
726 ev->cmd.param.meta.count = info;
727
728 ev->cmd.cur_param++;
729
730 if (ev->cmd.cur_param == 8)
731 _player_cmd_process(ev);
732}
733
734static void
735_player_cmd_read(Emotion_Generic_Video *ev)
736{
737 if (ev->cmd.type < 0)
738 {
739 if (!_player_cmd_param_read(ev, &ev->cmd.type, sizeof(ev->cmd.type)))
740 return;
741 ev->cmd.num_params = 0;
742 }
743
744 switch (ev->cmd.type) {
745 case EM_RESULT_INIT:
746 case EM_RESULT_FILE_SET:
747 case EM_RESULT_PLAYBACK_STARTED:
748 case EM_RESULT_PLAYBACK_STOPPED:
749 case EM_RESULT_FILE_CLOSE:
750 case EM_RESULT_FRAME_NEW:
751 _player_cmd_process(ev);
752 break;
753 case EM_RESULT_FILE_SET_DONE:
754 case EM_RESULT_SEEKABLE_CHANGED:
755 _player_cmd_single_int_process(ev);
756 break;
757 case EM_RESULT_LENGTH_CHANGED:
758 case EM_RESULT_POSITION_CHANGED:
759 _player_cmd_single_float_process(ev);
760 break;
761 case EM_RESULT_FRAME_SIZE:
762 _player_cmd_double_int_process(ev);
763 break;
764 case EM_RESULT_AUDIO_TRACK_INFO:
765 case EM_RESULT_VIDEO_TRACK_INFO:
766 case EM_RESULT_SPU_TRACK_INFO:
767 _player_cmd_track_info(ev);
768 break;
769 case EM_RESULT_META_INFO:
770 _player_cmd_meta_info(ev);
771 break;
772
773 default:
774 WRN("received wrong command: %d", ev->cmd.type);
775 ev->cmd.type = -1;
776 }
777}
778
779static void
780_player_cmd_handler_cb(void *data, void *buffer, unsigned int nbyte)
781{
782 Emotion_Generic_Video *ev = data;
783
784 ev->buffer = buffer;
785 ev->length = nbyte;
786 ev->offset = 0;
787
788 _player_cmd_read(ev);
789
790 ev->buffer = NULL;
791 ev->length = 0;
792}
793
794static Eina_Bool
795_player_data_cb(void *data, int type EINA_UNUSED, void *event)
796{
797 Ecore_Exe_Event_Data *ev = event;
798 Emotion_Generic_Video *evideo = data;
799 int i;
800
801 if (ev->exe != evideo->player.exe)
802 {
803 INF("slave != ev->exe");
804 return ECORE_CALLBACK_PASS_ON;
805 }
806
807 for (i = 0; ev->lines[i].line; i++)
808 INF("received input from player: \"%s\"", ev->lines[i].line);
809
810 return ECORE_CALLBACK_DONE;
811}
812
813static Eina_Bool
814_player_add_cb(void *data, int type EINA_UNUSED, void *event)
815{
816 Ecore_Exe_Event_Add *event_add = event;
817 Ecore_Exe *player = event_add->exe;
818 Emotion_Generic_Video *ev = data;
819
820 if (ev->player.exe != player)
821 {
822 INF("ev->player != player.");
823 return ECORE_CALLBACK_PASS_ON;
824 }
825
826 _player_send_cmd(ev, EM_CMD_INIT);
827 _player_send_str(ev, ev->shmname, EINA_TRUE);
828
829 return ECORE_CALLBACK_DONE;
830}
831
832static Eina_Bool
833_player_del_cb(void *data, int type EINA_UNUSED, void *event EINA_UNUSED)
834{
835 Ecore_Exe_Event_Del *event_del = event;
836 Ecore_Exe *player = event_del->exe;
837 Emotion_Generic_Video *ev = data;
838
839 if (ev->player.exe != player)
840 {
841 INF("ev->player != player.");
842 return ECORE_CALLBACK_PASS_ON;
843 }
844
845 ERR("player died.");
846
847 ev->player.exe = NULL;
848 ev->ready = EINA_FALSE;
849 ev->file_ready = EINA_FALSE;
850 ecore_pipe_del(ev->fd_read);
851 ecore_pipe_del(ev->fd_write);
852 ev->fd_read = NULL;
853 ev->fd_write = NULL;
854 _emotion_decode_stop(ev->obj);
855
856 return ECORE_CALLBACK_DONE;
857}
858
859static void
860_player_dummy(void *data EINA_UNUSED,
861 void *buffer EINA_UNUSED,
862 unsigned int nbyte EINA_UNUSED)
863{
864}
865
866static Eina_Bool
867_player_exec(Emotion_Generic_Video *ev)
868{
869 Ecore_Pipe *in;
870 Ecore_Pipe *out;
871 char buf[PATH_MAX];
872
873 out = ecore_pipe_full_add(_player_dummy, NULL, -1, -1, EINA_TRUE, EINA_FALSE);
874 if (!out)
875 {
876 ERR("could not create pipe for communication emotion -> player: %s", strerror(errno));
877 return EINA_FALSE;
878 }
879
880 in = ecore_pipe_full_add(_player_cmd_handler_cb, ev, -1, -1, EINA_FALSE, EINA_TRUE);
881 if (!in)
882 {
883 ERR("could not create pipe for communication player -> emotion: %s", strerror(errno));
884 ecore_pipe_del(in);
885 ecore_pipe_del(out);
886 return EINA_FALSE;
887 }
888
889 snprintf(buf, sizeof(buf), "%s %d %d", ev->engine->path,
890 ecore_pipe_read_fd(out),
891 ecore_pipe_write_fd(in));
892
893 ev->player.exe = ecore_exe_pipe_run(
894 buf, ECORE_EXE_NOT_LEADER | ECORE_EXE_TERM_WITH_PARENT, ev);
895
896 INF("created pipe emotion -> player: %d -> %d",
897 ecore_pipe_write_fd(out), ecore_pipe_read_fd(out));
898 INF("created pipe player -> emotion: %d -> %d",
899 ecore_pipe_write_fd(in), ecore_pipe_read_fd(in));
900
901 ecore_pipe_write_close(in);
902 ecore_pipe_read_close(out);
903
904 if (!ev->player.exe)
905 {
906 ecore_pipe_del(in);
907 ecore_pipe_del(out);
908 return EINA_FALSE;
909 }
910
911 ev->fd_read = in;
912 ev->fd_write = out;
913
914 return EINA_TRUE;
915}
916
917static Eina_Bool
918_fork_and_exec(Emotion_Generic_Video *ev)
919{
920 char shmname[256];
921
922 snprintf(shmname, sizeof(shmname), "/em-generic-shm_%d_%p_%f",
923 getpid(), ev->obj, ecore_time_get());
924
925 ev->shmname = eina_stringshare_add(shmname);
926
927 ev->player_add = ecore_event_handler_add(ECORE_EXE_EVENT_ADD,
928 _player_add_cb, ev);
929 ev->player_del = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
930 _player_del_cb, ev);
931 ev->player_data = ecore_event_handler_add(ECORE_EXE_EVENT_DATA,
932 _player_data_cb, ev);
933
934 if (!_player_exec(ev))
935 {
936 eina_stringshare_del(ev->shmname);
937 ecore_event_handler_del(ev->player_add);
938 ecore_event_handler_del(ev->player_del);
939 ecore_event_handler_del(ev->player_data);
940 ERR("could not start player.");
941 return EINA_FALSE;
942 }
943
944 ev->initializing = EINA_TRUE;
945
946 return EINA_TRUE;
947}
948
949typedef struct _Delay_Munmap Delay_Munmap;
950struct _Delay_Munmap
951{
952 void *map;
953 size_t size;
954};
955
956static void
957_delayed_munmap(void *data, Evas *e, void *event_info EINA_UNUSED)
958{
959 Delay_Munmap *dm = data;
960
961 evas_event_callback_del_full(e, EVAS_CALLBACK_RENDER_POST, _delayed_munmap, data);
962 fprintf(stderr, "munmapping !\n");
963 munmap(dm->map, dm->size);
964 free(dm);
965}
966
967static void
968_delayed_next_frame(void *data, Evas *e, void *event_info EINA_UNUSED)
969{
970 evas_event_callback_add(e, EVAS_CALLBACK_RENDER_POST, _delayed_munmap, data);
971 evas_event_callback_del_full(e, EVAS_CALLBACK_RENDER_PRE, _delayed_next_frame, data);
972}
973
974static void
975em_partial_shutdown(Emotion_Generic_Video *ev)
976{
977 if (ev->player.exe)
978 {
979 ecore_exe_terminate(ev->player.exe);
980 ecore_exe_free(ev->player.exe);
981 ev->player.exe = NULL;
982 }
983
984 ev->file_ready = EINA_FALSE;
985
986 if (ev->shared)
987 {
988 Evas_Object *o;
989 Delay_Munmap *dm;
990
991 dm = malloc(sizeof (Delay_Munmap));
992 if (dm)
993 {
994 dm->map = ev->shared;
995 dm->size = ev->shared->size;
996 evas_event_callback_add(evas_object_evas_get(ev->obj),
997 EVAS_CALLBACK_RENDER_PRE,
998 _delayed_next_frame, dm);
999 }
1000
1001 o = emotion_object_image_get(ev->obj);
1002 evas_object_image_data_set(o, NULL);
1003 evas_object_image_size_set(o, 1, 1);
1004 }
1005 ev->shared = NULL;
1006
1007 _emotion_image_reset(ev->obj);
1008
1009 if (ev->fd_read)
1010 ecore_pipe_del(ev->fd_read);
1011 ev->fd_read = NULL;
1012 if (ev->fd_write)
1013 ecore_pipe_del(ev->fd_write);
1014 ev->fd_write = NULL;
1015
1016 if (ev->player_add) ecore_event_handler_del(ev->player_add);
1017 ev->player_add = NULL;
1018 if (ev->player_data) ecore_event_handler_del(ev->player_data);
1019 ev->player_data = NULL;
1020 if (ev->player_del) ecore_event_handler_del(ev->player_del);
1021 ev->player_del = NULL;
1022}
1023
1024
1025/* Emotion interface */
1026static void *
1027em_add(const Emotion_Engine *api, Evas_Object *obj, const Emotion_Module_Options *opt EINA_UNUSED)
1028{
1029 Emotion_Generic_Video *ev;
1030
1031 ev = calloc(1, sizeof(*ev));
1032 EINA_SAFETY_ON_NULL_RETURN_VAL(ev, NULL);
1033
1034 ev->fd_read = NULL;
1035 ev->fd_write = NULL;
1036 ev->speed = 1.0;
1037 ev->volume = 0.8;
1038 ev->audio_mute = EINA_FALSE;
1039 ev->cmd.type = -1;
1040
1041 ev->obj = obj;
1042 ev->engine = (Emotion_Engine_Generic *)api;
1043
1044 if (!_fork_and_exec(ev))
1045 {
1046 free(ev);
1047 return NULL;
1048 }
1049
1050 return ev;
1051}
1052
1053static void
1054em_del(void *data)
1055{
1056 Emotion_Generic_Video *ev = data;
1057
1058 eina_stringshare_del(ev->shmname);
1059
1060 em_partial_shutdown(ev);
1061}
1062
1063static unsigned char
1064em_file_open(void *data, const char *file)
1065{
1066 Emotion_Generic_Video *ev = data;
1067 INF("file set: %s", file);
1068 if (!ev) return 0;
1069
1070 eina_stringshare_replace(&ev->filename, file);
1071
1072 ev->pos = 0;
1073 ev->w = 0;
1074 ev->h = 0;
1075 ev->ratio = 1;
1076 ev->len = 0;
1077
1078 if (ev->ready && ev->opening)
1079 {
1080 INF("file changed while opening.");
1081 ev->file_changed = EINA_TRUE;
1082 return 1;
1083 }
1084
1085 ev->opening = EINA_TRUE;
1086
1087 if (!ev->closing)
1088 _file_open(ev);
1089
1090 return 1;
1091}
1092
1093static void
1094em_file_close(void *data)
1095{
1096 Emotion_Generic_Video *ev = data;
1097
1098 if (!ev || !ev->filename) return;
1099
1100 INF("file close: %s", ev->filename);
1101
1102 eina_stringshare_replace(&ev->filename, NULL);
1103 eina_stringshare_replace(&ev->subtitle_path, NULL);
1104
1105 ev->file_ready = EINA_FALSE;
1106 _audio_channels_free(ev);
1107 _video_channels_free(ev);
1108 _spu_channels_free(ev);
1109 _player_meta_info_free(ev);
1110
1111 if (ev->opening)
1112 return;
1113
1114 _player_send_cmd(ev, EM_CMD_FILE_CLOSE);
1115 ev->closing = EINA_TRUE;
1116}
1117
1118static Emotion_Format
1119em_format_get(void *ef EINA_UNUSED)
1120{
1121 return EMOTION_FORMAT_BGRA;
1122}
1123
1124static void
1125em_video_data_size_get(void *data, int *w, int *h)
1126{
1127 Emotion_Generic_Video *ev = data;
1128
1129 if (!ev) return;
1130 if (w) *w = ev->w;
1131 if (h) *h = ev->h;
1132}
1133
1134static void
1135em_play(void *data, double pos)
1136{
1137 Emotion_Generic_Video *ev = data;
1138
1139 if (!ev)
1140 return;
1141
1142 ev->play = EINA_TRUE;
1143 INF("play: %0.3f", pos);
1144
1145 if (ev->initializing || ev->opening)
1146 return;
1147
1148 if (ev->ready)
1149 {
1150 if (ev->subtitle_path)
1151 {
1152 _player_send_cmd(ev, EM_CMD_SUBTITLE_SET);
1153 _player_send_str(ev, ev->subtitle_path, EINA_TRUE);
1154 }
1155
1156 _player_send_cmd(ev, EM_CMD_PLAY);
1157 _player_send_float(ev, ev->pos);
1158
1159 return;
1160 }
1161
1162 if (!_player_exec(ev))
1163 ERR("could not start player.");
1164}
1165
1166static void
1167em_stop(void *data)
1168{
1169 Emotion_Generic_Video *ev = data;
1170
1171 if (!ev)
1172 return;
1173
1174 ev->play = EINA_FALSE;
1175
1176 if (!ev->file_ready)
1177 return;
1178
1179 _player_send_cmd(ev, EM_CMD_STOP);
1180 _emotion_decode_stop(ev->obj);
1181}
1182
1183static void
1184em_size_get(void *data, int *w, int *h)
1185{
1186 Emotion_Generic_Video *ev = data;
1187 if (w) *w = ev->w;
1188 if (h) *h = ev->h;
1189}
1190
1191static void
1192em_pos_set(void *data, double pos)
1193{
1194 Emotion_Generic_Video *ev = data;
1195 float position = pos;
1196
1197 if (!ev->file_ready)
1198 return;
1199
1200 _player_send_cmd(ev, EM_CMD_POSITION_SET);
1201 _player_send_float(ev, position);
1202 _emotion_seek_done(ev->obj);
1203}
1204
1205static double
1206em_len_get(void *data)
1207{
1208 Emotion_Generic_Video *ev = data;
1209 return ev->len;
1210}
1211
1212static double
1213em_buffer_size_get(void *data EINA_UNUSED)
1214{
1215 return 1.0;
1216}
1217
1218static int
1219em_fps_num_get(void *data)
1220{
1221 Emotion_Generic_Video *ev = data;
1222 return (int)(ev->fps * 1000.0);
1223}
1224
1225static int
1226em_fps_den_get(void *ef EINA_UNUSED)
1227{
1228 return 1000;
1229}
1230
1231static double
1232em_fps_get(void *data)
1233{
1234 Emotion_Generic_Video *ev = data;
1235 return ev->fps;
1236}
1237
1238static double
1239em_pos_get(void *data)
1240{
1241 Emotion_Generic_Video *ev = data;
1242 return ev->pos;
1243}
1244
1245static void
1246em_vis_set(void *ef EINA_UNUSED, Emotion_Vis vis EINA_UNUSED)
1247{
1248}
1249
1250static Emotion_Vis
1251em_vis_get(void *data)
1252{
1253 Emotion_Generic_Video *ev = data;
1254 return ev->vis;
1255}
1256
1257static Eina_Bool
1258em_vis_supported(void *ef EINA_UNUSED, Emotion_Vis vis EINA_UNUSED)
1259{
1260 return EINA_FALSE;
1261}
1262
1263static double
1264em_ratio_get(void *data)
1265{
1266 Emotion_Generic_Video *ev = data;
1267 return ev->ratio;
1268}
1269
1270static int
1271em_video_handled(void *ef EINA_UNUSED)
1272{
1273 DBG("video handled!");
1274 return 1;
1275}
1276
1277static int
1278em_audio_handled(void *ef EINA_UNUSED)
1279{
1280 DBG("audio handled!");
1281 return 1;
1282}
1283
1284static int
1285em_seekable(void *data)
1286{
1287 Emotion_Generic_Video *ev = data;
1288 return ev->seekable;
1289}
1290
1291static void
1292em_frame_done(void *ef EINA_UNUSED)
1293{
1294}
1295
1296static int
1297em_yuv_rows_get(void *data EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED, unsigned char **yrows EINA_UNUSED, unsigned char **urows EINA_UNUSED, unsigned char **vrows EINA_UNUSED)
1298{
1299 return 0;
1300}
1301
1302static int
1303em_bgra_data_get(void *data, unsigned char **bgra_data)
1304{
1305 Emotion_Generic_Video *ev = data;
1306
1307 if (!ev || !ev->file_ready)
1308 return 0;
1309
1310 // lock frame here
1311 if (!eina_semaphore_lock(&ev->shared->lock))
1312 return 0;
1313
1314 // send current frame to emotion
1315 if (ev->shared->frame.emotion != ev->shared->frame.last)
1316 {
1317 ev->shared->frame.next = ev->shared->frame.emotion;
1318 ev->shared->frame.emotion = ev->shared->frame.last;
1319 }
1320 *bgra_data = ev->frame.frames[ev->shared->frame.emotion];
1321
1322 if (ev->shared->frame_drop > 1)
1323 WRN("dropped frames: %d", ev->shared->frame_drop - 1);
1324 ev->shared->frame_drop = 0;
1325
1326 // unlock frame here
1327 eina_semaphore_release(&ev->shared->lock, 1);
1328 ev->drop = 0;
1329
1330 return 1;
1331}
1332
1333static void
1334em_event_feed(void *ef EINA_UNUSED, int event EINA_UNUSED)
1335{
1336}
1337
1338static void
1339em_event_mouse_button_feed(void *ef EINA_UNUSED, int button EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED)
1340{
1341}
1342
1343static void
1344em_event_mouse_move_feed(void *ef EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED)
1345{
1346}
1347
1348static int
1349em_video_channel_count(void *data)
1350{
1351 Emotion_Generic_Video *ev = data;
1352 return ev->video_channels_count;
1353}
1354
1355static void
1356em_video_channel_set(void *data, int channel)
1357{
1358 Emotion_Generic_Video *ev = data;
1359
1360 if (channel < 0 || channel >= ev->video_channels_count)
1361 {
1362 WRN("video channel out of range.");
1363 return;
1364 }
1365
1366 _player_send_cmd(ev, EM_CMD_VIDEO_TRACK_SET);
1367 _player_send_int(ev, ev->video_channels[channel].id);
1368 ev->video_channel_current = channel;
1369}
1370
1371static int
1372em_video_channel_get(void *data)
1373{
1374 Emotion_Generic_Video *ev = data;
1375 return ev->video_channel_current;
1376}
1377
1378static void
1379em_video_subtitle_file_set(void *data, const char *filepath)
1380{
1381 Emotion_Generic_Video *ev = data;
1382 eina_stringshare_replace(&ev->subtitle_path, filepath);
1383}
1384
1385static const char *
1386em_video_subtitle_file_get(void *data)
1387{
1388 Emotion_Generic_Video *ev = data;
1389 return ev->subtitle_path;
1390}
1391
1392static const char *
1393em_video_channel_name_get(void *data, int channel)
1394{
1395 Emotion_Generic_Video *ev = data;
1396
1397 if (channel < 0 || channel >= ev->video_channels_count)
1398 {
1399 WRN("video channel out of range.");
1400 return NULL;
1401 }
1402
1403 return ev->video_channels[channel].name;
1404}
1405
1406static void
1407em_video_channel_mute_set(void *data, int mute)
1408{
1409 Emotion_Generic_Video *ev = data;
1410
1411 ev->video_mute = !!mute;
1412
1413 if (!ev->file_ready)
1414 return;
1415
1416 _player_send_cmd(ev, EM_CMD_VIDEO_MUTE_SET);
1417 _player_send_int(ev, mute);
1418}
1419
1420static int
1421em_video_channel_mute_get(void *data)
1422{
1423 Emotion_Generic_Video *ev = data;
1424 return ev->video_mute;
1425}
1426
1427static int
1428em_audio_channel_count(void *data)
1429{
1430 Emotion_Generic_Video *ev = data;
1431 return ev->audio_channels_count;
1432}
1433
1434static void
1435em_audio_channel_set(void *data, int channel)
1436{
1437 Emotion_Generic_Video *ev = data;
1438
1439 if (channel < 0 || channel >= ev->audio_channels_count)
1440 {
1441 WRN("audio channel out of range.");
1442 return;
1443 }
1444
1445 _player_send_cmd(ev, EM_CMD_AUDIO_TRACK_SET);
1446 _player_send_int(ev, ev->audio_channels[channel].id);
1447 ev->audio_channel_current = channel;
1448}
1449
1450static int
1451em_audio_channel_get(void *data)
1452{
1453 Emotion_Generic_Video *ev = data;
1454 return ev->audio_channel_current;
1455}
1456
1457static const char *
1458em_audio_channel_name_get(void *data, int channel)
1459{
1460 Emotion_Generic_Video *ev = data;
1461
1462 if (channel < 0 || channel >= ev->audio_channels_count)
1463 {
1464 WRN("audio channel out of range.");
1465 return NULL;
1466 }
1467
1468 return ev->audio_channels[channel].name;
1469}
1470
1471static void
1472em_audio_channel_mute_set(void *data, int mute)
1473{
1474 Emotion_Generic_Video *ev = data;
1475
1476 ev->audio_mute = !!mute;
1477
1478 if (!ev->file_ready)
1479 return;
1480
1481 _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET);
1482 _player_send_int(ev, mute);
1483}
1484
1485static int
1486em_audio_channel_mute_get(void *data)
1487{
1488 Emotion_Generic_Video *ev = data;
1489 return ev->audio_mute;
1490}
1491
1492static void
1493em_audio_channel_volume_set(void *data, double vol)
1494{
1495 Emotion_Generic_Video *ev = data;
1496
1497 if (vol > 1.0) vol = 1.0;
1498 if (vol < 0.0) vol = 0.0;
1499
1500 ev->volume = vol;
1501
1502 if (!ev->file_ready)
1503 return;
1504
1505 _player_send_cmd(ev, EM_CMD_VOLUME_SET);
1506 _player_send_float(ev, ev->volume);
1507}
1508
1509static double
1510em_audio_channel_volume_get(void *data)
1511{
1512 Emotion_Generic_Video *ev = data;
1513 return ev->volume;
1514}
1515
1516static int
1517em_spu_channel_count(void *data)
1518{
1519 Emotion_Generic_Video *ev = data;
1520 return ev->spu_channels_count;
1521}
1522
1523static void
1524em_spu_channel_set(void *data, int channel)
1525{
1526 Emotion_Generic_Video *ev = data;
1527
1528 if (channel < 0 || channel >= ev->spu_channels_count)
1529 {
1530 WRN("spu channel out of range.");
1531 return;
1532 }
1533
1534 _player_send_cmd(ev, EM_CMD_SPU_TRACK_SET);
1535 _player_send_int(ev, ev->spu_channels[channel].id);
1536 ev->spu_channel_current = channel;
1537}
1538
1539static int
1540em_spu_channel_get(void *data)
1541{
1542 Emotion_Generic_Video *ev = data;
1543 return ev->spu_channel_current;
1544}
1545
1546static const char *
1547em_spu_channel_name_get(void *data, int channel)
1548{
1549 Emotion_Generic_Video *ev = data;
1550
1551 if (channel < 0 || channel >= ev->spu_channels_count)
1552 {
1553 WRN("spu channel out of range.");
1554 return NULL;
1555 }
1556
1557 return ev->spu_channels[channel].name;
1558}
1559
1560static void
1561em_spu_channel_mute_set(void *data, int mute)
1562{
1563 Emotion_Generic_Video *ev = data;
1564
1565 ev->spu_mute = !!mute;
1566
1567 if (!ev->file_ready)
1568 return;
1569
1570 _player_send_cmd(ev, EM_CMD_SPU_MUTE_SET);
1571 _player_send_int(ev, mute);
1572}
1573
1574static int
1575em_spu_channel_mute_get(void *data)
1576{
1577 Emotion_Generic_Video *ev = data;
1578 return ev->spu_mute;
1579}
1580
1581static int
1582em_chapter_count(void *ef EINA_UNUSED)
1583{
1584 int num = 0;
1585 return num;
1586}
1587
1588static void
1589em_chapter_set(void *ef EINA_UNUSED, int chapter EINA_UNUSED)
1590{
1591}
1592
1593static int
1594em_chapter_get(void *ef EINA_UNUSED)
1595{
1596 int num = 0;
1597 return num;
1598}
1599
1600static const char *
1601em_chapter_name_get(void *ef EINA_UNUSED, int chapter EINA_UNUSED)
1602{
1603 return NULL;
1604}
1605
1606static void
1607em_speed_set(void *data, double speed)
1608{
1609 Emotion_Generic_Video *ev = data;
1610 float rate = speed;
1611 ev->speed = rate;
1612
1613 if (!ev->file_ready)
1614 return;
1615
1616 _player_send_cmd(ev, EM_CMD_SPEED_SET);
1617 _player_send_float(ev, rate);
1618}
1619
1620static double
1621em_speed_get(void *data)
1622{
1623 Emotion_Generic_Video *ev = data;
1624 return (double)ev->speed;
1625}
1626
1627static int
1628em_eject(void *ef EINA_UNUSED)
1629{
1630 return 1;
1631}
1632
1633static const char *
1634em_meta_get(void *data, int meta)
1635{
1636 Emotion_Generic_Video *ev = data;
1637
1638 switch (meta)
1639 {
1640 case EMOTION_META_INFO_TRACK_TITLE:
1641 return ev->meta.title;
1642 case EMOTION_META_INFO_TRACK_ARTIST:
1643 return ev->meta.artist;
1644 case EMOTION_META_INFO_TRACK_ALBUM:
1645 return ev->meta.album;
1646 case EMOTION_META_INFO_TRACK_YEAR:
1647 return ev->meta.year;
1648 case EMOTION_META_INFO_TRACK_GENRE:
1649 return ev->meta.genre;
1650 case EMOTION_META_INFO_TRACK_COMMENT:
1651 return ev->meta.comment;
1652 case EMOTION_META_INFO_TRACK_DISC_ID:
1653 return ev->meta.disc_id;
1654 case EMOTION_META_INFO_TRACK_COUNT:
1655 return ev->meta.count;
1656 }
1657
1658 return NULL;
1659}
1660
1661
1662/* Players/modules */
1663static const Emotion_Engine em_template_engine =
1664{
1665 EMOTION_ENGINE_API_VERSION,
1666 EMOTION_ENGINE_PRIORITY_DEFAULT,
1667 "generic",
1668 em_add, /* add */
1669 em_del, /* del */
1670 em_file_open, /* file_open */
1671 em_file_close, /* file_close */
1672 em_play, /* play */
1673 em_stop, /* stop */
1674 em_size_get, /* size_get */
1675 em_pos_set, /* pos_set */
1676 em_len_get, /* len_get */
1677 em_buffer_size_get, /* buffer_size_get */
1678 em_fps_num_get, /* fps_num_get */
1679 em_fps_den_get, /* fps_den_get */
1680 em_fps_get, /* fps_get */
1681 em_pos_get, /* pos_get */
1682 em_vis_set, /* vis_set */
1683 em_vis_get, /* vis_get */
1684 em_vis_supported, /* vis_supported */
1685 em_ratio_get, /* ratio_get */
1686 em_video_handled, /* video_handled */
1687 em_audio_handled, /* audio_handled */
1688 em_seekable, /* seekable */
1689 em_frame_done, /* frame_done */
1690 em_format_get, /* format_get */
1691 em_video_data_size_get, /* video_data_size_get */
1692 em_yuv_rows_get, /* yuv_rows_get */
1693 em_bgra_data_get, /* bgra_data_get */
1694 em_event_feed, /* event_feed */
1695 em_event_mouse_button_feed, /* event_mouse_button_feed */
1696 em_event_mouse_move_feed, /* event_mouse_move_feed */
1697 em_video_channel_count, /* video_channel_count */
1698 em_video_channel_set, /* video_channel_set */
1699 em_video_channel_get, /* video_channel_get */
1700 em_video_subtitle_file_set, /* video_subtitle_file_set */
1701 em_video_subtitle_file_get, /* video_subtitle_file_get */
1702 em_video_channel_name_get, /* video_channel_name_get */
1703 em_video_channel_mute_set, /* video_channel_mute_set */
1704 em_video_channel_mute_get, /* video_channel_mute_get */
1705 em_audio_channel_count, /* audio_channel_count */
1706 em_audio_channel_set, /* audio_channel_set */
1707 em_audio_channel_get, /* audio_channel_get */
1708 em_audio_channel_name_get, /* audio_channel_name_get */
1709 em_audio_channel_mute_set, /* audio_channel_mute_set */
1710 em_audio_channel_mute_get, /* audio_channel_mute_get */
1711 em_audio_channel_volume_set, /* audio_channel_volume_set */
1712 em_audio_channel_volume_get, /* audio_channel_volume_get */
1713 em_spu_channel_count, /* spu_channel_count */
1714 em_spu_channel_set, /* spu_channel_set */
1715 em_spu_channel_get, /* spu_channel_get */
1716 em_spu_channel_name_get, /* spu_channel_name_get */
1717 em_spu_channel_mute_set, /* spu_channel_mute_set */
1718 em_spu_channel_mute_get, /* spu_channel_mute_get */
1719 em_chapter_count, /* chapter_count */
1720 em_chapter_set, /* chapter_set */
1721 em_chapter_get, /* chapter_get */
1722 em_chapter_name_get, /* chapter_name_get */
1723 em_speed_set, /* speed_set */
1724 em_speed_get, /* speed_get */
1725 em_eject, /* eject */
1726 em_meta_get, /* meta_get */
1727 NULL, /* priority_set */
1728 NULL, /* priority_get */
1729 NULL /* em_meta_artwork_get */
1730};
1731
1732static void
1733_player_entry_add(const Eina_File_Direct_Info *info)
1734{
1735 Emotion_Engine_Generic *eg;
1736 const char *name;
1737 char *endptr;
1738 int priority;
1739
1740 name = info->path + info->name_start;
1741
1742 priority = strtol(name, &endptr, 10);
1743 if (endptr == name)
1744 priority = EMOTION_ENGINE_PRIORITY_DEFAULT;
1745 else
1746 {
1747 if ((*endptr == '-') || (*endptr == '_'))
1748 endptr++;
1749 name = endptr;
1750 }
1751
1752 if (*name == '\0')
1753 {
1754 ERR("Invalid generic player: %s", info->path);
1755 return;
1756 }
1757
1758 eg = malloc(sizeof(Emotion_Engine_Generic));
1759 EINA_SAFETY_ON_NULL_RETURN(eg);
1760
1761 /* inherit template */
1762 memcpy(&(eg->engine), &em_template_engine, sizeof(em_template_engine));
1763
1764 eg->path = strdup(info->path);
1765 EINA_SAFETY_ON_NULL_GOTO(eg->path, error_path);
1766
1767 eg->engine.name = strdup(name);
1768 EINA_SAFETY_ON_NULL_GOTO(eg->engine.name, error_name);
1769
1770 eg->engine.priority = priority;
1771
1772 DBG("Add player name=%s, priority=%d, path=%s",
1773 eg->engine.name, eg->engine.priority, eg->path);
1774 _generic_players = eina_list_append(_generic_players, eg);
1775
1776 return;
1777
1778 error_name:
1779 free(eg->path);
1780 error_path:
1781 free(eg);
1782}
1783
1784static void
1785_player_entry_free(Emotion_Engine_Generic *eg)
1786{
1787 free(eg->path);
1788 free((void *)eg->engine.name);
1789 free(eg);
1790}
1791
1792static void
1793_players_all_from(const char *path)
1794{
1795 const Eina_File_Direct_Info *info;
1796 int count = 0;
1797 Eina_Iterator *itr = eina_file_direct_ls(path);
1798 if (!itr) goto end;
1799 EINA_ITERATOR_FOREACH(itr, info)
1800 {
1801 if (access(info->path, R_OK | X_OK) == 0)
1802 {
1803 _player_entry_add(info);
1804 count++;
1805 }
1806 }
1807 eina_iterator_free(itr);
1808
1809 end:
1810 if (count == 0)
1811 DBG("No generic players at %s", path);
1812}
1813
1814static void
1815_players_load(void)
1816{
1817 char buf[PATH_MAX];
1818
1819 eina_str_join(buf, sizeof(buf), '/',
1820 eina_prefix_lib_get(pfx),
1821 "emotion/generic_players/" MODULE_ARCH);
1822 _players_all_from(buf);
1823
1824 if (!_generic_players)
1825 {
1826 WRN("no generic players available");
1827 }
1828 else
1829 {
1830 const Eina_List *n;
1831 const Emotion_Engine_Generic *eg;
1832 INF("Found %d generic players", eina_list_count(_generic_players));
1833 EINA_LIST_FOREACH(_generic_players, n, eg)
1834 _emotion_module_register(&(eg->engine));
1835 }
1836}
1837
1838Eina_Bool
1839generic_module_init(void)
1840{
1841 if (_emotion_init_count > 0)
1842 {
1843 _emotion_init_count++;
1844 return EINA_TRUE;
1845 }
1846
1847 _emotion_generic_log_domain = eina_log_domain_register("emotion_generic",
1848 EINA_COLOR_LIGHTCYAN);
1849 if (_emotion_generic_log_domain < 0)
1850 {
1851 EINA_LOG_CRIT("Could not register log domain 'emotion_generic'");
1852 return EINA_FALSE;
1853 }
1854
1855 pfx = eina_prefix_new(NULL, emotion_init,
1856 "EMOTION", "emotion", "checkme",
1857 PACKAGE_BIN_DIR, PACKAGE_LIB_DIR,
1858 PACKAGE_DATA_DIR, PACKAGE_DATA_DIR);
1859 if (!pfx)
1860 {
1861 CRI("Could not get prefix for emotion");
1862 eina_log_domain_unregister(_emotion_generic_log_domain);
1863 _emotion_generic_log_domain = -1;
1864 return EINA_FALSE;
1865 }
1866
1867 _players_load();
1868
1869 _emotion_init_count = 1;
1870 return EINA_TRUE;
1871}
1872
1873void
1874generic_module_shutdown(void)
1875{
1876 Emotion_Engine_Generic *eg;
1877
1878 if (_emotion_init_count > 1)
1879 {
1880 _emotion_init_count--;
1881 return;
1882 }
1883 else if (_emotion_init_count == 0)
1884 {
1885 EINA_LOG_ERR("too many generic_module_shutdown()");
1886 return;
1887 }
1888 _emotion_init_count = 0;
1889
1890 EINA_LIST_FREE(_generic_players, eg)
1891 {
1892 _emotion_module_unregister(&(eg->engine));
1893 _player_entry_free(eg);
1894 }
1895
1896 eina_log_domain_unregister(_emotion_generic_log_domain);
1897 _emotion_generic_log_domain = -1;
1898
1899 eina_prefix_free(pfx);
1900 pfx = NULL;
1901}
1902
1903#ifndef EMOTION_STATIC_BUILD_GENERIC
1904
1905EINA_MODULE_INIT(generic_module_init);
1906EINA_MODULE_SHUTDOWN(generic_module_shutdown);
1907
1908#endif
diff --git a/src/modules/emotion/generic/emotion_generic.h b/src/modules/emotion/generic/emotion_generic.h
deleted file mode 100644
index 2830d33d4a..0000000000
--- a/src/modules/emotion/generic/emotion_generic.h
+++ /dev/null
@@ -1,123 +0,0 @@
1#ifndef EMOTION_GENERIC_H
2#define EMOTION_GENERIC_H
3
4#include <sys/types.h>
5
6#include "Emotion_Generic_Plugin.h"
7
8/* default values */
9
10typedef struct _Emotion_Generic_Video Emotion_Generic_Video;
11typedef struct _Emotion_Generic_Player Emotion_Generic_Player;
12typedef struct _Emotion_Generic_Cmd_Buffer Emotion_Generic_Cmd_Buffer;
13typedef struct _Emotion_Generic_Channel Emotion_Generic_Channel;
14typedef struct _Emotion_Generic_Meta Emotion_Generic_Meta;
15
16struct _Emotion_Generic_Player
17{
18 Ecore_Exe *exe;
19};
20
21struct _Emotion_Generic_Channel
22{
23 int id;
24 const char *name;
25};
26
27struct _Emotion_Generic_Meta
28{
29 const char *title;
30 const char *artist;
31 const char *album;
32 const char *year;
33 const char *genre;
34 const char *comment;
35 const char *disc_id;
36 const char *count;
37};
38
39struct _Emotion_Generic_Cmd_Buffer
40{
41 char *tmp;
42 int type;
43 ssize_t i, total;
44 int s_len;
45 int num_params, cur_param;
46 int padding;
47 union {
48 struct {
49 int width;
50 int height;
51 } size;
52 int i_num;
53 float f_num;
54 struct {
55 int total;
56 int current;
57 Emotion_Generic_Channel *channels;
58 } track;
59 Emotion_Generic_Meta meta;
60 } param;
61};
62
63typedef struct _Emotion_Engine_Generic
64{
65 Emotion_Engine engine;
66 char *path;
67} Emotion_Engine_Generic;
68
69/* emotion/generic main structure */
70struct _Emotion_Generic_Video
71{
72 const Emotion_Engine_Generic *engine;
73 const char *shmname;
74
75 Emotion_Generic_Player player;
76 Emotion_Generic_Cmd_Buffer cmd;
77 Ecore_Event_Handler *player_add, *player_del, *player_data;
78 int drop;
79 Ecore_Pipe *fd_read;
80 Ecore_Pipe *fd_write;
81 const unsigned char *buffer;
82 ssize_t length;
83 ssize_t offset;
84
85 const char *filename;
86 volatile double len;
87 volatile double pos;
88 double fps;
89 double ratio;
90 int w, h;
91 Evas_Object *obj;
92 Emotion_Generic_Video_Shared *shared;
93 Emotion_Generic_Video_Frame frame;
94 volatile int fq;
95 float volume;
96 float speed;
97 Emotion_Vis vis;
98 Eina_Bool initializing : 1;
99 Eina_Bool ready : 1;
100 Eina_Bool play : 1;
101 Eina_Bool video_mute : 1;
102 Eina_Bool audio_mute : 1;
103 Eina_Bool spu_mute : 1;
104 Eina_Bool seekable : 1;
105 volatile Eina_Bool opening : 1;
106 volatile Eina_Bool closing : 1;
107 Eina_Bool file_changed : 1;
108 Eina_Bool file_ready : 1;
109 int audio_channels_count;
110 int audio_channel_current;
111 Emotion_Generic_Channel *audio_channels;
112 int video_channels_count;
113 int video_channel_current;
114 Emotion_Generic_Channel *video_channels;
115 int spu_channels_count;
116 int spu_channel_current;
117 Emotion_Generic_Channel *spu_channels;
118 Emotion_Generic_Meta meta;
119 const char *subtitle_path;
120};
121
122#endif
123
diff --git a/src/modules/emotion/generic/meson.build b/src/modules/emotion/generic/meson.build
deleted file mode 100644
index 4f62c7a43e..0000000000
--- a/src/modules/emotion/generic/meson.build
+++ /dev/null
@@ -1,24 +0,0 @@
1generic_src = files([
2 'emotion_generic.c',
3 'emotion_generic.h',
4])
5
6emotion_generic = declare_dependency(
7 include_directories: include_directories('.'),
8 dependencies: emotion,
9)
10
11if sys_windows == false
12 shared_module(emotion_loader,
13 generic_src,
14 include_directories : config_dir,
15 dependencies: [eina, evas, emotion, generic_deps, rt],
16 install: true,
17 install_dir : mod_install_dir,
18 c_args : package_c_args,
19 )
20
21 install_headers('Emotion_Generic_Plugin.h',
22 install_dir : dir_package_include,
23 )
24endif
diff --git a/src/modules/emotion/libvlc/emotion_libvlc.c b/src/modules/emotion/libvlc/emotion_libvlc.c
deleted file mode 100644
index 1e8f9d69b4..0000000000
--- a/src/modules/emotion/libvlc/emotion_libvlc.c
+++ /dev/null
@@ -1,1555 +0,0 @@
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
42static int _emotion_libvlc_log_domain = -1;
43static Eina_Bool debug_fps = EINA_FALSE;
44static libvlc_instance_t *libvlc = NULL;
45
46typedef struct _Emotion_LibVLC Emotion_LibVLC;
47
48static void em_file_close(void *);
49
50struct _Emotion_LibVLC
51{
52 /* Evas object */
53 Evas_Object *obj;
54 Evas_Object *evas_obj;
55 Emotion_Module_Options opt;
56
57 /* libvlc */
58 libvlc_media_t *m;
59 libvlc_media_player_t *mp;
60 unsigned int nb_tracks;
61 libvlc_media_track_t **tracks;
62 int nb_chapters;
63 libvlc_chapter_description_t **chapters;
64 char *subtitle_file;
65 char *metas[META_TRACK_COUNT];
66
67 /* options */
68 int video_mute;
69 int video_mute_force;
70 int audio_mute;
71 int spu_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
94struct close_data
95{
96 libvlc_media_player_t *mp;
97 Evas_Object *evas_obj;
98};
99
100static const libvlc_event_type_t mp_events[] = {
101 //libvlc_MediaPlayerMediaChanged,
102 //libvlc_MediaPlayerNothingSpecial,
103 //libvlc_MediaPlayerOpening,
104 libvlc_MediaPlayerBuffering,
105 libvlc_MediaPlayerPlaying,
106 //libvlc_MediaPlayerPaused,
107 libvlc_MediaPlayerStopped,
108 libvlc_MediaPlayerForward,
109 //libvlc_MediaPlayerBackward,
110 libvlc_MediaPlayerEndReached,
111 libvlc_MediaPlayerEncounteredError,
112 libvlc_MediaPlayerTimeChanged,
113 //libvlc_MediaPlayerPositionChanged,
114 //libvlc_MediaPlayerSeekableChanged,
115 //libvlc_MediaPlayerPausableChanged,
116 //libvlc_MediaPlayerTitleChanged,
117 //libvlc_MediaPlayerSnapshotTaken,
118 libvlc_MediaPlayerLengthChanged,
119 //libvlc_MediaPlayerVout,
120 //libvlc_MediaPlayerScrambledChanged,
121 libvlc_MediaPlayerESAdded,
122 libvlc_MediaPlayerESDeleted,
123 //libvlc_MediaPlayerESSelected,
124 //libvlc_MediaPlayerCorked,
125 //libvlc_MediaPlayerUncorked,
126 //libvlc_MediaPlayerMuted,
127 //libvlc_MediaPlayerUnmuted,
128 //libvlc_MediaPlayerAudioVolume,
129 //libvlc_MediaPlayerAudioDevice,
130 -1,
131};
132
133static void
134em_del_safe(Emotion_LibVLC *ev)
135{
136 eina_lock_free(&ev->lock);
137 eina_condition_free(&ev->wait);
138 free(ev->subtitle_file);
139 free(ev);
140}
141
142/* Take the ev->lock from a mainloop callback.
143 * Returns false if the ev object is destroyed. */
144static Eina_Bool
145emotion_mainloop_lock(Emotion_LibVLC *ev)
146{
147 eina_lock_take(&ev->lock);
148 _emotion_pending_ecore_end();
149 if (--ev->ref_count == 0)
150 {
151 eina_lock_release(&ev->lock);
152 WRN("callbacks ended, deleting Emotion_LibVLC");
153 em_del_safe(ev);
154 return EINA_FALSE;
155 }
156 return EINA_TRUE;
157}
158
159/* Send a callback to the mainloop */
160static void
161emotion_mainloop_call_locked(Emotion_LibVLC *ev, Ecore_Cb callback)
162{
163 ++ev->ref_count;
164 _emotion_pending_ecore_begin();
165 ecore_main_loop_thread_safe_call_async(callback, ev);
166}
167
168/* Process one libvlc event from the mainloop. */
169static void
170emotion_mainloop_event(Emotion_LibVLC *ev, const libvlc_event_t *event)
171{
172 switch (event->type)
173 {
174 case libvlc_MediaPlayerBuffering:
175 ev->buffer_cache = event->u.media_player_buffering.new_cache / 100.0;
176 break;
177
178 case libvlc_MediaPlayerPlaying:
179 if (!ev->started)
180 {
181 _emotion_open_done(ev->obj);
182 _emotion_playback_started(ev->obj);
183 ev->started = EINA_TRUE;
184 }
185 break;
186
187 case libvlc_MediaPlayerStopped:
188 case libvlc_MediaPlayerEndReached:
189 case libvlc_MediaPlayerEncounteredError:
190 _emotion_decode_stop(ev->obj);
191 _emotion_playback_finished(ev->obj);
192 break;
193
194 case libvlc_MediaPlayerTimeChanged:
195 {
196 if (ev->seeking)
197 {
198 _emotion_seek_done(ev->obj);
199 ev->seeking = EINA_FALSE;
200 }
201
202 ev->pos = event->u.media_player_time_changed.new_time / 1000.0;
203 if (ev->pos > 0 && ev->len > 0)
204 _emotion_video_pos_update(ev->obj, ev->pos, ev->len);
205 break;
206 }
207
208 case libvlc_MediaPlayerLengthChanged:
209 ev->len = event->u.media_player_length_changed.new_length / 1000.0;
210 if (ev->pos > 0 && ev->len > 0)
211 _emotion_video_pos_update(ev->obj, ev->pos, ev->len);
212 break;
213
214 case libvlc_MediaPlayerESAdded:
215 case libvlc_MediaPlayerESDeleted:
216 ev->invalidate_tracks = EINA_TRUE;
217 _emotion_channels_change(ev->obj);
218 break;
219 }
220}
221
222/* Mainloop callback, sent by libvlc_on_mp_event. It processes a list of libvlc
223 * event. */
224static void
225emotion_mainloop_event_list(void *data)
226{
227 Emotion_LibVLC *ev = data;
228 Eina_List *event_list;
229 libvlc_event_t *event;
230
231 if (!emotion_mainloop_lock(ev)) return;
232 event_list = ev->event_list;
233 ev->event_list = NULL;
234 eina_lock_release(&ev->lock);
235
236 if (!event_list) return;
237
238 EINA_LIST_FREE(event_list, event)
239 {
240 if (ev->mp)
241 emotion_mainloop_event(ev, event);
242 free(event);
243 }
244}
245
246/* Libvlc callback, see libvlc_event_manager_t. */
247static void
248libvlc_on_mp_event(const libvlc_event_t *event, void *opaque)
249{
250 Emotion_LibVLC *ev = opaque;
251
252 if (eina_main_loop_is())
253 {
254 /* Process the event directly */
255 emotion_mainloop_event(ev, event);
256 }
257 else
258 {
259 /* Add the event to a list of events that will be processed by the
260 * mainloop */
261
262 void *data = malloc(sizeof(libvlc_event_t));
263 if (!data) return;
264 memcpy(data, event, sizeof(libvlc_event_t));
265
266 eina_lock_take(&ev->lock);
267 if (!ev->event_list)
268 emotion_mainloop_call_locked(ev, emotion_mainloop_event_list);
269 ev->event_list = eina_list_append(ev->event_list, data);
270 eina_lock_release(&ev->lock);
271 }
272}
273
274static void
275evas_resize_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED,
276 void *event EINA_UNUSED)
277{
278 Emotion_LibVLC *ev = data;
279 int w, h;
280
281 evas_object_image_size_get(ev->evas_obj, &w, &h);
282 _emotion_frame_resize(ev->obj, w, h, w / (double) h);
283 efl_event_callback_call(ev->obj, EFL_CANVAS_VIDEO_EVENT_FRAME_DECODE, NULL);
284}
285
286/* Fetch all libvlc tracks. */
287static int
288libvlc_fetch_tracks(Emotion_LibVLC *ev)
289{
290 if (ev->invalidate_tracks)
291 {
292 if (ev->nb_tracks)
293 libvlc_media_tracks_release(ev->tracks, ev->nb_tracks);
294 ev->nb_tracks = libvlc_media_tracks_get(ev->m, &ev->tracks);
295 ev->invalidate_tracks = EINA_FALSE;
296 }
297 return ev->nb_tracks;
298}
299
300/* Get a libvlc tracks from a track_id. */
301static libvlc_media_track_t *
302libvlc_get_track(Emotion_LibVLC *ev, libvlc_track_type_t type, int id)
303{
304 unsigned int i;
305
306 if (!ev->m || id < 0 || type == libvlc_track_unknown) return NULL;
307
308 if (!libvlc_fetch_tracks(ev)) return NULL;
309
310 for (i = 0; i < ev->nb_tracks; ++i)
311 {
312 libvlc_media_track_t *track = ev->tracks[i];
313
314 if (track->i_id == id && track->i_type == type)
315 return track;
316 }
317
318 return NULL;
319}
320
321/* Get the current libvlc video track. */
322static libvlc_media_track_t *
323libvlc_get_current_video_track(Emotion_LibVLC *ev)
324{
325 int id = libvlc_video_get_track(ev->mp);
326 return id >= 0 ? libvlc_get_track(ev, libvlc_track_video, id) : NULL;
327}
328
329/* Get a libvlc video track at a pos.
330 * XXX: Libvlc use a track_id to get and select a track. The first track_id doesn't
331 * necessarily starts with 0. Emotion use a position (that starts with 0) to
332 * get and select a track. */
333static libvlc_media_track_t *
334libvlc_get_track_at_pos(Emotion_LibVLC *ev,
335 int pos, libvlc_track_type_t type)
336{
337 unsigned int i;
338
339 if (!ev->m || pos < 0 || type == libvlc_track_unknown) return NULL;
340
341 if (!libvlc_fetch_tracks(ev)) return NULL;
342
343 for (i = 0; i < ev->nb_tracks; ++i)
344 {
345 libvlc_media_track_t *track = ev->tracks[i];
346
347 if (type == track->i_type && pos-- == 0)
348 return track;
349 }
350
351 return NULL;
352}
353
354/* Get the position of the libvlc track.
355 * See libvlc_get_track_at_pos. */
356static int
357libvlc_get_track_pos(Emotion_LibVLC *ev, int id, libvlc_track_type_t type)
358{
359 unsigned int i;
360 int pos = 0;
361
362 if (!ev->m || id < 0 || type == libvlc_track_unknown) return -1;
363
364 if (!libvlc_fetch_tracks(ev)) return -1;
365
366 for (i = 0; i < ev->nb_tracks; ++i)
367 {
368 libvlc_media_track_t *track = ev->tracks[i];
369
370 if (type == track->i_type)
371 {
372 if (id == track->i_id)
373 return pos;
374 else
375 pos++;
376 }
377 }
378
379 return -1;
380}
381
382static void *
383em_add(const Emotion_Engine *api EINA_UNUSED,
384 Evas_Object *obj,
385 const Emotion_Module_Options *opt)
386{
387 Emotion_LibVLC *ev;
388 ev = calloc(1, sizeof(Emotion_LibVLC));
389 EINA_SAFETY_ON_NULL_RETURN_VAL(ev, NULL);
390
391 ev->obj = obj;
392 ev->opt = *opt;
393 eina_lock_new(&ev->lock);
394 eina_condition_new(&ev->wait, &ev->lock);
395 ev->ref_count = 1;
396 ev->audio_vol = -1;
397
398 return ev;
399}
400
401static void
402em_del(void *video)
403{
404 Emotion_LibVLC *ev = video;
405
406 if (!ev) return;
407
408 em_file_close(video);
409
410 eina_lock_take(&ev->lock);
411 if (--ev->ref_count > 0)
412 {
413 eina_lock_release(&ev->lock);
414 WRN("em_del delayed, some callbacks are still running");
415 }
416 else
417 {
418 eina_lock_release(&ev->lock);
419 em_del_safe(ev);
420 }
421}
422
423static Eina_Bool
424em_file_open(void *video,
425 const char *file)
426{
427 int ret, i;
428 Emotion_LibVLC *ev = video;
429 libvlc_event_manager_t *event_m;
430
431 if (!file) return EINA_FALSE;
432
433 ev->evas_obj = emotion_object_image_get(ev->obj);
434 if (!ev->evas_obj)
435 {
436 WRN("emotion_object_image_get failed: no video");
437 ev->opt.no_video = EINA_TRUE;
438 }
439
440 evas_object_image_pixels_get_callback_set(ev->evas_obj, NULL, NULL);
441
442 ev->invalidate_tracks = true;
443
444 /* Create libvlc_media */
445 ev->m = libvlc_media_new_path(libvlc, file);
446 if (strstr(file, "://") == NULL)
447 ev->m = libvlc_media_new_path(libvlc, file);
448 else
449 ev->m = libvlc_media_new_location(libvlc, file);
450
451 EINA_SAFETY_ON_NULL_GOTO(ev->m, error);
452
453 if (ev->opt.no_audio || ev->audio_mute)
454 libvlc_media_add_option(ev->m, ":no-audio");
455
456 if (ev->opt.no_video || ev->video_mute)
457 libvlc_media_add_option(ev->m, ":no-video");
458
459 if (ev->spu_mute)
460 libvlc_media_add_option(ev->m, ":no-spu");
461
462 /* Create libvlc_media_player */
463 ev->mp = libvlc_media_player_new_from_media(ev->m);
464 EINA_SAFETY_ON_NULL_GOTO(ev->mp, error);
465
466 event_m = libvlc_media_player_event_manager(ev->mp);
467 for (i = 0; mp_events[i] != -1; ++i)
468 libvlc_event_attach(event_m, mp_events[i], libvlc_on_mp_event, ev);
469
470 libvlc_media_player_set_video_title_display(ev->mp,
471 libvlc_position_disable, 0);
472
473 evas_object_ref(ev->evas_obj);
474 if (libvlc_media_player_set_evas_object(ev->mp, ev->evas_obj) == -1)
475 {
476 CRI("libvlc_media_player_set_evas_object failed");
477 libvlc_media_add_option(ev->m, ":no-video");
478 ev->video_mute = ev->video_mute_force = 1;
479 }
480
481 evas_object_event_callback_add(ev->evas_obj, EVAS_CALLBACK_IMAGE_RESIZE,
482 evas_resize_cb, ev);
483
484 if (ev->audio_vol != -1)
485 libvlc_audio_set_volume(ev->mp, ev->audio_vol);
486
487 ret = libvlc_media_player_play(ev->mp);
488 EINA_SAFETY_ON_FALSE_GOTO(ret == 0, error);
489
490 return EINA_TRUE;
491error:
492 em_file_close(video);
493 return EINA_FALSE;
494}
495
496static void
497emotion_close_cb(void *data, Ecore_Thread *thread EINA_UNUSED)
498{
499 struct close_data *close_data = data;
500
501 libvlc_media_player_release(close_data->mp);
502}
503
504static void
505emotion_close_mainloop_cb(void *data,
506 Ecore_Thread *thread EINA_UNUSED)
507{
508 struct close_data *close_data = data;
509
510 evas_object_unref(close_data->evas_obj);
511 free(close_data);
512 _emotion_pending_ecore_end();
513}
514
515static void
516em_file_close(void *video)
517{
518 Emotion_LibVLC *ev = video;
519 unsigned int i;
520
521 if (ev->mp)
522 {
523 struct close_data *close_data;
524 libvlc_event_manager_t *event_m;
525
526 evas_object_event_callback_del(ev->evas_obj, EVAS_CALLBACK_IMAGE_RESIZE,
527 evas_resize_cb);
528
529 event_m = libvlc_media_player_event_manager(ev->mp);
530 for (i = 0; mp_events[i] != -1; ++i)
531 libvlc_event_detach(event_m, mp_events[i], libvlc_on_mp_event, ev);
532
533 libvlc_media_player_set_evas_object(ev->mp, NULL);
534
535 close_data = malloc(sizeof(struct close_data));
536 if (close_data)
537 {
538 close_data->evas_obj = ev->evas_obj;
539 close_data->mp = ev->mp;
540 _emotion_pending_ecore_begin();
541 ecore_thread_run(emotion_close_cb,
542 emotion_close_mainloop_cb,
543 NULL, close_data);
544 }
545
546 ev->evas_obj = NULL;
547 ev->mp = NULL;
548
549 if (ev->seeking)
550 {
551 ev->seeking = EINA_FALSE;
552 _emotion_seek_done(ev->obj);
553 }
554 }
555 if (ev->m)
556 {
557 libvlc_media_release(ev->m);
558 ev->m = NULL;
559 }
560 if (ev->nb_tracks > 0)
561 {
562 libvlc_media_tracks_release(ev->tracks, ev->nb_tracks);
563 ev->nb_tracks = 0;
564 ev->tracks = NULL;
565 }
566 if (ev->nb_chapters > 0)
567 {
568 libvlc_chapter_descriptions_release(ev->chapters, ev->nb_chapters);
569 ev->nb_chapters = 0;
570 ev->chapters = NULL;
571 }
572 for (i = 0; i < META_TRACK_COUNT; ++i)
573 {
574 free(ev->metas[i]);
575 ev->metas[i] = NULL;
576 }
577 if (ev->subtitle_file)
578