LCOV - code coverage report
Current view: top level - libs/gst/base - gstadapter.c (source / functions) Hit Total Coverage
Test: GStreamer 0.10.32.1 Lines: 261 320 81.6 %
Date: 2011-03-25 Functions: 25 26 96.2 %
Branches: 141 284 49.6 %

           Branch data     Line data    Source code
       1                 :            : /* GStreamer
       2                 :            :  * Copyright (C) 2004 Benjamin Otte <otte@gnome.org>
       3                 :            :  *               2005 Wim Taymans <wim@fluendo.com>
       4                 :            :  *
       5                 :            :  * This library is free software; you can redistribute it and/or
       6                 :            :  * modify it under the terms of the GNU Library General Public
       7                 :            :  * License as published by the Free Software Foundation; either
       8                 :            :  * version 2 of the License, or (at your option) any later version.
       9                 :            :  *
      10                 :            :  * This library is distributed in the hope that it will be useful,
      11                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13                 :            :  * Library General Public License for more details.
      14                 :            :  *
      15                 :            :  * You should have received a copy of the GNU Library General Public
      16                 :            :  * License along with this library; if not, write to the
      17                 :            :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      18                 :            :  * Boston, MA 02111-1307, USA.
      19                 :            :  */
      20                 :            : 
      21                 :            : /**
      22                 :            :  * SECTION:gstadapter
      23                 :            :  * @short_description: adapts incoming data on a sink pad into chunks of N bytes
      24                 :            :  *
      25                 :            :  * This class is for elements that receive buffers in an undesired size.
      26                 :            :  * While for example raw video contains one image per buffer, the same is not
      27                 :            :  * true for a lot of other formats, especially those that come directly from
      28                 :            :  * a file. So if you have undefined buffer sizes and require a specific size,
      29                 :            :  * this object is for you.
      30                 :            :  *
      31                 :            :  * An adapter is created with gst_adapter_new(). It can be freed again with
      32                 :            :  * g_object_unref().
      33                 :            :  *
      34                 :            :  * The theory of operation is like this: All buffers received are put
      35                 :            :  * into the adapter using gst_adapter_push() and the data is then read back
      36                 :            :  * in chunks of the desired size using gst_adapter_peek(). After the data is
      37                 :            :  * processed, it is freed using gst_adapter_flush().
      38                 :            :  *
      39                 :            :  * Other methods such as gst_adapter_take() and gst_adapter_take_buffer()
      40                 :            :  * combine gst_adapter_peek() and gst_adapter_flush() in one method and are
      41                 :            :  * potentially more convenient for some use cases.
      42                 :            :  *
      43                 :            :  * For example, a sink pad's chain function that needs to pass data to a library
      44                 :            :  * in 512-byte chunks could be implemented like this:
      45                 :            :  * |[
      46                 :            :  * static GstFlowReturn
      47                 :            :  * sink_pad_chain (GstPad *pad, GstBuffer *buffer)
      48                 :            :  * {
      49                 :            :  *   MyElement *this;
      50                 :            :  *   GstAdapter *adapter;
      51                 :            :  *   GstFlowReturn ret = GST_FLOW_OK;
      52                 :            :  *
      53                 :            :  *   // will give the element an extra ref; remember to drop it
      54                 :            :  *   this = MY_ELEMENT (gst_pad_get_parent (pad));
      55                 :            :  *   adapter = this->adapter;
      56                 :            :  *
      57                 :            :  *   // put buffer into adapter
      58                 :            :  *   gst_adapter_push (adapter, buffer);
      59                 :            :  *   // while we can read out 512 bytes, process them
      60                 :            :  *   while (gst_adapter_available (adapter) >= 512 && ret == GST_FLOW_OK) {
      61                 :            :  *     // use flowreturn as an error value
      62                 :            :  *     ret = my_library_foo (gst_adapter_peek (adapter, 512));
      63                 :            :  *     gst_adapter_flush (adapter, 512);
      64                 :            :  *   }
      65                 :            :  *
      66                 :            :  *   gst_object_unref (this);
      67                 :            :  *   return ret;
      68                 :            :  * }
      69                 :            :  * ]|
      70                 :            :  *
      71                 :            :  * For another example, a simple element inside GStreamer that uses GstAdapter
      72                 :            :  * is the libvisual element.
      73                 :            :  *
      74                 :            :  * An element using GstAdapter in its sink pad chain function should ensure that
      75                 :            :  * when the FLUSH_STOP event is received, that any queued data is cleared using
      76                 :            :  * gst_adapter_clear(). Data should also be cleared or processed on EOS and
      77                 :            :  * when changing state from #GST_STATE_PAUSED to #GST_STATE_READY.
      78                 :            :  *
      79                 :            :  * Also check the GST_BUFFER_FLAG_DISCONT flag on the buffer. Some elements might
      80                 :            :  * need to clear the adapter after a discontinuity.
      81                 :            :  *
      82                 :            :  * Since 0.10.24, the adapter will keep track of the timestamps of the buffers
      83                 :            :  * that were pushed. The last seen timestamp before the current position
      84                 :            :  * can be queried with gst_adapter_prev_timestamp(). This function can
      85                 :            :  * optionally return the amount of bytes between the start of the buffer that
      86                 :            :  * carried the timestamp and the current adapter position. The distance is
      87                 :            :  * useful when dealing with, for example, raw audio samples because it allows
      88                 :            :  * you to calculate the timestamp of the current adapter position by using the
      89                 :            :  * last seen timestamp and the amount of bytes since.
      90                 :            :  *
      91                 :            :  * A last thing to note is that while GstAdapter is pretty optimized,
      92                 :            :  * merging buffers still might be an operation that requires a malloc() and
      93                 :            :  * memcpy() operation, and these operations are not the fastest. Because of
      94                 :            :  * this, some functions like gst_adapter_available_fast() are provided to help
      95                 :            :  * speed up such cases should you want to. To avoid repeated memory allocations,
      96                 :            :  * gst_adapter_copy() can be used to copy data into a (statically allocated)
      97                 :            :  * user provided buffer.
      98                 :            :  *
      99                 :            :  * GstAdapter is not MT safe. All operations on an adapter must be serialized by
     100                 :            :  * the caller. This is not normally a problem, however, as the normal use case
     101                 :            :  * of GstAdapter is inside one pad's chain function, in which case access is
     102                 :            :  * serialized via the pad's STREAM_LOCK.
     103                 :            :  *
     104                 :            :  * Note that gst_adapter_push() takes ownership of the buffer passed. Use
     105                 :            :  * gst_buffer_ref() before pushing it into the adapter if you still want to
     106                 :            :  * access the buffer later. The adapter will never modify the data in the
     107                 :            :  * buffer pushed in it.
     108                 :            :  *
     109                 :            :  * Last reviewed on 2009-05-13 (0.10.24).
     110                 :            :  */
     111                 :            : 
     112                 :            : #include <gst/gst_private.h>
     113                 :            : #include "gstadapter.h"
     114                 :            : #include <string.h>
     115                 :            : 
     116                 :            : /* default size for the assembled data buffer */
     117                 :            : #define DEFAULT_SIZE 4096
     118                 :            : 
     119                 :            : GST_DEBUG_CATEGORY_STATIC (gst_adapter_debug);
     120                 :            : #define GST_CAT_DEFAULT gst_adapter_debug
     121                 :            : 
     122                 :            : #define GST_ADAPTER_GET_PRIVATE(obj)  \
     123                 :            :    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_ADAPTER, GstAdapterPrivate))
     124                 :            : 
     125                 :            : struct _GstAdapterPrivate
     126                 :            : {
     127                 :            :   GstClockTime timestamp;
     128                 :            :   guint64 distance;
     129                 :            : 
     130                 :            :   guint scan_offset;
     131                 :            :   GSList *scan_entry;
     132                 :            : };
     133                 :            : 
     134                 :            : #define _do_init(thing) \
     135                 :            :   GST_DEBUG_CATEGORY_INIT (gst_adapter_debug, "adapter", 0, "object to splice and merge buffers to desired size")
     136 [ +  + ][ +  - ]:      55649 : GST_BOILERPLATE_FULL (GstAdapter, gst_adapter, GObject, G_TYPE_OBJECT,
     137                 :      55649 :     _do_init);
     138                 :            : 
     139                 :            : static void gst_adapter_dispose (GObject * object);
     140                 :            : static void gst_adapter_finalize (GObject * object);
     141                 :            : 
     142                 :            : static void
     143                 :          8 : gst_adapter_base_init (gpointer g_class)
     144                 :            : {
     145                 :            :   /* nop */
     146                 :          8 : }
     147                 :            : 
     148                 :            : static void
     149                 :          8 : gst_adapter_class_init (GstAdapterClass * klass)
     150                 :            : {
     151                 :          8 :   GObjectClass *object = G_OBJECT_CLASS (klass);
     152                 :            : 
     153                 :          8 :   g_type_class_add_private (klass, sizeof (GstAdapterPrivate));
     154                 :            : 
     155                 :          8 :   object->dispose = gst_adapter_dispose;
     156                 :          8 :   object->finalize = gst_adapter_finalize;
     157                 :          8 : }
     158                 :            : 
     159                 :            : static void
     160                 :          8 : gst_adapter_init (GstAdapter * adapter, GstAdapterClass * g_class)
     161                 :            : {
     162                 :          8 :   adapter->priv = GST_ADAPTER_GET_PRIVATE (adapter);
     163                 :          8 :   adapter->assembled_data = g_malloc (DEFAULT_SIZE);
     164                 :          8 :   adapter->assembled_size = DEFAULT_SIZE;
     165                 :          8 :   adapter->priv->timestamp = GST_CLOCK_TIME_NONE;
     166                 :          8 :   adapter->priv->distance = 0;
     167                 :          8 : }
     168                 :            : 
     169                 :            : static void
     170                 :          8 : gst_adapter_dispose (GObject * object)
     171                 :            : {
     172                 :          8 :   GstAdapter *adapter = GST_ADAPTER (object);
     173                 :            : 
     174                 :          8 :   gst_adapter_clear (adapter);
     175                 :            : 
     176         [ +  - ]:          8 :   GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
     177                 :          8 : }
     178                 :            : 
     179                 :            : static void
     180                 :          8 : gst_adapter_finalize (GObject * object)
     181                 :            : {
     182                 :          8 :   GstAdapter *adapter = GST_ADAPTER (object);
     183                 :            : 
     184                 :          8 :   g_free (adapter->assembled_data);
     185                 :            : 
     186         [ +  - ]:          8 :   GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
     187                 :          8 : }
     188                 :            : 
     189                 :            : /**
     190                 :            :  * gst_adapter_new:
     191                 :            :  *
     192                 :            :  * Creates a new #GstAdapter. Free with g_object_unref().
     193                 :            :  *
     194                 :            :  * Returns: (transfer full): a new #GstAdapter
     195                 :            :  */
     196                 :            : GstAdapter *
     197                 :          8 : gst_adapter_new (void)
     198                 :            : {
     199                 :          8 :   return g_object_newv (GST_TYPE_ADAPTER, 0, NULL);
     200                 :            : }
     201                 :            : 
     202                 :            : /**
     203                 :            :  * gst_adapter_clear:
     204                 :            :  * @adapter: a #GstAdapter
     205                 :            :  *
     206                 :            :  * Removes all buffers from @adapter.
     207                 :            :  */
     208                 :            : void
     209                 :         10 : gst_adapter_clear (GstAdapter * adapter)
     210                 :            : {
     211 [ -  + ][ +  - ]:         20 :   g_return_if_fail (GST_IS_ADAPTER (adapter));
         [ +  - ][ -  + ]
     212                 :            : 
     213                 :         10 :   g_slist_foreach (adapter->buflist, (GFunc) gst_mini_object_unref, NULL);
     214                 :         10 :   g_slist_free (adapter->buflist);
     215                 :         10 :   adapter->buflist = NULL;
     216                 :         10 :   adapter->buflist_end = NULL;
     217                 :         10 :   adapter->size = 0;
     218                 :         10 :   adapter->skip = 0;
     219                 :         10 :   adapter->assembled_len = 0;
     220                 :         10 :   adapter->priv->timestamp = GST_CLOCK_TIME_NONE;
     221                 :         10 :   adapter->priv->distance = 0;
     222                 :         10 :   adapter->priv->scan_offset = 0;
     223                 :         10 :   adapter->priv->scan_entry = NULL;
     224                 :            : }
     225                 :            : 
     226                 :            : static inline void
     227                 :       7513 : update_timestamp (GstAdapter * adapter, GstBuffer * buf)
     228                 :            : {
     229                 :            :   GstClockTime timestamp;
     230                 :            : 
     231                 :       7513 :   timestamp = GST_BUFFER_TIMESTAMP (buf);
     232         [ +  + ]:       7513 :   if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
     233 [ -  + ][ #  # ]:          6 :     GST_LOG_OBJECT (adapter, "new timestamp %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
     234                 :            :         GST_TIME_ARGS (timestamp));
     235                 :          6 :     adapter->priv->timestamp = timestamp;
     236                 :          6 :     adapter->priv->distance = 0;
     237                 :            :   }
     238                 :       7513 : }
     239                 :            : 
     240                 :            : /* copy data into @dest, skipping @skip bytes from the head buffers */
     241                 :            : static void
     242                 :      10001 : copy_into_unchecked (GstAdapter * adapter, guint8 * dest, guint skip,
     243                 :            :     guint size)
     244                 :            : {
     245                 :            :   GSList *g;
     246                 :            :   GstBuffer *buf;
     247                 :            :   guint bsize, csize;
     248                 :            : 
     249                 :            :   /* first step, do skipping */
     250                 :            :   /* we might well be copying where we were scanning */
     251 [ -  + ][ #  # ]:      10001 :   if (adapter->priv->scan_entry && (adapter->priv->scan_offset <= skip)) {
     252                 :          0 :     g = adapter->priv->scan_entry;
     253                 :          0 :     skip -= adapter->priv->scan_offset;
     254                 :            :   } else {
     255                 :      10001 :     g = adapter->buflist;
     256                 :            :   }
     257                 :      10001 :   buf = g->data;
     258                 :      10001 :   bsize = GST_BUFFER_SIZE (buf);
     259         [ -  + ]:      10001 :   while (G_UNLIKELY (skip >= bsize)) {
     260                 :          0 :     skip -= bsize;
     261         [ #  # ]:          0 :     g = g_slist_next (g);
     262                 :          0 :     buf = g->data;
     263                 :          0 :     bsize = GST_BUFFER_SIZE (buf);
     264                 :            :   }
     265                 :            :   /* copy partial buffer */
     266                 :      10001 :   csize = MIN (bsize - skip, size);
     267                 :      10001 :   memcpy (dest, GST_BUFFER_DATA (buf) + skip, csize);
     268                 :      10001 :   size -= csize;
     269                 :      10001 :   dest += csize;
     270                 :            : 
     271                 :            :   /* second step, copy remainder */
     272         [ -  + ]:      10001 :   while (size > 0) {
     273         [ #  # ]:          0 :     g = g_slist_next (g);
     274                 :          0 :     buf = g->data;
     275                 :          0 :     bsize = GST_BUFFER_SIZE (buf);
     276         [ #  # ]:          0 :     if (G_LIKELY (bsize > 0)) {
     277                 :          0 :       csize = MIN (bsize, size);
     278                 :          0 :       memcpy (dest, GST_BUFFER_DATA (buf), csize);
     279                 :          0 :       size -= csize;
     280                 :          0 :       dest += csize;
     281                 :            :     }
     282                 :            :   }
     283                 :      10001 : }
     284                 :            : 
     285                 :            : /**
     286                 :            :  * gst_adapter_push:
     287                 :            :  * @adapter: a #GstAdapter
     288                 :            :  * @buf: (transfer full): a #GstBuffer to add to queue in the adapter
     289                 :            :  *
     290                 :            :  * Adds the data from @buf to the data stored inside @adapter and takes
     291                 :            :  * ownership of the buffer.
     292                 :            :  */
     293                 :            : void
     294                 :       7517 : gst_adapter_push (GstAdapter * adapter, GstBuffer * buf)
     295                 :            : {
     296                 :            :   guint size;
     297                 :            : 
     298 [ -  + ][ +  - ]:       7517 :   g_return_if_fail (GST_IS_ADAPTER (adapter));
         [ +  - ][ -  + ]
     299 [ -  + ][ +  - ]:       7517 :   g_return_if_fail (GST_IS_BUFFER (buf));
         [ +  - ][ -  + ]
     300                 :            : 
     301                 :       7517 :   size = GST_BUFFER_SIZE (buf);
     302                 :       7517 :   adapter->size += size;
     303                 :            : 
     304                 :            :   /* Note: merging buffers at this point is premature. */
     305         [ +  + ]:       7517 :   if (G_UNLIKELY (adapter->buflist == NULL)) {
     306         [ -  + ]:          9 :     GST_LOG_OBJECT (adapter, "pushing first %u bytes", size);
     307                 :          9 :     adapter->buflist = adapter->buflist_end = g_slist_append (NULL, buf);
     308                 :          9 :     update_timestamp (adapter, buf);
     309                 :            :   } else {
     310                 :            :     /* Otherwise append to the end, and advance our end pointer */
     311         [ -  + ]:       7508 :     GST_LOG_OBJECT (adapter, "pushing %u bytes at end, size now %u", size,
     312                 :            :         adapter->size);
     313                 :       7508 :     adapter->buflist_end = g_slist_append (adapter->buflist_end, buf);
     314         [ +  - ]:       7517 :     adapter->buflist_end = g_slist_next (adapter->buflist_end);
     315                 :            :   }
     316                 :            : }
     317                 :            : 
     318                 :            : /* Internal method only. Tries to merge buffers at the head of the queue
     319                 :            :  * to form a single larger buffer of size 'size'. Only merges buffers that
     320                 :            :  * where 'gst_buffer_is_span_fast' returns TRUE.
     321                 :            :  *
     322                 :            :  * Returns TRUE if it managed to merge anything.
     323                 :            :  */
     324                 :            : static gboolean
     325                 :          1 : gst_adapter_try_to_merge_up (GstAdapter * adapter, guint size)
     326                 :            : {
     327                 :            :   GstBuffer *cur, *head;
     328                 :            :   GSList *g;
     329                 :          1 :   gboolean ret = FALSE;
     330                 :            : 
     331                 :          1 :   g = adapter->buflist;
     332         [ -  + ]:          1 :   if (g == NULL)
     333                 :          0 :     return FALSE;
     334                 :            : 
     335                 :          1 :   head = g->data;
     336         [ +  - ]:          1 :   g = g_slist_next (g);
     337                 :            : 
     338                 :            :   /* How large do we want our head buffer? The requested size, plus whatever's
     339                 :            :    * been skipped already */
     340                 :          1 :   size += adapter->skip;
     341                 :            : 
     342 [ +  + ][ +  - ]:          4 :   while (g != NULL && GST_BUFFER_SIZE (head) < size) {
     343                 :          3 :     cur = g->data;
     344         [ -  + ]:          3 :     if (!gst_buffer_is_span_fast (head, cur))
     345                 :          0 :       return ret;
     346                 :            : 
     347                 :            :     /* Merge the head buffer and the next in line */
     348         [ -  + ]:          3 :     GST_LOG_OBJECT (adapter,
     349                 :            :         "Merging buffers of size %u & %u in search of target %u",
     350                 :            :         GST_BUFFER_SIZE (head), GST_BUFFER_SIZE (cur), size);
     351                 :            : 
     352                 :          3 :     head = gst_buffer_join (head, cur);
     353                 :          3 :     ret = TRUE;
     354                 :            : 
     355                 :            :     /* Delete the front list item, and store our new buffer in the 2nd list
     356                 :            :      * item */
     357                 :          3 :     adapter->buflist = g_slist_delete_link (adapter->buflist, adapter->buflist);
     358                 :          3 :     g->data = head;
     359                 :            : 
     360                 :            :     /* invalidate scan position */
     361                 :          3 :     adapter->priv->scan_offset = 0;
     362                 :          3 :     adapter->priv->scan_entry = NULL;
     363                 :            : 
     364         [ +  - ]:          3 :     g = g_slist_next (g);
     365                 :            :   }
     366                 :            : 
     367                 :          1 :   return ret;
     368                 :            : }
     369                 :            : 
     370                 :            : /**
     371                 :            :  * gst_adapter_peek:
     372                 :            :  * @adapter: a #GstAdapter
     373                 :            :  * @size: the number of bytes to peek
     374                 :            :  *
     375                 :            :  * Gets the first @size bytes stored in the @adapter. The returned pointer is
     376                 :            :  * valid until the next function is called on the adapter.
     377                 :            :  *
     378                 :            :  * Note that setting the returned pointer as the data of a #GstBuffer is
     379                 :            :  * incorrect for general-purpose plugins. The reason is that if a downstream
     380                 :            :  * element stores the buffer so that it has access to it outside of the bounds
     381                 :            :  * of its chain function, the buffer will have an invalid data pointer after
     382                 :            :  * your element flushes the bytes. In that case you should use
     383                 :            :  * gst_adapter_take(), which returns a freshly-allocated buffer that you can set
     384                 :            :  * as #GstBuffer malloc_data or the potentially more performant
     385                 :            :  * gst_adapter_take_buffer().
     386                 :            :  *
     387                 :            :  * Returns #NULL if @size bytes are not available.
     388                 :            :  *
     389                 :            :  * Returns: (transfer none) (array length=size): a pointer to the first
     390                 :            :  *     @size bytes of data, or NULL
     391                 :            :  */
     392                 :            : const guint8 *
     393                 :          8 : gst_adapter_peek (GstAdapter * adapter, guint size)
     394                 :            : {
     395                 :            :   GstBuffer *cur;
     396                 :            :   guint skip;
     397                 :            :   guint toreuse, tocopy;
     398                 :            :   guint8 *data;
     399                 :            : 
     400 [ -  + ][ +  - ]:          8 :   g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
         [ +  - ][ -  + ]
     401         [ +  + ]:          8 :   g_return_val_if_fail (size > 0, NULL);
     402                 :            : 
     403                 :            :   /* we don't have enough data, return NULL. This is unlikely
     404                 :            :    * as one usually does an _available() first instead of peeking a
     405                 :            :    * random size. */
     406         [ +  + ]:          7 :   if (G_UNLIKELY (size > adapter->size))
     407                 :          2 :     return NULL;
     408                 :            : 
     409                 :            :   /* we have enough assembled data, return it */
     410         [ -  + ]:          5 :   if (adapter->assembled_len >= size)
     411                 :          0 :     return adapter->assembled_data;
     412                 :            : 
     413                 :            :   /* our head buffer has enough data left, return it */
     414                 :          5 :   cur = adapter->buflist->data;
     415                 :          5 :   skip = adapter->skip;
     416         [ +  - ]:          5 :   if (GST_BUFFER_SIZE (cur) >= size + skip)
     417                 :          5 :     return GST_BUFFER_DATA (cur) + skip;
     418                 :            : 
     419                 :            :   /* We may be able to efficiently merge buffers in our pool to
     420                 :            :    * gather a big enough chunk to return it from the head buffer directly */
     421         [ #  # ]:          0 :   if (gst_adapter_try_to_merge_up (adapter, size)) {
     422                 :            :     /* Merged something! Check if there's enough avail now */
     423                 :          0 :     cur = adapter->buflist->data;
     424         [ #  # ]:          0 :     if (GST_BUFFER_SIZE (cur) >= size + skip)
     425                 :          0 :       return GST_BUFFER_DATA (cur) + skip;
     426                 :            :   }
     427                 :            : 
     428                 :            :   /* see how much data we can reuse from the assembled memory and how much
     429                 :            :    * we need to copy */
     430                 :          0 :   toreuse = adapter->assembled_len;
     431                 :          0 :   tocopy = size - toreuse;
     432                 :            : 
     433                 :            :   /* Gonna need to copy stuff out */
     434         [ #  # ]:          0 :   if (G_UNLIKELY (adapter->assembled_size < size)) {
     435                 :          0 :     adapter->assembled_size = (size / DEFAULT_SIZE + 1) * DEFAULT_SIZE;
     436         [ #  # ]:          0 :     GST_DEBUG_OBJECT (adapter, "resizing internal buffer to %u",
     437                 :            :         adapter->assembled_size);
     438         [ #  # ]:          0 :     if (toreuse == 0) {
     439         [ #  # ]:          0 :       GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "alloc new buffer");
     440                 :            :       /* no g_realloc to avoid a memcpy that is not desired here since we are
     441                 :            :        * not going to reuse any data here */
     442                 :          0 :       g_free (adapter->assembled_data);
     443                 :          0 :       adapter->assembled_data = g_malloc (adapter->assembled_size);
     444                 :            :     } else {
     445                 :            :       /* we are going to reuse all data, realloc then */
     446         [ #  # ]:          0 :       GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "reusing %u bytes", toreuse);
     447                 :          0 :       adapter->assembled_data =
     448                 :          0 :           g_realloc (adapter->assembled_data, adapter->assembled_size);
     449                 :            :     }
     450                 :            :   }
     451         [ #  # ]:          0 :   GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy remaining %u bytes from adapter",
     452                 :            :       tocopy);
     453                 :          0 :   data = adapter->assembled_data;
     454                 :          0 :   copy_into_unchecked (adapter, data + toreuse, skip + toreuse, tocopy);
     455                 :          0 :   adapter->assembled_len = size;
     456                 :            : 
     457                 :          8 :   return adapter->assembled_data;
     458                 :            : }
     459                 :            : 
     460                 :            : /**
     461                 :            :  * gst_adapter_copy:
     462                 :            :  * @adapter: a #GstAdapter
     463                 :            :  * @dest: (out caller-allocates) (array length=size): the memory to copy into
     464                 :            :  * @offset: the bytes offset in the adapter to start from
     465                 :            :  * @size: the number of bytes to copy
     466                 :            :  *
     467                 :            :  * Copies @size bytes of data starting at @offset out of the buffers
     468                 :            :  * contained in @GstAdapter into an array @dest provided by the caller.
     469                 :            :  *
     470                 :            :  * The array @dest should be large enough to contain @size bytes.
     471                 :            :  * The user should check that the adapter has (@offset + @size) bytes
     472                 :            :  * available before calling this function.
     473                 :            :  *
     474                 :            :  * Since: 0.10.12
     475                 :            :  */
     476                 :            : void
     477                 :          0 : gst_adapter_copy (GstAdapter * adapter, guint8 * dest, guint offset, guint size)
     478                 :            : {
     479 [ #  # ][ #  # ]:          0 :   g_return_if_fail (GST_IS_ADAPTER (adapter));
         [ #  # ][ #  # ]
     480         [ #  # ]:          0 :   g_return_if_fail (size > 0);
     481         [ #  # ]:          0 :   g_return_if_fail (offset + size <= adapter->size);
     482                 :            : 
     483                 :          0 :   copy_into_unchecked (adapter, dest, offset + adapter->skip, size);
     484                 :            : }
     485                 :            : 
     486                 :            : /**
     487                 :            :  * gst_adapter_flush:
     488                 :            :  * @adapter: a #GstAdapter
     489                 :            :  * @flush: the number of bytes to flush
     490                 :            :  *
     491                 :            :  * Flushes the first @flush bytes in the @adapter. The caller must ensure that
     492                 :            :  * at least this many bytes are available.
     493                 :            :  *
     494                 :            :  * See also: gst_adapter_peek().
     495                 :            :  */
     496                 :            : static void
     497                 :      24016 : gst_adapter_flush_unchecked (GstAdapter * adapter, guint flush)
     498                 :            : {
     499                 :            :   GstBuffer *cur;
     500                 :            :   guint size;
     501                 :            :   GstAdapterPrivate *priv;
     502                 :            :   GSList *g;
     503                 :            : 
     504         [ -  + ]:      24016 :   GST_LOG_OBJECT (adapter, "flushing %u bytes", flush);
     505                 :            : 
     506                 :      24016 :   priv = adapter->priv;
     507                 :            : 
     508                 :            :   /* clear state */
     509                 :      24016 :   adapter->size -= flush;
     510                 :      24016 :   adapter->assembled_len = 0;
     511                 :            : 
     512                 :            :   /* take skip into account */
     513                 :      24016 :   flush += adapter->skip;
     514                 :            :   /* distance is always at least the amount of skipped bytes */
     515                 :      24016 :   priv->distance -= adapter->skip;
     516                 :            : 
     517                 :      24016 :   g = adapter->buflist;
     518                 :      24016 :   cur = g->data;
     519                 :      24016 :   size = GST_BUFFER_SIZE (cur);
     520         [ +  + ]:      31520 :   while (flush >= size) {
     521                 :            :     /* can skip whole buffer */
     522         [ -  + ]:       7511 :     GST_LOG_OBJECT (adapter, "flushing out head buffer");
     523                 :       7511 :     priv->distance += size;
     524                 :       7511 :     flush -= size;
     525                 :            : 
     526                 :       7511 :     gst_buffer_unref (cur);
     527                 :       7511 :     g = g_slist_delete_link (g, g);
     528                 :            : 
     529         [ +  + ]:       7511 :     if (G_UNLIKELY (g == NULL)) {
     530         [ -  + ]:          7 :       GST_LOG_OBJECT (adapter, "adapter empty now");
     531                 :          7 :       adapter->buflist_end = NULL;
     532                 :          7 :       break;
     533                 :            :     }
     534                 :            :     /* there is a new head buffer, update the timestamp */
     535                 :       7504 :     cur = g->data;
     536                 :       7504 :     update_timestamp (adapter, cur);
     537                 :       7504 :     size = GST_BUFFER_SIZE (cur);
     538                 :            :   }
     539                 :      24016 :   adapter->buflist = g;
     540                 :            :   /* account for the remaining bytes */
     541                 :      24016 :   adapter->skip = flush;
     542                 :      24016 :   adapter->priv->distance += flush;
     543                 :            :   /* invalidate scan position */
     544                 :      24016 :   priv->scan_offset = 0;
     545                 :      24016 :   priv->scan_entry = NULL;
     546                 :      24016 : }
     547                 :            : 
     548                 :            : void
     549                 :         13 : gst_adapter_flush (GstAdapter * adapter, guint flush)
     550                 :            : {
     551 [ -  + ][ +  - ]:         13 :   g_return_if_fail (GST_IS_ADAPTER (adapter));
         [ +  - ][ -  + ]
     552         [ +  + ]:         13 :   g_return_if_fail (flush <= adapter->size);
     553                 :            : 
     554                 :            :   /* flushing out 0 bytes will do nothing */
     555         [ -  + ]:         12 :   if (G_UNLIKELY (flush == 0))
     556                 :          0 :     return;
     557                 :            : 
     558                 :         13 :   gst_adapter_flush_unchecked (adapter, flush);
     559                 :            : }
     560                 :            : 
     561                 :            : /* internal function, nbytes should be flushed after calling this function */
     562                 :            : static guint8 *
     563                 :      10001 : gst_adapter_take_internal (GstAdapter * adapter, guint nbytes)
     564                 :            : {
     565                 :            :   guint8 *data;
     566                 :            :   guint toreuse, tocopy;
     567                 :            : 
     568                 :            :   /* see how much data we can reuse from the assembled memory and how much
     569                 :            :    * we need to copy */
     570                 :      10001 :   toreuse = MIN (nbytes, adapter->assembled_len);
     571                 :      10001 :   tocopy = nbytes - toreuse;
     572                 :            : 
     573                 :            :   /* find memory to return */
     574 [ +  - ][ -  + ]:      10001 :   if (adapter->assembled_size >= nbytes && toreuse > 0) {
     575                 :            :     /* we reuse already allocated memory but only when we're going to reuse
     576                 :            :      * something from it because else we are worse than the malloc and copy
     577                 :            :      * case below */
     578         [ #  # ]:          0 :     GST_LOG_OBJECT (adapter, "reusing %u bytes of assembled data", toreuse);
     579                 :            :     /* we have enough free space in the assembled array */
     580                 :          0 :     data = adapter->assembled_data;
     581                 :            :     /* flush after this function should set the assembled_size to 0 */
     582                 :          0 :     adapter->assembled_data = g_malloc (adapter->assembled_size);
     583                 :            :   } else {
     584         [ -  + ]:      10001 :     GST_LOG_OBJECT (adapter, "allocating %u bytes", nbytes);
     585                 :            :     /* not enough bytes in the assembled array, just allocate new space */
     586                 :      10001 :     data = g_malloc (nbytes);
     587                 :            :     /* reuse what we can from the already assembled data */
     588         [ -  + ]:      10001 :     if (toreuse) {
     589         [ #  # ]:          0 :       GST_LOG_OBJECT (adapter, "reusing %u bytes", toreuse);
     590                 :          0 :       memcpy (data, adapter->assembled_data, toreuse);
     591                 :            :     }
     592                 :            :   }
     593         [ +  - ]:      10001 :   if (tocopy) {
     594                 :            :     /* copy the remaining data */
     595         [ -  + ]:      10001 :     GST_LOG_OBJECT (adapter, "copying %u bytes", tocopy);
     596                 :      10001 :     copy_into_unchecked (adapter, toreuse + data, toreuse + adapter->skip,
     597                 :            :         tocopy);
     598                 :            :   }
     599                 :      10001 :   return data;
     600                 :            : }
     601                 :            : 
     602                 :            : /**
     603                 :            :  * gst_adapter_take:
     604                 :            :  * @adapter: a #GstAdapter
     605                 :            :  * @nbytes: the number of bytes to take
     606                 :            :  *
     607                 :            :  * Returns a freshly allocated buffer containing the first @nbytes bytes of the
     608                 :            :  * @adapter. The returned bytes will be flushed from the adapter.
     609                 :            :  *
     610                 :            :  * Caller owns returned value. g_free after usage.
     611                 :            :  *
     612                 :            :  * Free-function: g_free
     613                 :            :  *
     614                 :            :  * Returns: (transfer full) (array length=nbytes): oven-fresh hot data, or
     615                 :            :  *     #NULL if @nbytes bytes are not available
     616                 :            :  */
     617                 :            : guint8 *
     618                 :      10001 : gst_adapter_take (GstAdapter * adapter, guint nbytes)
     619                 :            : {
     620                 :            :   guint8 *data;
     621                 :            : 
     622 [ -  + ][ +  - ]:      10001 :   g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
         [ +  - ][ -  + ]
     623         [ -  + ]:      10001 :   g_return_val_if_fail (nbytes > 0, NULL);
     624                 :            : 
     625                 :            :   /* we don't have enough data, return NULL. This is unlikely
     626                 :            :    * as one usually does an _available() first instead of peeking a
     627                 :            :    * random size. */
     628         [ -  + ]:      10001 :   if (G_UNLIKELY (nbytes > adapter->size))
     629                 :          0 :     return NULL;
     630                 :            : 
     631                 :      10001 :   data = gst_adapter_take_internal (adapter, nbytes);
     632                 :            : 
     633                 :      10001 :   gst_adapter_flush_unchecked (adapter, nbytes);
     634                 :            : 
     635                 :      10001 :   return data;
     636                 :            : }
     637                 :            : 
     638                 :            : /**
     639                 :            :  * gst_adapter_take_buffer:
     640                 :            :  * @adapter: a #GstAdapter
     641                 :            :  * @nbytes: the number of bytes to take
     642                 :            :  *
     643                 :            :  * Returns a #GstBuffer containing the first @nbytes bytes of the
     644                 :            :  * @adapter. The returned bytes will be flushed from the adapter.
     645                 :            :  * This function is potentially more performant than gst_adapter_take()
     646                 :            :  * since it can reuse the memory in pushed buffers by subbuffering
     647                 :            :  * or merging.
     648                 :            :  *
     649                 :            :  * Caller owns returned value. gst_buffer_unref() after usage.
     650                 :            :  *
     651                 :            :  * Free-function: gst_buffer_unref
     652                 :            :  *
     653                 :            :  * Returns: (transfer full): a #GstBuffer containing the first @nbytes of
     654                 :            :  *     the adapter, or #NULL if @nbytes bytes are not available
     655                 :            :  *
     656                 :            :  * Since: 0.10.6
     657                 :            :  */
     658                 :            : GstBuffer *
     659                 :      14003 : gst_adapter_take_buffer (GstAdapter * adapter, guint nbytes)
     660                 :            : {
     661                 :            :   GstBuffer *buffer;
     662                 :            :   GstBuffer *cur;
     663                 :            :   guint hsize, skip;
     664                 :            :   guint8 *data;
     665                 :            : 
     666 [ -  + ][ +  - ]:      14003 :   g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
         [ +  - ][ -  + ]
     667         [ -  + ]:      14003 :   g_return_val_if_fail (nbytes > 0, NULL);
     668                 :            : 
     669         [ -  + ]:      14003 :   GST_LOG_OBJECT (adapter, "taking buffer of %u bytes", nbytes);
     670                 :            : 
     671                 :            :   /* we don't have enough data, return NULL. This is unlikely
     672                 :            :    * as one usually does an _available() first instead of grabbing a
     673                 :            :    * random size. */
     674         [ -  + ]:      14003 :   if (G_UNLIKELY (nbytes > adapter->size))
     675                 :          0 :     return NULL;
     676                 :            : 
     677                 :      14003 :   cur = adapter->buflist->data;
     678                 :      14003 :   skip = adapter->skip;
     679                 :      14003 :   hsize = GST_BUFFER_SIZE (cur);
     680                 :            : 
     681                 :            :   /* our head buffer has enough data left, return it */
     682 [ +  + ][ +  + ]:      14003 :   if (skip == 0 && hsize == nbytes) {
     683         [ -  + ]:       1001 :     GST_LOG_OBJECT (adapter, "providing buffer of %d bytes as head buffer",
     684                 :            :         nbytes);
     685                 :       1001 :     buffer = gst_buffer_ref (cur);
     686                 :       1001 :     goto done;
     687         [ +  + ]:      13002 :   } else if (hsize >= nbytes + skip) {
     688         [ -  + ]:      13001 :     GST_LOG_OBJECT (adapter, "providing buffer of %d bytes via sub-buffer",
     689                 :            :         nbytes);
     690                 :      13001 :     buffer = gst_buffer_create_sub (cur, skip, nbytes);
     691                 :      13001 :     goto done;
     692                 :            :   }
     693                 :            : 
     694         [ +  - ]:          1 :   if (gst_adapter_try_to_merge_up (adapter, nbytes)) {
     695                 :            :     /* Merged something, let's try again for sub-buffering */
     696                 :          1 :     cur = adapter->buflist->data;
     697         [ +  - ]:          1 :     if (GST_BUFFER_SIZE (cur) >= nbytes + skip) {
     698         [ -  + ]:          1 :       GST_LOG_OBJECT (adapter, "providing buffer of %d bytes via sub-buffer",
     699                 :            :           nbytes);
     700                 :          1 :       buffer = gst_buffer_create_sub (cur, skip, nbytes);
     701                 :          1 :       goto done;
     702                 :            :     }
     703                 :            :   }
     704                 :            : 
     705                 :          0 :   data = gst_adapter_take_internal (adapter, nbytes);
     706                 :            : 
     707                 :          0 :   buffer = gst_buffer_new ();
     708                 :          0 :   GST_BUFFER_SIZE (buffer) = nbytes;
     709                 :          0 :   GST_BUFFER_DATA (buffer) = data;
     710                 :          0 :   GST_BUFFER_MALLOCDATA (buffer) = data;
     711                 :            : 
     712                 :            : done:
     713                 :      14003 :   gst_adapter_flush_unchecked (adapter, nbytes);
     714                 :            : 
     715                 :      14003 :   return buffer;
     716                 :            : }
     717                 :            : 
     718                 :            : /**
     719                 :            :  * gst_adapter_take_list:
     720                 :            :  * @adapter: a #GstAdapter
     721                 :            :  * @nbytes: the number of bytes to take
     722                 :            :  *
     723                 :            :  * Returns a #GList of buffers containing the first @nbytes bytes of the
     724                 :            :  * @adapter. The returned bytes will be flushed from the adapter.
     725                 :            :  * When the caller can deal with individual buffers, this function is more
     726                 :            :  * performant because no memory should be copied.
     727                 :            :  *
     728                 :            :  * Caller owns returned list and contained buffers. gst_buffer_unref() each
     729                 :            :  * buffer in the list before freeing the list after usage.
     730                 :            :  *
     731                 :            :  * Returns: (element-type Gst.Buffer) (transfer full): a #GList of buffers
     732                 :            :  *     containing the first @nbytes of the adapter, or #NULL if @nbytes bytes
     733                 :            :  *     are not available
     734                 :            :  *
     735                 :            :  * Since: 0.10.31
     736                 :            :  */
     737                 :            : GList *
     738                 :       2000 : gst_adapter_take_list (GstAdapter * adapter, guint nbytes)
     739                 :            : {
     740                 :       2000 :   GList *result = NULL, *tail = NULL;
     741                 :            :   GstBuffer *cur;
     742                 :            :   guint hsize, skip;
     743                 :            : 
     744 [ -  + ][ +  - ]:       2000 :   g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
         [ +  - ][ -  + ]
     745         [ -  + ]:       2000 :   g_return_val_if_fail (nbytes <= adapter->size, NULL);
     746                 :            : 
     747         [ -  + ]:       2000 :   GST_LOG_OBJECT (adapter, "taking %u bytes", nbytes);
     748                 :            : 
     749         [ +  + ]:       6000 :   while (nbytes > 0) {
     750                 :       4000 :     cur = adapter->buflist->data;
     751                 :       4000 :     skip = adapter->skip;
     752                 :       4000 :     hsize = MIN (nbytes, GST_BUFFER_SIZE (cur) - skip);
     753                 :            : 
     754                 :       4000 :     cur = gst_adapter_take_buffer (adapter, hsize);
     755                 :            : 
     756         [ +  + ]:       4000 :     if (result == NULL) {
     757                 :       2000 :       result = tail = g_list_append (result, cur);
     758                 :            :     } else {
     759                 :       2000 :       tail = g_list_append (tail, cur);
     760         [ +  - ]:       2000 :       tail = g_list_next (tail);
     761                 :            :     }
     762                 :       4000 :     nbytes -= hsize;
     763                 :            :   }
     764                 :       2000 :   return result;
     765                 :            : }
     766                 :            : 
     767                 :            : /**
     768                 :            :  * gst_adapter_available:
     769                 :            :  * @adapter: a #GstAdapter
     770                 :            :  *
     771                 :            :  * Gets the maximum amount of bytes available, that is it returns the maximum
     772                 :            :  * value that can be supplied to gst_adapter_peek() without that function
     773                 :            :  * returning NULL.
     774                 :            :  *
     775                 :            :  * Returns: number of bytes available in @adapter
     776                 :            :  */
     777                 :            : guint
     778                 :      22034 : gst_adapter_available (GstAdapter * adapter)
     779                 :            : {
     780 [ -  + ][ +  - ]:      22034 :   g_return_val_if_fail (GST_IS_ADAPTER (adapter), 0);
         [ +  - ][ -  + ]
     781                 :            : 
     782                 :      22034 :   return adapter->size;
     783                 :            : }
     784                 :            : 
     785                 :            : /**
     786                 :            :  * gst_adapter_available_fast:
     787                 :            :  * @adapter: a #GstAdapter
     788                 :            :  *
     789                 :            :  * Gets the maximum number of bytes that are immediately available without
     790                 :            :  * requiring any expensive operations (like copying the data into a
     791                 :            :  * temporary buffer).
     792                 :            :  *
     793                 :            :  * Returns: number of bytes that are available in @adapter without expensive
     794                 :            :  * operations
     795                 :            :  */
     796                 :            : guint
     797                 :          4 : gst_adapter_available_fast (GstAdapter * adapter)
     798                 :            : {
     799                 :            :   GstBuffer *cur;
     800                 :            :   guint size;
     801                 :            :   GSList *g;
     802                 :            : 
     803 [ -  + ][ +  - ]:          4 :   g_return_val_if_fail (GST_IS_ADAPTER (adapter), 0);
         [ +  - ][ -  + ]
     804                 :            : 
     805                 :            :   /* no data */
     806         [ +  + ]:          4 :   if (adapter->size == 0)
     807                 :          1 :     return 0;
     808                 :            : 
     809                 :            :   /* some stuff we already assembled */
     810         [ -  + ]:          3 :   if (adapter->assembled_len)
     811                 :          0 :     return adapter->assembled_len;
     812                 :            : 
     813                 :            :   /* take the first non-zero buffer */
     814                 :          3 :   g = adapter->buflist;
     815                 :            :   while (TRUE) {
     816                 :          3 :     cur = g->data;
     817                 :          3 :     size = GST_BUFFER_SIZE (cur);
     818         [ +  - ]:          3 :     if (size != 0)
     819                 :          3 :       break;
     820         [ #  # ]:          0 :     g = g_slist_next (g);
     821                 :          0 :   }
     822                 :            : 
     823                 :            :   /* we can quickly get the (remaining) data of the first buffer */
     824                 :          4 :   return size - adapter->skip;
     825                 :            : }
     826                 :            : 
     827                 :            : /**
     828                 :            :  * gst_adapter_prev_timestamp:
     829                 :            :  * @adapter: a #GstAdapter
     830                 :            :  * @distance: (out) (allow-none): pointer to location for distance, or NULL
     831                 :            :  *
     832                 :            :  * Get the timestamp that was before the current byte in the adapter. When
     833                 :            :  * @distance is given, the amount of bytes between the timestamp and the current
     834                 :            :  * position is returned.
     835                 :            :  *
     836                 :            :  * The timestamp is reset to GST_CLOCK_TIME_NONE and the distance is set to 0 when
     837                 :            :  * the adapter is first created or when it is cleared. This also means that before
     838                 :            :  * the first byte with a timestamp is removed from the adapter, the timestamp
     839                 :            :  * and distance returned are GST_CLOCK_TIME_NONE and 0 respectively.
     840                 :            :  *
     841                 :            :  * Returns: The previously seen timestamp.
     842                 :            :  *
     843                 :            :  * Since: 0.10.24
     844                 :            :  */
     845                 :            : GstClockTime
     846                 :         19 : gst_adapter_prev_timestamp (GstAdapter * adapter, guint64 * distance)
     847                 :            : {
     848 [ -  + ][ +  - ]:         19 :   g_return_val_if_fail (GST_IS_ADAPTER (adapter), GST_CLOCK_TIME_NONE);
         [ +  - ][ -  + ]
     849                 :            : 
     850         [ +  - ]:         19 :   if (distance)
     851                 :         19 :     *distance = adapter->priv->distance;
     852                 :            : 
     853                 :         19 :   return adapter->priv->timestamp;
     854                 :            : }
     855                 :            : 
     856                 :            : /**
     857                 :            :  * gst_adapter_masked_scan_uint32_peek:
     858                 :            :  * @adapter: a #GstAdapter
     859                 :            :  * @mask: mask to apply to data before matching against @pattern
     860                 :            :  * @pattern: pattern to match (after mask is applied)
     861                 :            :  * @offset: offset into the adapter data from which to start scanning, returns
     862                 :            :  *          the last scanned position.
     863                 :            :  * @size: number of bytes to scan from offset
     864                 :            :  * @value: pointer to uint32 to return matching data
     865                 :            :  *
     866                 :            :  * Scan for pattern @pattern with applied mask @mask in the adapter data,
     867                 :            :  * starting from offset @offset.  If a match is found, the value that matched
     868                 :            :  * is returned through @value, otherwise @value is left untouched.
     869                 :            :  *
     870                 :            :  * The bytes in @pattern and @mask are interpreted left-to-right, regardless
     871                 :            :  * of endianness.  All four bytes of the pattern must be present in the
     872                 :            :  * adapter for it to match, even if the first or last bytes are masked out.
     873                 :            :  *
     874                 :            :  * It is an error to call this function without making sure that there is
     875                 :            :  * enough data (offset+size bytes) in the adapter.
     876                 :            :  *
     877                 :            :  * Returns: offset of the first match, or -1 if no match was found.
     878                 :            :  *
     879                 :            :  * Since: 0.10.30
     880                 :            :  */
     881                 :            : guint
     882                 :         42 : gst_adapter_masked_scan_uint32_peek (GstAdapter * adapter, guint32 mask,
     883                 :            :     guint32 pattern, guint offset, guint size, guint32 * value)
     884                 :            : {
     885                 :            :   GSList *g;
     886                 :            :   guint skip, bsize, i;
     887                 :            :   guint32 state;
     888                 :            :   guint8 *bdata;
     889                 :            :   GstBuffer *buf;
     890                 :            : 
     891         [ -  + ]:         42 :   g_return_val_if_fail (size > 0, -1);
     892         [ -  + ]:         42 :   g_return_val_if_fail (offset + size <= adapter->size, -1);
     893         [ +  + ]:         42 :   g_return_val_if_fail (((~mask) & pattern) == 0, -1);
     894                 :            : 
     895                 :            :   /* we can't find the pattern with less than 4 bytes */
     896         [ +  + ]:         41 :   if (G_UNLIKELY (size < 4))
     897                 :          3 :     return -1;
     898                 :            : 
     899                 :         38 :   skip = offset + adapter->skip;
     900                 :            : 
     901                 :            :   /* first step, do skipping and position on the first buffer */
     902                 :            :   /* optimistically assume scanning continues sequentially */
     903 [ +  + ][ +  + ]:         38 :   if (adapter->priv->scan_entry && (adapter->priv->scan_offset <= skip)) {
     904                 :          6 :     g = adapter->priv->scan_entry;
     905                 :          6 :     skip -= adapter->priv->scan_offset;
     906                 :            :   } else {
     907                 :         32 :     g = adapter->buflist;
     908                 :         32 :     adapter->priv->scan_offset = 0;
     909                 :         32 :     adapter->priv->scan_entry = NULL;
     910                 :            :   }
     911                 :         38 :   buf = g->data;
     912                 :         38 :   bsize = GST_BUFFER_SIZE (buf);
     913         [ +  + ]:         39 :   while (G_UNLIKELY (skip >= bsize)) {
     914                 :          1 :     skip -= bsize;
     915         [ +  - ]:          1 :     g = g_slist_next (g);
     916                 :          1 :     adapter->priv->scan_offset += bsize;
     917                 :          1 :     adapter->priv->scan_entry = g;
     918                 :          1 :     buf = g->data;
     919                 :          1 :     bsize = GST_BUFFER_SIZE (buf);
     920                 :            :   }
     921                 :            :   /* get the data now */
     922                 :         38 :   bsize -= skip;
     923                 :         38 :   bdata = GST_BUFFER_DATA (buf) + skip;
     924                 :         38 :   skip = 0;
     925                 :            : 
     926                 :            :   /* set the state to something that does not match */
     927                 :         38 :   state = ~pattern;
     928                 :            : 
     929                 :            :   /* now find data */
     930                 :            :   do {
     931                 :         52 :     bsize = MIN (bsize, size);
     932         [ +  + ]:       1904 :     for (i = 0; i < bsize; i++) {
     933                 :       1877 :       state = ((state << 8) | bdata[i]);
     934         [ +  + ]:       1877 :       if (G_UNLIKELY ((state & mask) == pattern)) {
     935                 :            :         /* we have a match but we need to have skipped at
     936                 :            :          * least 4 bytes to fill the state. */
     937         [ +  + ]:         27 :         if (G_LIKELY (skip + i >= 3)) {
     938         [ -  + ]:         25 :           if (G_LIKELY (value))
     939                 :          0 :             *value = state;
     940                 :         25 :           return offset + skip + i - 3;
     941                 :            :         }
     942                 :            :       }
     943                 :            :     }
     944                 :         27 :     size -= bsize;
     945         [ +  + ]:         27 :     if (size == 0)
     946                 :         13 :       break;
     947                 :            : 
     948                 :            :     /* nothing found yet, go to next buffer */
     949                 :         14 :     skip += bsize;
     950         [ +  - ]:         14 :     g = g_slist_next (g);
     951                 :         14 :     adapter->priv->scan_offset += GST_BUFFER_SIZE (buf);
     952                 :         14 :     adapter->priv->scan_entry = g;
     953                 :         14 :     buf = g->data;
     954                 :         14 :     bsize = GST_BUFFER_SIZE (buf);
     955                 :         14 :     bdata = GST_BUFFER_DATA (buf);
     956                 :         14 :   } while (TRUE);
     957                 :            : 
     958                 :            :   /* nothing found */
     959                 :         42 :   return -1;
     960                 :            : }
     961                 :            : 
     962                 :            : /**
     963                 :            :  * gst_adapter_masked_scan_uint32:
     964                 :            :  * @adapter: a #GstAdapter
     965                 :            :  * @mask: mask to apply to data before matching against @pattern
     966                 :            :  * @pattern: pattern to match (after mask is applied)
     967                 :            :  * @offset: offset into the adapter data from which to start scanning, returns
     968                 :            :  *          the last scanned position.
     969                 :            :  * @size: number of bytes to scan from offset
     970                 :            :  *
     971                 :            :  * Scan for pattern @pattern with applied mask @mask in the adapter data,
     972                 :            :  * starting from offset @offset.
     973                 :            :  *
     974                 :            :  * The bytes in @pattern and @mask are interpreted left-to-right, regardless
     975                 :            :  * of endianness.  All four bytes of the pattern must be present in the
     976                 :            :  * adapter for it to match, even if the first or last bytes are masked out.
     977                 :            :  *
     978                 :            :  * It is an error to call this function without making sure that there is
     979                 :            :  * enough data (offset+size bytes) in the adapter.
     980                 :            :  *
     981                 :            :  * This function calls gst_adapter_masked_scan_uint32_peek() passing NULL
     982                 :            :  * for value.
     983                 :            :  *
     984                 :            :  * Returns: offset of the first match, or -1 if no match was found.
     985                 :            :  *
     986                 :            :  * Example:
     987                 :            :  * <programlisting>
     988                 :            :  * // Assume the adapter contains 0x00 0x01 0x02 ... 0xfe 0xff
     989                 :            :  *
     990                 :            :  * gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x00010203, 0, 256);
     991                 :            :  * // -> returns 0
     992                 :            :  * gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x00010203, 1, 255);
     993                 :            :  * // -> returns -1
     994                 :            :  * gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x01020304, 1, 255);
     995                 :            :  * // -> returns 1
     996                 :            :  * gst_adapter_masked_scan_uint32 (adapter, 0xffff, 0x0001, 0, 256);
     997                 :            :  * // -> returns -1
     998                 :            :  * gst_adapter_masked_scan_uint32 (adapter, 0xffff, 0x0203, 0, 256);
     999                 :            :  * // -> returns 0
    1000                 :            :  * gst_adapter_masked_scan_uint32 (adapter, 0xffff0000, 0x02030000, 0, 256);
    1001                 :            :  * // -> returns 2
    1002                 :            :  * gst_adapter_masked_scan_uint32 (adapter, 0xffff0000, 0x02030000, 0, 4);
    1003                 :            :  * // -> returns -1
    1004                 :            :  * </programlisting>
    1005                 :            :  *
    1006                 :            :  * Since: 0.10.24
    1007                 :            :  */
    1008                 :            : guint
    1009                 :         42 : gst_adapter_masked_scan_uint32 (GstAdapter * adapter, guint32 mask,
    1010                 :            :     guint32 pattern, guint offset, guint size)
    1011                 :            : {
    1012                 :         42 :   return gst_adapter_masked_scan_uint32_peek (adapter, mask, pattern, offset,
    1013                 :            :       size, NULL);
    1014                 :            : }

Generated by: LCOV version 1.9