#include "emotion_gstreamer.h"
-Eina_Bool window_manager_video = EINA_FALSE;
int _emotion_gstreamer_log_domain = -1;
Eina_Bool debug_fps = EINA_FALSE;
-Eina_Bool _ecore_x_available = EINA_FALSE;
-static Ecore_Idler *restart_idler;
static int _emotion_init_count = 0;
/* Callbacks to get the eos */
GstMessage *message,
gpointer data);
-static Eina_Bool _em_restart_stream(void *data);
-
/* Module interface */
-
-static int priority_overide = 0;
-
static Emotion_Video_Stream *
emotion_video_stream_new(Emotion_Gstreamer_Video *ev)
{
ev->pipeline = NULL;
ev->sink = NULL;
- if (ev->eteepad) gst_object_unref(ev->eteepad);
- ev->eteepad = NULL;
- if (ev->xvteepad) gst_object_unref(ev->xvteepad);
- ev->xvteepad = NULL;
- if (ev->xvpad) gst_object_unref(ev->xvpad);
- ev->xvpad = NULL;
-
ev->src_width = 0;
ev->src_height = 0;
-
-#ifdef HAVE_ECORE_X
- INF("destroying window: %i", ev->win);
- if (ev->win) ecore_x_window_free(ev->win);
- ev->win = 0;
-#endif
- }
-
- if (restart_idler)
- {
- ecore_idler_del(restart_idler);
- restart_idler = NULL;
}
EINA_LIST_FREE(ev->audio_streams, astream)
return str;
}
-static void
-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 */
-
- if (ev->priority != pri && ev->pipeline)
- {
- if (ev->threads)
- {
- Ecore_Thread *t;
-
- EINA_LIST_FREE(ev->threads, t)
- ecore_thread_cancel(t);
- }
- em_cleanup(ev);
- restart_idler = ecore_idler_add(_em_restart_stream, ev);
- }
- ev->priority = pri;
-}
-
-static Eina_Bool
-em_priority_get(void *video)
-{
- Emotion_Gstreamer_Video *ev;
-
- ev = video;
- return !ev->stream;
-}
-
-#ifdef HAVE_ECORE_X
-static Eina_Bool
-_ecore_event_x_destroy(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
-{
- Ecore_X_Event_Window_Destroy *ev = event;
-
- INF("killed window: %x (%x).", ev->win, ev->event_win);
-
- return EINA_TRUE;
-}
-
-static void
-gstreamer_ecore_x_check(void)
-{
- Ecore_X_Window *roots;
- int num;
-
- ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DESTROY, _ecore_event_x_destroy, NULL);
-
- /* Check if the window manager is able to handle our special Xv window. */
- roots = ecore_x_window_root_list(&num);
- if (roots && num > 0)
- {
- Ecore_X_Window win, twin;
- int nwins;
-
- nwins = ecore_x_window_prop_window_get(roots[0],
- ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK,
- &win, 1);
- if (nwins > 0)
- {
- nwins = ecore_x_window_prop_window_get(win,
- ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK,
- &twin, 1);
- if (nwins > 0 && twin == win)
- {
- Ecore_X_Atom *supported;
- int supported_num;
- int i;
-
- if (ecore_x_netwm_supported_get(roots[0], &supported, &supported_num))
- {
- Eina_Bool parent = EINA_FALSE;
- Eina_Bool video_position = EINA_FALSE;
-
- for (i = 0; i < supported_num; ++i)
- {
- if (supported[i] == ECORE_X_ATOM_E_VIDEO_PARENT)
- parent = EINA_TRUE;
- else if (supported[i] == ECORE_X_ATOM_E_VIDEO_POSITION)
- video_position = EINA_TRUE;
- if (parent && video_position)
- break;
- }
-
- if (parent && video_position)
- {
- window_manager_video = EINA_TRUE;
- }
- }
- free(supported);
- }
- }
- }
- free(roots);
-}
-#endif
-
static void *
em_add(const Emotion_Engine *api,
Evas_Object *obj,
em_speed_get, /* speed_get */
em_eject, /* eject */
em_meta_get, /* meta_get */
- em_priority_set, /* priority_set */
- em_priority_get /* priority_get */
+ NULL, /* priority_set */
+ NULL /* priority_get */
};
Eina_Bool
goto error_gst_init;
}
-#ifdef HAVE_ECORE_X
- if (ecore_x_init(NULL) > 0)
- {
- _ecore_x_available = EINA_TRUE;
- gstreamer_ecore_x_check();
- }
-#endif
-
if (gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR,
"emotion-sink",
"video sink plugin for Emotion",
error_register:
error_gst_plugin:
-#ifdef HAVE_ECORE_X
- if (_ecore_x_available)
- {
- ecore_x_shutdown();
- _ecore_x_available = EINA_FALSE;
- window_manager_video = EINA_FALSE;
- }
-#endif
gst_deinit();
_emotion_module_unregister(&em_engine);
-#ifdef HAVE_ECORE_X
- if (_ecore_x_available)
- {
- ecore_x_shutdown();
- _ecore_x_available = EINA_FALSE;
- window_manager_video = EINA_FALSE;
- }
-#endif
-
eina_log_domain_unregister(_emotion_gstreamer_log_domain);
_emotion_gstreamer_log_domain = -1;
}
static Eina_Bool
-_em_restart_stream(void *data)
-{
- Emotion_Gstreamer_Video *ev;
-
- ev = data;
-
- ev->pipeline = gstreamer_video_sink_new(ev, ev->obj, ev->uri);
-
- if (ev->pipeline)
- {
- ev->eos_bus = gst_pipeline_get_bus(GST_PIPELINE(ev->pipeline));
- if (!ev->eos_bus)
- {
- ERR("could not get the bus");
- return EINA_FALSE;
- }
-
- gst_bus_set_sync_handler(ev->eos_bus, _eos_sync_fct, ev, NULL);
- }
-
- restart_idler = NULL;
-
- return ECORE_CALLBACK_CANCEL;
-}
-
-static Eina_Bool
_video_size_get(GstElement *elem, int *width, int *height)
{
GstIterator *itr = NULL;
break;
case GST_MESSAGE_ERROR:
em_cleanup(ev);
-
- if (ev->priority)
- {
- ERR("Switching back to canvas rendering.");
- ev->priority = EINA_FALSE;
- priority_overide++;
-
- restart_idler = ecore_idler_add(_em_restart_stream, ev);
- }
break;
default:
ERR("bus say: %s [%i - %s]",
g_error_free(error);
g_free(debug);
- /* FIXME: This is broken */
- if (strncmp(GST_OBJECT_NAME(msg->src), "xvimagesink", 11) == 0)
- {
- send = emotion_gstreamer_message_alloc(ev, msg);
+ send = emotion_gstreamer_message_alloc(ev, msg);
- if (send)
- {
- _emotion_pending_ecore_begin();
- ecore_main_loop_thread_safe_call_async(_eos_main_fct, send);
- }
+ if (send)
+ {
+ _emotion_pending_ecore_begin();
+ ecore_main_loop_thread_safe_call_async(_eos_main_fct, send);
}
break;
}
_emotion_gstreamer_video_pipeline_parse(data, EINA_TRUE);
}
-static void
-_video_resize(void *data, Evas_Object *obj EINA_UNUSED, const Evas_Video_Surface *surface EINA_UNUSED,
- Evas_Coord w, Evas_Coord h)
-{
-#ifdef HAVE_ECORE_X
- Emotion_Gstreamer_Video *ev = data;
-
- ecore_x_window_resize(ev->win, w, h);
- DBG("resize: %i, %i", w, h);
-#else
- if (data)
- {
- DBG("resize: %i, %i (fake)", w, h);
- }
-#endif
-}
-
-static void
-_video_move(void *data, Evas_Object *obj EINA_UNUSED, const Evas_Video_Surface *surface EINA_UNUSED,
- Evas_Coord x, Evas_Coord y)
-{
-#ifdef HAVE_ECORE_X
- Emotion_Gstreamer_Video *ev = data;
- unsigned int pos[2];
-
- DBG("move: %i, %i", x, y);
- pos[0] = x; pos[1] = y;
- ecore_x_window_prop_card32_set(ev->win, ECORE_X_ATOM_E_VIDEO_POSITION, pos, 2);
-#else
- if (data)
- {
- DBG("move: %i, %i (fake)", x, y);
- }
-#endif
-}
-
-#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->xvteepad, 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->xvteepad, 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 EINA_UNUSED, const Evas_Video_Surface *surface EINA_UNUSED)
-{
-#ifdef HAVE_ECORE_X
- Emotion_Gstreamer_Video *ev = data;
-
- DBG("show xv");
- ecore_x_window_show(ev->win);
-#else
- if (data)
- {
- DBG("show xv (fake)");
- }
-#endif
- /* gst_pad_set_blocked_async(ev->xvteepad, TRUE, _block_pad_link_cb, ev); */
-}
-
-static void
-_video_hide(void *data, Evas_Object *obj EINA_UNUSED, const Evas_Video_Surface *surface EINA_UNUSED)
-{
-#ifdef HAVE_ECORE_X
- Emotion_Gstreamer_Video *ev = data;
-
- DBG("hide xv");
- ecore_x_window_hide(ev->win);
-#else
- if (data)
- {
- DBG("hide xv (fake)");
- }
-#endif
- /* gst_pad_set_blocked_async(ev->xvteepad, TRUE, _block_pad_unlink_cb, ev); */
-}
-
-static void
-_video_update_pixels(void *data, Evas_Object *obj EINA_UNUSED, const Evas_Video_Surface *surface EINA_UNUSED)
-{
- Emotion_Gstreamer_Video *ev = data;
- Emotion_Gstreamer_Buffer *send;
-
- if (!ev->send) return;
-
- send = ev->send;
- send->force = EINA_TRUE;
- ev->send = NULL;
-
- _emotion_pending_ecore_begin();
- evas_video_sink_main_render(send);
-}
-
-
-static void
-_image_resize(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
-{
-}
-
GstElement *
gstreamer_video_sink_new(Emotion_Gstreamer_Video *ev,
Evas_Object *o,
GstElement *playbin;
GstElement *bin = NULL;
GstElement *esink = NULL;
- GstElement *xvsink = NULL;
- GstElement *tee = NULL;
GstElement *queue = NULL;
Evas_Object *obj;
GstPad *pad;
- GstPad *teepad;
int flags;
const char *launch;
-#if defined HAVE_ECORE_X
- const char *engine = NULL;
- Eina_List *engines;
-#endif
obj = emotion_object_image_get(o);
if (!obj)
goto unref_pipeline;
}
- tee = gst_element_factory_make("tee", NULL);
- if (!tee)
- {
- ERR("Unable to create 'tee' GstElement.");
- goto unref_pipeline;
- }
-
-#if defined HAVE_ECORE_X
- if (window_manager_video)
- {
- Eina_List *l;
- const char *ename;
-
- engines = evas_render_method_list();
-
- EINA_LIST_FOREACH(engines, l, ename)
- {
- if (evas_render_method_lookup(ename) ==
- evas_output_method_get(evas_object_evas_get(obj)))
- {
- engine = ename;
- break;
- }
- }
-
- if (ev->priority && engine && strstr(engine, "_x11") != NULL)
- {
- 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 < 4) w = 4;
- if (h < 2) h = 2;
-
- /* 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);
- DBG("parent: %x", parent);
-
- win = ecore_x_window_new(0, x, y, w, h);
- DBG("creating window: %x [%i, %i, %i, %i]", win, x, y, w, h);
- if (win)
- {
- Ecore_X_Window_State state[] = { ECORE_X_WINDOW_STATE_SKIP_TASKBAR, ECORE_X_WINDOW_STATE_SKIP_PAGER };
-
- ecore_x_netwm_window_state_set(win, state, 2);
- ecore_x_window_hide(win);
- xvsink = gst_element_factory_make("xvimagesink", NULL);
- if (xvsink)
- {
- unsigned int pos[2];
-
- gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(xvsink), win);
- ev->win = win;
-
- ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_VIDEO_PARENT, &parent, 1);
-
- pos[0] = x; pos[1] = y;
- ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_VIDEO_POSITION, pos, 2);
- }
- else
- {
- DBG("destroying win: %x", win);
- ecore_x_window_free(win);
- }
- }
- }
- evas_render_method_list_free(engines);
- }
-#else
-//# warning "missing: ecore_x"
-#endif
-
esink = gst_element_factory_make("emotion-sink", "sink");
if (!esink)
{
g_object_set(G_OBJECT(esink), "ev", ev, NULL);
evas_object_image_pixels_get_callback_set(obj, NULL, NULL);
- evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _image_resize, ev);
/* We need queue to force each video sink to be in its own thread */
queue = gst_element_factory_make("queue", "equeue");
goto unref_pipeline;
}
- gst_bin_add_many(GST_BIN(bin), tee, queue, esink, NULL);
+ gst_bin_add_many(GST_BIN(bin), queue, esink, NULL);
gst_element_link_many(queue, esink, NULL);
/* link both sink to GstTee */
pad = gst_element_get_static_pad(queue, "sink");
- teepad = gst_element_get_request_pad(tee, "src_%u");
- gst_pad_link(teepad, pad);
+ gst_element_add_pad(bin, gst_ghost_pad_new("sink", pad));
gst_object_unref(pad);
- ev->eteepad = teepad;
-
- /* FIXME: Why a bin that drops the EOS message?! */
- if (xvsink)
- {
- GstElement *fakeeos;
-
- queue = gst_element_factory_make("queue", "xvqueue");
- fakeeos = GST_ELEMENT(GST_BIN(g_object_new(GST_TYPE_FAKEEOS_BIN, "name", "eosbin", NULL)));
- if (queue && fakeeos)
- {
- GstPad *queue_pad;
-
- gst_bin_add_many(GST_BIN(bin), fakeeos, NULL);
-
- gst_bin_add_many(GST_BIN(fakeeos), queue, xvsink, NULL);
- gst_element_link_many(queue, xvsink, NULL);
- queue_pad = gst_element_get_static_pad(queue, "sink");
- gst_element_add_pad(fakeeos, gst_ghost_pad_new("sink", queue_pad));
-
- pad = gst_element_get_static_pad(fakeeos, "sink");
- teepad = gst_element_get_request_pad(tee, "src_%u");
- gst_pad_link(teepad, pad);
-
- xvsink = fakeeos;
-
- ev->xvteepad = teepad;
- ev->xvpad = pad;
- }
- else
- {
- if (fakeeos) gst_object_unref(fakeeos);
- if (queue) gst_object_unref(queue);
- gst_object_unref(xvsink);
- xvsink = NULL;
- }
- }
-
- teepad = gst_element_get_static_pad(tee, "sink");
- gst_element_add_pad(bin, gst_ghost_pad_new("sink", teepad));
- gst_object_unref(teepad);
-
#define GST_PLAY_FLAG_NATIVE_VIDEO (1 << 6)
#define GST_PLAY_FLAG_DOWNLOAD (1 << 7)
#define GST_PLAY_FLAG_AUDIO (1 << 1)
ev->stream = EINA_TRUE;
- if (xvsink)
- {
- Evas_Video_Surface video;
-
- video.version = EVAS_VIDEO_SURFACE_VERSION;
- video.data = ev;
- video.parent = NULL;
- video.move = _video_move;
- video.resize = _video_resize;
- video.show = _video_show;
- video.hide = _video_hide;
- video.update_pixels = _video_update_pixels;
-
- evas_object_image_video_surface_set(obj, &video);
- ev->stream = EINA_FALSE;
- }
-
eina_stringshare_replace(&ev->uri, uri);
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,
_emotion_gstreamer_end,
return playbin;
unref_pipeline:
- gst_object_unref(xvsink);
gst_object_unref(esink);
- gst_object_unref(tee);
gst_object_unref(bin);
gst_object_unref(playbin);
return NULL;