From 23d8478698a964dd3182504ebf275ac98c773925 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 25 Jun 2008 10:53:52 +0000 Subject: [PATCH] docs/design/part-block.txt: Fix typo. Original commit message from CVS: * docs/design/part-block.txt: Fix typo. * docs/design/part-element-transform.txt: Add notes about why transform needs to know input/output sizes. Add some issues that need to be solved. Add some more use cases. * tests/check/libs/test_transform.c: (gst_test_trans_base_init), (gst_test_trans_class_init), (result_sink_chain), (result_buffer_alloc), (gst_test_trans_new), (gst_test_trans_free), (gst_test_trans_push), (gst_test_trans_pop): * tests/check/libs/transform1.c: (buffer_alloc_pt1), (set_caps_pt1), (GST_START_TEST), (set_caps_pt2), (transform_ip_1), (set_caps_1), (set_caps_ct1), (transform_ct1), (transform_caps_ct1), (transform_size_ct1), (buffer_alloc_ct1), (gst_basetransform_suite): Add suport for different pad templates and buffer-alloc. Add more checks for caps and buffer-alloc. Add checks for proxy buffer alloc. Add unit test for copy transform. --- ChangeLog | 24 ++ docs/design/part-block.txt | 2 +- docs/design/part-element-transform.txt | 77 +++++ tests/check/libs/test_transform.c | 67 +++- tests/check/libs/transform1.c | 459 ++++++++++++++++++++++++- 5 files changed, 613 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3de3107915..5e78243f62 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2008-06-25 Wim Taymans + + * docs/design/part-block.txt: + Fix typo. + + * docs/design/part-element-transform.txt: + Add notes about why transform needs to know input/output sizes. + Add some issues that need to be solved. + Add some more use cases. + + * tests/check/libs/test_transform.c: (gst_test_trans_base_init), + (gst_test_trans_class_init), (result_sink_chain), + (result_buffer_alloc), (gst_test_trans_new), (gst_test_trans_free), + (gst_test_trans_push), (gst_test_trans_pop): + * tests/check/libs/transform1.c: (buffer_alloc_pt1), + (set_caps_pt1), (GST_START_TEST), (set_caps_pt2), (transform_ip_1), + (set_caps_1), (set_caps_ct1), (transform_ct1), + (transform_caps_ct1), (transform_size_ct1), (buffer_alloc_ct1), + (gst_basetransform_suite): + Add suport for different pad templates and buffer-alloc. + Add more checks for caps and buffer-alloc. + Add checks for proxy buffer alloc. + Add unit test for copy transform. + 2008-06-24 Tim-Philipp Müller Patch by: Luc Pionchon diff --git a/docs/design/part-block.txt b/docs/design/part-block.txt index 8be9dbf3ab..7459c4d649 100644 --- a/docs/design/part-block.txt +++ b/docs/design/part-block.txt @@ -125,7 +125,7 @@ Use cases: pipeline. 1) block element1 src pad. This can be done async. - 2) wait for block to happen. at this point nothing flowing between + 2) wait for block to happen. at that point nothing is flowing between element1 and element2 and nothing will flow until unblocked. 3) unlink element1 and element2 4) optional step: make sure data is flushed out of element2: diff --git a/docs/design/part-element-transform.txt b/docs/design/part-element-transform.txt index 3e13765138..3de4ad735a 100644 --- a/docs/design/part-element-transform.txt +++ b/docs/design/part-element-transform.txt @@ -397,3 +397,80 @@ Negotiation <----------------------------------| | | | | + In order to perform passthrough buffer-alloc or pad-alloc, we need to be able + to get the size of the output buffer after the transform. + + For passthrough buffer-alloc, this is trivial: the input size equals the output + size. + + For the copy transform or the in-place transform we need additional function to + retrieve the size. There are two functions: + + - transform_size() + + Given a caps and a size on one pad, and a caps on the other pad, calculate + the size of the other buffer. This function is able to perform all size + transforms and is the prefered method of transforming a size. + + - get_unit_size() + + When the input size and output size are always a multiple of eachother + (audio conversion, ..) we can define a more simple get_unit_size() function. + The transform will use this function to get the same amount of units in the + source and destination buffers. + + For performance reasons, the mapping between caps and size is kept in a cache. + + +Issues +------ + + passthrough and in-place transforms (with writable buffers) never need to + perform a pad-alloc on the srcpad. This means that if upstream negotiation + happens, the transform element will never know about it. + + The transform element will keep therefore track of the allocation pattern of + the peer elements. We can see the following cases: + + - upstream peer calls buffer-alloc on the sinkpad of the transform. In some + cases (see above) this call gets proxied or not. + + - upstream peer does never call buffer-alloc. + + We will keeps state about this allocation pattern and perform the following in + each case respectively: + + - Upstream calls buffer-alloc: In passthrough and (some) in-place we proxy + this call onto the downstream element. If the caps are changed, we mark + a flag that we will require a new pad-alloc for the output of the next + output buffer. + + - upstream peer does not call buffer-alloc: We always perform a pad-alloc + when processing buffers. We can further optimize by only looking at the + returned caps instead of doing a full, needless buffer copy. + + +Use cases +--------- + + videotestsrc ! ximagesink + + - resizing happens because videotestsrc performs pad-alloc. + + videotestsrc peer-alloc=0 ! ximagesink + + - resizing cannot happen because videotestsrc never performs pad-alloc. + + videotestsrc ! videoscale ! ximagesink + + - videoscale is initially configured in passthrough mode, pad-alloc from + videotestsrc is proxied through videoscale. + - pad-alloc will renegotiate a new size in videotestsrc. + + videotestsrc peer-alloc=0 ! videoscale ! ximagesink + + - videoscale is initially configured in passthrough mode. + - videoscale performs pad-alloc because no buffer-alloc is called on the + sinkpad + - resizing the videosink makes videoscale perform the scaling. + diff --git a/tests/check/libs/test_transform.c b/tests/check/libs/test_transform.c index ccb8d01dd3..7493450d04 100644 --- a/tests/check/libs/test_transform.c +++ b/tests/check/libs/test_transform.c @@ -9,6 +9,8 @@ typedef struct GList *buffers; GstElement *trans; GstBaseTransformClass *klass; + + GstPadBufferAllocFunction buffer_alloc; } TestTransData; static GstStaticPadTemplate gst_test_trans_src_template = @@ -56,6 +58,21 @@ struct _GstTestTransClass GST_BOILERPLATE (GstTestTrans, gst_test_trans, GstBaseTransform, GST_TYPE_BASE_TRANSFORM); +static GstFlowReturn (*klass_transform) (GstBaseTransform * trans, + GstBuffer * inbuf, GstBuffer * outbuf) = NULL; +static GstFlowReturn (*klass_transform_ip) (GstBaseTransform * trans, + GstBuffer * buf) = NULL; +static gboolean (*klass_set_caps) (GstBaseTransform * trans, GstCaps * incaps, + GstCaps * outcaps) = NULL; +static GstCaps *(*klass_transform_caps) (GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps) = NULL; +static gboolean (*klass_transform_size) (GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps, + guint * othersize) = NULL; + +static GstStaticPadTemplate *sink_template = &gst_test_trans_sink_template; +static GstStaticPadTemplate *src_template = &gst_test_trans_src_template; + static void gst_test_trans_base_init (gpointer g_class) { @@ -67,18 +84,11 @@ gst_test_trans_base_init (gpointer g_class) "Filter/Test", "Test transform", "Wim Taymans "); gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_test_trans_sink_template)); + gst_static_pad_template_get (sink_template)); gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_test_trans_src_template)); + gst_static_pad_template_get (src_template)); } -static GstFlowReturn (*klass_transform) (GstBaseTransform * trans, - GstBuffer * inbuf, GstBuffer * outbuf) = NULL; -static GstFlowReturn (*klass_transform_ip) (GstBaseTransform * trans, - GstBuffer * buf) = NULL; -static gboolean (*klass_set_caps) (GstBaseTransform * trans, GstCaps * incaps, - GstCaps * outcaps) = NULL; - static void gst_test_trans_class_init (GstTestTransClass * klass) { @@ -90,6 +100,8 @@ gst_test_trans_class_init (GstTestTransClass * klass) trans_class->transform_ip = klass_transform_ip; trans_class->transform = klass_transform; + trans_class->transform_caps = klass_transform_caps; + trans_class->transform_size = klass_transform_size; trans_class->set_caps = klass_set_caps; } @@ -116,23 +128,52 @@ result_sink_chain (GstPad * pad, GstBuffer * buffer) return GST_FLOW_OK; } +static GstFlowReturn +result_buffer_alloc (GstPad * pad, guint64 offset, guint size, GstCaps * caps, + GstBuffer ** buf) +{ + GstFlowReturn res; + TestTransData *data; + + data = gst_pad_get_element_private (pad); + + if (data->buffer_alloc) { + res = data->buffer_alloc (pad, offset, size, caps, buf); + } else { + *buf = gst_buffer_new_and_alloc (size); + gst_buffer_set_caps (*buf, caps); + res = GST_FLOW_OK; + } + + return res; +} + static TestTransData * gst_test_trans_new (void) { TestTransData *res; GstPad *tmp; + GstPadTemplate *templ; res = g_new0 (TestTransData, 1); res->trans = g_object_new (GST_TYPE_TEST_TRANS, NULL); - res->srcpad = - gst_pad_new_from_static_template (&gst_test_trans_src_template, "src"); - res->sinkpad = - gst_pad_new_from_static_template (&gst_test_trans_sink_template, "sink"); + + templ = gst_static_pad_template_get (sink_template); + templ->direction = GST_PAD_SRC; + res->srcpad = gst_pad_new_from_template (templ, "src"); + gst_object_unref (templ); + + templ = gst_static_pad_template_get (src_template); + templ->direction = GST_PAD_SINK; + res->sinkpad = gst_pad_new_from_template (templ, "sink"); + gst_object_unref (templ); + res->klass = GST_BASE_TRANSFORM_GET_CLASS (res->trans); gst_test_trans_set_data (GST_TEST_TRANS (res->trans), res); gst_pad_set_element_private (res->sinkpad, res); + gst_pad_set_bufferalloc_function (res->sinkpad, result_buffer_alloc); gst_pad_set_chain_function (res->sinkpad, result_sink_chain); tmp = gst_element_get_static_pad (res->trans, "sink"); diff --git a/tests/check/libs/transform1.c b/tests/check/libs/transform1.c index 592aa8c2a4..004dad15cc 100644 --- a/tests/check/libs/transform1.c +++ b/tests/check/libs/transform1.c @@ -31,6 +31,35 @@ #include "test_transform.c" +static gboolean buffer_alloc_pt1_called; + +static GstFlowReturn +buffer_alloc_pt1 (GstPad * pad, guint64 offset, guint size, GstCaps * caps, + GstBuffer ** buf) +{ + GST_DEBUG_OBJECT (pad, "buffer_alloc called %" G_GUINT64_FORMAT ", %u, %" + GST_PTR_FORMAT, offset, size, caps); + + buffer_alloc_pt1_called = TRUE; + + *buf = gst_buffer_new_and_alloc (size); + gst_buffer_set_caps (*buf, caps); + + return GST_FLOW_OK; +} + +static gboolean set_caps_pt1_called; + +static gboolean +set_caps_pt1 (GstBaseTransform * trans, GstCaps * incaps, GstCaps * outcaps) +{ + GST_DEBUG_OBJECT (trans, "set_caps called"); + + set_caps_pt1_called = TRUE; + + return TRUE; +} + /* basic passthrough, we don't have any transform functions so we can only * perform passthrough. We also don't have caps, which is fine */ GST_START_TEST (basetransform_chain_pt1) @@ -38,13 +67,25 @@ GST_START_TEST (basetransform_chain_pt1) TestTransData *trans; GstBuffer *buffer; GstFlowReturn res; + GstCaps *caps; + klass_set_caps = set_caps_pt1; trans = gst_test_trans_new (); + trans->buffer_alloc = buffer_alloc_pt1; + + GST_DEBUG_OBJECT (trans, "buffer without caps, size 20"); buffer = gst_buffer_new_and_alloc (20); + buffer_alloc_pt1_called = FALSE; + set_caps_pt1_called = FALSE;; res = gst_test_trans_push (trans, buffer); fail_unless (res == GST_FLOW_OK); +#ifdef FAILING_TESTS + /* FIXME, passthough without pad-alloc, do pad-alloc on the srcpad */ + fail_unless (buffer_alloc_pt1_called == TRUE); +#endif + fail_unless (set_caps_pt1_called == FALSE); buffer = gst_test_trans_pop (trans); fail_unless (buffer != NULL); @@ -54,9 +95,18 @@ GST_START_TEST (basetransform_chain_pt1) gst_buffer_unref (buffer); + GST_DEBUG_OBJECT (trans, "buffer without caps, size 10"); + buffer = gst_buffer_new_and_alloc (10); + buffer_alloc_pt1_called = FALSE; + set_caps_pt1_called = FALSE;; res = gst_test_trans_push (trans, buffer); fail_unless (res == GST_FLOW_OK); +#ifdef FAILING_TESTS + /* FIXME, passthough without pad-alloc, do pad-alloc on the srcpad */ + fail_unless (buffer_alloc_pt1_called == TRUE); +#endif + fail_unless (set_caps_pt1_called == FALSE); buffer = gst_test_trans_pop (trans); fail_unless (buffer != NULL); @@ -66,11 +116,59 @@ GST_START_TEST (basetransform_chain_pt1) gst_buffer_unref (buffer); + /* proxy buffer-alloc without caps */ + GST_DEBUG_OBJECT (trans, "alloc without caps, size 20"); + + buffer_alloc_pt1_called = FALSE; + set_caps_pt1_called = FALSE;; + res = gst_pad_alloc_buffer (trans->srcpad, 0, 20, NULL, &buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (buffer_alloc_pt1_called == TRUE); + fail_unless (set_caps_pt1_called == FALSE); + gst_buffer_unref (buffer); + + /* with caps buffer */ + GST_DEBUG_OBJECT (trans, "alloc with caps, size 10"); + + caps = gst_caps_new_simple ("foo/x-bar", NULL); + buffer_alloc_pt1_called = FALSE; + set_caps_pt1_called = FALSE;; + res = gst_pad_alloc_buffer (trans->srcpad, 0, 10, caps, &buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (buffer_alloc_pt1_called == TRUE); + fail_unless (set_caps_pt1_called == FALSE); + gst_buffer_unref (buffer); + + /* once more */ + buffer_alloc_pt1_called = FALSE; + set_caps_pt1_called = FALSE;; + res = gst_pad_alloc_buffer (trans->srcpad, 0, 10, caps, &buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (buffer_alloc_pt1_called == TRUE); + fail_unless (set_caps_pt1_called == FALSE); + gst_buffer_unref (buffer); + + gst_caps_unref (caps); + gst_test_trans_free (trans); } GST_END_TEST; +static gboolean set_caps_pt2_called; + +static gboolean +set_caps_pt2 (GstBaseTransform * trans, GstCaps * incaps, GstCaps * outcaps) +{ + GST_DEBUG_OBJECT (trans, "set_caps called"); + + set_caps_pt2_called = TRUE; + + fail_unless (gst_caps_is_equal (incaps, outcaps)); + + return TRUE; +} + /* basic passthrough, we don't have any transform functions so we can only * perform passthrough with same caps */ GST_START_TEST (basetransform_chain_pt2) @@ -80,16 +178,27 @@ GST_START_TEST (basetransform_chain_pt2) GstCaps *caps; GstFlowReturn res; + klass_set_caps = set_caps_pt2; trans = gst_test_trans_new (); + trans->buffer_alloc = buffer_alloc_pt1; /* first buffer */ caps = gst_caps_new_simple ("foo/x-bar", NULL); + GST_DEBUG_OBJECT (trans, "buffer with caps, size 20"); + buffer = gst_buffer_new_and_alloc (20); gst_buffer_set_caps (buffer, caps); + buffer_alloc_pt1_called = FALSE; + set_caps_pt2_called = FALSE; res = gst_test_trans_push (trans, buffer); fail_unless (res == GST_FLOW_OK); +#ifdef FAILING_TESTS + /* FIXME, passthough without pad-alloc, do pad-alloc on the srcpad */ + fail_unless (buffer_alloc_pt1_called == TRUE); +#endif + fail_unless (set_caps_pt2_called == TRUE); buffer = gst_test_trans_pop (trans); fail_unless (buffer != NULL); @@ -97,16 +206,37 @@ GST_START_TEST (basetransform_chain_pt2) fail_unless (GST_BUFFER_CAPS (buffer) == caps); gst_buffer_unref (buffer); + + /* with caps buffer */ + GST_DEBUG_OBJECT (trans, "alloc with caps, size 20"); + + buffer_alloc_pt1_called = FALSE; + set_caps_pt2_called = FALSE;; + res = gst_pad_alloc_buffer (trans->srcpad, 0, 20, caps, &buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (buffer_alloc_pt1_called == TRUE); + fail_unless (set_caps_pt2_called == FALSE); + gst_buffer_unref (buffer); + gst_caps_unref (caps); /* second buffer, renegotiates, keeps extra type arg in caps */ caps = gst_caps_new_simple ("foo/x-bar", "type", G_TYPE_INT, 1, NULL); + GST_DEBUG_OBJECT (trans, "buffer with caps, size 10"); + buffer = gst_buffer_new_and_alloc (10); gst_buffer_set_caps (buffer, caps); + buffer_alloc_pt1_called = FALSE; + set_caps_pt2_called = FALSE; res = gst_test_trans_push (trans, buffer); fail_unless (res == GST_FLOW_OK); +#ifdef FAILING_TESTS + /* FIXME, passthough without pad-alloc, do pad-alloc on the srcpad */ + fail_unless (buffer_alloc_pt1_called == TRUE); +#endif + fail_unless (set_caps_pt2_called == TRUE); buffer = gst_test_trans_pop (trans); fail_unless (buffer != NULL); @@ -114,6 +244,33 @@ GST_START_TEST (basetransform_chain_pt2) fail_unless (GST_BUFFER_CAPS (buffer) == caps); gst_buffer_unref (buffer); + + /* with caps buffer */ + GST_DEBUG_OBJECT (trans, "alloc with caps, size 20"); + + buffer_alloc_pt1_called = FALSE; + set_caps_pt2_called = FALSE;; + res = gst_pad_alloc_buffer (trans->srcpad, 0, 20, caps, &buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (buffer_alloc_pt1_called == TRUE); + fail_unless (set_caps_pt2_called == FALSE); + gst_buffer_unref (buffer); + + gst_caps_unref (caps); + + /* with caps that is a superset */ + caps = gst_caps_new_simple ("foo/x-bar", NULL); + + GST_DEBUG_OBJECT (trans, "alloc with superset caps, size 20"); + + buffer_alloc_pt1_called = FALSE; + set_caps_pt2_called = FALSE;; + res = gst_pad_alloc_buffer (trans->srcpad, 0, 20, caps, &buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (buffer_alloc_pt1_called == TRUE); + fail_unless (set_caps_pt2_called == FALSE); + gst_buffer_unref (buffer); + gst_caps_unref (caps); gst_test_trans_free (trans); @@ -147,21 +304,31 @@ GST_START_TEST (basetransform_chain_ip1) klass_transform_ip = transform_ip_1; trans = gst_test_trans_new (); + trans->buffer_alloc = buffer_alloc_pt1; + + GST_DEBUG_OBJECT (trans, "buffer without caps, size 20"); buffer = gst_buffer_new_and_alloc (20); transform_ip_1_called = FALSE;; transform_ip_1_writable = TRUE;; + buffer_alloc_pt1_called = FALSE; res = gst_test_trans_push (trans, buffer); fail_unless (res == GST_FLOW_OK); fail_unless (transform_ip_1_called == TRUE); fail_unless (transform_ip_1_writable == TRUE); +#ifdef FAILING_TESTS + /* FIXME, in-place without pad-alloc, do pad-alloc on the srcpad */ + fail_unless (buffer_alloc_pt1_called == TRUE); +#endif buffer = gst_test_trans_pop (trans); fail_unless (buffer != NULL); fail_unless (GST_BUFFER_SIZE (buffer) == 20); gst_buffer_unref (buffer); + GST_DEBUG_OBJECT (trans, "buffer without caps extra ref, size 20"); + buffer = gst_buffer_new_and_alloc (20); /* take additional ref to make it non-writable */ gst_buffer_ref (buffer); @@ -170,11 +337,13 @@ GST_START_TEST (basetransform_chain_ip1) transform_ip_1_called = FALSE;; transform_ip_1_writable = FALSE;; + buffer_alloc_pt1_called = FALSE; res = gst_test_trans_push (trans, buffer); fail_unless (res == GST_FLOW_OK); fail_unless (transform_ip_1_called == TRUE); - /* copy should have been taken */ + /* copy should have been taken with pad-alloc */ fail_unless (transform_ip_1_writable == TRUE); + fail_unless (buffer_alloc_pt1_called == TRUE); /* after push, get rid of the final ref we had */ gst_buffer_unref (buffer); @@ -186,6 +355,15 @@ GST_START_TEST (basetransform_chain_ip1) fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (buffer) == 1); gst_buffer_unref (buffer); + /* with caps buffer */ + GST_DEBUG_OBJECT (trans, "alloc without caps, size 20"); + + buffer_alloc_pt1_called = FALSE; + res = gst_pad_alloc_buffer (trans->srcpad, 0, 20, NULL, &buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (buffer_alloc_pt1_called == TRUE); + gst_buffer_unref (buffer); + gst_test_trans_free (trans); } @@ -225,33 +403,67 @@ GST_START_TEST (basetransform_chain_ip2) klass_set_caps = set_caps_1; trans = gst_test_trans_new (); + trans->buffer_alloc = buffer_alloc_pt1; + + /* with caps buffer */ + GST_DEBUG_OBJECT (trans, "alloc without caps, size 20"); + + buffer_alloc_pt1_called = FALSE; + res = gst_pad_alloc_buffer (trans->srcpad, 0, 20, NULL, &buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (buffer_alloc_pt1_called == TRUE); + fail_unless (GST_BUFFER_SIZE (buffer) == 20); + fail_unless (GST_BUFFER_CAPS (buffer) == NULL); + gst_buffer_unref (buffer); caps = gst_caps_new_simple ("foo/x-bar", NULL); + /* with caps buffer */ + GST_DEBUG_OBJECT (trans, "alloc with caps, size 20"); + + buffer_alloc_pt1_called = FALSE; + res = gst_pad_alloc_buffer (trans->srcpad, 0, 20, caps, &buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (buffer_alloc_pt1_called == TRUE); + fail_unless (GST_BUFFER_SIZE (buffer) == 20); + fail_unless (GST_BUFFER_CAPS (buffer) == caps); + gst_buffer_unref (buffer); + /* first try to push a buffer without caps, this should fail */ buffer = gst_buffer_new_and_alloc (20); + GST_DEBUG_OBJECT (trans, "buffer without caps, size 20"); + transform_ip_1_called = FALSE;; transform_ip_1_writable = FALSE;; + buffer_alloc_pt1_called = FALSE; set_caps_1_called = FALSE;; res = gst_test_trans_push (trans, buffer); fail_unless (res == GST_FLOW_NOT_NEGOTIATED); fail_unless (transform_ip_1_called == FALSE); fail_unless (transform_ip_1_writable == FALSE); fail_unless (set_caps_1_called == FALSE); + fail_unless (buffer_alloc_pt1_called == FALSE); /* try to push a buffer with caps */ + GST_DEBUG_OBJECT (trans, "buffer with caps, size 20"); + buffer = gst_buffer_new_and_alloc (20); gst_buffer_set_caps (buffer, caps); transform_ip_1_called = FALSE; transform_ip_1_writable = FALSE; set_caps_1_called = FALSE;; + buffer_alloc_pt1_called = FALSE; res = gst_test_trans_push (trans, buffer); fail_unless (res == GST_FLOW_OK); fail_unless (transform_ip_1_called == TRUE); fail_unless (transform_ip_1_writable == TRUE); fail_unless (set_caps_1_called == TRUE); +#ifdef FAILING_TESTS + /* FIXME, in-place without pad-alloc, do pad-alloc on the srcpad */ + fail_unless (buffer_alloc_pt1_called == TRUE); +#endif buffer = gst_test_trans_pop (trans); fail_unless (buffer != NULL); @@ -259,6 +471,17 @@ GST_START_TEST (basetransform_chain_ip2) fail_unless (GST_BUFFER_CAPS (buffer) == caps); gst_buffer_unref (buffer); + /* with caps buffer */ + GST_DEBUG_OBJECT (trans, "alloc with caps, size 20"); + + buffer_alloc_pt1_called = FALSE; + res = gst_pad_alloc_buffer (trans->srcpad, 0, 20, caps, &buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (buffer_alloc_pt1_called == TRUE); + gst_buffer_unref (buffer); + + GST_DEBUG_OBJECT (trans, "buffer with caps extra ref, size 20"); + buffer = gst_buffer_new_and_alloc (20); gst_buffer_set_caps (buffer, caps); /* take additional ref to make it non-writable */ @@ -268,10 +491,12 @@ GST_START_TEST (basetransform_chain_ip2) transform_ip_1_called = FALSE;; transform_ip_1_writable = FALSE;; + buffer_alloc_pt1_called = FALSE; res = gst_test_trans_push (trans, buffer); fail_unless (res == GST_FLOW_OK); fail_unless (transform_ip_1_called == TRUE); fail_unless (transform_ip_1_writable == TRUE); + fail_unless (buffer_alloc_pt1_called == TRUE); /* after push, get rid of the final ref we had */ gst_buffer_unref (buffer); @@ -284,14 +509,243 @@ GST_START_TEST (basetransform_chain_ip2) fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (buffer) == 1); gst_buffer_unref (buffer); + /* with caps buffer */ + GST_DEBUG_OBJECT (trans, "alloc with caps, size 20"); + + buffer_alloc_pt1_called = FALSE; + res = gst_pad_alloc_buffer (trans->srcpad, 0, 20, caps, &buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (buffer_alloc_pt1_called == TRUE); + gst_buffer_unref (buffer); + gst_caps_unref (caps); - trans->klass->transform_ip = NULL; gst_test_trans_free (trans); } GST_END_TEST; +static GstStaticPadTemplate sink_template_ct1 = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("baz/x-foo") + ); + +static gboolean set_caps_ct1_called; + +static gboolean +set_caps_ct1 (GstBaseTransform * trans, GstCaps * incaps, GstCaps * outcaps) +{ + GstCaps *caps1, *caps2; + + GST_DEBUG_OBJECT (trans, "set_caps called"); + + caps1 = gst_caps_new_simple ("baz/x-foo", NULL); + caps2 = gst_caps_new_simple ("foo/x-bar", NULL); + + fail_unless (gst_caps_is_equal (incaps, caps1)); + fail_unless (gst_caps_is_equal (outcaps, caps2)); + + set_caps_ct1_called = TRUE;; + + gst_caps_unref (caps1); + gst_caps_unref (caps2); + + return TRUE; +} + +static gboolean transform_ct_1_called; +static gboolean transform_ct_1_writable; + +static GstFlowReturn +transform_ct1 (GstBaseTransform * trans, GstBuffer * in, GstBuffer * out) +{ + transform_ct_1_called = TRUE; + transform_ct_1_writable = gst_buffer_is_writable (out); + + GST_DEBUG_OBJECT (trans, "writable: %d", transform_ct_1_writable); + + return GST_FLOW_OK; +} + +static GstCaps * +transform_caps_ct1 (GstBaseTransform * trans, GstPadDirection dir, + GstCaps * caps) +{ + GstCaps *res; + + if (dir == GST_PAD_SINK) { + res = gst_caps_new_simple ("foo/x-bar", NULL); + } else { + res = gst_caps_new_simple ("baz/x-foo", NULL); + } + return res; +} + +static gboolean +transform_size_ct1 (GstBaseTransform * trans, GstPadDirection direction, + GstCaps * caps, guint size, GstCaps * othercaps, guint * othersize) +{ + if (direction == GST_PAD_SINK) { + *othersize = size * 2; + } else { + *othersize = size / 2; + } + + return TRUE; +} + +gboolean buffer_alloc_ct1_called; + +static GstFlowReturn +buffer_alloc_ct1 (GstPad * pad, guint64 offset, guint size, GstCaps * caps, + GstBuffer ** buf) +{ + GstCaps *outcaps; + + GST_DEBUG_OBJECT (pad, "buffer_alloc called %" G_GUINT64_FORMAT ", %u, %" + GST_PTR_FORMAT, offset, size, caps); + + buffer_alloc_ct1_called = TRUE; + + outcaps = gst_caps_new_simple ("foo/x-bar", NULL); + fail_unless (gst_caps_is_equal (outcaps, caps)); + gst_caps_unref (outcaps); + + *buf = gst_buffer_new_and_alloc (size); + gst_buffer_set_caps (*buf, caps); + + return GST_FLOW_OK; +} + +/* basic copy-transform, check if the transform function is called, + * buffer should be writable. we also set a setcaps function and + * see if it's called. */ +GST_START_TEST (basetransform_chain_ct1) +{ + TestTransData *trans; + GstBuffer *buffer; + GstFlowReturn res; + GstCaps *incaps, *outcaps; + + sink_template = &sink_template_ct1; + klass_transform = transform_ct1; + klass_set_caps = set_caps_ct1; + klass_transform_caps = transform_caps_ct1; + klass_transform_size = transform_size_ct1; + + trans = gst_test_trans_new (); + trans->buffer_alloc = buffer_alloc_ct1; + + incaps = gst_caps_new_simple ("baz/x-foo", NULL); + outcaps = gst_caps_new_simple ("foo/x-bar", NULL); + +#if 0 + /* without caps buffer, I think this should fail */ + GST_DEBUG_OBJECT (trans, "alloc without caps, size 20"); + + buffer_alloc_ct1_called = FALSE; + res = gst_pad_alloc_buffer (trans->srcpad, 0, 20, NULL, &buffer); + fail_unless (res == GST_FLOW_NOT_NEGOTIATED); + /* should not call pad-alloc because the caps and sizes are different */ + fail_unless (buffer_alloc_ct1_called == FALSE); +#endif + + /* with wrong caps buffer */ + GST_DEBUG_OBJECT (trans, "alloc with wrong caps, size 20"); + + buffer_alloc_ct1_called = FALSE; + res = gst_pad_alloc_buffer (trans->srcpad, 0, 20, outcaps, &buffer); + fail_unless (res == GST_FLOW_NOT_NEGOTIATED); + fail_unless (buffer_alloc_ct1_called == TRUE); + + /* with caps buffer */ + GST_DEBUG_OBJECT (trans, "alloc with caps, size 20"); + + buffer_alloc_ct1_called = FALSE; + res = gst_pad_alloc_buffer (trans->srcpad, 0, 20, incaps, &buffer); + fail_unless (res == GST_FLOW_OK); + /* should not call pad-alloc because the caps and sizes are different */ + fail_unless (buffer_alloc_ct1_called == FALSE); + gst_buffer_unref (buffer); + + /* first try to push a buffer without caps, this should fail */ + buffer = gst_buffer_new_and_alloc (20); + + GST_DEBUG_OBJECT (trans, "buffer without caps"); + + transform_ct_1_called = FALSE;; + transform_ct_1_writable = FALSE;; + set_caps_ct1_called = FALSE;; + buffer_alloc_ct1_called = FALSE; + res = gst_test_trans_push (trans, buffer); + fail_unless (res == GST_FLOW_NOT_NEGOTIATED); + fail_unless (transform_ct_1_called == FALSE); + fail_unless (transform_ct_1_writable == FALSE); + fail_unless (set_caps_ct1_called == FALSE); + fail_unless (buffer_alloc_ct1_called == FALSE); + + /* try to push a buffer with caps */ + buffer = gst_buffer_new_and_alloc (20); + gst_buffer_set_caps (buffer, incaps); + + GST_DEBUG_OBJECT (trans, "buffer with caps %" GST_PTR_FORMAT, incaps); + + transform_ct_1_called = FALSE; + transform_ct_1_writable = FALSE; + set_caps_ct1_called = FALSE;; + buffer_alloc_ct1_called = FALSE; + res = gst_test_trans_push (trans, buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (transform_ct_1_called == TRUE); + fail_unless (transform_ct_1_writable == TRUE); + fail_unless (set_caps_ct1_called == TRUE); + fail_unless (buffer_alloc_ct1_called == TRUE); + + buffer = gst_test_trans_pop (trans); + fail_unless (buffer != NULL); + fail_unless (GST_BUFFER_SIZE (buffer) == 40); + fail_unless (gst_caps_is_equal (GST_BUFFER_CAPS (buffer), outcaps)); + gst_buffer_unref (buffer); + + buffer = gst_buffer_new_and_alloc (20); + gst_buffer_set_caps (buffer, incaps); + /* take additional ref to make it non-writable */ + gst_buffer_ref (buffer); + + fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (buffer) == 2); + + GST_DEBUG_OBJECT (trans, "buffer with caps %" GST_PTR_FORMAT, incaps); + + transform_ct_1_called = FALSE;; + transform_ct_1_writable = FALSE;; + buffer_alloc_ct1_called = FALSE; + res = gst_test_trans_push (trans, buffer); + fail_unless (res == GST_FLOW_OK); + fail_unless (transform_ct_1_called == TRUE); + fail_unless (transform_ct_1_writable == TRUE); + fail_unless (buffer_alloc_ct1_called == TRUE); + /* after push, get rid of the final ref we had */ + gst_buffer_unref (buffer); + + buffer = gst_test_trans_pop (trans); + fail_unless (buffer != NULL); + fail_unless (GST_BUFFER_SIZE (buffer) == 40); + fail_unless (gst_caps_is_equal (GST_BUFFER_CAPS (buffer), outcaps)); + + /* output buffer has refcount 1 */ + fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (buffer) == 1); + gst_buffer_unref (buffer); + + gst_caps_unref (incaps); + gst_caps_unref (outcaps); + + gst_test_trans_free (trans); +} + +GST_END_TEST; + + static Suite * gst_basetransform_suite (void) { @@ -303,6 +757,7 @@ gst_basetransform_suite (void) tcase_add_test (tc, basetransform_chain_pt2); tcase_add_test (tc, basetransform_chain_ip1); tcase_add_test (tc, basetransform_chain_ip2); + tcase_add_test (tc, basetransform_chain_ct1); return s; }