emotion: make Xv work.

NOTE: we need the help of the window manager to make this
really work. So for the moment, it half work. As soon as I
hack E17, the Xv fast path for Emotion will only work when
used with E17 and it will fallback to canvas inlined rendering
in other case.


SVN revision: 63802
This commit is contained in:
Cedric BAIL 2011-10-04 11:14:58 +00:00
parent 4376c4f995
commit 35c9a8f56c
4 changed files with 135 additions and 32 deletions

View File

@ -22,7 +22,8 @@ pkg_LTLIBRARIES = gstreamer.la
gstreamer_la_SOURCES = \
emotion_gstreamer.c \
emotion_sink.c \
emotion_alloc.c
emotion_alloc.c \
emotion_fakeeos.c
gstreamer_la_LIBADD = @ECORE_X_LIBS@ @GSTREAMER_LIBS@ @GSTREAMER_INTERFACE_LIBS@ $(top_builddir)/src/lib/libemotion.la
gstreamer_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
gstreamer_la_LIBTOOLFLAGS = --tag=disable-static

View File

@ -237,6 +237,8 @@ static Emotion_Video_Module em_module =
NULL /* handle */
};
static int priority_overide = 0;
static Emotion_Video_Stream *
emotion_video_stream_new(Emotion_Gstreamer_Video *ev)
{
@ -404,6 +406,7 @@ em_cleanup(Emotion_Gstreamer_Video *ev)
if (ev->xvpad) gst_object_unref(ev->xvpad);
ev->xvpad = NULL;
fprintf(stderr, "destroying window: %i\n", ev->win);
if (ev->win) ecore_x_window_free(ev->win);
ev->win = 0;
}
@ -1226,6 +1229,7 @@ em_priority_set(void *video, Eina_Bool pri)
Emotion_Gstreamer_Video *ev;
ev = video;
if (priority_overide > 3) return ; /* If we failed to much to create that pipeline, let's don't wast our time anymore */
ev->priority = pri;
}
@ -1238,6 +1242,16 @@ em_priority_get(void *video)
return ev->stream;
}
static Eina_Bool
_ecore_event_x_destroy(void *data, int type, void *event)
{
Ecore_X_Event_Window_Destroy *ev = event;
fprintf(stderr, "killed window: %x (%x)\n", ev->win, ev->event_win);
return EINA_TRUE;
}
static Eina_Bool
module_open(Evas_Object *obj,
const Emotion_Video_Module **module,
@ -1263,6 +1277,8 @@ module_open(Evas_Object *obj,
if (!em_module.init(obj, video, opt))
return EINA_FALSE;
ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DESTROY, _ecore_event_x_destroy, NULL);
eina_threads_init();
*module = &em_module;
@ -1524,12 +1540,16 @@ _eos_main_fct(void *data)
case GST_MESSAGE_STREAM_STATUS:
break;
case GST_MESSAGE_ERROR:
ERR("Switching back to composited rendering.");
em_cleanup(ev);
ev->priority = EINA_FALSE;
if (ev->priority)
{
ERR("Switching back to canvas rendering.");
ev->priority = EINA_FALSE;
priority_overide++;
ecore_idler_add(_em_restart_stream, ev);
ecore_idler_add(_em_restart_stream, ev);
}
break;
default:
ERR("bus say: %s [%i - %s]",
@ -1642,9 +1662,11 @@ _emotion_gstreamer_video_pipeline_parse(Emotion_Gstreamer_Video *ev,
res = gst_element_get_state(ev->pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
if (res == GST_STATE_CHANGE_NO_PREROLL)
gst_element_set_state(ev->pipeline, GST_STATE_PLAYING);
{
gst_element_set_state(ev->pipeline, GST_STATE_PLAYING);
res = gst_element_get_state(ev->pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
res = gst_element_get_state(ev->pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
}
/** NOTE: you need to set: GST_DEBUG_DUMP_DOT_DIR=/tmp EMOTION_ENGINE=gstreamer to save the $EMOTION_GSTREAMER_DOT file in '/tmp' */
/** then call dot -Tpng -oemotion_pipeline.png /tmp/$TIMESTAMP-$EMOTION_GSTREAMER_DOT.dot */

View File

@ -78,6 +78,7 @@ struct _Emotion_Gstreamer_Video
GstElement *pipeline;
GstElement *sink;
GstElement *esink;
GstElement *xvsink;
GstElement *tee;
GstPad *teepad;
GstPad *xvpad;
@ -138,7 +139,6 @@ struct _Emotion_Gstreamer_Video
Eina_Bool delete_me : 1;
Eina_Bool samsung : 1;
Eina_Bool kill_buffer : 1;
Eina_Bool linked : 1;
Eina_Bool stream : 1;
Eina_Bool priority : 1;
};
@ -210,6 +210,8 @@ extern int _emotion_gstreamer_log_domain;
#define EVAS_TYPE_VIDEO_SINK evas_video_sink_get_type()
GType fakeeos_bin_get_type(void);
#define EVAS_VIDEO_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), \
EVAS_TYPE_VIDEO_SINK, EvasVideoSink))
@ -230,6 +232,8 @@ extern int _emotion_gstreamer_log_domain;
(G_TYPE_INSTANCE_GET_CLASS((obj), \
EVAS_TYPE_VIDEO_SINK, EvasVideoSinkClass))
#define GST_TYPE_FAKEEOS_BIN fakeeos_bin_get_type()
GstElement *gstreamer_video_sink_new(Emotion_Gstreamer_Video *ev,
Evas_Object *obj,
const char *uri);

View File

@ -730,6 +730,12 @@ evas_video_sink_samsung_main_render(void *data)
evas_object_image_data_update_add(priv->o, 0, 0, priv->width, priv->height);
evas_object_image_pixels_dirty_set(priv->o, 0);
if (!preroll && send->ev->play_started)
{
_emotion_playback_started(send->ev->obj);
send->ev->play_started = 0;
}
_emotion_frame_new(send->ev->obj);
vstream = eina_list_nth(send->ev->video_streams, send->ev->video_stream_nbr - 1);
@ -790,6 +796,7 @@ evas_video_sink_main_render(void *data)
if (ev->send)
emotion_gstreamer_buffer_free(ev->send);
ev->send = send;
evas_object_image_data_update_add(priv->o, 0, 0, priv->width, priv->height);
goto exit_stream;
}
@ -812,6 +819,12 @@ evas_video_sink_main_render(void *data)
evas_object_image_data_update_add(priv->o, 0, 0, priv->width, priv->height);
evas_object_image_pixels_dirty_set(priv->o, 0);
if (!preroll && ev->play_started)
{
_emotion_playback_started(ev->obj);
ev->play_started = 0;
}
_emotion_frame_new(ev->obj);
gst_element_query_position(ev->pipeline, &fmt, &pos);
@ -944,10 +957,17 @@ static void
_emotion_gstreamer_pause(void *data, Ecore_Thread *thread)
{
Emotion_Gstreamer_Video *ev = data;
gboolean res;
if (ecore_thread_check(thread) || !ev->pipeline) return ;
gst_element_set_state(ev->pipeline, GST_STATE_PAUSED);
res = gst_element_get_state(ev->pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
if (res == GST_STATE_CHANGE_NO_PREROLL)
{
gst_element_set_state(ev->pipeline, GST_STATE_PLAYING);
gst_element_get_state(ev->pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
}
}
static void
@ -1009,19 +1029,51 @@ _video_move(void *data, Evas_Object *obj __UNUSED__, const Evas_Video_Surface *s
{
Emotion_Gstreamer_Video *ev = data;
fprintf(stderr, "move: %i, %i\n", x, y);
ecore_x_window_move(ev->win, x, y);
}
#if 0
/* Much better idea to always feed the XvImageSink and let him handle optimizing the rendering as we do */
static void
_block_pad_unlink_cb(GstPad *pad, gboolean blocked, gpointer user_data)
{
if (blocked)
{
Emotion_Gstreamer_Video *ev = user_data;
GstEvent *gev;
gst_pad_unlink(ev->teepad, ev->xvpad);
gev = gst_event_new_eos();
gst_pad_send_event(ev->xvpad, gev);
gst_pad_set_blocked_async(pad, FALSE, _block_pad_unlink_cb, NULL);
}
}
static void
_block_pad_link_cb(GstPad *pad, gboolean blocked, gpointer user_data)
{
if (blocked)
{
Emotion_Gstreamer_Video *ev = user_data;
gst_pad_link(ev->teepad, ev->xvpad);
if (ev->play)
gst_element_set_state(ev->xvsink, GST_STATE_PLAYING);
else
gst_element_set_state(ev->xvsink, GST_STATE_PAUSED);
gst_pad_set_blocked_async(pad, FALSE, _block_pad_link_cb, NULL);
}
}
#endif
static void
_video_show(void *data, Evas_Object *obj __UNUSED__, const Evas_Video_Surface *surface __UNUSED__)
{
Emotion_Gstreamer_Video *ev = data;
fprintf(stderr, "show xwin %i\n", ev->win);
ecore_x_window_show(ev->win);
gst_pad_link(ev->teepad, ev->xvpad);
ev->linked = EINA_TRUE;
/* gst_pad_set_blocked_async(ev->teepad, TRUE, _block_pad_link_cb, ev); */
}
static void
@ -1029,11 +1081,8 @@ _video_hide(void *data, Evas_Object *obj __UNUSED__, const Evas_Video_Surface *s
{
Emotion_Gstreamer_Video *ev = data;
fprintf(stderr, "hide xwin: %i\n", ev->win);
ecore_x_window_hide(ev->win);
gst_pad_unlink(ev->teepad, ev->xvpad);
ev->linked = EINA_FALSE;
/* gst_pad_set_blocked_async(ev->teepad, TRUE, _block_pad_unlink_cb, ev); */
}
static void
@ -1101,8 +1150,6 @@ gstreamer_video_sink_new(Emotion_Gstreamer_Video *ev,
goto unref_pipeline;
}
fprintf(stderr, "priority: %i\n", ev->priority);
#if defined HAVE_ECORE_X && defined HAVE_XOVERLAY_H
engines = evas_render_method_list();
@ -1113,25 +1160,41 @@ gstreamer_video_sink_new(Emotion_Gstreamer_Video *ev,
Ecore_Evas *ee;
Evas_Coord x, y, w, h;
Ecore_X_Window win;
Ecore_X_Window parent;
evas_object_geometry_get(obj, &x, &y, &w, &h);
ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
if (w < 1) w = 1;
if (h < 1) h = 1;
if (w < 4) w = 4;
if (h < 2) h = 2;
win = ecore_x_window_new((Ecore_X_Window) ecore_evas_window_get(ee), x, y, w, h);
/* Here we really need to have the help of the window manager, this code will change when we update E17. */
parent = (Ecore_X_Window) ecore_evas_window_get(ee);
fprintf(stderr, "parent: %x\n", parent);
win = ecore_x_window_override_new(0, x, y, w, h);
fprintf(stderr, "creating window: %x [%i, %i, %i, %i]\n", win, x, y, w, h);
if (win)
{
ecore_x_window_show(win);
xvsink = gst_element_factory_make("xvimagesink", NULL);
if (xvsink)
{
Ecore_X_Atom atom;
gst_x_overlay_set_window_handle(GST_X_OVERLAY(xvsink), win);
ev->win = win;
atom = ecore_x_atom_get("enlightenment.video");
if (atom)
{
ecore_x_window_prop_card32_set(win, atom, &parent, 1);
}
}
else
{
fprintf(stderr, "destroying win: %x\n", win);
ecore_x_window_free(win);
}
}
@ -1161,7 +1224,7 @@ gstreamer_video_sink_new(Emotion_Gstreamer_Video *ev,
goto unref_pipeline;
}
gst_bin_add_many(GST_BIN(bin), tee, queue, esink, xvsink, NULL);
gst_bin_add_many(GST_BIN(bin), tee, queue, esink, NULL);
gst_element_link_many(queue, esink, NULL);
/* link both sink to GstTee */
@ -1173,23 +1236,36 @@ gstreamer_video_sink_new(Emotion_Gstreamer_Video *ev,
if (xvsink)
{
GstElement *fakeeos;
queue = gst_element_factory_make("queue", NULL);
if (queue)
fakeeos = GST_ELEMENT(GST_BIN(g_object_new(GST_TYPE_FAKEEOS_BIN, "name", "eosbin", NULL)));
if (queue && fakeeos)
{
gst_bin_add_many(GST_BIN(bin), queue, NULL);
gst_element_link_many(queue, xvsink, NULL);
GstPad *queue_pad;
pad = gst_element_get_pad(queue, "sink");
teepad = gst_element_get_request_pad(tee, "src%d");
gst_pad_link(teepad, pad);
gst_bin_add_many(GST_BIN(bin), fakeeos, NULL);
ev->teepad = teepad;
ev->xvpad = pad;
gst_bin_add_many(GST_BIN(fakeeos), queue, xvsink, NULL);
gst_element_link_many(queue, xvsink, NULL);
queue_pad = gst_element_get_pad(queue, "sink");
gst_element_add_pad(fakeeos, gst_ghost_pad_new("sink", queue_pad));
pad = gst_element_get_pad(fakeeos, "sink");
teepad = gst_element_get_request_pad(tee, "src%d");
gst_pad_link(teepad, pad);
xvsink = fakeeos;
ev->teepad = teepad;
ev->xvpad = pad;
}
else
{
gst_object_unref(xvsink);
xvsink = NULL;
if (fakeeos) gst_object_unref(fakeeos);
if (queue) gst_object_unref(queue);
gst_object_unref(xvsink);
xvsink = NULL;
}
}
@ -1230,10 +1306,10 @@ gstreamer_video_sink_new(Emotion_Gstreamer_Video *ev,
}
eina_stringshare_replace(&ev->uri, uri);
ev->linked = EINA_TRUE;
ev->pipeline = playbin;
ev->sink = bin;
ev->esink = esink;
ev->xvsink = xvsink;
ev->tee = tee;
ev->threads = eina_list_append(ev->threads,
ecore_thread_run(_emotion_gstreamer_pause,