[gstreamermm] Message: Modify create() method so that wrappers are not leaked.



commit 043fe17814f21fe05aae9af7146b8baffd90a172
Author: José Alburquerque <jaalburqu svn gnome org>
Date:   Sun Feb 7 23:21:47 2010 -0500

    	Message: Modify create() method so that wrappers are not leaked.
    
    	* gstreamer/src/message.ccg:
    	* gstreamer/src/message.hg: Wrapped the finalize virtual function of
    	GstMiniObject.  Modified the create() method so that the C++ wrapper
    	is stored in the structure of the message.  Hooked into the
    	GstMiniObject finalize virtual function so that wrappers can be
    	deleted before final message destruction.
    	* gstreamer/src/gst_vfuncs.defs: Defined GstMessage finalize vfunc.
    
    	Partly fixes bug #608702 (Massimiliano).

 ChangeLog                     |   14 ++
 gstreamer/src/gst_vfuncs.defs |    7 +
 gstreamer/src/message.ccg     |  304 +++++++++++++++++++++++++++--------------
 gstreamer/src/message.hg      |   21 +++-
 4 files changed, 238 insertions(+), 108 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 265789a..de06ead 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2010-02-07  José Alburquerque  <jaalburqu svn gnome org>
+
+	Message: Modify create() method so that wrappers are not leaked.
+
+	* gstreamer/src/message.ccg:
+	* gstreamer/src/message.hg: Wrapped the finalize virtual function of
+	GstMiniObject.  Modified the create() method so that the C++ wrapper
+	is stored in the structure of the message.  Hooked into the
+	GstMiniObject finalize virtual function so that wrappers can be
+	deleted before final message destruction.
+	* gstreamer/src/gst_vfuncs.defs: Defined GstMessage finalize vfunc.
+
+	Partly fixes bug #608702 (Massimiliano).
+
 2010-02-04  José Alburquerque  <jaalburqu svn gnome org>
 
 	MiniObject: Lay the foundation for virtual methods in derived classes.
diff --git a/gstreamer/src/gst_vfuncs.defs b/gstreamer/src/gst_vfuncs.defs
index 23333f3..7d1763b 100644
--- a/gstreamer/src/gst_vfuncs.defs
+++ b/gstreamer/src/gst_vfuncs.defs
@@ -755,6 +755,13 @@
   )
 )
 
+; GstMessage
+
+(define-vfunc finalize
+  (of-object "GstMessage")
+  (return-type "void")
+)
+
 ; GstMixer
 
 (define-vfunc list_tracks
diff --git a/gstreamer/src/message.ccg b/gstreamer/src/message.ccg
index 61337e6..6a03940 100644
--- a/gstreamer/src/message.ccg
+++ b/gstreamer/src/message.ccg
@@ -961,129 +961,223 @@ Glib::RefPtr<Gst::Element> MessageStreamStatus::parse_owner() const
   return Glib::wrap(gst_element, true);
 }
 
