Example #1
0
/**
 * gst_adapter_take_buffer:
 * @adapter: a #GstAdapter
 * @nbytes: the number of bytes to take
 *
 * Returns a #GstBuffer containing the first @nbytes bytes of the
 * @adapter. The returned bytes will be flushed from the adapter.
 * This function is potentially more performant than gst_adapter_take()
 * since it can reuse the memory in pushed buffers by subbuffering
 * or merging.
 *
 * Caller owns returned value. gst_buffer_unref() after usage.
 *
 * Since: 0.10.6
 *
 * Returns: a #GstBuffer containing the first @nbytes of the adapter,
 * or #NULL if @nbytes bytes are not available
 */
GstBuffer *
gst_adapter_take_buffer (GstAdapter * adapter, guint nbytes)
{
    GstBuffer *buffer;
    GstBuffer *cur;
    guint hsize, skip;
    guint8 *data;

    g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
    g_return_val_if_fail (nbytes > 0, NULL);

    GST_LOG_OBJECT (adapter, "taking buffer of %u bytes", nbytes);

    /* we don't have enough data, return NULL. This is unlikely
     * as one usually does an _available() first instead of grabbing a
     * random size. */
    if (G_UNLIKELY (nbytes > adapter->size))
        return NULL;

    cur = adapter->buflist->data;
    skip = adapter->skip;
    hsize = GST_BUFFER_SIZE (cur);

    /* our head buffer has enough data left, return it */
    if (skip == 0 && hsize == nbytes) {
        GST_LOG_OBJECT (adapter, "providing buffer of %d bytes as head buffer",
                        nbytes);
        buffer = gst_buffer_ref (cur);
        goto done;
    } else if (hsize >= nbytes + skip) {
        GST_LOG_OBJECT (adapter, "providing buffer of %d bytes via sub-buffer",
                        nbytes);
        buffer = gst_buffer_create_sub (cur, skip, nbytes);
        goto done;
    }

    if (gst_adapter_try_to_merge_up (adapter, nbytes)) {
        /* Merged something, let's try again for sub-buffering */
        cur = adapter->buflist->data;
        if (GST_BUFFER_SIZE (cur) >= nbytes + skip) {
            GST_LOG_OBJECT (adapter, "providing buffer of %d bytes via sub-buffer",
                            nbytes);
            buffer = gst_buffer_create_sub (cur, skip, nbytes);
            goto done;
        }
    }

    data = gst_adapter_take_internal (adapter, nbytes);

    buffer = gst_buffer_new ();
    GST_BUFFER_SIZE (buffer) = nbytes;
    GST_BUFFER_DATA (buffer) = data;
    GST_BUFFER_MALLOCDATA (buffer) = data;

done:
    gst_adapter_flush_unchecked (adapter, nbytes);

    return buffer;
}
Example #2
0
/**
 * gst_adapter_take_buffer:
 * @adapter: a #GstAdapter
 * @nbytes: the number of bytes to take
 *
 * Returns a #GstBuffer containing the first @nbytes bytes of the
 * @adapter. The returned bytes will be flushed from the adapter.
 * This function is potentially more performant than gst_adapter_take()
 * since it can reuse the memory in pushed buffers by subbuffering
 * or merging.
 *
 * Note that no assumptions should be made as to whether certain buffer
 * flags such as the DISCONT flag are set on the returned buffer, or not.
 * The caller needs to explicitly set or unset flags that should be set or
 * unset.
 *
 * Caller owns a reference to the returned buffer. gst_buffer_unref() after
 * usage.
 *
 * Free-function: gst_buffer_unref
 *
 * Returns: (transfer full): a #GstBuffer containing the first @nbytes of
 *     the adapter, or #NULL if @nbytes bytes are not available.
 *     gst_buffer_unref() when no longer needed.
 */
GstBuffer *
gst_adapter_take_buffer (GstAdapter * adapter, gsize nbytes)
{
  GstBuffer *buffer;
  GstBuffer *cur;
  gsize hsize, skip;
  guint8 *data;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
  g_return_val_if_fail (nbytes > 0, NULL);

  GST_LOG_OBJECT (adapter, "taking buffer of %" G_GSIZE_FORMAT " bytes",
      nbytes);

  /* we don't have enough data, return NULL. This is unlikely
   * as one usually does an _available() first instead of grabbing a
   * random size. */
  if (G_UNLIKELY (nbytes > adapter->size))
    return NULL;

  cur = adapter->buflist->data;
  skip = adapter->skip;
  hsize = gst_buffer_get_size (cur);

  /* our head buffer has enough data left, return it */
  if (skip == 0 && hsize == nbytes) {
    GST_LOG_OBJECT (adapter, "providing buffer of %" G_GSIZE_FORMAT " bytes"
        " as head buffer", nbytes);
    buffer = gst_buffer_ref (cur);
    goto done;
  } else if (hsize >= nbytes + skip) {
    GST_LOG_OBJECT (adapter, "providing buffer of %" G_GSIZE_FORMAT " bytes"
        " via region copy", nbytes);
    buffer = gst_buffer_copy_region (cur, GST_BUFFER_COPY_ALL, skip, nbytes);
    goto done;
  }
#if 0
  if (gst_adapter_try_to_merge_up (adapter, nbytes)) {
    /* Merged something, let's try again for sub-buffering */
    cur = adapter->buflist->data;
    skip = adapter->skip;
    if (gst_buffer_get_size (cur) >= nbytes + skip) {
      GST_LOG_OBJECT (adapter, "providing buffer of %" G_GSIZE_FORMAT " bytes"
          " via sub-buffer", nbytes);
      buffer = gst_buffer_copy_region (cur, GST_BUFFER_COPY_ALL, skip, nbytes);
      goto done;
    }
  }
#endif

  data = gst_adapter_take_internal (adapter, nbytes);

  buffer = gst_buffer_new_wrapped (data, nbytes);

done:
  gst_adapter_flush_unchecked (adapter, nbytes);

  return buffer;
}
Example #3
0
/**
 * gst_adapter_peek:
 * @adapter: a #GstAdapter
 * @size: the number of bytes to peek
 *
 * Gets the first @size bytes stored in the @adapter. The returned pointer is
 * valid until the next function is called on the adapter.
 *
 * Note that setting the returned pointer as the data of a #GstBuffer is
 * incorrect for general-purpose plugins. The reason is that if a downstream
 * element stores the buffer so that it has access to it outside of the bounds
 * of its chain function, the buffer will have an invalid data pointer after
 * your element flushes the bytes. In that case you should use
 * gst_adapter_take(), which returns a freshly-allocated buffer that you can set
 * as #GstBuffer malloc_data or the potentially more performant
 * gst_adapter_take_buffer().
 *
 * Returns #NULL if @size bytes are not available.
 *
 * Returns: a pointer to the first @size bytes of data, or NULL.
 */
const guint8 *
gst_adapter_peek (GstAdapter * adapter, guint size)
{
  GstBuffer *cur;
  guint skip;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
  g_return_val_if_fail (size > 0, NULL);

  /* we don't have enough data, return NULL. This is unlikely
   * as one usually does an _available() first instead of peeking a
   * random size. */
  if (G_UNLIKELY (size > adapter->size))
    return NULL;

  /* we have enough assembled data, return it */
  if (adapter->assembled_len >= size)
    return adapter->assembled_data;

  /* our head buffer has enough data left, return it */
  cur = adapter->buflist->data;
  skip = adapter->skip;
  if (GST_BUFFER_SIZE (cur) >= size + skip)
    return GST_BUFFER_DATA (cur) + skip;

  /* We may be able to efficiently merge buffers in our pool to
   * gather a big enough chunk to return it from the head buffer directly */
  if (gst_adapter_try_to_merge_up (adapter, size)) {
    /* Merged something! Check if there's enough avail now */
    cur = adapter->buflist->data;
    if (GST_BUFFER_SIZE (cur) >= size + skip)
      return GST_BUFFER_DATA (cur) + skip;
  }

  /* Gonna need to copy stuff out */
  if (G_UNLIKELY (adapter->assembled_size < size)) {
    adapter->assembled_size = (size / DEFAULT_SIZE + 1) * DEFAULT_SIZE;
    GST_DEBUG_OBJECT (adapter, "resizing internal buffer to %u",
        adapter->assembled_size);
    /* no g_realloc to avoid a memcpy that is not desired here since we are
     * going to copy new data into the area below */
    g_free (adapter->assembled_data);
    adapter->assembled_data = g_malloc (adapter->assembled_size);
  }
  adapter->assembled_len = size;

  GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy data from adapter");
  copy_into_unchecked (adapter, adapter->assembled_data, skip, size);

  return adapter->assembled_data;
}
Example #4
0
/**
 * gst_adapter_take_buffer:
 * @adapter: a #GstAdapter
 * @nbytes: the number of bytes to take
 *
 * Returns a #GstBuffer containing the first @nbytes bytes of the
 * @adapter. The returned bytes will be flushed from the adapter.
 * This function is potentially more performant than gst_adapter_take()
 * since it can reuse the memory in pushed buffers by subbuffering
 * or merging.
 *
 * Caller owns returned value. gst_buffer_unref() after usage.
 *
 * Since: 0.10.6
 *
 * Returns: a #GstBuffer containing the first @nbytes of the adapter,
 * or #NULL if @nbytes bytes are not available
 */
GstBuffer *
gst_adapter_take_buffer (GstAdapter * adapter, guint nbytes)
{
  GstBuffer *buffer;
  GstBuffer *cur;
  guint hsize, skip;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
  g_return_val_if_fail (nbytes > 0, NULL);

  GST_LOG_OBJECT (adapter, "taking buffer of %u bytes", nbytes);

  /* we don't have enough data, return NULL. This is unlikely
   * as one usually does an _available() first instead of grabbing a
   * random size. */
  if (G_UNLIKELY (nbytes > adapter->size))
    return NULL;

  cur = adapter->buflist->data;
  skip = adapter->skip;
  hsize = GST_BUFFER_SIZE (cur);

  /* our head buffer has enough data left, return it */
  if (skip == 0 && hsize == nbytes) {
    GST_LOG_OBJECT (adapter, "providing buffer of %d bytes as head buffer",
        nbytes);
    buffer = gst_buffer_ref (cur);
    goto done;
  } else if (hsize >= nbytes + skip) {
    GST_LOG_OBJECT (adapter, "providing buffer of %d bytes via sub-buffer",
        nbytes);
    buffer = gst_buffer_create_sub (cur, skip, nbytes);
    goto done;
  }

  if (gst_adapter_try_to_merge_up (adapter, nbytes)) {
    /* Merged something, let's try again for sub-buffering */
    cur = adapter->buflist->data;
    if (GST_BUFFER_SIZE (cur) >= nbytes + skip) {
      GST_LOG_OBJECT (adapter, "providing buffer of %d bytes via sub-buffer",
          nbytes);
      buffer = gst_buffer_create_sub (cur, skip, nbytes);
      goto done;
    }
  }

  /* we have enough assembled data, copy from there */
  if (adapter->assembled_len >= nbytes) {
    GST_LOG_OBJECT (adapter, "taking %u bytes already assembled", nbytes);
    buffer = gst_buffer_new ();
    GST_BUFFER_SIZE (buffer) = nbytes;
    GST_BUFFER_DATA (buffer) = adapter->assembled_data;
    GST_BUFFER_MALLOCDATA (buffer) = adapter->assembled_data;
    /* flush will set the assembled_len to 0 */
    adapter->assembled_data = g_malloc (adapter->assembled_size);
  } else {
    /* we need to allocate and copy. We could potentially copy bytes from the
     * assembled data before doing the copy_into */
    buffer = gst_buffer_new_and_alloc (nbytes);
    GST_LOG_OBJECT (adapter, "taking %u bytes by collection", nbytes);
    copy_into_unchecked (adapter, GST_BUFFER_DATA (buffer), skip, nbytes);
  }

done:
  gst_adapter_flush_unchecked (adapter, nbytes);

  return buffer;
}
Example #5
0
/**
 * gst_adapter_map:
 * @adapter: a #GstAdapter
 * @size: the number of bytes to map/peek
 *
 * Gets the first @size bytes stored in the @adapter. The returned pointer is
 * valid until the next function is called on the adapter.
 *
 * Note that setting the returned pointer as the data of a #GstBuffer is
 * incorrect for general-purpose plugins. The reason is that if a downstream
 * element stores the buffer so that it has access to it outside of the bounds
 * of its chain function, the buffer will have an invalid data pointer after
 * your element flushes the bytes. In that case you should use
 * gst_adapter_take(), which returns a freshly-allocated buffer that you can set
 * as #GstBuffer memory or the potentially more performant
 * gst_adapter_take_buffer().
 *
 * Returns #NULL if @size bytes are not available.
 *
 * Returns: (transfer none) (array length=size) (element-type guint8):
 *     a pointer to the first @size bytes of data, or NULL
 */
