1 /* GStreamer SBC audio parser
2 * Copyright (C) 2012 Collabora Ltd. <tim.muller@collabora.co.uk>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
25 * SECTION:element-sbcparse
26 * @see_also: sbcdec, sbcenc
28 * The sbcparse element will parse a bluetooth SBC audio stream into
29 * frames and timestamp them properly.
38 #include "gstsbcparse.h"
41 #include <gst/tag/tag.h>
42 #include <gst/audio/audio.h>
43 #include <gst/base/base.h>
44 #include <gst/pbutils/pbutils.h>
46 #define SBC_SYNCBYTE 0x9C
48 GST_DEBUG_CATEGORY_STATIC (sbcparse_debug);
49 #define GST_CAT_DEFAULT sbcparse_debug
51 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
54 GST_STATIC_CAPS ("audio/x-sbc, parsed = (boolean) true, "
55 "channels = (int) [ 1, 2 ], "
56 "rate = (int) { 16000, 32000, 44100, 48000 }")
59 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
62 GST_STATIC_CAPS ("audio/x-sbc")
65 static gboolean gst_sbc_parse_start (GstBaseParse * parse);
66 static gboolean gst_sbc_parse_stop (GstBaseParse * parse);
67 static GstFlowReturn gst_sbc_parse_handle_frame (GstBaseParse * parse,
68 GstBaseParseFrame * frame, gint * skipsize);
69 static GstFlowReturn gst_sbc_parse_pre_push_frame (GstBaseParse * parse,
70 GstBaseParseFrame * frame);
71 static GstCaps *gst_sbc_parse_get_sink_caps (GstBaseParse * parse,
74 static guint8 gst_sbc_calculate_crc8 (const guint8 * data, gint bits_crc);
75 static gsize gst_sbc_calc_framelen (guint subbands, GstSbcChannelMode ch_mode,
76 guint blocks, guint bitpool);
77 static gsize gst_sbc_parse_header (const guint8 * data, guint * rate,
78 guint * n_blocks, GstSbcChannelMode * ch_mode,
79 GstSbcAllocationMethod * alloc_method, guint * n_subbands, guint * bitpool);
81 #define parent_class gst_sbc_parse_parent_class
82 G_DEFINE_TYPE (GstSbcParse, gst_sbc_parse, GST_TYPE_BASE_PARSE);
85 gst_sbc_parse_class_init (GstSbcParseClass * klass)
87 GstBaseParseClass *baseparse_class = GST_BASE_PARSE_CLASS (klass);
88 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
90 GST_DEBUG_CATEGORY_INIT (sbcparse_debug, "sbcparse", 0, "SBC audio parser");
92 baseparse_class->start = GST_DEBUG_FUNCPTR (gst_sbc_parse_start);
93 baseparse_class->stop = GST_DEBUG_FUNCPTR (gst_sbc_parse_stop);
94 baseparse_class->pre_push_frame =
95 GST_DEBUG_FUNCPTR (gst_sbc_parse_pre_push_frame);
96 baseparse_class->handle_frame =
97 GST_DEBUG_FUNCPTR (gst_sbc_parse_handle_frame);
98 baseparse_class->get_sink_caps =
99 GST_DEBUG_FUNCPTR (gst_sbc_parse_get_sink_caps);
101 gst_element_class_add_pad_template (element_class,
102 gst_static_pad_template_get (&src_factory));
103 gst_element_class_add_pad_template (element_class,
104 gst_static_pad_template_get (&sink_factory));
106 gst_element_class_set_static_metadata (element_class, "SBC audio parser",
107 "Codec/Parser/Audio", "Parses an SBC bluetooth audio stream",
108 "Tim-Philipp Müller <tim.muller@collabora.co.uk>");
112 gst_sbc_parse_reset (GstSbcParse * sbcparse)
114 sbcparse->alloc_method = GST_SBC_ALLOCATION_METHOD_INVALID;
115 sbcparse->ch_mode = GST_SBC_CHANNEL_MODE_INVALID;
117 sbcparse->n_blocks = -1;
118 sbcparse->n_subbands = -1;
119 sbcparse->bitpool = -1;
120 sbcparse->sent_codec_tag = FALSE;
124 gst_sbc_parse_init (GstSbcParse * sbcparse)
126 gst_sbc_parse_reset (sbcparse);
127 GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (sbcparse));
131 gst_sbc_parse_start (GstBaseParse * parse)
133 gst_base_parse_set_min_frame_size (parse,
134 gst_sbc_calc_framelen (4, GST_SBC_CHANNEL_MODE_MONO, 4, 2));
136 gst_base_parse_set_has_timing_info (parse, FALSE);
138 gst_base_parse_set_syncable (parse, TRUE);
144 gst_sbc_parse_stop (GstBaseParse * parse)
146 gst_sbc_parse_reset (GST_SBC_PARSE (parse));
151 gst_sbc_channel_mode_get_name (GstSbcChannelMode ch_mode)
154 case GST_SBC_CHANNEL_MODE_MONO:
156 case GST_SBC_CHANNEL_MODE_DUAL:
158 case GST_SBC_CHANNEL_MODE_STEREO:
160 case GST_SBC_CHANNEL_MODE_JOINT_STEREO:
169 gst_sbc_allocation_method_get_name (GstSbcAllocationMethod alloc_method)
171 switch (alloc_method) {
172 case GST_SBC_ALLOCATION_METHOD_SNR:
174 case GST_SBC_ALLOCATION_METHOD_LOUDNESS:
183 gst_sbc_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame,
186 GstSbcParse *sbcparse = GST_SBC_PARSE (parse);
187 GstSbcAllocationMethod alloc_method = GST_SBC_ALLOCATION_METHOD_INVALID;
188 GstSbcChannelMode ch_mode = GST_SBC_CHANNEL_MODE_INVALID;
190 guint rate = 0, n_blocks = 0, n_subbands = 0, bitpool = 0;
191 gsize frame_len, next_len;
194 gst_buffer_map (frame->buffer, &map, GST_MAP_READ);
196 g_assert (map.size >= 6);
198 frame_len = gst_sbc_parse_header (map.data, &rate, &n_blocks, &ch_mode,
199 &alloc_method, &n_subbands, &bitpool);
201 GST_LOG_OBJECT (parse, "frame_len: %u", (guint) frame_len);
206 if (sbcparse->alloc_method != alloc_method
207 || sbcparse->ch_mode != ch_mode
208 || sbcparse->rate != rate
209 || sbcparse->n_blocks != n_blocks
210 || sbcparse->n_subbands != n_subbands || sbcparse->bitpool != bitpool) {
214 /* FIXME: do all of these need to be in the caps? */
215 caps = gst_caps_new_simple ("audio/x-sbc", "rate", G_TYPE_INT, rate,
216 "channels", G_TYPE_INT, (ch_mode == GST_SBC_CHANNEL_MODE_MONO) ? 1 : 2,
217 "channel-mode", G_TYPE_STRING, gst_sbc_channel_mode_get_name (ch_mode),
218 "blocks", G_TYPE_INT, n_blocks, "subbands", G_TYPE_INT, n_subbands,
219 "allocation-method", G_TYPE_STRING,
220 gst_sbc_allocation_method_get_name (alloc_method),
221 "bitpool", G_TYPE_INT, bitpool, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
223 GST_INFO_OBJECT (sbcparse, "caps changed to %" GST_PTR_FORMAT, caps);
225 gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (sbcparse),
226 gst_event_new_caps (caps));
228 avg_bitrate = (8 * frame_len * rate) / (n_subbands * n_blocks);
229 gst_base_parse_set_average_bitrate (parse, avg_bitrate);
231 gst_base_parse_set_frame_rate (parse, rate, n_subbands * n_blocks, 0, 0);
233 sbcparse->alloc_method = alloc_method;
234 sbcparse->ch_mode = ch_mode;
235 sbcparse->rate = rate;
236 sbcparse->n_blocks = n_blocks;
237 sbcparse->n_subbands = n_subbands;
238 sbcparse->bitpool = bitpool;
240 gst_caps_unref (caps);
243 if (frame_len > map.size)
246 GST_BUFFER_OFFSET (frame->buffer) = GST_BUFFER_OFFSET_NONE;
247 GST_BUFFER_OFFSET_END (frame->buffer) = GST_BUFFER_OFFSET_NONE;
249 /* completely arbitrary limit, we only process data we already have,
250 * so we aren't introducing latency here */
251 max_frames = MIN (map.size / frame_len, n_blocks * n_subbands * 5);
252 GST_LOG_OBJECT (sbcparse, "parsing up to %d frames", max_frames);
254 for (i = 1; i < max_frames; ++i) {
255 next_len = gst_sbc_parse_header (map.data + (i * frame_len), &rate,
256 &n_blocks, &ch_mode, &alloc_method, &n_subbands, &bitpool);
258 if (next_len != frame_len || sbcparse->alloc_method != alloc_method ||
259 sbcparse->ch_mode != ch_mode || sbcparse->rate != rate ||
260 sbcparse->n_blocks != n_blocks || sbcparse->n_subbands != n_subbands ||
261 sbcparse->bitpool != bitpool) {
265 GST_LOG_OBJECT (sbcparse, "packing %d SBC frames into next output buffer", i);
267 /* Note: local n_subbands and n_blocks variables might be tainted if we
268 * bailed out of the loop above because of a header configuration mismatch */
269 gst_base_parse_set_frame_rate (parse, rate,
270 sbcparse->n_subbands * sbcparse->n_blocks * i, 0, 0);
272 gst_buffer_unmap (frame->buffer, &map);
273 return gst_base_parse_finish_frame (parse, frame, i * frame_len);
277 const guint8 *possible_sync;
279 GST_DEBUG_OBJECT (parse, "no sync, resyncing");
281 possible_sync = memchr (map.data, SBC_SYNCBYTE, map.size);
283 if (possible_sync != NULL)
284 *skipsize = (gint) (possible_sync - map.data);
286 *skipsize = map.size;
288 gst_buffer_unmap (frame->buffer, &map);
290 /* we could optimise things here by looping over the data and checking
291 * whether the sync is good or not instead of handing control back to
292 * the base class just to be called again */
297 GST_LOG_OBJECT (parse,
298 "need %" G_GSIZE_FORMAT " bytes, but only have %" G_GSIZE_FORMAT,
299 frame_len, map.size);
300 gst_base_parse_set_min_frame_size (parse, frame_len);
301 gst_buffer_unmap (frame->buffer, &map);
307 remove_fields (GstCaps * caps)
311 n = gst_caps_get_size (caps);
312 for (i = 0; i < n; i++) {
313 GstStructure *s = gst_caps_get_structure (caps, i);
315 gst_structure_remove_field (s, "parsed");
320 gst_sbc_parse_get_sink_caps (GstBaseParse * parse, GstCaps * filter)
322 GstCaps *peercaps, *templ;
325 templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
327 GstCaps *fcopy = gst_caps_copy (filter);
328 /* Remove the fields we convert */
329 remove_fields (fcopy);
330 peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
331 gst_caps_unref (fcopy);
333 peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), NULL);
336 /* Remove the parsed field */
337 peercaps = gst_caps_make_writable (peercaps);
338 remove_fields (peercaps);
340 res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
341 gst_caps_unref (peercaps);
342 gst_caps_unref (templ);
348 GstCaps *intersection;
351 gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
352 gst_caps_unref (res);
359 static const guint8 crc_table[256] = {
360 0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53,
361 0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB,
362 0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E,
363 0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76,
364 0x87, 0x9A, 0xBD, 0xA0, 0xF3, 0xEE, 0xC9, 0xD4,
365 0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C,
366 0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19,
367 0xA2, 0xBF, 0x98, 0x85, 0xD6, 0xCB, 0xEC, 0xF1,
368 0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40,
369 0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8,
370 0xDE, 0xC3, 0xE4, 0xF9, 0xAA, 0xB7, 0x90, 0x8D,
371 0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65,
372 0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7,
373 0x7C, 0x61, 0x46, 0x5B, 0x08, 0x15, 0x32, 0x2F,
374 0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A,
375 0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2,
376 0x26, 0x3B, 0x1C, 0x01, 0x52, 0x4F, 0x68, 0x75,
377 0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D,
378 0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8,
379 0x03, 0x1E, 0x39, 0x24, 0x77, 0x6A, 0x4D, 0x50,
380 0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2,
381 0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A,
382 0x6C, 0x71, 0x56, 0x4B, 0x18, 0x05, 0x22, 0x3F,
383 0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7,
384 0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66,
385 0xDD, 0xC0, 0xE7, 0xFA, 0xA9, 0xB4, 0x93, 0x8E,
386 0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB,
387 0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43,
388 0xB2, 0xAF, 0x88, 0x95, 0xC6, 0xDB, 0xFC, 0xE1,
389 0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09,
390 0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C,
391 0x97, 0x8A, 0xAD, 0xB0, 0xE3, 0xFE, 0xD9, 0xC4
395 gst_sbc_calculate_crc8 (const guint8 * data, gint crc_bits)
400 while (crc_bits >= 8) {
401 crc = crc_table[crc ^ *data];
407 while (crc_bits > 0) {
408 gchar bit = ((octet ^ crc) & 0x80) >> 7;
410 crc = ((crc & 0x7f) << 1) ^ (bit ? 0x1d : 0);
420 gst_sbc_calc_framelen (guint subbands, GstSbcChannelMode ch_mode,
421 guint blocks, guint bitpool)
424 case GST_SBC_CHANNEL_MODE_MONO:
425 return 4 + (subbands * 1) / 2 + (blocks * 1 * bitpool) / 8;
426 case GST_SBC_CHANNEL_MODE_DUAL:
427 return 4 + (subbands * 2) / 2 + (blocks * 2 * bitpool) / 8;
428 case GST_SBC_CHANNEL_MODE_STEREO:
429 return 4 + (subbands * 2) / 2 + (blocks * bitpool) / 8;
430 case GST_SBC_CHANNEL_MODE_JOINT_STEREO:
431 return 4 + (subbands * 2) / 2 + (subbands + blocks * bitpool) / 8;
436 g_return_val_if_reached (0);
440 gst_sbc_parse_header (const guint8 * data, guint * rate, guint * n_blocks,
441 GstSbcChannelMode * ch_mode, GstSbcAllocationMethod * alloc_method,
442 guint * n_subbands, guint * bitpool)
444 static const guint16 sbc_rates[4] = { 16000, 32000, 44100, 48000 };
445 static const guint8 sbc_blocks[4] = { 4, 8, 12, 16 };
446 guint8 crc_data[2 + 1 + 8], crc_bits, i;
448 GST_MEMDUMP ("header", data, 8);
450 if (data[0] != SBC_SYNCBYTE)
453 *rate = sbc_rates[(data[1] >> 6) & 0x03];
454 *n_blocks = sbc_blocks[(data[1] >> 4) & 0x03];
455 *ch_mode = (GstSbcChannelMode) ((data[1] >> 2) & 0x03);
456 *alloc_method = (data[1] >> 1) & 0x01;
457 *n_subbands = (data[1] & 0x01) ? 8 : 4;
460 GST_TRACE ("rate=%u, n_blocks=%u, ch_mode=%u, alloc_method=%u, "
461 "n_subbands=%u, bitpool=%u", *rate, *n_blocks, *ch_mode, *alloc_method,
462 *n_subbands, *bitpool);
468 crc_data[0] = data[1];
469 crc_data[1] = data[2];
472 /* joint flags and RFA */
473 if (*ch_mode == GST_SBC_CHANNEL_MODE_JOINT_STEREO)
474 crc_bits += *n_subbands;
477 if (*ch_mode == GST_SBC_CHANNEL_MODE_MONO)
478 crc_bits += *n_subbands * 1 * 4;
480 crc_bits += *n_subbands * 2 * 4;
482 for (i = 16; i < crc_bits; i += 8) {
483 crc_data[i / 8] = data[1 + (i / 8) + 1];
487 crc_data[(i / 8) - 1] &= 0xF0;
490 GST_MEMDUMP ("crc bytes", crc_data, GST_ROUND_UP_8 (crc_bits) / 8);
491 if (gst_sbc_calculate_crc8 (crc_data, crc_bits) != data[3]) {
492 GST_LOG ("header CRC check failed, bits=%u, got 0x%02x, expected 0x%02x",
493 crc_bits, gst_sbc_calculate_crc8 (crc_data, crc_bits), data[3]);
497 return gst_sbc_calc_framelen (*n_subbands, *ch_mode, *n_blocks, *bitpool);
501 gst_sbc_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
503 GstSbcParse *sbcparse = GST_SBC_PARSE (parse);
505 if (!sbcparse->sent_codec_tag) {
509 taglist = gst_tag_list_new_empty ();
512 caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
513 gst_pb_utils_add_codec_description_to_tag_list (taglist,
514 GST_TAG_AUDIO_CODEC, caps);
515 gst_caps_unref (caps);
517 gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (sbcparse),
518 gst_event_new_tag (taglist));
520 /* also signals the end of first-frame processing */
521 sbcparse->sent_codec_tag = TRUE;