mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
adapter: add _masked_scan_uint32
Add a reasonably optimized new gst_adapter_masked_scan_uint32() function to scan the adapter for a pattern after applying a mask. Add some unit tests. API: GstAdapter::gst_adapter_masked_scan_uint32() Fixes #583187
This commit is contained in:
parent
d6b21ba529
commit
270723c85c
3 changed files with 259 additions and 0 deletions
|
@ -707,3 +707,80 @@ gst_adapter_prev_timestamp (GstAdapter * adapter, guint64 * distance)
|
|||
|
||||
return adapter->priv->timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_adapter_masked_scan_uint32:
|
||||
* @adapter: a #GstAdapter
|
||||
* @mask: mask to apply to data before matching against @pattern
|
||||
* @pattern: pattern to match (after mask is applied)
|
||||
* @offset: offset into the adapter data from which to start scanning, returns
|
||||
* the last scanned position.
|
||||
* @size: number of bytes to scan from offset
|
||||
*
|
||||
* Scan for pattern @pattern with applied mask @mask in the adapter data,
|
||||
* starting from offset @offset.
|
||||
*
|
||||
* It is an error to call this function without making sure that there is
|
||||
* enough data (offset+size bytes) in the adapter.
|
||||
*
|
||||
* Returns: offset of the first match, or -1 if no match was found.
|
||||
*
|
||||
* Since: 0.10.24
|
||||
*/
|
||||
guint
|
||||
gst_adapter_masked_scan_uint32 (GstAdapter * adapter, guint32 mask,
|
||||
guint32 pattern, guint offset, guint size)
|
||||
{
|
||||
GSList *g;
|
||||
guint skip, bsize, i;
|
||||
guint32 state;
|
||||
guint8 *bdata;
|
||||
|
||||
g_return_val_if_fail (size > 0, -1);
|
||||
g_return_val_if_fail (offset + size <= adapter->size, -1);
|
||||
|
||||
/* we can't find the pattern with less than 4 bytes */
|
||||
if (G_UNLIKELY (size < 4))
|
||||
return -1;
|
||||
|
||||
skip = offset + adapter->skip;
|
||||
|
||||
/* first step, do skipping and position on the first buffer */
|
||||
g = adapter->buflist;
|
||||
bsize = GST_BUFFER_SIZE (g->data);
|
||||
while (skip >= bsize) {
|
||||
skip -= bsize;
|
||||
g = g_slist_next (g);
|
||||
bsize = GST_BUFFER_SIZE (g->data);
|
||||
}
|
||||
/* get the data now */
|
||||
bsize -= skip;
|
||||
bdata = GST_BUFFER_DATA (g->data) + skip;
|
||||
|
||||
/* set the state to something that does not match */
|
||||
state = ~pattern;
|
||||
|
||||
/* now find data */
|
||||
while (size > 0) {
|
||||
bsize = MIN (bsize, size);
|
||||
for (i = bsize; i; i--) {
|
||||
state = ((state << 8) | *bdata++);
|
||||
if (G_UNLIKELY ((state & mask) == pattern)) {
|
||||
offset += (bsize - i) - 3;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
size -= bsize;
|
||||
if (size > 0) {
|
||||
/* nothing found yet, go to next buffer */
|
||||
offset += bsize;
|
||||
g = g_slist_next (g);
|
||||
bsize = GST_BUFFER_SIZE (g->data);
|
||||
bdata = GST_BUFFER_DATA (g->data);
|
||||
}
|
||||
}
|
||||
/* nothing found */
|
||||
offset = -1;
|
||||
found:
|
||||
return offset;
|
||||
}
|
||||
|
|
|
@ -95,6 +95,10 @@ guint gst_adapter_available_fast (GstAdapter *adapter);
|
|||
|
||||
GstClockTime gst_adapter_prev_timestamp (GstAdapter *adapter, guint64 *distance);
|
||||
|
||||
guint gst_adapter_masked_scan_uint32 (GstAdapter * adapter, guint32 mask,
|
||||
guint32 pattern, guint offset, guint size);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_ADAPTER_H__ */
|
||||
|
|
|
@ -407,6 +407,183 @@ GST_START_TEST (test_timestamp)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_scan)
|
||||
{
|
||||
GstAdapter *adapter;
|
||||
GstBuffer *buffer;
|
||||
guint8 *data;
|
||||
guint offset;
|
||||
guint i;
|
||||
|
||||
adapter = gst_adapter_new ();
|
||||
fail_unless (adapter != NULL);
|
||||
|
||||
buffer = gst_buffer_new_and_alloc (100);
|
||||
data = GST_BUFFER_DATA (buffer);
|
||||
/* fill with pattern */
|
||||
for (i = 0; i < 100; i++)
|
||||
data[i] = i;
|
||||
|
||||
gst_adapter_push (adapter, buffer);
|
||||
|
||||
/* find first bytes */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x00010203, 0, 100);
|
||||
fail_unless (offset == 0);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x01020304, 0, 100);
|
||||
fail_unless (offset == 1);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x01020304, 1, 99);
|
||||
fail_unless (offset == 1);
|
||||
/* offset is past the pattern start */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x01020304, 2, 98);
|
||||
fail_unless (offset == -1);
|
||||
/* not enough bytes to find the pattern */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x02030405, 2, 3);
|
||||
fail_unless (offset == -1);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x02030405, 2, 4);
|
||||
fail_unless (offset == 2);
|
||||
/* size does not include the last scanned byte */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x40414243, 0, 0x41);
|
||||
fail_unless (offset == -1);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x40414243, 0, 0x43);
|
||||
fail_unless (offset == -1);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x40414243, 0, 0x44);
|
||||
fail_unless (offset == 0x40);
|
||||
/* past the start */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x40414243, 65, 10);
|
||||
fail_unless (offset == -1);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x40414243, 64, 5);
|
||||
fail_unless (offset == 64);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x60616263, 65, 35);
|
||||
fail_unless (offset == 0x60);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x60616263, 0x60, 4);
|
||||
fail_unless (offset == 0x60);
|
||||
/* past the start */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x60616263, 0x61, 3);
|
||||
fail_unless (offset == -1);
|
||||
|
||||
/* add another buffer */
|
||||
buffer = gst_buffer_new_and_alloc (100);
|
||||
data = GST_BUFFER_DATA (buffer);
|
||||
/* fill with pattern */
|
||||
for (i = 0; i < 100; i++)
|
||||
data[i] = i + 100;
|
||||
|
||||
gst_adapter_push (adapter, buffer);
|
||||
|
||||
/* past the start */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x60616263, 0x61, 6);
|
||||
fail_unless (offset == -1);
|
||||
/* this should work */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x61626364, 0x61, 4);
|
||||
fail_unless (offset == 0x61);
|
||||
/* not enough data */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x62636465, 0x61, 4);
|
||||
fail_unless (offset == -1);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x62636465, 0x61, 5);
|
||||
fail_unless (offset == 0x62);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x62636465, 0, 120);
|
||||
fail_unless (offset == 0x62);
|
||||
|
||||
/* border conditions */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x62636465, 0, 200);
|
||||
fail_unless (offset == 0x62);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x63646566, 0, 200);
|
||||
fail_unless (offset == 0x63);
|
||||
/* we completely searched the first list */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x64656667, 0, 200);
|
||||
fail_unless (offset == 0x64);
|
||||
/* skip first buffer */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x64656667, 0x64,
|
||||
100);
|
||||
fail_unless (offset == 0x64);
|
||||
/* past the start */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x64656667, 0x65,
|
||||
10);
|
||||
fail_unless (offset == -1);
|
||||
/* not enough data to scan */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x64656667, 0x63, 4);
|
||||
fail_unless (offset == -1);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x64656667, 0x63, 5);
|
||||
fail_unless (offset == 0x64);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0xc4c5c6c7, 0, 199);
|
||||
fail_unless (offset == -1);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0xc4c5c6c7, 0x62,
|
||||
102);
|
||||
fail_unless (offset == 0xc4);
|
||||
/* different masks */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0x00ffffff, 0x00656667, 0x64,
|
||||
100);
|
||||
fail_unless (offset == 0x64);
|
||||
/* does not even exist */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0x00ffffff, 0xffffffff, 0x65,
|
||||
99);
|
||||
fail_unless (offset == -1);
|
||||
|
||||
/* flush some bytes */
|
||||
gst_adapter_flush (adapter, 0x20);
|
||||
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x20212223, 0, 100);
|
||||
fail_unless (offset == 0);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x20212223, 0, 4);
|
||||
fail_unless (offset == 0);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0xc4c5c6c7, 0x62,
|
||||
70);
|
||||
fail_unless (offset == 0xa4);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0xc4c5c6c7, 0, 168);
|
||||
fail_unless (offset == 0xa4);
|
||||
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0xc4c5c6c7, 164, 4);
|
||||
fail_unless (offset == 0xa4);
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0xc4c5c6c7, 0x44,
|
||||
100);
|
||||
fail_unless (offset == 0xa4);
|
||||
/* not enough bytes */
|
||||
offset =
|
||||
gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0xc4c5c6c7, 0x44,
|
||||
99);
|
||||
fail_unless (offset == -1);
|
||||
|
||||
g_object_unref (adapter);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
gst_adapter_suite (void)
|
||||
{
|
||||
|
@ -423,6 +600,7 @@ gst_adapter_suite (void)
|
|||
tcase_add_test (tc_chain, test_take_order);
|
||||
tcase_add_test (tc_chain, test_take_buf_order);
|
||||
tcase_add_test (tc_chain, test_timestamp);
|
||||
tcase_add_test (tc_chain, test_scan);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue