Beispiel #1
0
/**
 * gst_adapter_take:
 * @adapter: a #GstAdapter
 * @nbytes: the number of bytes to take
 *
 * Returns a freshly allocated buffer containing the first @nbytes bytes of the
 * @adapter. The returned bytes will be flushed from the adapter.
 *
 * Caller owns returned value. g_free after usage.
 *
 * Returns: oven-fresh hot data, or #NULL if @nbytes bytes are not available
 */
guint8 *
gst_adapter_take (GstAdapter * adapter, guint nbytes)
{
  guint8 *data;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
  g_return_val_if_fail (nbytes > 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 (nbytes > adapter->size))
    return NULL;

  /* we have enough assembled data, take from there */
  if (adapter->assembled_len >= nbytes) {
    GST_LOG_OBJECT (adapter, "taking %u bytes already assembled", nbytes);
    data = adapter->assembled_data;
    /* allocate new data, assembled_len will be set to 0 in the flush below */
    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 */
    GST_LOG_OBJECT (adapter, "taking %u bytes by collection", nbytes);
    data = g_malloc (nbytes);
    copy_into_unchecked (adapter, data, adapter->skip, nbytes);
  }

  gst_adapter_flush_unchecked (adapter, nbytes);

  return data;
}
Beispiel #2
0
/**
 * gst_adapter_copy:
 * @adapter: a #GstAdapter
 * @dest: the memory where to copy to
 * @offset: the bytes offset in the adapter to start from
 * @size: the number of bytes to copy
 *
 * Copies @size bytes of data starting at @offset out of the buffers
 * contained in @GstAdapter into an array @dest provided by the caller.
 *
 * The array @dest should be large enough to contain @size bytes.
 * The user should check that the adapter has (@offset + @size) bytes
 * available before calling this function.
 *
 * Since: 0.10.12
 */
void
gst_adapter_copy (GstAdapter * adapter, guint8 * dest, guint offset, guint size)
{
    g_return_if_fail (GST_IS_ADAPTER (adapter));
    g_return_if_fail (size > 0);
    g_return_if_fail (offset + size <= adapter->size);

    copy_into_unchecked (adapter, dest, offset + adapter->skip, size);
}
Beispiel #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;
}
Beispiel #4
0
/* internal function, nbytes should be flushed after calling this function */
static guint8 *
gst_adapter_take_internal (GstAdapter * adapter, gsize nbytes)
{
  guint8 *data;
  gsize toreuse, tocopy;

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

  /* find memory to return */
  if (adapter->assembled_size >= nbytes && toreuse > 0) {
    /* we reuse already allocated memory but only when we're going to reuse
     * something from it because else we are worse than the malloc and copy
     * case below */
    GST_LOG_OBJECT (adapter, "reusing %" G_GSIZE_FORMAT " bytes of assembled"
        " data", toreuse);
    /* we have enough free space in the assembled array */
    data = adapter->assembled_data;
    /* flush after this function should set the assembled_size to 0 */
    adapter->assembled_data = g_malloc (adapter->assembled_size);
  } else {
    GST_LOG_OBJECT (adapter, "allocating %" G_GSIZE_FORMAT " bytes", nbytes);
    /* not enough bytes in the assembled array, just allocate new space */
    data = g_malloc (nbytes);
    /* reuse what we can from the already assembled data */
    if (toreuse) {
      GST_LOG_OBJECT (adapter, "reusing %" G_GSIZE_FORMAT " bytes", toreuse);
      GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, adapter,
          "memcpy %" G_GSIZE_FORMAT " bytes", toreuse);
      memcpy (data, adapter->assembled_data, toreuse);
    }
  }
  if (tocopy) {
    /* copy the remaining data */
    copy_into_unchecked (adapter, toreuse + data, toreuse + adapter->skip,
        tocopy);
  }
  return data;
}
Beispiel #5
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;
}
Beispiel #6
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;
}