gconstpointer
gst_adapter_map (GstAdapter * adapter, gsize size)
{
  GstBuffer *cur;
  gsize skip, csize;
  gsize toreuse, tocopy;
  guint8 *data;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
  g_return_val_if_fail (size > 0, NULL);

  if (adapter->info.memory)
    gst_adapter_unmap (adapter);

  /* we don't have enough data, return NULL. This is unlikely
   * as one usually does an _available() first instead of peeking a
   * random size. */
  if (G_UNLIKELY (size > adapter->size))
    return NULL;

  /* we have enough assembled data, return it */
  if (adapter->assembled_len >= size)
    return adapter->assembled_data;

#if 0
  do {
#endif
    cur = adapter->buflist->data;
    skip = adapter->skip;

    csize = gst_buffer_get_size (cur);
    if (csize >= size + skip) {
      if (!gst_buffer_map (cur, &adapter->info, GST_MAP_READ))
        return FALSE;

      return (guint8 *) adapter->info.data + skip;
    }
    /* We may be able to efficiently merge buffers in our pool to
     * gather a big enough chunk to return it from the head buffer directly */
#if 0
  } while (gst_adapter_try_to_merge_up (adapter, size));
#endif

  /* see how much data we can reuse from the assembled memory and how much
   * we need to copy */
  toreuse = adapter->assembled_len;
  tocopy = size - toreuse;

  /* Gonna need to copy stuff out */
  if (G_UNLIKELY (adapter->assembled_size < size)) {
    adapter->assembled_size = (size / DEFAULT_SIZE + 1) * DEFAULT_SIZE;
    GST_DEBUG_OBJECT (adapter, "resizing internal buffer to %" G_GSIZE_FORMAT,
        adapter->assembled_size);
    if (toreuse == 0) {
      GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "alloc new buffer");
      /* no g_realloc to avoid a memcpy that is not desired here since we are
       * not going to reuse any data here */
      g_free (adapter->assembled_data);
      adapter->assembled_data = g_malloc (adapter->assembled_size);
    } else {
      /* we are going to reuse all data, realloc then */
      GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "reusing %" G_GSIZE_FORMAT " bytes",
          toreuse);
      adapter->assembled_data =
          g_realloc (adapter->assembled_data, adapter->assembled_size);
    }
  }
  GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy remaining %" G_GSIZE_FORMAT
      " bytes from adapter", tocopy);
  data = adapter->assembled_data;
  copy_into_unchecked (adapter, data + toreuse, skip + toreuse, tocopy);
  adapter->assembled_len = size;

  return adapter->assembled_data;
}