Commit 51ac26b8 authored by Edward Hervey's avatar Edward Hervey 🤘

GstPad: Use gst_pad_set_blocked_async_full() if available.

Avoids leaking arguments.
Fixes #514717
parent c09e3207
......@@ -24,6 +24,17 @@
%%
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;
......
......@@ -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()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment