[gst-cvs] gstreamer: bytereader: add gst_byte_reader_masked_scan_uint32()
Tim Mueller
tpm at kemper.freedesktop.org
Sat Jun 13 03:00:26 PDT 2009
Module: gstreamer
Branch: master
Commit: 674447fafe0bce733dc85eda4fcf325dba60716a
URL: http://cgit.freedesktop.org/gstreamer/gstreamer/commit/?id=674447fafe0bce733dc85eda4fcf325dba60716a
Author: Tim-Philipp Müller <tim.muller at collabora.co.uk>
Date: Fri Jun 12 18:36:15 2009 +0100
bytereader: add gst_byte_reader_masked_scan_uint32()
Add a pattern scan function similar to the one recently added to
GstAdapter, and a unit test (based on the adapter one).
Fixes #585592.
API: add gst_byte_reader_masked_scan_uint32()
---
docs/libs/gstreamer-libs-sections.txt | 2 +
libs/gst/base/gstbytereader.c | 78 ++++++++++++++++++++++++++++
libs/gst/base/gstbytereader.h | 6 ++
tests/check/libs/bytereader.c | 92 +++++++++++++++++++++++++++++++++
win32/common/libgstbase.def | 1 +
5 files changed, 179 insertions(+), 0 deletions(-)
diff --git a/docs/libs/gstreamer-libs-sections.txt b/docs/libs/gstreamer-libs-sections.txt
index 839c999..ec0ee4c 100644
--- a/docs/libs/gstreamer-libs-sections.txt
+++ b/docs/libs/gstreamer-libs-sections.txt
@@ -446,6 +446,8 @@ gst_byte_reader_peek_float64_be
gst_byte_reader_get_data
gst_byte_reader_peek_data
+
+gst_byte_reader_masked_scan_uint32
</SECTION>
<SECTION>
diff --git a/libs/gst/base/gstbytereader.c b/libs/gst/base/gstbytereader.c
index e08a0bd..40b1385 100644
--- a/libs/gst/base/gstbytereader.c
+++ b/libs/gst/base/gstbytereader.c
@@ -1207,3 +1207,81 @@ gst_byte_reader_peek_data (GstByteReader * reader, guint size,
*val = reader->data + reader->byte;
return TRUE;
}
+
+/**
+ * gst_byte_reader_masked_scan_uint32:
+ * @reader: a #GstByteReader
+ * @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
+ * @size: number of bytes to scan from offset
+ *
+ * Scan for pattern @pattern with applied mask @mask in the adapter data,
+ * starting from offset @offset.
+ *
+ * The bytes in @pattern and @mask are interpreted left-to-right, regardless
+ * of endianness. All four bytes of the pattern must be present in the
+ * adapter for it to match, even if the first or last bytes are masked out.
+ *
+ * It is an error to call this function without making sure that there is
+ * enough data (offset+size bytes) in the byte reader.
+ *
+ * Returns: offset of the first match, or -1 if no match was found.
+ *
+ * Example:
+ * <programlisting>
+ * // Assume the reader contains 0x00 0x01 0x02 ... 0xfe 0xff
+ *
+ * gst_byte_reader_masked_scan_uint32 (reader, 0x00010203, 0xffffffff, 0, 256);
+ * // -> returns 0
+ * gst_byte_reader_masked_scan_uint32 (reader, 0x00010203, 0xffffffff, 1, 255);
+ * // -> returns -1
+ * gst_byte_reader_masked_scan_uint32 (reader, 0x01020304, 0xffffffff, 1, 255);
+ * // -> returns 1
+ * gst_byte_reader_masked_scan_uint32 (reader, 0x0001, 0xffff, 0, 256);
+ * // -> returns -1
+ * gst_byte_reader_masked_scan_uint32 (reader, 0x0203, 0xffff, 0, 256);
+ * // -> returns 0
+ * gst_byte_reader_masked_scan_uint32 (reader, 0x02030000, 0xffff0000, 0, 256);
+ * // -> returns 2
+ * gst_byte_reader_masked_scan_uint32 (reader, 0x02030000, 0xffff0000, 0, 4);
+ * // -> returns -1
+ * </programlisting>
+ *
+ * Since: 0.10.24
+ */
+guint
+gst_byte_reader_masked_scan_uint32 (GstByteReader * reader, guint32 mask,
+ guint32 pattern, guint offset, guint size)
+{
+ const guint8 *data;
+ guint32 state;
+ guint i;
+
+ g_return_val_if_fail (size > 0, -1);
+ g_return_val_if_fail (offset + size <= reader->size, -1);
+
+ /* we can't find the pattern with less than 4 bytes */
+ if (G_UNLIKELY (size < 4))
+ return -1;
+
+ data = reader->data + reader->byte + offset;
+
+ /* set the state to something that does not match */
+ state = ~pattern;
+
+ /* now find data */
+ for (i = 0; i < size; i++) {
+ /* throw away one byte and move in the next byte */
+ state = ((state << 8) | data[i]);
+ if (G_UNLIKELY ((state & mask) == pattern)) {
+ /* we have a match but we need to have skipped at
+ * least 4 bytes to fill the state. */
+ if (G_LIKELY (i >= 3))
+ return offset + i - 3;
+ }
+ }
+
+ /* nothing found */
+ return -1;
+}
diff --git a/libs/gst/base/gstbytereader.h b/libs/gst/base/gstbytereader.h
index 4c672d5..1570f76 100644
--- a/libs/gst/base/gstbytereader.h
+++ b/libs/gst/base/gstbytereader.h
@@ -105,6 +105,12 @@ gboolean gst_byte_reader_peek_float64_be (GstByteReader *reader, gdouble *val);
gboolean gst_byte_reader_get_data (GstByteReader *reader, guint size, const guint8 **val);
gboolean gst_byte_reader_peek_data (GstByteReader *reader, guint size, const guint8 **val);
+guint gst_byte_reader_masked_scan_uint32 (GstByteReader * reader,
+ guint32 mask,
+ guint32 pattern,
+ guint offset,
+ guint size);
+
/**
* GST_BYTE_READER_INIT:
* @data: Data from which the #GstByteReader should read
diff --git a/tests/check/libs/bytereader.c b/tests/check/libs/bytereader.c
index c4ba8f9..607750c 100644
--- a/tests/check/libs/bytereader.c
+++ b/tests/check/libs/bytereader.c
@@ -460,6 +460,97 @@ GST_START_TEST (test_position_tracking)
GST_END_TEST;
+#define do_scan(r,m,p,o,s,x) \
+ fail_unless_equals_int (gst_byte_reader_masked_scan_uint32 (r,m,p,o,s), x);
+
+GST_START_TEST (test_scan)
+{
+ GstByteReader reader;
+ guint8 data[200];
+ guint i;
+
+ /* fill half the buffer with a pattern */
+ for (i = 0; i < 100; i++)
+ data[i] = i;
+
+ gst_byte_reader_init (&reader, data, 100);
+
+ /* find first bytes */
+ do_scan (&reader, 0xffffffff, 0x00010203, 0, 100, 0);
+ do_scan (&reader, 0xffffffff, 0x01020304, 0, 100, 1);
+ do_scan (&reader, 0xffffffff, 0x01020304, 1, 99, 1);
+ /* offset is past the pattern start */
+ do_scan (&reader, 0xffffffff, 0x01020304, 2, 98, -1);
+ /* not enough bytes to find the pattern */
+ do_scan (&reader, 0xffffffff, 0x02030405, 2, 3, -1);
+ do_scan (&reader, 0xffffffff, 0x02030405, 2, 4, 2);
+ /* size does not include the last scanned byte */
+ do_scan (&reader, 0xffffffff, 0x40414243, 0, 0x41, -1);
+ do_scan (&reader, 0xffffffff, 0x40414243, 0, 0x43, -1);
+ do_scan (&reader, 0xffffffff, 0x40414243, 0, 0x44, 0x40);
+ /* past the start */
+ do_scan (&reader, 0xffffffff, 0x40414243, 65, 10, -1);
+ do_scan (&reader, 0xffffffff, 0x40414243, 64, 5, 64);
+ do_scan (&reader, 0xffffffff, 0x60616263, 65, 35, 0x60);
+ do_scan (&reader, 0xffffffff, 0x60616263, 0x60, 4, 0x60);
+ /* past the start */
+ do_scan (&reader, 0xffffffff, 0x60616263, 0x61, 3, -1);
+ do_scan (&reader, 0xffffffff, 0x60616263, 99, 1, -1);
+
+ /* add more data to the buffer */
+ for (i = 100; i < 200; i++)
+ data[i] = i;
+ gst_byte_reader_init (&reader, data, 200);
+
+ /* past the start */
+ do_scan (&reader, 0xffffffff, 0x60616263, 0x61, 6, -1);
+ /* this should work */
+ do_scan (&reader, 0xffffffff, 0x61626364, 0x61, 4, 0x61);
+ /* not enough data */
+ do_scan (&reader, 0xffffffff, 0x62636465, 0x61, 4, -1);
+ do_scan (&reader, 0xffffffff, 0x62636465, 0x61, 5, 0x62);
+ do_scan (&reader, 0xffffffff, 0x62636465, 0, 120, 0x62);
+
+ /* border conditions */
+ do_scan (&reader, 0xffffffff, 0x62636465, 0, 200, 0x62);
+ do_scan (&reader, 0xffffffff, 0x63646566, 0, 200, 0x63);
+ /* we completely searched the first list */
+ do_scan (&reader, 0xffffffff, 0x64656667, 0, 200, 0x64);
+ /* skip first buffer */
+ do_scan (&reader, 0xffffffff, 0x64656667, 0x64, 100, 0x64);
+ /* past the start */
+ do_scan (&reader, 0xffffffff, 0x64656667, 0x65, 10, -1);
+ /* not enough data to scan */
+ do_scan (&reader, 0xffffffff, 0x64656667, 0x63, 4, -1);
+ do_scan (&reader, 0xffffffff, 0x64656667, 0x63, 5, 0x64);
+ do_scan (&reader, 0xffffffff, 0xc4c5c6c7, 0, 199, -1);
+ do_scan (&reader, 0xffffffff, 0xc4c5c6c7, 0x62, 102, 0xc4);
+ /* different masks */
+ do_scan (&reader, 0x00ffffff, 0x00656667, 0x64, 100, 0x64);
+ do_scan (&reader, 0x000000ff, 0x00000000, 0, 100, -1);
+ do_scan (&reader, 0x000000ff, 0x00000003, 0, 100, 0);
+ do_scan (&reader, 0x000000ff, 0x00000061, 0x61, 100, -1);
+ do_scan (&reader, 0xff000000, 0x61000000, 0, 0x62, -1);
+ /* does not even exist */
+ do_scan (&reader, 0x00ffffff, 0xffffffff, 0x65, 99, -1);
+
+ /* flush some bytes */
+ gst_byte_reader_skip (&reader, 0x20);
+
+ do_scan (&reader, 0xffffffff, 0x20212223, 0, 100, 0);
+ do_scan (&reader, 0xffffffff, 0x20212223, 0, 4, 0);
+ do_scan (&reader, 0xffffffff, 0xc4c5c6c7, 0x62, 70, 0xa4);
+ do_scan (&reader, 0xffffffff, 0xc4c5c6c7, 0, 168, 0xa4);
+
+ do_scan (&reader, 0xffffffff, 0xc4c5c6c7, 164, 4, 0xa4);
+ do_scan (&reader, 0xffffffff, 0xc4c5c6c7, 0x44, 100, 0xa4);
+
+ /* not enough bytes */
+ do_scan (&reader, 0xffffffff, 0xc4c5c6c7, 0x44, 99, -1);
+}
+
+GST_END_TEST;
+
static Suite *
gst_byte_reader_suite (void)
{
@@ -476,6 +567,7 @@ gst_byte_reader_suite (void)
tcase_add_test (tc_chain, test_get_float_le);
tcase_add_test (tc_chain, test_get_float_be);
tcase_add_test (tc_chain, test_position_tracking);
+ tcase_add_test (tc_chain, test_scan);
return s;
}
diff --git a/win32/common/libgstbase.def b/win32/common/libgstbase.def
index c3e89b2..f7b2a9d 100644
--- a/win32/common/libgstbase.def
+++ b/win32/common/libgstbase.def
@@ -101,6 +101,7 @@ EXPORTS
gst_byte_reader_get_uint8
gst_byte_reader_init
gst_byte_reader_init_from_buffer
+ gst_byte_reader_masked_scan_uint32
gst_byte_reader_new
gst_byte_reader_new_from_buffer
gst_byte_reader_peek_data
More information about the Gstreamer-commits
mailing list