adapter: add support for 0 sized buffers

Add support for 0 sized buffers. This is interesting in combination with the
timestamp functions.

Fixes #629553
This commit is contained in:
Wim Taymans 2010-09-17 12:40:12 +02:00
parent 47743aa7ac
commit 1dde3cb440
2 changed files with 112 additions and 31 deletions

View file

@ -271,10 +271,13 @@ copy_into_unchecked (GstAdapter * adapter, guint8 * dest, guint skip,
while (size > 0) {
g = g_slist_next (g);
buf = g->data;
csize = MIN (GST_BUFFER_SIZE (buf), size);
memcpy (dest, GST_BUFFER_DATA (buf), csize);
size -= csize;
dest += csize;
bsize = GST_BUFFER_SIZE (buf);
if (G_LIKELY (bsize > 0)) {
csize = MIN (bsize, size);
memcpy (dest, GST_BUFFER_DATA (buf), csize);
size -= csize;
dest += csize;
}
}
}
@ -285,8 +288,6 @@ copy_into_unchecked (GstAdapter * adapter, guint8 * dest, guint skip,
*
* Adds the data from @buf to the data stored inside @adapter and takes
* ownership of the buffer.
* Empty buffers will be automatically dereferenced and not stored in the
* @adapter.
*/
void
gst_adapter_push (GstAdapter * adapter, GstBuffer * buf)
@ -297,27 +298,19 @@ gst_adapter_push (GstAdapter * adapter, GstBuffer * buf)
g_return_if_fail (GST_IS_BUFFER (buf));
size = GST_BUFFER_SIZE (buf);
adapter->size += size;
if (G_UNLIKELY (size == 0)) {
/* we can't have empty buffers, several parts in this file rely on it, this
* has some problems for the timestamp tracking. */
GST_LOG_OBJECT (adapter, "discarding empty buffer");
gst_buffer_unref (buf);
/* Note: merging buffers at this point is premature. */
if (G_UNLIKELY (adapter->buflist == NULL)) {
GST_LOG_OBJECT (adapter, "pushing first %u bytes", size);
adapter->buflist = adapter->buflist_end = g_slist_append (NULL, buf);
update_timestamp (adapter, buf);
} else {
adapter->size += size;
/* Note: merging buffers at this point is premature. */
if (G_UNLIKELY (adapter->buflist == NULL)) {
GST_LOG_OBJECT (adapter, "pushing first %u bytes", size);
adapter->buflist = adapter->buflist_end = g_slist_append (NULL, buf);
update_timestamp (adapter, buf);
} else {
/* Otherwise append to the end, and advance our end pointer */
GST_LOG_OBJECT (adapter, "pushing %u bytes at end, size now %u", size,
adapter->size);
adapter->buflist_end = g_slist_append (adapter->buflist_end, buf);
adapter->buflist_end = g_slist_next (adapter->buflist_end);
}
/* Otherwise append to the end, and advance our end pointer */
GST_LOG_OBJECT (adapter, "pushing %u bytes at end, size now %u", size,
adapter->size);
adapter->buflist_end = g_slist_append (adapter->buflist_end, buf);
adapter->buflist_end = g_slist_next (adapter->buflist_end);
}
}
@ -711,22 +704,29 @@ gst_adapter_available (GstAdapter * adapter)
guint
gst_adapter_available_fast (GstAdapter * adapter)
{
GstBuffer *first;
GstBuffer *cur;
guint size;
GSList *g;
g_return_val_if_fail (GST_IS_ADAPTER (adapter), 0);
/* no buffers, we have no data */
if (!adapter->buflist)
/* no data */
if (adapter->size == 0)
return 0;
/* some stuff we already assembled */
if (adapter->assembled_len)
return adapter->assembled_len;
/* take the first buffer and its size */
first = GST_BUFFER_CAST (adapter->buflist->data);
size = GST_BUFFER_SIZE (first);
/* take the first non-zero buffer */
g = adapter->buflist;
while (TRUE) {
cur = g->data;
size = GST_BUFFER_SIZE (cur);
if (size != 0)
break;
g = g_slist_next (g);
}
/* we can quickly get the (remaining) data of the first buffer */
return size - adapter->skip;

View file

@ -335,6 +335,8 @@ GST_START_TEST (test_timestamp)
guint avail;
GstClockTime timestamp;
guint64 dist;
guint8 *data;
const guint8 *cdata;
adapter = gst_adapter_new ();
fail_unless (adapter != NULL);
@ -448,6 +450,85 @@ GST_START_TEST (test_timestamp)
fail_unless (timestamp == GST_CLOCK_TIME_NONE);
fail_unless (dist == 0);
/* push an empty buffer with timestamp in the adapter */
buffer = gst_buffer_new ();
GST_BUFFER_TIMESTAMP (buffer) = 2 * GST_SECOND;
gst_adapter_push (adapter, buffer);
avail = gst_adapter_available (adapter);
fail_unless (avail == 0);
timestamp = gst_adapter_prev_timestamp (adapter, &dist);
fail_unless (timestamp == 2 * GST_SECOND);
fail_unless (dist == 0);
/* push another empty buffer */
buffer = gst_buffer_new ();
GST_BUFFER_TIMESTAMP (buffer) = 3 * GST_SECOND;
gst_adapter_push (adapter, buffer);
avail = gst_adapter_available (adapter);
fail_unless (avail == 0);
timestamp = gst_adapter_prev_timestamp (adapter, &dist);
fail_unless (timestamp == 2 * GST_SECOND);
fail_unless (dist == 0);
/* push a buffer with timestamp in the adapter */
buffer = gst_buffer_new_and_alloc (100);
GST_BUFFER_TIMESTAMP (buffer) = 4 * GST_SECOND;
gst_adapter_push (adapter, buffer);
avail = gst_adapter_available (adapter);
fail_unless (avail == 100);
timestamp = gst_adapter_prev_timestamp (adapter, &dist);
fail_unless (timestamp == 2 * GST_SECOND);
fail_unless (dist == 0);
gst_adapter_flush (adapter, 1);
avail = gst_adapter_available (adapter);
fail_unless (avail == 99);
timestamp = gst_adapter_prev_timestamp (adapter, &dist);
fail_unless (timestamp == 4 * GST_SECOND);
fail_unless (dist == 1);
/* push an empty buffer with timestamp in the adapter */
buffer = gst_buffer_new ();
GST_BUFFER_TIMESTAMP (buffer) = 5 * GST_SECOND;
gst_adapter_push (adapter, buffer);
avail = gst_adapter_available (adapter);
fail_unless (avail == 99);
timestamp = gst_adapter_prev_timestamp (adapter, &dist);
fail_unless (timestamp == 4 * GST_SECOND);
fail_unless (dist == 1);
/* push buffer without timestamp */
buffer = gst_buffer_new_and_alloc (100);
gst_adapter_push (adapter, buffer);
avail = gst_adapter_available (adapter);
fail_unless (avail == 199);
timestamp = gst_adapter_prev_timestamp (adapter, &dist);
fail_unless (timestamp == 4 * GST_SECOND);
fail_unless (dist == 1);
/* remove first buffer, timestamp of empty buffer is visible */
buffer = gst_adapter_take_buffer (adapter, 99);
fail_unless (buffer != NULL);
fail_unless (GST_BUFFER_SIZE (buffer) == 99);
gst_buffer_unref (buffer);
avail = gst_adapter_available (adapter);
fail_unless (avail == 100);
timestamp = gst_adapter_prev_timestamp (adapter, &dist);
fail_unless (timestamp == 5 * GST_SECOND);
fail_unless (dist == 0);
/* remove empty buffer, timestamp still visible */
cdata = gst_adapter_peek (adapter, 50);
fail_unless (cdata != NULL);
data = gst_adapter_take (adapter, 50);
fail_unless (data != NULL);
g_free (data);
avail = gst_adapter_available (adapter);
fail_unless (avail == 50);
timestamp = gst_adapter_prev_timestamp (adapter, &dist);
fail_unless (timestamp == 5 * GST_SECOND);
fail_unless (dist == 50);
g_object_unref (adapter);
}