Пример #1
0
/**
 * gst_adapter_take_buffer_list:
 * @adapter: a #GstAdapter
 * @nbytes: the number of bytes to take
 *
 * Returns a #GstBufferList of buffers containing the first @nbytes bytes of
 * the @adapter. The returned bytes will be flushed from the adapter.
 * When the caller can deal with individual buffers, this function is more
 * performant because no memory should be copied.
 *
 * Caller owns the returned list. Call gst_buffer_list_unref() to free
 * the list after usage.
 *
 * Returns: (transfer full) (nullable): a #GstBufferList of buffers containing
 *     the first @nbytes of the adapter, or %NULL if @nbytes bytes are not
 *     available
 *
 * Since: 1.6
 */
GstBufferList *
gst_adapter_take_buffer_list (GstAdapter * adapter, gsize nbytes)
{
  GstBufferList *buffer_list;
  GstBuffer *cur;
  gsize hsize, skip, cur_size;
  guint n_bufs;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);

  if (nbytes > adapter->size)
    return NULL;

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

  /* try to create buffer list with sufficient size, so no resize is done later */
  if (adapter->count < 64)
    n_bufs = adapter->count;
  else
    n_bufs = (adapter->count * nbytes * 1.2 / adapter->size) + 1;

  buffer_list = gst_buffer_list_new_sized (n_bufs);

  while (nbytes > 0) {
    cur = adapter->buflist->data;
    skip = adapter->skip;
    cur_size = gst_buffer_get_size (cur);
    hsize = MIN (nbytes, cur_size - skip);

    gst_buffer_list_add (buffer_list, gst_adapter_take_buffer (adapter, hsize));
    nbytes -= hsize;
  }
  return buffer_list;
}
Пример #2
0
static int
gst_ffmpeg_pipe_open (URLContext * h, const char *filename, int flags)
{
    GstFFMpegPipe *ffpipe;

    GST_LOG ("Opening %s", filename);

    /* we don't support W together */
    if (flags != URL_RDONLY) {
        GST_WARNING ("Only read-only is supported");
        return -EINVAL;
    }

    if (sscanf (&filename[10], "%p", &ffpipe) != 1) {
        GST_WARNING ("could not decode pipe info from %s", filename);
        return -EIO;
    }

    /* sanity check */
    g_return_val_if_fail (GST_IS_ADAPTER (ffpipe->adapter), -EINVAL);

    h->priv_data = (void *) ffpipe;
    h->is_streamed = TRUE;
    h->max_packet_size = 0;

    return 0;
}
Пример #3
0
/**
 * gst_adapter_take_list:
 * @adapter: a #GstAdapter
 * @nbytes: the number of bytes to take
 *
 * Returns a #GList of buffers containing the first @nbytes bytes of the
 * @adapter. The returned bytes will be flushed from the adapter.
 * When the caller can deal with individual buffers, this function is more
 * performant because no memory should be copied.
 *
 * Caller owns returned list and contained buffers. gst_buffer_unref() each
 * buffer in the list before freeing the list after usage.
 *
 * Returns: (element-type Gst.Buffer) (transfer full) (nullable): a #GList of
 *     buffers containing the first @nbytes of the adapter, or %NULL if @nbytes
 *     bytes are not available
 */
GList *
gst_adapter_take_list (GstAdapter * adapter, gsize nbytes)
{
  GQueue queue = G_QUEUE_INIT;
  GstBuffer *cur;
  gsize hsize, skip, cur_size;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
  g_return_val_if_fail (nbytes <= adapter->size, NULL);

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

  while (nbytes > 0) {
    cur = adapter->buflist->data;
    skip = adapter->skip;
    cur_size = gst_buffer_get_size (cur);
    hsize = MIN (nbytes, cur_size - skip);

    cur = gst_adapter_take_buffer (adapter, hsize);

    g_queue_push_tail (&queue, cur);

    nbytes -= hsize;
  }
  return queue.head;
}
Пример #4
0
/**
 * gst_adapter_take_list:
 * @adapter: a #GstAdapter
 * @nbytes: the number of bytes to take
 *
 * Returns a #GSList of buffers containing the first @nbytes bytes of the
 * @adapter. The returned bytes will be flushed from the adapter.
 * When the caller can deal with individual buffers, this function is more
 * performant because no memory should be coppied.
 *
 * Caller owns returned list and contained buffers. gst_buffer_unref() each
 * buffer in the list before freeng the list after usage.
 *
 * Returns: a #GSList of buffers containing the first @nbytes of the adapter,
 * or #NULL if @nbytes bytes are not available
 *
 * Since: 0.10.31
 */
GList *
gst_adapter_take_list (GstAdapter * adapter, guint nbytes)
{
    GList *result = NULL, *tail = NULL;
    GstBuffer *cur;
    guint hsize, skip;

    g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
    g_return_val_if_fail (nbytes <= adapter->size, NULL);

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

    while (nbytes > 0) {
        cur = adapter->buflist->data;
        skip = adapter->skip;
        hsize = MIN (nbytes, GST_BUFFER_SIZE (cur) - skip);

        cur = gst_adapter_take_buffer (adapter, hsize);

        if (result == NULL) {
            result = tail = g_list_append (result, cur);
        } else {
            tail = g_list_append (tail, cur);
            tail = g_list_next (tail);
        }
        nbytes -= hsize;
    }
    return result;
}
Пример #5
0
/**
 * gst_adapter_prev_dts_at_offset:
 * @adapter: a #GstAdapter
 * @offset: the offset in the adapter at which to get timestamp
 * @distance: (out) (allow-none): pointer to location for distance, or %NULL
 *
 * Get the dts that was before the byte at offset @offset in the adapter. When
 * @distance is given, the amount of bytes between the dts and the current
 * position is returned.
 *
 * The dts is reset to GST_CLOCK_TIME_NONE and the distance is set to 0 when
 * the adapter is first created or when it is cleared. This also means that before
 * the first byte with a dts is removed from the adapter, the dts
 * and distance returned are GST_CLOCK_TIME_NONE and 0 respectively.
 *
 * Since: 1.2
 * Returns: The previously seen dts at given offset.
 */
GstClockTime
gst_adapter_prev_dts_at_offset (GstAdapter * adapter, gsize offset,
    guint64 * distance)
{
  GstBuffer *cur;
  GSList *g;
  gsize read_offset = 0;
  GstClockTime dts = adapter->dts;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), GST_CLOCK_TIME_NONE);

  g = adapter->buflist;

  while (g && read_offset < offset + adapter->skip) {
    cur = g->data;

    read_offset += gst_buffer_get_size (cur);
    if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (cur))) {
      dts = GST_BUFFER_DTS (cur);
    }

    g = g_slist_next (g);
  }

  if (distance)
    *distance = adapter->dts_distance + offset;

  return dts;
}
Пример #6
0
/**
 * gst_adapter_take_list:
 * @adapter: a #GstAdapter
 * @nbytes: the number of bytes to take
 *
 * Returns a #GList of buffers containing the first @nbytes bytes of the
 * @adapter. The returned bytes will be flushed from the adapter.
 * When the caller can deal with individual buffers, this function is more
 * performant because no memory should be copied.
 *
 * Caller owns returned list and contained buffers. gst_buffer_unref() each
 * buffer in the list before freeing the list after usage.
 *
 * Returns: (element-type Gst.Buffer) (transfer full): a #GList of buffers
 *     containing the first @nbytes of the adapter, or #NULL if @nbytes bytes
 *     are not available
 *
 * Since: 0.10.31
 */
GList *
gst_adapter_take_list (GstAdapter * adapter, guint nbytes)
{
  GQueue queue = G_QUEUE_INIT;
  GstBuffer *cur;
  guint hsize, skip;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
  g_return_val_if_fail (nbytes <= adapter->size, NULL);

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

  while (nbytes > 0) {
    cur = adapter->buflist->data;
    skip = adapter->skip;
    hsize = MIN (nbytes, GST_BUFFER_SIZE (cur) - skip);

    cur = gst_adapter_take_buffer (adapter, hsize);

    g_queue_push_tail (&queue, cur);

    nbytes -= hsize;
  }
  return queue.head;
}
Пример #7
0
/**
 * gst_adapter_push:
 * @adapter: a #GstAdapter
 * @buf: a #GstBuffer to add to queue in the adapter
 *
 * Adds the data from @buf to the data stored inside @adapter and takes
 * ownership of the buffer.
 * Empty buffers will be automatically dereferenced and not stored in the
 * @adapter.
 */
