emotion: remove g stuff and make it safer.
authorcedric <cedric>
Tue, 16 Aug 2011 16:11:50 +0000 (16:11 +0000)
committercedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 16 Aug 2011 16:11:50 +0000 (16:11 +0000)
git-svn-id: http://svn.enlightenment.org/svn/e/trunk/emotion@62514 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/modules/gstreamer/emotion_alloc.c
src/modules/gstreamer/emotion_gstreamer.c
src/modules/gstreamer/emotion_gstreamer.h
src/modules/gstreamer/emotion_sink.c

index cf376e2..1f55904 100644 (file)
@@ -14,12 +14,16 @@ emotion_gstreamer_buffer_alloc(EvasVideoSinkPrivate *sink,
 {
    Emotion_Gstreamer_Buffer *send;
 
+   if (!sink->ev) return NULL;
+
    send = malloc(sizeof (Emotion_Gstreamer_Buffer));
    if (!send) return NULL;
 
    send->sink = sink;
    send->frame = gst_buffer_ref(buffer);
    send->preroll = preroll;
+   sink->ev->out++;
+   send->ev = sink->ev;
 
    return send;
 }
@@ -27,6 +31,13 @@ emotion_gstreamer_buffer_alloc(EvasVideoSinkPrivate *sink,
 void
 emotion_gstreamer_buffer_free(Emotion_Gstreamer_Buffer *send)
 {
+   send->ev->in++;
+
+   if (send->ev->in == send->ev->out
+       && send->ev->threads == NULL
+       && send->ev->delete_me)
+     em_shutdown(send->ev);
+
    gst_buffer_unref(send->frame);
    free(send);
 }
@@ -37,6 +48,8 @@ emotion_gstreamer_message_alloc(Emotion_Gstreamer_Video *ev,
 {
    Emotion_Gstreamer_Message *send;
 
+   if (!ev) return NULL;
+
    send = malloc(sizeof (Emotion_Gstreamer_Message));
    if (!send) return NULL;
 
@@ -52,7 +65,9 @@ emotion_gstreamer_message_free(Emotion_Gstreamer_Message *send)
 {
    send->ev->in++;
 
-   if (send->ev->in == send->ev->out && send->ev->delete_me)
+   if (send->ev->in == send->ev->out
+       && send->ev->threads == NULL
+       && send->ev->delete_me)
      em_shutdown(send->ev);
 
    gst_message_unref(send->msg);
index f0449cf..ba80aef 100644 (file)
@@ -333,6 +333,7 @@ em_init(Evas_Object            *obj,
    ev->volume = 0.8;
    ev->play_started = 0;
    ev->delete_me = EINA_FALSE;
+   ev->threads = NULL;
 
    *emotion_video = ev;
 
@@ -355,10 +356,15 @@ em_shutdown(void *video)
    if (!ev)
      return 0;
 
-   if (ev->thread)
+   if (ev->threads)
      {
-        ecore_thread_cancel(ev->thread);
-        ev->thread = NULL;
+        Ecore_Thread *t;
+
+        EINA_LIST_FREE(ev->threads, t)
+          ecore_thread_cancel(t);
+
+        ev->delete_me = EINA_TRUE;
+        return 1;
      }
 
    if (ev->in != ev->out)
@@ -375,9 +381,12 @@ em_shutdown(void *video)
 
    if (ev->pipeline)
      {
+       g_object_set(G_OBJECT(ev->sink), "ev", NULL, NULL);
+       g_object_set(G_OBJECT(ev->sink), "evas-object", NULL, NULL);
        gst_element_set_state(ev->pipeline, GST_STATE_NULL);
        gst_object_unref(ev->pipeline);
        ev->pipeline = NULL;
+       ev->sink = NULL;
      }
 
    EINA_LIST_FREE(ev->audio_streams, astream)
@@ -470,17 +479,22 @@ em_file_close(void *video)
         ev->eos_bus = NULL;
      }
 
-   if (ev->thread)
+   if (ev->threads)
      {
-        ecore_thread_cancel(ev->thread);
-        ev->thread = NULL;
+        Ecore_Thread *t;
+
+        EINA_LIST_FREE(ev->threads, t)
+          ecore_thread_cancel(t);
      }
 
    if (ev->pipeline)
      {
+        g_object_set(G_OBJECT(ev->sink), "ev", NULL, NULL);
+        g_object_set(G_OBJECT(ev->sink), "evas-object", NULL, NULL);
         gst_element_set_state(ev->pipeline, GST_STATE_NULL);
         gst_object_unref(ev->pipeline);
         ev->pipeline = NULL;
+        ev->sink = NULL;
      }
 
    /* we clear the stream lists */
@@ -521,7 +535,7 @@ em_stop(void *video)
    ev = (Emotion_Gstreamer_Video *)video;
 
    if (!ev->pipeline) return ;
+
    gst_element_set_state(ev->pipeline, GST_STATE_PAUSED);
    ev->play = 0;
 }
@@ -1478,7 +1492,7 @@ _eos_sync_fct(GstBus *bus, GstMessage *msg, gpointer data)
       case GST_MESSAGE_ASYNC_DONE:
          send = emotion_gstreamer_message_alloc(ev, msg);
 
-         if (send) ecore_main_loop_thread_safe_call(_eos_main_fct, send);
+         if (send) ecore_main_loop_thread_safe_call_async(_eos_main_fct, send);
 
          break;
 
@@ -1504,13 +1518,15 @@ _emotion_gstreamer_video_pipeline_parse(Emotion_Gstreamer_Video *ev,
    if (ev->pipeline_parsed)
      return EINA_TRUE;
 
-   if (force && ev->thread)
+   if (force && ev->threads)
      {
-        ecore_thread_cancel(ev->thread);
-        ev->thread = NULL;
+        Ecore_Thread *t;
+
+        EINA_LIST_FREE(ev->threads, t)
+          ecore_thread_cancel(t);
      }
 
-   if (ev->thread)
+   if (ev->threads)
      return EINA_FALSE;
 
    res = gst_element_get_state(ev->pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
index 9feea1e..3afadff 100644 (file)
@@ -59,7 +59,8 @@ struct _Emotion_Gstreamer_Video
 {
    /* Gstreamer elements */
    GstElement       *pipeline;
-   Ecore_Thread     *thread;
+   GstElement       *sink;
+   Eina_List        *threads;
 
    /* eos */
    GstBus           *eos_bus;
@@ -113,13 +114,15 @@ struct _EvasVideoSinkPrivate {
 
    Evas_Object *o;
 
+   Emotion_Gstreamer_Video *ev;
+
    int width;
    int height;
    Evas_Colorspace eformat;
    GstVideoFormat gformat;
 
-   GMutex* buffer_mutex;
-   GCond* data_cond;
+   Eina_Lock m;
+   Eina_Condition c;
 
     /* We need to keep a copy of the last inserted buffer as evas doesn't copy YUV data around */
    GstBuffer *last_buffer;
@@ -137,6 +140,7 @@ struct _EvasVideoSinkPrivate {
 
 struct _Emotion_Gstreamer_Buffer
 {
+   Emotion_Gstreamer_Video *ev;
    EvasVideoSinkPrivate *sink;
 
    GstBuffer *frame;
index 4c336e1..a6bfa53 100644 (file)
@@ -20,7 +20,8 @@ enum {
   PROP_EVAS_OBJECT,
   PROP_WIDTH,
   PROP_HEIGHT,
-  PROP_LAST,
+  PROP_EV,
+  PROP_LAST
 };
 
 static guint evas_video_sink_signals[LAST_SIGNAL] = { 0, };
@@ -67,13 +68,25 @@ evas_video_sink_init(EvasVideoSink* sink, EvasVideoSinkClass* klass __UNUSED__)
    priv->height = 0;
    priv->gformat = GST_VIDEO_FORMAT_UNKNOWN;
    priv->eformat = EVAS_COLORSPACE_ARGB8888;
-   priv->data_cond = g_cond_new();
-   priv->buffer_mutex = g_mutex_new();
+   eina_lock_new(&priv->m);
+   eina_condition_new(&priv->c, &priv->m);
    priv->unlocked = EINA_FALSE;
 }
 
 
 /**** Object methods ****/
+static void
+_cleanup_priv(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
+{
+   EvasVideoSinkPrivate* priv;
+
+   priv = data;
+
+   eina_lock_take(&priv->m);
+   if (priv->o == obj)
+     priv->o = NULL;
+   eina_lock_release(&priv->m);
+}
 
 static void
 evas_video_sink_set_property(GObject * object, guint prop_id,
@@ -87,9 +100,16 @@ evas_video_sink_set_property(GObject * object, guint prop_id,
 
    switch (prop_id) {
     case PROP_EVAS_OBJECT:
-       g_mutex_lock(priv->buffer_mutex);
+       eina_lock_take(&priv->m);
+       evas_object_event_callback_del(priv->o, EVAS_CALLBACK_FREE, _cleanup_priv);
        priv->o = g_value_get_pointer (value);
-       g_mutex_unlock(priv->buffer_mutex);
+       evas_object_event_callback_add(priv->o, EVAS_CALLBACK_FREE, _cleanup_priv, priv);
+       eina_lock_release(&priv->m);
+       break;
+    case PROP_EV:
+       eina_lock_take(&priv->m);
+       priv->ev = g_value_get_pointer (value);
+       eina_lock_release(&priv->m);
        break;
     default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -110,19 +130,24 @@ evas_video_sink_get_property(GObject * object, guint prop_id,
 
    switch (prop_id) {
     case PROP_EVAS_OBJECT:
-       g_mutex_lock(priv->buffer_mutex);
+       eina_lock_take(&priv->m);
        g_value_set_pointer (value, priv->o);
-       g_mutex_unlock(priv->buffer_mutex);
+       eina_lock_release(&priv->m);
        break;
     case PROP_WIDTH:
-       g_mutex_lock(priv->buffer_mutex);
+       eina_lock_take(&priv->m);
        g_value_set_int(value, priv->width);
-       g_mutex_unlock(priv->buffer_mutex);
+       eina_lock_release(&priv->m);
        break;
     case PROP_HEIGHT:
-       g_mutex_lock(priv->buffer_mutex);
+       eina_lock_take(&priv->m);
        g_value_set_int (value, priv->height);
-       g_mutex_unlock(priv->buffer_mutex);
+       eina_lock_release(&priv->m);
+       break;
+    case PROP_EV:
+       eina_lock_take(&priv->m);
+       g_value_set_pointer (value, priv->ev);
+       eina_lock_release(&priv->m);
        break;
     default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -140,15 +165,8 @@ evas_video_sink_dispose(GObject* object)
    sink = EVAS_VIDEO_SINK(object);
    priv = sink->priv;
 
-   if (priv->buffer_mutex) {
-      g_mutex_free(priv->buffer_mutex);
-      priv->buffer_mutex = 0;
-   }
-
-   if (priv->data_cond) {
-      g_cond_free(priv->data_cond);
-      priv->data_cond = 0;
-   }
+   eina_lock_free(&priv->m);
+   eina_condition_free(&priv->c);
 
    if (priv->last_buffer) {
       gst_buffer_unref(priv->last_buffer);
@@ -217,12 +235,12 @@ evas_video_sink_start(GstBaseSink* base_sink)
    gboolean res = TRUE;
 
    priv = EVAS_VIDEO_SINK(base_sink)->priv;
-   g_mutex_lock(priv->buffer_mutex);
+   eina_lock_take(&priv->m);
    if (!priv->o)
      res = FALSE;
    else
      priv->unlocked = EINA_FALSE;
-   g_mutex_unlock(priv->buffer_mutex);
+   eina_lock_release(&priv->m);
    return res;
 }
 
@@ -257,9 +275,9 @@ evas_video_sink_unlock_stop(GstBaseSink* object)
    sink = EVAS_VIDEO_SINK(object);
    priv = sink->priv;
 
-   g_mutex_lock(priv->buffer_mutex);
+   eina_lock_take(&priv->m);
    priv->unlocked = FALSE;
-   g_mutex_unlock(priv->buffer_mutex);
+   eina_lock_release(&priv->m);
 
    return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock_stop,
                                        (object), TRUE);
@@ -278,7 +296,7 @@ evas_video_sink_preroll(GstBaseSink* bsink, GstBuffer* buffer)
    send = emotion_gstreamer_buffer_alloc(priv, buffer, EINA_TRUE);
 
    if (send)
-     ecore_main_loop_thread_safe_call(evas_video_sink_main_render, send);
+     ecore_main_loop_thread_safe_call_async(evas_video_sink_main_render, send);
 
    return GST_FLOW_OK;
 }
@@ -289,40 +307,42 @@ evas_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
    Emotion_Gstreamer_Buffer *send;
    EvasVideoSinkPrivate *priv;
    EvasVideoSink *sink;
-   Eina_Bool ret;
 
    sink = EVAS_VIDEO_SINK(bsink);
    priv = sink->priv;
 
-   g_mutex_lock(priv->buffer_mutex);
+   eina_lock_take(&priv->m);
 
    if (priv->unlocked) {
       ERR("LOCKED");
-      g_mutex_unlock(priv->buffer_mutex);
+      eina_lock_release(&priv->m);
       return GST_FLOW_OK;
    }
 
    send = emotion_gstreamer_buffer_alloc(priv, buffer, EINA_FALSE);
-   if (!send) return GST_FLOW_ERROR;
+   if (!send) {
+      eina_lock_release(&priv->m);
+      return GST_FLOW_ERROR;
+   }
 
-   ecore_main_loop_thread_safe_call(evas_video_sink_main_render, send);
+   ecore_main_loop_thread_safe_call_async(evas_video_sink_main_render, send);
 
-   g_cond_wait(priv->data_cond, priv->buffer_mutex);
-   g_mutex_unlock(priv->buffer_mutex);
+   eina_condition_wait(&priv->c);
+   eina_lock_release(&priv->m);
 
    return GST_FLOW_OK;
 }
 
-static void evas_video_sink_main_render(void *data)
+static void
+evas_video_sink_main_render(void *data)
 {
    Emotion_Gstreamer_Buffer *send;
-   Emotion_Gstreamer_Video *ev;
+   Emotion_Gstreamer_Video *ev = NULL;
    Emotion_Video_Stream *vstream;
    EvasVideoSinkPrivate* priv;
    GstBuffer* buffer;
    unsigned char *evas_data;
    const guint8 *gst_data;
-   GstQuery *query;
    GstFormat fmt = GST_FORMAT_TIME;
    Evas_Coord w, h;
    gint64 pos;
@@ -332,6 +352,7 @@ static void evas_video_sink_main_render(void *data)
 
    priv = send->sink;
    if (!priv) goto exit_point;
+   if (!priv->o) goto exit_point;
 
    buffer = send->frame;
    preroll = send->preroll;
@@ -341,7 +362,7 @@ static void evas_video_sink_main_render(void *data)
    gst_data = GST_BUFFER_DATA(buffer);
    if (!gst_data) goto exit_point;
 
-   ev = evas_object_data_get(priv->o, "_emotion_gstreamer_video");
+   ev = send->ev;
    if (!ev) goto exit_point;
 
    _emotion_gstreamer_video_pipeline_parse(ev, EINA_TRUE);
@@ -514,27 +535,23 @@ static void evas_video_sink_main_render(void *data)
  exit_point:
    emotion_gstreamer_buffer_free(send);
 
-   if (preroll) return ;
+   if (preroll || !priv->o || !ev) return ;
 
-   g_mutex_lock(priv->buffer_mutex);
+   eina_lock_take(&priv->m);
+   if (!priv->unlocked)
+     eina_condition_signal(&priv->c);
 
-   if (priv->unlocked) {
-      g_mutex_unlock(priv->buffer_mutex);
-      return;
-   }
-
-   g_cond_signal(priv->data_cond);
-   g_mutex_unlock(priv->buffer_mutex);
+   eina_lock_release(&priv->m);
 }
 
 static void
 unlock_buffer_mutex(EvasVideoSinkPrivate* priv)
 {
-   g_mutex_lock(priv->buffer_mutex);
-
+   eina_lock_take(&priv->m);
    priv->unlocked = EINA_TRUE;
-   g_cond_signal(priv->data_cond);
-   g_mutex_unlock(priv->buffer_mutex);
+
+   eina_condition_signal(&priv->c);
+   eina_lock_release(&priv->m);
 }
 
 static void
@@ -591,6 +608,10 @@ evas_video_sink_class_init(EvasVideoSinkClass* klass)
                                     g_param_spec_int ("height", "Height",
                                                       "The height of the video",
                                                       0, 65536, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+   g_object_class_install_property (gobject_class, PROP_EV,
+                                    g_param_spec_pointer ("ev", "Emotion_Gstreamer_Video",
+                                                          "THe internal data of the emotion object",
+                                                          G_PARAM_READWRITE));
 
    gobject_class->dispose = evas_video_sink_dispose;
 
@@ -622,19 +643,24 @@ gstreamer_plugin_init (GstPlugin * plugin)
 }
 
 static void
-_emotion_gstreamer_pause(void *data, Ecore_Thread *thread __UNUSED__)
+_emotion_gstreamer_pause(void *data, Ecore_Thread *thread)
 {
    Emotion_Gstreamer_Video *ev = data;
 
+   if (ecore_thread_check(thread) || !ev->pipeline) return ;
+
    gst_element_set_state(ev->pipeline, GST_STATE_PAUSED);
 }
 
 static void
-_emotion_gstreamer_cancel(void *data, Ecore_Thread *thread __UNUSED__)
+_emotion_gstreamer_cancel(void *data, Ecore_Thread *thread)
 {
    Emotion_Gstreamer_Video *ev = data;
 
-   ev->thread = NULL;
+   ev->threads = eina_list_remove(ev->threads, thread);
+
+   if (ev->in == ev->out && ev->threads == NULL && ev->delete_me)
+     em_shutdown(ev);
 }
 
 static void
@@ -652,7 +678,6 @@ gstreamer_video_sink_new(Emotion_Gstreamer_Video *ev,
    GstElement *playbin;
    GstElement *sink;
    Evas_Object *obj;
-   GstStateChangeReturn res;
 
    obj = emotion_object_image_get(o);
    if (!obj)
@@ -675,22 +700,24 @@ gstreamer_video_sink_new(Emotion_Gstreamer_Video *ev,
         goto unref_pipeline;
      }
 
+   g_object_set(G_OBJECT(sink), "evas-object", obj, NULL);
+   g_object_set(G_OBJECT(sink), "ev", ev, NULL);
+
    g_object_set(G_OBJECT(playbin), "video-sink", sink, NULL);
    g_object_set(G_OBJECT(playbin), "uri", uri, NULL);
-   g_object_set(G_OBJECT(sink), "evas-object", obj, NULL);
 
    ev->pipeline = playbin;
-   ev->thread = ecore_thread_run(_emotion_gstreamer_pause,
-                                 _emotion_gstreamer_end,
-                                 _emotion_gstreamer_cancel,
-                                 ev);
+   ev->sink = sink;
+   ev->threads = eina_list_append(ev->threads,
+                                  ecore_thread_run(_emotion_gstreamer_pause,
+                                                   _emotion_gstreamer_end,
+                                                   _emotion_gstreamer_cancel,
+                                                   ev));
 
    /** 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 */
    if (getenv("EMOTION_GSTREAMER_DOT")) GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(playbin), GST_DEBUG_GRAPH_SHOW_ALL, getenv("EMOTION_GSTREAMER_DOT"));
 
-   evas_object_data_set(obj, "_emotion_gstreamer_video", ev);
-
    return playbin;
 
  unref_pipeline: