/** * 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; }
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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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); } } }
/** * 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); } }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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); }
/** * 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; }
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); }
/** * 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; } }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }