GstPad: Use gst_pad_set_blocked_async_full() if available.
authorEdward Hervey <bilboed@bilboed.com>
Sun, 22 Feb 2009 19:12:23 +0000 (20:12 +0100)
committerEdward Hervey <bilboed@bilboed.com>
Sun, 22 Feb 2009 19:12:23 +0000 (20:12 +0100)
Avoids leaking arguments.
Fixes #514717

gst/gstpad.override
testsuite/test_pad.py

index 0050ca7..930019f 100644 (file)
 %%
 headers
 
+#if ((GST_VERSION_MAJOR > 0) ||                                    \
+     (GST_VERSION_MAJOR == 0 && GST_VERSION_MINOR > 10) ||         \
+     (GST_VERSION_MAJOR == 0 && GST_VERSION_MINOR == 10 &&         \
+      GST_VERSION_MICRO >= 23) ||                                                 \
+     (GST_VERSION_MAJOR == 0 && GST_VERSION_MINOR == 10 &&         \
+      GST_VERSION_MICRO == 22 && GST_VERSION_NANO > 0))
+#define HAVE_SET_BLOCKED_ASYNC_FULL 1
+#else
+#define HAVE_SET_BLOCKED_ASYNC_FULL 0
+#endif
+
 /* we need to do this until PyClosures get exception handlers */
 #ifndef pyg_closure_set_exception_handler
 #  define pyg_closure_set_exception_handler(ig, nore)
@@ -1331,6 +1342,16 @@ _wrap_gst_pad_get_query_types_default (PyGObject *self)
 %%
 override gst_pad_set_blocked_async args
 
+#if HAVE_SET_BLOCKED_ASYNC_FULL
+static void
+pad_block_destroy_data (gpointer data)
+{
+       PyObject *py_data = (PyObject *) data;
+
+       Py_DECREF (py_data);
+}
+#endif
+
 static void
 pad_block_callback_marshal(GstPad *pad, gboolean blocked, gpointer user_data)
 {
@@ -1397,8 +1418,14 @@ _wrap_gst_pad_set_blocked_async (PyGObject *self, PyObject *args)
     if (data == NULL)
         return NULL;
     pyg_begin_allow_threads;
+#if HAVE_SET_BLOCKED_ASYNC_FULL
+    ret = gst_pad_set_blocked_async_full (GST_PAD (self->obj), blocked,
+        (GstPadBlockCallback) pad_block_callback_marshal, data,
+                               pad_block_destroy_data);
+#else
     ret = gst_pad_set_blocked_async (GST_PAD (self->obj), blocked,
         (GstPadBlockCallback) pad_block_callback_marshal, data);
+#endif
     pyg_end_allow_threads;
     if (ret)
         pret = Py_True;
index e255de4..6460d9a 100644 (file)
@@ -516,40 +516,47 @@ class PadRefCountTest(TestCase):
             self.assertEquals(self.gccollect(), 1) # collected the pad
         gst.debug('going into teardown')
 
-# re-enable this test once #514717 is fixed
-
-# class PadBlockRefcountTest(TestCase):
-#     def testCallbackRefcount(self):
-#         def blocked_cb(pad, blocked):
-#             self.assertTrue(pad.set_blocked_async(False, unblocked_cb))
-
-#         def unblocked_cb(pad, blocked):
-#             pass
-
-#         cb_refcount = sys.getrefcount(blocked_cb)
-#         # sys.getrefcount() returns refcount + 1
-#         self.assertEquals(cb_refcount, 2)
-
-#         fakesrc = gst.element_factory_make('fakesrc')
-#         fakesrc.props.num_buffers = 2
-#         fakesink = gst.element_factory_make('fakesink')
-
-#         pipeline = gst.Pipeline()
-#         pipeline.add(fakesrc, fakesink)
-
-#         fakesrc.link(fakesink)
-
-#         pad = fakesrc.get_pad('src')
-#         pad.set_blocked_async(True, blocked_cb)
-
-#         pipeline.set_state(gst.STATE_PLAYING)
-#         pipeline.get_bus().poll(gst.MESSAGE_EOS, -1)
-#         pipeline.set_state(gst.STATE_NULL)
-
-#         # check that we don't leak a ref to the callback
-#         cb_refcount_after = sys.getrefcount(blocked_cb)
-#         self.assertEquals(cb_refcount_after, cb_refcount)
+class PadBlockTest(TestCase):
+    def testCallbackFlush(self):
+        # check that the same block callback can be called more than once (weird
+        # test but it was broken)
+
+        def blocked_cb(pad, blocked):
+            pad.push_event(gst.event_new_flush_start())
+       
+        pad = gst.Pad('src', gst.PAD_SRC)
+        pad.set_active(True)
+        pad.set_blocked_async(True, blocked_cb)
+
+        for i in xrange(10):
+            buf = gst.Buffer('ciao')
+            pad.push(buf)
+            pad.push_event(gst.event_new_flush_stop())
+
+    def testCallbackRefcount(self):
+        def blocked_cb(pad, blocked):
+            pad.set_blocked_async(False, unblocked_cb)
+
+        def unblocked_cb(pad, blocked):
+            pass
 
+        cb_refcount = sys.getrefcount(blocked_cb)
+        # sys.getrefcount() returns refcount + 1
+        self.assertEquals(cb_refcount, 2)
+       
+        pad = gst.Pad('src', gst.PAD_SRC)
+        pad.set_active(True)
+        pad.set_blocked_async(True, blocked_cb)
+        # set_blocked_async refs the callback
+        self.assertEquals(sys.getrefcount(blocked_cb), 3)
+            
+        buf = gst.Buffer('ciao')
+        pad.push(buf)
+        
+        # in blocked_cb() we called set_blocked_async() with a different
+        # callback, so blocked_cb() should have been unreffed
+        cb_refcount_after = sys.getrefcount(blocked_cb)
+        self.assertEquals(sys.getrefcount(blocked_cb), cb_refcount)
 
 if __name__ == "__main__":
     unittest.main()