From 3a4d09d9e5f535634ba2503fbe1da45c39110ce0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 4 Mar 2005 10:16:10 +0000 Subject: More work on subclassing the sinks from the basesink. Original commit message from CVS: More work on subclassing the sinks from the basesink. First attempt at generic audiosink base objects. Make oss DMA audiosink. --- ChangeLog | 61 ++++++++ examples/seeking/seek.c | 2 +- gst-libs/gst/audio/Makefile.am | 6 +- gst-libs/gst/audio/gstbaseaudiosink.c | 235 ++++++++++++++++++++++++++++ gst-libs/gst/audio/gstbaseaudiosink.h | 87 +++++++++++ gst-libs/gst/audio/gstringbuffer.c | 282 ++++++++++++++++++++++++++++++++++ gst-libs/gst/audio/gstringbuffer.h | 114 ++++++++++++++ gst-libs/gst/video/Makefile.am | 2 +- gst-libs/gst/video/gstvideosink.c | 16 +- gst-libs/gst/video/videosink.h | 13 +- 10 files changed, 792 insertions(+), 26 deletions(-) create mode 100644 gst-libs/gst/audio/gstbaseaudiosink.c create mode 100644 gst-libs/gst/audio/gstbaseaudiosink.h create mode 100644 gst-libs/gst/audio/gstringbuffer.c create mode 100644 gst-libs/gst/audio/gstringbuffer.h diff --git a/ChangeLog b/ChangeLog index fd5501f1a..53dc38e95 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,64 @@ +2005-03-04 Wim Taymans + + * examples/seeking/seek.c: + * ext/theora/theoraenc.c: (theora_enc_sink_event), + (theora_enc_chain): + * ext/vorbis/vorbisenc.c: (gst_vorbisenc_sink_event), + (gst_vorbisenc_chain): + * gst-libs/gst/audio/Makefile.am: + * gst-libs/gst/audio/gstbaseaudiosink.c: + (gst_baseaudiosink_base_init), (gst_baseaudiosink_class_init), + (gst_baseaudiosink_init), (gst_baseaudiosink_set_property), + (gst_baseaudiosink_get_property), (gst_baseaudiosink_setcaps), + (gst_baseaudiosink_get_times), (gst_baseaudiosink_event), + (gst_baseaudiosink_preroll), (gst_baseaudiosink_render), + (gst_baseaudiosink_create_ringbuffer), + (gst_baseaudiosink_callback), (gst_baseaudiosink_change_state): + * gst-libs/gst/audio/gstbaseaudiosink.h: + * gst-libs/gst/audio/gstringbuffer.c: (gst_ringbuffer_get_type), + (gst_ringbuffer_class_init), (gst_ringbuffer_init), + (gst_ringbuffer_dispose), (gst_ringbuffer_finalize), + (gst_ringbuffer_set_callback), (gst_ringbuffer_acquire), + (gst_ringbuffer_release), (gst_ringbuffer_play), + (gst_ringbuffer_stop), (gst_ringbuffer_callback), + (gst_ringbuffer_write): + * gst-libs/gst/audio/gstringbuffer.h: + * gst-libs/gst/video/Makefile.am: + * gst-libs/gst/video/gstvideosink.c: (gst_videosink_init), + (gst_videosink_class_init), (gst_videosink_get_type): + * gst-libs/gst/video/videosink.h: + * sys/oss/Makefile.am: + * sys/oss/gstossdmabuffer.c: (gst_ossdmabuffer_get_type), + (gst_ossdmabuffer_class_init), (gst_ossdmabuffer_init), + (gst_ossdmabuffer_dispose), (gst_ossdmabuffer_finalize), + (gst_ossdmabuffer_func), (gst_ossdmabuffer_acquire), + (gst_ossdmabuffer_release), (gst_ossdmabuffer_play), + (gst_ossdmabuffer_stop): + * sys/oss/gstossdmabuffer.h: + * sys/oss/gstosselement.c: (gst_osselement_class_init), + (gst_osselement_parse_caps), (gst_osselement_sync_parms), + (gst_osselement_open_audio): + * sys/oss/gstosselement.h: + * sys/oss/gstosssink.c: (gst_osssink_get_type), + (gst_osssink_gettemplate), (gst_osssink_class_init), + (gst_osssink_init), (gst_osssink_getcaps), (gst_osssink_get_delay), + (gst_osssink_get_time), (gst_osssink_create_ringbuffer), + (gst_osssink_render), (gst_osssink_convert), + (gst_osssink_sink_query), (gst_osssink_query), + (gst_osssink_set_property), (gst_osssink_get_property), + (gst_osssink_change_state): + * sys/oss/gstosssink.h: + * sys/xvimage/xvimagesink.c: (gst_xvimagesink_getcaps), + (gst_xvimagesink_setcaps), (gst_xvimagesink_change_state), + (gst_xvimagesink_get_times), (gst_xvimagesink_show_frame), + (gst_xvimagesink_chain), (gst_xvimagesink_buffer_alloc), + (gst_xvimagesink_init), (gst_xvimagesink_get_template), + (gst_xvimagesink_class_init): + * sys/xvimage/xvimagesink.h: + More work on subclassing the sinks from the basesink. + First attempt at generic audiosink base objects. + Make oss DMA audiosink. + 2005-02-20 Ronald S. Bultje * gst/avi/gstavidemux.c: (gst_avi_demux_index_next), diff --git a/examples/seeking/seek.c b/examples/seeking/seek.c index 81ba7d8f4..ef73db6b8 100644 --- a/examples/seeking/seek.c +++ b/examples/seeking/seek.c @@ -27,7 +27,7 @@ static gulong changed_id; /* number of milliseconds to play for after a seek */ #define SCRUB_TIME 250 -#undef SCRUB +#define SCRUB #define THREAD #define PAD_SEEK diff --git a/gst-libs/gst/audio/Makefile.am b/gst-libs/gst/audio/Makefile.am index 99089947e..9bf04c2c2 100644 --- a/gst-libs/gst/audio/Makefile.am +++ b/gst-libs/gst/audio/Makefile.am @@ -17,7 +17,9 @@ CLEANFILES = gstaudiofilterexample.c \ $(BUILT_SOURCES) libgstaudio_la_SOURCES = audio.c audioclock.c \ - multichannel.c + multichannel.c \ + gstbaseaudiosink.c \ + gstringbuffer.c nodist_libgstaudio_la_SOURCES = $(built_sources) libgstaudioincludedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/audio @@ -25,6 +27,8 @@ libgstaudioinclude_HEADERS = \ audio.h \ audioclock.h \ gstaudiofilter.h \ + gstbaseaudiosink.h \ + gstringbuffer.h \ multichannel.h \ multichannel-enumtypes.h diff --git a/gst-libs/gst/audio/gstbaseaudiosink.c b/gst-libs/gst/audio/gstbaseaudiosink.c new file mode 100644 index 000000000..d27b4a222 --- /dev/null +++ b/gst-libs/gst/audio/gstbaseaudiosink.c @@ -0,0 +1,235 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2005 Wim Taymans + * + * gstbaseaudiosink.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 "gstbaseaudiosink.h" + +GST_DEBUG_CATEGORY_STATIC (gst_baseaudiosink_debug); +#define GST_CAT_DEFAULT gst_baseaudiosink_debug + +/* BaseAudioSink signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0, +}; + +#define _do_init(bla) \ + GST_DEBUG_CATEGORY_INIT (gst_baseaudiosink_debug, "baseaudiosink", 0, "baseaudiosink element"); + +GST_BOILERPLATE_FULL (GstBaseAudioSink, gst_baseaudiosink, GstBaseSink, + GST_TYPE_BASESINK, _do_init); + +static void gst_baseaudiosink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_baseaudiosink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstElementStateReturn gst_baseaudiosink_change_state (GstElement * + element); + +static GstFlowReturn gst_baseaudiosink_preroll (GstBaseSink * bsink, + GstBuffer * buffer); +static GstFlowReturn gst_baseaudiosink_render (GstBaseSink * bsink, + GstBuffer * buffer); +static void gst_baseaudiosink_event (GstBaseSink * bsink, GstEvent * event); +static void gst_baseaudiosink_get_times (GstBaseSink * bsink, + GstBuffer * buffer, GstClockTime * start, GstClockTime * end); +static gboolean gst_baseaudiosink_setcaps (GstBaseSink * bsink, GstCaps * caps); + +//static guint gst_baseaudiosink_signals[LAST_SIGNAL] = { 0 }; + +static void +gst_baseaudiosink_base_init (gpointer g_class) +{ +} + +static void +gst_baseaudiosink_class_init (GstBaseAudioSinkClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSinkClass *gstbasesink_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesink_class = (GstBaseSinkClass *) klass; + + gobject_class->set_property = + GST_DEBUG_FUNCPTR (gst_baseaudiosink_set_property); + gobject_class->get_property = + GST_DEBUG_FUNCPTR (gst_baseaudiosink_get_property); + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_baseaudiosink_change_state); + + gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_baseaudiosink_event); + gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_baseaudiosink_preroll); + gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_baseaudiosink_render); + gstbasesink_class->get_times = + GST_DEBUG_FUNCPTR (gst_baseaudiosink_get_times); + gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_baseaudiosink_setcaps); +} + +static void +gst_baseaudiosink_init (GstBaseAudioSink * baseaudiosink) +{ +} + +static void +gst_baseaudiosink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstBaseAudioSink *sink; + + sink = GST_BASEAUDIOSINK (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_baseaudiosink_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstBaseAudioSink *sink; + + sink = GST_BASEAUDIOSINK (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_baseaudiosink_setcaps (GstBaseSink * bsink, GstCaps * caps) +{ + GstBaseAudioSink *sink = GST_BASEAUDIOSINK (bsink); + GstRingBufferSpec spec; + + spec.caps = caps; + spec.segsize = 64; + spec.segtotal = 64; + + gst_ringbuffer_release (sink->ringbuffer); + gst_ringbuffer_acquire (sink->ringbuffer, &spec); + + return TRUE; +} + +static void +gst_baseaudiosink_get_times (GstBaseSink * bsink, GstBuffer * buffer, + GstClockTime * start, GstClockTime * end) +{ + *start = GST_CLOCK_TIME_NONE; + *end = GST_CLOCK_TIME_NONE; +} + +static void +gst_baseaudiosink_event (GstBaseSink * bsink, GstEvent * event) +{ +} + +static GstFlowReturn +gst_baseaudiosink_preroll (GstBaseSink * bsink, GstBuffer * buffer) +{ + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_baseaudiosink_render (GstBaseSink * bsink, GstBuffer * buf) +{ + GstBaseAudioSink *sink = GST_BASEAUDIOSINK (bsink); + + gst_ringbuffer_write (sink->ringbuffer, GST_CLOCK_TIME_NONE, + GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); + + return GST_FLOW_OK; +} + +GstRingBuffer * +gst_baseaudiosink_create_ringbuffer (GstBaseAudioSink * sink) +{ + GstBaseAudioSinkClass *bclass; + GstRingBuffer *buffer = NULL; + + bclass = GST_BASEAUDIOSINK_GET_CLASS (sink); + if (bclass->create_ringbuffer) + buffer = bclass->create_ringbuffer (sink); + + return buffer; +} + +void +gst_baseaudiosink_callback (GstRingBuffer * rbuf, guint advance, gpointer data) +{ + //GstBaseAudioSink *sink = GST_BASEAUDIOSINK (data); +} + +static GstElementStateReturn +gst_baseaudiosink_change_state (GstElement * element) +{ + GstElementStateReturn ret = GST_STATE_SUCCESS; + GstBaseAudioSink *sink = GST_BASEAUDIOSINK (element); + GstElementState transition = GST_STATE_TRANSITION (element); + + switch (transition) { + case GST_STATE_NULL_TO_READY: + break; + case GST_STATE_READY_TO_PAUSED: + sink->ringbuffer = gst_baseaudiosink_create_ringbuffer (sink); + gst_ringbuffer_set_callback (sink->ringbuffer, gst_baseaudiosink_callback, + sink); + break; + case GST_STATE_PAUSED_TO_PLAYING: + gst_ringbuffer_play (sink->ringbuffer); + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element); + + switch (transition) { + case GST_STATE_PLAYING_TO_PAUSED: + gst_ringbuffer_stop (sink->ringbuffer); + break; + case GST_STATE_PAUSED_TO_READY: + gst_object_unref (GST_OBJECT (sink->ringbuffer)); + break; + case GST_STATE_READY_TO_NULL: + break; + default: + break; + } + + return ret; +} diff --git a/gst-libs/gst/audio/gstbaseaudiosink.h b/gst-libs/gst/audio/gstbaseaudiosink.h new file mode 100644 index 000000000..cd8bb61a8 --- /dev/null +++ b/gst-libs/gst/audio/gstbaseaudiosink.h @@ -0,0 +1,87 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2005 Wim Taymans + * + * gstbaseaudosink.h: + * + * 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. + */ + +/* a base class for audio sinks. + * + * It uses a ringbuffer to schedule playback of samples. This makes + * it very easy to drop or insert samples to align incomming + * buffers to the exact playback timestamp. + * + * Subclasses must provide a ringbuffer pointing to either DMA + * memory or regular memory. A subclass should also call a callback + * function when it has processed N samples in the buffer. The subclass + * is free to use a thread to signal this callback, use EIO or any + * other mechanism. + * + * The base class is able to operate in push or pull mode. The chain + * mode will queue the samples in the ringbuffer as much as possible. + * The available space is calculated in the callback function. + * + * The pull mode will pull_range() a new buffer of N samples with a + * configurable latency. This allows for high-end real time + * audio processing pipelines driven by the audiosink. The callback + * function will be used to perform a pull_range() on the sinkpad. + * The thread scheduling the callback can be a real-time thread. + */ + +#ifndef __GST_BASEAUDIOSINK_H__ +#define __GST_BASEAUDIOSINK_H__ + +#include +#include +#include "gstringbuffer.h" + +G_BEGIN_DECLS + +#define GST_TYPE_BASEAUDIOSINK (gst_baseaudiosink_get_type()) +#define GST_BASEAUDIOSINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASEAUDIOSINK,GstBaseAudioSink)) +#define GST_BASEAUDIOSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASEAUDIOSINK,GstBaseAudioSinkClass)) +#define GST_BASEAUDIOSINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BASEAUDIOSINK, GstBaseAudioSinkClass)) +#define GST_IS_BASEAUDIOSINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASEAUDIOSINK)) +#define GST_IS_BASEAUDIOSINK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASEAUDIOSINK)) + +#define GST_BASEAUDIOSINK_CLOCK(obj) (GST_BASEAUDIOSINK (obj)->clock) +#define GST_BASEAUDIOSINK_PAD(obj) (GST_BASEAUDIOSINK (obj)->sinkpad) + +typedef struct _GstBaseAudioSink GstBaseAudioSink; +typedef struct _GstBaseAudioSinkClass GstBaseAudioSinkClass; + +struct _GstBaseAudioSink { + GstBaseSink element; + + GstRingBuffer *ringbuffer; +}; + +struct _GstBaseAudioSinkClass { + GstBaseSinkClass parent_class; + + /* subclass ringbuffer allocation */ + GstRingBuffer* (*create_ringbuffer) (GstBaseAudioSink *sink); +}; + +GType gst_baseaudiosink_get_type(void); + +GstRingBuffer *gst_baseaudiosink_create_ringbuffer (GstBaseAudioSink *sink); + +G_END_DECLS + +#endif /* __GST_BASEAUDIOSINK_H__ */ diff --git a/gst-libs/gst/audio/gstringbuffer.c b/gst-libs/gst/audio/gstringbuffer.c new file mode 100644 index 000000000..07889db20 --- /dev/null +++ b/gst-libs/gst/audio/gstringbuffer.c @@ -0,0 +1,282 @@ +/* GStreamer + * Copyright (C) 2005 Wim Taymans + * + * gstringbuffer.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 "gstringbuffer.h" + +static void gst_ringbuffer_class_init (GstRingBufferClass * klass); +static void gst_ringbuffer_init (GstRingBuffer * ringbuffer); +static void gst_ringbuffer_dispose (GObject * object); +static void gst_ringbuffer_finalize (GObject * object); + +static GstObjectClass *parent_class = NULL; + +/* ringbuffer abstract base class */ +GType +gst_ringbuffer_get_type (void) +{ + static GType ringbuffer_type = 0; + + if (!ringbuffer_type) { + static const GTypeInfo ringbuffer_info = { + sizeof (GstRingBufferClass), + NULL, + NULL, + (GClassInitFunc) gst_ringbuffer_class_init, + NULL, + NULL, + sizeof (GstRingBuffer), + 0, + (GInstanceInitFunc) gst_ringbuffer_init, + NULL + }; + + ringbuffer_type = g_type_register_static (GST_TYPE_OBJECT, "GstRingBuffer", + &ringbuffer_info, G_TYPE_FLAG_ABSTRACT); + } + return ringbuffer_type; +} + +static void +gst_ringbuffer_class_init (GstRingBufferClass * klass) +{ + GObjectClass *gobject_class; + GstObjectClass *gstobject_class; + + gobject_class = (GObjectClass *) klass; + gstobject_class = (GstObjectClass *) klass; + + parent_class = g_type_class_ref (GST_TYPE_OBJECT); + + gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ringbuffer_dispose); + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ringbuffer_finalize); +} + +static void +gst_ringbuffer_init (GstRingBuffer * ringbuffer) +{ + ringbuffer->acquired = FALSE; + ringbuffer->state = GST_RINGBUFFER_STATE_STOPPED; + ringbuffer->playseg = 0; + ringbuffer->writeseg = 1; + ringbuffer->segfilled = 0; + ringbuffer->waiters = FALSE; + ringbuffer->cond = g_cond_new (); +} + +static void +gst_ringbuffer_dispose (GObject * object) +{ + GstRingBuffer *ringbuffer = GST_RINGBUFFER (object); + + G_OBJECT_CLASS (parent_class)->dispose (G_OBJECT (ringbuffer)); +} + +static void +gst_ringbuffer_finalize (GObject * object) +{ + GstRingBuffer *ringbuffer = GST_RINGBUFFER (object); + + g_cond_free (ringbuffer->cond); + + G_OBJECT_CLASS (parent_class)->finalize (G_OBJECT (ringbuffer)); +} + +void +gst_ringbuffer_set_callback (GstRingBuffer * buf, GstRingBufferCallback cb, + gpointer data) +{ + GST_LOCK (buf); + buf->callback = cb; + buf->cb_data = data; + GST_UNLOCK (buf); +} + + +gboolean +gst_ringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) +{ + gboolean res = FALSE; + GstRingBufferClass *rclass; + + GST_LOCK (buf); + if (buf->acquired) { + res = TRUE; + goto done; + } + buf->acquired = TRUE; + GST_UNLOCK (buf); + + rclass = GST_RINGBUFFER_GET_CLASS (buf); + if (rclass->acquire) + res = rclass->acquire (buf, spec); + + GST_LOCK (buf); + if (!res) { + buf->acquired = FALSE; + } +done: + GST_UNLOCK (buf); + + return res; +} + +gboolean +gst_ringbuffer_release (GstRingBuffer * buf) +{ + gboolean res = FALSE; + GstRingBufferClass *rclass; + + GST_LOCK (buf); + if (!buf->acquired) { + res = TRUE; + goto done; + } + buf->acquired = FALSE; + GST_UNLOCK (buf); + + rclass = GST_RINGBUFFER_GET_CLASS (buf); + if (rclass->release) + res = rclass->release (buf); + + GST_LOCK (buf); + if (!res) { + buf->acquired = TRUE; + } +done: + GST_UNLOCK (buf); + + return res; +} + +gboolean +gst_ringbuffer_play (GstRingBuffer * buf) +{ + gboolean res = FALSE; + GstRingBufferClass *rclass; + + GST_LOCK (buf); + if (buf->state == GST_RINGBUFFER_STATE_PLAYING) { + res = TRUE; + goto done; + } + buf->state = GST_RINGBUFFER_STATE_PLAYING; + + rclass = GST_RINGBUFFER_GET_CLASS (buf); + if (rclass->play) + res = rclass->play (buf); + + if (!res) { + buf->state = GST_RINGBUFFER_STATE_STOPPED; + } +done: + GST_UNLOCK (buf); + + return res; +} + +gboolean +gst_ringbuffer_stop (GstRingBuffer * buf) +{ + gboolean res = FALSE; + GstRingBufferClass *rclass; + + GST_LOCK (buf); + if (buf->state == GST_RINGBUFFER_STATE_STOPPED) { + res = TRUE; + goto done; + } + buf->state = GST_RINGBUFFER_STATE_STOPPED; + + rclass = GST_RINGBUFFER_GET_CLASS (buf); + if (rclass->stop) + res = rclass->stop (buf); + + if (!res) { + buf->state = GST_RINGBUFFER_STATE_PLAYING; + } +done: + GST_UNLOCK (buf); + + return res; +} + +void +gst_ringbuffer_callback (GstRingBuffer * buf, guint advance) +{ + GST_LOCK (buf); + buf->playseg = (buf->playseg + advance) % buf->spec.segtotal; + if (buf->playseg == buf->writeseg) { + g_print ("underrun!! read %d, write %d\n", buf->playseg, buf->writeseg); + buf->writeseg = (buf->playseg + 1) % buf->spec.segtotal; + buf->segfilled = 0; + } + if (buf->waiters) + GST_RINGBUFFER_SIGNAL (buf); + GST_UNLOCK (buf); + + if (buf->callback) + buf->callback (buf, advance, buf->cb_data); +} + +guint +gst_ringbuffer_write (GstRingBuffer * buf, GstClockTime time, guchar * data, + guint len) +{ + guint towrite = len; + guint written = 0; + + GST_LOCK (buf); + /* we write the complete buffer */ + while (towrite > 0) { + guint segavail; + guint segwrite; + + /* we cannot write anymore since the buffer is filled, wait for + * some space to become available */ + while (buf->writeseg == buf->playseg) { + buf->waiters = TRUE; + GST_RINGBUFFER_WAIT (buf); + buf->waiters = FALSE; + } + + /* this is the available size now in the current segment */ + segavail = buf->spec.segsize - buf->segfilled; + + /* we write up to the available space */ + segwrite = MIN (segavail, towrite); + memcpy (GST_BUFFER_DATA (buf->data) + buf->writeseg * buf->spec.segsize + + buf->segfilled, data, segwrite); + towrite -= segwrite; + data += segwrite; + buf->segfilled += segwrite; + written += segwrite; + /* we wrote a complete segment, advance the write pointer */ + if (buf->segfilled == buf->spec.segsize) { + buf->writeseg = (buf->writeseg + 1) % buf->spec.segtotal; + buf->segfilled = 0; + } + } + GST_UNLOCK (buf); + + return written; +} diff --git a/gst-libs/gst/audio/gstringbuffer.h b/gst-libs/gst/audio/gstringbuffer.h new file mode 100644 index 000000000..aaa379450 --- /dev/null +++ b/gst-libs/gst/audio/gstringbuffer.h @@ -0,0 +1,114 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2005 Wim Taymans + * + * gstrinbuffer.h: + * + * 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_RINGBUFFER_H__ +#define __GST_RINGBUFFER_H__ + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_RINGBUFFER (gst_ringbuffer_get_type()) +#define GST_RINGBUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RINGBUFFER,GstRingBuffer)) +#define GST_RINGBUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RINGBUFFER,GstRingBufferClass)) +#define GST_RINGBUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RINGBUFFER, GstRingBufferClass)) +#define GST_IS_RINGBUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RINGBUFFER)) +#define GST_IS_RINGBUFFER_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RINGBUFFER)) + +typedef struct _GstRingBuffer GstRingBuffer; +typedef struct _GstRingBufferClass GstRingBufferClass; +typedef struct _GstRingBufferSpec GstRingBufferSpec; + +typedef void (*GstRingBufferCallback) (GstRingBuffer *rbuf, guint advance, gpointer data); + +typedef enum { + GST_RINGBUFFER_STATE_STOPPED, + GST_RINGBUFFER_STATE_PLAYING, +} GstRingBufferState; + +typedef enum { + GST_SEGSTATE_INVALID, + GST_SEGSTATE_EMPTY, + GST_SEGSTATE_FILLED, +} GstRingBufferSegState; + +struct _GstRingBufferSpec +{ + GstCaps *caps; + + guint segsize; + guint segtotal; +}; +#define GST_RINGBUFFER_GET_COND(buf) (((GstRingBuffer *)buf)->cond) +#define GST_RINGBUFFER_WAIT(buf) (g_cond_wait (GST_RINGBUFFER_GET_COND (buf), GST_GET_LOCK (buf))) +#define GST_RINGBUFFER_SIGNAL(buf) (g_cond_signal (GST_RINGBUFFER_GET_COND (buf))) + +struct _GstRingBuffer { + GstObject object; + + /*< public >*/ /* with LOCK */ + GCond *cond; + gboolean acquired; + GstRingBufferState state; + GstBuffer *data; + GstRingBufferSpec spec; + GstRingBufferSegState *segstate; + + gboolean waiters; + gint playseg; + gint writeseg; + gint segfilled; + + GstRingBufferCallback callback; + gpointer cb_data; +}; + +struct _GstRingBufferClass { + GstObjectClass parent_class; + + /*< public >*/ + gboolean (*acquire) (GstRingBuffer *buf, GstRingBufferSpec *spec); + gboolean (*release) (GstRingBuffer *buf); + + gboolean (*play) (GstRingBuffer *buf); + gboolean (*stop) (GstRingBuffer *buf); +}; + +GType gst_ringbuffer_get_type(void); + +void gst_ringbuffer_set_callback (GstRingBuffer *buf, GstRingBufferCallback cb, + gpointer data); + +gboolean gst_ringbuffer_acquire (GstRingBuffer *buf, GstRingBufferSpec *spec); +gboolean gst_ringbuffer_release (GstRingBuffer *buf); + +gboolean gst_ringbuffer_play (GstRingBuffer *buf); +gboolean gst_ringbuffer_stop (GstRingBuffer *buf); + +guint gst_ringbuffer_write (GstRingBuffer *buf, GstClockTime time, + guchar *data, guint len); + +void gst_ringbuffer_callback (GstRingBuffer *buf, guint advance); + +G_END_DECLS + +#endif /* __GST_RINGBUFFER_H__ */ diff --git a/gst-libs/gst/video/Makefile.am b/gst-libs/gst/video/Makefile.am index 7a163773b..3db87f06b 100644 --- a/gst-libs/gst/video/Makefile.am +++ b/gst-libs/gst/video/Makefile.am @@ -9,4 +9,4 @@ libgstvideoinclude_HEADERS = video.h videosink.h libgstvideo_la_LIBADD = libgstvideo_la_CFLAGS = $(GST_CFLAGS) -libgstvideo_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstvideo_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) ../../../../gstreamer2/gst/base/libgstbase.la diff --git a/gst-libs/gst/video/gstvideosink.c b/gst-libs/gst/video/gstvideosink.c index 1085ace95..2d06b3157 100644 --- a/gst-libs/gst/video/gstvideosink.c +++ b/gst-libs/gst/video/gstvideosink.c @@ -27,17 +27,6 @@ static GstElementClass *parent_class = NULL; -/* Private methods */ - -static void -gst_videosink_set_clock (GstElement * element, GstClock * clock) -{ - GstVideoSink *videosink; - - videosink = GST_VIDEOSINK (element); - - videosink->clock = clock; -} /* Initing stuff */ @@ -46,7 +35,6 @@ gst_videosink_init (GstVideoSink * videosink) { videosink->width = 0; videosink->height = 0; - videosink->clock = NULL; } static void @@ -59,8 +47,6 @@ gst_videosink_class_init (GstVideoSinkClass * klass) gstelement_class = (GstElementClass *) klass; parent_class = g_type_class_ref (GST_TYPE_ELEMENT); - - gstelement_class->set_clock = gst_videosink_set_clock; } /* Public methods */ @@ -83,7 +69,7 @@ gst_videosink_get_type (void) (GInstanceInitFunc) gst_videosink_init, }; - videosink_type = g_type_register_static (GST_TYPE_ELEMENT, + videosink_type = g_type_register_static (GST_TYPE_BASESINK, "GstVideoSink", &videosink_info, 0); } diff --git a/gst-libs/gst/video/videosink.h b/gst-libs/gst/video/videosink.h index d1e3aa975..dc7b2805c 100644 --- a/gst-libs/gst/video/videosink.h +++ b/gst-libs/gst/video/videosink.h @@ -23,6 +23,7 @@ #define __GST_VIDEOSINK_H__ #include +#include #ifdef __cplusplus extern "C" { @@ -40,28 +41,24 @@ extern "C" { #define GST_VIDEOSINK_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VIDEOSINK, GstVideoSinkClass)) -#define GST_VIDEOSINK_PAD(obj) (GST_VIDEOSINK (obj)->sinkpad) +#define GST_VIDEOSINK_PAD GST_BASESINK_PAD +#define GST_VIDEOSINK_CLOCK GST_BASESINK_CLOCK #define GST_VIDEOSINK_WIDTH(obj) (GST_VIDEOSINK (obj)->width) #define GST_VIDEOSINK_HEIGHT(obj) (GST_VIDEOSINK (obj)->height) -#define GST_VIDEOSINK_CLOCK(obj) (GST_VIDEOSINK (obj)->clock) typedef struct _GstVideoSink GstVideoSink; typedef struct _GstVideoSinkClass GstVideoSinkClass; struct _GstVideoSink { - GstElement element; - - GstPad *sinkpad; + GstBaseSink element; gint width, height; - GstClock *clock; - gpointer _gst_reserved[GST_PADDING]; }; struct _GstVideoSinkClass { - GstElementClass parent_class; + GstBaseSinkClass parent_class; gpointer _gst_reserved[GST_PADDING]; }; -- cgit v1.2.1