From: Thomas Vander Stichele Date: Sun, 23 Dec 2001 00:07:59 +0000 (+0000) Subject: moving bytestream in the same way as in gst-plugins since ac3parse needs it X-Git-Tag: RELEASE-0_3_1-BELGIANBEER~125 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2b20b7178ffefa631712581aec3b2618065c47c0;p=platform%2Fupstream%2Fgstreamer.git moving bytestream in the same way as in gst-plugins since ac3parse needs it Original commit message from CVS: moving bytestream in the same way as in gst-plugins since ac3parse needs it --- diff --git a/libs/gst/Makefile.am b/libs/gst/Makefile.am new file mode 100644 index 0000000..a2279b5 --- /dev/null +++ b/libs/gst/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = bytestream + +DIST_SUBDIRS = bytestream diff --git a/libs/gst/bytestream/Makefile.am b/libs/gst/bytestream/Makefile.am new file mode 100644 index 0000000..3468201 --- /dev/null +++ b/libs/gst/bytestream/Makefile.am @@ -0,0 +1,15 @@ +libdir = $(libdir)/gst + +lib_LTLIBRARIES = libgstbytestream.la libgstbstest.la + +libgstbytestream_la_SOURCES = bytestream.c +libgstbstest_la_SOURCES = bstest.c + +libgstbytestreamincludedir = $(includedir)/gst/bytestream +libgstbytestreaminclude_HEADERS = bytestream.h + +libgstbytestream_la_LIBADD = $(GST_LIBS) +libgstbytestream_la_CFLAGS = $(GST_CFLAGS) + +libgstbstest_la_LIBADD = $(GST_LIBS) +libgstbstest_la_CFLAGS = $(GST_CFLAGS) diff --git a/libs/gst/bytestream/bstest.c b/libs/gst/bytestream/bstest.c new file mode 100644 index 0000000..087d63a --- /dev/null +++ b/libs/gst/bytestream/bstest.c @@ -0,0 +1,294 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstidentity.c: + * + * 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. + */ + +#include +#include "gstbytestream.h" + +#define GST_TYPE_IDENTITY \ + (gst_identity_get_type()) +#define GST_IDENTITY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_IDENTITY,GstIdentity)) +#define GST_IDENTITY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_IDENTITY,GstIdentityClass)) +#define GST_IS_IDENTITY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_IDENTITY)) +#define GST_IS_IDENTITY_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_IDENTITY)) + +typedef struct _GstIdentity GstIdentity; +typedef struct _GstIdentityClass GstIdentityClass; + +struct _GstIdentity { + GstElement element; + + GstPad *sinkpad; + GstPad *srcpad; + + GstByteStream *bs; + gint byte_size; + gint count; +}; + +struct _GstIdentityClass { + GstElementClass parent_class; +}; + +GType gst_identity_get_type(void); + + +GstElementDetails gst_identity_details = { + "ByteStreamTest", + "Filter", + "Test for the GstByteStream code", + VERSION, + "Erik Walthinsen ", + "(C) 2001", +}; + + +/* Identity signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_BYTE_SIZE, + ARG_COUNT, +}; + + +static void gst_identity_class_init (GstIdentityClass *klass); +static void gst_identity_init (GstIdentity *identity); + +static void gst_identity_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_identity_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +static void gst_identity_loop (GstElement *element); + +static GstElementClass *parent_class = NULL; +// static guint gst_identity_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_identity_get_type (void) +{ + static GType identity_type = 0; + + if (!identity_type) { + static const GTypeInfo identity_info = { + sizeof(GstIdentityClass), NULL, + NULL, + (GClassInitFunc)gst_identity_class_init, + NULL, + NULL, + sizeof(GstIdentity), + 0, + (GInstanceInitFunc)gst_identity_init, + }; + identity_type = g_type_register_static (GST_TYPE_ELEMENT, "GstBSTest", &identity_info, 0); + } + return identity_type; +} + +static void +gst_identity_class_init (GstIdentityClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass*)klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BYTE_SIZE, + g_param_spec_uint ("byte_size", "byte_size", "byte_size", + 0, G_MAXUINT, 0, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COUNT, + g_param_spec_uint ("count", "count", "count", + 0, G_MAXUINT, 0, G_PARAM_READWRITE)); + + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property); + gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property); +} + +static GstPadNegotiateReturn +gst_identity_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data) +{ + GstIdentity *identity; + + identity = GST_IDENTITY (gst_pad_get_parent (pad)); + + return gst_pad_negotiate_proxy (pad, identity->sinkpad, caps); +} + +static GstPadNegotiateReturn +gst_identity_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data) +{ + GstIdentity *identity; + + identity = GST_IDENTITY (gst_pad_get_parent (pad)); + + return gst_pad_negotiate_proxy (pad, identity->srcpad, caps); +} + +static void +gst_identity_init (GstIdentity *identity) +{ + identity->sinkpad = gst_pad_new ("sink", GST_PAD_SINK); + gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad); + gst_pad_set_negotiate_function (identity->sinkpad, gst_identity_negotiate_sink); + + identity->srcpad = gst_pad_new ("src", GST_PAD_SRC); + gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad); + gst_pad_set_negotiate_function (identity->srcpad, gst_identity_negotiate_src); + + gst_element_set_loop_function (GST_ELEMENT (identity), gst_identity_loop); + + identity->byte_size = 384; + identity->count = 5; + + identity->bs = gst_bytestream_new(identity->sinkpad); +} + +static void +gst_identity_loop (GstElement *element) +{ + GstIdentity *identity; + GstBuffer *buf; + int i; + + g_return_if_fail (element != NULL); + g_return_if_fail (GST_IS_IDENTITY (element)); + + identity = GST_IDENTITY (element); + +/* THIS IS THE BUFFER BASED ONE + do { +// g_print("\n"); + + for (i=0;icount;i++) { +// g_print("bstest: getting a buffer of %d bytes\n",identity->byte_size); + buf = gst_bytestream_read(identity->bs,identity->byte_size); + if (!buf) g_print("BUFFER IS BOGUS\n"); +// g_print("pushing the buffer, %d bytes at %d\n",GST_BUFFER_SIZE(buf),GST_BUFFER_OFFSET(buf)); + gst_pad_push(identity->srcpad,buf); +// g_print("\n"); + gst_bytestream_print_status(identity->bs); +// g_print("\n\n"); + } + + exit(1); + } while (!GST_ELEMENT_IS_COTHREAD_STOPPING(element)); +*/ + +/* THIS IS THE BYTE BASED ONE*/ + do { + for (i=0;icount;i++) { + buf = gst_buffer_new(); + // note that this is dangerous, as it does *NOT* refcount the data, it can go away!!! + GST_BUFFER_DATA(buf) = gst_bytestream_peek_bytes(identity->bs,identity->byte_size); + GST_BUFFER_SIZE(buf) = identity->byte_size; + GST_BUFFER_FLAG_SET(buf,GST_BUFFER_DONTFREE); + gst_pad_push(identity->srcpad,buf); + gst_bytestream_flush(identity->bs,identity->byte_size); + } + + exit(1); + } while (!GST_ELEMENT_IS_COTHREAD_STOPPING(element)); +/**/ +} + +static void +gst_identity_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstIdentity *identity; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_IDENTITY (object)); + + identity = GST_IDENTITY (object); + + switch (prop_id) { + case ARG_BYTE_SIZE: + identity->byte_size = g_value_get_uint (value); + break; + case ARG_COUNT: + identity->count = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void gst_identity_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { + GstIdentity *identity; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_IDENTITY (object)); + + identity = GST_IDENTITY (object); + + switch (prop_id) { + case ARG_BYTE_SIZE: + g_value_set_uint (value, identity->byte_size); + break; + case ARG_COUNT: + g_value_set_uint (value, identity->count); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + + // we need gstbytestream + if (!gst_library_load ("gstbytestream")) { + g_print("can't load bytestream\n"); + return FALSE; + } + + /* We need to create an ElementFactory for each element we provide. + * This consists of the name of the element, the GType identifier, + * and a pointer to the details structure at the top of the file. + */ + factory = gst_elementfactory_new("gstbstest", GST_TYPE_IDENTITY, &gst_identity_details); + g_return_val_if_fail(factory != NULL, FALSE); + + /* The very last thing is to register the elementfactory with the plugin. */ + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "gstbstest", + plugin_init +}; + diff --git a/libs/gst/bytestream/bytestream.c b/libs/gst/bytestream/bytestream.c new file mode 100644 index 0000000..e5162ae --- /dev/null +++ b/libs/gst/bytestream/bytestream.c @@ -0,0 +1,455 @@ +/* GStreamer + * Copyright (C) 2001 Erik Walthinsen + * + * gstbytestream.c: adds a convenient bytestream based API to a pad. + * + * 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. + */ + +#include +#include +#include + +#include +#include "gstbytestream.h" + +//#define BS_DEBUG + +#ifdef BS_DEBUG +# define bs_print(format,args...) GST_DEBUG (GST_CAT_BUFFER, format, ## args) +# define bs_status(bs) gst_bytestream_print_status(bs) +#else +# define bs_print(format,args...) +# define bs_status(bs) +#endif + +guint8 *gst_bytestream_assemble (GstByteStream * bs, guint32 len); + +/** + * gst_bytestream_new: + * @pad: the pad to attach the bytestream to + * + * creates a bytestream from the given pad + * + * Returns: a new #GstByteStream object + */ +GstByteStream * +gst_bytestream_new (GstPad * pad) +{ + GstByteStream *bs = g_new (GstByteStream, 1); + + bs->pad = pad; + bs->event = NULL; + bs->buflist = NULL; + bs->headbufavail = 0; + bs->listavail = 0; + bs->assembled = NULL; + + return bs; +} + +void +gst_bytestream_destroy (GstByteStream * bs) +{ + GSList *walk; + + if (bs->event) + gst_event_free (bs->event); + + walk = bs->buflist; + while (walk) { + gst_buffer_unref (GST_BUFFER (walk->data)); + walk = g_slist_next (walk); + } + g_slist_free (bs->buflist); + if (bs->assembled) + g_free (bs->assembled); + g_free (bs); +} + +// HOW THIS WORKS: +// +// The fundamental structure is a singly-linked list of buffers. The +// buffer on the front is the oldest, and thus the first to read data +// from. The number of bytes left to be read in this buffer is stored +// in bs->headbufavail. The number of bytes available in the entire +// list (including the head buffer) is in bs->listavail. +// +// When a request is made for data (peek), _fill_bytes is called with +// the number of bytes needed, but only if the listavail indicates +// that there aren't already enough. This calls _get_next_buf until +// the listavail is sufficient to satisfy the demand. +// +// _get_next_buf pulls a buffer from the pad the bytestream is attached +// to, and shoves it in the list. There are actually two things it can +// do. If there's already a buffer in the list, and the _is_span_fast() +// test returns true, it will merge it with that last buffer. Otherwise +// it will simply tack it onto the end of the list. +// +// The _peek itself first checks the simple case of the request fitting +// within the head buffer, and if so creates a subbuffer and returns. +// Otherwise, it creates a new buffer and allocates space for the request +// and calls _assemble to fill it. We know we have to copy because this +// case only happens when the _merge wasn't feasible during _get_next_buf. +// +// The _flush method repeatedly inspects the head buffer and flushes as +// much data from it as it needs to, up to the size of the buffer. If +// the flush decimates the buffer, it's stripped, unref'd, and removed. + + +// get the next buffer +// if the buffer can be merged with the head buffer, do so +// else add it onto the head of the +static gboolean +gst_bytestream_get_next_buf (GstByteStream * bs) +{ + GstBuffer *nextbuf, *lastbuf; + GSList *end; + + g_assert (!bs->event); + + bs_print ("get_next_buf: pulling buffer\n"); + nextbuf = gst_pad_pull (bs->pad); + + if (GST_IS_EVENT (nextbuf)) + { + bs->event = GST_EVENT (nextbuf); + return FALSE; + } + + if (!nextbuf) + return FALSE; + + bs_print ("get_next_buf: got buffer of %d bytes\n", GST_BUFFER_SIZE (nextbuf)); + + // first see if there are any buffers in the list at all + if (bs->buflist) { + bs_print ("gst_next_buf: there is at least one buffer in the list\n"); + // now find the end of the list + end = g_slist_last (bs->buflist); + // get the buffer that's there + lastbuf = GST_BUFFER (end->data); + + // see if we can marge cheaply + if (gst_buffer_is_span_fast (lastbuf, nextbuf)) { + bs_print ("get_next_buf: merging new buffer with last buf on list\n"); + // it is, let's merge them (this is really an append, but...) + end->data = gst_buffer_merge (lastbuf, nextbuf); + // add to the length of the list + bs->listavail += GST_BUFFER_SIZE (nextbuf); + + // have to check to see if we merged with the head buffer + if (end == bs->buflist) { + bs->headbufavail += GST_BUFFER_SIZE (nextbuf); + } + + gst_buffer_unref (lastbuf); + gst_buffer_unref (nextbuf); + + // if we can't, we just append this buffer + } + else { + bs_print ("get_next_buf: adding new buffer to the end of the list\n"); + end = g_slist_append (end, nextbuf); + // also need to increment length of list and buffer count + bs->listavail += GST_BUFFER_SIZE (nextbuf); + } + + // if there are no buffers in the list + } + else { + bs_print ("get_next_buf: buflist is empty, adding new buffer to list\n"); + // put this on the end of the list + bs->buflist = g_slist_append (bs->buflist, nextbuf); + // and increment the number of bytes in the list + bs->listavail = GST_BUFFER_SIZE (nextbuf); + // set the head buffer avail to the size + bs->headbufavail = GST_BUFFER_SIZE (nextbuf); + } + + return TRUE; +} + +static gboolean +gst_bytestream_fill_bytes (GstByteStream * bs, guint32 len) +{ + // as long as we don't have enough, we get more buffers + while (bs->listavail < len) { + bs_print ("fill_bytes: there are %d bytes in the list, we need %d\n", bs->listavail, len); + if (!gst_bytestream_get_next_buf (bs)) + return FALSE; + } + + return TRUE; +} + + +GstBuffer * +gst_bytestream_peek (GstByteStream * bs, guint32 len) +{ + GstBuffer *headbuf, *retbuf = NULL; + + g_return_val_if_fail (bs != NULL, NULL); + g_return_val_if_fail (len > 0, NULL); + + bs_print ("peek: asking for %d bytes\n", len); + + // make sure we have enough + bs_print ("peek: there are %d bytes in the list\n", bs->listavail); + if (len > bs->listavail) { + if (!gst_bytestream_fill_bytes (bs, len)) + return NULL; + bs_print ("peek: there are now %d bytes in the list\n", bs->listavail); + } + bs_status (bs); + + // extract the head buffer + headbuf = GST_BUFFER (bs->buflist->data); + + // if the requested bytes are in the current buffer + bs_print ("peek: headbufavail is %d\n", bs->headbufavail); + if (len <= bs->headbufavail) { + bs_print ("peek: there are enough bytes in headbuf (need %d, have %d)\n", len, bs->headbufavail); + // create a sub-buffer of the headbuf + retbuf = gst_buffer_create_sub (headbuf, GST_BUFFER_SIZE (headbuf) - bs->headbufavail, len); + + // otherwise we need to figure out how to assemble one + } + else { + bs_print ("peek: current buffer is not big enough for len %d\n", len); + + retbuf = gst_buffer_new (); + GST_BUFFER_SIZE (retbuf) = len; + GST_BUFFER_DATA (retbuf) = gst_bytestream_assemble (bs, len); + if (GST_BUFFER_OFFSET (headbuf) != -1) + GST_BUFFER_OFFSET (retbuf) = GST_BUFFER_OFFSET (headbuf) + (GST_BUFFER_SIZE (headbuf) - bs->headbufavail); + } + + return retbuf; +} + +guint8 * +gst_bytestream_peek_bytes (GstByteStream * bs, guint32 len) +{ + GstBuffer *headbuf; + guint8 *data = NULL; + + g_return_val_if_fail (bs != NULL, NULL); + g_return_val_if_fail (len > 0, NULL); + + bs_print ("peek_bytes: asking for %d bytes\n", len); + if (bs->assembled) { + g_free (bs->assembled); + bs->assembled = NULL; + } + + // make sure we have enough + bs_print ("peek_bytes: there are %d bytes in the list\n", bs->listavail); + if (len > bs->listavail) { + if (!gst_bytestream_fill_bytes (bs, len)) + return NULL; + bs_print ("peek_bytes: there are now %d bytes in the list\n", bs->listavail); + } + bs_status (bs); + + // extract the head buffer + headbuf = GST_BUFFER (bs->buflist->data); + + // if the requested bytes are in the current buffer + bs_print ("peek_bytes: headbufavail is %d\n", bs->headbufavail); + if (len <= bs->headbufavail) { + bs_print ("peek_bytes: there are enough bytes in headbuf (need %d, have %d)\n", len, bs->headbufavail); + // create a sub-buffer of the headbuf + data = GST_BUFFER_DATA (headbuf) + (GST_BUFFER_SIZE (headbuf) - bs->headbufavail); + + // otherwise we need to figure out how to assemble one + } + else { + bs_print ("peek_bytes: current buffer is not big enough for len %d\n", len); + + data = gst_bytestream_assemble (bs, len); + bs->assembled = data; + bs->assembled_len = len; + } + + return data; +} + +guint8 * +gst_bytestream_assemble (GstByteStream * bs, guint32 len) +{ + guint8 *data = g_malloc (len); + GSList *walk; + guint32 copied = 0; + GstBuffer *buf; + + // copy the data from the curbuf + buf = GST_BUFFER (bs->buflist->data); + bs_print ("assemble: copying %d bytes from curbuf at %d to *data\n", bs->headbufavail, + GST_BUFFER_SIZE (buf) - bs->headbufavail); + memcpy (data, GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf) - bs->headbufavail, bs->headbufavail); + copied += bs->headbufavail; + + // asumption is made that the buffers all exist in the list + walk = g_slist_next (bs->buflist); + while (copied < len) { + buf = GST_BUFFER (walk->data); + if (GST_BUFFER_SIZE (buf) < (len - copied)) { + bs_print ("assemble: copying %d bytes from buf to output offset %d\n", GST_BUFFER_SIZE (buf), copied); + memcpy (data + copied, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); + copied += GST_BUFFER_SIZE (buf); + } + else { + bs_print ("assemble: copying %d bytes from buf to output offset %d\n", len - copied, copied); + memcpy (data + copied, GST_BUFFER_DATA (buf), len - copied); + copied = len; + } + walk = g_slist_next (walk); + } + + return data; +} + +gboolean +gst_bytestream_flush (GstByteStream * bs, guint32 len) +{ + bs_print ("flush: flushing %d bytes\n", len); + + // make sure we have enough + bs_print ("flush: there are %d bytes in the list\n", bs->listavail); + if (len > bs->listavail) { + if (!gst_bytestream_fill_bytes (bs, len)) + return FALSE; + bs_print ("flush: there are now %d bytes in the list\n", bs->listavail); + } + + gst_bytestream_flush_fast (bs, len); + + return TRUE; +} + +void +gst_bytestream_flush_fast (GstByteStream * bs, guint32 len) +{ + GstBuffer *headbuf; + + g_assert (len <= bs->listavail); + + if (bs->assembled) { + g_free (bs->assembled); + bs->assembled = NULL; + } + + // repeat until we've flushed enough data + while (len > 0) { + headbuf = GST_BUFFER (bs->buflist->data); + + bs_print ("flush: analyzing buffer that's %d bytes long, offset %d\n", GST_BUFFER_SIZE (headbuf), + GST_BUFFER_OFFSET (headbuf)); + + // if there's enough to complete the flush + if (bs->headbufavail > len) { + // just trim it off + bs_print ("flush: trimming %d bytes off end of headbuf\n", len); + bs->headbufavail -= len; + bs->listavail -= len; + len = 0; + + // otherwise we have to trim the whole buffer + } + else { + bs_print ("flush: removing head buffer completely\n"); + // remove it from the list + bs->buflist = g_slist_delete_link (bs->buflist, bs->buflist); + // trim it from the avail size + bs->listavail -= bs->headbufavail; + // record that we've trimmed this many bytes + len -= bs->headbufavail; + // unref it + gst_buffer_unref (headbuf); + + // record the new headbufavail + if (bs->buflist) { + bs->headbufavail = GST_BUFFER_SIZE (GST_BUFFER (bs->buflist->data)); + bs_print ("flush: next headbuf is %d bytes\n", bs->headbufavail); + } + else { + bs_print ("flush: no more bytes at all\n"); + } + } + + bs_print ("flush: bottom of while(), len is now %d\n", len); + } +} + +GstBuffer * +gst_bytestream_read (GstByteStream * bs, guint32 len) +{ + GstBuffer *buf = gst_bytestream_peek (bs, len); + if (!buf) + return NULL; + + gst_bytestream_flush_fast (bs, len); + + return buf; +} + + +/** + * gst_bytestream_get_status + * @bs: a bytestream + * @avail_out: total number of bytes buffered + * @event_out: an event + * + * When an event occurs, the bytestream will return NULL. You must + * retrieve the event using this API before reading more bytes from + * the stream. + * + * It is possible for the bytestream to return NULL due to running + * out of buffers, however, this indicates a bug because an EOS + * event should have been sent. + */ +void +gst_bytestream_get_status (GstByteStream *bs, + guint32 *avail_out, + GstEvent **event_out) +{ + if (avail_out) + *avail_out = bs->listavail; + + if (event_out) + { + *event_out = bs->event; + bs->event = NULL; + } +} + +void +gst_bytestream_print_status (GstByteStream * bs) +{ + GSList *walk; + GstBuffer *buf; + + bs_print ("STATUS: head buffer has %d bytes available\n", bs->headbufavail); + bs_print ("STATUS: list has %d bytes available\n", bs->listavail); + walk = bs->buflist; + while (walk) { + buf = GST_BUFFER (walk->data); + walk = g_slist_next (walk); + + bs_print ("STATUS: buffer starts at %d and is %d bytes long\n", GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf)); + } +} diff --git a/libs/gst/bytestream/bytestream.h b/libs/gst/bytestream/bytestream.h new file mode 100644 index 0000000..3906b22 --- /dev/null +++ b/libs/gst/bytestream/bytestream.h @@ -0,0 +1,57 @@ +/* GStreamer + * Copyright (C) 2001 Erik Walthinsen + * + * 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. + */ + +#ifndef __GST_BYTESTREAM_H__ +#define __GST_BYTESTREAM_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _GstByteStream GstByteStream; + +struct _GstByteStream { + GstPad *pad; + + GstEvent * event; + + GSList *buflist; + guint32 headbufavail; + guint32 listavail; + + // we keep state of assembled pieces + guint8 *assembled; + guint32 assembled_len; +}; + +GstByteStream* gst_bytestream_new (GstPad *pad); +void gst_bytestream_destroy (GstByteStream *bs); + +GstBuffer* gst_bytestream_read (GstByteStream *bs, guint32 len); +GstBuffer* gst_bytestream_peek (GstByteStream *bs, guint32 len); +guint8* gst_bytestream_peek_bytes (GstByteStream *bs, guint32 len); +gboolean gst_bytestream_flush (GstByteStream *bs, guint32 len); +void gst_bytestream_flush_fast (GstByteStream * bs, guint32 len); +void gst_bytestream_get_status (GstByteStream *bs, guint32 *avail_out, GstEvent **event_out); + +void gst_bytestream_print_status (GstByteStream *bs); + +#endif /* __GST_BYTESTREAM_H__ */