• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*  GStreamer SBC audio encoder
2  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
3  *  Copyright (C) 2013       Tim-Philipp Müller <tim centricular net>
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2.1 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  */
20 
21 /**
22  * SECTION:element-sbenc
23  * @title: sbenc
24  *
25  * This element encodes raw integer PCM audio into a Bluetooth SBC audio.
26  *
27  * Encoding parameters such as blocks, subbands, bitpool, channel-mode, and
28  * allocation-mode can be set by adding a capsfilter element with appropriate
29  * filtercaps after the sbcenc encoder element.
30  *
31  * ## Example pipelines
32  * |[
33  * gst-launch-1.0 -v audiotestsrc ! sbcenc ! rtpsbcpay ! udpsink
34  * ]| Encode a sine wave into SBC, RTP payload it and send over the network using UDP
35  *
36  */
37 
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41 
42 #include <string.h>
43 
44 #include "gstsbcenc.h"
45 
46 GST_DEBUG_CATEGORY_STATIC (sbc_enc_debug);
47 #define GST_CAT_DEFAULT sbc_enc_debug
48 
49 G_DEFINE_TYPE (GstSbcEnc, gst_sbc_enc, GST_TYPE_AUDIO_ENCODER);
50 GST_ELEMENT_REGISTER_DEFINE (sbcenc, "sbcenc", GST_RANK_NONE, GST_TYPE_SBC_ENC);
51 
52 static GstStaticPadTemplate sbc_enc_sink_factory =
53 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
54     GST_STATIC_CAPS ("audio/x-raw, format=" GST_AUDIO_NE (S16) ", "
55         "rate = (int) { 16000, 32000, 44100, 48000 }, "
56         "channels = (int) [ 1, 2 ]"));
57 
58 static GstStaticPadTemplate sbc_enc_src_factory =
59 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
60     GST_STATIC_CAPS ("audio/x-sbc, "
61         "rate = (int) { 16000, 32000, 44100, 48000 }, "
62         "channels = (int) [ 1, 2 ], "
63         "channel-mode = (string) { mono, dual, stereo, joint }, "
64         "blocks = (int) { 4, 8, 12, 16 }, "
65         "subbands = (int) { 4, 8 }, "
66         "allocation-method = (string) { snr, loudness }, "
67         "bitpool = (int) [ 2, 64 ]"));
68 
69 
70 static gboolean gst_sbc_enc_start (GstAudioEncoder * enc);
71 static gboolean gst_sbc_enc_stop (GstAudioEncoder * enc);
72 static gboolean gst_sbc_enc_set_format (GstAudioEncoder * enc,
73     GstAudioInfo * info);
74 static GstFlowReturn gst_sbc_enc_handle_frame (GstAudioEncoder * enc,
75     GstBuffer * buffer);
76 
77 static gboolean
gst_sbc_enc_set_format(GstAudioEncoder * audio_enc,GstAudioInfo * info)78 gst_sbc_enc_set_format (GstAudioEncoder * audio_enc, GstAudioInfo * info)
79 {
80   const gchar *allocation_method, *channel_mode;
81   GstSbcEnc *enc = GST_SBC_ENC (audio_enc);
82   GstStructure *s;
83   GstCaps *caps, *filter_caps;
84   GstCaps *output_caps = NULL;
85   guint sampleframes_per_frame;
86 
87   enc->rate = GST_AUDIO_INFO_RATE (info);
88   enc->channels = GST_AUDIO_INFO_CHANNELS (info);
89 
90   /* negotiate output format based on downstream caps restrictions */
91   caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (enc));
92 
93   if (caps == NULL)
94     caps = gst_static_pad_template_get_caps (&sbc_enc_src_factory);
95   else if (gst_caps_is_empty (caps))
96     goto failure;
97 
98   /* fixate output caps */
99   filter_caps = gst_caps_new_simple ("audio/x-sbc", "rate", G_TYPE_INT,
100       enc->rate, "channels", G_TYPE_INT, enc->channels, NULL);
101   output_caps = gst_caps_intersect (caps, filter_caps);
102   gst_caps_unref (filter_caps);
103 
104   if (output_caps == NULL || gst_caps_is_empty (output_caps)) {
105     GST_WARNING_OBJECT (enc, "Couldn't negotiate output caps with input rate "
106         "%d and input channels %d and allowed output caps %" GST_PTR_FORMAT,
107         enc->rate, enc->channels, caps);
108     goto failure;
109   }
110 
111   gst_caps_unref (caps);
112   caps = NULL;
113 
114   GST_DEBUG_OBJECT (enc, "fixating caps %" GST_PTR_FORMAT, output_caps);
115   output_caps = gst_caps_truncate (output_caps);
116   s = gst_caps_get_structure (output_caps, 0);
117   if (enc->channels == 1)
118     gst_structure_fixate_field_string (s, "channel-mode", "mono");
119   else
120     gst_structure_fixate_field_string (s, "channel-mode", "joint");
121 
122   gst_structure_fixate_field_nearest_int (s, "bitpool", 64);
123   gst_structure_fixate_field_nearest_int (s, "blocks", 16);
124   gst_structure_fixate_field_nearest_int (s, "subbands", 8);
125   gst_structure_fixate_field_string (s, "allocation-method", "loudness");
126   s = NULL;
127 
128   /* in case there's anything else left to fixate */
129   output_caps = gst_caps_fixate (output_caps);
130   gst_caps_set_simple (output_caps, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
131 
132   GST_INFO_OBJECT (enc, "output caps %" GST_PTR_FORMAT, output_caps);
133 
134   /* let's see what we fixated to */
135   s = gst_caps_get_structure (output_caps, 0);
136   gst_structure_get_int (s, "blocks", &enc->blocks);
137   gst_structure_get_int (s, "subbands", &enc->subbands);
138   gst_structure_get_int (s, "bitpool", &enc->bitpool);
139   allocation_method = gst_structure_get_string (s, "allocation-method");
140   channel_mode = gst_structure_get_string (s, "channel-mode");
141 
142   /* We want channel-mode and channels coherent */
143   if (enc->channels == 1) {
144     if (g_strcmp0 (channel_mode, "mono") != 0) {
145       GST_ERROR_OBJECT (enc, "Can't have channel-mode '%s' for 1 channel",
146           channel_mode);
147       goto failure;
148     }
149   } else {
150     if (g_strcmp0 (channel_mode, "joint") != 0 &&
151         g_strcmp0 (channel_mode, "stereo") != 0 &&
152         g_strcmp0 (channel_mode, "dual") != 0) {
153       GST_ERROR_OBJECT (enc, "Can't have channel-mode '%s' for 2 channels",
154           channel_mode);
155       goto failure;
156     }
157   }
158 
159   /* we want to be handed all available samples in handle_frame, but always
160    * enough to encode a frame */
161   sampleframes_per_frame = enc->blocks * enc->subbands;
162   gst_audio_encoder_set_frame_samples_min (audio_enc, sampleframes_per_frame);
163   gst_audio_encoder_set_frame_samples_max (audio_enc, sampleframes_per_frame);
164   gst_audio_encoder_set_frame_max (audio_enc, 0);
165 
166   /* FIXME: what to do with left-over samples at the end? can we encode them? */
167   gst_audio_encoder_set_hard_min (audio_enc, TRUE);
168 
169   /* and configure encoder based on the output caps we negotiated */
170   if (enc->rate == 16000)
171     enc->sbc.frequency = SBC_FREQ_16000;
172   else if (enc->rate == 32000)
173     enc->sbc.frequency = SBC_FREQ_32000;
174   else if (enc->rate == 44100)
175     enc->sbc.frequency = SBC_FREQ_44100;
176   else if (enc->rate == 48000)
177     enc->sbc.frequency = SBC_FREQ_48000;
178   else
179     goto failure;
180 
181   if (enc->blocks == 4)
182     enc->sbc.blocks = SBC_BLK_4;
183   else if (enc->blocks == 8)
184     enc->sbc.blocks = SBC_BLK_8;
185   else if (enc->blocks == 12)
186     enc->sbc.blocks = SBC_BLK_12;
187   else if (enc->blocks == 16)
188     enc->sbc.blocks = SBC_BLK_16;
189   else
190     goto failure;
191 
192   enc->sbc.subbands = (enc->subbands == 4) ? SBC_SB_4 : SBC_SB_8;
193   enc->sbc.bitpool = enc->bitpool;
194 
195   if (channel_mode == NULL || allocation_method == NULL)
196     goto failure;
197 
198   if (strcmp (channel_mode, "joint") == 0)
199     enc->sbc.mode = SBC_MODE_JOINT_STEREO;
200   else if (strcmp (channel_mode, "stereo") == 0)
201     enc->sbc.mode = SBC_MODE_STEREO;
202   else if (strcmp (channel_mode, "dual") == 0)
203     enc->sbc.mode = SBC_MODE_DUAL_CHANNEL;
204   else if (strcmp (channel_mode, "mono") == 0)
205     enc->sbc.mode = SBC_MODE_MONO;
206   else if (strcmp (channel_mode, "auto") == 0)
207     enc->sbc.mode = SBC_MODE_JOINT_STEREO;
208   else
209     goto failure;
210 
211   if (strcmp (allocation_method, "loudness") == 0)
212     enc->sbc.allocation = SBC_AM_LOUDNESS;
213   else if (strcmp (allocation_method, "snr") == 0)
214     enc->sbc.allocation = SBC_AM_SNR;
215   else
216     goto failure;
217 
218   if (!gst_audio_encoder_set_output_format (audio_enc, output_caps))
219     goto failure;
220 
221   return gst_audio_encoder_negotiate (audio_enc);
222 
223 failure:
224   if (output_caps)
225     gst_caps_unref (output_caps);
226   if (caps)
227     gst_caps_unref (caps);
228   return FALSE;
229 }
230 
231 static GstFlowReturn
gst_sbc_enc_handle_frame(GstAudioEncoder * audio_enc,GstBuffer * buffer)232 gst_sbc_enc_handle_frame (GstAudioEncoder * audio_enc, GstBuffer * buffer)
233 {
234   GstSbcEnc *enc = GST_SBC_ENC (audio_enc);
235   GstMapInfo in_map, out_map;
236   GstBuffer *outbuf = NULL;
237   guint samples_per_frame, frames, i = 0;
238 
239   /* no fancy draining */
240   if (buffer == NULL)
241     return GST_FLOW_OK;
242 
243   if (G_UNLIKELY (enc->channels == 0 || enc->blocks == 0 || enc->subbands == 0))
244     return GST_FLOW_NOT_NEGOTIATED;
245 
246   samples_per_frame = enc->channels * enc->blocks * enc->subbands;
247 
248   if (!gst_buffer_map (buffer, &in_map, GST_MAP_READ))
249     goto map_failed;
250 
251   frames = in_map.size / (samples_per_frame * sizeof (gint16));
252 
253   GST_LOG_OBJECT (enc,
254       "encoding %" G_GSIZE_FORMAT " samples into %u SBC frames",
255       in_map.size / (enc->channels * sizeof (gint16)), frames);
256 
257   if (frames > 0) {
258     gsize frame_len;
259 
260     frame_len = sbc_get_frame_length (&enc->sbc);
261     outbuf = gst_audio_encoder_allocate_output_buffer (audio_enc,
262         frames * frame_len);
263 
264     if (outbuf == NULL)
265       goto no_buffer;
266 
267     gst_buffer_map (outbuf, &out_map, GST_MAP_WRITE);
268 
269     for (i = 0; i < frames; ++i) {
270       gssize ret, written = 0;
271 
272       ret = sbc_encode (&enc->sbc, in_map.data + (i * samples_per_frame * 2),
273           samples_per_frame * 2, out_map.data + (i * frame_len), frame_len,
274           &written);
275 
276       if (ret < 0 || written != frame_len) {
277         GST_WARNING_OBJECT (enc, "encoding error, ret = %" G_GSSIZE_FORMAT ", "
278             "written = %" G_GSSIZE_FORMAT, ret, written);
279         break;
280       }
281     }
282 
283     gst_buffer_unmap (outbuf, &out_map);
284 
285     if (i > 0)
286       gst_buffer_set_size (outbuf, i * frame_len);
287     else
288       gst_buffer_replace (&outbuf, NULL);
289   }
290 
291   gst_buffer_unmap (buffer, &in_map);
292 
293   return gst_audio_encoder_finish_frame (audio_enc, outbuf,
294       i * (samples_per_frame / enc->channels));
295 
296 /* ERRORS */
297 no_buffer:
298   {
299     gst_buffer_unmap (buffer, &in_map);
300     GST_ELEMENT_ERROR (enc, STREAM, FAILED, (NULL),
301         ("Could not allocate output buffer"));
302     return GST_FLOW_ERROR;
303   }
304 map_failed:
305   {
306     GST_ELEMENT_ERROR (enc, STREAM, FAILED, (NULL),
307         ("Could not allocate output buffer"));
308     return GST_FLOW_ERROR;
309   }
310 }
311 
312 static gboolean
gst_sbc_enc_start(GstAudioEncoder * audio_enc)313 gst_sbc_enc_start (GstAudioEncoder * audio_enc)
314 {
315   GstSbcEnc *enc = GST_SBC_ENC (audio_enc);
316 
317   GST_INFO_OBJECT (enc, "Setup subband codec");
318   sbc_init (&enc->sbc, 0);
319 
320   return TRUE;
321 }
322 
323 static gboolean
gst_sbc_enc_stop(GstAudioEncoder * audio_enc)324 gst_sbc_enc_stop (GstAudioEncoder * audio_enc)
325 {
326   GstSbcEnc *enc = GST_SBC_ENC (audio_enc);
327 
328   GST_INFO_OBJECT (enc, "Finish subband codec");
329   sbc_finish (&enc->sbc);
330 
331   enc->subbands = 0;
332   enc->blocks = 0;
333   enc->rate = 0;
334   enc->channels = 0;
335   enc->bitpool = 0;
336 
337   return TRUE;
338 }
339 
340 static void
gst_sbc_enc_class_init(GstSbcEncClass * klass)341 gst_sbc_enc_class_init (GstSbcEncClass * klass)
342 {
343   GstAudioEncoderClass *encoder_class = GST_AUDIO_ENCODER_CLASS (klass);
344   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
345 
346   encoder_class->start = GST_DEBUG_FUNCPTR (gst_sbc_enc_start);
347   encoder_class->stop = GST_DEBUG_FUNCPTR (gst_sbc_enc_stop);
348   encoder_class->set_format = GST_DEBUG_FUNCPTR (gst_sbc_enc_set_format);
349   encoder_class->handle_frame = GST_DEBUG_FUNCPTR (gst_sbc_enc_handle_frame);
350 
351   gst_element_class_add_static_pad_template (element_class,
352       &sbc_enc_sink_factory);
353   gst_element_class_add_static_pad_template (element_class,
354       &sbc_enc_src_factory);
355 
356   gst_element_class_set_static_metadata (element_class,
357       "Bluetooth SBC audio encoder", "Codec/Encoder/Audio",
358       "Encode an SBC audio stream", "Marcel Holtmann <marcel@holtmann.org>");
359 
360   GST_DEBUG_CATEGORY_INIT (sbc_enc_debug, "sbcenc", 0, "SBC encoding element");
361 }
362 
363 static void
gst_sbc_enc_init(GstSbcEnc * self)364 gst_sbc_enc_init (GstSbcEnc * self)
365 {
366   GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (self));
367   self->subbands = 0;
368   self->blocks = 0;
369   self->rate = 0;
370   self->channels = 0;
371   self->bitpool = 0;
372 }
373