emotion: make Xv work.
authorcedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 4 Oct 2011 11:14:58 +0000 (11:14 +0000)
committercedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 4 Oct 2011 11:14:58 +0000 (11:14 +0000)
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.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/emotion@63802 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/modules/gstreamer/Makefile.am
src/modules/gstreamer/emotion_gstreamer.c
src/modules/gstreamer/emotion_gstreamer.h
src/modules/gstreamer/emotion_sink.c

index 8ac1d2f..f861cde 100644 (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
index d6b0b07..48a6e6a 100644 (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;
 }
 
@@ -1239,6 +1243,16 @@ em_priority_get(void *video)
 }
 
 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,
             void                 **video,
@@ -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 */
index dd676c0..c4afd13 100644 (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);
index 2f4ef5f..f2273b7 100644 (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;
+
+        /* 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_new((Ecore_X_Window) ecore_evas_window_get(ee), x, y, w, h);
+       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;
+
+             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_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);
 
-           pad = gst_element_get_pad(queue, "sink");
-           teepad = gst_element_get_request_pad(tee, "src%d");
-           gst_pad_link(teepad, pad);
+             xvsink = fakeeos;
 
-           ev->teepad = teepad;
-           ev->xvpad = pad;
+             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,