diff --git a/libs/Makefile.am b/libs/Makefile.am index 4ced9cf040..003bbf648a 100644 --- a/libs/Makefile.am +++ b/libs/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = riff getbits putbits idct audio bytestream control resample +SUBDIRS = gst -DIST_SUBDIRS = riff getbits putbits audio idct bytestream control resample +DIST_SUBDIRS = gst diff --git a/libs/bytestream/Makefile.am b/libs/bytestream/Makefile.am deleted file mode 100644 index 5853dc3924..0000000000 --- a/libs/bytestream/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -filterdir = $(libdir)/gst - -filter_LTLIBRARIES = libgstbytestream.la libgstbstest.la - -libgstbytestream_la_SOURCES = gstbytestream.c -libgstbstest_la_SOURCES = gstbstest.c - -libgstbytestreamincludedir = $(includedir)/gst/libs/bytestream -libgstbytestreaminclude_HEADERS = gstbytestream.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/bytestream/gstbstest.c b/libs/bytestream/gstbstest.c deleted file mode 100644 index 087d63ade7..0000000000 --- a/libs/bytestream/gstbstest.c +++ /dev/null @@ -1,294 +0,0 @@ -/* 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/bytestream/gstbytestream.c b/libs/bytestream/gstbytestream.c deleted file mode 100644 index e5162aeecd..0000000000 --- a/libs/bytestream/gstbytestream.c +++ /dev/null @@ -1,455 +0,0 @@ -/* 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/bytestream/gstbytestream.h b/libs/bytestream/gstbytestream.h deleted file mode 100644 index 7061e93e08..0000000000 --- a/libs/bytestream/gstbytestream.h +++ /dev/null @@ -1,57 +0,0 @@ -/* 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__ */ diff --git a/libs/gst/control/Makefile.am b/libs/gst/control/Makefile.am new file mode 100644 index 0000000000..026fe8d5dc --- /dev/null +++ b/libs/gst/control/Makefile.am @@ -0,0 +1,22 @@ +libdir = $(libdir)/gst + +lib_LTLIBRARIES = libgstcontrol.la + +libgstcontrol_la_SOURCES = \ + control.c \ + dparammanager.c \ + dparam.c \ + dplinearinterp.c + + +libgstcontrolincludedir = $(includedir)/gst/control +libgstcontrolinclude_HEADERS = \ + control.h \ + dparammanager.h \ + dparam.h \ + dparamcommon.h \ + plinearinterp.h + +libgstcontrol_la_LIBADD = $(GST_LIBS) +libgstcontrol_la_CFLAGS = $(GST_CFLAGS) -finline-functions -ffast-math + diff --git a/libs/gst/control/control.c b/libs/gst/control/control.c new file mode 100644 index 0000000000..30c9b818b9 --- /dev/null +++ b/libs/gst/control/control.c @@ -0,0 +1,27 @@ +/* GStreamer + * Copyright (C) 2001 Steve Baker + * + * gstcontrol.c: GStreamer control utility library + * + * 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 + +void +gst_control_init (int *argc, char **argv[]) { + _gst_dpman_initialize (); +} diff --git a/libs/gst/control/control.h b/libs/gst/control/control.h new file mode 100644 index 0000000000..88096571cd --- /dev/null +++ b/libs/gst/control/control.h @@ -0,0 +1,39 @@ +/* GStreamer + * Copyright (C) 2001 Steve Baker + * + * gstcontrol.h: GStreamer control utility library + * + * 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_CONTROL_H__ +#define __GST_CONTROL_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include +#include + +void gst_control_init (int *argc, char **argv[]); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GST_CONTROL_H__ */ diff --git a/libs/gst/control/dparam.c b/libs/gst/control/dparam.c new file mode 100644 index 0000000000..088dbe195a --- /dev/null +++ b/libs/gst/control/dparam.c @@ -0,0 +1,408 @@ +/* GStreamer + * Copyright (C) 2001 Steve Baker + * + * gstdparam.c: Dynamic Parameter functionality + * + * 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 + +static void gst_dparam_class_init (GstDParamClass *klass); +static void gst_dparam_init (GstDParam *dparam); +static void gst_dparam_dispose (GObject *object); + +static void gst_dparam_do_update_realtime (GstDParam *dparam, gint64 timestamp); +static GValue** gst_dparam_get_point_realtime (GstDParam *dparam, gint64 timestamp); + +GType +gst_dparam_get_type(void) { + static GType dparam_type = 0; + + if (!dparam_type) { + static const GTypeInfo dparam_info = { + sizeof(GstDParamClass), + NULL, + NULL, + (GClassInitFunc)gst_dparam_class_init, + NULL, + NULL, + sizeof(GstDParam), + 0, + (GInstanceInitFunc)gst_dparam_init, + }; + dparam_type = g_type_register_static(GST_TYPE_OBJECT, "GstDParam", &dparam_info, 0); + } + return dparam_type; +} + +static void +gst_dparam_class_init (GstDParamClass *klass) +{ + GObjectClass *gobject_class; + GstDParamClass *dparam_class; + GstObjectClass *gstobject_class; + + gobject_class = (GObjectClass*)klass; + dparam_class = (GstDParamClass*)klass; + gstobject_class = (GstObjectClass*) klass; + + gobject_class->dispose = gst_dparam_dispose; + //gstobject_class->save_thyself = gst_dparam_save_thyself; + +} + +static void +gst_dparam_init (GstDParam *dparam) +{ + g_return_if_fail (dparam != NULL); + GST_DPARAM_VALUE(dparam) = NULL; + GST_DPARAM_TYPE(dparam) = 0; + GST_DPARAM_NEXT_UPDATE_TIMESTAMP(dparam)=0LL; + GST_DPARAM_LAST_UPDATE_TIMESTAMP(dparam)=0LL; + GST_DPARAM_READY_FOR_UPDATE(dparam)=FALSE; + dparam->lock = g_mutex_new (); +} + +/** + * gst_dparam_new: + * @type: the type that this dparam will store + * + * Returns: a new instance of GstDParam + */ +GstDParam* +gst_dparam_new (GType type) +{ + GstDParam *dparam; + + dparam = g_object_new (gst_dparam_get_type (), NULL); + dparam->do_update_func = gst_dparam_do_update_realtime; + dparam->get_point_func = gst_dparam_get_point_realtime; + + dparam->point = gst_dparam_new_value_array(type, 0); + GST_DPARAM_TYPE(dparam) = type; + + return dparam; +} + +static void +gst_dparam_dispose (GObject *object) +{ + GstDParam *dparam = GST_DPARAM(object); + GValue **point = dparam->point; + guint i = 0; + gchar *dparam_name = g_strdup(GST_DPARAM_NAME(dparam)); + + g_print("disposing of %s\n", dparam_name); + if (GST_DPARAM_MANAGER(dparam)){ + gst_dpman_detach_dparam(GST_DPARAM_MANAGER(dparam), dparam_name); + } + point = dparam->point; + while (point[i]){ + g_value_unset(point[i]); + g_free(point[i]); + i++; + } + g_free(dparam_name); + +} + +/** + * gst_dparam_attach + * @dparam: GstDParam instance + * @manager: the GstDParamManager that this dparam belongs to + * + */ +void +gst_dparam_attach (GstDParam *dparam, GstDParamManager *manager, GValue *value, GstDParamSpec *spec) +{ + + g_return_if_fail (dparam != NULL); + g_return_if_fail (GST_IS_DPARAM (dparam)); + g_return_if_fail (manager != NULL); + g_return_if_fail (GST_IS_DPMAN (manager)); + g_return_if_fail (value != NULL); + g_return_if_fail (spec != NULL); + g_return_if_fail (GST_DPARAM_TYPE(dparam) == G_VALUE_TYPE(value)); + + GST_DPARAM_NAME(dparam) = spec->dparam_name; + GST_DPARAM_VALUE(dparam) = value; + GST_DPARAM_SPEC(dparam) = spec; + GST_DPARAM_MANAGER(dparam) = manager; +} + +/** + * gst_dparam_detach + * @dparam: GstDParam instance + * @manager: the GstDParamManager that this dparam belongs to + * + */ +void +gst_dparam_detach (GstDParam *dparam) +{ + + g_return_if_fail (dparam != NULL); + g_return_if_fail (GST_IS_DPARAM (dparam)); + + GST_DPARAM_NAME(dparam) = NULL; + GST_DPARAM_VALUE(dparam) = NULL; + GST_DPARAM_SPEC(dparam) = NULL; + GST_DPARAM_MANAGER(dparam) = NULL; +} + +/** + * gst_dparam_new_value_array + * @type: the type of the first GValue in the array + * @...: the type of other GValues in the array + * + * The list of types should be terminated with a 0. + * If the type of a value is not yet known then use G_TYPE_NONE . + * + * Returns: an newly created array of GValues + */ +GValue** +gst_dparam_new_value_array(GType type, ...) +{ + GValue **point; + GValue *value; + guint x; + guint values_length = 0; + va_list var_args; + GType each_type; + + va_start (var_args, type); + each_type = type; + while (each_type){ + values_length++; + each_type = va_arg (var_args, GType); + } + va_end (var_args); + + point = g_new0(GValue*,values_length + 1); + + va_start (var_args, type); + each_type = type; + for (x=0 ; x < values_length ; x++){ + value = g_new0(GValue,1); + if (each_type != G_TYPE_NONE){ + g_value_init(value, each_type); + } + point[x] = value; + each_type = va_arg (var_args, GType); + } + point[values_length] = NULL; + va_end (var_args); + + GST_DEBUG(GST_CAT_PARAMS, "array with %d values created\n", values_length); + + return point; +} + +void +gst_dparam_set_value_from_string(GValue *value, const gchar *value_str) +{ + + g_return_if_fail(value != NULL); + g_return_if_fail(value_str != NULL); + + GST_DEBUG(GST_CAT_PARAMS, "parsing '%s' to type %s\n", value_str, g_type_name(G_VALUE_TYPE(value))); + + switch (G_VALUE_TYPE(value)) { + case G_TYPE_STRING: + g_value_set_string(value, g_strdup(value_str)); + break; + case G_TYPE_ENUM: + case G_TYPE_INT: { + gint i; + sscanf (value_str, "%d", &i); + g_value_set_int(value, i); + break; + } + case G_TYPE_UINT: { + guint i; + sscanf (value_str, "%u", &i); + g_value_set_uint(value, i); + break; + } + case G_TYPE_LONG: { + glong i; + sscanf (value_str, "%ld", &i); + g_value_set_long(value, i); + break; + } + case G_TYPE_ULONG: { + gulong i; + sscanf (value_str, "%lu", &i); + g_value_set_ulong(value, i); + break; + } + case G_TYPE_BOOLEAN: { + gboolean i = FALSE; + if (!strncmp ("true", value_str, 4)) i = TRUE; + g_value_set_boolean(value, i); + break; + } + case G_TYPE_CHAR: { + gchar i; + sscanf (value_str, "%c", &i); + g_value_set_char(value, i); + break; + } + case G_TYPE_UCHAR: { + guchar i; + sscanf (value_str, "%c", &i); + g_value_set_uchar(value, i); + break; + } + case G_TYPE_FLOAT: { + gfloat i; + sscanf (value_str, "%f", &i); + g_value_set_float(value, i); + break; + } + case G_TYPE_DOUBLE: { + gfloat i; + sscanf (value_str, "%g", &i); + g_value_set_double(value, (gdouble)i); + break; + } + default: + break; + } +} + +static void +gst_dparam_do_update_realtime (GstDParam *dparam, gint64 timestamp) +{ + GST_DPARAM_LOCK(dparam); + GST_DPARAM_READY_FOR_UPDATE(dparam) = FALSE; + GST_DEBUG(GST_CAT_PARAMS, "updating value for %s(%p)\n",GST_DPARAM_NAME (dparam),dparam); + g_value_copy(dparam->point[0], GST_DPARAM_VALUE(dparam)); + GST_DPARAM_UNLOCK(dparam); +} + +static GValue** +gst_dparam_get_point_realtime (GstDParam *dparam, gint64 timestamp) +{ + GST_DEBUG(GST_CAT_PARAMS, "getting point for %s(%p)\n",GST_DPARAM_NAME (dparam),dparam); + return dparam->point; +} + +/********************** + * GstDParamSmooth + **********************/ + +static void gst_dparam_do_update_smooth (GstDParam *dparam, gint64 timestamp); +static GValue** gst_dparam_get_point_smooth (GstDParam *dparam, gint64 timestamp); + +/** + * gst_dparam_smooth_new: + * @type: the type that this dparam will store + * + * Returns: a new instance of GstDParamSmooth + */ +GstDParam* +gst_dparam_smooth_new (GType type) +{ + GstDParam *dparam; + + dparam = g_object_new (gst_dparam_get_type (), NULL); + + dparam->do_update_func = gst_dparam_do_update_smooth; + dparam->get_point_func = gst_dparam_get_point_smooth; + + dparam->point = gst_dparam_new_value_array(type, type, G_TYPE_FLOAT, 0); + GST_DPARAM_TYPE(dparam) = type; + + return dparam; +} + +static void +gst_dparam_do_update_smooth (GstDParam *dparam, gint64 timestamp) +{ + gint64 time_diff; + gfloat time_ratio; + + time_diff = MIN(GST_DPARAM_DEFAULT_UPDATE_PERIOD(dparam), + timestamp - GST_DPARAM_LAST_UPDATE_TIMESTAMP(dparam)); + + time_ratio = (gfloat)time_diff / g_value_get_float(dparam->point[2]); + + GST_DPARAM_LOCK(dparam); + + GST_DPARAM_LAST_UPDATE_TIMESTAMP(dparam) = GST_DPARAM_NEXT_UPDATE_TIMESTAMP(dparam); + while(GST_DPARAM_NEXT_UPDATE_TIMESTAMP(dparam) <= timestamp){ + GST_DPARAM_NEXT_UPDATE_TIMESTAMP(dparam) += GST_DPARAM_DEFAULT_UPDATE_PERIOD(dparam); + } + GST_DEBUG(GST_CAT_PARAMS, "last:%lld current:%lld next:%lld\n", + GST_DPARAM_LAST_UPDATE_TIMESTAMP(dparam), timestamp, GST_DPARAM_NEXT_UPDATE_TIMESTAMP(dparam)); + + + switch (G_VALUE_TYPE(GST_DPARAM_VALUE(dparam))){ + case G_TYPE_FLOAT: { + gfloat current, target, max_change, current_diff, final_val; + + target = g_value_get_float(dparam->point[0]); + current = g_value_get_float(GST_DPARAM_VALUE(dparam)); + max_change = time_ratio * g_value_get_float(dparam->point[1]); + + GST_DEBUG(GST_CAT_PARAMS, "target:%f current:%f max_change:%f \n", + target, current, max_change); + + if (dparam->spec->is_log){ + gfloat current_log; + current_log = log(current); + current_diff = ABS(current_log - log(target)); + if (current_diff > max_change) + final_val = (target < current) ? exp(current_log-max_change) : exp(current_log+max_change); + else + final_val = target; + } + else { + current_diff = ABS (current - target); + if (current_diff > max_change) + final_val = (target < current) ? current-max_change : current+max_change; + else + final_val = target; + } + + GST_DPARAM_READY_FOR_UPDATE(dparam) = (current_diff > max_change); + g_value_set_float(GST_DPARAM_VALUE(dparam), final_val); + + break; + } + default: + break; + } + + + //GST_DEBUG(GST_CAT_PARAMS, "smooth update for %s(%p): %f\n", + // GST_DPARAM_NAME (dparam),dparam, g_value_get_float(GST_DPARAM_VALUE(dparam))); + + GST_DPARAM_UNLOCK(dparam); +} + +static GValue** +gst_dparam_get_point_smooth (GstDParam *dparam, gint64 timestamp) +{ + GST_DEBUG(GST_CAT_PARAMS, "getting point for %s(%p)\n",GST_DPARAM_NAME (dparam),dparam); + return dparam->point; +} diff --git a/libs/gst/control/dparam.h b/libs/gst/control/dparam.h new file mode 100644 index 0000000000..44c57f9bfe --- /dev/null +++ b/libs/gst/control/dparam.h @@ -0,0 +1,147 @@ +/* GStreamer + * Copyright (C) 2001 Steve Baker + * + * gstdparam.h: Dynamic Parameter functionality + * + * 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_DPARAM_H__ +#define __GST_DPARAM_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define GST_TYPE_DPARAM (gst_dparam_get_type ()) +#define GST_DPARAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DPARAM,GstDParam)) +#define GST_DPARAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DPARAM,GstDParam)) +#define GST_IS_DPARAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DPARAM)) +#define GST_IS_DPARAM_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DPARAM)) + +#define GST_DPARAM_NAME(dparam) (GST_OBJECT_NAME(dparam)) +#define GST_DPARAM_PARENT(dparam) (GST_OBJECT_PARENT(dparam)) +#define GST_DPARAM_VALUE(dparam) ((dparam)->value) +#define GST_DPARAM_SPEC(dparam) ((dparam)->spec) +#define GST_DPARAM_MANAGER(dparam) ((dparam)->manager) +#define GST_DPARAM_TYPE(dparam) ((dparam)->type) + +#define GST_DPARAM_LOCK(dparam) (g_mutex_lock((dparam)->lock)) +#define GST_DPARAM_UNLOCK(dparam) (g_mutex_unlock((dparam)->lock)) + +#define GST_DPARAM_READY_FOR_UPDATE(dparam) ((dparam)->ready_for_update) +#define GST_DPARAM_DEFAULT_UPDATE_PERIOD(dparam) ((dparam)->default_update_period) +#define GST_DPARAM_NEXT_UPDATE_TIMESTAMP(dparam) ((dparam)->next_update_timestamp) +#define GST_DPARAM_LAST_UPDATE_TIMESTAMP(dparam) ((dparam)->last_update_timestamp) + +#define GST_DPARAM_GET_POINT(dparam, timestamp) \ + ((dparam->get_point_func)(dparam, timestamp)) + +#define GST_DPARAM_FIND_POINT(dparam, timestamp, search_flag) \ + ((dparam->find_point_func)(dparam, data, search_flag)) + +#define GST_DPARAM_DO_UPDATE(dparam, timestamp) \ + ((dparam->do_update_func)(dparam, timestamp)) + +#define GST_DPARAM_INSERT_POINT(dparam, timestamp) \ + ((dparam->insert_point_func)(dparam, timestamp)) + +#define GST_DPARAM_REMOVE_POINT(dparam, data) \ + ((dparam->remove_point_func)(dparam, data)) + +typedef enum { + GST_DPARAM_CLOSEST, + GST_DPARAM_CLOSEST_AFTER, + GST_DPARAM_CLOSEST_BEFORE, + GST_DPARAM_EXACT, +} GstDParamSearchFlag; + +typedef enum { + GST_DPARAM_NOT_FOUND = 0, + GST_DPARAM_FOUND_EXACT, + GST_DPARAM_FOUND_CLOSEST, +} GstDParamSearchResult; + +typedef struct _GstDParamClass GstDParamClass; + +typedef GValue** (*GstDParamInsertPointFunction) (GstDParam *dparam, guint64 timestamp); +typedef void (*GstDParamRemovePointFunction) (GstDParam *dparam, GValue** point); +typedef GValue** (*GstDParamGetPointFunction) (GstDParam *dparam, gint64 timestamp); +typedef GstDParamSearchResult (*GstDParamFindPointFunction) (GstDParam *dparam, gint64 *timestamp, GstDParamSearchFlag search_flag); + +typedef void (*GstDParamDoUpdateFunction) (GstDParam *dparam, gint64 timestamp); + +struct _GstDParam { + GstObject object; + + GstDParamGetPointFunction get_point_func; + GstDParamFindPointFunction find_point_func; + + GstDParamDoUpdateFunction do_update_func; + + GstDParamInsertPointFunction insert_point_func; + GstDParamRemovePointFunction remove_point_func; + + GMutex *lock; + GValue *value; + GstDParamManager *manager; + GstDParamSpec *spec; + GValue **point; + GType type; + gint64 last_update_timestamp; + gint64 next_update_timestamp; + gint64 default_update_period; + gboolean ready_for_update; +}; + +struct _GstDParamClass { + GstObjectClass parent_class; + + /* signal callbacks */ +}; + +struct _GstDParamSpec { + gchar *dparam_name; + gchar *unit_name; + GValue *min_val; + GValue *max_val; + GValue *default_val; + gboolean is_log; + gboolean is_rate; +}; + +GType gst_dparam_get_type (void); +GstDParam* gst_dparam_new (GType type); +void gst_dparam_attach (GstDParam *dparam, GstDParamManager *manager, GValue *value, GstDParamSpec *spec); +void gst_dparam_detach (GstDParam *dparam); +GValue** gst_dparam_new_value_array(GType type, ...); +void gst_dparam_set_value_from_string(GValue *value, const gchar *value_str); + +/********************** + * GstDParamSmooth + **********************/ + +GstDParam* gst_dparam_smooth_new (GType type); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GST_DPARAM_H__ */ diff --git a/libs/gst/control/dparamcommon.h b/libs/gst/control/dparamcommon.h new file mode 100644 index 0000000000..96c388bf6d --- /dev/null +++ b/libs/gst/control/dparamcommon.h @@ -0,0 +1,37 @@ +/* GStreamer + * Copyright (C) 2001 Steve Baker + * + * gstdparamcommon.h: Dynamic Parameter common header + * + * 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_DPCOMMON_H__ +#define __GST_DPCOMMON_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _GstDParam GstDParam; +typedef struct _GstDParamSpec GstDParamSpec; +typedef struct _GstDParamManager GstDParamManager; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GST_DPCOMMON_H__ */ diff --git a/libs/gst/control/dparammanager.c b/libs/gst/control/dparammanager.c new file mode 100644 index 0000000000..3436681c0a --- /dev/null +++ b/libs/gst/control/dparammanager.c @@ -0,0 +1,782 @@ +/* GStreamer + * Copyright (C) 2001 Steve Baker + * + * gstdparammanager.c: Dynamic Parameter group functionality + * + * 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 + +static GHashTable *_element_registry; + +static void gst_dpman_class_init (GstDParamManagerClass *klass); +static void gst_dpman_init (GstDParamManager *dpman); +static void gst_dpman_dispose (GObject *object); +static GstDParamWrapper* gst_dpman_new_wrapper(GstDParamManager *dpman, gchar *dparam_name, GType type, GstDPMUpdateMethod update_method); +static GstDParamWrapper* gst_dpman_get_wrapper(GstDParamManager *dpman, gchar *dparam_name); +static void gst_dpman_state_change (GstElement *element, gint state, GstDParamManager *dpman); +static void gst_dpman_caps_changed (GstPad *pad, GstCaps *caps, GstDParamManager *dpman); +static guint gst_dpman_preprocess_synchronous(GstDParamManager *dpman, guint frames, gint64 timestamp); +static guint gst_dpman_preprocess_noop(GstDParamManager *dpman, guint frames, gint64 timestamp); +static guint gst_dpman_process_noop(GstDParamManager *dpman, guint frame_count); + +static GObjectClass *parent_class; + +void +_gst_dpman_initialize() +{ +} + +GType +gst_dpman_get_type (void) +{ + static GType dpman_type = 0; + + if (!dpman_type) { + static const GTypeInfo dpman_info = { + sizeof(GstDParamManagerClass), + NULL, + NULL, + (GClassInitFunc)gst_dpman_class_init, + NULL, + NULL, + sizeof(GstDParamManager), + 0, + (GInstanceInitFunc)gst_dpman_init, + }; + dpman_type = g_type_register_static(GST_TYPE_OBJECT, "GstDParamManager", &dpman_info, 0); + } + return dpman_type; +} + +static void +gst_dpman_class_init (GstDParamManagerClass *klass) +{ + GstObjectClass *gstobject_class; + GObjectClass *gobject_class; + + parent_class = g_type_class_peek_parent (klass); + + gstobject_class = (GstObjectClass*) klass; + gobject_class = (GObjectClass*) klass; + gobject_class->dispose = gst_dpman_dispose; + + klass->modes = g_hash_table_new(g_str_hash,g_str_equal); + + gst_dpman_register_mode (klass, "synchronous", + gst_dpman_preprocess_synchronous, gst_dpman_process_noop, NULL, NULL); + gst_dpman_register_mode (klass, "asynchronous", + gst_dpman_preprocess_noop, gst_dpman_process_noop, NULL, NULL); + gst_dpman_register_mode (klass, "disabled", + gst_dpman_preprocess_noop, gst_dpman_process_noop, NULL, NULL); + + _element_registry = g_hash_table_new(NULL,NULL); +} + +static void +gst_dpman_init (GstDParamManager *dpman) +{ + GST_DPMAN_DPARAMS(dpman) = g_hash_table_new(g_str_hash,g_str_equal); + GST_DPMAN_DPARAMS_LIST(dpman) = NULL; + GST_DPMAN_NAME(dpman) = NULL; + GST_DPMAN_PARENT(dpman) = NULL; + GST_DPMAN_MODE_NAME(dpman) = NULL; + GST_DPMAN_MODE(dpman) = NULL; + GST_DPMAN_MODE_DATA(dpman) = NULL; + GST_DPMAN_RATE(dpman) = 0; +} + +/** + * gst_dpman_new: + * @name: name of the GstDParamManager instance + * @parent: element which created this instance + * + * Returns: a new instance of GstDParamManager + */ +GstDParamManager* +gst_dpman_new (gchar *name, GstElement *parent) +{ + GstDParamManager *dpman; + + g_return_val_if_fail (name != NULL, NULL); + + dpman = g_object_new (gst_dpman_get_type (), NULL); + gst_object_set_name (GST_OBJECT (dpman), name); + gst_dpman_set_parent(dpman, parent); + + gst_dpman_set_mode(dpman, "disabled"); + + return dpman; +} + + +static void +gst_dpman_dispose (GObject *object) +{ +/* GstDParamManager *dpman = GST_DPMAN(object); */ + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +/** + * gst_dpman_add_required_dparam_callback: + * @dpman: GstDParamManager instance + * @dparam_name: a parameter name unique to this GstDParamManager + * @type: the GValue type that this parameter will store + * @update_func: callback to update the element with the new value + * @update_data: will be included in the call to update_func + * + * Returns: true if it was successfully added + */ +gboolean +gst_dpman_add_required_dparam_callback (GstDParamManager *dpman, + gchar *dparam_name, + GType type, + GstDPMUpdateFunction update_func, + gpointer update_data) +{ + GstDParamWrapper* dpwrap; + + g_return_val_if_fail (dpman != NULL, FALSE); + g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE); + g_return_val_if_fail (update_func != NULL, FALSE); + + dpwrap = gst_dpman_new_wrapper(dpman, dparam_name, type, GST_DPMAN_CALLBACK); + + g_return_val_if_fail (dpwrap != NULL, FALSE); + + GST_DEBUG(GST_CAT_PARAMS,"adding required callback dparam '%s' of type %s\n", dparam_name, g_type_name(type)); + + dpwrap->update_func = update_func; + dpwrap->update_data = update_data; + + return TRUE; +} + +/** + * gst_dpman_add_required_dparam_direct: + * @dpman: GstDParamManager instance + * @dparam_name: a parameter name unique to this GstDParamManager + * @type: the GValue type that this parameter will store + * @update_data: pointer to the member to be updated + * + * Returns: true if it was successfully added + */ +gboolean +gst_dpman_add_required_dparam_direct (GstDParamManager *dpman, + gchar *dparam_name, + GType type, + gpointer update_data) +{ + GstDParamWrapper* dpwrap; + + g_return_val_if_fail (dpman != NULL, FALSE); + g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE); + g_return_val_if_fail (update_data != NULL, FALSE); + + dpwrap = gst_dpman_new_wrapper(dpman, dparam_name, type, GST_DPMAN_DIRECT); + + g_return_val_if_fail (dpwrap != NULL, FALSE); + + GST_DEBUG(GST_CAT_PARAMS,"adding required direct dparam '%s' of type %s\n", dparam_name, g_type_name(type)); + + dpwrap->update_data = update_data; + + return TRUE; +} + +/** + * gst_dpman_add_required_dparam_array: + * @dpman: GstDParamManager instance + * @dparam_name: a parameter name unique to this GstDParamManager + * @type: the GValue type that this parameter will store + * @update_data: pointer to where the array will be stored + * + * Returns: true if it was successfully added + */ +gboolean +gst_dpman_add_required_dparam_array (GstDParamManager *dpman, + gchar *dparam_name, + GType type, + gpointer update_data) +{ + GstDParamWrapper* dpwrap; + + g_return_val_if_fail (dpman != NULL, FALSE); + g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE); + g_return_val_if_fail (update_data != NULL, FALSE); + + dpwrap = gst_dpman_new_wrapper(dpman, dparam_name, type, GST_DPMAN_ARRAY); + + g_return_val_if_fail (dpwrap != NULL, FALSE); + + GST_DEBUG(GST_CAT_PARAMS,"adding required array dparam '%s' of type %s\n", dparam_name, g_type_name(type)); + + dpwrap->update_data = update_data; + + return TRUE; +} + +/** + * gst_dpman_remove_required_dparam: + * @dpman: GstDParamManager instance + * @dparam_name: the name of an existing parameter + * + */ +void +gst_dpman_remove_required_dparam (GstDParamManager *dpman, gchar *dparam_name) +{ + GstDParamWrapper* dpwrap; + + g_return_if_fail (dpman != NULL); + g_return_if_fail (GST_IS_DPMAN (dpman)); + g_return_if_fail (dparam_name != NULL); + + dpwrap = gst_dpman_get_wrapper(dpman, dparam_name); + + g_return_if_fail(dpwrap != NULL); + g_return_if_fail(dpwrap->dparam == NULL); + + GST_DEBUG(GST_CAT_PARAMS, "removing required dparam: %s\n", dparam_name); + + g_hash_table_remove(GST_DPMAN_DPARAMS(dpman), dparam_name); + GST_DPMAN_DPARAMS_LIST(dpman) = g_slist_remove(GST_DPMAN_DPARAMS_LIST(dpman), dpwrap); + + g_free(dpwrap->value); + g_free(dpwrap); +} + +/** + * gst_dpman_attach_dparam: + * @dpman: GstDParamManager instance + * @dparam_name: a name previously added with gst_dpman_add_required_dparam + * @dparam: GstDParam instance to attach + * + * Returns: true if it was successfully attached + */ +gboolean +gst_dpman_attach_dparam (GstDParamManager *dpman, gchar *dparam_name, GstDParam *dparam) +{ + GstDParamWrapper* dpwrap; + + g_return_val_if_fail (dpman != NULL, FALSE); + g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE); + g_return_val_if_fail (dparam_name != NULL, FALSE); + g_return_val_if_fail (dparam != NULL, FALSE); + g_return_val_if_fail (GST_IS_DPARAM (dparam), FALSE); + g_return_val_if_fail (dparam != NULL, FALSE); + + dpwrap = gst_dpman_get_wrapper(dpman, dparam_name); + + g_return_val_if_fail(dpwrap != NULL, FALSE); + g_return_val_if_fail(dpwrap->value != NULL, FALSE); + + dpwrap->dparam = dparam; + gst_dparam_attach(dparam, dpman, dpwrap->value, dpwrap->spec); + + return TRUE; +} + +/** + * gst_dpman_detach_dparam: + * @dpman: GstDParamManager instance + * @dparam_name: the name of a parameter with a previously attached GstDParam + * + */ +void +gst_dpman_detach_dparam (GstDParamManager *dpman, gchar *dparam_name) +{ + GstDParamWrapper* dpwrap; + + g_return_if_fail (dpman != NULL); + g_return_if_fail (GST_IS_DPMAN (dpman)); + g_return_if_fail (dparam_name != NULL); + + dpwrap = gst_dpman_get_wrapper(dpman, dparam_name); + + g_return_if_fail(dpwrap); + + gst_dparam_detach(dpwrap->dparam); + dpwrap->dparam = NULL; + +} + +/** + * gst_dpman_get_dparam: + * @dpman: GstDParamManager instance + * @name: the name of an existing dparam instance + * + * Returns: the dparam with the given name - or NULL otherwise + */ +GstDParam * +gst_dpman_get_dparam (GstDParamManager *dpman, gchar *name) +{ + GstDParamWrapper* dpwrap; + + g_return_val_if_fail (dpman != NULL, NULL); + g_return_val_if_fail (GST_IS_DPMAN (dpman), NULL); + g_return_val_if_fail (name != NULL, NULL); + + dpwrap = g_hash_table_lookup(GST_DPMAN_DPARAMS(dpman), name); + g_return_val_if_fail (dpwrap != NULL, NULL); + + return dpwrap->dparam; +} + +/** + * gst_dpman_get_dparam_type: + * @dpman: GstDParamManager instance + * @name: the name of dparam + * + * Returns: the type that this dparam requires/uses + */ +GType +gst_dpman_get_dparam_type (GstDParamManager *dpman, gchar *name) +{ + GstDParamWrapper* dpwrap; + + g_return_val_if_fail (dpman != NULL, 0); + g_return_val_if_fail (GST_IS_DPMAN (dpman), 0); + g_return_val_if_fail (name != NULL, 0); + + dpwrap = g_hash_table_lookup(GST_DPMAN_DPARAMS(dpman), name); + g_return_val_if_fail (dpwrap != NULL, 0); + + return G_VALUE_TYPE(dpwrap->value); +} + +GstDParamSpec** +gst_dpman_list_dparam_specs(GstDParamManager *dpman) +{ + GstDParamWrapper* dpwrap; + GSList *dpwraps; + GstDParamSpec** dparam_specs; + guint x = 0; + + g_return_val_if_fail (dpman != NULL, NULL); + g_return_val_if_fail (GST_IS_DPMAN (dpman), NULL); + + dpwraps = GST_DPMAN_DPARAMS_LIST(dpman); + + dparam_specs = g_new0(GstDParamSpec*, g_slist_length(dpwraps) + 1); + + while (dpwraps){ + dpwrap = (GstDParamWrapper*)dpwraps->data; + dparam_specs[x++] = dpwrap->spec; + dpwraps = g_slist_next(dpwraps); + } + return dparam_specs; +} + +GstDParamSpec* +gst_dpman_get_dparam_spec (GstDParamManager *dpman, gchar *dparam_name) +{ + GstDParamWrapper* dpwrap; + + g_return_val_if_fail (dpman != NULL, NULL); + g_return_val_if_fail (GST_IS_DPMAN (dpman), NULL); + g_return_val_if_fail (dparam_name != NULL, NULL); + + dpwrap = gst_dpman_get_wrapper(dpman, dparam_name); + return dpwrap->spec; +} + +void +gst_dpman_dparam_spec_has_changed (GstDParamManager *dpman, gchar *dparam_name) +{ + +} + +/** + * gst_dpman_register_mode + * @klass: GstDParamManagerClass class instance + * @modename: the unique name of the new mode + * @preprocessfunc: the function which will be called before each buffer is processed + * @processfunc: the function which may be called throughout the processing of a buffer + * @setupfunc: the function which initialises the mode when activated + * @teardownfunc: the function which frees any resources the mode uses + * + */ +void +gst_dpman_register_mode (GstDParamManagerClass *klass, + gchar *modename, + GstDPMModePreProcessFunction preprocessfunc, + GstDPMModeProcessFunction processfunc, + GstDPMModeSetupFunction setupfunc, + GstDPMModeTeardownFunction teardownfunc) +{ + GstDPMMode *mode; + + g_return_if_fail (klass != NULL); + g_return_if_fail (modename != NULL); + g_return_if_fail (GST_IS_DPMAN_CLASS (klass)); + + mode = g_new0(GstDPMMode,1); + + mode->preprocessfunc = preprocessfunc; + mode->processfunc = processfunc; + mode->setupfunc = setupfunc; + mode->teardownfunc = teardownfunc; + + g_hash_table_insert(klass->modes, modename, mode); + GST_DEBUG(GST_CAT_PARAMS, "mode '%s' registered\n", modename); +} + +/** + * gst_dpman_set_mode + * @dpman: GstDParamManager instance + * @modename: the name of the mode to use + * + * Returns: TRUE if the mode was set, FALSE otherwise + */ +gboolean +gst_dpman_set_mode(GstDParamManager *dpman, gchar *modename) +{ + GstDPMMode *mode=NULL; + GstDParamManagerClass *oclass; + + g_return_val_if_fail (dpman != NULL, FALSE); + g_return_val_if_fail (GST_IS_DPMAN (dpman), FALSE); + g_return_val_if_fail (modename != NULL, FALSE); + + oclass = (GstDParamManagerClass*)(G_OBJECT_GET_CLASS(dpman)); + + mode = g_hash_table_lookup(oclass->modes, modename); + g_return_val_if_fail (mode != NULL, FALSE); + + if (GST_DPMAN_MODE(dpman) == mode) { + GST_DEBUG(GST_CAT_PARAMS, "mode %s already set\n", modename); + return TRUE; + } + + GST_DEBUG(GST_CAT_PARAMS, "setting mode to %s\n", modename); + if (GST_DPMAN_MODE(dpman) && GST_DPMAN_TEARDOWNFUNC(dpman)){ + GST_DPMAN_TEARDOWNFUNC(dpman)(dpman); + } + + GST_DPMAN_MODE(dpman) = mode; + + if (GST_DPMAN_SETUPFUNC(dpman)){ + GST_DPMAN_SETUPFUNC(dpman)(dpman); + } + + return TRUE; +} + +/** + * gst_dpman_set_parent + * @dpman: GstDParamManager instance + * @parent: the element that this GstDParamManager belongs to + * + */ +void +gst_dpman_set_parent (GstDParamManager *dpman, GstElement *parent) +{ + g_return_if_fail (dpman != NULL); + g_return_if_fail (GST_IS_DPMAN (dpman)); + g_return_if_fail (parent != NULL); + g_return_if_fail (GST_IS_ELEMENT (parent)); + + g_hash_table_insert(_element_registry, parent, dpman); + gst_object_set_parent (GST_OBJECT (dpman), GST_OBJECT(parent)); + g_signal_connect(G_OBJECT(parent), "state_change", + G_CALLBACK (gst_dpman_state_change), dpman); +} + +/** + * gst_dpman_get_manager + * @parent: the element that the desired GstDParamManager belongs to + * + * Returns: the GstDParamManager which belongs to this element or NULL + * if it doesn't exist + */ +GstDParamManager * +gst_dpman_get_manager (GstElement *parent) +{ + GstDParamManager *dpman; + g_return_val_if_fail (parent != NULL, NULL); + g_return_val_if_fail (GST_IS_ELEMENT (parent), NULL); + + dpman = (GstDParamManager*)g_hash_table_lookup(_element_registry, parent); + return dpman; +} + +/** + * gst_dpman_set_rate_change_pad + * @dpman: GstDParamManager instance + * @pad: the pad which may have a "rate" caps property + * + */ +void +gst_dpman_set_rate_change_pad(GstDParamManager *dpman, GstPad *pad) +{ + g_return_if_fail (dpman != NULL); + g_return_if_fail (GST_IS_DPMAN (dpman)); + g_return_if_fail (pad != NULL); + g_return_if_fail (GST_IS_PAD (pad)); + + g_signal_connect(G_OBJECT(pad), "caps_changed", + G_CALLBACK (gst_dpman_caps_changed), dpman); +} + +static GstDParamWrapper* +gst_dpman_get_wrapper(GstDParamManager *dpman, gchar *dparam_name) +{ + g_return_val_if_fail (dpman != NULL, NULL); + g_return_val_if_fail (GST_IS_DPMAN (dpman), NULL); + g_return_val_if_fail (dparam_name != NULL, NULL); + + return g_hash_table_lookup(GST_DPMAN_DPARAMS(dpman), dparam_name); +} + +static GstDParamWrapper* +gst_dpman_new_wrapper(GstDParamManager *dpman, gchar *dparam_name, GType type, GstDPMUpdateMethod update_method) +{ + GstDParamWrapper* dpwrap; + + g_return_val_if_fail (dpman != NULL, NULL); + g_return_val_if_fail (GST_IS_DPMAN (dpman), NULL); + g_return_val_if_fail (dparam_name != NULL, NULL); + + g_return_val_if_fail(gst_dpman_get_wrapper(dpman, dparam_name) == NULL, NULL); + + dpwrap = g_new0(GstDParamWrapper,1); + dpwrap->update_method = update_method; + dpwrap->value = g_new0(GValue,1); + g_value_init(dpwrap->value, type); + + dpwrap->spec = g_new0(GstDParamSpec,1); + dpwrap->spec->dparam_name = dparam_name; + dpwrap->spec->min_val = g_new0(GValue,1); + dpwrap->spec->max_val = g_new0(GValue,1); + dpwrap->spec->default_val = g_new0(GValue,1); + g_value_init(dpwrap->spec->min_val, type); + g_value_init(dpwrap->spec->max_val, type); + g_value_init(dpwrap->spec->default_val, type); + + g_hash_table_insert(GST_DPMAN_DPARAMS(dpman), dparam_name, dpwrap); + GST_DPMAN_DPARAMS_LIST(dpman) = g_slist_append(GST_DPMAN_DPARAMS_LIST(dpman), dpwrap); + + return dpwrap; +} + + +static void +gst_dpman_state_change (GstElement *element, gint state, GstDParamManager *dpman) +{ + GSList *dwraps; + GstDParam *dparam; + GstDParamWrapper *dpwrap; + + g_return_if_fail (dpman != NULL); + g_return_if_fail (GST_IS_DPMAN (dpman)); + + if (state == GST_STATE_PLAYING){ + GST_DEBUG(GST_CAT_PARAMS, "initialising params\n"); + + // force all params to be updated + dwraps = GST_DPMAN_DPARAMS_LIST(dpman); + while (dwraps){ + dpwrap = (GstDParamWrapper*)dwraps->data; + dparam = dpwrap->dparam; + + if (dparam){ + GST_DPARAM_READY_FOR_UPDATE(dparam) = TRUE; + if (dparam->spec){ + g_value_copy(dparam->spec->default_val, GST_DPARAM_VALUE(dparam)); + } + } + dwraps = g_slist_next(dwraps); + } + } +} + +static void +gst_dpman_caps_changed (GstPad *pad, GstCaps *caps, GstDParamManager *dpman) +{ + g_return_if_fail (caps != NULL); + g_return_if_fail (dpman != NULL); + g_return_if_fail (GST_IS_DPMAN (dpman)); + + GST_DPMAN_RATE(dpman) = gst_caps_get_int (caps, "rate"); + + GST_DEBUG(GST_CAT_PARAMS, "got caps change %d\n", GST_DPMAN_RATE(dpman)); +} + +static guint +gst_dpman_preprocess_synchronous(GstDParamManager *dpman, guint frames, gint64 timestamp) +{ + GSList *dwraps; + GstDParam *dparam; + GstDParamWrapper *dpwrap; + guint x; + + g_return_val_if_fail (dpman != NULL, frames); + g_return_val_if_fail (GST_IS_DPMAN (dpman), frames); + + // now check whether any passive dparams are ready for an update + dwraps = GST_DPMAN_DPARAMS_LIST(dpman); + while (dwraps){ + dpwrap = (GstDParamWrapper*)dwraps->data; + dparam = dpwrap->dparam; + + if (dparam && (GST_DPARAM_READY_FOR_UPDATE(dparam) && + (GST_DPARAM_NEXT_UPDATE_TIMESTAMP(dparam) <= timestamp))){ + + // this will make dpwrap->value contain the latest value. + // now we just need to get it to the element + GST_DPARAM_DO_UPDATE(dparam, timestamp); + + switch (dpwrap->update_method) { + + // direct method - set the value directly in the struct of the element + case GST_DPMAN_DIRECT: + GST_DEBUG(GST_CAT_PARAMS, "doing direct update\n"); + switch (G_VALUE_TYPE(dpwrap->value)){ + case G_TYPE_CHAR: + *(gchar*)dpwrap->update_data = g_value_get_char(dpwrap->value); + break; + case G_TYPE_UCHAR: + *(guchar*)dpwrap->update_data = g_value_get_uchar(dpwrap->value); + break; + case G_TYPE_BOOLEAN: + *(gboolean*)dpwrap->update_data = g_value_get_boolean(dpwrap->value); + break; + case G_TYPE_INT: + *(gint*)dpwrap->update_data = g_value_get_int(dpwrap->value); + break; + case G_TYPE_UINT: + *(guint*)dpwrap->update_data = g_value_get_uint(dpwrap->value); + break; + case G_TYPE_LONG: + *(glong*)dpwrap->update_data = g_value_get_long(dpwrap->value); + break; + case G_TYPE_ULONG: + *(gulong*)dpwrap->update_data = g_value_get_ulong(dpwrap->value); + break; + case G_TYPE_FLOAT: + *(gfloat*)dpwrap->update_data = g_value_get_float(dpwrap->value); + break; + case G_TYPE_DOUBLE: + *(gdouble*)dpwrap->update_data = g_value_get_double(dpwrap->value); + break; + case G_TYPE_POINTER: + *(gpointer*)dpwrap->update_data = g_value_get_pointer(dpwrap->value); + break; + default: + break; + } + break; + + // callback method - call the element's callback so it can do what it likes + case GST_DPMAN_CALLBACK: + GST_DEBUG(GST_CAT_PARAMS, "doing callback update\n"); + GST_DPMAN_DO_UPDATE(dpwrap); + break; + + // array method - generate an array of the right size + // with each value being the same (in synchronous update mode) + case GST_DPMAN_ARRAY: + GST_DEBUG(GST_CAT_PARAMS, "doing array update\n"); + switch (G_VALUE_TYPE(dpwrap->value)){ + case G_TYPE_CHAR: + (gchar*)dpwrap->update_data = g_new(gchar, frames); + *(gchar*)dpwrap->update_data = g_value_get_char(dpwrap->value); + for (x = 1 ; x < frames ; x++) + ((gchar*)dpwrap->update_data)[x] = *(gchar*)dpwrap->update_data; + break; + case G_TYPE_UCHAR: + (guchar*)dpwrap->update_data = g_new(guchar, frames); + *(guchar*)dpwrap->update_data = g_value_get_uchar(dpwrap->value); + for (x = 1 ; x < frames ; x++) + ((guchar*)dpwrap->update_data)[x] = *(guchar*)dpwrap->update_data; + break; + case G_TYPE_BOOLEAN: + (gboolean*)dpwrap->update_data = g_new(gboolean, frames); + *(gboolean*)dpwrap->update_data = g_value_get_boolean(dpwrap->value); + for (x = 1 ; x < frames ; x++) + ((gboolean*)dpwrap->update_data)[x] = *(gboolean*)dpwrap->update_data; + break; + case G_TYPE_INT: + (gint*)dpwrap->update_data = g_new(gint, frames); + *(gint*)dpwrap->update_data = g_value_get_int(dpwrap->value); + for (x = 1 ; x < frames ; x++) + ((gint*)dpwrap->update_data)[x] = *(gint*)dpwrap->update_data; + break; + case G_TYPE_UINT: + (guint*)dpwrap->update_data = g_new(guint, frames); + *(guint*)dpwrap->update_data = g_value_get_uint(dpwrap->value); + for (x = 1 ; x < frames ; x++) + ((guint*)dpwrap->update_data)[x] = *(guint*)dpwrap->update_data; + break; + case G_TYPE_LONG: + (glong*)dpwrap->update_data = g_new(glong, frames); + *(glong*)dpwrap->update_data = g_value_get_long(dpwrap->value); + for (x = 1 ; x < frames ; x++) + ((glong*)dpwrap->update_data)[x] = *(glong*)dpwrap->update_data; + break; + case G_TYPE_ULONG: + (gulong*)dpwrap->update_data = g_new(gulong, frames); + *(gulong*)dpwrap->update_data = g_value_get_ulong(dpwrap->value); + for (x = 1 ; x < frames ; x++) + ((gulong*)dpwrap->update_data)[x] = *(gulong*)dpwrap->update_data; + break; + case G_TYPE_FLOAT: + (gfloat*)dpwrap->update_data = g_new(gfloat, frames); + *(gfloat*)dpwrap->update_data = g_value_get_float(dpwrap->value); + for (x = 1 ; x < frames ; x++) + ((gfloat*)dpwrap->update_data)[x] = *(gfloat*)dpwrap->update_data; + break; + case G_TYPE_DOUBLE: + (gdouble*)dpwrap->update_data = g_new(gdouble, frames); + *(gdouble*)dpwrap->update_data = g_value_get_double(dpwrap->value); + for (x = 1 ; x < frames ; x++) + ((gdouble*)dpwrap->update_data)[x] = *(gdouble*)dpwrap->update_data; + break; + case G_TYPE_POINTER: + (gpointer*)dpwrap->update_data = g_new(gpointer, frames); + *(gpointer*)dpwrap->update_data = g_value_get_pointer(dpwrap->value); + for (x = 1 ; x < frames ; x++) + ((gpointer*)dpwrap->update_data)[x] = *(gpointer*)dpwrap->update_data; + break; + default: + break; + } + break; + default: + break; + } + } + dwraps = g_slist_next(dwraps); + } + return frames; +} + +static guint +gst_dpman_preprocess_noop(GstDParamManager *dpman, guint frames, gint64 timestamp) +{ + return frames; +} + +static guint +gst_dpman_process_noop(GstDParamManager *dpman, guint frame_count) +{ + return 0; +} + diff --git a/libs/gst/control/dparammanager.h b/libs/gst/control/dparammanager.h new file mode 100644 index 0000000000..965c58a5dc --- /dev/null +++ b/libs/gst/control/dparammanager.h @@ -0,0 +1,164 @@ +/* GStreamer + * Copyright (C) 2001 Steve Baker + * + * gstdparammanager.h: Dynamic Parameter group functionality + * + * 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_DPMAN_H__ +#define __GST_DPMAN_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define GST_TYPE_DPMAN (gst_dpman_get_type ()) +#define GST_DPMAN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DPMAN,GstDParamManager)) +#define GST_DPMAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DPMAN,GstDParamManager)) +#define GST_IS_DPMAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DPMAN)) +#define GST_IS_DPMAN_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DPMAN)) + +#define GST_DPMAN_NAME(dpman) (GST_OBJECT_NAME(dpman)) +#define GST_DPMAN_PARENT(dpman) (GST_OBJECT_PARENT(dpman)) +#define GST_DPMAN_DPARAMS(dpman) ((dpman)->dparams) +#define GST_DPMAN_DPARAMS_LIST(dpman) ((dpman)->dparams_list) + +#define GST_DPMAN_MODE_NAME(dpman) ((dpman)->mode_name) +#define GST_DPMAN_MODE(dpman) ((dpman)->mode) +#define GST_DPMAN_MODE_DATA(dpman) ((dpman)->mode_data) +#define GST_DPMAN_RATE(dpman) ((dpman)->rate) + +typedef enum { + GST_DPMAN_CALLBACK, + GST_DPMAN_DIRECT, + GST_DPMAN_ARRAY, +} GstDPMUpdateMethod; + +typedef struct _GstDParamManagerClass GstDParamManagerClass; +typedef struct _GstDPMMode GstDPMMode; +typedef struct _GstDParamWrapper GstDParamWrapper; + +typedef guint (*GstDPMModePreProcessFunction) (GstDParamManager *dpman, guint frames, gint64 timestamp); +typedef guint (*GstDPMModeProcessFunction) (GstDParamManager *dpman, guint frame_count); +typedef void (*GstDPMModeSetupFunction) (GstDParamManager *dpman); +typedef void (*GstDPMModeTeardownFunction) (GstDParamManager *dpman); + +typedef void (*GstDPMUpdateFunction) (GValue *value, gpointer data); + +struct _GstDParamManager { + GstObject object; + + GHashTable *dparams; + GSList *dparams_list; + + gchar *mode_name; + GstDPMMode* mode; + gpointer mode_data; + + gint64 timestamp; + guint rate; +}; + +struct _GstDParamManagerClass { + GstObjectClass parent_class; + + GHashTable *modes; + /* signal callbacks */ +}; + +struct _GstDPMMode { + GstDPMModePreProcessFunction preprocessfunc; + GstDPMModeProcessFunction processfunc; + GstDPMModeSetupFunction setupfunc; + GstDPMModeTeardownFunction teardownfunc; +}; + +struct _GstDParamWrapper { + GstDParamSpec* spec; + GValue *value; + GstDParam *dparam; + GstDPMUpdateMethod update_method; + gpointer update_data; + GstDPMUpdateFunction update_func; +}; + +#define GST_DPMAN_PREPROCESSFUNC(dpman) (((dpman)->mode)->preprocessfunc) +#define GST_DPMAN_PROCESSFUNC(dpman) (((dpman)->mode)->processfunc) +#define GST_DPMAN_SETUPFUNC(dpman) (((dpman)->mode)->setupfunc) +#define GST_DPMAN_TEARDOWNFUNC(dpman) (((dpman)->mode)->teardownfunc) + +#define GST_DPMAN_PREPROCESS(dpman, buffer_size, timestamp) \ + (GST_DPMAN_PREPROCESSFUNC(dpman)(dpman, buffer_size, timestamp)) + +#define GST_DPMAN_PROCESS(dpman, frame_count) \ + (GST_DPMAN_PROCESSFUNC(dpman)(dpman, frame_count)) + +#define GST_DPMAN_PROCESS_COUNTDOWN(dpman, frame_countdown, frame_count) \ + (frame_countdown-- || \ + (frame_countdown = GST_DPMAN_PROCESS(dpman, frame_count))) + +#define GST_DPMAN_DO_UPDATE(dpwrap) ((dpwrap->update_func)(dpwrap->value, dpwrap->update_data)) + +void _gst_dpman_initialize(); +GType gst_dpman_get_type (void); +GstDParamManager* gst_dpman_new (gchar *name, GstElement *parent); +void gst_dpman_set_parent (GstDParamManager *dpman, GstElement *parent); +GstDParamManager* gst_dpman_get_manager (GstElement *parent); + +gboolean gst_dpman_add_required_dparam_callback (GstDParamManager *dpman, + gchar *dparam_name, + GType type, + GstDPMUpdateFunction update_func, + gpointer update_data); +gboolean gst_dpman_add_required_dparam_direct (GstDParamManager *dpman, + gchar *dparam_name, + GType type, + gpointer update_data); +gboolean gst_dpman_add_required_dparam_array (GstDParamManager *dpman, + gchar *dparam_name, + GType type, + gpointer update_data); +void gst_dpman_remove_required_dparam (GstDParamManager *dpman, gchar *dparam_name); +gboolean gst_dpman_attach_dparam (GstDParamManager *dpman, gchar *dparam_name, GstDParam *dparam); +void gst_dpman_detach_dparam (GstDParamManager *dpman, gchar *dparam_name); +GstDParam* gst_dpman_get_dparam(GstDParamManager *dpman, gchar *name); +GType gst_dpman_get_dparam_type (GstDParamManager *dpman, gchar *name); + +GstDParamSpec** gst_dpman_list_dparam_specs(GstDParamManager *dpman); +GstDParamSpec* gst_dpman_get_dparam_spec (GstDParamManager *dpman, gchar *dparam_name); +void gst_dpman_dparam_spec_has_changed (GstDParamManager *dpman, gchar *dparam_name); + +void gst_dpman_set_rate_change_pad(GstDParamManager *dpman, GstPad *pad); + +gboolean gst_dpman_set_mode(GstDParamManager *dpman, gchar *modename); +void gst_dpman_register_mode (GstDParamManagerClass *klass, + gchar *modename, + GstDPMModePreProcessFunction preprocessfunc, + GstDPMModeProcessFunction processfunc, + GstDPMModeSetupFunction setupfunc, + GstDPMModeTeardownFunction teardownfunc); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GST_DPMAN_H__ */ diff --git a/libs/gst/control/dplinearinterp.c b/libs/gst/control/dplinearinterp.c new file mode 100644 index 0000000000..d595bebeed --- /dev/null +++ b/libs/gst/control/dplinearinterp.c @@ -0,0 +1,83 @@ +/* GStreamer + * Copyright (C) 2001 Steve Baker + * + * gstdplinearinterp.c: linear interpolation dynamic parameter + * + * 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 + +static void gst_dp_linint_class_init (GstDParamClass *klass); +static void gst_dp_linint_base_class_init (GstDParamClass *klass); +static void gst_dp_linint_init (GstDParam *dp_linint); + +GType +gst_dp_linint_get_type(void) { + static GType dp_linint_type = 0; + + if (!dp_linint_type) { + static const GTypeInfo dp_linint_info = { + sizeof(GstDParamClass), + (GBaseInitFunc)gst_dp_linint_base_class_init, + NULL, + (GClassInitFunc)gst_dp_linint_class_init, + NULL, + NULL, + sizeof(GstDParam), + 0, + (GInstanceInitFunc)gst_dp_linint_init, + }; + dp_linint_type = g_type_register_static(GST_TYPE_DPARAM, "GstDParamLinInterp", &dp_linint_info, 0); + } + return dp_linint_type; +} + +static void +gst_dp_linint_base_class_init (GstDParamClass *klass) +{ + +} + +static void +gst_dp_linint_class_init (GstDParamClass *klass) +{ + +} + +static void +gst_dp_linint_init (GstDParam *dp_linint) +{ + g_return_if_fail (dp_linint != NULL); +} + +/** + * gst_dp_linint_new: + * @type: the type that this dp_linint will store + * + * Returns: a new instance of GstDParam + */ +GstDParam* +gst_dp_linint_new (GType type) +{ + GstDParam *dparam; + GstDParamLinInterp *dp_linint; + + dp_linint = g_object_new (gst_dp_linint_get_type (), NULL); + dparam = GST_DPARAM(dp_linint); + + return dparam; +} diff --git a/libs/gst/control/dplinearinterp.h b/libs/gst/control/dplinearinterp.h new file mode 100644 index 0000000000..db50f826d8 --- /dev/null +++ b/libs/gst/control/dplinearinterp.h @@ -0,0 +1,61 @@ +/* GStreamer + * Copyright (C) 2001 Steve Baker + * + * gstdplinearinterp.h: linear interpolation dynamic parameter + * + * 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_DP_LININT_H__ +#define __GST_DP_LININT_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_DP_LININT (gst_dp_linint_get_type ()) +#define GST_DP_LININT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DP_LININT,GstDParamLinInterp)) +#define GST_DP_LININT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DP_LININT,GstDParamLinInterp)) +#define GST_IS_DP_LININT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DP_LININT)) +#define GST_IS_DP_LININT_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DP_LININT)) + +typedef struct _GstDParamLinInterp GstDParamLinInterp; +typedef struct _GstDParamLinInterpClass GstDParamLinInterpClass; + +struct _GstDParamLinInterp { + GstDParam dparam; + +}; + +struct _GstDParamLinInterpClass { + GstDParamClass parent_class; + + /* signal callbacks */ +}; + +GType gst_dp_linint_get_type (void); +GstDParam* gst_dp_linint_new (GType type); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GST_DP_LININT_H__ */