diff --git a/docs/libs/gstreamer-libs-sections.txt b/docs/libs/gstreamer-libs-sections.txt index 839c999080..ec0ee4cdb0 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
diff --git a/libs/gst/base/gstbytereader.c b/libs/gst/base/gstbytereader.c index e08a0bdfad..40b1385996 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: + * + * // 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 + * + * + * 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 4c672d5c3d..1570f763e7 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 c4ba8f9752..607750cc7e 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 c3e89b21c7..f7b2a9d800 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