mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 03:31:05 +00:00
adapter: Add methods to query current offset
API: gst_buffer_prev_offset API: gst_buffer_get_offset_from_discont The gst_buffer_get_offset_from_discont() method allows retrieving the current offset based on the GST_BUFFER_OFFSET of the buffers that were pushed in. The offset will be set initially by the GST_BUFFER_OFFSET of DISCONT buffers, and then incremented by the sizes of the following buffers. The gst_buffer_prev_offset() method allows retrievent the previous GST_BUFFER_OFFSET regardless of flags. It works in the same way as the other gst_buffer_prev_*() methods. https://bugzilla.gnome.org/show_bug.cgi?id=766647
This commit is contained in:
parent
665de91347
commit
67ae0ad225
5 changed files with 267 additions and 3 deletions
|
@ -178,6 +178,8 @@ gst_adapter_prev_pts
|
|||
gst_adapter_prev_dts
|
||||
gst_adapter_prev_pts_at_offset
|
||||
gst_adapter_prev_dts_at_offset
|
||||
gst_adapter_prev_offset
|
||||
gst_adapter_get_offset_from_discont
|
||||
gst_adapter_masked_scan_uint32
|
||||
gst_adapter_masked_scan_uint32_peek
|
||||
<SUBSECTION Standard>
|
||||
|
|
|
@ -92,6 +92,17 @@
|
|||
* gst_adapter_prev_pts_at_offset() can be used to determine the last
|
||||
* seen timestamp at a particular offset in the adapter.
|
||||
*
|
||||
* The adapter will also keep track of the offset of the buffers
|
||||
* (#GST_BUFFER_OFFSET) that were pushed. The last seen offset before the
|
||||
* current position can be queried with gst_adapter_prev_offset(). This function
|
||||
* can optionally return the number of bytes between the start of the buffer
|
||||
* that carried the offset and the current adapter position. If the meaning of
|
||||
* #GST_BUFFER_OFFSET for the stream being handled corresponds to bytes, then
|
||||
* the accumulated offset since the last #GST_BUFFER_FLAG_DISCONT buffer can be
|
||||
* queried with gst_adapter_get_offset_from_discont(). This is useful for
|
||||
* elements that want to track the position of data in the stream based on the
|
||||
* offset of the incoming buffers.
|
||||
*
|
||||
* A last thing to note is that while #GstAdapter is pretty optimized,
|
||||
* merging buffers still might be an operation that requires a malloc() and
|
||||
* memcpy() operation, and these operations are not the fastest. Because of
|
||||
|
@ -118,6 +129,8 @@
|
|||
/* default size for the assembled data buffer */
|
||||
#define DEFAULT_SIZE 4096
|
||||
|
||||
#define INCREASE_OFFSET(a, offs) if ((a)->offset_discont != GST_BUFFER_OFFSET_NONE) { (a)->offset_discont += (offs); }
|
||||
|
||||
static void gst_adapter_flush_unchecked (GstAdapter * adapter, gsize flush);
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_adapter_debug);
|
||||
|
@ -143,10 +156,14 @@ struct _GstAdapter
|
|||
guint64 pts_distance;
|
||||
GstClockTime dts;
|
||||
guint64 dts_distance;
|
||||
guint64 offset;
|
||||
guint64 offset_distance;
|
||||
|
||||
gsize scan_offset;
|
||||
GSList *scan_entry;
|
||||
|
||||
guint64 offset_discont;
|
||||
|
||||
GstMapInfo info;
|
||||
};
|
||||
|
||||
|
@ -181,6 +198,9 @@ gst_adapter_init (GstAdapter * adapter)
|
|||
adapter->pts_distance = 0;
|
||||
adapter->dts = GST_CLOCK_TIME_NONE;
|
||||
adapter->dts_distance = 0;
|
||||
adapter->offset = GST_BUFFER_OFFSET_NONE;
|
||||
adapter->offset_distance = 0;
|
||||
adapter->offset_discont = GST_BUFFER_OFFSET_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -242,14 +262,18 @@ gst_adapter_clear (GstAdapter * adapter)
|
|||
adapter->pts_distance = 0;
|
||||
adapter->dts = GST_CLOCK_TIME_NONE;
|
||||
adapter->dts_distance = 0;
|
||||
adapter->offset = GST_BUFFER_OFFSET_NONE;
|
||||
adapter->offset_distance = 0;
|
||||
adapter->scan_offset = 0;
|
||||
adapter->scan_entry = NULL;
|
||||
adapter->offset_discont = GST_BUFFER_OFFSET_NONE;
|
||||
}
|
||||
|
||||
static inline void
|
||||
update_timestamps (GstAdapter * adapter, GstBuffer * buf)
|
||||
update_timestamps_and_offset (GstAdapter * adapter, GstBuffer * buf)
|
||||
{
|
||||
GstClockTime pts, dts;
|
||||
guint64 offset;
|
||||
|
||||
pts = GST_BUFFER_PTS (buf);
|
||||
if (GST_CLOCK_TIME_IS_VALID (pts)) {
|
||||
|
@ -263,6 +287,18 @@ update_timestamps (GstAdapter * adapter, GstBuffer * buf)
|
|||
adapter->dts = dts;
|
||||
adapter->dts_distance = 0;
|
||||
}
|
||||
offset = GST_BUFFER_OFFSET (buf);
|
||||
if (GST_BUFFER_IS_DISCONT (buf)) {
|
||||
/* Take offset as-is (might be NONE) */
|
||||
adapter->offset_discont = offset;
|
||||
GST_LOG_OBJECT (adapter, "offset discont now %" G_GUINT64_FORMAT,
|
||||
adapter->offset_discont);
|
||||
}
|
||||
if (offset != GST_BUFFER_OFFSET_NONE) {
|
||||
GST_LOG_OBJECT (adapter, "new offset %" G_GUINT64_FORMAT, offset);
|
||||
adapter->offset = offset;
|
||||
adapter->offset_distance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy data into @dest, skipping @skip bytes from the head buffers */
|
||||
|
@ -340,7 +376,7 @@ gst_adapter_push (GstAdapter * adapter, GstBuffer * buf)
|
|||
GST_LOG_OBJECT (adapter, "pushing %p first %" G_GSIZE_FORMAT " bytes",
|
||||
buf, size);
|
||||
adapter->buflist = adapter->buflist_end = g_slist_append (NULL, buf);
|
||||
update_timestamps (adapter, buf);
|
||||
update_timestamps_and_offset (adapter, buf);
|
||||
} else {
|
||||
/* Otherwise append to the end, and advance our end pointer */
|
||||
GST_LOG_OBJECT (adapter, "pushing %p %" G_GSIZE_FORMAT " bytes at end, "
|
||||
|
@ -597,6 +633,8 @@ gst_adapter_flush_unchecked (GstAdapter * adapter, gsize flush)
|
|||
/* distance is always at least the amount of skipped bytes */
|
||||
adapter->pts_distance -= adapter->skip;
|
||||
adapter->dts_distance -= adapter->skip;
|
||||
adapter->offset_distance -= adapter->skip;
|
||||
INCREASE_OFFSET (adapter, -adapter->skip);
|
||||
|
||||
g = adapter->buflist;
|
||||
cur = g->data;
|
||||
|
@ -606,7 +644,9 @@ gst_adapter_flush_unchecked (GstAdapter * adapter, gsize flush)
|
|||
GST_LOG_OBJECT (adapter, "flushing out head buffer");
|
||||
adapter->pts_distance += size;
|
||||
adapter->dts_distance += size;
|
||||
adapter->offset_distance += size;
|
||||
flush -= size;
|
||||
INCREASE_OFFSET (adapter, size);
|
||||
|
||||
gst_buffer_unref (cur);
|
||||
g = g_slist_delete_link (g, g);
|
||||
|
@ -619,7 +659,7 @@ gst_adapter_flush_unchecked (GstAdapter * adapter, gsize flush)
|
|||
}
|
||||
/* there is a new head buffer, update the timestamps */
|
||||
cur = g->data;
|
||||
update_timestamps (adapter, cur);
|
||||
update_timestamps_and_offset (adapter, cur);
|
||||
size = gst_buffer_get_size (cur);
|
||||
}
|
||||
adapter->buflist = g;
|
||||
|
@ -627,6 +667,8 @@ gst_adapter_flush_unchecked (GstAdapter * adapter, gsize flush)
|
|||
adapter->skip = flush;
|
||||
adapter->pts_distance += flush;
|
||||
adapter->dts_distance += flush;
|
||||
adapter->offset_distance += flush;
|
||||
INCREASE_OFFSET (adapter, flush);
|
||||
/* invalidate scan position */
|
||||
adapter->scan_offset = 0;
|
||||
adapter->scan_entry = NULL;
|
||||
|
@ -1311,6 +1353,57 @@ gst_adapter_available_fast (GstAdapter * adapter)
|
|||
return size - adapter->skip;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_adapter_get_offset_from_discont:
|
||||
* @adapter: a #GstAdapter
|
||||
*
|
||||
* Get the offset of the adapter based on the incoming buffer offset. Will only
|
||||
* return valid values if the incoming buffers have valid offsets set on them.
|
||||
*
|
||||
* The offset will be initially recorded for all buffers with
|
||||
* %GST_BUFFER_FLAG_DISCONT on them, and then calculated for all other following
|
||||
* buffers based on their size.
|
||||
*
|
||||
* Since: 1.10
|
||||
*
|
||||
* Returns: The offset. Can be %GST_BUFFER_OFFSET_NONE.
|
||||
*/
|
||||
guint64
|
||||
gst_adapter_get_offset_from_discont (GstAdapter * adapter)
|
||||
{
|
||||
return adapter->offset_discont;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_adapter_prev_offset:
|
||||
* @adapter: a #GstAdapter
|
||||
* @distance: (out) (allow-none): pointer to a location for distance, or %NULL
|
||||
*
|
||||
* Get the offset that was before the current byte in the adapter. When
|
||||
* @distance is given, the amount of bytes between the offset and the current
|
||||
* position is returned.
|
||||
*
|
||||
* The offset is reset to GST_BUFFER_OFFSET_NONE and the distance is set to 0
|
||||
* when the adapter is first created or when it is cleared. This also means that
|
||||
* before the first byte with an offset is removed from the adapter, the offset
|
||||
* and distance returned are GST_BUFFER_OFFSET_NONE and 0 respectively.
|
||||
*
|
||||
* Since: 1.10
|
||||
*
|
||||
* Returns: The previous seen offset.
|
||||
*/
|
||||
guint64
|
||||
gst_adapter_prev_offset (GstAdapter * adapter, guint64 * distance)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_ADAPTER (adapter), GST_BUFFER_OFFSET_NONE);
|
||||
|
||||
if (distance)
|
||||
*distance = adapter->offset_distance;
|
||||
|
||||
return adapter->offset;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_adapter_prev_pts:
|
||||
* @adapter: a #GstAdapter
|
||||
|
|
|
@ -75,6 +75,8 @@ GstClockTime gst_adapter_prev_pts (GstAdapter *adapter, gu
|
|||
GstClockTime gst_adapter_prev_dts (GstAdapter *adapter, guint64 *distance);
|
||||
GstClockTime gst_adapter_prev_pts_at_offset (GstAdapter * adapter, gsize offset, guint64 * distance);
|
||||
GstClockTime gst_adapter_prev_dts_at_offset (GstAdapter * adapter, gsize offset, guint64 * distance);
|
||||
guint64 gst_adapter_prev_offset (GstAdapter *adapter, guint64 *distance);
|
||||
guint64 gst_adapter_get_offset_from_discont (GstAdapter *adapter);
|
||||
|
||||
gssize gst_adapter_masked_scan_uint32 (GstAdapter * adapter, guint32 mask,
|
||||
guint32 pattern, gsize offset, gsize size);
|
||||
|
|
|
@ -364,6 +364,7 @@ GST_START_TEST (test_timestamp)
|
|||
guint64 dist;
|
||||
guint8 *data;
|
||||
const guint8 *cdata;
|
||||
guint64 offset;
|
||||
|
||||
adapter = gst_adapter_new ();
|
||||
fail_unless (adapter != NULL);
|
||||
|
@ -380,6 +381,10 @@ GST_START_TEST (test_timestamp)
|
|||
fail_unless (timestamp == GST_CLOCK_TIME_NONE);
|
||||
fail_unless (dist == 0);
|
||||
|
||||
/* Offset should be undefined */
|
||||
offset = gst_adapter_get_offset_from_discont (adapter);
|
||||
fail_unless (offset == GST_BUFFER_OFFSET_NONE);
|
||||
|
||||
gst_adapter_flush (adapter, 50);
|
||||
avail = gst_adapter_available (adapter);
|
||||
fail_unless (avail == 50);
|
||||
|
@ -389,6 +394,10 @@ GST_START_TEST (test_timestamp)
|
|||
fail_unless (timestamp == GST_CLOCK_TIME_NONE);
|
||||
fail_unless (dist == 50);
|
||||
|
||||
/* Offset still undefined */
|
||||
offset = gst_adapter_get_offset_from_discont (adapter);
|
||||
fail_unless (offset == GST_BUFFER_OFFSET_NONE);
|
||||
|
||||
buffer = gst_buffer_new_and_alloc (100);
|
||||
GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
|
||||
|
||||
|
@ -563,6 +572,161 @@ GST_START_TEST (test_timestamp)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_offset)
|
||||
{
|
||||
GstAdapter *adapter;
|
||||
GstBuffer *buffer;
|
||||
guint avail;
|
||||
guint64 offset;
|
||||
guint64 dist;
|
||||
|
||||
adapter = gst_adapter_new ();
|
||||
fail_unless (adapter != NULL);
|
||||
|
||||
buffer = gst_buffer_new_and_alloc (100);
|
||||
|
||||
/* push in the adapter */
|
||||
gst_adapter_push (adapter, buffer);
|
||||
avail = gst_adapter_available (adapter);
|
||||
fail_unless (avail == 100);
|
||||
|
||||
/* Offset should be undefined */
|
||||
offset = gst_adapter_get_offset_from_discont (adapter);
|
||||
fail_unless_equals_uint64 (offset, GST_BUFFER_OFFSET_NONE);
|
||||
offset = gst_adapter_prev_offset (adapter, &dist);
|
||||
fail_unless_equals_uint64 (offset, GST_BUFFER_OFFSET_NONE);
|
||||
fail_unless_equals_int (dist, 0);
|
||||
|
||||
gst_adapter_flush (adapter, 50);
|
||||
avail = gst_adapter_available (adapter);
|
||||
fail_unless (avail == 50);
|
||||
|
||||
/* Offset still undefined, dist changed though */
|
||||
offset = gst_adapter_get_offset_from_discont (adapter);
|
||||
fail_unless_equals_uint64 (offset, GST_BUFFER_OFFSET_NONE);
|
||||
offset = gst_adapter_prev_offset (adapter, &dist);
|
||||
fail_unless_equals_uint64 (offset, GST_BUFFER_OFFSET_NONE);
|
||||
fail_unless_equals_int (dist, 50);
|
||||
|
||||
/* Let's push in a discont buffer with a valid offset */
|
||||
buffer = gst_buffer_new_and_alloc (100);
|
||||
GST_BUFFER_OFFSET (buffer) = 10000;
|
||||
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
|
||||
|
||||
/* push in the adapter */
|
||||
gst_adapter_push (adapter, buffer);
|
||||
avail = gst_adapter_available (adapter);
|
||||
fail_unless (avail == 150);
|
||||
|
||||
/* offset is still undefined */
|
||||
offset = gst_adapter_get_offset_from_discont (adapter);
|
||||
fail_unless_equals_uint64 (offset, GST_BUFFER_OFFSET_NONE);
|
||||
offset = gst_adapter_prev_offset (adapter, &dist);
|
||||
fail_unless_equals_uint64 (offset, GST_BUFFER_OFFSET_NONE);
|
||||
fail_unless_equals_int (dist, 50);
|
||||
|
||||
/* flush out first buffer we are now at the second buffer offset */
|
||||
gst_adapter_flush (adapter, 50);
|
||||
avail = gst_adapter_available (adapter);
|
||||
fail_unless (avail == 100);
|
||||
|
||||
offset = gst_adapter_get_offset_from_discont (adapter);
|
||||
fail_unless_equals_uint64 (offset, 10000);
|
||||
offset = gst_adapter_prev_offset (adapter, &dist);
|
||||
fail_unless_equals_uint64 (offset, 10000);
|
||||
fail_unless_equals_int (dist, 0);
|
||||
|
||||
/* move some more, we should have an updated offset */
|
||||
gst_adapter_flush (adapter, 50);
|
||||
avail = gst_adapter_available (adapter);
|
||||
fail_unless (avail == 50);
|
||||
|
||||
offset = gst_adapter_get_offset_from_discont (adapter);
|
||||
fail_unless_equals_uint64 (offset, 10050);
|
||||
offset = gst_adapter_prev_offset (adapter, &dist);
|
||||
fail_unless_equals_uint64 (offset, 10000);
|
||||
fail_unless_equals_int (dist, 50);
|
||||
|
||||
/* push a buffer without offset in the adapter (contiguous with the
|
||||
other) */
|
||||
buffer = gst_buffer_new_and_alloc (100);
|
||||
gst_adapter_push (adapter, buffer);
|
||||
avail = gst_adapter_available (adapter);
|
||||
fail_unless (avail == 150);
|
||||
|
||||
/* push a buffer with offset in the adapter (but contiguous with the
|
||||
other), the offset shouldn't be taken into account */
|
||||
buffer = gst_buffer_new_and_alloc (100);
|
||||
GST_BUFFER_OFFSET (buffer) = 50000;
|
||||
gst_adapter_push (adapter, buffer);
|
||||
avail = gst_adapter_available (adapter);
|
||||
fail_unless (avail == 250);
|
||||
|
||||
/* offset still as it was before the push */
|
||||
offset = gst_adapter_get_offset_from_discont (adapter);
|
||||
fail_unless_equals_uint64 (offset, 10050);
|
||||
offset = gst_adapter_prev_offset (adapter, &dist);
|
||||
fail_unless_equals_uint64 (offset, 10000);
|
||||
fail_unless_equals_int (dist, 50);
|
||||
|
||||
/* flush away buffer with the offset */
|
||||
gst_adapter_flush (adapter, 50);
|
||||
avail = gst_adapter_available (adapter);
|
||||
fail_unless (avail == 200);
|
||||
offset = gst_adapter_get_offset_from_discont (adapter);
|
||||
fail_unless_equals_uint64 (offset, 10100);
|
||||
/* The previous valid offset seen is now 100 bytes away */
|
||||
offset = gst_adapter_prev_offset (adapter, &dist);
|
||||
fail_unless_equals_uint64 (offset, 10000);
|
||||
fail_unless_equals_int (dist, 100);
|
||||
|
||||
/* move into the second buffer */
|
||||
gst_adapter_flush (adapter, 50);
|
||||
avail = gst_adapter_available (adapter);
|
||||
fail_unless (avail == 150);
|
||||
offset = gst_adapter_get_offset_from_discont (adapter);
|
||||
fail_unless_equals_uint64 (offset, 10150);
|
||||
offset = gst_adapter_prev_offset (adapter, &dist);
|
||||
fail_unless_equals_uint64 (offset, 10000);
|
||||
fail_unless_equals_int (dist, 150);
|
||||
|
||||
/* move to third buffer, we should still see a continuously increasing
|
||||
* offset and ignore the non-discont offset */
|
||||
gst_adapter_flush (adapter, 50);
|
||||
avail = gst_adapter_available (adapter);
|
||||
fail_unless (avail == 100);
|
||||
offset = gst_adapter_get_offset_from_discont (adapter);
|
||||
fail_unless_equals_uint64 (offset, 10200);
|
||||
/* But the prev_offset *does* give us the actual buffer offset value */
|
||||
offset = gst_adapter_prev_offset (adapter, &dist);
|
||||
fail_unless_equals_uint64 (offset, 50000);
|
||||
fail_unless_equals_int (dist, 0);
|
||||
|
||||
/* move everything out, we end up at the last offset */
|
||||
gst_adapter_flush (adapter, 100);
|
||||
avail = gst_adapter_available (adapter);
|
||||
fail_unless (avail == 0);
|
||||
offset = gst_adapter_get_offset_from_discont (adapter);
|
||||
fail_unless_equals_uint64 (offset, 10300);
|
||||
offset = gst_adapter_prev_offset (adapter, &dist);
|
||||
fail_unless_equals_uint64 (offset, 50000);
|
||||
fail_unless_equals_int (dist, 100);
|
||||
|
||||
/* clear everything */
|
||||
gst_adapter_clear (adapter);
|
||||
avail = gst_adapter_available (adapter);
|
||||
fail_unless (avail == 0);
|
||||
offset = gst_adapter_get_offset_from_discont (adapter);
|
||||
fail_unless_equals_uint64 (offset, GST_BUFFER_OFFSET_NONE);
|
||||
offset = gst_adapter_prev_offset (adapter, &dist);
|
||||
fail_unless_equals_uint64 (offset, GST_BUFFER_OFFSET_NONE);
|
||||
fail_unless_equals_int (dist, 0);
|
||||
|
||||
g_object_unref (adapter);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_scan)
|
||||
{
|
||||
GstAdapter *adapter;
|
||||
|
@ -1064,6 +1228,7 @@ gst_adapter_suite (void)
|
|||
tcase_add_test (tc_chain, test_get_buffer_list);
|
||||
tcase_add_test (tc_chain, test_merge);
|
||||
tcase_add_test (tc_chain, test_take_buffer_fast);
|
||||
tcase_add_test (tc_chain, test_offset);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ EXPORTS
|
|||
gst_adapter_get_buffer_fast
|
||||
gst_adapter_get_buffer_list
|
||||
gst_adapter_get_list
|
||||
gst_adapter_get_offset_from_discont
|
||||
gst_adapter_get_type
|
||||
gst_adapter_map
|
||||
gst_adapter_masked_scan_uint32
|
||||
|
@ -16,6 +17,7 @@ EXPORTS
|
|||
gst_adapter_new
|
||||
gst_adapter_prev_dts
|
||||
gst_adapter_prev_dts_at_offset
|
||||
gst_adapter_prev_offset
|
||||
gst_adapter_prev_pts
|
||||
gst_adapter_prev_pts_at_offset
|
||||
gst_adapter_push
|
||||
|
|
Loading…
Reference in a new issue