+namespace
+{
+
+static GstMiniObjectFinalizeFunction original_gst_message_finalize_function = 0;
+
+static void gstreamermm_gst_message_finalize_hook_function(GstMiniObject* mini_object)
+{
+  gpointer wrapper = 0;
+
+  GstStructure* structure = const_cast<GstStructure*>(
+    gst_message_get_structure(GST_MESSAGE(mini_object)));
+
+  if(structure && gst_structure_get(structure, "cpp_wrapper", G_TYPE_POINTER,
+    &wrapper, static_cast<void*>(0)))
+  {
+    gst_structure_remove_field(structure, "cpp_wrapper");
+    // An extra ref is needed for the unref in the Gst::MiniObject destructor.
+    gst_mini_object_ref(mini_object);
+    delete static_cast<Gst::Message*>(wrapper);
+  }
+
+  // Call the original finalize function.
+  original_gst_message_finalize_function(mini_object);
+}
+
+}
+
 Glib::RefPtr<Gst::Message> Message::wrap(GstMessage* message, bool take_copy)
 {
+  Gst::Message* wrapper = 0;
   Glib::RefPtr<Gst::Message> result;
 
   if(!message)
     return result;
 
-  if(gst_mixer_message_get_type(message) == GST_MIXER_MESSAGE_INVALID)
+  // Attempt to get an existing wrapper before creating a new one.  The
+  // current wrapper is stored in the GstStructure of the message.  If the
+  // message does not have a structure (some don't), it is given one in which
+  // the wrapper can be stored.
+
+  GstStructure* structure =
+    const_cast<GstStructure*>(gst_message_get_structure(message));
+
+  if(!structure)
   {
-    switch(GST_MESSAGE_TYPE(message))
-    {
-      case GST_MESSAGE_EOS:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageEos(message) );
-        break;
-      case GST_MESSAGE_ERROR:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageError(message) );
-        break;
-      case GST_MESSAGE_WARNING:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageWarning(message) );
-        break;
-      case GST_MESSAGE_INFO:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageInfo(message) );
-        break;
-      case GST_MESSAGE_TAG:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageTag(message) );
-        break;
-      case GST_MESSAGE_BUFFERING:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageBuffering(message) );
-        break;
-      case GST_MESSAGE_STATE_CHANGED:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageStateChanged(message) );
-        break;
-      case GST_MESSAGE_STATE_DIRTY:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageStateDirty(message) );
-        break;
-      case GST_MESSAGE_STEP_DONE:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageStepDone(message) );
-        break;
-      case GST_MESSAGE_CLOCK_PROVIDE:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageClockProvide(message) );
-        break;
-      case GST_MESSAGE_CLOCK_LOST:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageClockLost(message) );
-        break;
-      case GST_MESSAGE_NEW_CLOCK:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageNewClock(message) );
-        break;
-      case GST_MESSAGE_APPLICATION:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageApplication(message) );
-        break;
-      case GST_MESSAGE_ELEMENT:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageElement(message) );
-        break;
-      case GST_MESSAGE_SEGMENT_START:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageSegmentStart(message) );
-        break;
-      case GST_MESSAGE_SEGMENT_DONE:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageSegmentDone(message) );
-        break;
-      case GST_MESSAGE_DURATION:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageDuration(message) );
-        break;
-      case GST_MESSAGE_LATENCY:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageLatency(message) );
-        break;
-      case GST_MESSAGE_ASYNC_START:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageAsyncStart(message) );
-        break;
-      case GST_MESSAGE_ASYNC_DONE:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageAsyncDone(message) );
-        break;
-      case GST_MESSAGE_STEP_START:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageStepStart(message) );
-        break;
-      case GST_MESSAGE_STRUCTURE_CHANGE:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageStructureChange(message) );
-        break;
-      case GST_MESSAGE_REQUEST_STATE:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageRequestState(message) );
-        break;
-      case GST_MESSAGE_STREAM_STATUS:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageStreamStatus(message) );
-        break;
-      case GST_MESSAGE_UNKNOWN:
-      case GST_MESSAGE_ANY:
-        result = Gst::wrap(message, false);
-        break;
-        /* The rest of the message types are custom ones */
-      default:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageCustom(message) );
-    }
+    // Add a structure to a message that does not have one.  The lines are
+    // adapted from gst_message_new_custom().
+    structure = gst_structure_empty_new("wrapper");
+    gst_structure_set_parent_refcount (structure, &message->mini_object.refcount);
+    message->structure = structure;
   }
