Пример #1
0
/**
 * gst_buffer_span:
 * @buf1: the first source #GstBuffer to merge.
 * @offset: the offset in the first buffer from where the new
 * buffer should start.
 * @buf2: the second source #GstBuffer to merge.
 * @len: the total length of the new buffer.
 *
 * Creates a new buffer that consists of part of buf1 and buf2.
 * Logically, buf1 and buf2 are concatenated into a single larger
 * buffer, and a new buffer is created at the given offset inside
 * this space, with a given length.
 *
 * If the two source buffers are children of the same larger buffer,
 * and are contiguous, the new buffer will be a child of the shared
 * parent, and thus no copying is necessary. you can use
 * gst_buffer_is_span_fast() to determine if a memcpy will be needed.
 *
 * MT safe.
 * Returns: the new #GstBuffer that spans the two source buffers.
 * Returns NULL if the arguments are invalid.
 */
GstBuffer *
gst_buffer_span (GstBuffer * buf1, guint32 offset, GstBuffer * buf2,
    guint32 len)
{
  GstBuffer *newbuf;

  g_return_val_if_fail (buf1 != NULL && buf2 != NULL, NULL);
  g_return_val_if_fail (buf1->mini_object.refcount > 0, NULL);
  g_return_val_if_fail (buf2->mini_object.refcount > 0, NULL);
  g_return_val_if_fail (len > 0, NULL);
  g_return_val_if_fail (len <= buf1->size + buf2->size - offset, NULL);

  /* if the two buffers have the same parent and are adjacent */
  if (gst_buffer_is_span_fast (buf1, buf2)) {
    GstBuffer *parent = GST_SUBBUFFER_CAST (buf1)->parent;

    /* we simply create a subbuffer of the common parent */
    newbuf = gst_buffer_create_sub (parent,
        buf1->data - parent->data + offset, len);
  } else {
    GST_CAT_DEBUG (GST_CAT_BUFFER,
        "slow path taken while spanning buffers %p and %p", buf1, buf2);
    /* otherwise we simply have to brute-force copy the buffers */
    newbuf = gst_buffer_new_and_alloc (len);

    /* copy the first buffer's data across */
    memcpy (newbuf->data, buf1->data + offset, buf1->size - offset);
    /* copy the second buffer's data across */
    memcpy (newbuf->data + (buf1->size - offset), buf2->data,
        len - (buf1->size - offset));
  }
  /* if the offset is 0, the new buffer has the same timestamp as buf1 */
  if (offset == 0) {
    GST_BUFFER_OFFSET (newbuf) = GST_BUFFER_OFFSET (buf1);
    GST_BUFFER_TIMESTAMP (newbuf) = GST_BUFFER_TIMESTAMP (buf1);

    /* if we completely merged the two buffers (appended), we can
     * calculate the duration too. Also make sure we's not messing with
     * invalid DURATIONS */
    if (buf1->size + buf2->size == len) {
      if (GST_BUFFER_DURATION_IS_VALID (buf1) &&
          GST_BUFFER_DURATION_IS_VALID (buf2)) {
        /* add duration */
        GST_BUFFER_DURATION (newbuf) = GST_BUFFER_DURATION (buf1) +
            GST_BUFFER_DURATION (buf2);
      }
      if (GST_BUFFER_OFFSET_END_IS_VALID (buf2)) {
        /* add offset_end */
        GST_BUFFER_OFFSET_END (newbuf) = GST_BUFFER_OFFSET_END (buf2);
      }
    }
  }

  return newbuf;
}
Пример #2
0
/* Internal method only. Tries to merge buffers at the head of the queue
 * to form a single larger buffer of size 'size'. Only merges buffers that
 * where 'gst_buffer_is_span_fast' returns TRUE.
 *
 * Returns TRUE if it managed to merge anything.
 */
static gboolean
gst_adapter_try_to_merge_up (GstAdapter * adapter, guint size)
{
    GstBuffer *cur, *head;
    GSList *g;
    gboolean ret = FALSE;

    g = adapter->buflist;
    if (g == NULL)
        return FALSE;

    head = g->data;
    g = g_slist_next (g);

    /* How large do we want our head buffer? The requested size, plus whatever's
     * been skipped already */
    size += adapter->skip;

    while (g != NULL && GST_BUFFER_SIZE (head) < size) {
        cur = g->data;
        if (!gst_buffer_is_span_fast (head, cur))
            return ret;

        /* Merge the head buffer and the next in line */
        GST_LOG_OBJECT (adapter,
                        "Merging buffers of size %u & %u in search of target %u",
                        GST_BUFFER_SIZE (head), GST_BUFFER_SIZE (cur), size);

        head = gst_buffer_join (head, cur);
        ret = TRUE;

        /* Delete the front list item, and store our new buffer in the 2nd list
         * item */
        adapter->buflist = g_slist_delete_link (adapter->buflist, adapter->buflist);
        g->data = head;

        /* invalidate scan position */
        adapter->priv->scan_offset = 0;
        adapter->priv->scan_entry = NULL;

        g = g_slist_next (g);
    }

    return ret;
}