• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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