-  else
+
+  gst_structure_get(structure, "cpp_wrapper", G_TYPE_POINTER, &wrapper,
+    static_cast<void*>(0));
+
+  if(!wrapper)
   {
-    switch(GST_MESSAGE_TYPE(message))
+    // In this case there is no pre-existing wrapper so create one which will
+    // then be stored for later usage and then deletion on message
+    // finalization.
+    if(gst_mixer_message_get_type(message) == GST_MIXER_MESSAGE_INVALID)
+    {
+      switch(GST_MESSAGE_TYPE(message))
+      {
+        case GST_MESSAGE_EOS:
+          wrapper = new Gst::MessageEos(message);
+          break;
+        case GST_MESSAGE_ERROR:
+          wrapper = new Gst::MessageError(message);
+          break;
+        case GST_MESSAGE_WARNING:
+          wrapper = new Gst::MessageWarning(message);
+          break;
+        case GST_MESSAGE_INFO:
+          wrapper = new Gst::MessageInfo(message);
+          break;
+        case GST_MESSAGE_TAG:
+          wrapper = new Gst::MessageTag(message);
+          break;
+        case GST_MESSAGE_BUFFERING:
+          wrapper = new Gst::MessageBuffering(message);
+          break;
+        case GST_MESSAGE_STATE_CHANGED:
+          wrapper = new Gst::MessageStateChanged(message);
+          break;
+        case GST_MESSAGE_STATE_DIRTY:
+          wrapper = new Gst::MessageStateDirty(message);
+          break;
+        case GST_MESSAGE_STEP_DONE:
+          wrapper = new Gst::MessageStepDone(message);
+          break;
+        case GST_MESSAGE_CLOCK_PROVIDE:
+          wrapper = new Gst::MessageClockProvide(message);
+          break;
+        case GST_MESSAGE_CLOCK_LOST:
+          wrapper = new Gst::MessageClockLost(message);
+          break;
+        case GST_MESSAGE_NEW_CLOCK:
+          wrapper = new Gst::MessageNewClock(message);
+          break;
+        case GST_MESSAGE_APPLICATION:
+          wrapper = new Gst::MessageApplication(message);
+          break;
+        case GST_MESSAGE_ELEMENT:
+          wrapper = new Gst::MessageElement(message);
+          break;
+        case GST_MESSAGE_SEGMENT_START:
+          wrapper = new Gst::MessageSegmentStart(message);
+          break;
+        case GST_MESSAGE_SEGMENT_DONE:
+          wrapper = new Gst::MessageSegmentDone(message);
+          break;
+        case GST_MESSAGE_DURATION:
+          wrapper = new Gst::MessageDuration(message);
+          break;
+        case GST_MESSAGE_LATENCY:
+          wrapper = new Gst::MessageLatency(message);
+          break;
+        case GST_MESSAGE_ASYNC_START:
+          wrapper = new Gst::MessageAsyncStart(message);
+          break;
+        case GST_MESSAGE_ASYNC_DONE:
+          wrapper = new Gst::MessageAsyncDone(message);
+          break;
+        case GST_MESSAGE_STEP_START:
+          wrapper = new Gst::MessageStepStart(message);
+          break;
+        case GST_MESSAGE_STRUCTURE_CHANGE:
+          wrapper = new Gst::MessageStructureChange(message);
+          break;
+        case GST_MESSAGE_REQUEST_STATE:
+          wrapper = new Gst::MessageRequestState(message);
+          break;
+        case GST_MESSAGE_STREAM_STATUS:
+          wrapper = new Gst::MessageStreamStatus(message);
+          break;
+        case GST_MESSAGE_UNKNOWN:
+        case GST_MESSAGE_ANY:
+          wrapper = new Gst::Message(message);
+          break;
+          /* The rest of the message types are custom ones */
+        default:
+          wrapper = new Gst::MessageCustom(message);
+      }
+    }
+    else
     {
-      case GST_MIXER_MESSAGE_MUTE_TOGGLED:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageMixerMuteToggled(message) );
-        break;
-      case GST_MIXER_MESSAGE_RECORD_TOGGLED:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageMixerRecordToggled(message) );
-        break;
-      case GST_MIXER_MESSAGE_VOLUME_CHANGED:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageMixerVolumeChanged(message) );
-        break;
-      case GST_MIXER_MESSAGE_OPTION_CHANGED:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageMixerOptionChanged(message) );
-        break;
-      case GST_MIXER_MESSAGE_OPTIONS_LIST_CHANGED:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageMixerOptionsListChanged(message) );
-        break;
-      case GST_MIXER_MESSAGE_MIXER_CHANGED:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageMixerChanged(message) );
-        break;
-      default:
-        result = Glib::RefPtr<Gst::Message>( new Gst::MessageCustom(message) );
+      switch(GST_MESSAGE_TYPE(message))
+      {
+        case GST_MIXER_MESSAGE_MUTE_TOGGLED:
+          wrapper = new Gst::MessageMixerMuteToggled(message);
+          break;
+        case GST_MIXER_MESSAGE_RECORD_TOGGLED:
+          wrapper = new Gst::MessageMixerRecordToggled(message);
+          break;
+        case GST_MIXER_MESSAGE_VOLUME_CHANGED:
+          wrapper = new Gst::MessageMixerVolumeChanged(message);
+          break;
+        case GST_MIXER_MESSAGE_OPTION_CHANGED:
+          wrapper = new Gst::MessageMixerOptionChanged(message);
+          break;
+        case GST_MIXER_MESSAGE_OPTIONS_LIST_CHANGED:
+          wrapper = new Gst::MessageMixerOptionsListChanged(message);
+          break;
+        case GST_MIXER_MESSAGE_MIXER_CHANGED:
+          wrapper = new Gst::MessageMixerChanged(message);
+          break;
+        default:
+          wrapper = new Gst::MessageCustom(message);
+      }
     }
