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.
This commit is contained in:
Wim Taymans 2008-06-25 10:53:52 +00:00
parent 7dd35f98f7
commit 23d8478698
5 changed files with 613 additions and 16 deletions

View file

@ -1,3 +1,27 @@
2008-06-25 Wim Taymans <wim.taymans@collabora.co.uk>
* 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 <tim.muller at collabora co uk>
Patch by: Luc Pionchon <luc.pionchon@nokia.com>

View file

@ -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:

View file

@ -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.

View file

@ -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 <wim.taymans@gmail.com>");
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");

View file

@ -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;
}