void
gst_adapter_push (GstAdapter * adapter, GstBuffer * buf)
{
  guint size;

  g_return_if_fail (GST_IS_ADAPTER (adapter));
  g_return_if_fail (GST_IS_BUFFER (buf));

  size = GST_BUFFER_SIZE (buf);

  if (G_UNLIKELY (size == 0)) {
    /* we can't have empty buffers, several parts in this file rely on it, this
     * has some problems for the timestamp tracking. */
    GST_LOG_OBJECT (adapter, "discarding empty buffer");
    gst_buffer_unref (buf);
  } else {
    adapter->size += size;

    /* Note: merging buffers at this point is premature. */
    if (G_UNLIKELY (adapter->buflist == NULL)) {
      GST_LOG_OBJECT (adapter, "pushing first %u bytes", size);
      adapter->buflist = adapter->buflist_end = g_slist_append (NULL, buf);
      update_timestamp (adapter, buf);
    } else {
      /* Otherwise append to the end, and advance our end pointer */
      GST_LOG_OBJECT (adapter, "pushing %u bytes at end, size now %u", size,
          adapter->size);
      adapter->buflist_end = g_slist_append (adapter->buflist_end, buf);
      adapter->buflist_end = g_slist_next (adapter->buflist_end);
    }
  }
}
Пример #8
0
/**
 * gst_adapter_push:
 * @adapter: a #GstAdapter
 * @buf: (transfer full): a #GstBuffer to add to queue in the adapter
 *
 * Adds the data from @buf to the data stored inside @adapter and takes
 * ownership of the buffer.
 */
void
gst_adapter_push (GstAdapter * adapter, GstBuffer * buf)
{
  gsize size;

  g_return_if_fail (GST_IS_ADAPTER (adapter));
  g_return_if_fail (GST_IS_BUFFER (buf));

  size = gst_buffer_get_size (buf);
  adapter->size += size;

  /* Note: merging buffers at this point is premature. */
  if (G_UNLIKELY (adapter->buflist == NULL)) {
    GST_LOG_OBJECT (adapter, "pushing %p first %" G_GSIZE_FORMAT " bytes",
        buf, size);
    adapter->buflist = adapter->buflist_end = g_slist_append (NULL, buf);
    update_timestamps (adapter, buf);
  } else {
    /* Otherwise append to the end, and advance our end pointer */
    GST_LOG_OBJECT (adapter, "pushing %p %" G_GSIZE_FORMAT " bytes at end, "
        "size now %" G_GSIZE_FORMAT, buf, size, adapter->size);
    adapter->buflist_end = g_slist_append (adapter->buflist_end, buf);
    adapter->buflist_end = g_slist_next (adapter->buflist_end);
  }
}
Пример #9
0
/**
 * gst_adapter_available:
 * @adapter: a #GstAdapter
 *
 * Gets the maximum amount of bytes available, that is it returns the maximum
 * value that can be supplied to gst_adapter_peek() without that function
 * returning NULL.
 *
 * Returns: number of bytes available in @adapter
 */
guint
gst_adapter_available (GstAdapter * adapter)
{
    g_return_val_if_fail (GST_IS_ADAPTER (adapter), 0);

    return adapter->size;
}
Пример #10
0
/**
 * gst_adapter_available_fast:
 * @adapter: a #GstAdapter
 *
 * Gets the maximum number of bytes that are immediately available without
 * requiring any expensive operations (like copying the data into a
 * temporary buffer).
 *
 * Returns: number of bytes that are available in @adapter without expensive
 * operations
 */
guint
gst_adapter_available_fast (GstAdapter * adapter)
{
    GstBuffer *cur;
    guint size;
    GSList *g;

    g_return_val_if_fail (GST_IS_ADAPTER (adapter), 0);

    /* no data */
    if (adapter->size == 0)
        return 0;

    /* some stuff we already assembled */
    if (adapter->assembled_len)
        return adapter->assembled_len;

    /* take the first non-zero buffer */
    g = adapter->buflist;
    while (TRUE) {
        cur = g->data;
        size = GST_BUFFER_SIZE (cur);
        if (size != 0)
            break;
        g = g_slist_next (g);
    }

    /* we can quickly get the (remaining) data of the first buffer */
    return size - adapter->skip;
}
Пример #11
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;
}
Пример #12
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;
}
Пример #13
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;
}
Пример #14
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);
}
Пример #15
0
/**
 * gst_adapter_prev_timestamp:
 * @adapter: a #GstAdapter
 * @distance: pointer to location for distance or NULL
 *
 * Get the timestamp that was before the current byte in the adapter. When
 * @distance is given, the amount of bytes between the timestamp and the current
 * position is returned.
 *
 * The timestamp is reset to GST_CLOCK_TIME_NONE when the adapter is first
 * created or when it is cleared.
 *
 * Returns: The previously seen timestamp.
 *
 * Since: 0.10.24
 */
GstClockTime
gst_adapter_prev_timestamp (GstAdapter * adapter, guint64 * distance)
{
    g_return_val_if_fail (GST_IS_ADAPTER (adapter), GST_CLOCK_TIME_NONE);

    if (distance)
        *distance = adapter->priv->distance;

    return adapter->priv->timestamp;
}
Пример #16
0
void
gst_adapter_flush (GstAdapter * adapter, guint flush)
{
    g_return_if_fail (GST_IS_ADAPTER (adapter));
    g_return_if_fail (flush <= adapter->size);

    /* flushing out 0 bytes will do nothing */
    if (G_UNLIKELY (flush == 0))
        return;

    gst_adapter_flush_unchecked (adapter, flush);
}
Пример #17
0
/**
 * gst_adapter_unmap:
 * @adapter: a #GstAdapter
 *
 * Releases the memory obtained with the last gst_adapter_map().
 */
void
gst_adapter_unmap (GstAdapter * adapter)
{
  g_return_if_fail (GST_IS_ADAPTER (adapter));

  if (adapter->info.memory) {
    GstBuffer *cur = adapter->buflist->data;
    GST_LOG_OBJECT (adapter, "unmap memory buffer %p", cur);
    gst_buffer_unmap (cur, &adapter->info);
    adapter->info.memory = NULL;
  }
}
Пример #18
0
/**
 * gst_adapter_get_buffer_fast:
 * @adapter:  a #GstAdapter
 * @nbytes: the number of bytes to get
 *
 * Returns a #GstBuffer containing the first @nbytes of the @adapter, but
 * does not flush them from the adapter. See gst_adapter_take_buffer_fast()
 * for details.
 *
 * Caller owns a reference to the returned buffer. gst_buffer_unref() after
 * usage.
 *
 * Free-function: gst_buffer_unref
 *
 * Returns: (transfer full) (nullable): a #GstBuffer containing the first
 *     @nbytes of the adapter, or %NULL if @nbytes bytes are not available.
 *     gst_buffer_unref() when no longer needed.
 *
 * Since: 1.6
 */
GstBuffer *
gst_adapter_get_buffer_fast (GstAdapter * adapter, gsize nbytes)
{
  GstBuffer *buffer = NULL;
  GstBuffer *cur;
  GSList *item;
  gsize skip;
  gsize left = nbytes;

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

  GST_LOG_OBJECT (adapter, "getting 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;

  skip = adapter->skip;
  cur = adapter->buflist->data;

  if (skip == 0 && gst_buffer_get_size (cur) == nbytes) {
    GST_LOG_OBJECT (adapter, "providing buffer of %" G_GSIZE_FORMAT " bytes"
        " as head buffer", nbytes);
    buffer = gst_buffer_ref (cur);
    goto done;
  }

  for (item = adapter->buflist; item && left > 0; item = item->next) {
    gsize size, cur_size;

    cur = item->data;
    cur_size = gst_buffer_get_size (cur);
    size = MIN (cur_size - skip, left);

    GST_LOG_OBJECT (adapter, "appending %" G_GSIZE_FORMAT " bytes"
        " via region copy", size);
    if (buffer)
      gst_buffer_copy_into (buffer, cur,
          GST_BUFFER_COPY_MEMORY | GST_BUFFER_COPY_META, skip, size);
    else
      buffer = gst_buffer_copy_region (cur, GST_BUFFER_COPY_ALL, skip, size);
    skip = 0;
    left -= size;
  }

done:

  return buffer;
}
Пример #19
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;
}
Пример #20
0
/**
 * gst_adapter_get_buffer_list:
 * @adapter: a #GstAdapter
 * @nbytes: the number of bytes to get
 *
 * Returns a #GstBufferList of buffers containing the first @nbytes bytes of
 * the @adapter but does not flush them from the adapter. See
 * gst_adapter_take_buffer_list() for details.
 *
 * Caller owns the returned list. Call gst_buffer_list_unref() to free
 * the list after usage.
 *
 * Returns: (transfer full) (nullable): a #GstBufferList of buffers containing
 *     the first @nbytes of the adapter, or %NULL if @nbytes bytes are not
 *     available
 *
 * Since: 1.6
 */
