diff --git a/ChangeLog b/ChangeLog index 1b6bce9590..a799909071 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2005-05-09 Andy Wingo + + * gst/volume/Makefile.am: + * gst/volume/demo.c + * gst/volume/gstvolume.h + * gst/volume/gstvolume.c: Port to 0.9 API, derive from + basetransform. Probably need an audio filter base class. + 2005-05-09 Wim Taymans * ext/vorbis/vorbisenc.c: (gst_vorbisenc_sink_setcaps), diff --git a/configure.ac b/configure.ac index f500013886..8519e9dfb4 100644 --- a/configure.ac +++ b/configure.ac @@ -377,6 +377,7 @@ GST_PLUGINS_ALL="\ subparse \ typefind \ videotestsrc \ + volume \ " dnl see if we can build C++ plug-ins @@ -873,6 +874,7 @@ gst/sine/Makefile gst/subparse/Makefile gst/typefind/Makefile gst/videotestsrc/Makefile +gst/volume/Makefile sys/Makefile sys/ximage/Makefile sys/xvimage/Makefile diff --git a/gst/volume/Makefile.am b/gst/volume/Makefile.am index 2ad38c59b0..2440ccf567 100644 --- a/gst/volume/Makefile.am +++ b/gst/volume/Makefile.am @@ -4,7 +4,8 @@ plugin_LTLIBRARIES = libgstvolume.la libgstvolume_la_SOURCES = gstvolume.c libgstvolume_la_CFLAGS = $(GST_CFLAGS) libgstvolume_la_LIBADD = $(GST_LIBS) $(GST_CONTROL_LIBS) \ - $(top_builddir)/gst-libs/gst/libgstinterfaces-$(GST_MAJORMINOR).la + $(top_builddir)/gst-libs/gst/libgstinterfaces-$(GST_MAJORMINOR).la \ + $(GST_BASE_LIBS) libgstvolume_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) noinst_HEADERS = gstvolume.h filter.func diff --git a/gst/volume/demo.c b/gst/volume/demo.c index 1dfc6ba54e..ebcbadae57 100644 --- a/gst/volume/demo.c +++ b/gst/volume/demo.c @@ -49,18 +49,6 @@ value_changed_callback (GtkWidget * widget, GstElement * volume) g_object_set (volume, "volume", level, NULL); } -static gboolean -idler (gpointer data) -{ - GstElement *pipeline = GST_ELEMENT (data); - - g_print ("+"); - if (gst_bin_iterate (GST_BIN (pipeline))) - return TRUE; - gtk_main_quit (); - return FALSE; -} - static void setup_gui (GstElement * volume) { @@ -128,9 +116,9 @@ main (int argc, char *argv[]) /* go to main loop */ gst_element_set_state (pipeline, GST_STATE_PLAYING); - g_idle_add (idler, pipeline); - - gtk_main (); + gst_bus_poll (gst_element_get_bus (pipeline), + GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1); + gst_element_set_state (pipeline, GST_STATE_NULL); return 0; } diff --git a/gst/volume/gstvolume.c b/gst/volume/gstvolume.c index 89dd25c4c7..42242d7505 100644 --- a/gst/volume/gstvolume.c +++ b/gst/volume/gstvolume.c @@ -23,6 +23,7 @@ #endif #include #include +#include #include #include #include @@ -46,7 +47,7 @@ static GstElementDetails volume_details = { "Volume", "Filter/Effect/Audio", "Set volume on audio/raw streams", - "Andy Wingo ", + "Andy Wingo ", }; @@ -59,10 +60,10 @@ enum enum { - ARG_0, - ARG_SILENT, - ARG_MUTE, - ARG_VOLUME + PROP_0, + PROP_SILENT, + PROP_MUTE, + PROP_VOLUME }; static GstStaticPadTemplate volume_sink_factory = @@ -98,9 +99,30 @@ static GstStaticPadTemplate volume_src_factory = GST_STATIC_PAD_TEMPLATE ("src", "width = (int) 16, " "depth = (int) 16, " "signed = (bool) TRUE") ); -static void volume_base_init (gpointer g_class); -static void volume_class_init (GstVolumeClass * klass); -static void volume_init (GstVolume * filter); +static void gst_volume_interface_init (GstImplementsInterfaceClass * klass); +static void gst_volume_mixer_init (GstMixerClass * iface); + +#define _init_interfaces(type) \ + { \ + static const GInterfaceInfo voliface_info = { \ + (GInterfaceInitFunc) gst_volume_interface_init, \ + NULL, \ + NULL \ + }; \ + static const GInterfaceInfo volmixer_info = { \ + (GInterfaceInitFunc) gst_volume_mixer_init, \ + NULL, \ + NULL \ + }; \ + \ + g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, \ + &voliface_info); \ + g_type_add_interface_static (type, GST_TYPE_MIXER, &volmixer_info); \ + } + +GST_BOILERPLATE_FULL (GstVolume, gst_volume, GstBaseTransform, + GST_TYPE_BASE_TRANSFORM, _init_interfaces); + static void volume_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); @@ -109,18 +131,12 @@ static void volume_get_property (GObject * object, guint prop_id, static void volume_update_volume (const GValue * value, gpointer data); static void volume_update_mute (const GValue * value, gpointer data); -static gboolean volume_parse_caps (GstVolume * filter, - GstStructure * structure); - -static void volume_chain_float (GstPad * pad, GstData * _data); -static void volume_chain_int16 (GstPad * pad, GstData * _data); - -static void gst_volume_interface_init (GstImplementsInterfaceClass * klass); -static void gst_volume_mixer_init (GstMixerClass * iface); - -static GstElementClass *parent_class = NULL; - -/*static guint gst_filter_signals[LAST_SIGNAL] = { 0 }; */ +static GstFlowReturn volume_transform (GstBaseTransform * base, + GstBuffer * inbuf, GstBuffer ** outbuf); +static void volume_process_float (GstVolume * filter, GstClockTime tstamp, + gpointer bytes, gint n_bytes); +static void volume_process_int16 (GstVolume * filter, GstClockTime tstamp, + gpointer bytes, gint n_bytes); static gboolean gst_volume_interface_supported (GstImplementsInterface * iface, GType type) @@ -233,97 +249,8 @@ gst_volume_dispose (GObject * object) G_OBJECT_CLASS (parent_class)->dispose (object); } -static GstPadLinkReturn -volume_connect (GstPad * pad, const GstCaps * caps) -{ - GstVolume *filter; - GstPad *otherpad; - gint rate; - GstPadLinkReturn link_ret; - GstStructure *structure; - - filter = GST_VOLUME (gst_pad_get_parent (pad)); - g_return_val_if_fail (GST_IS_VOLUME (filter), GST_PAD_LINK_REFUSED); - otherpad = (pad == filter->srcpad ? filter->sinkpad : filter->srcpad); - - structure = gst_caps_get_structure (caps, 0); - gst_structure_get_int (structure, "rate", &rate); - - link_ret = gst_pad_try_set_caps (otherpad, caps); - if (GST_PAD_LINK_FAILED (link_ret)) { - return link_ret; - } - - if (!volume_parse_caps (filter, structure)) - return GST_PAD_LINK_REFUSED; - - gst_dpman_set_rate (filter->dpman, rate); - - return GST_PAD_LINK_OK; -} - -static gboolean -volume_parse_caps (GstVolume * filter, GstStructure * structure) -{ - const gchar *mimetype; - - g_return_val_if_fail (filter != NULL, FALSE); - g_return_val_if_fail (structure != NULL, FALSE); - - mimetype = gst_structure_get_name (structure); - - if (strcmp (mimetype, "audio/x-raw-int") == 0) { - gst_pad_set_chain_function (filter->sinkpad, volume_chain_int16); - return TRUE; - } - - if (strcmp (mimetype, "audio/x-raw-float") == 0) { - gst_pad_set_chain_function (filter->sinkpad, volume_chain_float); - return TRUE; - } - - return FALSE; -} - - -GType -gst_volume_get_type (void) -{ - static GType volume_type = 0; - - if (!volume_type) { - static const GTypeInfo volume_info = { - sizeof (GstVolumeClass), - volume_base_init, - NULL, - (GClassInitFunc) volume_class_init, - NULL, - NULL, - sizeof (GstVolume), - 0, - (GInstanceInitFunc) volume_init - }; - static const GInterfaceInfo voliface_info = { - (GInterfaceInitFunc) gst_volume_interface_init, - NULL, - NULL - }; - static const GInterfaceInfo volmixer_info = { - (GInterfaceInitFunc) gst_volume_mixer_init, - NULL, - NULL - }; - - volume_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstVolume", &volume_info, 0); - g_type_add_interface_static (volume_type, GST_TYPE_IMPLEMENTS_INTERFACE, - &voliface_info); - g_type_add_interface_static (volume_type, GST_TYPE_MIXER, &volmixer_info); - } - return volume_type; -} static void -volume_base_init (gpointer g_class) +gst_volume_base_init (gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); @@ -333,51 +260,32 @@ volume_base_init (gpointer g_class) gst_static_pad_template_get (&volume_sink_factory)); gst_element_class_set_details (element_class, &volume_details); } + static void -volume_class_init (GstVolumeClass * klass) +gst_volume_class_init (GstVolumeClass * klass) { GObjectClass *gobject_class; - GstElementClass *gstelement_class; gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - parent_class = g_type_class_ref (GST_TYPE_ELEMENT); - - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MUTE, - g_param_spec_boolean ("mute", "mute", "mute", FALSE, G_PARAM_READWRITE)); - - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VOLUME, - g_param_spec_double ("volume", "volume", "volume", - 0.0, VOLUME_MAX_DOUBLE, 1.0, G_PARAM_READWRITE)); - gobject_class->set_property = volume_set_property; gobject_class->get_property = volume_get_property; gobject_class->dispose = gst_volume_dispose; + + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MUTE, + g_param_spec_boolean ("mute", "mute", "mute", FALSE, G_PARAM_READWRITE)); + + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VOLUME, + g_param_spec_double ("volume", "volume", "volume", + 0.0, VOLUME_MAX_DOUBLE, 1.0, G_PARAM_READWRITE)); + + GST_BASE_TRANSFORM_CLASS (klass)->transform = volume_transform; } static void -volume_init (GstVolume * filter) +gst_volume_init (GstVolume * filter) { GstMixerTrack *track = NULL; - filter->sinkpad = - gst_pad_new_from_template (gst_static_pad_template_get - (&volume_sink_factory), "sink"); - gst_pad_set_getcaps_function (filter->sinkpad, gst_pad_proxy_getcaps); - gst_pad_set_link_function (filter->sinkpad, volume_connect); - - filter->srcpad = - gst_pad_new_from_template (gst_static_pad_template_get - (&volume_src_factory), "src"); - gst_pad_set_getcaps_function (filter->srcpad, gst_pad_proxy_getcaps); - gst_pad_set_link_function (filter->srcpad, volume_connect); - - gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); - gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); - - gst_pad_set_chain_function (filter->sinkpad, volume_chain_int16); - filter->mute = FALSE; filter->volume_i = VOLUME_UNITY_INT; filter->volume_f = 1.0; @@ -407,65 +315,77 @@ volume_init (GstVolume * filter) } static void -volume_chain_float (GstPad * pad, GstData * _data) +volume_typefind (GstVolume * filter, const GstStructure * structure) { - GstBuffer *buf = GST_BUFFER (_data); - GstVolume *filter; - GstBuffer *out_buf; - gfloat *data; - gint i, num_samples; + const gchar *mimetype; - g_return_if_fail (GST_IS_PAD (pad)); - g_return_if_fail (buf != NULL); + mimetype = gst_structure_get_name (structure); - filter = GST_VOLUME (GST_OBJECT_PARENT (pad)); - g_return_if_fail (GST_IS_VOLUME (filter)); + if (strcmp (mimetype, "audio/x-raw-int") == 0) + filter->process = volume_process_int16; + else if (strcmp (mimetype, "audio/x-raw-float") == 0) + filter->process = volume_process_float; +} - GST_LOG_OBJECT (filter, "processing incoming float buffer with refcount %d", - GST_BUFFER_REFCOUNT_VALUE (buf)); - out_buf = gst_buffer_copy_on_write (buf); +static GstFlowReturn +volume_transform (GstBaseTransform * base, GstBuffer * inbuf, + GstBuffer ** outbuf) +{ + GstVolume *filter = GST_VOLUME (base); - data = (gfloat *) GST_BUFFER_DATA (out_buf); - num_samples = GST_BUFFER_SIZE (out_buf) / sizeof (gfloat); - GST_DPMAN_PREPROCESS (filter->dpman, num_samples, - GST_BUFFER_TIMESTAMP (out_buf)); - i = 0; + if (G_UNLIKELY (!filter->process)) { + GstCaps *caps = GST_BUFFER_CAPS (inbuf); - while (GST_DPMAN_PROCESS (filter->dpman, i)) { - data[i++] *= filter->real_vol_f; + if (gst_caps_get_size (caps) == 1) + volume_typefind (filter, gst_caps_get_structure (caps, 0)); + + if (!filter->process) { + GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION, + ("Invalid caps on first buffer"), NULL); + return GST_FLOW_UNEXPECTED; + } } - gst_pad_push (filter->srcpad, GST_DATA (out_buf)); + *outbuf = gst_buffer_copy_on_write (gst_buffer_ref (inbuf)); + filter->process (filter, GST_BUFFER_TIMESTAMP (*outbuf), + GST_BUFFER_DATA (*outbuf), GST_BUFFER_SIZE (*outbuf)); + + return GST_FLOW_OK; } static void -volume_chain_int16 (GstPad * pad, GstData * _data) +volume_process_float (GstVolume * filter, GstClockTime tstamp, + gpointer bytes, gint n_bytes) +{ + gfloat *data; + gint i, num_samples; + + data = (gfloat *) bytes; + num_samples = n_bytes / sizeof (gfloat); + + GST_DPMAN_PREPROCESS (filter->dpman, num_samples, tstamp); + + i = 0; + while (GST_DPMAN_PROCESS (filter->dpman, i)) { + data[i++] *= filter->real_vol_f; + } +} + +static void +volume_process_int16 (GstVolume * filter, GstClockTime tstamp, + gpointer bytes, gint n_bytes) { - GstBuffer *buf = GST_BUFFER (_data); - GstVolume *filter; - GstBuffer *out_buf; gint16 *data; gint i, num_samples; - g_return_if_fail (_data); - g_return_if_fail (GST_IS_PAD (pad)); - g_return_if_fail (buf != NULL); + data = (gint16 *) bytes; + num_samples = n_bytes / sizeof (gint16); - filter = GST_VOLUME (GST_OBJECT_PARENT (pad)); - g_return_if_fail (GST_IS_VOLUME (filter)); - - GST_LOG_OBJECT (filter, "processing incoming int16 buffer with refcount %d", - GST_BUFFER_REFCOUNT_VALUE (buf)); - out_buf = gst_buffer_copy_on_write (buf); - - data = (gint16 *) GST_BUFFER_DATA (out_buf); - g_assert (data); - num_samples = GST_BUFFER_SIZE (out_buf) / sizeof (gint16); - GST_DPMAN_PREPROCESS (filter->dpman, num_samples, - GST_BUFFER_TIMESTAMP (out_buf)); + GST_DPMAN_PREPROCESS (filter->dpman, num_samples, tstamp); i = 0; + /* need... liboil... */ while (GST_DPMAN_PROCESS (filter->dpman, i)) { /* only clamp if the gain is greater than 1.0 */ if (filter->real_vol_i > VOLUME_UNITY_INT) { @@ -487,8 +407,6 @@ volume_chain_int16 (GstPad * pad, GstData * _data) } } } - - gst_pad_push (filter->srcpad, GST_DATA (out_buf)); } static void @@ -535,18 +453,14 @@ static void volume_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstVolume *filter; - - /* it's not null if we got it, but it might not be ours */ - g_return_if_fail (GST_IS_VOLUME (object)); - filter = GST_VOLUME (object); + GstVolume *filter = GST_VOLUME (object); switch (prop_id) { - case ARG_MUTE: + case PROP_MUTE: gst_dpman_bypass_dparam (filter->dpman, "mute"); volume_update_mute (value, filter); break; - case ARG_VOLUME: + case PROP_VOLUME: gst_dpman_bypass_dparam (filter->dpman, "volume"); volume_update_volume (value, filter); break; @@ -560,17 +474,13 @@ static void volume_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstVolume *filter; - - /* it's not null if we got it, but it might not be ours */ - g_return_if_fail (GST_IS_VOLUME (object)); - filter = GST_VOLUME (object); + GstVolume *filter = GST_VOLUME (object); switch (prop_id) { - case ARG_MUTE: + case PROP_MUTE: g_value_set_boolean (value, filter->mute); break; - case ARG_VOLUME: + case PROP_VOLUME: g_value_set_double (value, filter->volume_f); break; default: diff --git a/gst/volume/gstvolume.h b/gst/volume/gstvolume.h index 5a481c8a27..e48a2d714d 100644 --- a/gst/volume/gstvolume.h +++ b/gst/volume/gstvolume.h @@ -24,12 +24,9 @@ #include -/* #include */ -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +G_BEGIN_DECLS #define GST_TYPE_VOLUME \ @@ -37,7 +34,7 @@ extern "C" { #define GST_VOLUME(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VOLUME,GstVolume)) #define GST_VOLUME_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ULAW,GstVolume)) + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VOLUME,GstVolume)) #define GST_IS_VOLUME(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VOLUME)) #define GST_IS_VOLUME_CLASS(obj) \ @@ -53,9 +50,10 @@ enum _GstVolumeFormat { }; struct _GstVolume { - GstElement element; + GstBaseTransform element; + + void (*process)(GstVolume*, GstClockTime, gpointer, gint); - GstPad *sinkpad, *srcpad; GstDParamManager *dpman; gboolean mute; @@ -66,14 +64,13 @@ struct _GstVolume { }; struct _GstVolumeClass { - GstElementClass parent_class; + GstBaseTransformClass parent_class; }; GType gst_volume_get_type(void); -#ifdef __cplusplus -} -#endif /* __cplusplus */ + +G_END_DECLS #endif /* __GST_VOLUME_H__ */