+
+    // Store the current wrapper in the structure of the message.
+    gst_structure_set(structure, "cpp_wrapper", G_TYPE_POINTER, wrapper,
+      static_cast<void*>(0));
   }
 
+  result = Glib::RefPtr<Gst::Message>(wrapper);
+
   if(result && take_copy)
     result->reference();
 
+  // Hook into the GstMessage finalize function.
+  if(!original_gst_message_finalize_function)
+  {
+    original_gst_message_finalize_function =
+      GST_MINI_OBJECT_GET_CLASS(message)->finalize;
+
+    GST_MINI_OBJECT_GET_CLASS(message)->finalize =
+      gstreamermm_gst_message_finalize_hook_function;
+  }
+
   return result;
 }
 
+#ifdef GLIBMM_VFUNCS_ENABLED
+void Message_Class::finalize_vfunc_callback(GstMiniObject* self)
+{
+  BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(GST_MINI_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+  // Call the original underlying C function:
+  if(base && GST_MINI_OBJECT_CLASS(base)->finalize)
+    (*GST_MINI_OBJECT_CLASS(base)->finalize)(self);
+
+}
+void Message::finalize_vfunc() 
+{
+  BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(gobj())) // Get the parent class of the object class (The original underlying C class).
+  );
+
+  if(base && GST_MINI_OBJECT_CLASS(base)->finalize)
+    (*GST_MINI_OBJECT_CLASS(base)->finalize)(GST_MINI_OBJECT(gobj()));
+}
+#endif //GLIBMM_VFUNCS_ENABLED
+
+
 } //namespace Gst
diff --git a/gstreamer/src/message.hg b/gstreamer/src/message.hg
index 4e1155b..64d2a06 100644
--- a/gstreamer/src/message.hg
+++ b/gstreamer/src/message.hg
@@ -73,9 +73,9 @@ class TagList;
  */
 class Message : public Gst::MiniObject
 {
-protected:
- _CLASS_GSTMINIOBJECT(Message, GstMessage, GST_MESSAGE, Gst::MiniObject, GstMiniObject)
- _IGNORE(gst_message_ref, gst_message_unref)
+  _CLASS_GSTMINIOBJECT(Message, GstMessage, GST_MESSAGE, Gst::MiniObject, GstMiniObject)
+  _IGNORE(gst_message_ref, gst_message_unref)
+
 public:
   /** Wrap a GstMessage* in a C++ instance, creating an instance of a
    *  derived Gst::Message.  Gst::wrap() would just create a Gst::Message
@@ -109,6 +109,21 @@ public:
   /** Get the object that posted the message.
    */
   _MEMBER_GET_GOBJECT(source, src, Gst::Object, GstObject*)
+
+#ifdef GLIBMM_VFUNCS_ENABLED
+  /** Virtual function called when the Gst::Message is about to be finalized.
+   */
+  virtual void finalize_vfunc();
+#endif //GLIBMM_VFUNCS_ENABLED
+
+protected:
+#m4begin
+  _PUSH(SECTION_PCC_CLASS_INIT_VFUNCS)
+  GST_MINI_OBJECT_CLASS(klass)->finalize = &finalize_vfunc_callback;
+  _SECTION(SECTION_PH_VFUNCS)
+  static void finalize_vfunc_callback(GstMiniObject* self);
+  _POP()
+#m4end
 };
 
 //TODO: Modify create methods of derived Message classes to return



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]