diff options
author | Wim Taymans <wim.taymans@collabora.co.uk> | 2009-12-24 19:56:55 +0100 |
---|---|---|
committer | Wim Taymans <wim@metal.(none)> | 2009-12-24 19:56:55 +0100 |
commit | 775636e7341c31c86a5871c395d3472fe0f06ed8 (patch) | |
tree | 6d947cb0188fa666b8d852862e347c75e2181fcb | |
parent | 59ace1b9ee9015f0035e32366296b6c6dd199155 (diff) |
adder: be a lot smarter with buffer management
Detect EOS faster.
Try to reuse one of the input buffer as the output buffer. This usually works
and avoids an allocation and a memcpy.
Be smarter with GAP buffers so that they don't get mixed or cleared at all. Also
try to use a GAP buffer as the output buffer when all input buffers are GAP
buffers.
-rw-r--r-- | gst/adder/gstadder.c | 109 |
1 files changed, 62 insertions, 47 deletions
diff --git a/gst/adder/gstadder.c b/gst/adder/gstadder.c index 4fe973946..4dc9fd42e 100644 --- a/gst/adder/gstadder.c +++ b/gst/adder/gstadder.c @@ -1061,8 +1061,7 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data) GstAdder *adder; - GSList *collected; + GSList *collected, *next = NULL; GstFlowReturn ret; - GstBuffer *outbuf = NULL; + GstBuffer *outbuf = NULL, *gapbuf = NULL; gpointer outdata = NULL; guint outsize; - gboolean empty = TRUE; @@ -1082,2 +1081,5 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data) outsize = gst_collect_pads_available (pads); + /* can only happen when no pads to collect or all EOS */ + if (outsize == 0) + goto eos; @@ -1087,7 +1089,9 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data) - for (collected = pads->data; collected; collected = g_slist_next (collected)) { + for (collected = pads->data; collected; collected = next) { GstCollectData *collect_data; GstBuffer *inbuf; - guint8 *indata; - guint insize; + gboolean is_gap; + + /* take next to see if this is the last collectdata */ + next = g_slist_next (collected); @@ -1095,3 +1099,4 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data) - /* get a subbuffer of size bytes */ + /* get a buffer of size bytes, if we get a buffer, it is at least outsize + * bytes big. */ inbuf = gst_collect_pads_take_buffer (pads, collect_data, outsize); @@ -1104,51 +1109,65 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data) - indata = GST_BUFFER_DATA (inbuf); - insize = GST_BUFFER_SIZE (inbuf); + is_gap = GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP); + /* Try to make an output buffer */ if (outbuf == NULL) { - GST_LOG_OBJECT (adder, "channel %p: making output buffer of %d bytes", - collect_data, outsize); + /* if this is a gap buffer but we have some more pads to check, skip it. + * If we are at the last buffer, take it, regardless if it is a GAP + * buffer or not. */ + if (is_gap && next) { + GST_DEBUG_OBJECT (adder, "skipping, non-last GAP buffer"); + /* we keep the GAP buffer, if we don't have anymore buffers (all pads + * EOS, we can use this one as the output buffer. */ + if (gapbuf == NULL) + gapbuf = inbuf; + else + gst_buffer_unref (inbuf); + continue; + } - /* first buffer, alloc outsize. - * FIXME: we can easily subbuffer and _make_writable. - * FIXME: only create empty buffer for first non-gap buffer, so that we - * only use adder function when really adding - */ - outbuf = gst_buffer_new_and_alloc (outsize); + GST_LOG_OBJECT (adder, "channel %p: preparing output buffer of %d bytes", + collect_data, outsize); + /* make data and metadata writable, can simply return the inbuf when we + * are the only one referencing this buffer. If this is the last (and + * only) GAP buffer, it will automatically copy the GAP flag. */ + outbuf = gst_buffer_make_writable (inbuf); outdata = GST_BUFFER_DATA (outbuf); gst_buffer_set_caps (outbuf, GST_PAD_CAPS (adder->srcpad)); - - if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) { - GST_LOG_OBJECT (adder, "channel %p: copying %d bytes from data %p", - collect_data, insize, indata); - /* clear if we are only going to fill a partial buffer */ - if (G_UNLIKELY (outsize > insize)) - memset ((guint8 *) outdata + insize, 0, outsize - insize); - /* and copy the data into it */ - memcpy (outdata, indata, insize); - empty = FALSE; - } else { - /* clear whole buffer */ - GST_LOG_OBJECT (adder, "channel %p: zeroing %d bytes from data %p", - collect_data, insize, indata); - memset (outdata, 0, outsize); - } } else { - if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) { + if (!is_gap) { + /* we had a previous output buffer, mix this non-GAP buffer */ + guint8 *indata; + guint insize; + + indata = GST_BUFFER_DATA (inbuf); + insize = GST_BUFFER_SIZE (inbuf); + + /* all buffers should have outsize, there are no short buffers because we + * asked for the max size above */ + g_assert (insize == outsize); + GST_LOG_OBJECT (adder, "channel %p: mixing %d bytes from data %p", collect_data, insize, indata); + /* further buffers, need to add them */ adder->func ((gpointer) outdata, (gpointer) indata, insize); - empty = FALSE; } else { - GST_LOG_OBJECT (adder, "channel %p: skipping %d bytes from data %p", - collect_data, insize, indata); + /* skip gap buffer */ + GST_LOG_OBJECT (adder, "channel %p: skipping GAP buffer", collect_data); } + gst_buffer_unref (inbuf); } - gst_buffer_unref (inbuf); } - /* can only happen when no pads to collect or all EOS */ - if (outbuf == NULL) - goto eos; + if (outbuf == NULL) { + /* no output buffer, reuse one of the GAP buffers then if we have one */ + if (gapbuf) { + GST_LOG_OBJECT (adder, "reusing GAP buffer %p", gapbuf); + outbuf = gapbuf; + } else + /* assume EOS otherwise, this should not happen, really */ + goto eos; + } else if (gapbuf) + /* we had an output buffer, unref the gapbuffer we kept */ + gst_buffer_unref (gapbuf); @@ -1217,9 +1236,5 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data) - /* if we only processed silence, mark output again as silence */ - if (empty) - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP); - /* send it out */ - GST_LOG_OBJECT (adder, "pushing outbuf, timestamp %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); + GST_LOG_OBJECT (adder, "pushing outbuf %p, timestamp %" GST_TIME_FORMAT, + outbuf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); ret = gst_pad_push (adder->srcpad, outbuf); |