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));
128 GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (sbcparse));
132 gst_sbc_parse_start (GstBaseParse * parse)
134 gst_base_parse_set_min_frame_size (parse,
135 gst_sbc_calc_framelen (4, GST_SBC_CHANNEL_MODE_MONO, 4, 2));
137 gst_base_parse_set_has_timing_info (parse, FALSE);
139 gst_base_parse_set_syncable (parse, TRUE);
145 gst_sbc_parse_stop (GstBaseParse * parse)
147 gst_sbc_parse_reset (GST_SBC_PARSE (parse));
152 gst_sbc_channel_mode_get_name (GstSbcChannelMode ch_mode)
155 case GST_SBC_CHANNEL_MODE_MONO:
157 case GST_SBC_CHANNEL_MODE_DUAL:
159 case GST_SBC_CHANNEL_MODE_STEREO:
161 case GST_SBC_CHANNEL_MODE_JOINT_STEREO:
170 gst_sbc_allocation_method_get_name (GstSbcAllocationMethod alloc_method)
172 switch (alloc_method) {
173 case GST_SBC_ALLOCATION_METHOD_SNR:
175 case GST_SBC_ALLOCATION_METHOD_LOUDNESS:
184 gst_sbc_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame,
187 GstSbcParse *sbcparse = GST_SBC_PARSE (parse);
188 GstSbcAllocationMethod alloc_method = GST_SBC_ALLOCATION_METHOD_INVALID;
189 GstSbcChannelMode ch_mode = GST_SBC_CHANNEL_MODE_INVALID;
191 guint rate = 0, n_blocks = 0, n_subbands = 0, bitpool = 0;
192 gsize frame_len, next_len;
195 gst_buffer_map (frame->buffer, &map, GST_MAP_READ);
197 g_assert (map.size >= 6);
199 frame_len = gst_sbc_parse_header (map.data, &rate, &n_blocks, &ch_mode,
200 &alloc_method, &n_subbands, &bitpool);
202 GST_LOG_OBJECT (parse, "frame_len: %u", (guint) frame_len);
207 if (sbcparse->alloc_method != alloc_method
208 || sbcparse->ch_mode != ch_mode
209 || sbcparse->rate != rate
210 || sbcparse->n_blocks != n_blocks
211 || sbcparse->n_subbands != n_subbands || sbcparse->bitpool != bitpool) {
215 /* FIXME: do all of these need to be in the caps? */
216 caps = gst_caps_new_simple ("audio/x-sbc", "rate", G_TYPE_INT, rate,
217 "channels", G_TYPE_INT, (ch_mode == GST_SBC_CHANNEL_MODE_MONO) ? 1 : 2,
218 "channel-mode", G_TYPE_STRING, gst_sbc_channel_mode_get_name (ch_mode),
219 "blocks", G_TYPE_INT, n_blocks, "subbands", G_TYPE_INT, n_subbands,
220 "allocation-method", G_TYPE_STRING,
221 gst_sbc_allocation_method_get_name (alloc_method),
222 "bitpool", G_TYPE_INT, bitpool, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
224 GST_INFO_OBJECT (sbcparse, "caps changed to %" GST_PTR_FORMAT, caps);
226 gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (sbcparse),
227 gst_event_new_caps (caps));
229 avg_bitrate = (8 * frame_len * rate) / (n_subbands * n_blocks);
230 gst_base_parse_set_average_bitrate (parse, avg_bitrate);
232 gst_base_parse_set_frame_rate (parse, rate, n_subbands * n_blocks, 0, 0);
234 sbcparse->alloc_method = alloc_method;
235 sbcparse->ch_mode = ch_mode;
236 sbcparse->rate = rate;
237 sbcparse->n_blocks = n_blocks;
238 sbcparse->n_subbands = n_subbands;
239 sbcparse->bitpool = bitpool;
241 gst_caps_unref (caps);
244 if (frame_len > map.size)
247 GST_BUFFER_OFFSET (frame->buffer) = GST_BUFFER_OFFSET_NONE;
248 GST_BUFFER_OFFSET_END (frame->buffer) = GST_BUFFER_OFFSET_NONE;
250 /* completely arbitrary limit, we only process data we already have,
251 * so we aren't introducing latency here */
252 max_frames = MIN (map.size / frame_len, n_blocks * n_subbands * 5);
253 GST_LOG_OBJECT (sbcparse, "parsing up to %d frames", max_frames);
255 for (i = 1; i < max_frames; ++i) {
256 next_len = gst_sbc_parse_header (map.data + (i * frame_len), &rate,
257 &n_blocks, &ch_mode, &alloc_method, &n_subbands, &bitpool);
259 if (next_len != frame_len || sbcparse->alloc_method != alloc_method ||
260 sbcparse->ch_mode != ch_mode || sbcparse->rate != rate ||
261 sbcparse->n_blocks != n_blocks || sbcparse->n_subbands != n_subbands ||
262 sbcparse->bitpool != bitpool) {
266 GST_LOG_OBJECT (sbcparse, "packing %d SBC frames into next output buffer", i);
268 /* Note: local n_subbands and n_blocks variables might be tainted if we
269 * bailed out of the loop above because of a header configuration mismatch */
270 gst_base_parse_set_frame_rate (parse, rate,
271 sbcparse->n_subbands * sbcparse->n_blocks * i, 0, 0);
273 gst_buffer_unmap (frame->buffer, &map);
274 return gst_base_parse_finish_frame (parse, frame, i * frame_len);
278 const guint8 *possible_sync;
280 GST_DEBUG_OBJECT (parse, "no sync, resyncing");
282 possible_sync = memchr (map.data, SBC_SYNCBYTE, map.size);
284 if (possible_sync != NULL)
285 *skipsize = (gint) (possible_sync - map.data);
287 *skipsize = map.size;
289 gst_buffer_unmap (frame->buffer, &map);
291 /* we could optimise things here by looping over the data and checking
292 * whether the sync is good or not instead of handing control back to
293 * the base class just to be called again */
298 GST_LOG_OBJECT (parse,
299 "need %" G_GSIZE_FORMAT " bytes, but only have %" G_GSIZE_FORMAT,
300 frame_len, map.size);
301 gst_base_parse_set_min_frame_size (parse, frame_len);
302 gst_buffer_unmap (frame->buffer, &map);
308 remove_fields (GstCaps * caps)
312 n = gst_caps_get_size (caps);
313 for (i = 0; i < n; i++) {
314 GstStructure *s = gst_caps_get_structure (caps, i);
316 gst_structure_remove_field (s, "parsed");
321 gst_sbc_parse_get_sink_caps (GstBaseParse * parse, GstCaps * filter)
323 GstCaps *peercaps, *templ;
326 templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
328 GstCaps *fcopy = gst_caps_copy (filter);
329 /* Remove the fields we convert */
330 remove_fields (fcopy);
331 peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
332 gst_caps_unref (fcopy);
334 peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), NULL);
337 /* Remove the parsed field */
338 peercaps = gst_caps_make_writable (peercaps);
339 remove_fields (peercaps);
341 res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
342 gst_caps_unref (peercaps);
343 gst_caps_unref (templ);
349 GstCaps *intersection;
352 gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
353 gst_caps_unref (res);
360 static const guint8 crc_table[256] = {
361 0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53,
362 0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB,
363 0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E,
364 0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76,
365 0x87, 0x9A, 0xBD, 0xA0, 0xF3, 0xEE, 0xC9, 0xD4,
366 0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C,
367 0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19,
368 0xA2, 0xBF, 0x98, 0x85, 0xD6, 0xCB, 0xEC, 0xF1,
369 0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40,
370 0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8,
371 0xDE, 0xC3, 0xE4, 0xF9, 0xAA, 0xB7, 0x90, 0x8D,
372 0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65,
373 0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7,
374 0x7C, 0x61, 0x46, 0x5B, 0x08, 0x15, 0x32, 0x2F,
375 0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A,
376 0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2,
377 0x26, 0x3B, 0x1C, 0x01, 0x52, 0x4F, 0x68, 0x75,
378 0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D,
379 0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8,
380 0x03, 0x1E, 0x39, 0x24, 0x77, 0x6A, 0x4D, 0x50,
381 0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2,
382 0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A,
383 0x6C, 0x71, 0x56, 0x4B, 0x18, 0x05, 0x22, 0x3F,
384 0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7,
385 0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66,
386 0xDD, 0xC0, 0xE7, 0xFA, 0xA9, 0xB4, 0x93, 0x8E,
387 0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB,
388 0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43,
389 0xB2, 0xAF, 0x88, 0x95, 0xC6, 0xDB, 0xFC, 0xE1,
390 0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09,
391 0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C,
392 0x97, 0x8A, 0xAD, 0xB0, 0xE3, 0xFE, 0xD9, 0xC4
396 gst_sbc_calculate_crc8 (const guint8 * data, gint crc_bits)
401 while (crc_bits >= 8) {
402 crc = crc_table[crc ^ *data];
408 while (crc_bits > 0) {
409 gchar bit = ((octet ^ crc) & 0x80) >> 7;
411 crc = ((crc & 0x7f) << 1) ^ (bit ? 0x1d : 0);
421 gst_sbc_calc_framelen (guint subbands, GstSbcChannelMode ch_mode,
422 guint blocks, guint bitpool)
425 case GST_SBC_CHANNEL_MODE_MONO:
426 return 4 + (subbands * 1) / 2 + (blocks * 1 * bitpool) / 8;
427 case GST_SBC_CHANNEL_MODE_DUAL:
428 return 4 + (subbands * 2) / 2 + (blocks * 2 * bitpool) / 8;
429 case GST_SBC_CHANNEL_MODE_STEREO:
430 return 4 + (subbands * 2) / 2 + (blocks * bitpool) / 8;
431 case GST_SBC_CHANNEL_MODE_JOINT_STEREO:
432 return 4 + (subbands * 2) / 2 + (subbands + blocks * bitpool) / 8;
437 g_return_val_if_reached (0);
441 gst_sbc_parse_header (const guint8 * data, guint * rate, guint * n_blocks,
442 GstSbcChannelMode * ch_mode, GstSbcAllocationMethod * alloc_method,
443 guint * n_subbands, guint * bitpool)
445 static const guint16 sbc_rates[4] = { 16000, 32000, 44100, 48000 };
446 static const guint8 sbc_blocks[4] = { 4, 8, 12, 16 };
447 guint8 crc_data[2 + 1 + 8], crc_bits, i;
449 GST_MEMDUMP ("header", data, 8);
451 if (data[0] != SBC_SYNCBYTE)
454 *rate = sbc_rates[(data[1] >> 6) & 0x03];
455 *n_blocks = sbc_blocks[(data[1] >> 4) & 0x03];
456 *ch_mode = (GstSbcChannelMode) ((data[1] >> 2) & 0x03);
457 *alloc_method = (data[1] >> 1) & 0x01;
458 *n_subbands = (data[1] & 0x01) ? 8 : 4;
461 GST_TRACE ("rate=%u, n_blocks=%u, ch_mode=%u, alloc_method=%u, "
462 "n_subbands=%u, bitpool=%u", *rate, *n_blocks, *ch_mode, *alloc_method,
463 *n_subbands, *bitpool);
469 crc_data[0] = data[1];
470 crc_data[1] = data[2];
473 /* joint flags and RFA */
474 if (*ch_mode == GST_SBC_CHANNEL_MODE_JOINT_STEREO)
475 crc_bits += *n_subbands;
478 if (*ch_mode == GST_SBC_CHANNEL_MODE_MONO)
479 crc_bits += *n_subbands * 1 * 4;
481 crc_bits += *n_subbands * 2 * 4;
483 for (i = 16; i < crc_bits; i += 8) {
484 crc_data[i / 8] = data[1 + (i / 8) + 1];
488 crc_data[(i / 8) - 1] &= 0xF0;
491 GST_MEMDUMP ("crc bytes", crc_data, GST_ROUND_UP_8 (crc_bits) / 8);
492 if (gst_sbc_calculate_crc8 (crc_data, crc_bits) != data[3]) {
493 GST_LOG ("header CRC check failed, bits=%u, got 0x%02x, expected 0x%02x",
494 crc_bits, gst_sbc_calculate_crc8 (crc_data, crc_bits), data[3]);
498 return gst_sbc_calc_framelen (*n_subbands, *ch_mode, *n_blocks, *bitpool);
502 gst_sbc_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
504 GstSbcParse *sbcparse = GST_SBC_PARSE (parse);
506 if (!sbcparse->sent_codec_tag) {
510 taglist = gst_tag_list_new_empty ();
513 caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
514 gst_pb_utils_add_codec_description_to_tag_list (taglist,
515 GST_TAG_AUDIO_CODEC, caps);
516 gst_caps_unref (caps);
518 gst_base_parse_merge_tags (parse, taglist, GST_TAG_MERGE_REPLACE);
519 gst_tag_list_unref (taglist);
521 /* also signals the end of first-frame processing */
522 sbcparse->sent_codec_tag = TRUE;