Add generic player backend (with vlc player).
This generic player backend executes a separate player in another process. It receives the bytes to be drawn on the emotion object through a shared memory, and communicates with the player through a pipe, using the player standard input/output. The player must communicate with emotion using the defined commands specified in the Emotion_Generic_Plugin.h. It doesn't need to link against emotion, just include this file for easier implementation. This implementation was sponsored by Zodiac Aerospace. SVN revision: 63062
This commit is contained in:
parent
1cacec0d41
commit
a7ae4566b8
|
@ -3,4 +3,4 @@ Vincent Torri <torri@maths.univ-evry.fr>
|
|||
Nicolas Aguirre <aguirre.nicolas@gmail.com>
|
||||
Sebastian Dransfeld <sd@tango.flipp.net>
|
||||
Cedric Bail <cedric.bail@free.fr>
|
||||
|
||||
Rafael Antognolli <antognolli@profusion.mobi>
|
||||
|
|
|
@ -54,6 +54,7 @@ VMAJ=v_maj
|
|||
AC_SUBST(VMAJ)
|
||||
|
||||
want_vlc="no"
|
||||
want_generic="yes"
|
||||
case "$host_os" in
|
||||
mingw* | cegcc*)
|
||||
want_xine="no"
|
||||
|
@ -230,6 +231,7 @@ AC_MSG_RESULT([${have_v4l2}])
|
|||
EMOTION_CHECK_MODULE([Xine], [${want_xine}])
|
||||
EMOTION_CHECK_MODULE([Gstreamer], [${want_gstreamer}])
|
||||
EMOTION_CHECK_MODULE([VLC], [${want_vlc}])
|
||||
EMOTION_CHECK_MODULE([generic], [${want_generic}])
|
||||
|
||||
#disabled vlc
|
||||
#if test "x${enable_xine}" = "xno" && test "x${enable_gstreamer}" = "xno" && test "x${enable_vlc}" = "xno" ; then
|
||||
|
@ -269,7 +271,10 @@ src/lib/Makefile
|
|||
src/modules/Makefile
|
||||
src/modules/xine/Makefile
|
||||
src/modules/gstreamer/Makefile
|
||||
src/modules/generic/Makefile
|
||||
src/edje_external/Makefile
|
||||
src/generic_players/Makefile
|
||||
src/generic_players/vlc/Makefile
|
||||
src/bin/Makefile
|
||||
src/examples/Makefile
|
||||
doc/Makefile
|
||||
|
|
|
@ -71,6 +71,28 @@ AS_IF([test "x$have_dep" = "xyes"], [$2], [$3])
|
|||
|
||||
])
|
||||
|
||||
dnl use: EMOTION_CHECK_DEP_GENERIC(want_static[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
|
||||
|
||||
AC_DEFUN([EMOTION_CHECK_DEP_GENERIC],
|
||||
[
|
||||
|
||||
requirement=""
|
||||
|
||||
PKG_CHECK_MODULES([GENERIC],
|
||||
[evas >= 0.9.9],
|
||||
[
|
||||
have_dep="yes"
|
||||
],
|
||||
[have_dep="no"])
|
||||
|
||||
if test "x$1" = "xstatic" ; then
|
||||
requirement_emotion="${requirement} ${requirement_emotion}"
|
||||
fi
|
||||
|
||||
AS_IF([test "x$have_dep" = "xyes"], [$2], [$3])
|
||||
|
||||
])
|
||||
|
||||
dnl use: EMOTION_CHECK_MODULE(description, want_module[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
|
||||
AC_DEFUN([EMOTION_CHECK_MODULE],
|
||||
[
|
||||
|
|
|
@ -6,3 +6,7 @@ SUBDIRS = lib bin modules examples
|
|||
if ENABLE_EDJE_EXTERNAL
|
||||
SUBDIRS += edje_external
|
||||
endif
|
||||
|
||||
if EMOTION_BUILD_GENERIC
|
||||
SUBDIRS += generic_players
|
||||
endif
|
||||
|
|
|
@ -16,6 +16,7 @@ LDADD = \
|
|||
|
||||
SRCS = \
|
||||
emotion_basic_example.c \
|
||||
emotion_generic_example.c \
|
||||
emotion_signals_example.c
|
||||
|
||||
EXTRA_DIST = $(SRCS)
|
||||
|
@ -30,6 +31,7 @@ endif
|
|||
if EFL_BUILD_EXAMPLES
|
||||
pkglib_PROGRAMS += \
|
||||
emotion_basic_example \
|
||||
emotion_generic_example \
|
||||
emotion_signals_example
|
||||
endif
|
||||
|
||||
|
|
|
@ -0,0 +1,209 @@
|
|||
#include <Ecore.h>
|
||||
#include <Ecore_Evas.h>
|
||||
#include <Evas.h>
|
||||
#include <Emotion.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define WIDTH (320)
|
||||
#define HEIGHT (240)
|
||||
|
||||
static Eina_List *filenames = NULL;
|
||||
static Eina_List *curfile = NULL;
|
||||
|
||||
static void
|
||||
_playback_started_cb(void *data, Evas_Object *o, void *event_info)
|
||||
{
|
||||
printf("Emotion object started playback.\n");
|
||||
}
|
||||
|
||||
static Evas_Object *
|
||||
_create_emotion_object(Evas *e)
|
||||
{
|
||||
Evas_Object *em = emotion_object_add(e);
|
||||
|
||||
emotion_object_init(em, "generic");
|
||||
|
||||
evas_object_smart_callback_add(
|
||||
em, "playback_started", _playback_started_cb, NULL);
|
||||
|
||||
return em;
|
||||
}
|
||||
|
||||
static void
|
||||
_on_key_down(void *data, Evas *e, Evas_Object *o, void *event_info)
|
||||
{
|
||||
Evas_Event_Key_Down *ev = event_info;
|
||||
Evas_Object *em = data;
|
||||
|
||||
if (!strcmp(ev->keyname, "Return"))
|
||||
{
|
||||
emotion_object_play_set(em, EINA_TRUE);
|
||||
}
|
||||
else if (!strcmp(ev->keyname, "space"))
|
||||
{
|
||||
emotion_object_play_set(em, EINA_FALSE);
|
||||
}
|
||||
else if (!strcmp(ev->keyname, "Escape"))
|
||||
{
|
||||
ecore_main_loop_quit();
|
||||
}
|
||||
else if (!strcmp(ev->keyname, "t"))
|
||||
{
|
||||
int w, h;
|
||||
emotion_object_size_get(em, &w, &h);
|
||||
fprintf(stderr, "example -> size: %dx%d\n", w, h);
|
||||
}
|
||||
else if (!strcmp(ev->keyname, "s"))
|
||||
{
|
||||
fprintf(stderr, "skipping to position 60\n");
|
||||
emotion_object_position_set(em, 60);
|
||||
}
|
||||
else if (!strcmp(ev->keyname, "1"))
|
||||
{
|
||||
fprintf(stderr, "setting speed to 1.0\n");
|
||||
emotion_object_play_speed_set(em, 1.0);
|
||||
}
|
||||
else if (!strcmp(ev->keyname, "2"))
|
||||
{
|
||||
fprintf(stderr, "setting speed to 2.0\n");
|
||||
emotion_object_play_speed_set(em, 2.0);
|
||||
}
|
||||
else if (!strcmp(ev->keyname, "n"))
|
||||
{
|
||||
const char *file;
|
||||
curfile = eina_list_next(curfile);
|
||||
file = eina_list_data_get(curfile);
|
||||
fprintf(stderr, "playing next file: %s\n", file);
|
||||
emotion_object_file_set(em, file);
|
||||
}
|
||||
else if (!strcmp(ev->keyname, "p"))
|
||||
{
|
||||
const char *file;
|
||||
curfile = eina_list_prev(curfile);
|
||||
file = eina_list_data_get(curfile);
|
||||
fprintf(stderr, "playing next file: %s\n", file);
|
||||
emotion_object_file_set(em, file);
|
||||
}
|
||||
else if (!strcmp(ev->keyname, "d"))
|
||||
{
|
||||
evas_object_del(em);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "unhandled key: %s\n", ev->keyname);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_frame_decode_cb(void *data, Evas_Object *o, void *event_info)
|
||||
{
|
||||
// fprintf(stderr, "smartcb: frame_decode\n");
|
||||
}
|
||||
|
||||
static void
|
||||
_length_change_cb(void *data, Evas_Object *o, void *event_info)
|
||||
{
|
||||
fprintf(stderr, "smartcb: length_change: %0.3f\n", emotion_object_play_length_get(o));
|
||||
}
|
||||
|
||||
static void
|
||||
_position_update_cb(void *data, Evas_Object *o, void *event_info)
|
||||
{
|
||||
fprintf(stderr, "smartcb: position_update: %0.3f\n", emotion_object_position_get(o));
|
||||
}
|
||||
|
||||
static void
|
||||
_progress_change_cb(void *data, Evas_Object *o, void *event_info)
|
||||
{
|
||||
fprintf(stderr, "smartcb: progress_change: %0.3f, %s\n",
|
||||
emotion_object_progress_status_get(o),
|
||||
emotion_object_progress_info_get(o));
|
||||
}
|
||||
|
||||
static void
|
||||
_frame_resize_cb(void *data, Evas_Object *o, void *event_info)
|
||||
{
|
||||
int w, h;
|
||||
emotion_object_size_get(o, &w, &h);
|
||||
fprintf(stderr, "smartcb: frame_resize: %dx%d\n", w, h);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, const char *argv[])
|
||||
{
|
||||
int err;
|
||||
Ecore_Evas *ee;
|
||||
Evas *e;
|
||||
Evas_Object *bg, *em;
|
||||
int i;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("One argument is necessary. Usage:\n");
|
||||
printf("\t%s <filename>\n", argv[0]);
|
||||
}
|
||||
|
||||
eina_init();
|
||||
for (i = 1; i < argc; i++)
|
||||
filenames = eina_list_append(filenames, eina_stringshare_add(argv[i]));
|
||||
|
||||
curfile = filenames;
|
||||
|
||||
if (!ecore_evas_init())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
/* this will give you a window with an Evas canvas under the first
|
||||
* engine available */
|
||||
ee = ecore_evas_new(NULL, 10, 10, WIDTH, HEIGHT, NULL);
|
||||
if (!ee)
|
||||
goto error;
|
||||
|
||||
ecore_evas_show(ee);
|
||||
|
||||
/* the canvas pointer, de facto */
|
||||
e = ecore_evas_get(ee);
|
||||
|
||||
/* adding a background to this example */
|
||||
bg = evas_object_rectangle_add(e);
|
||||
evas_object_name_set(bg, "our dear rectangle");
|
||||
evas_object_color_set(bg, 255, 255, 255, 255); /* white bg */
|
||||
evas_object_move(bg, 0, 0); /* at canvas' origin */
|
||||
evas_object_resize(bg, WIDTH, HEIGHT); /* covers full canvas */
|
||||
evas_object_show(bg);
|
||||
|
||||
/* Creating the emotion object */
|
||||
em = _create_emotion_object(e);
|
||||
emotion_object_file_set(em, eina_list_data_get(curfile));
|
||||
evas_object_move(em, 0, 0);
|
||||
evas_object_resize(em, WIDTH, HEIGHT);
|
||||
evas_object_show(em);
|
||||
|
||||
evas_object_smart_callback_add(em, "frame_decode", _frame_decode_cb, NULL);
|
||||
evas_object_smart_callback_add(em, "length_change", _length_change_cb, NULL);
|
||||
evas_object_smart_callback_add(em, "position_update", _position_update_cb, NULL);
|
||||
evas_object_smart_callback_add(em, "progress_change", _progress_change_cb, NULL);
|
||||
evas_object_smart_callback_add(em, "frame_resize", _frame_resize_cb, NULL);
|
||||
|
||||
evas_object_event_callback_add(bg, EVAS_CALLBACK_KEY_DOWN, _on_key_down, em);
|
||||
evas_object_focus_set(bg, EINA_TRUE);
|
||||
|
||||
emotion_object_play_set(em, EINA_TRUE);
|
||||
|
||||
ecore_main_loop_begin();
|
||||
|
||||
ecore_evas_free(ee);
|
||||
ecore_evas_shutdown();
|
||||
return 0;
|
||||
|
||||
error:
|
||||
fprintf(stderr, "you got to have at least one evas engine built and linked"
|
||||
" up to ecore-evas for this example to run properly.\n");
|
||||
|
||||
EINA_LIST_FREE(filenames, curfile)
|
||||
eina_stringshare_del(eina_list_data_get(curfile));
|
||||
|
||||
ecore_evas_shutdown();
|
||||
eina_shutdown();
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
SUBDIRS =
|
||||
|
||||
if EMOTION_BUILD_VLC
|
||||
SUBDIRS += vlc
|
||||
endif
|
|
@ -0,0 +1,19 @@
|
|||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/src/lib \
|
||||
-I$(top_srcdir)/src/modules \
|
||||
-I$(top_srcdir)/src/modules/generic \
|
||||
-DPACKAGE_BIN_DIR=\"$(bindir)\" \
|
||||
-DPACKAGE_LIB_DIR=\"$(libdir)\" \
|
||||
-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
|
||||
@VLC_CFLAGS@
|
||||
|
||||
pkgdir = $(libdir)/emotion/generic_players/$(MODULE_ARCH)
|
||||
|
||||
bin_PROGRAMS = em_generic_vlc
|
||||
|
||||
em_generic_vlc_SOURCES = emotion_generic_vlc.c
|
||||
em_generic_vlc_DEPENDENCIES = $(top_srcdir)/src/modules/generic/Emotion_Generic_Plugin.h
|
||||
em_generic_vlc_LDADD = @VLC_LIBS@
|
|
@ -0,0 +1,700 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <vlc/vlc.h>
|
||||
#include <Emotion_Generic_Plugin.h>
|
||||
|
||||
enum _Thread_Events {
|
||||
EM_THREAD_POSITION_CHANGED,
|
||||
EM_THREAD_LAST
|
||||
};
|
||||
|
||||
struct _App {
|
||||
Emotion_Generic_Video_Shared *vs;
|
||||
Emotion_Generic_Video_Frame vf;
|
||||
libvlc_instance_t *libvlc;
|
||||
libvlc_media_t *m;
|
||||
libvlc_media_player_t *mp;
|
||||
libvlc_event_manager_t *event_mgr;
|
||||
libvlc_event_manager_t *mevent_mgr;
|
||||
char *filename;
|
||||
char *shmname;
|
||||
int w, h;
|
||||
int fd_read;
|
||||
int fd_write;
|
||||
int size_sent;
|
||||
int opening;
|
||||
int closing;
|
||||
int playing;
|
||||
};
|
||||
|
||||
static pthread_mutex_t _mutex_fd = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
int
|
||||
_em_read_safe(int fd, void *buf, ssize_t size)
|
||||
{
|
||||
ssize_t todo;
|
||||
char *p;
|
||||
|
||||
todo = size;
|
||||
p = buf;
|
||||
|
||||
while (todo > 0)
|
||||
{
|
||||
ssize_t r;
|
||||
|
||||
r = read(fd, p, todo);
|
||||
if (r > 0)
|
||||
{
|
||||
todo -= r;
|
||||
p += r;
|
||||
}
|
||||
else if (r == 0)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "could not read from fd %d: %s",
|
||||
fd, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
_em_write_safe(int fd, const void *buf, ssize_t size)
|
||||
{
|
||||
ssize_t todo;
|
||||
const char *p;
|
||||
|
||||
todo = size;
|
||||
p = buf;
|
||||
|
||||
while (todo > 0)
|
||||
{
|
||||
ssize_t r;
|
||||
|
||||
r = write(fd, p, todo);
|
||||
if (r > 0)
|
||||
{
|
||||
todo -= r;
|
||||
p += r;
|
||||
}
|
||||
else if (r == 0)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "could not write to fd %d: %s",
|
||||
fd, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_em_str_read(char **str)
|
||||
{
|
||||
int size;
|
||||
int r;
|
||||
char buf[PATH_MAX];
|
||||
|
||||
r = _em_read_safe(STDIN_FILENO, &size, sizeof(size));
|
||||
if (!r)
|
||||
{
|
||||
*str = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!size)
|
||||
{
|
||||
*str = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = _em_read_safe(STDIN_FILENO, buf, size);
|
||||
if (!r)
|
||||
{
|
||||
*str = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*str = strdup(buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_em_cmd_read(void)
|
||||
{
|
||||
int cmd;
|
||||
_em_read_safe(STDIN_FILENO, &cmd, sizeof(cmd));
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
static void
|
||||
_send_cmd_start(int cmd)
|
||||
{
|
||||
pthread_mutex_lock(&_mutex_fd);
|
||||
_em_write_safe(STDOUT_FILENO, &cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
static void
|
||||
_send_cmd_finish(void)
|
||||
{
|
||||
static const char c = '\n';
|
||||
_em_write_safe(STDOUT_FILENO, &c, sizeof(c));
|
||||
pthread_mutex_unlock(&_mutex_fd);
|
||||
}
|
||||
|
||||
static void
|
||||
_send_cmd(int cmd)
|
||||
{
|
||||
_send_cmd_start(cmd);
|
||||
_send_cmd_finish();
|
||||
}
|
||||
|
||||
static void
|
||||
_send_cmd_str(const char *str)
|
||||
{
|
||||
int len;
|
||||
len = strlen(str) + 1;
|
||||
_em_write_safe(STDOUT_FILENO, &len, sizeof(len));
|
||||
_em_write_safe(STDOUT_FILENO, str, len);
|
||||
}
|
||||
|
||||
#define SEND_CMD_PARAM(i) \
|
||||
_em_write_safe(STDOUT_FILENO, &(i), sizeof((i)));
|
||||
|
||||
static void
|
||||
_send_resize(int width, int height)
|
||||
{
|
||||
_send_cmd_start(EM_RESULT_FRAME_SIZE);
|
||||
SEND_CMD_PARAM(width);
|
||||
SEND_CMD_PARAM(height);
|
||||
_send_cmd_finish();
|
||||
}
|
||||
|
||||
static void
|
||||
_send_length_changed(const struct libvlc_event_t *ev)
|
||||
{
|
||||
float length = ev->u.media_player_length_changed.new_length;
|
||||
length /= 1000;
|
||||
|
||||
fprintf(stderr, "length changed: %0.3f\n", length);
|
||||
_send_cmd_start(EM_RESULT_LENGTH_CHANGED);
|
||||
SEND_CMD_PARAM(length);
|
||||
_send_cmd_finish();
|
||||
}
|
||||
|
||||
static void
|
||||
_send_time_changed(const struct libvlc_event_t *ev)
|
||||
{
|
||||
float new_time = ev->u.media_player_time_changed.new_time;
|
||||
new_time /= 1000;
|
||||
_send_cmd_start(EM_RESULT_POSITION_CHANGED);
|
||||
SEND_CMD_PARAM(new_time);
|
||||
_send_cmd_finish();
|
||||
}
|
||||
|
||||
static void
|
||||
_send_seekable_changed(const struct libvlc_event_t *ev)
|
||||
{
|
||||
int seekable = ev->u.media_player_seekable_changed.new_seekable;
|
||||
_send_cmd_start(EM_RESULT_SEEKABLE_CHANGED);
|
||||
SEND_CMD_PARAM(seekable);
|
||||
_send_cmd_finish();
|
||||
}
|
||||
|
||||
static void *
|
||||
_lock(void *data, void **pixels)
|
||||
{
|
||||
struct _App *app = data;
|
||||
|
||||
if (app->playing)
|
||||
*pixels = app->vf.frames[app->vs->frame.player];
|
||||
else
|
||||
*pixels = NULL;
|
||||
|
||||
return NULL; // picture identifier, not needed here
|
||||
}
|
||||
|
||||
static void
|
||||
_unlock(void *data, void *id, void *const *pixels)
|
||||
{
|
||||
struct _App *app = data;
|
||||
|
||||
if (!app->playing)
|
||||
return;
|
||||
|
||||
sem_wait(&app->vs->lock);
|
||||
app->vs->frame.last = app->vs->frame.player;
|
||||
app->vs->frame.player = app->vs->frame.next;
|
||||
app->vs->frame.next = app->vs->frame.last;
|
||||
|
||||
sem_post(&app->vs->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
_display(void *data, void *id)
|
||||
{
|
||||
struct _App *app = data;
|
||||
if (!app->playing)
|
||||
return;
|
||||
|
||||
_send_cmd(EM_RESULT_FRAME_NEW);
|
||||
}
|
||||
|
||||
static void *
|
||||
_tmp_lock(void *data, void **pixels)
|
||||
{
|
||||
*pixels = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_tmp_unlock(void *data, void *id, void *const *pixels)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
_tmp_display(void *data, void *id)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
_play(struct _App *app)
|
||||
{
|
||||
float pos;
|
||||
|
||||
if (!app->mp)
|
||||
return;
|
||||
|
||||
_em_read_safe(STDIN_FILENO, &pos, sizeof(pos));
|
||||
|
||||
if (app->playing)
|
||||
{
|
||||
libvlc_media_player_set_pause(app->mp, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
libvlc_time_t new_time = pos * 1000;
|
||||
libvlc_media_player_play(app->mp);
|
||||
libvlc_media_player_set_time(app->mp, new_time);
|
||||
app->playing = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_stop(struct _App *app)
|
||||
{
|
||||
if (app->mp)
|
||||
libvlc_media_player_set_pause(app->mp, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
_send_file_closed(struct _App *app)
|
||||
{
|
||||
app->closing = 0;
|
||||
emotion_generic_shm_free(app->vs);
|
||||
_send_cmd(EM_RESULT_FILE_CLOSE);
|
||||
}
|
||||
|
||||
static void
|
||||
_send_file_set(struct _App *app)
|
||||
{
|
||||
if (app->opening)
|
||||
_send_cmd(EM_RESULT_FILE_SET);
|
||||
|
||||
if (app->closing)
|
||||
_send_file_closed(app);
|
||||
}
|
||||
|
||||
static void
|
||||
_event_cb(const struct libvlc_event_t *ev, void *data)
|
||||
{
|
||||
struct _App *app = data;
|
||||
int thread_event;
|
||||
|
||||
switch (ev->type) {
|
||||
case libvlc_MediaPlayerTimeChanged:
|
||||
_send_time_changed(ev);
|
||||
break;
|
||||
case libvlc_MediaPlayerPositionChanged:
|
||||
thread_event = EM_THREAD_POSITION_CHANGED;
|
||||
write(app->fd_write, &thread_event, sizeof(thread_event));
|
||||
break;
|
||||
case libvlc_MediaPlayerLengthChanged:
|
||||
_send_length_changed(ev);
|
||||
break;
|
||||
case libvlc_MediaPlayerSeekableChanged:
|
||||
_send_seekable_changed(ev);
|
||||
break;
|
||||
case libvlc_MediaPlayerPlaying:
|
||||
_send_resize(app->w, app->h);
|
||||
break;
|
||||
case libvlc_MediaPlayerStopped:
|
||||
_send_file_set(app);
|
||||
break;
|
||||
case libvlc_MediaPlayerEndReached:
|
||||
_send_cmd(EM_RESULT_PLAYBACK_STOPPED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_file_set(struct _App *app)
|
||||
{
|
||||
_em_str_read(&app->filename);
|
||||
|
||||
app->m = libvlc_media_new_path(app->libvlc, app->filename);
|
||||
if (!app->m)
|
||||
{
|
||||
fprintf(stderr, "could not open path: \"%s\"\n", app->filename);
|
||||
return;
|
||||
}
|
||||
app->mp = libvlc_media_player_new_from_media(app->m);
|
||||
|
||||
if (!app->mp)
|
||||
{
|
||||
fprintf(stderr, "could not create new player from media.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
app->opening = 1;
|
||||
libvlc_video_set_format(app->mp, "RV32", DEFAULTWIDTH, DEFAULTHEIGHT, DEFAULTWIDTH * 4);
|
||||
libvlc_video_set_callbacks(app->mp, _tmp_lock, _tmp_unlock, _tmp_display, NULL);
|
||||
app->event_mgr = libvlc_media_player_event_manager(app->mp);
|
||||
libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPositionChanged,
|
||||
_event_cb, app);
|
||||
libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerStopped,
|
||||
_event_cb, app);
|
||||
|
||||
app->mevent_mgr = libvlc_media_event_manager(app->m);
|
||||
|
||||
libvlc_audio_set_mute(app->mp, 1);
|
||||
libvlc_media_player_play(app->mp);
|
||||
}
|
||||
|
||||
static void
|
||||
_position_set(struct _App *app)
|
||||
{
|
||||
if (!app->mp)
|
||||
return;
|
||||
|
||||
float position;
|
||||
_em_read_safe(STDIN_FILENO, &position, sizeof(position));
|
||||
|
||||
libvlc_time_t new_time = position * 1000;
|
||||
libvlc_media_player_set_time(app->mp, new_time);
|
||||
}
|
||||
|
||||
static void
|
||||
_speed_set(struct _App *app)
|
||||
{
|
||||
float rate;
|
||||
|
||||
if (!app->mp)
|
||||
return;
|
||||
|
||||
_em_read_safe(STDIN_FILENO, &rate, sizeof(rate));
|
||||
|
||||
libvlc_media_player_set_rate(app->mp, rate);
|
||||
}
|
||||
|
||||
static void
|
||||
_mute_set(struct _App *app)
|
||||
{
|
||||
int mute;
|
||||
|
||||
if (!app->mp)
|
||||
return;
|
||||
|
||||
_em_read_safe(STDIN_FILENO, &mute, sizeof(mute));
|
||||
|
||||
libvlc_audio_set_mute(app->mp, mute);
|
||||
}
|
||||
|
||||
static void
|
||||
_volume_set(struct _App *app)
|
||||
{
|
||||
float volume;
|
||||
int vol;
|
||||
|
||||
if (!app->mp)
|
||||
return;
|
||||
|
||||
_em_read_safe(STDIN_FILENO, &volume, sizeof(volume));
|
||||
vol = volume * 100;
|
||||
|
||||
libvlc_audio_set_volume(app->mp, vol);
|
||||
}
|
||||
|
||||
static void
|
||||
_audio_track_set(struct _App *app)
|
||||
{
|
||||
int track;
|
||||
|
||||
_em_read_safe(STDIN_FILENO, &track, sizeof(track));
|
||||
|
||||
libvlc_audio_set_track(app->mp, track);
|
||||
}
|
||||
|
||||
static void
|
||||
_file_set_done(struct _App *app)
|
||||
{
|
||||
emotion_generic_shm_get(app->shmname, &app->vs, &app->vf);
|
||||
app->w = app->vs->width;
|
||||
app->h = app->vs->height;
|
||||
libvlc_video_set_format(app->mp, "RV32", app->w, app->h, app->w * 4);
|
||||
libvlc_video_set_callbacks(app->mp, _lock, _unlock, _display, app);
|
||||
app->opening = 0;
|
||||
|
||||
|
||||
libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerPlaying,
|
||||
_event_cb, app);
|
||||
libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerTimeChanged,
|
||||
_event_cb, app);
|
||||
libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerLengthChanged,
|
||||
_event_cb, app);
|
||||
libvlc_event_attach(app->event_mgr, libvlc_MediaPlayerSeekableChanged,
|
||||
_event_cb, app);
|
||||
|
||||
libvlc_audio_set_mute(app->mp, 0);
|
||||
_send_cmd(EM_RESULT_FILE_SET_DONE);
|
||||
}
|
||||
|
||||
static void
|
||||
_file_close(struct _App *app)
|
||||
{
|
||||
app->playing = 0;
|
||||
if (libvlc_media_player_get_state(app->mp) != libvlc_Playing)
|
||||
{
|
||||
_send_file_closed(app);
|
||||
return;
|
||||
}
|
||||
|
||||
app->closing = 1;
|
||||
libvlc_media_player_stop(app->mp);
|
||||
if (app->filename)
|
||||
free(app->filename);
|
||||
if (app->mp)
|
||||
{
|
||||
libvlc_media_release(app->m);
|
||||
libvlc_media_player_release(app->mp);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_process_emotion_commands(struct _App *app)
|
||||
{
|
||||
int cmd = _em_cmd_read();
|
||||
switch (cmd) {
|
||||
case EM_CMD_FILE_SET:
|
||||
_file_set(app);
|
||||
break;
|
||||
case EM_CMD_FILE_SET_DONE:
|
||||
_file_set_done(app);
|
||||
break;
|
||||
case EM_CMD_FILE_CLOSE:
|
||||
_file_close(app);
|
||||
break;
|
||||
case EM_CMD_PLAY:
|
||||
_play(app);
|
||||
break;
|
||||
case EM_CMD_STOP:
|
||||
_stop(app);
|
||||
break;
|
||||
case EM_CMD_POSITION_SET:
|
||||
_position_set(app);
|
||||
break;
|
||||
case EM_CMD_SPEED_SET:
|
||||
_speed_set(app);
|
||||
break;
|
||||
case EM_CMD_AUDIO_MUTE_SET:
|
||||
_mute_set(app);
|
||||
break;
|
||||
case EM_CMD_VOLUME_SET:
|
||||
_volume_set(app);
|
||||
break;
|
||||
case EM_CMD_AUDIO_TRACK_SET:
|
||||
_audio_track_set(app);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
_send_track_info(libvlc_media_player_t *mp)
|
||||
{
|
||||
int track_count, current;
|
||||
libvlc_track_description_t *desc;
|
||||
|
||||
current = libvlc_audio_get_track(mp);
|
||||
track_count = libvlc_audio_get_track_count(mp);
|
||||
desc = libvlc_audio_get_track_description(mp);
|
||||
|
||||
_send_cmd_start(EM_RESULT_AUDIO_TRACK_INFO);
|
||||
SEND_CMD_PARAM(current);
|
||||
SEND_CMD_PARAM(track_count);
|
||||
while (desc)
|
||||
{
|
||||
int tid = desc->i_id;
|
||||
const char *name = desc->psz_name;
|
||||
SEND_CMD_PARAM(tid);
|
||||
_send_cmd_str(name);
|
||||
desc = desc->p_next;
|
||||
}
|
||||
_send_cmd_finish();
|
||||
}
|
||||
|
||||
static void
|
||||
_position_changed(struct _App *app)
|
||||
{
|
||||
if (!app->opening)
|
||||
return;
|
||||
|
||||
/* sending size info only once */
|
||||
int r, w, h;
|
||||
r = libvlc_video_get_size(app->mp, 0, &w, &h);
|
||||
if (r < 0)
|
||||
return;
|
||||
_send_resize(w, h);
|
||||
|
||||
/* sending audio track info */
|
||||
// _send_track_info(app->mp);
|
||||
|
||||
libvlc_media_player_stop(app->mp);
|
||||
}
|
||||
|
||||
static void
|
||||
_process_thread_events(struct _App *app)
|
||||
{
|
||||
int event;
|
||||
size_t size;
|
||||
|
||||
size = read(app->fd_read, &event, sizeof(event));
|
||||
if (size != sizeof(event))
|
||||
{
|
||||
fprintf(stderr, "player: problem when reading thread event. size = %zd\n", size);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case EM_THREAD_POSITION_CHANGED:
|
||||
_position_changed(app);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, const char *argv[])
|
||||
{
|
||||
struct _App app;
|
||||
Emotion_Generic_Video_Shared *vs;
|
||||
struct pollfd fds[2]; // watching on 2 file descriptors
|
||||
int tpipe[2]; // pipe for comunicating events from threads
|
||||
char shmname[256];
|
||||
char cwidth[64], cheight[64], cpitch[64], chroma[64];
|
||||
char buf[64];
|
||||
const char *vlc_argv[] =
|
||||
{
|
||||
"--quiet",
|
||||
"--vout",
|
||||
"vmem",
|
||||
"--vmem-width",
|
||||
cwidth,
|
||||
"--vmem-height",
|
||||
cheight,
|
||||
"--vmem-pitch",
|
||||
cpitch,
|
||||
"--vmem-chroma",
|
||||
chroma
|
||||
};
|
||||
|
||||
int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);
|
||||
snprintf(cwidth, sizeof(cwidth), "%d", DEFAULTWIDTH);
|
||||
snprintf(cheight, sizeof(cheight), "%d", DEFAULTHEIGHT);
|
||||
snprintf(cpitch, sizeof(cpitch), "%d", DEFAULTWIDTH * 4);
|
||||
snprintf(chroma, sizeof(chroma), "RV32");
|
||||
|
||||
app.libvlc = libvlc_new(vlc_argc, vlc_argv);
|
||||
app.mp = NULL;
|
||||
app.filename = NULL;
|
||||
app.w = 0;
|
||||
app.h = 0;
|
||||
app.size_sent = 0;
|
||||
app.opening = 0;
|
||||
app.playing = 0;
|
||||
app.closing = 0;
|
||||
|
||||
if (_em_cmd_read() != EM_CMD_INIT)
|
||||
{
|
||||
fprintf(stderr, "player: wrong init command!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int size;
|
||||
_em_read_safe(STDIN_FILENO, &size, sizeof(size));
|
||||
_em_read_safe(STDIN_FILENO, buf, size);
|
||||
app.shmname = strdup(buf);
|
||||
|
||||
_send_cmd(EM_RESULT_INIT);
|
||||
|
||||
pipe(tpipe);
|
||||
app.fd_read = tpipe[0];
|
||||
app.fd_write = tpipe[1];
|
||||
fds[0].fd = STDIN_FILENO;
|
||||
fds[0].events = POLLIN;
|
||||
fds[1].fd = app.fd_read;
|
||||
fds[1].events = POLLIN;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = poll(fds, 2, 30);
|
||||
if (r == 0)
|
||||
continue;
|
||||
else if (r < 0)
|
||||
{
|
||||
fprintf(stderr, "an error ocurred on poll().\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (fds[0].revents & POLLIN)
|
||||
_process_emotion_commands(&app);
|
||||
if (fds[1].revents & POLLIN)
|
||||
_process_thread_events(&app);
|
||||
}
|
||||
|
||||
libvlc_release(app.libvlc);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
#undef SEND_CMD_PARAM
|
|
@ -41,6 +41,7 @@ enum _Emotion_Format
|
|||
|
||||
struct _Emotion_Module_Options
|
||||
{
|
||||
const char *player;
|
||||
Eina_Bool no_video : 1;
|
||||
Eina_Bool no_audio : 1;
|
||||
};
|
||||
|
|
|
@ -124,7 +124,8 @@ static int _log_domain = -1;
|
|||
static const char *_backend_priority[] = {
|
||||
"gstreamer",
|
||||
"xine",
|
||||
"vlc"
|
||||
"vlc",
|
||||
"generic"
|
||||
};
|
||||
|
||||
static const char SIG_FRAME_DECODE[] = "frame_decode";
|
||||
|
@ -312,6 +313,9 @@ emotion_object_module_option_set(Evas_Object *obj, const char *opt, const char *
|
|||
|
||||
E_SMART_OBJ_GET(sd, obj, E_OBJ_NAME);
|
||||
if ((!opt) || (!val)) return;
|
||||
|
||||
if (!strcmp(opt, "player"))
|
||||
eina_stringshare_replace(&sd->module_options.player, val);
|
||||
}
|
||||
|
||||
EAPI Eina_Bool
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
SUBDIRS = xine gstreamer
|
||||
SUBDIRS = xine gstreamer generic
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
#ifndef EMOTION_GENERIC_PLUGIN_H
|
||||
#define EMOTION_GENERIC_PLUGIN_H
|
||||
|
||||
#include <semaphore.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define DEFAULTWIDTH 320
|
||||
#define DEFAULTHEIGHT 240
|
||||
#define DEFAULTPITCH 4
|
||||
|
||||
typedef enum _Emotion_Generic_Cmd Emotion_Generic_Cmd;
|
||||
typedef enum _Emotion_Generic_Result Emotion_Generic_Result;
|
||||
typedef struct _Emotion_Generic_Video_Frame Emotion_Generic_Video_Frame;
|
||||
typedef struct _Emotion_Generic_Video_Shared Emotion_Generic_Video_Shared;
|
||||
|
||||
enum _Emotion_Generic_Cmd
|
||||
{
|
||||
EM_CMD_INIT, // param: shared memory identifier (string)
|
||||
EM_CMD_PLAY, // param: position (float)
|
||||
EM_CMD_STOP, // param: none
|
||||
EM_CMD_FILE_SET, // param: filename (string)
|
||||
EM_CMD_FILE_SET_DONE, // param: none
|
||||
EM_CMD_FILE_CLOSE, // param: none
|
||||
EM_CMD_POSITION_SET, // param: position (float)
|
||||
EM_CMD_SPEED_SET, // param: speed (float)
|
||||
EM_CMD_AUDIO_MUTE_SET, // param: muted (int)
|
||||
EM_CMD_VOLUME_SET, // param: volume (float)
|
||||
EM_CMD_AUDIO_TRACK_SET, // param: track id (int)
|
||||
EM_CMD_LAST
|
||||
};
|
||||
|
||||
enum _Emotion_Generic_Result
|
||||
{
|
||||
EM_RESULT_INIT, // param: none
|
||||
EM_RESULT_FILE_SET, // param: none
|
||||
EM_RESULT_FILE_SET_DONE, // param: none
|
||||
EM_RESULT_PLAYBACK_STOPPED, // param: none
|
||||
EM_RESULT_FILE_CLOSE, // param: none
|
||||
EM_RESULT_FRAME_NEW, // param: none
|
||||
EM_RESULT_FRAME_SIZE, // param: int, int (width, height)
|
||||
EM_RESULT_LENGTH_CHANGED, // param: float
|
||||
EM_RESULT_POSITION_CHANGED, // param: float
|
||||
EM_RESULT_SEEKABLE_CHANGED, // param: int
|
||||
EM_RESULT_AUDIO_TRACK_INFO, // param: current track, track count, track_id, track_name, track_id2, track_name2, ...
|
||||
// (int, int, int, string, int, string, ...)
|
||||
EM_RESULT_LAST
|
||||
};
|
||||
|
||||
/* structure for frames 2 buffers to keep integrity */
|
||||
struct _Emotion_Generic_Video_Frame
|
||||
{
|
||||
unsigned char *frames[3];
|
||||
};
|
||||
|
||||
/* structure for frames 2 buffers to keep integrity */
|
||||
struct _Emotion_Generic_Video_Shared
|
||||
{
|
||||
int size;
|
||||
int width;
|
||||
int height;
|
||||
int pitch;
|
||||
/**
|
||||
* - "emotion" is the frame from where the Emotion process is reading pixels.
|
||||
* The player shouldn't touch this frame.
|
||||
* - "player" is the frame where the slayer process is writing pixels.
|
||||
* The emotion process shouldn't touch this frame.
|
||||
* - "last" is the last frame that was rendered by the player. Emotion will
|
||||
* use this frame the next time it will fetch pixels to Evas.
|
||||
* - "next" is the unused frame. The player currently using the "player"
|
||||
* should, after finishing this frame, set "last" to "player", and "player"
|
||||
* to "next", and finally "next" to "last" so this operation can be done
|
||||
* many times in case that Emotion does not request pixels fast enough.
|
||||
*/
|
||||
struct {
|
||||
int emotion;
|
||||
int player;
|
||||
int last;
|
||||
int next;
|
||||
} frame;
|
||||
sem_t lock;
|
||||
};
|
||||
|
||||
inline void
|
||||
emotion_generic_shm_get(const char *shmname, Emotion_Generic_Video_Shared **vs, Emotion_Generic_Video_Frame *vf)
|
||||
{
|
||||
int shmfd = -1;
|
||||
int size;
|
||||
Emotion_Generic_Video_Shared *t_vs;
|
||||
|
||||
shmfd = shm_open(shmname, O_RDWR, 0777);
|
||||
|
||||
t_vs = mmap(NULL, sizeof(*t_vs), PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0);
|
||||
size = t_vs->size;
|
||||
munmap(t_vs, sizeof(*t_vs));
|
||||
t_vs = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0);
|
||||
|
||||
vf->frames[0] = (char *)t_vs + sizeof(*t_vs);
|
||||
vf->frames[1] = (char *)t_vs + sizeof(*t_vs) + t_vs->height * t_vs->width * t_vs->pitch;
|
||||
vf->frames[2] = (char *)t_vs + sizeof(*t_vs) + 2 * t_vs->height * t_vs->width * t_vs->pitch;
|
||||
|
||||
*vs = t_vs;
|
||||
}
|
||||
|
||||
inline void
|
||||
emotion_generic_shm_free(Emotion_Generic_Video_Shared *vs)
|
||||
{
|
||||
munmap(vs, vs->size);
|
||||
}
|
||||
|
||||
#endif // EMOTION_GENERIC_PLUGIN_H
|
|
@ -0,0 +1,31 @@
|
|||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/src/lib \
|
||||
-I$(top_srcdir)/src/modules \
|
||||
-DPACKAGE_BIN_DIR=\"$(bindir)\" \
|
||||
-DPACKAGE_LIB_DIR=\"$(libdir)\" \
|
||||
-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
|
||||
@EMOTION_CFLAGS@ \
|
||||
@EMOTION_CPPFLAGS@ \
|
||||
@EFL_EMOTION_BUILD@
|
||||
|
||||
if EMOTION_BUILD_GENERIC
|
||||
if !EMOTION_STATIC_BUILD_GENERIC
|
||||
|
||||
pkgdir = $(libdir)/emotion
|
||||
|
||||
pkg_LTLIBRARIES = em_generic.la
|
||||
includes_HEADERS = Emotion_Generic_Plugin.h
|
||||
includesdir = $(includedir)/emotion-@VMAJ@
|
||||
noinst_HEADERS = emotion_generic.h
|
||||
|
||||
em_generic_la_SOURCES = emotion_generic.c
|
||||
em_generic_la_LIBADD = $(top_builddir)/src/lib/libemotion.la
|
||||
em_generic_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
|
||||
em_generic_la_LIBTOOLFLAGS = --tag=disable-static
|
||||
em_generic_la_DEPENDENCIES = emotion_generic.h Emotion_Generic_Plugin.h
|
||||
|
||||
endif
|
||||
endif
|
|
@ -0,0 +1,79 @@
|
|||
Generic - emotion backend
|
||||
=========================
|
||||
|
||||
This generic player backend executes a separate player in another
|
||||
process. It receives the bytes to be drawn on the emotion object through
|
||||
a shared memory, and communicates with the player through a pipe, using
|
||||
the player standard input/output.
|
||||
|
||||
The player must communicate with emotion using the defined commands
|
||||
specified in the Emotion_Generic_Plugin.h. It doesn't need to link
|
||||
against emotion, just include this file for easier implementation.
|
||||
|
||||
|
||||
How does it work?
|
||||
=================
|
||||
|
||||
When the module is initialized for an emotion object, it starts another process
|
||||
that runs the specified player. The player command line is specified using:
|
||||
|
||||
emotion_object_module_option_set(object, "player", <command>);
|
||||
|
||||
A player using libvlc is being provided now, and the generic module internally
|
||||
checks if the command given was "vlc", in which case it will use this provided
|
||||
vlc player.
|
||||
|
||||
When a file is set to this object, it will send the file name to the player, and
|
||||
expect an answer that will tell that the player already decoded a bit of the
|
||||
file, and the video size is already set on the module, so it can allocate a
|
||||
shared memory with correct size.
|
||||
|
||||
The module then allocates the memory, sends a message to the player and expect
|
||||
an answer. After this last answer, the "open_done" signal is sent and the module
|
||||
knows that it is ready for playing. Commands sent before the module being ready
|
||||
are now applied (and play is resumed if necessary).
|
||||
|
||||
During this setup stage, info about the file set will be stored in the module,
|
||||
so commands like meta data get, length get and so will be available to sync
|
||||
calls like emotion_object_play_length_get();
|
||||
|
||||
If the player dies for any reason, a "decode_stop" signal is sent (should change
|
||||
to something more like an error signal), and if play is called again, it will be
|
||||
restarted. The playback should start from the same point it was before the
|
||||
player crashed, if the player supports seek on the current media format).
|
||||
|
||||
TODO
|
||||
====
|
||||
|
||||
- Provide better description for commands;
|
||||
- Explain in details the communication emotion <-> player;
|
||||
- Make more common functions for players;
|
||||
- (maybe) add support for named pipes, so we don't rely on standard in/out
|
||||
for communication;
|
||||
- Add a detection on the player to know that the emotion process died (so it
|
||||
can just exit);
|
||||
- shmname should contain the child pid too;
|
||||
- better names for commands, maybe add namespace everywhere;
|
||||
|
||||
|
||||
questions
|
||||
=========
|
||||
|
||||
- Using semaphores to lock the critical region between process, and pthread
|
||||
mutexes for the threads inside the player. Should move to only one type
|
||||
(semphores or mutexes)?
|
||||
- There are 2 inline functions insde Emotion_Generic_Plugin.h to make it easier
|
||||
for the player to get the shared memory correctly. Any problem with this?
|
||||
Would be good to add more functions/macros to make common tasks like
|
||||
parsing commands there too?
|
||||
- Should move players to another project (outside of emotion)?
|
||||
|
||||
|
||||
problems
|
||||
========
|
||||
- file_set has some critical time when file is not set yet when we can't call
|
||||
some functions (I think only another file_set now);
|
||||
- comunication player -> emotion depends on '\n' to delimitate commands, will
|
||||
remove this soon (fix this urgently!);
|
||||
- need to implement missing APIs;
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,70 @@
|
|||
#ifndef EMOTION_GENERIC_H
|
||||
#define EMOTION_GENERIC_H
|
||||
|
||||
#include "Emotion_Generic_Plugin.h"
|
||||
|
||||
/* default values */
|
||||
|
||||
typedef struct _Emotion_Generic_Video Emotion_Generic_Video;
|
||||
typedef struct _Emotion_Generic_Player Emotion_Generic_Player;
|
||||
typedef struct _Emotion_Generic_Audio_Channel Emotion_Generic_Audio_Channel;
|
||||
|
||||
struct _Emotion_Generic_Player
|
||||
{
|
||||
Ecore_Exe *exe;
|
||||
};
|
||||
|
||||
struct _Emotion_Generic_Audio_Channel
|
||||
{
|
||||
int id;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/* emotion/generic main structure */
|
||||
struct _Emotion_Generic_Video
|
||||
{
|
||||
const char *cmdline;
|
||||
const char *shmname;
|
||||
|
||||
Emotion_Generic_Player player;
|
||||
Ecore_Event_Handler *player_add, *player_del, *player_data;
|
||||
int drop;
|
||||
|
||||
const char *filename;
|
||||
volatile double len;
|
||||
volatile double pos;
|
||||
double fps;
|
||||
double ratio;
|
||||
int w, h;
|
||||
Evas_Object *obj;
|
||||
Emotion_Generic_Video_Shared *shared;
|
||||
Emotion_Generic_Video_Frame frame;
|
||||
volatile int spu_channel;
|
||||
volatile int video_channel;
|
||||
volatile int fq;
|
||||
int volume;
|
||||
float speed;
|
||||
Emotion_Vis vis;
|
||||
Eina_Bool initializing : 1;
|
||||
Eina_Bool ready : 1;
|
||||
Eina_Bool play : 1;
|
||||
Eina_Bool video_mute : 1;
|
||||
Eina_Bool audio_mute : 1;
|
||||
Eina_Bool spu_mute : 1;
|
||||
Eina_Bool seekable : 1;
|
||||
volatile Eina_Bool opening : 1;
|
||||
volatile Eina_Bool closing : 1;
|
||||
int audio_channels_count;
|
||||
int audio_channel_current;
|
||||
struct _Emotion_Generic_Audio_Channel *audio_channels;
|
||||
};
|
||||
|
||||
extern int _emotion_generic_log_domain;
|
||||
#define DBG(...) EINA_LOG_DOM_DBG(_emotion_generic_log_domain, __VA_ARGS__)
|
||||
#define INF(...) EINA_LOG_DOM_INFO(_emotion_generic_log_domain, __VA_ARGS__)
|
||||
#define WRN(...) EINA_LOG_DOM_WARN(_emotion_generic_log_domain, __VA_ARGS__)
|
||||
#define ERR(...) EINA_LOG_DOM_ERR(_emotion_generic_log_domain, __VA_ARGS__)
|
||||
#define CRITICAL(...) EINA_LOG_DOM_CRIT(_emotion_generic_log_domain, __VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue