source: trunk/third/gstreamer/gst/gstbuffer.c @ 21448

Revision 21448, 14.3 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21447, which included commits to RCS files with non-trunk default branches.
Line 
1/* GStreamer
2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 *                    2000 Wim Taymans <wtay@chello.be>
4 *
5 * gstbuffer.c: Buffer operations
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
22
23#include "gst_private.h"
24
25#include "gstatomic_impl.h"
26#include "gstdata_private.h"
27#include "gstbuffer.h"
28#include "gstmemchunk.h"
29#include "gstinfo.h"
30
31GType _gst_buffer_type;
32
33#ifndef GST_DISABLE_TRACE
34/* #define GST_WITH_ALLOC_TRACE  */
35#include "gsttrace.h"
36
37static GstAllocTrace *_gst_buffer_trace;
38#endif
39
40static GstMemChunk *chunk;
41
42static GstBuffer *gst_buffer_alloc_chunk (void);
43static void gst_buffer_free_chunk (GstBuffer * buffer);
44
45void
46_gst_buffer_initialize (void)
47{
48  gst_buffer_get_type ();
49
50#ifndef GST_DISABLE_TRACE
51  _gst_buffer_trace = gst_alloc_trace_register (GST_BUFFER_TRACE_NAME);
52#endif
53
54  chunk = gst_mem_chunk_new ("GstBufferChunk", sizeof (GstBuffer),
55      sizeof (GstBuffer) * 200, 0);
56
57  GST_CAT_LOG (GST_CAT_BUFFER, "Buffers are initialized now");
58}
59
60GType
61gst_buffer_get_type (void)
62{
63  if (_gst_buffer_type == 0) {
64    _gst_buffer_type = g_boxed_type_register_static ("GstBuffer",
65        (GBoxedCopyFunc) gst_data_copy, (GBoxedFreeFunc) gst_data_unref);
66  }
67  return _gst_buffer_type;
68}
69
70static void
71_gst_buffer_sub_free (GstBuffer * buffer)
72{
73  gst_data_unref (GST_DATA (buffer->buffer_private));
74
75  GST_BUFFER_DATA (buffer) = NULL;
76  GST_BUFFER_SIZE (buffer) = 0;
77
78  _GST_DATA_DISPOSE (GST_DATA (buffer));
79
80  gst_buffer_free_chunk (buffer);
81}
82
83/**
84 * gst_buffer_default_free:
85 * @buffer: a #GstBuffer to free.
86 *
87 * Frees the memory associated with the buffer including the buffer data,
88 * unless the GST_BUFFER_DONTFREE flags was set or the buffer data is NULL.
89 */
90void
91gst_buffer_default_free (GstBuffer * buffer)
92{
93  g_return_if_fail (buffer != NULL);
94
95  /* free our data */
96  if (GST_BUFFER_FREE_DATA_FUNC (buffer)) {
97    GST_BUFFER_FREE_DATA_FUNC (buffer) (buffer);
98  } else if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_DONTFREE)) {
99    g_free (GST_BUFFER_DATA (buffer));
100  }
101
102  /* set to safe values */
103  GST_BUFFER_DATA (buffer) = NULL;
104  GST_BUFFER_SIZE (buffer) = 0;
105
106  _GST_DATA_DISPOSE (GST_DATA (buffer));
107
108  gst_buffer_free_chunk (buffer);
109}
110
111/**
112 * gst_buffer_stamp:
113 * @dest: buffer to stamp
114 * @src: buffer to stamp from
115 *
116 * Copies additional information (timestamps and offsets) from one buffer to
117 * the other.
118 */
119void
120gst_buffer_stamp (GstBuffer * dest, const GstBuffer * src)
121{
122  g_return_if_fail (dest != NULL);
123  g_return_if_fail (src != NULL);
124
125  GST_BUFFER_TIMESTAMP (dest) = GST_BUFFER_TIMESTAMP (src);
126  GST_BUFFER_DURATION (dest) = GST_BUFFER_DURATION (src);
127  GST_BUFFER_OFFSET (dest) = GST_BUFFER_OFFSET (src);
128  GST_BUFFER_OFFSET_END (dest) = GST_BUFFER_OFFSET_END (src);
129}
130
131/**
132 * gst_buffer_default_copy:
133 * @buffer: a #GstBuffer to make a copy of.
134 *
135 * Make a full newly allocated copy of the given buffer, data and all.
136 *
137 * Returns: the new #GstBuffer.
138 */
139GstBuffer *
140gst_buffer_default_copy (GstBuffer * buffer)
141{
142  GstBuffer *copy;
143  guint16 flags;
144
145  g_return_val_if_fail (buffer != NULL, NULL);
146
147  /* create a fresh new buffer */
148  copy = gst_buffer_alloc_chunk ();
149
150  /* copy relevant flags */
151  flags = GST_DATA_FLAG_SHIFT (GST_BUFFER_KEY_UNIT) |
152      GST_DATA_FLAG_SHIFT (GST_BUFFER_IN_CAPS) |
153      GST_DATA_FLAG_SHIFT (GST_BUFFER_DELTA_UNIT);
154  flags = GST_BUFFER_FLAGS (buffer) & flags;
155
156  _GST_DATA_INIT (GST_DATA (copy),
157      _gst_buffer_type,
158      flags,
159      (GstDataFreeFunction) gst_buffer_default_free,
160      (GstDataCopyFunction) gst_buffer_default_copy);
161
162  /* we simply copy everything from our parent */
163  GST_BUFFER_DATA (copy) = g_memdup (GST_BUFFER_DATA (buffer),
164      GST_BUFFER_SIZE (buffer));
165  GST_BUFFER_SIZE (copy) = GST_BUFFER_SIZE (buffer);
166  GST_BUFFER_MAXSIZE (copy) = GST_BUFFER_SIZE (buffer);
167
168  gst_buffer_stamp (copy, buffer);
169  GST_BUFFER_FREE_DATA_FUNC (copy) = NULL;
170  GST_BUFFER_PRIVATE (copy) = NULL;
171
172  return copy;
173}
174
175static GstBuffer *
176gst_buffer_alloc_chunk (void)
177{
178  GstBuffer *newbuf;
179
180  newbuf = gst_mem_chunk_alloc (chunk);
181#ifndef GST_DISABLE_TRACE
182  gst_alloc_trace_new (_gst_buffer_trace, newbuf);
183#endif
184
185  return newbuf;
186}
187
188static void
189gst_buffer_free_chunk (GstBuffer * buffer)
190{
191  gst_mem_chunk_free (chunk, GST_DATA (buffer));
192#ifndef GST_DISABLE_TRACE
193  gst_alloc_trace_free (_gst_buffer_trace, buffer);
194#endif
195}
196
197/**
198 * gst_buffer_new:
199 *
200 * Creates a newly allocated buffer without any data.
201 *
202 * Returns: the new #GstBuffer.
203 */
204GstBuffer *
205gst_buffer_new (void)
206{
207  GstBuffer *newbuf;
208
209  newbuf = gst_buffer_alloc_chunk ();
210
211  GST_CAT_LOG (GST_CAT_BUFFER, "new %p", newbuf);
212
213  _GST_DATA_INIT (GST_DATA (newbuf),
214      _gst_buffer_type,
215      0,
216      (GstDataFreeFunction) gst_buffer_default_free,
217      (GstDataCopyFunction) gst_buffer_default_copy);
218
219  GST_BUFFER_DATA (newbuf) = NULL;
220  GST_BUFFER_SIZE (newbuf) = 0;
221  GST_BUFFER_MAXSIZE (newbuf) = GST_BUFFER_MAXSIZE_NONE;
222  GST_BUFFER_TIMESTAMP (newbuf) = GST_CLOCK_TIME_NONE;
223  GST_BUFFER_DURATION (newbuf) = GST_CLOCK_TIME_NONE;
224  GST_BUFFER_OFFSET (newbuf) = GST_BUFFER_OFFSET_NONE;
225  GST_BUFFER_OFFSET_END (newbuf) = GST_BUFFER_OFFSET_NONE;
226  GST_BUFFER_FREE_DATA_FUNC (newbuf) = NULL;
227  GST_BUFFER_PRIVATE (newbuf) = NULL;
228
229  return newbuf;
230}
231
232/**
233 * gst_buffer_new_and_alloc:
234 * @size: the size of the new buffer's data.
235 *
236 * Creates a newly allocated buffer with data of the given size.
237 *
238 * Returns: the new #GstBuffer.
239 */
240GstBuffer *
241gst_buffer_new_and_alloc (guint size)
242{
243  GstBuffer *newbuf;
244
245  newbuf = gst_buffer_new ();
246
247  GST_BUFFER_DATA (newbuf) = g_malloc (size);
248  GST_BUFFER_SIZE (newbuf) = size;
249  GST_BUFFER_MAXSIZE (newbuf) = size;
250
251  return newbuf;
252}
253
254/**
255 * gst_buffer_create_sub:
256 * @parent: a parent #GstBuffer to create a subbuffer from.
257 * @offset: the offset into parent #GstBuffer.
258 * @size: the size of the new #GstBuffer sub-buffer (with size > 0).
259 *
260 * Creates a sub-buffer from the parent at a given offset.
261 * This sub-buffer uses the actual memory space of the parent buffer.
262 * This function will copy the offset and timestamp field when the
263 * offset is 0, else they are set to _NONE.
264 * The duration field of the new buffer are set to GST_CLOCK_TIME_NONE.
265 *
266 * Returns: the new #GstBuffer, or NULL if there was an error.
267 */
268GstBuffer *
269gst_buffer_create_sub (GstBuffer * parent, guint offset, guint size)
270{
271  GstBuffer *buffer;
272  gpointer buffer_data;
273
274  g_return_val_if_fail (parent != NULL, NULL);
275  g_return_val_if_fail (GST_BUFFER_REFCOUNT_VALUE (parent) > 0, NULL);
276  g_return_val_if_fail (size > 0, NULL);
277  g_return_val_if_fail (parent->size >= offset + size, NULL);
278
279  /* remember the data for the new buffer */
280  buffer_data = parent->data + offset;
281  /* make sure we're child not child from a child buffer */
282  while (GST_BUFFER_FLAG_IS_SET (parent, GST_BUFFER_SUBBUFFER)) {
283    parent = GST_BUFFER (parent->buffer_private);
284  }
285  /* ref the real parent */
286  gst_data_ref (GST_DATA (parent));
287
288  /* create the new buffer */
289  buffer = gst_buffer_alloc_chunk ();
290
291  GST_CAT_LOG (GST_CAT_BUFFER, "new subbuffer %p (parent %p)", buffer, parent);
292
293  /* make sure nobody overwrites data in the new buffer
294   * by setting the READONLY flag */
295  _GST_DATA_INIT (GST_DATA (buffer),
296      _gst_buffer_type,
297      GST_DATA_FLAG_SHIFT (GST_BUFFER_SUBBUFFER) |
298      GST_DATA_FLAG_SHIFT (GST_DATA_READONLY),
299      (GstDataFreeFunction) _gst_buffer_sub_free,
300      (GstDataCopyFunction) gst_buffer_default_copy);
301
302  /* set the right values in the child */
303  GST_BUFFER_DATA (buffer) = buffer_data;
304  GST_BUFFER_SIZE (buffer) = size;
305  GST_BUFFER_MAXSIZE (buffer) = size;
306  GST_BUFFER_FREE_DATA_FUNC (buffer) = NULL;
307  GST_BUFFER_PRIVATE (buffer) = parent;
308  /* we can copy the timestamp and offset if the new buffer starts at
309   * offset 0 */
310  if (offset == 0) {
311    GST_BUFFER_TIMESTAMP (buffer) = GST_BUFFER_TIMESTAMP (parent);
312    GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET (parent);
313  } else {
314    GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
315    GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE;
316  }
317
318  GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
319  GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE;
320
321  if (GST_BUFFER_FLAG_IS_SET (parent, GST_BUFFER_DONTKEEP)) {
322    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_DONTKEEP);
323  }
324  if (GST_BUFFER_FLAG_IS_SET (parent, GST_BUFFER_READONLY)) {
325    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_READONLY);
326  }
327
328  return buffer;
329}
330
331
332/**
333 * gst_buffer_merge:
334 * @buf1: a first source #GstBuffer to merge.
335 * @buf2: the second source #GstBuffer to merge.
336 *
337 * Create a new buffer that is the concatenation of the two source
338 * buffers.  The original source buffers will not be modified or
339 * unref'd.
340 *
341 * WARNING: Incorrect use of this function can lead to memory leaks.
342 * It is recommended to use gst_buffer_join() instead of this function.
343 *
344 * If the buffers point to contiguous areas of memory, the buffer
345 * is created without copying the data.
346 *
347 * Returns: the new #GstBuffer that's the concatenation of the source buffers.
348 */
349GstBuffer *
350gst_buffer_merge (GstBuffer * buf1, GstBuffer * buf2)
351{
352  GstBuffer *result;
353
354  /* we're just a specific case of the more general gst_buffer_span() */
355  result = gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size);
356
357  return result;
358}
359
360/**
361 * gst_buffer_join:
362 * @buf1: a first source #GstBuffer to merge.
363 * @buf2: the second source #GstBuffer to merge.
364 *
365 * Create a new buffer that is the concatenation of the two source
366 * buffers.  The original buffers are unreferenced.
367 *
368 * If the buffers point to contiguous areas of memory, the buffer
369 * is created without copying the data.
370 *
371 * Returns: the new #GstBuffer that's the concatenation of the source buffers.
372 */
373GstBuffer *
374gst_buffer_join (GstBuffer * buf1, GstBuffer * buf2)
375{
376  GstBuffer *result;
377
378  /* we're just a specific case of the more general gst_buffer_span() */
379  result = gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size);
380
381  gst_buffer_unref (buf1);
382  gst_buffer_unref (buf2);
383
384  return result;
385}
386
387/**
388 * gst_buffer_is_span_fast:
389 * @buf1: a first source #GstBuffer.
390 * @buf2: the second source #GstBuffer.
391 *
392 * Determines whether a gst_buffer_span() can be done without copying
393 * the contents, that is, whether the data areas are contiguous.
394 *
395 * Returns: TRUE if the buffers are contiguous,
396 * FALSE if a copy would be required.
397 */
398gboolean
399gst_buffer_is_span_fast (GstBuffer * buf1, GstBuffer * buf2)
400{
401  g_return_val_if_fail (buf1 != NULL && buf2 != NULL, FALSE);
402  g_return_val_if_fail (GST_BUFFER_REFCOUNT_VALUE (buf1) > 0, FALSE);
403  g_return_val_if_fail (GST_BUFFER_REFCOUNT_VALUE (buf2) > 0, FALSE);
404
405  /* it's only fast if we have subbuffers of the same parent */
406  return ((GST_BUFFER_FLAG_IS_SET (buf1, GST_BUFFER_SUBBUFFER)) &&
407      (GST_BUFFER_FLAG_IS_SET (buf2, GST_BUFFER_SUBBUFFER)) &&
408      (buf1->buffer_private == buf2->buffer_private) &&
409      ((buf1->data + buf1->size) == buf2->data));
410}
411
412/**
413 * gst_buffer_span:
414 * @buf1: a first source #GstBuffer to merge.
415 * @offset: the offset in the first buffer from where the new
416 * buffer should start.
417 * @buf2: the second source #GstBuffer to merge.
418 * @len: the total length of the new buffer.
419 *
420 * Creates a new buffer that consists of part of buf1 and buf2.
421 * Logically, buf1 and buf2 are concatenated into a single larger
422 * buffer, and a new buffer is created at the given offset inside
423 * this space, with a given length.
424 *
425 * If the two source buffers are children of the same larger buffer,
426 * and are contiguous, the new buffer will be a child of the shared
427 * parent, and thus no copying is necessary. you can use
428 * gst_buffer_is_span_fast() to determine if a memcpy will be needed.
429 *
430 * Returns: the new #GstBuffer that spans the two source buffers.
431 */
432GstBuffer *
433gst_buffer_span (GstBuffer * buf1, guint32 offset, GstBuffer * buf2,
434    guint32 len)
435{
436  GstBuffer *newbuf;
437
438  g_return_val_if_fail (buf1 != NULL && buf2 != NULL, NULL);
439  g_return_val_if_fail (GST_BUFFER_REFCOUNT_VALUE (buf1) > 0, NULL);
440  g_return_val_if_fail (GST_BUFFER_REFCOUNT_VALUE (buf2) > 0, NULL);
441  g_return_val_if_fail (len > 0, NULL);
442  g_return_val_if_fail (len <= buf1->size + buf2->size - offset, NULL);
443
444  /* if the two buffers have the same parent and are adjacent */
445  if (gst_buffer_is_span_fast (buf1, buf2)) {
446    GstBuffer *parent = GST_BUFFER (buf1->buffer_private);
447
448    /* we simply create a subbuffer of the common parent */
449    newbuf = gst_buffer_create_sub (parent,
450        buf1->data - parent->data + offset, len);
451  } else {
452    GST_CAT_DEBUG (GST_CAT_BUFFER,
453        "slow path taken while spanning buffers %p and %p", buf1, buf2);
454    /* otherwise we simply have to brute-force copy the buffers */
455    newbuf = gst_buffer_new_and_alloc (len);
456
457    /* copy the first buffer's data across */
458    memcpy (newbuf->data, buf1->data + offset, buf1->size - offset);
459    /* copy the second buffer's data across */
460    memcpy (newbuf->data + (buf1->size - offset), buf2->data,
461        len - (buf1->size - offset));
462    /* if the offset is 0, the new buffer has the same timestamp as buf1 */
463    if (offset == 0) {
464      GST_BUFFER_OFFSET (newbuf) = GST_BUFFER_OFFSET (buf1);
465      GST_BUFFER_TIMESTAMP (newbuf) = GST_BUFFER_TIMESTAMP (buf1);
466    }
467  }
468  /* if we completely merged the two buffers (appended), we can
469   * calculate the duration too. Also make sure we's not messing with
470   * invalid DURATIONS */
471  if (offset == 0 && buf1->size + buf2->size == len) {
472    if (GST_BUFFER_DURATION_IS_VALID (buf1) &&
473        GST_BUFFER_DURATION_IS_VALID (buf2)) {
474      /* add duration */
475      GST_BUFFER_DURATION (newbuf) = GST_BUFFER_DURATION (buf1) +
476          GST_BUFFER_DURATION (buf2);
477    }
478    if (GST_BUFFER_OFFSET_END_IS_VALID (buf2)) {
479      /* add offset_end */
480      GST_BUFFER_OFFSET_END (newbuf) = GST_BUFFER_OFFSET_END (buf2);
481    }
482  }
483
484  return newbuf;
485}
Note: See TracBrowser for help on using the repository browser.