1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2010 Marcel Holtmann <marcel (at) holtmann.org> 6 * 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24 #ifdef HAVE_CONFIG_H 25 #include <config.h> 26 #endif 27 28 #include <string.h> 29 30 #include "gstpragma.h" 31 #include "gstsbcutil.h" 32 #include "gstsbcparse.h" 33 34 GST_DEBUG_CATEGORY_STATIC(sbc_parse_debug); 35 #define GST_CAT_DEFAULT sbc_parse_debug 36 37 GST_BOILERPLATE(GstSbcParse, gst_sbc_parse, GstElement, GST_TYPE_ELEMENT); 38 39 static const GstElementDetails sbc_parse_details = 40 GST_ELEMENT_DETAILS("Bluetooth SBC parser", 41 "Codec/Parser/Audio", 42 "Parse a SBC audio stream", 43 "Marcel Holtmann <marcel (at) holtmann.org>"); 44 45 static GstStaticPadTemplate sbc_parse_sink_factory = 46 GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, 47 GST_STATIC_CAPS("audio/x-sbc," 48 "parsed = (boolean) false")); 49 50 static GstStaticPadTemplate sbc_parse_src_factory = 51 GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, 52 GST_STATIC_CAPS("audio/x-sbc, " 53 "rate = (int) { 16000, 32000, 44100, 48000 }, " 54 "channels = (int) [ 1, 2 ], " 55 "mode = (string) { \"mono\", \"dual\", \"stereo\", \"joint\" }, " 56 "blocks = (int) { 4, 8, 12, 16 }, " 57 "subbands = (int) { 4, 8 }, " 58 "allocation = (string) { \"snr\", \"loudness\" }," 59 "bitpool = (int) [ 2, 64 ]," 60 "parsed = (boolean) true")); 61 62 static GstFlowReturn sbc_parse_chain(GstPad *pad, GstBuffer *buffer) 63 { 64 GstSbcParse *parse = GST_SBC_PARSE(gst_pad_get_parent(pad)); 65 GstFlowReturn res = GST_FLOW_OK; 66 guint size, offset = 0; 67 guint8 *data; 68 69 /* FIXME use a gstadpter */ 70 if (parse->buffer) { 71 GstBuffer *temp; 72 temp = buffer; 73 buffer = gst_buffer_span(parse->buffer, 0, buffer, 74 GST_BUFFER_SIZE(parse->buffer) 75 + GST_BUFFER_SIZE(buffer)); 76 gst_buffer_unref(parse->buffer); 77 gst_buffer_unref(temp); 78 parse->buffer = NULL; 79 } 80 81 data = GST_BUFFER_DATA(buffer); 82 size = GST_BUFFER_SIZE(buffer); 83 84 while (offset < size) { 85 GstBuffer *output; 86 int consumed; 87 88 consumed = sbc_parse(&parse->new_sbc, data + offset, 89 size - offset); 90 if (consumed <= 0) 91 break; 92 93 if (parse->first_parsing || (memcmp(&parse->sbc, 94 &parse->new_sbc, sizeof(sbc_t)) != 0)) { 95 96 memcpy(&parse->sbc, &parse->new_sbc, sizeof(sbc_t)); 97 if (parse->outcaps != NULL) 98 gst_caps_unref(parse->outcaps); 99 100 parse->outcaps = gst_sbc_parse_caps_from_sbc( 101 &parse->sbc); 102 103 parse->first_parsing = FALSE; 104 } 105 106 res = gst_pad_alloc_buffer_and_set_caps(parse->srcpad, 107 GST_BUFFER_OFFSET_NONE, 108 consumed, parse->outcaps, &output); 109 110 if (res != GST_FLOW_OK) 111 goto done; 112 113 memcpy(GST_BUFFER_DATA(output), data + offset, consumed); 114 115 res = gst_pad_push(parse->srcpad, output); 116 if (res != GST_FLOW_OK) 117 goto done; 118 119 offset += consumed; 120 } 121 122 if (offset < size) 123 parse->buffer = gst_buffer_create_sub(buffer, 124 offset, size - offset); 125 126 done: 127 gst_buffer_unref(buffer); 128 gst_object_unref(parse); 129 130 return res; 131 } 132 133 static GstStateChangeReturn sbc_parse_change_state(GstElement *element, 134 GstStateChange transition) 135 { 136 GstSbcParse *parse = GST_SBC_PARSE(element); 137 138 switch (transition) { 139 case GST_STATE_CHANGE_READY_TO_PAUSED: 140 GST_DEBUG("Setup subband codec"); 141 142 parse->channels = -1; 143 parse->rate = -1; 144 parse->first_parsing = TRUE; 145 146 sbc_init(&parse->sbc, 0); 147 break; 148 149 case GST_STATE_CHANGE_PAUSED_TO_READY: 150 GST_DEBUG("Finish subband codec"); 151 152 if (parse->buffer) { 153 gst_buffer_unref(parse->buffer); 154 parse->buffer = NULL; 155 } 156 if (parse->outcaps != NULL) { 157 gst_caps_unref(parse->outcaps); 158 parse->outcaps = NULL; 159 } 160 161 sbc_finish(&parse->sbc); 162 break; 163 164 default: 165 break; 166 } 167 168 return parent_class->change_state(element, transition); 169 } 170 171 static void gst_sbc_parse_base_init(gpointer g_class) 172 { 173 GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); 174 175 gst_element_class_add_pad_template(element_class, 176 gst_static_pad_template_get(&sbc_parse_sink_factory)); 177 178 gst_element_class_add_pad_template(element_class, 179 gst_static_pad_template_get(&sbc_parse_src_factory)); 180 181 gst_element_class_set_details(element_class, &sbc_parse_details); 182 } 183 184 static void gst_sbc_parse_class_init(GstSbcParseClass *klass) 185 { 186 GstElementClass *element_class = GST_ELEMENT_CLASS(klass); 187 188 parent_class = g_type_class_peek_parent(klass); 189 190 element_class->change_state = GST_DEBUG_FUNCPTR(sbc_parse_change_state); 191 192 GST_DEBUG_CATEGORY_INIT(sbc_parse_debug, "sbcparse", 0, 193 "SBC parsing element"); 194 } 195 196 static void gst_sbc_parse_init(GstSbcParse *self, GstSbcParseClass *klass) 197 { 198 self->sinkpad = gst_pad_new_from_static_template( 199 &sbc_parse_sink_factory, "sink"); 200 gst_pad_set_chain_function(self->sinkpad, 201 GST_DEBUG_FUNCPTR(sbc_parse_chain)); 202 gst_element_add_pad(GST_ELEMENT(self), self->sinkpad); 203 204 self->srcpad = gst_pad_new_from_static_template( 205 &sbc_parse_src_factory, "src"); 206 gst_element_add_pad(GST_ELEMENT(self), self->srcpad); 207 208 self->outcaps = NULL; 209 self->buffer = NULL; 210 self->channels = -1; 211 self->rate = -1; 212 self->first_parsing = TRUE; 213 } 214 215 gboolean gst_sbc_parse_plugin_init(GstPlugin *plugin) 216 { 217 return gst_element_register(plugin, "sbcparse", GST_RANK_NONE, 218 GST_TYPE_SBC_PARSE); 219 } 220 221