GstBufferList *
gst_adapter_get_buffer_list (GstAdapter * adapter, gsize nbytes)
{
  GstBufferList *buffer_list;
  GstBuffer *cur, *buffer;
  gsize hsize, skip, cur_size;
  guint n_bufs;
  GSList *g = NULL;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);

  if (nbytes > adapter->size)
    return NULL;

  GST_LOG_OBJECT (adapter, "getting %" G_GSIZE_FORMAT " bytes", nbytes);

  /* try to create buffer list with sufficient size, so no resize is done later */
  if (adapter->count < 64)
    n_bufs = adapter->count;
  else
    n_bufs = (adapter->count * nbytes * 1.2 / adapter->size) + 1;

  buffer_list = gst_buffer_list_new_sized (n_bufs);

  g = adapter->buflist;
  skip = adapter->skip;

  while (nbytes > 0) {
    cur = g->data;
    cur_size = gst_buffer_get_size (cur);
    hsize = MIN (nbytes, cur_size - skip);

    if (skip == 0 && cur_size == hsize) {
      GST_LOG_OBJECT (adapter,
          "inserting a buffer of %" G_GSIZE_FORMAT " bytes", hsize);
      buffer = gst_buffer_ref (cur);
    } else {
      GST_LOG_OBJECT (adapter, "inserting a buffer of %" G_GSIZE_FORMAT " bytes"
          " via region copy", hsize);
      buffer = gst_buffer_copy_region (cur, GST_BUFFER_COPY_ALL, skip, hsize);
    }

    gst_buffer_list_add (buffer_list, buffer);

    nbytes -= hsize;
    skip = 0;
    g = g_slist_next (g);
  }

  return buffer_list;
}
Пример #21
0
/**
 * gst_adapter_take_buffer_fast:
 * @adapter:  a #GstAdapter
 * @nbytes: the number of bytes to take
 *
 * Returns a #GstBuffer containing the first @nbytes of the @adapter.
 * The returned bytes will be flushed from the adapter.  This function
 * is potentially more performant than gst_adapter_take_buffer() since
 * it can reuse the memory in pushed buffers by subbuffering or
 * merging. Unlike gst_adapter_take_buffer(), the returned buffer may
 * be composed of multiple non-contiguous #GstMemory objects, no
 * copies are made.
 *
 * 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.
 *
 * This will also copy over all GstMeta of the input buffers except
 * for meta with the %GST_META_FLAG_POOLED flag or with the "memory" tag.
 *
 * This function can return buffer up to the return value of
 * gst_adapter_available() without making copies if possible.
 *
 * Caller owns a reference to the returned buffer. gst_buffer_unref() after
 * usage.
 *
 * Free-function: gst_buffer_unref
 *
 * Returns: (transfer full) (nullable): a #GstBuffer containing the first
 *     @nbytes of the adapter, or %NULL if @nbytes bytes are not available.
 *     gst_buffer_unref() when no longer needed.
 *
 * Since: 1.2
 */
GstBuffer *
gst_adapter_take_buffer_fast (GstAdapter * adapter, gsize nbytes)
{
  GstBuffer *buffer;

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

  buffer = gst_adapter_get_buffer_fast (adapter, nbytes);
  if (buffer)
    gst_adapter_flush_unchecked (adapter, nbytes);

  return buffer;
}
Пример #22
0
/**
 * gst_adapter_clear:
 * @adapter: a #GstAdapter
 *
 * Removes all buffers from @adapter.
 */
