From 0a527f667ae62ac335f22d1d053179b20ff26e94 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 23 Aug 2007 19:12:23 +0000 Subject: Add SBC encoder and decoder skeletons for GStreamer --- audio/gstsbcenc.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 audio/gstsbcenc.c (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c new file mode 100644 index 00000000..6e63ac45 --- /dev/null +++ b/audio/gstsbcenc.c @@ -0,0 +1,60 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2007 Marcel Holtmann + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "sbc.h" + +#include "gstsbcenc.h" + +GST_DEBUG_CATEGORY_STATIC(sbc_enc_debug); +#define GST_CAT_DEFAULT sbc_enc_debug + +GST_BOILERPLATE(GstSbcEnc, gst_sbc_enc, GstElement, GST_TYPE_ELEMENT); + +static const GstElementDetails sbc_enc_details = + GST_ELEMENT_DETAILS("Bluetooth SBC encoder", + "Codec/Encoder/Audio", + "Encode a SBC audio stream", + "Marcel Holtmann "); + +static void gst_sbc_enc_base_init(gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); + + gst_element_class_set_details(element_class, &sbc_enc_details); +} + +static void gst_sbc_enc_class_init(GstSbcEncClass *klass) +{ + parent_class = g_type_class_peek_parent(klass); + + GST_DEBUG_CATEGORY_INIT(sbc_enc_debug, "sbcenc", 0, + "SBC encoding element"); +} + +static void gst_sbc_enc_init(GstSbcEnc *sbcenc, GstSbcEncClass *klass) +{ +} -- cgit From d542fb37a81d1d96604d41b36a6d6b11087ba2da Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 25 Aug 2007 19:32:03 +0000 Subject: Implement full encoding support --- audio/gstsbcenc.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 2 deletions(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 6e63ac45..86a66270 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -25,7 +25,7 @@ #include #endif -#include "sbc.h" +#include #include "gstsbcenc.h" @@ -40,21 +40,132 @@ static const GstElementDetails sbc_enc_details = "Encode a SBC audio stream", "Marcel Holtmann "); +static GstStaticPadTemplate sbc_enc_sink_factory = + GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, + GST_STATIC_CAPS("audio/x-raw-int, " + "rate = (int) { 16000, 32000, 44100, 48000 }, " + "channels = (int) [ 1, 2 ], " + "endianness = (int) BYTE_ORDER, " + "signed = (boolean) true, " + "width = (int) 16, " + "depth = (int) 16")); + +static GstStaticPadTemplate sbc_enc_src_factory = + GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, + GST_STATIC_CAPS("audio/x-sbc")); + +static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) +{ + GstSbcEnc *enc = GST_SBC_ENC(gst_pad_get_parent(pad)); + GstFlowReturn res = GST_FLOW_OK; + GstStructure *structure; + gint rate, channels; + guint size, offset = 0; + guint8 *data; + + data = GST_BUFFER_DATA(buffer); + size = GST_BUFFER_SIZE(buffer); + + structure = gst_caps_get_structure(GST_PAD_CAPS(pad), 0); + gst_structure_get_int(structure, "rate", &rate); + gst_structure_get_int(structure, "channels", &channels); + + enc->sbc.rate = rate; + enc->sbc.channels = channels; + enc->sbc.subbands = 8; + enc->sbc.joint = 0; + + while (offset < size) { + GstBuffer *output; + GstCaps *caps; + int consumed; + + consumed = sbc_encode(&enc->sbc, data + offset, size - offset); + if (consumed <= 0) + break; + + caps = GST_PAD_CAPS(enc->srcpad); + + res = gst_pad_alloc_buffer_and_set_caps(enc->srcpad, + GST_BUFFER_OFFSET_NONE, + enc->sbc.len, caps, &output); + + if (res != GST_FLOW_OK) + goto done; + + memcpy(GST_BUFFER_DATA(output), enc->sbc.data, enc->sbc.len); + + res = gst_pad_push(enc->srcpad, output); + if (res != GST_FLOW_OK) + goto done; + + offset += consumed; + } + + if (offset < size) + res = GST_FLOW_ERROR; + +done: + gst_buffer_unref(buffer); + gst_object_unref(enc); + + return res; +} + +static GstStateChangeReturn sbc_enc_change_state(GstElement *element, + GstStateChange transition) +{ + GstSbcEnc *enc = GST_SBC_ENC(element); + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + GST_DEBUG("Setup subband codec"); + sbc_init(&enc->sbc, 0); + break; + + case GST_STATE_CHANGE_PAUSED_TO_READY: + GST_DEBUG("Finish subband codec"); + sbc_finish(&enc->sbc); + break; + + default: + break; + } + + return parent_class->change_state(element, transition); +} + static void gst_sbc_enc_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_enc_sink_factory)); + + gst_element_class_add_pad_template(element_class, + gst_static_pad_template_get(&sbc_enc_src_factory)); + gst_element_class_set_details(element_class, &sbc_enc_details); } static void gst_sbc_enc_class_init(GstSbcEncClass *klass) { + GstElementClass *element_class = GST_ELEMENT_CLASS(klass); + parent_class = g_type_class_peek_parent(klass); + element_class->change_state = GST_DEBUG_FUNCPTR(sbc_enc_change_state); + GST_DEBUG_CATEGORY_INIT(sbc_enc_debug, "sbcenc", 0, "SBC encoding element"); } -static void gst_sbc_enc_init(GstSbcEnc *sbcenc, GstSbcEncClass *klass) +static void gst_sbc_enc_init(GstSbcEnc *self, GstSbcEncClass *klass) { + self->sinkpad = gst_pad_new_from_static_template(&sbc_enc_sink_factory, "sink"); + gst_element_add_pad(GST_ELEMENT(self), self->sinkpad); + + self->srcpad = gst_pad_new_from_static_template(&sbc_enc_src_factory, "src"); + gst_pad_set_chain_function(self->sinkpad, GST_DEBUG_FUNCPTR(sbc_enc_chain)); + gst_element_add_pad(GST_ELEMENT(self), self->srcpad); } -- cgit From 0551d4b78641ad4cc286d3e69c3268a27f5e9647 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 26 Aug 2007 13:12:47 +0000 Subject: Add mode property to the encoder --- audio/gstsbcenc.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 86a66270..7f94fc2a 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -32,6 +32,31 @@ GST_DEBUG_CATEGORY_STATIC(sbc_enc_debug); #define GST_CAT_DEFAULT sbc_enc_debug +#define GST_TYPE_SBC_MODE (gst_sbc_mode_get_type()) + +static GType gst_sbc_mode_get_type(void) +{ + static GType sbc_mode_type = 0; + static GEnumValue sbc_modes[] = { + { 0, "Auto", "auto" }, + { 1, "Mono", "mono" }, + { 2, "Dual Channel", "dual" }, + { 3, "Stereo", "stereo" }, + { 4, "Joint Stereo", "joint" }, + { -1, NULL, NULL} + }; + + if (!sbc_mode_type) + sbc_mode_type = g_enum_register_static("GstSbcMode", sbc_modes); + + return sbc_mode_type; +} + +enum { + PROP_0, + PROP_MODE, +}; + GST_BOILERPLATE(GstSbcEnc, gst_sbc_enc, GstElement, GST_TYPE_ELEMENT); static const GstElementDetails sbc_enc_details = @@ -52,7 +77,13 @@ static GstStaticPadTemplate sbc_enc_sink_factory = static GstStaticPadTemplate sbc_enc_src_factory = GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS("audio/x-sbc")); + GST_STATIC_CAPS("audio/x-sbc, " + "rate = (int) { 16000, 32000, 44100, 48000 }, " + "channels = (int) [ 1, 2 ], " + "mode = (string) { mono, dual, stereo, joint }, " + "blocks = (int) { 4, 8, 12, 16 }, " + "subbands = (int) { 4, 8 }, " + "allocation = (string) { snr, loudness }")); static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) { @@ -148,14 +179,54 @@ static void gst_sbc_enc_base_init(gpointer g_class) gst_element_class_set_details(element_class, &sbc_enc_details); } +static void gst_sbc_enc_set_property(GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + GstSbcEnc *enc = GST_SBC_ENC(object); + + switch (prop_id) { + case PROP_MODE: + enc->mode = g_value_get_enum(value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void gst_sbc_enc_get_property(GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + GstSbcEnc *enc = GST_SBC_ENC(object); + + switch (prop_id) { + case PROP_MODE: + g_value_set_enum(value, enc->mode); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + static void gst_sbc_enc_class_init(GstSbcEncClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS(klass); GstElementClass *element_class = GST_ELEMENT_CLASS(klass); parent_class = g_type_class_peek_parent(klass); + object_class->set_property = GST_DEBUG_FUNCPTR(gst_sbc_enc_set_property); + object_class->get_property = GST_DEBUG_FUNCPTR(gst_sbc_enc_get_property); + element_class->change_state = GST_DEBUG_FUNCPTR(sbc_enc_change_state); + g_object_class_install_property(object_class, PROP_MODE, + g_param_spec_enum("mode", "Mode", "Encoding mode", + GST_TYPE_SBC_MODE, 0, G_PARAM_READWRITE)); + GST_DEBUG_CATEGORY_INIT(sbc_enc_debug, "sbcenc", 0, "SBC encoding element"); } -- cgit From 2bb0572a896151e0cf838282fb81372fa6c47999 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 27 Aug 2007 14:10:00 +0000 Subject: Force LITTLE_ENDIAN instead of BYTE_ORDER for now --- audio/gstsbcenc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 7f94fc2a..812c1193 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -70,7 +70,7 @@ static GstStaticPadTemplate sbc_enc_sink_factory = GST_STATIC_CAPS("audio/x-raw-int, " "rate = (int) { 16000, 32000, 44100, 48000 }, " "channels = (int) [ 1, 2 ], " - "endianness = (int) BYTE_ORDER, " + "endianness = (int) LITTLE_ENDIAN, " "signed = (boolean) true, " "width = (int) 16, " "depth = (int) 16")); -- cgit From 5dee78747cac71ad970b513dc229712be1348290 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 18 Oct 2007 21:46:49 +0000 Subject: Fixes for gstsbcenc. --- audio/gstsbcenc.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 141 insertions(+), 15 deletions(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 812c1193..ea97563e 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -28,6 +28,13 @@ #include #include "gstsbcenc.h" +#include "gstsbcutil.h" + + +#define SBC_ENC_DEFAULT_MODE CFG_MODE_AUTO +#define SBC_ENC_DEFAULT_BLOCKS 16 +#define SBC_ENC_DEFAULT_SUB_BANDS 8 +#define SBC_ENC_DEFAULT_ALLOCATION CFG_ALLOCATION_AUTO GST_DEBUG_CATEGORY_STATIC(sbc_enc_debug); #define GST_CAT_DEFAULT sbc_enc_debug @@ -52,9 +59,31 @@ static GType gst_sbc_mode_get_type(void) return sbc_mode_type; } +#define GST_TYPE_SBC_ALLOCATION (gst_sbc_allocation_get_type()) + +static GType gst_sbc_allocation_get_type(void) +{ + static GType sbc_allocation_type = 0; + static GEnumValue sbc_allocations[] = { + { CFG_ALLOCATION_AUTO, "Auto", "auto" }, + { CFG_ALLOCATION_LOUDNESS, "Loudness", "loudness" }, + { CFG_ALLOCATION_SNR, "SNR", "snr" }, + { -1, NULL, NULL} + }; + + if (!sbc_allocation_type) + sbc_allocation_type = g_enum_register_static( + "GstSbcAllocation", sbc_allocations); + + return sbc_allocation_type; +} + enum { PROP_0, PROP_MODE, + PROP_ALLOCATION, + PROP_BLOCKS, + PROP_SUB_BANDS }; GST_BOILERPLATE(GstSbcEnc, gst_sbc_enc, GstElement, GST_TYPE_ELEMENT); @@ -85,27 +114,81 @@ static GstStaticPadTemplate sbc_enc_src_factory = "subbands = (int) { 4, 8 }, " "allocation = (string) { snr, loudness }")); + +static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc, GstCaps *caps) +{ + gint rate; + gint channels; + GstCaps* src_caps; + GstStructure *structure; + + structure = gst_caps_get_structure(caps, 0); + + if (!gst_structure_get_int (structure, "rate", &rate)) + return NULL; + if (!gst_structure_get_int (structure, "channels", &channels)) + return NULL; + + enc->sbc.rate = rate; + enc->sbc.channels = channels; + + if (enc->mode == 0) + enc->sbc.joint = CFG_MODE_JOINT_STEREO; + else + enc->sbc.joint = enc->mode; + + enc->sbc.blocks = enc->blocks; + enc->sbc.subbands = enc->subbands; + if (enc->allocation == 0) + enc->sbc.allocation = CFG_ALLOCATION_LOUDNESS; + else + enc->sbc.allocation = enc->allocation; + + src_caps = gst_caps_new_simple("audio/x-sbc", "rate", G_TYPE_INT, + enc->sbc.rate, "channels", G_TYPE_INT, + enc->sbc.channels, "mode", G_TYPE_STRING, + gst_sbc_get_mode_string(enc->sbc.joint), "subbands", + G_TYPE_INT, enc->sbc.subbands, "blocks", G_TYPE_INT, + enc->sbc.blocks, "allocation", G_TYPE_STRING, + gst_sbc_get_allocation_string(enc->sbc.allocation), + NULL); + + return src_caps; +} + +static gboolean sbc_enc_sink_setcaps (GstPad * pad, GstCaps * caps) +{ + GstSbcEnc *enc; + GstStructure *structure; + GstCaps *othercaps; + + enc = GST_SBC_ENC(GST_PAD_PARENT (pad)); + structure = gst_caps_get_structure(caps, 0); + + othercaps = sbc_enc_generate_srcpad_caps(enc, caps); + if (othercaps == NULL) + goto error; + + gst_pad_set_caps (enc->srcpad, othercaps); + gst_caps_unref(othercaps); + + return TRUE; + +error: + GST_ERROR_OBJECT (enc, "invalid input caps"); + return FALSE; +} + static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) { GstSbcEnc *enc = GST_SBC_ENC(gst_pad_get_parent(pad)); GstFlowReturn res = GST_FLOW_OK; - GstStructure *structure; - gint rate, channels; guint size, offset = 0; guint8 *data; data = GST_BUFFER_DATA(buffer); size = GST_BUFFER_SIZE(buffer); - structure = gst_caps_get_structure(GST_PAD_CAPS(pad), 0); - gst_structure_get_int(structure, "rate", &rate); - gst_structure_get_int(structure, "channels", &channels); - - enc->sbc.rate = rate; - enc->sbc.channels = channels; - enc->sbc.subbands = 8; - enc->sbc.joint = 0; - while (offset < size) { GstBuffer *output; GstCaps *caps; @@ -184,11 +267,23 @@ static void gst_sbc_enc_set_property(GObject *object, guint prop_id, { GstSbcEnc *enc = GST_SBC_ENC(object); + /* TODO - CAN ONLY BE CHANGED ON READY AND BELOW */ + switch (prop_id) { case PROP_MODE: enc->mode = g_value_get_enum(value); break; - + case PROP_ALLOCATION: + enc->allocation = g_value_get_enum(value); + break; + case PROP_BLOCKS: + /* TODO - verify consistency */ + enc->blocks = g_value_get_int(value); + break; + case PROP_SUB_BANDS: + /* TODO - verify consistency */ + enc->subbands = g_value_get_int(value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -204,7 +299,15 @@ static void gst_sbc_enc_get_property(GObject *object, guint prop_id, case PROP_MODE: g_value_set_enum(value, enc->mode); break; - + case PROP_ALLOCATION: + g_value_set_enum(value, enc->allocation); + break; + case PROP_BLOCKS: + g_value_set_int(value, enc->blocks); + break; + case PROP_SUB_BANDS: + g_value_set_int(value, enc->subbands); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -224,8 +327,24 @@ static void gst_sbc_enc_class_init(GstSbcEncClass *klass) element_class->change_state = GST_DEBUG_FUNCPTR(sbc_enc_change_state); g_object_class_install_property(object_class, PROP_MODE, - g_param_spec_enum("mode", "Mode", "Encoding mode", - GST_TYPE_SBC_MODE, 0, G_PARAM_READWRITE)); + g_param_spec_enum("mode", "Mode", + "Encoding mode", GST_TYPE_SBC_MODE, + SBC_ENC_DEFAULT_MODE, G_PARAM_READWRITE)); + + g_object_class_install_property(object_class, PROP_ALLOCATION, + g_param_spec_enum("allocation", "Allocation", + "Allocation mode", GST_TYPE_SBC_ALLOCATION, + SBC_ENC_DEFAULT_ALLOCATION, G_PARAM_READWRITE)); + + g_object_class_install_property(object_class, PROP_BLOCKS, + g_param_spec_int("blocks", "Blocks", + "Blocks", 0, G_MAXINT, + SBC_ENC_DEFAULT_BLOCKS, G_PARAM_READWRITE)); + + g_object_class_install_property(object_class, PROP_SUB_BANDS, + g_param_spec_int("subbands", "Sub Bands", + "Sub Bands", 0, G_MAXINT, + SBC_ENC_DEFAULT_SUB_BANDS, G_PARAM_READWRITE)); GST_DEBUG_CATEGORY_INIT(sbc_enc_debug, "sbcenc", 0, "SBC encoding element"); @@ -234,9 +353,16 @@ static void gst_sbc_enc_class_init(GstSbcEncClass *klass) static void gst_sbc_enc_init(GstSbcEnc *self, GstSbcEncClass *klass) { self->sinkpad = gst_pad_new_from_static_template(&sbc_enc_sink_factory, "sink"); + gst_pad_set_setcaps_function (self->sinkpad, + GST_DEBUG_FUNCPTR (sbc_enc_sink_setcaps)); gst_element_add_pad(GST_ELEMENT(self), self->sinkpad); self->srcpad = gst_pad_new_from_static_template(&sbc_enc_src_factory, "src"); gst_pad_set_chain_function(self->sinkpad, GST_DEBUG_FUNCPTR(sbc_enc_chain)); gst_element_add_pad(GST_ELEMENT(self), self->srcpad); + + self->subbands = SBC_ENC_DEFAULT_SUB_BANDS; + self->blocks = SBC_ENC_DEFAULT_BLOCKS; + self->mode = SBC_ENC_DEFAULT_MODE; + self->allocation = SBC_ENC_DEFAULT_ALLOCATION; } -- cgit From 2dda76438063672e2bdccf1709db3615d453ad5b Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 18 Oct 2007 22:46:12 +0000 Subject: Fix coding style issues. --- audio/gstsbcenc.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index ea97563e..628d15c9 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -30,7 +30,6 @@ #include "gstsbcenc.h" #include "gstsbcutil.h" - #define SBC_ENC_DEFAULT_MODE CFG_MODE_AUTO #define SBC_ENC_DEFAULT_BLOCKS 16 #define SBC_ENC_DEFAULT_SUB_BANDS 8 @@ -83,7 +82,7 @@ enum { PROP_MODE, PROP_ALLOCATION, PROP_BLOCKS, - PROP_SUB_BANDS + PROP_SUBBANDS }; GST_BOILERPLATE(GstSbcEnc, gst_sbc_enc, GstElement, GST_TYPE_ELEMENT); @@ -121,6 +120,8 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc, GstCaps *caps) gint channels; GstCaps* src_caps; GstStructure *structure; + const gchar *mode; + const gchar *allocation; structure = gst_caps_get_structure(caps, 0); @@ -144,14 +145,17 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc, GstCaps *caps) else enc->sbc.allocation = enc->allocation; - src_caps = gst_caps_new_simple("audio/x-sbc", "rate", G_TYPE_INT, - enc->sbc.rate, "channels", G_TYPE_INT, - enc->sbc.channels, "mode", G_TYPE_STRING, - gst_sbc_get_mode_string(enc->sbc.joint), "subbands", - G_TYPE_INT, enc->sbc.subbands, "blocks", G_TYPE_INT, - enc->sbc.blocks, "allocation", G_TYPE_STRING, - gst_sbc_get_allocation_string(enc->sbc.allocation), - NULL); + mode = gst_sbc_get_mode_string(enc->sbc.joint); + allocation = gst_sbc_get_allocation_string(enc->sbc.allocation); + + src_caps = gst_caps_new_simple("audio/x-sbc", + "rate", G_TYPE_INT, enc->sbc.rate, + "channels", G_TYPE_INT, enc->sbc.channels, + "mode", G_TYPE_STRING, mode, + "subbands", G_TYPE_INT, enc->sbc.subbands, + "blocks", G_TYPE_INT, enc->sbc.blocks, + "allocation", G_TYPE_STRING, allocation, + NULL); return src_caps; } @@ -280,7 +284,7 @@ static void gst_sbc_enc_set_property(GObject *object, guint prop_id, /* TODO - verify consistency */ enc->blocks = g_value_get_int(value); break; - case PROP_SUB_BANDS: + case PROP_SUBBANDS: /* TODO - verify consistency */ enc->subbands = g_value_get_int(value); break; @@ -305,7 +309,7 @@ static void gst_sbc_enc_get_property(GObject *object, guint prop_id, case PROP_BLOCKS: g_value_set_int(value, enc->blocks); break; - case PROP_SUB_BANDS: + case PROP_SUBBANDS: g_value_set_int(value, enc->subbands); break; default: @@ -341,7 +345,7 @@ static void gst_sbc_enc_class_init(GstSbcEncClass *klass) "Blocks", 0, G_MAXINT, SBC_ENC_DEFAULT_BLOCKS, G_PARAM_READWRITE)); - g_object_class_install_property(object_class, PROP_SUB_BANDS, + g_object_class_install_property(object_class, PROP_SUBBANDS, g_param_spec_int("subbands", "Sub Bands", "Sub Bands", 0, G_MAXINT, SBC_ENC_DEFAULT_SUB_BANDS, G_PARAM_READWRITE)); -- cgit From ea39736b353ba409d03e8f86b7ca6ca1e746fecd Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 29 Oct 2007 15:02:26 +0000 Subject: Add bitpool capability. --- audio/gstsbcenc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 628d15c9..69e67aeb 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -33,6 +33,7 @@ #define SBC_ENC_DEFAULT_MODE CFG_MODE_AUTO #define SBC_ENC_DEFAULT_BLOCKS 16 #define SBC_ENC_DEFAULT_SUB_BANDS 8 +#define SBC_ENC_DEFAULT_BITPOOL 53 #define SBC_ENC_DEFAULT_ALLOCATION CFG_ALLOCATION_AUTO GST_DEBUG_CATEGORY_STATIC(sbc_enc_debug); @@ -111,7 +112,8 @@ static GstStaticPadTemplate sbc_enc_src_factory = "mode = (string) { mono, dual, stereo, joint }, " "blocks = (int) { 4, 8, 12, 16 }, " "subbands = (int) { 4, 8 }, " - "allocation = (string) { snr, loudness }")); + "allocation = (string) { snr, loudness }," + "bitpool = (int) [ 2, 64 ]")); static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc, GstCaps *caps) @@ -145,6 +147,8 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc, GstCaps *caps) else enc->sbc.allocation = enc->allocation; + enc->sbc.bitpool = SBC_ENC_DEFAULT_BITPOOL; + mode = gst_sbc_get_mode_string(enc->sbc.joint); allocation = gst_sbc_get_allocation_string(enc->sbc.allocation); @@ -155,6 +159,7 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc, GstCaps *caps) "subbands", G_TYPE_INT, enc->sbc.subbands, "blocks", G_TYPE_INT, enc->sbc.blocks, "allocation", G_TYPE_STRING, allocation, + "bitpool", G_TYPE_INT, enc->sbc.bitpool, NULL); return src_caps; -- cgit From 9a5725b6306e1d69a89d988af94bd3efe1ef5de6 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 1 Nov 2007 13:56:51 +0000 Subject: Fix buffers timestamps in sbcenc. --- audio/gstsbcenc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 69e67aeb..681a2291 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -217,6 +217,7 @@ static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) goto done; memcpy(GST_BUFFER_DATA(output), enc->sbc.data, enc->sbc.len); + GST_BUFFER_TIMESTAMP(output) = GST_BUFFER_TIMESTAMP(buffer); res = gst_pad_push(enc->srcpad, output); if (res != GST_FLOW_OK) -- cgit From 96d6078ada20a76f885ea04893aac5f0ca5fe48d Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 1 Nov 2007 19:45:00 +0000 Subject: Fix sbc negotiation and improves buffer handling by using GstAdapter. --- audio/gstsbcenc.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 14 deletions(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 681a2291..0e9daed1 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -115,7 +115,6 @@ static GstStaticPadTemplate sbc_enc_src_factory = "allocation = (string) { snr, loudness }," "bitpool = (int) [ 2, 64 ]")); - static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc, GstCaps *caps) { gint rate; @@ -188,24 +187,83 @@ error: return FALSE; } +gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps) +{ + GstStructure *structure; + gint rate, channels, subbands, blocks, bitpool; + const gchar* mode; + const gchar* allocation; + + g_assert(gst_caps_is_fixed(caps)); + + structure = gst_caps_get_structure(caps, 0); + + if (!gst_structure_get_int(structure, "rate", &rate)) + return FALSE; + if (!gst_structure_get_int(structure, "channels", &channels)) + return FALSE; + if (!gst_structure_get_int(structure, "subbands", &subbands)) + return FALSE; + if (!gst_structure_get_int(structure, "blocks", &blocks)) + return FALSE; + if (!gst_structure_get_int(structure, "bitpool", &bitpool)) + return FALSE; + + if (!(mode = gst_structure_get_string(structure, "mode"))) + return FALSE; + if (!(allocation = gst_structure_get_string(structure, "allocation"))) + return FALSE; + + enc->sbc.rate = rate; + enc->sbc.channels = channels; + enc->blocks = blocks; + enc->sbc.subbands = subbands; + enc->sbc.bitpool = bitpool; + enc->mode = gst_sbc_get_mode_int(mode); + enc->allocation = gst_sbc_get_allocation_mode_int(allocation); + + return TRUE; +} + +static gboolean gst_sbc_enc_change_caps(GstSbcEnc *enc, GstCaps *caps) +{ + GST_INFO_OBJECT(enc, "Changing srcpad caps (renegotiation)"); + + if (!gst_pad_accept_caps(enc->srcpad, caps)) { + GST_WARNING_OBJECT(enc, "Src pad refused caps"); + return FALSE; + } + + if (!gst_sbc_enc_fill_sbc_params(enc, caps)) { + GST_ERROR_OBJECT(enc, "couldn't get sbc parameters from caps"); + return FALSE; + } + + return TRUE; +} + static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) { GstSbcEnc *enc = GST_SBC_ENC(gst_pad_get_parent(pad)); + GstAdapter *adapter = enc->adapter; GstFlowReturn res = GST_FLOW_OK; - guint size, offset = 0; - guint8 *data; + gint codesize = enc->sbc.subbands * enc->sbc.blocks * enc->sbc.channels * 2; - data = GST_BUFFER_DATA(buffer); - size = GST_BUFFER_SIZE(buffer); + gst_adapter_push(adapter, buffer); - while (offset < size) { + while (gst_adapter_available(adapter) >= codesize && res == GST_FLOW_OK) { GstBuffer *output; GstCaps *caps; + const guint8 *data; int consumed; - consumed = sbc_encode(&enc->sbc, data + offset, size - offset); - if (consumed <= 0) + data = gst_adapter_peek(adapter, codesize); + consumed = sbc_encode(&enc->sbc, (gpointer) data, codesize); + if (consumed <= 0) { + GST_ERROR ("comsumed < 0, codesize: %d", codesize); break; + } + gst_adapter_flush(adapter, consumed); caps = GST_PAD_CAPS(enc->srcpad); @@ -216,21 +274,26 @@ static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) if (res != GST_FLOW_OK) goto done; + if (!gst_caps_is_equal(caps, GST_BUFFER_CAPS(output))) + if (!gst_sbc_enc_change_caps(enc, + GST_BUFFER_CAPS(output))) { + res = GST_FLOW_ERROR; + GST_ERROR_OBJECT(enc, "couldn't renegotiate caps"); + goto done; + } + memcpy(GST_BUFFER_DATA(output), enc->sbc.data, enc->sbc.len); GST_BUFFER_TIMESTAMP(output) = GST_BUFFER_TIMESTAMP(buffer); res = gst_pad_push(enc->srcpad, output); - if (res != GST_FLOW_OK) + if (res != GST_FLOW_OK) { + GST_ERROR_OBJECT(enc, "pad pushing failed"); goto done; + } - offset += consumed; } - if (offset < size) - res = GST_FLOW_ERROR; - done: - gst_buffer_unref(buffer); gst_object_unref(enc); return res; @@ -259,6 +322,16 @@ static GstStateChangeReturn sbc_enc_change_state(GstElement *element, return parent_class->change_state(element, transition); } +static void gst_sbc_enc_dispose(GObject *object) +{ + GstSbcEnc *enc = GST_SBC_ENC(object); + + if (enc->adapter != NULL) + g_object_unref (G_OBJECT (enc->adapter)); + + enc->adapter = NULL; +} + static void gst_sbc_enc_base_init(gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); @@ -333,6 +406,7 @@ static void gst_sbc_enc_class_init(GstSbcEncClass *klass) object_class->set_property = GST_DEBUG_FUNCPTR(gst_sbc_enc_set_property); object_class->get_property = GST_DEBUG_FUNCPTR(gst_sbc_enc_get_property); + object_class->dispose = GST_DEBUG_FUNCPTR(gst_sbc_enc_dispose); element_class->change_state = GST_DEBUG_FUNCPTR(sbc_enc_change_state); @@ -375,4 +449,6 @@ static void gst_sbc_enc_init(GstSbcEnc *self, GstSbcEncClass *klass) self->blocks = SBC_ENC_DEFAULT_BLOCKS; self->mode = SBC_ENC_DEFAULT_MODE; self->allocation = SBC_ENC_DEFAULT_ALLOCATION; + + self->adapter = gst_adapter_new(); } -- cgit From 397d6c2b3bc7661f978c1777442d33fd86ada21e Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 12 Nov 2007 18:15:59 +0000 Subject: Make sbc codec to write directly in application buffers and so avoiding memcpys. --- audio/gstsbcenc.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 0e9daed1..e1c480a0 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -134,10 +134,11 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc, GstCaps *caps) enc->sbc.rate = rate; enc->sbc.channels = channels; - if (enc->mode == 0) - enc->sbc.joint = CFG_MODE_JOINT_STEREO; - else - enc->sbc.joint = enc->mode; + if (enc->mode == CFG_MODE_AUTO) + enc->mode = CFG_MODE_JOINT_STEREO; + + if (enc->mode == CFG_MODE_MONO || enc->mode == CFG_MODE_JOINT_STEREO) + enc->sbc.joint = 1; enc->sbc.blocks = enc->blocks; enc->sbc.subbands = enc->subbands; @@ -247,8 +248,10 @@ static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) GstSbcEnc *enc = GST_SBC_ENC(gst_pad_get_parent(pad)); GstAdapter *adapter = enc->adapter; GstFlowReturn res = GST_FLOW_OK; - gint codesize = enc->sbc.subbands * enc->sbc.blocks * enc->sbc.channels * 2; + gint codesize, frame_len; + codesize = sbc_get_codesize(&enc->sbc); + frame_len = sbc_get_frame_length(&enc->sbc); gst_adapter_push(adapter, buffer); while (gst_adapter_available(adapter) >= codesize && res == GST_FLOW_OK) { @@ -257,20 +260,22 @@ static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) const guint8 *data; int consumed; + caps = GST_PAD_CAPS(enc->srcpad); + + res = gst_pad_alloc_buffer_and_set_caps(enc->srcpad, + GST_BUFFER_OFFSET_NONE, + frame_len, caps, &output); + data = gst_adapter_peek(adapter, codesize); - consumed = sbc_encode(&enc->sbc, (gpointer) data, codesize); + consumed = sbc_encode(&enc->sbc, (gpointer) data, codesize, + GST_BUFFER_DATA(output), frame_len, + NULL); if (consumed <= 0) { GST_ERROR ("comsumed < 0, codesize: %d", codesize); break; } gst_adapter_flush(adapter, consumed); - caps = GST_PAD_CAPS(enc->srcpad); - - res = gst_pad_alloc_buffer_and_set_caps(enc->srcpad, - GST_BUFFER_OFFSET_NONE, - enc->sbc.len, caps, &output); - if (res != GST_FLOW_OK) goto done; @@ -282,7 +287,6 @@ static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) goto done; } - memcpy(GST_BUFFER_DATA(output), enc->sbc.data, enc->sbc.len); GST_BUFFER_TIMESTAMP(output) = GST_BUFFER_TIMESTAMP(buffer); res = gst_pad_push(enc->srcpad, output); -- cgit From b1c42bfbbcabbb056820490500e78371ceda0818 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 12 Nov 2007 22:21:45 +0000 Subject: Fix bug in sbcenc when changing encoder parameters. --- audio/gstsbcenc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index e1c480a0..1749460d 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -215,6 +215,8 @@ gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps) if (!(allocation = gst_structure_get_string(structure, "allocation"))) return FALSE; + sbc_finish(&enc->sbc); + sbc_init(&enc->sbc, 0); enc->sbc.rate = rate; enc->sbc.channels = channels; enc->blocks = blocks; -- cgit From 6d94a5b2e34c55611f2d6ea70c241971e65afc8c Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 13 Nov 2007 20:04:12 +0000 Subject: Add sbc_reinit. --- audio/gstsbcenc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 1749460d..54bb7f8a 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -215,8 +215,7 @@ gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps) if (!(allocation = gst_structure_get_string(structure, "allocation"))) return FALSE; - sbc_finish(&enc->sbc); - sbc_init(&enc->sbc, 0); + sbc_reinit(&enc->sbc, 0); enc->sbc.rate = rate; enc->sbc.channels = channels; enc->blocks = blocks; -- cgit From d4e24bf6a3d8af6479abce92fbbf1869a59669aa Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 21 Nov 2007 20:24:11 +0000 Subject: Integrate new ipc API implementation. --- audio/gstsbcenc.c | 276 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 210 insertions(+), 66 deletions(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 54bb7f8a..021ecacf 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -27,14 +27,17 @@ #include +#include "ipc.h" #include "gstsbcenc.h" #include "gstsbcutil.h" -#define SBC_ENC_DEFAULT_MODE CFG_MODE_AUTO -#define SBC_ENC_DEFAULT_BLOCKS 16 -#define SBC_ENC_DEFAULT_SUB_BANDS 8 -#define SBC_ENC_DEFAULT_BITPOOL 53 -#define SBC_ENC_DEFAULT_ALLOCATION CFG_ALLOCATION_AUTO +#define SBC_ENC_DEFAULT_MODE BT_A2DP_CHANNEL_MODE_AUTO +#define SBC_ENC_DEFAULT_BLOCKS 0 +#define SBC_ENC_DEFAULT_SUB_BANDS 0 +#define SBC_ENC_DEFAULT_BITPOOL 0 +#define SBC_ENC_DEFAULT_ALLOCATION BT_A2DP_ALLOCATION_AUTO +#define SBC_ENC_DEFAULT_RATE 0 +#define SBC_ENC_DEFAULT_CHANNELS 0 GST_DEBUG_CATEGORY_STATIC(sbc_enc_debug); #define GST_CAT_DEFAULT sbc_enc_debug @@ -65,9 +68,9 @@ static GType gst_sbc_allocation_get_type(void) { static GType sbc_allocation_type = 0; static GEnumValue sbc_allocations[] = { - { CFG_ALLOCATION_AUTO, "Auto", "auto" }, - { CFG_ALLOCATION_LOUDNESS, "Loudness", "loudness" }, - { CFG_ALLOCATION_SNR, "SNR", "snr" }, + { BT_A2DP_ALLOCATION_AUTO, "Auto", "auto" }, + { BT_A2DP_ALLOCATION_LOUDNESS, "Loudness", "loudness" }, + { BT_A2DP_ALLOCATION_SNR, "SNR", "snr" }, { -1, NULL, NULL} }; @@ -115,73 +118,193 @@ static GstStaticPadTemplate sbc_enc_src_factory = "allocation = (string) { snr, loudness }," "bitpool = (int) [ 2, 64 ]")); -static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc, GstCaps *caps) +gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps); + +static void sbc_enc_set_structure_int_param(GstSbcEnc *enc, + GstStructure *structure, const gchar* field, + gint field_value) +{ + GValue *value; + + value = g_new0(GValue,1); + value = g_value_init(value, G_TYPE_INT); + g_value_set_int(value, field_value); + gst_structure_set_value(structure, field, value); + g_free(value); +} + +static void sbc_enc_set_structure_string_param(GstSbcEnc *enc, + GstStructure *structure, const gchar* field, + const gchar* field_value) +{ + GValue *value; + + value = g_new0(GValue,1); + value = g_value_init(value, G_TYPE_STRING); + g_value_set_string(value, field_value); + gst_structure_set_value(structure, field, value); + g_free(value); +} + +static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc) { - gint rate; - gint channels; GstCaps* src_caps; GstStructure *structure; - const gchar *mode; - const gchar *allocation; + GEnumValue *enum_value; + GEnumClass *enum_class; + gchar* temp; + + src_caps = gst_caps_copy(gst_pad_get_pad_template_caps(enc->srcpad)); + structure = gst_caps_get_structure(src_caps, 0); + + if (enc->rate != 0) + sbc_enc_set_structure_int_param(enc, structure, "rate", + enc->rate); + + if (enc->channels != 0) + sbc_enc_set_structure_int_param(enc, structure, "channels", + enc->channels); + + if (enc->subbands != 0) + sbc_enc_set_structure_int_param(enc, structure, "subbands", + enc->subbands); + + if (enc->blocks != 0) + sbc_enc_set_structure_int_param(enc, structure, "blocks", + enc->blocks); + + if (enc->mode != BT_A2DP_CHANNEL_MODE_AUTO) { + enum_class = g_type_class_ref(GST_TYPE_SBC_MODE); + enum_value = g_enum_get_value(enum_class, enc->mode); + sbc_enc_set_structure_string_param(enc, structure, "mode", + enum_value->value_nick); + g_type_class_unref(enum_class); + } - structure = gst_caps_get_structure(caps, 0); + if (enc->allocation != BT_A2DP_ALLOCATION_AUTO) { + enum_class = g_type_class_ref(GST_TYPE_SBC_ALLOCATION); + enum_value = g_enum_get_value(enum_class, enc->allocation); + sbc_enc_set_structure_string_param(enc, structure, "allocation", + enum_value->value_nick); + g_type_class_unref(enum_class); + } - if (!gst_structure_get_int (structure, "rate", &rate)) - return NULL; - if (!gst_structure_get_int (structure, "channels", &channels)) + temp = gst_caps_to_string(src_caps); + GST_DEBUG_OBJECT(enc, "Srcpad caps: %s", temp); + g_free(temp); + + return src_caps; +} + +static GstCaps* sbc_enc_src_getcaps (GstPad * pad) +{ + GstSbcEnc *enc; + + enc = GST_SBC_ENC(GST_PAD_PARENT(pad)); + + return sbc_enc_generate_srcpad_caps(enc); +} + +static gboolean sbc_enc_src_setcaps (GstPad *pad, GstCaps *caps) +{ + GstCaps* srcpad_caps; + GstCaps* temp_caps; + gboolean res = TRUE; + GstSbcEnc *enc = GST_SBC_ENC(GST_PAD_PARENT(pad)); + + GST_LOG_OBJECT(enc, "setting srcpad caps"); + + srcpad_caps = sbc_enc_generate_srcpad_caps(enc); + temp_caps = gst_caps_intersect(srcpad_caps, caps); + if (temp_caps == GST_CAPS_NONE) + res = FALSE; + + gst_caps_unref(temp_caps); + gst_caps_unref(srcpad_caps); + + g_return_val_if_fail(res, FALSE); + + return gst_sbc_enc_fill_sbc_params(enc, caps); +} + +static GstCaps* sbc_enc_src_caps_fixate(GstSbcEnc *enc, GstCaps *caps) +{ + + gchar *error_message = NULL; + GstCaps* result; + + result = gst_sbc_util_caps_fixate(caps, &error_message); + + if (!result) { + GST_ERROR_OBJECT (enc, "Invalid input caps caused parsing " + "error: %s", error_message); + g_free(error_message); return NULL; + } - enc->sbc.rate = rate; - enc->sbc.channels = channels; + return result; +} - if (enc->mode == CFG_MODE_AUTO) - enc->mode = CFG_MODE_JOINT_STEREO; +static GstCaps* sbc_enc_get_fixed_srcpad_caps(GstSbcEnc *enc) +{ + GstCaps *peer_caps; + GstCaps *src_caps; + GstCaps *caps; + gboolean res = TRUE; + GstCaps *result_caps = NULL; + + peer_caps = gst_pad_peer_get_caps(enc->srcpad); + if (!peer_caps) + return NULL; - if (enc->mode == CFG_MODE_MONO || enc->mode == CFG_MODE_JOINT_STEREO) - enc->sbc.joint = 1; + src_caps = sbc_enc_generate_srcpad_caps(enc); + caps = gst_caps_intersect(src_caps, peer_caps); - enc->sbc.blocks = enc->blocks; - enc->sbc.subbands = enc->subbands; - if (enc->allocation == 0) - enc->sbc.allocation = CFG_ALLOCATION_LOUDNESS; - else - enc->sbc.allocation = enc->allocation; + if (caps == GST_CAPS_NONE || gst_caps_is_empty(caps)) { + res = FALSE; + goto done; + } - enc->sbc.bitpool = SBC_ENC_DEFAULT_BITPOOL; + result_caps = sbc_enc_src_caps_fixate(enc, caps); - mode = gst_sbc_get_mode_string(enc->sbc.joint); - allocation = gst_sbc_get_allocation_string(enc->sbc.allocation); +done: - src_caps = gst_caps_new_simple("audio/x-sbc", - "rate", G_TYPE_INT, enc->sbc.rate, - "channels", G_TYPE_INT, enc->sbc.channels, - "mode", G_TYPE_STRING, mode, - "subbands", G_TYPE_INT, enc->sbc.subbands, - "blocks", G_TYPE_INT, enc->sbc.blocks, - "allocation", G_TYPE_STRING, allocation, - "bitpool", G_TYPE_INT, enc->sbc.bitpool, - NULL); + gst_caps_unref(src_caps); + gst_caps_unref(peer_caps); + gst_caps_unref(caps); - return src_caps; + if (!res) + return NULL; + + return result_caps; } static gboolean sbc_enc_sink_setcaps (GstPad * pad, GstCaps * caps) { GstSbcEnc *enc; GstStructure *structure; - GstCaps *othercaps; + GstCaps *src_caps; + gint rate, channels; + gboolean res; enc = GST_SBC_ENC(GST_PAD_PARENT (pad)); structure = gst_caps_get_structure(caps, 0); - othercaps = sbc_enc_generate_srcpad_caps(enc, caps); - if (othercaps == NULL) + if (!gst_structure_get_int(structure, "rate", &rate)) + goto error; + if (!gst_structure_get_int(structure, "channels", &channels)) goto error; - gst_pad_set_caps (enc->srcpad, othercaps); - gst_caps_unref(othercaps); + enc->rate = rate; + enc->channels = channels; - return TRUE; + src_caps = sbc_enc_get_fixed_srcpad_caps(enc); + if (!src_caps) + goto error; + res = gst_pad_set_caps(enc->srcpad, src_caps); + gst_caps_unref(src_caps); + + return res; error: GST_ERROR_OBJECT (enc, "invalid input caps"); @@ -215,14 +338,13 @@ gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps) if (!(allocation = gst_structure_get_string(structure, "allocation"))) return FALSE; - sbc_reinit(&enc->sbc, 0); - enc->sbc.rate = rate; - enc->sbc.channels = channels; - enc->blocks = blocks; - enc->sbc.subbands = subbands; + enc->rate = enc->sbc.rate = rate; + enc->channels = enc->sbc.channels = channels; + enc->blocks = enc->sbc.blocks = blocks; + enc->subbands = enc->sbc.subbands = subbands; enc->sbc.bitpool = bitpool; - enc->mode = gst_sbc_get_mode_int(mode); - enc->allocation = gst_sbc_get_allocation_mode_int(allocation); + enc->mode = enc->sbc.joint = gst_sbc_get_mode_int(mode); + enc->allocation = enc->sbc.allocation = gst_sbc_get_allocation_mode_int(allocation); return TRUE; } @@ -291,11 +413,8 @@ static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) GST_BUFFER_TIMESTAMP(output) = GST_BUFFER_TIMESTAMP(buffer); res = gst_pad_push(enc->srcpad, output); - if (res != GST_FLOW_OK) { - GST_ERROR_OBJECT(enc, "pad pushing failed"); + if (res != GST_FLOW_OK) goto done; - } - } done: @@ -350,12 +469,30 @@ static void gst_sbc_enc_base_init(gpointer g_class) gst_element_class_set_details(element_class, &sbc_enc_details); } +static gboolean sbc_enc_set_blocks(GstSbcEnc *enc, gint value) +{ + if (value != 4 && value != 8 && value != 12 && + value != 16 && value != 0) + return FALSE; + enc->blocks = value; + return TRUE; +} + +static gboolean sbc_enc_set_subbands(GstSbcEnc *enc, gint value) +{ + if (value != 4 && value != 8 && value != 0) + return FALSE; + enc->subbands = value; + return TRUE; +} + static void gst_sbc_enc_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GstSbcEnc *enc = GST_SBC_ENC(object); - /* TODO - CAN ONLY BE CHANGED ON READY AND BELOW */ + /* changes to those properties will only happen on the next caps + * negotiation */ switch (prop_id) { case PROP_MODE: @@ -365,12 +502,14 @@ static void gst_sbc_enc_set_property(GObject *object, guint prop_id, enc->allocation = g_value_get_enum(value); break; case PROP_BLOCKS: - /* TODO - verify consistency */ - enc->blocks = g_value_get_int(value); + if (!sbc_enc_set_blocks(enc, g_value_get_int(value))) + GST_WARNING_OBJECT(enc, "invalid value %d for " + "blocks property", g_value_get_int(value)); break; case PROP_SUBBANDS: - /* TODO - verify consistency */ - enc->subbands = g_value_get_int(value); + if (!sbc_enc_set_subbands(enc, g_value_get_int(value))) + GST_WARNING_OBJECT(enc, "invalid value %d for " + "subbands property", g_value_get_int(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -428,7 +567,7 @@ static void gst_sbc_enc_class_init(GstSbcEncClass *klass) g_object_class_install_property(object_class, PROP_BLOCKS, g_param_spec_int("blocks", "Blocks", "Blocks", 0, G_MAXINT, - SBC_ENC_DEFAULT_BLOCKS, G_PARAM_READWRITE)); + SBC_ENC_DEFAULT_BLOCKS, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_SUBBANDS, g_param_spec_int("subbands", "Sub Bands", @@ -447,13 +586,18 @@ static void gst_sbc_enc_init(GstSbcEnc *self, GstSbcEncClass *klass) gst_element_add_pad(GST_ELEMENT(self), self->sinkpad); self->srcpad = gst_pad_new_from_static_template(&sbc_enc_src_factory, "src"); - gst_pad_set_chain_function(self->sinkpad, GST_DEBUG_FUNCPTR(sbc_enc_chain)); + gst_pad_set_getcaps_function(self->srcpad, GST_DEBUG_FUNCPTR(sbc_enc_src_getcaps)); + gst_pad_set_setcaps_function(self->srcpad, GST_DEBUG_FUNCPTR(sbc_enc_src_setcaps)); gst_element_add_pad(GST_ELEMENT(self), self->srcpad); + gst_pad_set_chain_function(self->sinkpad, GST_DEBUG_FUNCPTR(sbc_enc_chain)); + self->subbands = SBC_ENC_DEFAULT_SUB_BANDS; self->blocks = SBC_ENC_DEFAULT_BLOCKS; self->mode = SBC_ENC_DEFAULT_MODE; self->allocation = SBC_ENC_DEFAULT_ALLOCATION; + self->rate = SBC_ENC_DEFAULT_RATE; + self->channels = SBC_ENC_DEFAULT_CHANNELS; self->adapter = gst_adapter_new(); } -- cgit From d509d4960ff6fb74bf86bf2791067197d3795440 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Fri, 23 Nov 2007 17:00:13 +0000 Subject: Code cleanup. --- audio/gstsbcenc.c | 57 ++++++++++++++++++------------------------------------- 1 file changed, 18 insertions(+), 39 deletions(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 021ecacf..185151f5 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -345,23 +345,11 @@ gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps) enc->sbc.bitpool = bitpool; enc->mode = enc->sbc.joint = gst_sbc_get_mode_int(mode); enc->allocation = enc->sbc.allocation = gst_sbc_get_allocation_mode_int(allocation); - - return TRUE; -} - -static gboolean gst_sbc_enc_change_caps(GstSbcEnc *enc, GstCaps *caps) -{ - GST_INFO_OBJECT(enc, "Changing srcpad caps (renegotiation)"); - - if (!gst_pad_accept_caps(enc->srcpad, caps)) { - GST_WARNING_OBJECT(enc, "Src pad refused caps"); - return FALSE; - } - - if (!gst_sbc_enc_fill_sbc_params(enc, caps)) { - GST_ERROR_OBJECT(enc, "couldn't get sbc parameters from caps"); - return FALSE; - } + enc->codesize = sbc_get_codesize(&enc->sbc); + enc->frame_length = sbc_get_frame_length(&enc->sbc); + enc->frame_duration = sbc_get_frame_duration(&enc->sbc); + GST_DEBUG("codesize: %d, frame_length: %d, frame_duration: %d", + enc->codesize, enc->frame_length, enc->frame_duration); return TRUE; } @@ -371,45 +359,36 @@ static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) GstSbcEnc *enc = GST_SBC_ENC(gst_pad_get_parent(pad)); GstAdapter *adapter = enc->adapter; GstFlowReturn res = GST_FLOW_OK; - gint codesize, frame_len; - codesize = sbc_get_codesize(&enc->sbc); - frame_len = sbc_get_frame_length(&enc->sbc); gst_adapter_push(adapter, buffer); - while (gst_adapter_available(adapter) >= codesize && res == GST_FLOW_OK) { + while (gst_adapter_available(adapter) >= enc->codesize && + res == GST_FLOW_OK) { GstBuffer *output; GstCaps *caps; const guint8 *data; int consumed; caps = GST_PAD_CAPS(enc->srcpad); - res = gst_pad_alloc_buffer_and_set_caps(enc->srcpad, GST_BUFFER_OFFSET_NONE, - frame_len, caps, &output); + enc->frame_length, caps, + &output); + if (res != GST_FLOW_OK) + goto done; - data = gst_adapter_peek(adapter, codesize); - consumed = sbc_encode(&enc->sbc, (gpointer) data, codesize, - GST_BUFFER_DATA(output), frame_len, - NULL); + data = gst_adapter_peek(adapter, enc->codesize); + consumed = sbc_encode(&enc->sbc, (gpointer) data, + enc->codesize, + GST_BUFFER_DATA(output), + GST_BUFFER_SIZE(output), NULL); if (consumed <= 0) { - GST_ERROR ("comsumed < 0, codesize: %d", codesize); + GST_ERROR ("comsumed < 0, codesize: %d", + enc->codesize); break; } gst_adapter_flush(adapter, consumed); - if (res != GST_FLOW_OK) - goto done; - - if (!gst_caps_is_equal(caps, GST_BUFFER_CAPS(output))) - if (!gst_sbc_enc_change_caps(enc, - GST_BUFFER_CAPS(output))) { - res = GST_FLOW_ERROR; - GST_ERROR_OBJECT(enc, "couldn't renegotiate caps"); - goto done; - } - GST_BUFFER_TIMESTAMP(output) = GST_BUFFER_TIMESTAMP(buffer); res = gst_pad_push(enc->srcpad, output); -- cgit From a0af7ee44534dad8f35a4142c6a22177e54ffc57 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 23 Jan 2008 13:14:02 +0000 Subject: Make a2dpsink to act like a bin and split the payloader. --- audio/gstsbcenc.c | 131 +++++++++++++++++++----------------------------------- 1 file changed, 46 insertions(+), 85 deletions(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 185151f5..08ddc14f 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -120,32 +120,6 @@ static GstStaticPadTemplate sbc_enc_src_factory = gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps); -static void sbc_enc_set_structure_int_param(GstSbcEnc *enc, - GstStructure *structure, const gchar* field, - gint field_value) -{ - GValue *value; - - value = g_new0(GValue,1); - value = g_value_init(value, G_TYPE_INT); - g_value_set_int(value, field_value); - gst_structure_set_value(structure, field, value); - g_free(value); -} - -static void sbc_enc_set_structure_string_param(GstSbcEnc *enc, - GstStructure *structure, const gchar* field, - const gchar* field_value) -{ - GValue *value; - - value = g_new0(GValue,1); - value = g_value_init(value, G_TYPE_STRING); - g_value_set_string(value, field_value); - gst_structure_set_value(structure, field, value); - g_free(value); -} - static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc) { GstCaps* src_caps; @@ -153,45 +127,49 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc) GEnumValue *enum_value; GEnumClass *enum_class; gchar* temp; + GValue *value; src_caps = gst_caps_copy(gst_pad_get_pad_template_caps(enc->srcpad)); structure = gst_caps_get_structure(src_caps, 0); + value = g_new0(GValue, 1); + if (enc->rate != 0) - sbc_enc_set_structure_int_param(enc, structure, "rate", - enc->rate); + gst_sbc_util_set_structure_int_param(structure, "rate", + enc->rate, value); if (enc->channels != 0) - sbc_enc_set_structure_int_param(enc, structure, "channels", - enc->channels); + gst_sbc_util_set_structure_int_param(structure, "channels", + enc->channels, value); if (enc->subbands != 0) - sbc_enc_set_structure_int_param(enc, structure, "subbands", - enc->subbands); + gst_sbc_util_set_structure_int_param(structure, "subbands", + enc->subbands, value); if (enc->blocks != 0) - sbc_enc_set_structure_int_param(enc, structure, "blocks", - enc->blocks); + gst_sbc_util_set_structure_int_param(structure, "blocks", + enc->blocks, value); if (enc->mode != BT_A2DP_CHANNEL_MODE_AUTO) { enum_class = g_type_class_ref(GST_TYPE_SBC_MODE); enum_value = g_enum_get_value(enum_class, enc->mode); - sbc_enc_set_structure_string_param(enc, structure, "mode", - enum_value->value_nick); + gst_sbc_util_set_structure_string_param(structure, "mode", + enum_value->value_nick, value); g_type_class_unref(enum_class); } if (enc->allocation != BT_A2DP_ALLOCATION_AUTO) { enum_class = g_type_class_ref(GST_TYPE_SBC_ALLOCATION); enum_value = g_enum_get_value(enum_class, enc->allocation); - sbc_enc_set_structure_string_param(enc, structure, "allocation", - enum_value->value_nick); + gst_sbc_util_set_structure_string_param(structure, "allocation", + enum_value->value_nick, value); g_type_class_unref(enum_class); } temp = gst_caps_to_string(src_caps); GST_DEBUG_OBJECT(enc, "Srcpad caps: %s", temp); g_free(temp); + g_free(value); return src_caps; } @@ -207,23 +185,10 @@ static GstCaps* sbc_enc_src_getcaps (GstPad * pad) static gboolean sbc_enc_src_setcaps (GstPad *pad, GstCaps *caps) { - GstCaps* srcpad_caps; - GstCaps* temp_caps; - gboolean res = TRUE; GstSbcEnc *enc = GST_SBC_ENC(GST_PAD_PARENT(pad)); GST_LOG_OBJECT(enc, "setting srcpad caps"); - srcpad_caps = sbc_enc_generate_srcpad_caps(enc); - temp_caps = gst_caps_intersect(srcpad_caps, caps); - if (temp_caps == GST_CAPS_NONE) - res = FALSE; - - gst_caps_unref(temp_caps); - gst_caps_unref(srcpad_caps); - - g_return_val_if_fail(res, FALSE); - return gst_sbc_enc_fill_sbc_params(enc, caps); } @@ -313,38 +278,16 @@ error: gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps) { - GstStructure *structure; - gint rate, channels, subbands, blocks, bitpool; - const gchar* mode; - const gchar* allocation; - - g_assert(gst_caps_is_fixed(caps)); - structure = gst_caps_get_structure(caps, 0); - - if (!gst_structure_get_int(structure, "rate", &rate)) - return FALSE; - if (!gst_structure_get_int(structure, "channels", &channels)) - return FALSE; - if (!gst_structure_get_int(structure, "subbands", &subbands)) - return FALSE; - if (!gst_structure_get_int(structure, "blocks", &blocks)) - return FALSE; - if (!gst_structure_get_int(structure, "bitpool", &bitpool)) + if (!gst_sbc_util_fill_sbc_params(&enc->sbc, caps)) return FALSE; - if (!(mode = gst_structure_get_string(structure, "mode"))) - return FALSE; - if (!(allocation = gst_structure_get_string(structure, "allocation"))) - return FALSE; - - enc->rate = enc->sbc.rate = rate; - enc->channels = enc->sbc.channels = channels; - enc->blocks = enc->sbc.blocks = blocks; - enc->subbands = enc->sbc.subbands = subbands; - enc->sbc.bitpool = bitpool; - enc->mode = enc->sbc.joint = gst_sbc_get_mode_int(mode); - enc->allocation = enc->sbc.allocation = gst_sbc_get_allocation_mode_int(allocation); + enc->rate = enc->sbc.rate; + enc->channels = enc->sbc.channels; + enc->blocks = enc->sbc.blocks; + enc->subbands = enc->sbc.subbands; + enc->mode = enc->sbc.joint; + enc->allocation = enc->sbc.allocation; enc->codesize = sbc_get_codesize(&enc->sbc); enc->frame_length = sbc_get_frame_length(&enc->sbc); enc->frame_duration = sbc_get_frame_duration(&enc->sbc); @@ -390,6 +333,8 @@ static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) gst_adapter_flush(adapter, consumed); GST_BUFFER_TIMESTAMP(output) = GST_BUFFER_TIMESTAMP(buffer); + /* we have only 1 frame */ + GST_BUFFER_DURATION(output) = enc->frame_duration; res = gst_pad_push(enc->srcpad, output); if (res != GST_FLOW_OK) @@ -559,17 +504,22 @@ static void gst_sbc_enc_class_init(GstSbcEncClass *klass) static void gst_sbc_enc_init(GstSbcEnc *self, GstSbcEncClass *klass) { - self->sinkpad = gst_pad_new_from_static_template(&sbc_enc_sink_factory, "sink"); + self->sinkpad = gst_pad_new_from_static_template( + &sbc_enc_sink_factory, "sink"); gst_pad_set_setcaps_function (self->sinkpad, GST_DEBUG_FUNCPTR (sbc_enc_sink_setcaps)); gst_element_add_pad(GST_ELEMENT(self), self->sinkpad); - self->srcpad = gst_pad_new_from_static_template(&sbc_enc_src_factory, "src"); - gst_pad_set_getcaps_function(self->srcpad, GST_DEBUG_FUNCPTR(sbc_enc_src_getcaps)); - gst_pad_set_setcaps_function(self->srcpad, GST_DEBUG_FUNCPTR(sbc_enc_src_setcaps)); + self->srcpad = gst_pad_new_from_static_template( + &sbc_enc_src_factory, "src"); + gst_pad_set_getcaps_function(self->srcpad, + GST_DEBUG_FUNCPTR(sbc_enc_src_getcaps)); + gst_pad_set_setcaps_function(self->srcpad, + GST_DEBUG_FUNCPTR(sbc_enc_src_setcaps)); gst_element_add_pad(GST_ELEMENT(self), self->srcpad); - gst_pad_set_chain_function(self->sinkpad, GST_DEBUG_FUNCPTR(sbc_enc_chain)); + gst_pad_set_chain_function(self->sinkpad, + GST_DEBUG_FUNCPTR(sbc_enc_chain)); self->subbands = SBC_ENC_DEFAULT_SUB_BANDS; self->blocks = SBC_ENC_DEFAULT_BLOCKS; @@ -578,5 +528,16 @@ static void gst_sbc_enc_init(GstSbcEnc *self, GstSbcEncClass *klass) self->rate = SBC_ENC_DEFAULT_RATE; self->channels = SBC_ENC_DEFAULT_CHANNELS; + self->frame_length = 0; + self->frame_duration = 0; + self->adapter = gst_adapter_new(); } + +gboolean gst_sbc_enc_plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "sbcenc", + GST_RANK_NONE, GST_TYPE_SBC_ENC); +} + + -- cgit From ae689c59cc62acc9f160afe6beb6ccc07b6c6f55 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Fri, 1 Feb 2008 19:28:37 +0000 Subject: Add bitpool property and others fixes for gstreamer plugin. --- audio/gstsbcenc.c | 177 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 119 insertions(+), 58 deletions(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 08ddc14f..88737475 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -34,11 +34,16 @@ #define SBC_ENC_DEFAULT_MODE BT_A2DP_CHANNEL_MODE_AUTO #define SBC_ENC_DEFAULT_BLOCKS 0 #define SBC_ENC_DEFAULT_SUB_BANDS 0 -#define SBC_ENC_DEFAULT_BITPOOL 0 #define SBC_ENC_DEFAULT_ALLOCATION BT_A2DP_ALLOCATION_AUTO #define SBC_ENC_DEFAULT_RATE 0 #define SBC_ENC_DEFAULT_CHANNELS 0 +#define SBC_ENC_BITPOOL_AUTO 1 +#define SBC_ENC_BITPOOL_MIN 2 +#define SBC_ENC_BITPOOL_MIN_STR "2" +#define SBC_ENC_BITPOOL_MAX 64 +#define SBC_ENC_BITPOOL_MAX_STR "64" + GST_DEBUG_CATEGORY_STATIC(sbc_enc_debug); #define GST_CAT_DEFAULT sbc_enc_debug @@ -81,12 +86,53 @@ static GType gst_sbc_allocation_get_type(void) return sbc_allocation_type; } +#define GST_TYPE_SBC_BLOCKS (gst_sbc_blocks_get_type()) + +static GType gst_sbc_blocks_get_type(void) +{ + static GType sbc_blocks_type = 0; + static GEnumValue sbc_blocks[] = { + { 0, "Auto", "auto" }, + { 4, "4", "4" }, + { 8, "8", "8" }, + { 12, "12", "12" }, + { 16, "16", "16" }, + { -1, NULL, NULL} + }; + + if (!sbc_blocks_type) + sbc_blocks_type = g_enum_register_static( + "GstSbcBlocks", sbc_blocks); + + return sbc_blocks_type; +} + +#define GST_TYPE_SBC_SUBBANDS (gst_sbc_subbands_get_type()) + +static GType gst_sbc_subbands_get_type(void) +{ + static GType sbc_subbands_type = 0; + static GEnumValue sbc_subbands[] = { + { 0, "Auto", "auto" }, + { 4, "4 subbands", "4" }, + { 8, "8 subbands", "8" }, + { -1, NULL, NULL} + }; + + if (!sbc_subbands_type) + sbc_subbands_type = g_enum_register_static( + "GstSbcSubbands", sbc_subbands); + + return sbc_subbands_type; +} + enum { PROP_0, PROP_MODE, PROP_ALLOCATION, PROP_BLOCKS, - PROP_SUBBANDS + PROP_SUBBANDS, + PROP_BITPOOL }; GST_BOILERPLATE(GstSbcEnc, gst_sbc_enc, GstElement, GST_TYPE_ELEMENT); @@ -116,7 +162,8 @@ static GstStaticPadTemplate sbc_enc_src_factory = "blocks = (int) { 4, 8, 12, 16 }, " "subbands = (int) { 4, 8 }, " "allocation = (string) { snr, loudness }," - "bitpool = (int) [ 2, 64 ]")); + "bitpool = (int) [ " SBC_ENC_BITPOOL_MIN_STR + ", " SBC_ENC_BITPOOL_MAX_STR " ]")); gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps); @@ -150,6 +197,10 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc) gst_sbc_util_set_structure_int_param(structure, "blocks", enc->blocks, value); + if (enc->bitpool != SBC_ENC_BITPOOL_AUTO) + gst_sbc_util_set_structure_int_param(structure, "bitpool", + enc->bitpool, value); + if (enc->mode != BT_A2DP_CHANNEL_MODE_AUTO) { enum_class = g_type_class_ref(GST_TYPE_SBC_MODE); enum_value = g_enum_get_value(enum_class, enc->mode); @@ -201,7 +252,7 @@ static GstCaps* sbc_enc_src_caps_fixate(GstSbcEnc *enc, GstCaps *caps) result = gst_sbc_util_caps_fixate(caps, &error_message); if (!result) { - GST_ERROR_OBJECT (enc, "Invalid input caps caused parsing " + GST_WARNING_OBJECT (enc, "Invalid input caps caused parsing " "error: %s", error_message); g_free(error_message); return NULL; @@ -212,18 +263,13 @@ static GstCaps* sbc_enc_src_caps_fixate(GstSbcEnc *enc, GstCaps *caps) static GstCaps* sbc_enc_get_fixed_srcpad_caps(GstSbcEnc *enc) { - GstCaps *peer_caps; - GstCaps *src_caps; GstCaps *caps; gboolean res = TRUE; GstCaps *result_caps = NULL; - peer_caps = gst_pad_peer_get_caps(enc->srcpad); - if (!peer_caps) - return NULL; - - src_caps = sbc_enc_generate_srcpad_caps(enc); - caps = gst_caps_intersect(src_caps, peer_caps); + caps = gst_pad_get_allowed_caps(enc->srcpad); + if (caps == NULL) + caps = sbc_enc_src_getcaps(enc->srcpad); if (caps == GST_CAPS_NONE || gst_caps_is_empty(caps)) { res = FALSE; @@ -233,9 +279,6 @@ static GstCaps* sbc_enc_get_fixed_srcpad_caps(GstSbcEnc *enc) result_caps = sbc_enc_src_caps_fixate(enc, caps); done: - - gst_caps_unref(src_caps); - gst_caps_unref(peer_caps); gst_caps_unref(caps); if (!res) @@ -256,45 +299,71 @@ static gboolean sbc_enc_sink_setcaps (GstPad * pad, GstCaps * caps) structure = gst_caps_get_structure(caps, 0); if (!gst_structure_get_int(structure, "rate", &rate)) - goto error; + return FALSE; if (!gst_structure_get_int(structure, "channels", &channels)) - goto error; + return FALSE; enc->rate = rate; enc->channels = channels; src_caps = sbc_enc_get_fixed_srcpad_caps(enc); if (!src_caps) - goto error; + return FALSE; res = gst_pad_set_caps(enc->srcpad, src_caps); gst_caps_unref(src_caps); return res; - -error: - GST_ERROR_OBJECT (enc, "invalid input caps"); - return FALSE; } gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps) { + gint mode; + + if (!gst_caps_is_fixed(caps)) { + GST_DEBUG_OBJECT(enc, "didn't receive fixed caps, " + "returning false"); + return FALSE; + } if (!gst_sbc_util_fill_sbc_params(&enc->sbc, caps)) return FALSE; - enc->rate = enc->sbc.rate; - enc->channels = enc->sbc.channels; - enc->blocks = enc->sbc.blocks; - enc->subbands = enc->sbc.subbands; - enc->mode = enc->sbc.joint; - enc->allocation = enc->sbc.allocation; + if (enc->rate != 0 && enc->sbc.rate != enc->rate) + goto fail; + + if (enc->channels != 0 && enc->sbc.channels != enc->channels) + goto fail; + + if (enc->blocks != 0 && enc->sbc.blocks != enc->blocks) + goto fail; + + if (enc->subbands != 0 && enc->sbc.subbands != enc->subbands) + goto fail; + + mode = gst_sbc_get_mode_int_from_sbc_t(&enc->sbc); + if (enc->mode != BT_A2DP_CHANNEL_MODE_AUTO && mode != enc->mode) + goto fail; + + if (enc->allocation != BT_A2DP_ALLOCATION_AUTO && + enc->sbc.allocation != enc->allocation) + goto fail; + + if (enc->bitpool != SBC_ENC_BITPOOL_AUTO && + enc->sbc.bitpool != enc->bitpool) + goto fail; + enc->codesize = sbc_get_codesize(&enc->sbc); enc->frame_length = sbc_get_frame_length(&enc->sbc); enc->frame_duration = sbc_get_frame_duration(&enc->sbc); + GST_DEBUG("codesize: %d, frame_length: %d, frame_duration: %d", enc->codesize, enc->frame_length, enc->frame_duration); return TRUE; + +fail: + memset(&enc->sbc, 0, sizeof(sbc_t)); + return FALSE; } static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) @@ -393,23 +462,6 @@ static void gst_sbc_enc_base_init(gpointer g_class) gst_element_class_set_details(element_class, &sbc_enc_details); } -static gboolean sbc_enc_set_blocks(GstSbcEnc *enc, gint value) -{ - if (value != 4 && value != 8 && value != 12 && - value != 16 && value != 0) - return FALSE; - enc->blocks = value; - return TRUE; -} - -static gboolean sbc_enc_set_subbands(GstSbcEnc *enc, gint value) -{ - if (value != 4 && value != 8 && value != 0) - return FALSE; - enc->subbands = value; - return TRUE; -} - static void gst_sbc_enc_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { @@ -426,14 +478,13 @@ static void gst_sbc_enc_set_property(GObject *object, guint prop_id, enc->allocation = g_value_get_enum(value); break; case PROP_BLOCKS: - if (!sbc_enc_set_blocks(enc, g_value_get_int(value))) - GST_WARNING_OBJECT(enc, "invalid value %d for " - "blocks property", g_value_get_int(value)); + enc->blocks = g_value_get_enum(value); break; case PROP_SUBBANDS: - if (!sbc_enc_set_subbands(enc, g_value_get_int(value))) - GST_WARNING_OBJECT(enc, "invalid value %d for " - "subbands property", g_value_get_int(value)); + enc->subbands = g_value_get_enum(value); + break; + case PROP_BITPOOL: + enc->bitpool = g_value_get_int(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -454,10 +505,13 @@ static void gst_sbc_enc_get_property(GObject *object, guint prop_id, g_value_set_enum(value, enc->allocation); break; case PROP_BLOCKS: - g_value_set_int(value, enc->blocks); + g_value_set_enum(value, enc->blocks); break; case PROP_SUBBANDS: - g_value_set_int(value, enc->subbands); + g_value_set_enum(value, enc->subbands); + break; + case PROP_BITPOOL: + g_value_set_int(value, enc->bitpool); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -485,19 +539,25 @@ static void gst_sbc_enc_class_init(GstSbcEncClass *klass) g_object_class_install_property(object_class, PROP_ALLOCATION, g_param_spec_enum("allocation", "Allocation", - "Allocation mode", GST_TYPE_SBC_ALLOCATION, + "Allocation method", GST_TYPE_SBC_ALLOCATION, SBC_ENC_DEFAULT_ALLOCATION, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_BLOCKS, - g_param_spec_int("blocks", "Blocks", - "Blocks", 0, G_MAXINT, + g_param_spec_enum("blocks", "Blocks", + "Blocks", GST_TYPE_SBC_BLOCKS, SBC_ENC_DEFAULT_BLOCKS, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_SUBBANDS, - g_param_spec_int("subbands", "Sub Bands", - "Sub Bands", 0, G_MAXINT, + g_param_spec_enum("subbands", "Sub bands", + "Number of sub bands", GST_TYPE_SBC_SUBBANDS, SBC_ENC_DEFAULT_SUB_BANDS, G_PARAM_READWRITE)); + g_object_class_install_property(object_class, PROP_BITPOOL, + g_param_spec_int("bitpool", "Bitpool", + "Bitpool (use 1 for automatic selection)", + SBC_ENC_BITPOOL_AUTO, SBC_ENC_BITPOOL_MAX, + SBC_ENC_BITPOOL_AUTO, G_PARAM_READWRITE)); + GST_DEBUG_CATEGORY_INIT(sbc_enc_debug, "sbcenc", 0, "SBC encoding element"); } @@ -527,6 +587,7 @@ static void gst_sbc_enc_init(GstSbcEnc *self, GstSbcEncClass *klass) self->allocation = SBC_ENC_DEFAULT_ALLOCATION; self->rate = SBC_ENC_DEFAULT_RATE; self->channels = SBC_ENC_DEFAULT_CHANNELS; + self->bitpool = SBC_ENC_BITPOOL_AUTO; self->frame_length = 0; self->frame_duration = 0; -- cgit From e823c15e43a6f924779e466d434c51157002d9ee Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 2 Feb 2008 03:37:05 +0000 Subject: Update copyright information --- audio/gstsbcenc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 88737475..918324b2 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -2,7 +2,7 @@ * * BlueZ - Bluetooth protocol stack for Linux * - * Copyright (C) 2004-2007 Marcel Holtmann + * Copyright (C) 2004-2008 Marcel Holtmann * * * This library is free software; you can redistribute it and/or -- cgit From 8fbc804e08629e5450d2641b4ba660f111dedbb2 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 14 Feb 2008 21:22:38 +0000 Subject: Make use of parameters selected in alsa plugin and fix auto selection. --- audio/gstsbcenc.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 918324b2..7777084c 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -31,10 +31,10 @@ #include "gstsbcenc.h" #include "gstsbcutil.h" -#define SBC_ENC_DEFAULT_MODE BT_A2DP_CHANNEL_MODE_AUTO +#define SBC_ENC_DEFAULT_MODE BT_A2DP_CHANNEL_MODE_JOINT_STEREO #define SBC_ENC_DEFAULT_BLOCKS 0 #define SBC_ENC_DEFAULT_SUB_BANDS 0 -#define SBC_ENC_DEFAULT_ALLOCATION BT_A2DP_ALLOCATION_AUTO +#define SBC_ENC_DEFAULT_ALLOCATION BT_A2DP_ALLOCATION_LOUDNESS #define SBC_ENC_DEFAULT_RATE 0 #define SBC_ENC_DEFAULT_CHANNELS 0 @@ -73,7 +73,6 @@ static GType gst_sbc_allocation_get_type(void) { static GType sbc_allocation_type = 0; static GEnumValue sbc_allocations[] = { - { BT_A2DP_ALLOCATION_AUTO, "Auto", "auto" }, { BT_A2DP_ALLOCATION_LOUDNESS, "Loudness", "loudness" }, { BT_A2DP_ALLOCATION_SNR, "SNR", "snr" }, { -1, NULL, NULL} @@ -201,7 +200,7 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc) gst_sbc_util_set_structure_int_param(structure, "bitpool", enc->bitpool, value); - if (enc->mode != BT_A2DP_CHANNEL_MODE_AUTO) { + if (enc->mode != SBC_ENC_DEFAULT_MODE) { enum_class = g_type_class_ref(GST_TYPE_SBC_MODE); enum_value = g_enum_get_value(enum_class, enc->mode); gst_sbc_util_set_structure_string_param(structure, "mode", @@ -209,7 +208,7 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc) g_type_class_unref(enum_class); } - if (enc->allocation != BT_A2DP_ALLOCATION_AUTO) { + if (enc->allocation != SBC_ENC_DEFAULT_ALLOCATION) { enum_class = g_type_class_ref(GST_TYPE_SBC_ALLOCATION); enum_value = g_enum_get_value(enum_class, enc->allocation); gst_sbc_util_set_structure_string_param(structure, "allocation", @@ -341,10 +340,10 @@ gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps) goto fail; mode = gst_sbc_get_mode_int_from_sbc_t(&enc->sbc); - if (enc->mode != BT_A2DP_CHANNEL_MODE_AUTO && mode != enc->mode) + if (enc->mode != SBC_ENC_DEFAULT_MODE && mode != enc->mode) goto fail; - if (enc->allocation != BT_A2DP_ALLOCATION_AUTO && + if (enc->allocation != SBC_ENC_DEFAULT_ALLOCATION && enc->sbc.allocation != enc->allocation) goto fail; -- cgit From a8b3b548ec9870df10709a839ed4c07e6d8eb76d Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 19 Feb 2008 19:49:24 +0000 Subject: Update gstreamer plugin to use new sbc API. --- audio/gstsbcenc.c | 57 +++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 29 deletions(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 7777084c..03423ecf 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -27,14 +27,13 @@ #include -#include "ipc.h" #include "gstsbcenc.h" #include "gstsbcutil.h" -#define SBC_ENC_DEFAULT_MODE BT_A2DP_CHANNEL_MODE_JOINT_STEREO +#define SBC_ENC_DEFAULT_MODE SBC_MODE_AUTO #define SBC_ENC_DEFAULT_BLOCKS 0 #define SBC_ENC_DEFAULT_SUB_BANDS 0 -#define SBC_ENC_DEFAULT_ALLOCATION BT_A2DP_ALLOCATION_LOUDNESS +#define SBC_ENC_DEFAULT_ALLOCATION SBC_AM_AUTO #define SBC_ENC_DEFAULT_RATE 0 #define SBC_ENC_DEFAULT_CHANNELS 0 @@ -53,11 +52,11 @@ static GType gst_sbc_mode_get_type(void) { static GType sbc_mode_type = 0; static GEnumValue sbc_modes[] = { - { 0, "Auto", "auto" }, - { 1, "Mono", "mono" }, - { 2, "Dual Channel", "dual" }, - { 3, "Stereo", "stereo" }, - { 4, "Joint Stereo", "joint" }, + { SBC_MODE_MONO, "Mono", "mono" }, + { SBC_MODE_DUAL_CHANNEL, "Dual Channel", "dual" }, + { SBC_MODE_STEREO, "Stereo", "stereo"}, + { SBC_MODE_JOINT_STEREO, "Joint Stereo", "joint" }, + { SBC_MODE_AUTO, "Auto", "auto" }, { -1, NULL, NULL} }; @@ -73,8 +72,9 @@ static GType gst_sbc_allocation_get_type(void) { static GType sbc_allocation_type = 0; static GEnumValue sbc_allocations[] = { - { BT_A2DP_ALLOCATION_LOUDNESS, "Loudness", "loudness" }, - { BT_A2DP_ALLOCATION_SNR, "SNR", "snr" }, + { SBC_AM_LOUDNESS, "Loudness", "loudness" }, + { SBC_AM_SNR, "SNR", "snr" }, + { SBC_AM_AUTO, "Auto", "auto" }, { -1, NULL, NULL} }; @@ -172,7 +172,6 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc) GstStructure *structure; GEnumValue *enum_value; GEnumClass *enum_class; - gchar* temp; GValue *value; src_caps = gst_caps_copy(gst_pad_get_pad_template_caps(enc->srcpad)); @@ -208,7 +207,7 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc) g_type_class_unref(enum_class); } - if (enc->allocation != SBC_ENC_DEFAULT_ALLOCATION) { + if (enc->allocation != SBC_AM_AUTO) { enum_class = g_type_class_ref(GST_TYPE_SBC_ALLOCATION); enum_value = g_enum_get_value(enum_class, enc->allocation); gst_sbc_util_set_structure_string_param(structure, "allocation", @@ -216,9 +215,6 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc) g_type_class_unref(enum_class); } - temp = gst_caps_to_string(src_caps); - GST_DEBUG_OBJECT(enc, "Srcpad caps: %s", temp); - g_free(temp); g_free(value); return src_caps; @@ -244,7 +240,6 @@ static gboolean sbc_enc_src_setcaps (GstPad *pad, GstCaps *caps) static GstCaps* sbc_enc_src_caps_fixate(GstSbcEnc *enc, GstCaps *caps) { - gchar *error_message = NULL; GstCaps* result; @@ -316,8 +311,6 @@ static gboolean sbc_enc_sink_setcaps (GstPad * pad, GstCaps * caps) gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps) { - gint mode; - if (!gst_caps_is_fixed(caps)) { GST_DEBUG_OBJECT(enc, "didn't receive fixed caps, " "returning false"); @@ -327,23 +320,26 @@ gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps) if (!gst_sbc_util_fill_sbc_params(&enc->sbc, caps)) return FALSE; - if (enc->rate != 0 && enc->sbc.rate != enc->rate) + if (enc->rate != 0 && gst_sbc_parse_rate_from_sbc(enc->sbc.frequency) + != enc->rate) goto fail; - if (enc->channels != 0 && enc->sbc.channels != enc->channels) + if (enc->channels != 0 && gst_sbc_get_channel_number(enc->sbc.mode) + != enc->channels) goto fail; - if (enc->blocks != 0 && enc->sbc.blocks != enc->blocks) + if (enc->blocks != 0 && gst_sbc_parse_blocks_from_sbc(enc->sbc.blocks) + != enc->blocks) goto fail; - if (enc->subbands != 0 && enc->sbc.subbands != enc->subbands) + if (enc->subbands != 0 && gst_sbc_parse_subbands_from_sbc( + enc->sbc.subbands) != enc->subbands) goto fail; - mode = gst_sbc_get_mode_int_from_sbc_t(&enc->sbc); - if (enc->mode != SBC_ENC_DEFAULT_MODE && mode != enc->mode) + if (enc->mode != SBC_ENC_DEFAULT_MODE && enc->sbc.mode != enc->mode) goto fail; - if (enc->allocation != SBC_ENC_DEFAULT_ALLOCATION && + if (enc->allocation != SBC_AM_AUTO && enc->sbc.allocation != enc->allocation) goto fail; @@ -355,8 +351,9 @@ gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps) enc->frame_length = sbc_get_frame_length(&enc->sbc); enc->frame_duration = sbc_get_frame_duration(&enc->sbc); - GST_DEBUG("codesize: %d, frame_length: %d, frame_duration: %d", - enc->codesize, enc->frame_length, enc->frame_duration); + GST_DEBUG_OBJECT(enc, "codesize: %d, frame_length: %d, frame_duration:" + " %d", enc->codesize, enc->frame_length, + enc->frame_duration); return TRUE; @@ -378,7 +375,7 @@ static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) GstBuffer *output; GstCaps *caps; const guint8 *data; - int consumed; + gint consumed; caps = GST_PAD_CAPS(enc->srcpad); res = gst_pad_alloc_buffer_and_set_caps(enc->srcpad, @@ -389,12 +386,13 @@ static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) goto done; data = gst_adapter_peek(adapter, enc->codesize); + consumed = sbc_encode(&enc->sbc, (gpointer) data, enc->codesize, GST_BUFFER_DATA(output), GST_BUFFER_SIZE(output), NULL); if (consumed <= 0) { - GST_ERROR ("comsumed < 0, codesize: %d", + GST_DEBUG_OBJECT (enc, "comsumed < 0, codesize: %d", enc->codesize); break; } @@ -405,6 +403,7 @@ static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) GST_BUFFER_DURATION(output) = enc->frame_duration; res = gst_pad_push(enc->srcpad, output); + if (res != GST_FLOW_OK) goto done; } -- cgit From 41387ca1ae954c4b8ea99e8e4e1646198af254a7 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 20 Feb 2008 13:37:00 +0000 Subject: Fix runtime warnings of gstreamer plugin. --- audio/gstsbcenc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'audio/gstsbcenc.c') diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 03423ecf..65e3da5b 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -157,10 +157,10 @@ static GstStaticPadTemplate sbc_enc_src_factory = GST_STATIC_CAPS("audio/x-sbc, " "rate = (int) { 16000, 32000, 44100, 48000 }, " "channels = (int) [ 1, 2 ], " - "mode = (string) { mono, dual, stereo, joint }, " + "mode = (string) { \"mono\", \"dual\", \"stereo\", \"joint\" }, " "blocks = (int) { 4, 8, 12, 16 }, " "subbands = (int) { 4, 8 }, " - "allocation = (string) { snr, loudness }," + "allocation = (string) { \"snr\", \"loudness\" }, " "bitpool = (int) [ " SBC_ENC_BITPOOL_MIN_STR ", " SBC_ENC_BITPOOL_MAX_STR " ]")); -- cgit