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 "gstsbcdec.h" 33 34 GST_DEBUG_CATEGORY_STATIC(sbc_dec_debug); 35 #define GST_CAT_DEFAULT sbc_dec_debug 36 37 GST_BOILERPLATE(GstSbcDec, gst_sbc_dec, GstElement, GST_TYPE_ELEMENT); 38 39 static const GstElementDetails sbc_dec_details = 40 GST_ELEMENT_DETAILS("Bluetooth SBC decoder", 41 "Codec/Decoder/Audio", 42 "Decode a SBC audio stream", 43 "Marcel Holtmann <marcel (at) holtmann.org>"); 44 45 static GstStaticPadTemplate sbc_dec_sink_factory = 46 GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, 47 GST_STATIC_CAPS("audio/x-sbc")); 48 49 static GstStaticPadTemplate sbc_dec_src_factory = 50 GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, 51 GST_STATIC_CAPS("audio/x-raw-int, " 52 "rate = (int) { 16000, 32000, 44100, 48000 }, " 53 "channels = (int) [ 1, 2 ], " 54 "endianness = (int) BYTE_ORDER, " 55 "signed = (boolean) true, " 56 "width = (int) 16, " 57 "depth = (int) 16")); 58 59 static GstFlowReturn sbc_dec_chain(GstPad *pad, GstBuffer *buffer) 60 { 61 GstSbcDec *dec = GST_SBC_DEC(gst_pad_get_parent(pad)); 62 GstFlowReturn res = GST_FLOW_OK; 63 guint size, codesize, offset = 0; 64 guint8 *data; 65 66 codesize = sbc_get_codesize(&dec->sbc); 67 68 if (dec->buffer) { 69 GstBuffer *temp = buffer; 70 buffer = gst_buffer_span(dec->buffer, 0, buffer, 71 GST_BUFFER_SIZE(dec->buffer) + GST_BUFFER_SIZE(buffer)); 72 gst_buffer_unref(temp); 73 gst_buffer_unref(dec->buffer); 74 dec->buffer = NULL; 75 } 76 77 data = GST_BUFFER_DATA(buffer); 78 size = GST_BUFFER_SIZE(buffer); 79 80 while (offset < size) { 81 GstBuffer *output; 82 GstPadTemplate *template; 83 GstCaps *caps; 84 int consumed; 85 86 res = gst_pad_alloc_buffer_and_set_caps(dec->srcpad, 87 GST_BUFFER_OFFSET_NONE, 88 codesize, NULL, &output); 89 90 if (res != GST_FLOW_OK) 91 goto done; 92 93 consumed = sbc_decode(&dec->sbc, data + offset, size - offset, 94 GST_BUFFER_DATA(output), codesize, 95 NULL); 96 if (consumed <= 0) 97 break; 98 99 /* we will reuse the same caps object */ 100 if (dec->outcaps == NULL) { 101 caps = gst_caps_new_simple("audio/x-raw-int", 102 "rate", G_TYPE_INT, 103 gst_sbc_parse_rate_from_sbc( 104 dec->sbc.frequency), 105 "channels", G_TYPE_INT, 106 gst_sbc_get_channel_number( 107 dec->sbc.mode), 108 NULL); 109 110 template = gst_static_pad_template_get(&sbc_dec_src_factory); 111 112 dec->outcaps = gst_caps_intersect(caps, 113 gst_pad_template_get_caps(template)); 114 115 gst_caps_unref(caps); 116 } 117 118 gst_buffer_set_caps(output, dec->outcaps); 119 120 /* FIXME get a real timestamp */ 121 GST_BUFFER_TIMESTAMP(output) = GST_CLOCK_TIME_NONE; 122 123 res = gst_pad_push(dec->srcpad, output); 124 if (res != GST_FLOW_OK) 125 goto done; 126 127 offset += consumed; 128 } 129 130 if (offset < size) 131 dec->buffer = gst_buffer_create_sub(buffer, 132 offset, size - offset); 133 134 done: 135 gst_buffer_unref(buffer); 136 gst_object_unref(dec); 137 138 return res; 139 } 140 141 static GstStateChangeReturn sbc_dec_change_state(GstElement *element, 142 GstStateChange transition) 143 { 144 GstSbcDec *dec = GST_SBC_DEC(element); 145 146 switch (transition) { 147 case GST_STATE_CHANGE_READY_TO_PAUSED: 148 GST_DEBUG("Setup subband codec"); 149 if (dec->buffer) { 150 gst_buffer_unref(dec->buffer); 151 dec->buffer = NULL; 152 } 153 sbc_init(&dec->sbc, 0); 154 dec->outcaps = NULL; 155 break; 156 157 case GST_STATE_CHANGE_PAUSED_TO_READY: 158 GST_DEBUG("Finish subband codec"); 159 if (dec->buffer) { 160 gst_buffer_unref(dec->buffer); 161 dec->buffer = NULL; 162 } 163 sbc_finish(&dec->sbc); 164 if (dec->outcaps) { 165 gst_caps_unref(dec->outcaps); 166 dec->outcaps = NULL; 167 } 168 break; 169 170 default: 171 break; 172 } 173 174 return parent_class->change_state(element, transition); 175 } 176 177 static void gst_sbc_dec_base_init(gpointer g_class) 178 { 179 GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); 180 181 gst_element_class_add_pad_template(element_class, 182 gst_static_pad_template_get(&sbc_dec_sink_factory)); 183 184 gst_element_class_add_pad_template(element_class, 185 gst_static_pad_template_get(&sbc_dec_src_factory)); 186 187 gst_element_class_set_details(element_class, &sbc_dec_details); 188 } 189 190 static void gst_sbc_dec_class_init(GstSbcDecClass *klass) 191 { 192 GstElementClass *element_class = GST_ELEMENT_CLASS(klass); 193 194 parent_class = g_type_class_peek_parent(klass); 195 196 element_class->change_state = GST_DEBUG_FUNCPTR(sbc_dec_change_state); 197 198 GST_DEBUG_CATEGORY_INIT(sbc_dec_debug, "sbcdec", 0, 199 "SBC decoding element"); 200 } 201 202 static void gst_sbc_dec_init(GstSbcDec *self, GstSbcDecClass *klass) 203 { 204 self->sinkpad = gst_pad_new_from_static_template( 205 &sbc_dec_sink_factory, "sink"); 206 gst_pad_set_chain_function(self->sinkpad, GST_DEBUG_FUNCPTR( 207 sbc_dec_chain)); 208 gst_element_add_pad(GST_ELEMENT(self), self->sinkpad); 209 210 self->srcpad = gst_pad_new_from_static_template( 211 &sbc_dec_src_factory, "src"); 212 gst_element_add_pad(GST_ELEMENT(self), self->srcpad); 213 214 self->outcaps = NULL; 215 } 216 217 gboolean gst_sbc_dec_plugin_init(GstPlugin *plugin) 218 { 219 return gst_element_register(plugin, "sbcdec", GST_RANK_PRIMARY, 220 GST_TYPE_SBC_DEC); 221 } 222 223 224