void
gst_adapter_clear (GstAdapter * adapter)
{
    g_return_if_fail (GST_IS_ADAPTER (adapter));

    g_slist_foreach (adapter->buflist, (GFunc) gst_mini_object_unref, NULL);
    g_slist_free (adapter->buflist);
    adapter->buflist = NULL;
    adapter->buflist_end = NULL;
    adapter->size = 0;
    adapter->skip = 0;
    adapter->assembled_len = 0;
    adapter->priv->timestamp = GST_CLOCK_TIME_NONE;
    adapter->priv->distance = 0;
    adapter->priv->scan_offset = 0;
    adapter->priv->scan_entry = NULL;
}
Пример #23
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;

    data = gst_adapter_take_internal (adapter, nbytes);

    gst_adapter_flush_unchecked (adapter, nbytes);

    return data;
}
Пример #24
0
/**
 * gst_adapter_get_list:
 * @adapter: a #GstAdapter
 * @nbytes: the number of bytes to get
 *
 * Returns a #GList of buffers containing the first @nbytes bytes of the
 * @adapter, but does not flush them from the adapter. See
 * gst_adapter_take_list() for details.
 *
 * Caller owns returned list and contained buffers. gst_buffer_unref() each
 * buffer in the list before freeing the list after usage.
 *
 * Returns: (element-type Gst.Buffer) (transfer full) (nullable): a #GList of
 *     buffers containing the first @nbytes of the adapter, or %NULL if @nbytes
 *     bytes are not available
 *
 * Since: 1.6
 */
GList *
gst_adapter_get_list (GstAdapter * adapter, gsize nbytes)
{
  GQueue queue = G_QUEUE_INIT;
  GstBuffer *cur, *buffer;
  gsize hsize, skip, cur_size;
  GSList *g = NULL;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
  g_return_val_if_fail (nbytes <= adapter->size, NULL);

  GST_LOG_OBJECT (adapter, "getting %" G_GSIZE_FORMAT " bytes", nbytes);

  g = adapter->buflist;
  skip = adapter->skip;

  while (nbytes > 0) {
    cur = g->data;
    cur_size = gst_buffer_get_size (cur);
    hsize = MIN (nbytes, cur_size - skip);

    if (skip == 0 && cur_size == hsize) {
      GST_LOG_OBJECT (adapter,
          "inserting a buffer of %" G_GSIZE_FORMAT " bytes", hsize);
      buffer = gst_buffer_ref (cur);
    } else {
      GST_LOG_OBJECT (adapter, "inserting a buffer of %" G_GSIZE_FORMAT " bytes"
          " via region copy", hsize);
      buffer = gst_buffer_copy_region (cur, GST_BUFFER_COPY_ALL, skip, hsize);
    }

    g_queue_push_tail (&queue, buffer);

    nbytes -= hsize;
    skip = 0;
    g = g_slist_next (g);
  }

  return queue.head;
}
Пример #25
0
/**
 * gst_adapter_clear:
 * @adapter: a #GstAdapter
 *
 * Removes all buffers from @adapter.
 */
void
gst_adapter_clear (GstAdapter * adapter)
{
  g_return_if_fail (GST_IS_ADAPTER (adapter));

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

  g_slist_foreach (adapter->buflist, (GFunc) gst_mini_object_unref, NULL);
  g_slist_free (adapter->buflist);
  adapter->buflist = NULL;
  adapter->buflist_end = NULL;
  adapter->count = 0;
  adapter->size = 0;
  adapter->skip = 0;
  adapter->assembled_len = 0;
  adapter->pts = GST_CLOCK_TIME_NONE;
  adapter->pts_distance = 0;
  adapter->dts = GST_CLOCK_TIME_NONE;
  adapter->dts_distance = 0;
  adapter->scan_offset = 0;
  adapter->scan_entry = NULL;
}
Пример #26
0
/**
 * gst_adapter_available_fast:
 * @adapter: a #GstAdapter
 *
 * Gets the maximum number of bytes that are immediately available without
 * requiring any expensive operations (like copying the data into a
 * temporary buffer).
 *
 * Returns: number of bytes that are available in @adapter without expensive
 * operations
 */
guint
gst_adapter_available_fast (GstAdapter * adapter)
{
  GstBuffer *first;
  guint size;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), 0);

  /* no buffers, we have no data */
  if (!adapter->buflist)
    return 0;

  /* some stuff we already assembled */
  if (adapter->assembled_len)
    return adapter->assembled_len;

  /* take the first buffer and its size */
  first = GST_BUFFER_CAST (adapter->buflist->data);
  size = GST_BUFFER_SIZE (first);

  /* we can quickly get the (remaining) data of the first buffer */
  return size - adapter->skip;
}
Пример #27
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;
}
Пример #28
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;
}