diff options
| author | Marcel Holtmann <marcel@holtmann.org> | 2007-08-25 17:03:03 +0000 | 
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2007-08-25 17:03:03 +0000 | 
| commit | c7826e102e38e12166a038086ce80d3e6645dc3d (patch) | |
| tree | 5c2d1c2bacdcea192e24cb244c4db8d9c8633a35 /audio | |
| parent | a889dc322a49c0bf8f8b77389cfbaa97703e828e (diff) | |
Implement full decoding support
Diffstat (limited to 'audio')
| -rw-r--r-- | audio/gstsbcdec.c | 138 | ||||
| -rw-r--r-- | audio/gstsbcdec.h | 6 | 
2 files changed, 142 insertions, 2 deletions
diff --git a/audio/gstsbcdec.c b/audio/gstsbcdec.c index 9d547eda..ceea4383 100644 --- a/audio/gstsbcdec.c +++ b/audio/gstsbcdec.c @@ -25,7 +25,7 @@  #include <config.h>  #endif -#include "sbc.h" +#include <string.h>  #include "gstsbcdec.h" @@ -40,21 +40,155 @@ static const GstElementDetails sbc_dec_details =  				"Decode a SBC audio stream",  				"Marcel Holtmann <marcel@holtmann.org>"); +static GstStaticPadTemplate sbc_dec_sink_factory = +	GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, +		GST_STATIC_CAPS("audio/x-sbc")); + +static GstStaticPadTemplate sbc_dec_src_factory = +	GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, +		GST_STATIC_CAPS("audio/x-raw-int, " +				"rate = (int) [ 6000, 48000 ], " +				"channels = (int) [ 1, 2 ], " +				"endianness = (int) BYTE_ORDER, " +				"signed = (boolean) true, " +				"width = (int) 16, " +				"depth = (int) 16")); + +static GstFlowReturn sbc_dec_chain(GstPad *pad, GstBuffer *buffer) +{ +	GstSbcDec *dec = GST_SBC_DEC(gst_pad_get_parent(pad)); +	GstFlowReturn res = GST_FLOW_OK; +	guint size, offset = 0; +	guint8 *data; +	GstClockTime timestamp; + +	timestamp = GST_BUFFER_TIMESTAMP(buffer); + +	if (dec->buffer) { +		GstBuffer *temp = buffer; +		buffer = gst_buffer_span(dec->buffer, 0, buffer, +			GST_BUFFER_SIZE(dec->buffer) + GST_BUFFER_SIZE(buffer)); +		gst_buffer_unref(temp); +		gst_buffer_unref(dec->buffer); +		dec->buffer = NULL; +	} + +	data = GST_BUFFER_DATA(buffer); +	size = GST_BUFFER_SIZE(buffer); + +	while (offset < size) { +		GstBuffer *output; +		GstPadTemplate *template; +		GstCaps *caps, *temp; +		int consumed; + +		consumed = sbc_decode(&dec->sbc, data + offset, size - offset); +		if (consumed <= 0) +			break; + +		caps = gst_caps_new_simple("audio/x-raw-int", +				"rate", G_TYPE_INT, dec->sbc.rate, +				"channels", G_TYPE_INT, dec->sbc.channels, +				NULL); + +		template = gst_static_pad_template_get(&sbc_dec_src_factory); + +		temp = gst_caps_intersect(caps, +					gst_pad_template_get_caps(template)); + +		gst_caps_unref(caps); + +		res = gst_pad_alloc_buffer_and_set_caps(dec->srcpad, +						GST_BUFFER_OFFSET_NONE, +						dec->sbc.len, temp, &output); + +		gst_caps_unref(temp); + +		if (res != GST_FLOW_OK) +			goto done; + +		memcpy(GST_BUFFER_DATA(output), dec->sbc.data, dec->sbc.len); + +		res = gst_pad_push(dec->srcpad, output); +		if (res != GST_FLOW_OK) +			goto done; + +		offset += consumed; +	} + +	if (offset < size) +		dec->buffer = gst_buffer_create_sub(buffer, +							offset, size - offset); + +done: +	gst_buffer_unref(buffer); +	gst_object_unref(dec); + +	return res; +} + +static GstStateChangeReturn sbc_dec_change_state(GstElement *element, +						GstStateChange transition) +{ +	GstSbcDec *dec = GST_SBC_DEC(element); + +	switch (transition) { +	case GST_STATE_CHANGE_READY_TO_PAUSED: +		GST_DEBUG("Setup subband codec"); +		if (dec->buffer) { +			gst_buffer_unref(dec->buffer); +			dec->buffer = NULL; +		} +		sbc_init(&dec->sbc, 0); +		break; + +	case GST_STATE_CHANGE_PAUSED_TO_READY: +		GST_DEBUG("Finish subband codec"); +		if (dec->buffer) { +			gst_buffer_unref(dec->buffer); +			dec->buffer = NULL; +		} +		sbc_finish(&dec->sbc); +		break; + +	default: +		break; +	} + +	return parent_class->change_state(element, transition); +} +  static void gst_sbc_dec_base_init(gpointer g_class)  {  	GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); +	gst_element_class_add_pad_template(element_class, +		gst_static_pad_template_get(&sbc_dec_sink_factory)); + +	gst_element_class_add_pad_template(element_class, +		gst_static_pad_template_get(&sbc_dec_src_factory)); +  	gst_element_class_set_details(element_class, &sbc_dec_details);  }  static void gst_sbc_dec_class_init(GstSbcDecClass *klass)  { +	GstElementClass *gstelement_class = GST_ELEMENT_CLASS(klass); +  	parent_class = g_type_class_peek_parent(klass); +	gstelement_class->change_state = GST_DEBUG_FUNCPTR(sbc_dec_change_state); +  	GST_DEBUG_CATEGORY_INIT(sbc_dec_debug, "sbcdec", 0,  						"SBC decoding element");  } -static void gst_sbc_dec_init(GstSbcDec *sbcdec, GstSbcDecClass *klass) +static void gst_sbc_dec_init(GstSbcDec *self, GstSbcDecClass *klass)  { +	self->sinkpad = gst_pad_new_from_static_template(&sbc_dec_sink_factory, "sink"); +	gst_pad_set_chain_function(self->sinkpad, GST_DEBUG_FUNCPTR(sbc_dec_chain)); +	gst_element_add_pad(GST_ELEMENT(self), self->sinkpad); + +	self->srcpad = gst_pad_new_from_static_template(&sbc_dec_src_factory, "src"); +	gst_element_add_pad(GST_ELEMENT(self), self->srcpad);  } diff --git a/audio/gstsbcdec.h b/audio/gstsbcdec.h index 0737b9d9..4a6922a0 100644 --- a/audio/gstsbcdec.h +++ b/audio/gstsbcdec.h @@ -23,6 +23,8 @@  #include <gst/gst.h> +#include "sbc.h" +  G_BEGIN_DECLS  #define GST_TYPE_SBC_DEC \ @@ -44,6 +46,10 @@ struct _GstSbcDec {  	GstPad *sinkpad;  	GstPad *srcpad; + +	GstBuffer *buffer; + +	sbc_t sbc;  };  struct _GstSbcDecClass {  | 
