gstreamer/gst/gstbuffer.c

554 lines
16 KiB
C
Raw Normal View History

/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstbuffer.c: Buffer operations
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
Changes made to the DEBUG system. New header file gstdebug.h holds the stuff to keep it out of gst.h's hair. DEBUG ... Original commit message from CVS: Changes made to the DEBUG system. New header file gstdebug.h holds the stuff to keep it out of gst.h's hair. DEBUG prints out the process id, cothread id, source filename and line number. Two new macros DEBUG_ENTER and DEBUG_LEAVE are used to show the entry and exit of a given function. This eventually might be used to construct call trace graphs, even taking cothreads into account. This would be quite useful in visualizing the scheduling mechanism. Minor changes to various debug messages. Also sitting in gstdebug.h is a prototypical DEBUG_ENTER that's capable of performing DEBUG_LEAVE automatically. It does this by utilizing a little-known GCC extension that allows one to call a function with the same parameters as the current function. The macro uses this to basically call itself. A boolean is used to ensure that when it calls itself it actually runs the body of the function. In the meantime it prints stuff out before and after the real function, as well as constructing a debugging string. This can be used eventually to provide call-wide data on the DEBUG lines, instead of having to replicate data on each call to DEBUG. More research is needed into how this would most cleanly be fit into some other chunk of code, like GStreamer (I think of this DEBUG trick as a separate project, sorta). Unfortunately, the aforementioned DEBUG trick interacts quite poorly with cothreads. Almost any time it's used in a function that has anything remotely to do with a cothread context (as in, it runs in one), a segfault results from the __builtin_apply call, which is the heart of the whole thing. If someone who really knows assembly could analyze the resulting code to see what's really going on, we might find a way to fix either the macro or the cothreads (I'm thinking that there's something we missed in constructing the cothreads themselves) so this works in all cases. In the meantime, please insert both DEBUG_ENTER and DEBUG_LEAVE in your functions. Be sure to put DEBUG_ENTER after your variable declarations and before any functional code, not to put the function name in any DEBUG strings (it's already there, trust me), and put a DEBUG_LEAVE if you care enough. Changes are going to happen in the way DEBUGs and other printouts occur, so stay tuned.
2000-12-04 09:35:08 +00:00
/* this file makes too much noise for most debugging sessions */
#define GST_DEBUG_FORCE_DISABLE
#include "gst_private.h"
#include "gstbuffer.h"
#include "gstobject.h"
static GMemChunk *_buffer_chunk = NULL;
static GstBufferPool *_default_pool = NULL;
static GstBufferPool *_sub_buffer_pool = NULL;
static GstBuffer * gst_buffer_pool_default_buffer_new (GstBufferPool *pool,
guint size);
static GstBuffer * gst_buffer_pool_default_buffer_copy (GstBufferPool *from_pool,
const GstBuffer *buffer,
guint offset,
guint size);
static void gst_buffer_pool_default_buffer_dispose (GstData *buffer);
static GstBuffer * gst_buffer_pool_sub_buffer_new (GstBufferPool *pool,
guint size);
static GstBuffer * gst_buffer_pool_sub_buffer_copy (GstBufferPool *from_pool,
const GstBuffer *buffer,
guint offset,
guint size);
static void gst_buffer_pool_sub_buffer_dispose (GstData *buffer);
This is an attempt at not segfaulting on errors but reporting some usefull info instead. Original commit message from CVS: This is an attempt at not segfaulting on errors but reporting some usefull info instead. - bin changes so errors can propagate. - changed the _FAST macros to _CAST because that is what they do. - removed all references to cothreads out of the core, they are really a scheduler issue, handler with a sched_private gpointer. - added a live buffer count, for debugging buffer leaks. - added error checking in gst_scheduler_state_transition this solves the "out of cothreads" problem. - GST_ELEMENT_NO_ENTRY == GST_ELEMENT_INFINITE_LOOP - added 2 private element flasg for use by the scheduler (_COTHREAD_STOPPING) is now - added scheduler entry points: - _yield : to create possible scheduling points. - _interrupt: to stop execution of an element. - _error: to signal en error condition to the scheduler. - improved error messages for pads. - signal gst_element_error where appropriate. - added the a new bin to the parent before entering it so one can reference its children. - queue memleak fixes on dispose. - added possible deadlock detection in queue (turned off be default) - GstBasicScheduler is a real class of its own now, hiding its internal variables. - GST_ELEMENT_IS_COTHREAD_STOPPING is gone. either call explicit _yield operations, or make a sane loop. - Better state change handling in filesrc. Better error reporting/recovery too. - updated core plugins. - detect non decoupled elements on scheduler boundries and error.
2001-12-22 21:18:17 +00:00
void
_gst_buffer_initialize (void)
This is an attempt at not segfaulting on errors but reporting some usefull info instead. Original commit message from CVS: This is an attempt at not segfaulting on errors but reporting some usefull info instead. - bin changes so errors can propagate. - changed the _FAST macros to _CAST because that is what they do. - removed all references to cothreads out of the core, they are really a scheduler issue, handler with a sched_private gpointer. - added a live buffer count, for debugging buffer leaks. - added error checking in gst_scheduler_state_transition this solves the "out of cothreads" problem. - GST_ELEMENT_NO_ENTRY == GST_ELEMENT_INFINITE_LOOP - added 2 private element flasg for use by the scheduler (_COTHREAD_STOPPING) is now - added scheduler entry points: - _yield : to create possible scheduling points. - _interrupt: to stop execution of an element. - _error: to signal en error condition to the scheduler. - improved error messages for pads. - signal gst_element_error where appropriate. - added the a new bin to the parent before entering it so one can reference its children. - queue memleak fixes on dispose. - added possible deadlock detection in queue (turned off be default) - GstBasicScheduler is a real class of its own now, hiding its internal variables. - GST_ELEMENT_IS_COTHREAD_STOPPING is gone. either call explicit _yield operations, or make a sane loop. - Better state change handling in filesrc. Better error reporting/recovery too. - updated core plugins. - detect non decoupled elements on scheduler boundries and error.
2001-12-22 21:18:17 +00:00
{
gint buffersize = sizeof (GstBuffer);
if (_buffer_chunk == NULL)
{
/* create the default buffer chunk */
_buffer_chunk = g_mem_chunk_new ("GstBufferChunk", buffersize, buffersize * 128, G_ALLOC_AND_FREE);
/* create the default pool that uses g_malloc/free */
_default_pool = gst_buffer_pool_new ();
/* create the pool for subbuffers */
_sub_buffer_pool = gst_buffer_pool_new ();
gst_buffer_pool_set_buffer_new_function (_sub_buffer_pool, gst_buffer_pool_sub_buffer_new);
gst_buffer_pool_set_buffer_copy_function (_sub_buffer_pool, gst_buffer_pool_sub_buffer_copy);
gst_buffer_pool_set_buffer_dispose_function (_sub_buffer_pool, gst_buffer_pool_sub_buffer_dispose);
GST_INFO (GST_CAT_BUFFER, "Buffers are initialized now");
}
}
/**
* gst_buffer_alloc:
*
* Allocate space for a new buffer. Works the same way
* as g_malloc.
* Buffers allocated with gst_buffer_alloc must be freed
* with gst_buffer_free.
*
* Returns: A new buffer or NULL on failure
*/
GstBuffer *
gst_buffer_alloc (void)
{
return g_mem_chunk_alloc (_buffer_chunk);
}
/**
* gst_buffer_free:
* @buffer: The buffer to free.
*
* Frees a buffer that wa previously allocated with gst_buffer_alloc.
*/
void
gst_buffer_free (GstBuffer *buffer)
{
g_mem_chunk_free (_buffer_chunk, buffer);
}
/**
* gst_buffer_init:
* @buffer: The buffer to be initialized
* @pool: The bufferpool to initialize from
*
* Initializes a buffer from a given bufferpool.
* This function is a convenience function to be used in buffer_new
* routines of bufferpools.
*/
void
gst_buffer_init (GstBuffer *buffer, GstBufferPool *pool)
{
GST_DEBUG (GST_CAT_BUFFER, "initializing new buffer %p", buffer);
gst_data_ref (GST_DATA (pool));
gst_data_init (GST_DATA (buffer));
GST_DATA (buffer)->type = GST_DATA_BUFFER;
GST_DATA (buffer)->dispose = pool->buffer_dispose;
GST_DATA (buffer)->free = pool->buffer_free;
buffer->data = NULL;
buffer->size = 0;
buffer->pool = pool;
buffer->pool_private = NULL;
}
/**
* gst_buffer_dispose:
* @buffer: The buffer to be disposed
*
* Disposes a buffer.
* This function is a convenience function to be used in buffer_dispose
* routines of bufferpools.
*/
void
gst_buffer_dispose (GstData *buffer)
{
gst_data_unref (GST_DATA (GST_BUFFER (buffer)->pool));
gst_data_dispose (buffer);
}
/**
* gst_buffer_new:
* @pool: bufferpool to create the buffer from
* @size: size of the data, 0 if no data initialization
*
* Create a new buffer from the given bufferpool. If the bufferpool
* is set to NULL, the default pool is used.
*
* Returns: new buffer or NULL, if buffer couldn't be created.
*/
GstBuffer*
gst_buffer_new (GstBufferPool *pool, guint size)
{
if (pool == NULL)
{
GstBufferPool *def = _default_pool;
return def->buffer_new (def, size);
} else {
return pool->buffer_new (pool, size);
}
}
/**
* gst_buffer_create_sub:
* @parent: parent buffer
* @offset: offset into parent buffer
* @size: size of new subbuffer
*
* Creates a sub-buffer from the parent at a given offset.
*
* Returns: new buffer
*/
GstBuffer*
gst_buffer_create_sub (GstBuffer *parent, guint offset, guint size)
{
GstBuffer *buffer;
gpointer buffer_data;
g_return_val_if_fail (parent != NULL, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(parent) > 0, NULL);
g_return_val_if_fail (size > 0, NULL);
g_return_val_if_fail (parent->size >= offset + size, NULL);
/* remember the data for the new buffer */
buffer_data = parent->data + offset;
/* make sure we're child not child from a child buffer */
while (parent->pool == _sub_buffer_pool)
{
parent = GST_BUFFER (parent->pool_private);
}
/* ref the real parent */
gst_data_ref (GST_DATA (parent));
/* make sure nobody overwrites data in the parent */
if (GST_DATA_IS_WRITABLE (parent))
GST_DATA_FLAG_SET(parent, GST_DATA_READONLY);
/* create the new buffer */
buffer = gst_buffer_new (_sub_buffer_pool, 0);
/* make sure nobody overwrites data in the new buffer */
GST_DATA_FLAG_SET(buffer, GST_DATA_READONLY);
/* set the right values in the child */
buffer->pool_private = parent;
buffer->data = buffer_data;
buffer->size = size;
return buffer;
}
/**
* gst_buffer_append:
* @buffer: a buffer
* @append: the buffer to append
*
* Creates a new buffer by appending the data of append to the
* existing data of buffer.
*
* Returns: new buffer
*/
GstBuffer*
gst_buffer_append (GstBuffer *buffer, GstBuffer *append)
{
GstBuffer *newbuf;
g_return_val_if_fail (buffer != NULL, NULL);
g_return_val_if_fail (append != NULL, NULL);
g_return_val_if_fail (buffer->pool == NULL, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(append) > 0, NULL);
GST_INFO (GST_CAT_BUFFER,"appending buffers %p and %p",buffer,append);
newbuf = gst_buffer_merge (buffer, append);
gst_data_unref (GST_DATA (buffer));
return newbuf;
}
/**
* gst_buffer_copy_part_from_pool:
* @pool: the GstBufferPool to create the buffer from or NULL to use the default
* @buffer: the orignal GstBuffer to make a copy of
* @offset: the offset into the buffer
* @offset: the offset into the buffer
*
* Make a full copy of the given buffer with the given part of the data. Use the
* given bufferpool to create the buffer.
*
* Returns: new buffer
*/
GstBuffer *
gst_buffer_copy_part_from_pool (GstBufferPool *pool, const GstBuffer *buffer, guint offset, guint size)
{
GstBufferPool *use_pool;
g_return_val_if_fail (buffer != NULL, NULL);
g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT (buffer) > 0, NULL);
g_return_val_if_fail (buffer->size >= offset + size, NULL);
use_pool = pool ? pool : _default_pool;
return use_pool->buffer_copy (use_pool, buffer, offset, size);
}
/**
* gst_buffer_is_span_fast:
* @buf1: first source buffer
* @buf2: second source buffer
*
* Determines whether a gst_buffer_span is free, or requires a memcpy.
*
* Returns: TRUE if the buffers are contiguous, FALSE if a copy would be required.
*/
gboolean
gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2)
{
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf1) > 0, FALSE);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf2) > 0, FALSE);
/* it's only fast if we have subbuffers of the same parent */
return ((buf1->pool == _sub_buffer_pool) &&
(buf2->pool == _sub_buffer_pool) &&
(buf1->pool_private == buf2->pool_private) &&
((buf1->data + buf1->size) == buf2->data));
}
/**
* gst_buffer_span:
* @buf1: first source buffer to merge
* @offset: offset in first buffer to start new buffer
* @buf2: second source buffer to merge
* @len: length of new buffer
*
* Create 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.
*
* Returns: new buffer that spans the two source buffers
*/
/* FIXME need to think about CoW and such... */
GstBuffer *
gst_buffer_span (GstBuffer *buf1, guint offset, GstBuffer *buf2, guint len)
{
GstBuffer *newbuf;
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf1) > 0, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf2) > 0, NULL);
g_return_val_if_fail (len > 0, NULL);
/* if the two buffers have the same parent and are adjacent */
if (gst_buffer_is_span_fast(buf1,buf2)) {
GstBuffer *parent = GST_BUFFER (buf1->pool_private);
/* we simply create a subbuffer of the common parent */
newbuf = gst_buffer_create_sub (parent, buf1->data - parent->data + offset, len);
}
else {
GST_DEBUG (GST_CAT_BUFFER,"slow path taken while spanning buffers %p and %p", buffer, append);
/* otherwise we simply have to brute-force copy the buffers */
newbuf = gst_buffer_new (buf1->pool, len);
/* copy relevant stuff from data struct of buffer1 */
gst_data_copy (GST_DATA (newbuf), GST_DATA (buf1));
/* 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));
}
return newbuf;
}
/**
* gst_buffer_merge:
* @buf1: first source buffer to merge
* @buf2: second source buffer to merge
*
* Create a new buffer that is the concatenation of the two source
* buffers. The original source buffers will not be modified or
* unref'd.
*
* Internally is nothing more than a specialized gst_buffer_span,
* so the same optimizations can occur.
*
* Returns: new buffer that's the concatenation of the source buffers
*/
GstBuffer *
gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2)
{
guint i;
- some fixes to int2float making automake 1.5 happy (gst now requires automake1.5). It's still not perfect but it bui... Original commit message from CVS: - added playondemand plugin by Leif Morgan Johnson <lmjohns3@eos.ncsu.edu> - some fixes to int2float - aplied a patch from wrobell <wrobell@ite.pl> that is a first attempt at making automake 1.5 happy (gst now requires automake1.5). It's still not perfect but it builds. - Made the schedulers plugable. The default scheduler now lives inside a plugin. - Added a new mpeg1/2 parser/demuxer. - Fixed some compiler warnings in the core libs. - substantial work to GstThread (hopefully less race conditions). simplified the code in GstThread a bit. A state change can now also happen in the thread context. - reworked the state semantics of a bin. it'll now automatically get the highest state of its children. - the autoplugger now nests the threads so that a state change failure of one thread doesn't make its upstream thread lock. - GstQueue refuses to go to PLAYING if the sinkpad is not connected. This way the queue will not wedge in the _get lock. - GstQueue unlocks its mutexes when going to PAUSED. - make sure that when all elements in a bin/thread go to PAUSED, the bin is set to PAUSED too. - make a parent bin wait for its children to PAUSE before ending the iteration with FALSE (EOS) - Some changes to GstPlay to deal with EOS. - aplied the latest patch from Zeenix to gstrtp. end result: GstPlay doesn't crash on EOS and the pipeline is now shut down properly.
2001-12-04 22:12:50 +00:00
GstBuffer *result;
/* we're just a specific case of the more general gst_buffer_span() */
- some fixes to int2float making automake 1.5 happy (gst now requires automake1.5). It's still not perfect but it bui... Original commit message from CVS: - added playondemand plugin by Leif Morgan Johnson <lmjohns3@eos.ncsu.edu> - some fixes to int2float - aplied a patch from wrobell <wrobell@ite.pl> that is a first attempt at making automake 1.5 happy (gst now requires automake1.5). It's still not perfect but it builds. - Made the schedulers plugable. The default scheduler now lives inside a plugin. - Added a new mpeg1/2 parser/demuxer. - Fixed some compiler warnings in the core libs. - substantial work to GstThread (hopefully less race conditions). simplified the code in GstThread a bit. A state change can now also happen in the thread context. - reworked the state semantics of a bin. it'll now automatically get the highest state of its children. - the autoplugger now nests the threads so that a state change failure of one thread doesn't make its upstream thread lock. - GstQueue refuses to go to PLAYING if the sinkpad is not connected. This way the queue will not wedge in the _get lock. - GstQueue unlocks its mutexes when going to PAUSED. - make sure that when all elements in a bin/thread go to PAUSED, the bin is set to PAUSED too. - make a parent bin wait for its children to PAUSE before ending the iteration with FALSE (EOS) - Some changes to GstPlay to deal with EOS. - aplied the latest patch from Zeenix to gstrtp. end result: GstPlay doesn't crash on EOS and the pipeline is now shut down properly.
2001-12-04 22:12:50 +00:00
result = gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size);
/* but we can include offset info */
for (i = 0; i < GST_OFFSET_TYPES; i++)
{
GST_DATA (result)->offset[i] = GST_DATA (buf1)->offset[i];
}
- some fixes to int2float making automake 1.5 happy (gst now requires automake1.5). It's still not perfect but it bui... Original commit message from CVS: - added playondemand plugin by Leif Morgan Johnson <lmjohns3@eos.ncsu.edu> - some fixes to int2float - aplied a patch from wrobell <wrobell@ite.pl> that is a first attempt at making automake 1.5 happy (gst now requires automake1.5). It's still not perfect but it builds. - Made the schedulers plugable. The default scheduler now lives inside a plugin. - Added a new mpeg1/2 parser/demuxer. - Fixed some compiler warnings in the core libs. - substantial work to GstThread (hopefully less race conditions). simplified the code in GstThread a bit. A state change can now also happen in the thread context. - reworked the state semantics of a bin. it'll now automatically get the highest state of its children. - the autoplugger now nests the threads so that a state change failure of one thread doesn't make its upstream thread lock. - GstQueue refuses to go to PLAYING if the sinkpad is not connected. This way the queue will not wedge in the _get lock. - GstQueue unlocks its mutexes when going to PAUSED. - make sure that when all elements in a bin/thread go to PAUSED, the bin is set to PAUSED too. - make a parent bin wait for its children to PAUSE before ending the iteration with FALSE (EOS) - Some changes to GstPlay to deal with EOS. - aplied the latest patch from Zeenix to gstrtp. end result: GstPlay doesn't crash on EOS and the pipeline is now shut down properly.
2001-12-04 22:12:50 +00:00
return result;
}
/**
* gst_buffer_pool_new:
*
* Create a new buffer pool.
*
* Returns: new buffer pool
*/
GstBufferPool*
gst_buffer_pool_new (void)
{
GstBufferPool *pool;
pool = g_new0 (GstBufferPool, 1);
GST_DEBUG (GST_CAT_BUFFER,"allocating new buffer pool %p\n", pool);
/* init data struct */
gst_data_init (GST_DATA (pool));
GST_DATA_TYPE (pool) = GST_DATA_BUFFERPOOL;
/* set functions */
pool->buffer_new = gst_buffer_pool_default_buffer_new;
pool->buffer_copy = gst_buffer_pool_default_buffer_copy;
pool->buffer_dispose = gst_buffer_pool_default_buffer_dispose;
pool->buffer_free = (GstDataFreeFunction) gst_buffer_free;
return pool;
}
/**
* gst_buffer_pool_set_buffer_new_function:
* @pool: the pool to set the buffer create function for
* @create: the create function
*
* Sets the function that will be called when a buffer is created
* from this pool.
*/
void
gst_buffer_pool_set_buffer_new_function (GstBufferPool *pool,
GstBufferPoolBufferNewFunction create)
{
g_return_if_fail (pool != NULL);
g_return_if_fail (create != NULL);
pool->buffer_new = create;
}
/**
* gst_buffer_pool_set_buffer_dispose_function:
* @pool: the pool to set the buffer dispose function for
* @free: the dispose function
*
* Sets the function that will be called when a buffer should be disposed.
*/
void
gst_buffer_pool_set_buffer_dispose_function (GstBufferPool *pool,
GstDataFreeFunction dispose)
{
g_return_if_fail (pool != NULL);
g_return_if_fail (dispose != NULL);
pool->buffer_dispose = dispose;
}
/**
* gst_buffer_pool_set_buffer_free_function:
* @pool: the pool to set the buffer free function for
* @free: the free function
*
* Sets the function that will be called when a buffer should be freed.
*/
void
gst_buffer_pool_set_buffer_free_function (GstBufferPool *pool,
GstDataFreeFunction free)
{
g_return_if_fail (pool != NULL);
g_return_if_fail (free != NULL);
pool->buffer_free = free;
}
/**
* gst_buffer_pool_set_buffer_copy_function:
* @pool: the pool to set the buffer copy function for
* @copy: the copy function
*
* Sets the function that will be called when a buffer is copied.
* Your function does not need to check the given parameters, they will
* be checked before calling your function.
*/
void
gst_buffer_pool_set_buffer_copy_function (GstBufferPool *pool, GstBufferPoolBufferCopyFunction copy)
{
g_return_if_fail (pool != NULL);
g_return_if_fail (copy != NULL);
pool->buffer_copy = copy;
}
/**
* gst_buffer_pool_set_user_data:
* @pool: the pool to set the user data for
* @user_data: any user data to be passed to the create/destroy buffer functions
* and the destroy hook
*
* You can put your private data here.
*/
void
gst_buffer_pool_set_user_data (GstBufferPool *pool, gpointer user_data)
{
g_return_if_fail (pool != NULL);
pool->user_data = user_data;
}
/**
* gst_buffer_pool_get_user_data:
* @pool: the pool to get the user data from
*
* gets user data
*
* Returns: The user data of this bufferpool
*/
gpointer
gst_buffer_pool_get_user_data (GstBufferPool *pool)
{
g_return_val_if_fail (pool != NULL, NULL);
return pool->user_data;
}
static GstBuffer*
gst_buffer_pool_default_buffer_new (GstBufferPool *pool, guint size)
{
GstBuffer *buffer;
g_return_val_if_fail((buffer = gst_buffer_alloc()), NULL);
GST_INFO (GST_CAT_BUFFER,"creating new buffer %p from pool %p", buffer, pool);
gst_buffer_init (buffer, pool);
GST_BUFFER_DATA(buffer) = size > 0 ? g_malloc (size) : NULL;
GST_BUFFER_SIZE(buffer) = GST_BUFFER_DATA(buffer) ? size : 0;
return buffer;
}
static GstBuffer *
gst_buffer_pool_default_buffer_copy (GstBufferPool *from_pool, const GstBuffer *buffer, guint offset, guint size)
{
GstBuffer *newbuf;
/* allocate a new buffer with the right size */
newbuf = gst_buffer_new (from_pool, size);
/* copy all relevant data stuff */
gst_data_copy (GST_DATA (newbuf), GST_DATA (buffer));
/* copy the data straight across */
memcpy (newbuf->data, buffer->data + offset, size);
return newbuf;
}
static void
gst_buffer_pool_default_buffer_dispose(GstData *buffer)
{
GstBuffer *buf = GST_BUFFER (buffer);
gst_buffer_dispose (buffer);
g_free (buf->data);
buf->data = NULL;
buf->size = 0;
}
static GstBuffer *
gst_buffer_pool_sub_buffer_new (GstBufferPool *pool, guint size)
{
GstBuffer *buffer;
g_return_val_if_fail((buffer = gst_buffer_alloc()), NULL);
GST_DEBUG (GST_CAT_BUFFER, "creating new subbuffer %p", buffer, pool);
gst_buffer_init (buffer, pool);
GST_BUFFER_DATA(buffer) = NULL;
GST_BUFFER_SIZE(buffer) = 0;
return buffer;
}
static GstBuffer *
gst_buffer_pool_sub_buffer_copy (GstBufferPool *from_pool, const GstBuffer *buffer, guint offset, guint size)
{
GstBuffer *parent = GST_BUFFER (buffer->pool_private);
guint new_offset = buffer->data - parent->data;
GstBufferPool *use_pool = from_pool == _sub_buffer_pool ? NULL : from_pool;
return parent->pool->buffer_copy (use_pool, parent, new_offset, size);
}
static void
gst_buffer_pool_sub_buffer_dispose (GstData *buffer)
{
GstBuffer *buf = GST_BUFFER (buffer);
buf->data = NULL;
buf->size = 0;
gst_data_unref (GST_DATA (buf->pool_private));
buf->pool_private = NULL;
gst_buffer_dispose (buffer);
}