1 /* GStreamer SBC audio decoder
2 *
3 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
4 * Copyright (C) 2013 Tim-Philipp Müller <tim centricular net>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22 /**
23 * SECTION:element-sbdec
24 * @title: sbdec
25 *
26 * This element decodes a Bluetooth SBC audio streams to raw integer PCM audio
27 *
28 * ## Example pipelines
29 * |[
30 * gst-launch-1.0 -v filesrc location=audio.sbc ! sbcparse ! sbcdec ! audioconvert ! audioresample ! autoaudiosink
31 * ]| Decode a raw SBC file.
32 *
33 */
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include <string.h>
40
41 #include "gstsbcdec.h"
42
43 /* FIXME: where does this come from? how is it derived? */
44 #define BUF_SIZE 8192
45
46 GST_DEBUG_CATEGORY_STATIC (sbc_dec_debug);
47 #define GST_CAT_DEFAULT sbc_dec_debug
48
49 #define parent_class gst_sbc_dec_parent_class
50 G_DEFINE_TYPE (GstSbcDec, gst_sbc_dec, GST_TYPE_AUDIO_DECODER);
51 GST_ELEMENT_REGISTER_DEFINE (sbcdec, "sbcdec", GST_RANK_PRIMARY,
52 GST_TYPE_SBC_DEC);
53
54 static GstStaticPadTemplate sbc_dec_sink_factory =
55 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
56 GST_STATIC_CAPS ("audio/x-sbc, channels = (int) [ 1, 2 ], "
57 "rate = (int) { 16000, 32000, 44100, 48000 }, "
58 "parsed = (boolean) true"));
59
60 static GstStaticPadTemplate sbc_dec_src_factory =
61 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
62 GST_STATIC_CAPS ("audio/x-raw, format=" GST_AUDIO_NE (S16) ", "
63 "rate = (int) { 16000, 32000, 44100, 48000 }, "
64 "channels = (int) [ 1, 2 ], layout=interleaved"));
65
66 static GstFlowReturn
gst_sbc_dec_handle_frame(GstAudioDecoder * audio_dec,GstBuffer * buf)67 gst_sbc_dec_handle_frame (GstAudioDecoder * audio_dec, GstBuffer * buf)
68 {
69 GstSbcDec *dec = GST_SBC_DEC (audio_dec);
70 GstBuffer *outbuf = NULL;
71 GstMapInfo out_map;
72 GstMapInfo in_map;
73 gsize output_size;
74 guint num_frames, i;
75
76 /* no fancy draining */
77 if (G_UNLIKELY (buf == NULL))
78 return GST_FLOW_OK;
79
80 gst_buffer_map (buf, &in_map, GST_MAP_READ);
81
82 if (G_UNLIKELY (in_map.size == 0))
83 goto done;
84
85 /* we assume all frames are of the same size, this is implied by the
86 * input caps applying to the whole input buffer, and the parser should
87 * also have made sure of that */
88 if (G_UNLIKELY (in_map.size % dec->frame_len != 0))
89 goto mixed_frames;
90
91 num_frames = in_map.size / dec->frame_len;
92 output_size = num_frames * dec->samples_per_frame * sizeof (gint16);
93
94 outbuf = gst_audio_decoder_allocate_output_buffer (audio_dec, output_size);
95
96 if (outbuf == NULL)
97 goto no_buffer;
98
99 gst_buffer_map (outbuf, &out_map, GST_MAP_WRITE);
100
101 for (i = 0; i < num_frames; ++i) {
102 gssize ret;
103 gsize written;
104
105 ret = sbc_decode (&dec->sbc, in_map.data + (i * dec->frame_len),
106 dec->frame_len, out_map.data + (i * dec->samples_per_frame * 2),
107 dec->samples_per_frame * 2, &written);
108
109 if (ret <= 0 || written != (dec->samples_per_frame * 2)) {
110 GST_WARNING_OBJECT (dec, "decoding error, ret = %" G_GSSIZE_FORMAT ", "
111 "written = %" G_GSSIZE_FORMAT, ret, written);
112 break;
113 }
114 }
115
116 gst_buffer_unmap (outbuf, &out_map);
117
118 if (i > 0)
119 gst_buffer_set_size (outbuf, i * dec->samples_per_frame * 2);
120 else
121 gst_buffer_replace (&outbuf, NULL);
122
123 done:
124
125 gst_buffer_unmap (buf, &in_map);
126
127 return gst_audio_decoder_finish_frame (audio_dec, outbuf, 1);
128
129 /* ERRORS */
130 mixed_frames:
131 {
132 GST_WARNING_OBJECT (dec, "inconsistent input data/frames, skipping");
133 goto done;
134 }
135 no_buffer:
136 {
137 GST_ERROR_OBJECT (dec, "could not allocate output buffer");
138 goto done;
139 }
140 }
141
142 static gboolean
gst_sbc_dec_set_format(GstAudioDecoder * audio_dec,GstCaps * caps)143 gst_sbc_dec_set_format (GstAudioDecoder * audio_dec, GstCaps * caps)
144 {
145 GstSbcDec *dec = GST_SBC_DEC (audio_dec);
146 const gchar *channel_mode;
147 GstAudioInfo info;
148 GstStructure *s;
149 gint channels, rate, subbands, blocks, bitpool;
150
151 s = gst_caps_get_structure (caps, 0);
152 gst_structure_get_int (s, "channels", &channels);
153 gst_structure_get_int (s, "rate", &rate);
154
155 /* save input format */
156 channel_mode = gst_structure_get_string (s, "channel-mode");
157 if (channel_mode == NULL ||
158 !gst_structure_get_int (s, "subbands", &subbands) ||
159 !gst_structure_get_int (s, "blocks", &blocks) ||
160 !gst_structure_get_int (s, "bitpool", &bitpool))
161 return FALSE;
162
163 if (strcmp (channel_mode, "mono") == 0) {
164 dec->frame_len = 4 + (subbands * 1) / 2 + ((blocks * 1 * bitpool) + 7) / 8;
165 } else if (strcmp (channel_mode, "dual") == 0) {
166 dec->frame_len = 4 + (subbands * 2) / 2 + ((blocks * 2 * bitpool) + 7) / 8;
167 } else if (strcmp (channel_mode, "stereo") == 0) {
168 dec->frame_len = 4 + (subbands * 2) / 2 + ((blocks * bitpool) + 7) / 8;
169 } else if (strcmp (channel_mode, "joint") == 0) {
170 dec->frame_len =
171 4 + (subbands * 2) / 2 + ((subbands + blocks * bitpool) + 7) / 8;
172 } else {
173 return FALSE;
174 }
175
176 dec->samples_per_frame = channels * blocks * subbands;
177
178 GST_INFO_OBJECT (dec, "frame len: %" G_GSIZE_FORMAT ", samples per frame "
179 "%" G_GSIZE_FORMAT, dec->frame_len, dec->samples_per_frame);
180
181 /* set up output format */
182 gst_audio_info_init (&info);
183 gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, rate, channels, NULL);
184 gst_audio_decoder_set_output_format (audio_dec, &info);
185
186 return TRUE;
187 }
188
189 static gboolean
gst_sbc_dec_start(GstAudioDecoder * dec)190 gst_sbc_dec_start (GstAudioDecoder * dec)
191 {
192 GstSbcDec *sbcdec = GST_SBC_DEC (dec);
193
194 GST_INFO_OBJECT (dec, "Setup subband codec");
195 sbc_init (&sbcdec->sbc, 0);
196
197 return TRUE;
198 }
199
200 static gboolean
gst_sbc_dec_stop(GstAudioDecoder * dec)201 gst_sbc_dec_stop (GstAudioDecoder * dec)
202 {
203 GstSbcDec *sbcdec = GST_SBC_DEC (dec);
204
205 GST_INFO_OBJECT (sbcdec, "Finish subband codec");
206 sbc_finish (&sbcdec->sbc);
207 sbcdec->samples_per_frame = 0;
208 sbcdec->frame_len = 0;
209
210 return TRUE;
211 }
212
213 static void
gst_sbc_dec_class_init(GstSbcDecClass * klass)214 gst_sbc_dec_class_init (GstSbcDecClass * klass)
215 {
216 GstAudioDecoderClass *audio_decoder_class = (GstAudioDecoderClass *) klass;
217 GstElementClass *element_class = (GstElementClass *) klass;
218
219 audio_decoder_class->start = GST_DEBUG_FUNCPTR (gst_sbc_dec_start);
220 audio_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_sbc_dec_stop);
221 audio_decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_sbc_dec_set_format);
222 audio_decoder_class->handle_frame =
223 GST_DEBUG_FUNCPTR (gst_sbc_dec_handle_frame);
224
225 gst_element_class_add_static_pad_template (element_class,
226 &sbc_dec_sink_factory);
227 gst_element_class_add_static_pad_template (element_class,
228 &sbc_dec_src_factory);
229
230 gst_element_class_set_static_metadata (element_class,
231 "Bluetooth SBC audio decoder", "Codec/Decoder/Audio",
232 "Decode an SBC audio stream", "Marcel Holtmann <marcel@holtmann.org>");
233
234 GST_DEBUG_CATEGORY_INIT (sbc_dec_debug, "sbcdec", 0, "SBC decoding element");
235 }
236
237 static void
gst_sbc_dec_init(GstSbcDec * dec)238 gst_sbc_dec_init (GstSbcDec * dec)
239 {
240 gst_audio_decoder_set_needs_format (GST_AUDIO_DECODER (dec), TRUE);
241 gst_audio_decoder_set_use_default_pad_acceptcaps (GST_AUDIO_DECODER_CAST
242 (dec), TRUE);
243 GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_DECODER_SINK_PAD (dec));
244
245 dec->samples_per_frame = 0;
246 dec->frame_len = 0;
247 }
248