bc237b850f4cc64535b70b54852a35a582c67f05
1 /* GStreamer
2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 *
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.
8 *
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.
13 *
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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19 /* Element-Checklist-Version: 5 */
22 #define PCM_BUFFER_SIZE (1152*4)
24 /*#define DEBUG_ENABLED*/
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 #include "gstac3parse.h"
30 /* struct and table stolen from ac3dec by Aaron Holtzman */
31 struct frmsize_s
32 {
33 guint16 bit_rate;
34 guint16 frm_size[3];
35 };
37 static struct frmsize_s frmsizecod_tbl[] = {
38 {32, {64, 69, 96}},
39 {32, {64, 70, 96}},
40 {40, {80, 87, 120}},
41 {40, {80, 88, 120}},
42 {48, {96, 104, 144}},
43 {48, {96, 105, 144}},
44 {56, {112, 121, 168}},
45 {56, {112, 122, 168}},
46 {64, {128, 139, 192}},
47 {64, {128, 140, 192}},
48 {80, {160, 174, 240}},
49 {80, {160, 175, 240}},
50 {96, {192, 208, 288}},
51 {96, {192, 209, 288}},
52 {112, {224, 243, 336}},
53 {112, {224, 244, 336}},
54 {128, {256, 278, 384}},
55 {128, {256, 279, 384}},
56 {160, {320, 348, 480}},
57 {160, {320, 349, 480}},
58 {192, {384, 417, 576}},
59 {192, {384, 418, 576}},
60 {224, {448, 487, 672}},
61 {224, {448, 488, 672}},
62 {256, {512, 557, 768}},
63 {256, {512, 558, 768}},
64 {320, {640, 696, 960}},
65 {320, {640, 697, 960}},
66 {384, {768, 835, 1152}},
67 {384, {768, 836, 1152}},
68 {448, {896, 975, 1344}},
69 {448, {896, 976, 1344}},
70 {512, {1024, 1114, 1536}},
71 {512, {1024, 1115, 1536}},
72 {576, {1152, 1253, 1728}},
73 {576, {1152, 1254, 1728}},
74 {640, {1280, 1393, 1920}},
75 {640, {1280, 1394, 1920}}
76 };
78 /* elementfactory information */
79 static GstElementDetails ac3parse_details = GST_ELEMENT_DETAILS ("AC3 Parser",
80 "Codec/Parser/Audio",
81 "Parses and frames AC3 audio streams, provides seek",
82 "Erik Walthinsen <omega@cse.ogi.edu>");
84 /* GstAc3Parse signals and args */
85 enum
86 {
87 /* FILL ME */
88 LAST_SIGNAL
89 };
91 enum
92 {
93 ARG_0,
94 ARG_SKIP
95 /* FILL ME */
96 };
98 static GstStaticPadTemplate gst_ac3parse_src_template =
99 GST_STATIC_PAD_TEMPLATE ("src",
100 GST_PAD_SRC,
101 GST_PAD_ALWAYS,
102 GST_STATIC_CAPS ("audio/x-ac3, "
103 "channels = (int) [ 1, 6 ], " "rate = (int) [ 32000, 48000 ]")
104 );
106 static GstStaticPadTemplate gst_ac3parse_sink_template =
107 GST_STATIC_PAD_TEMPLATE ("sink",
108 GST_PAD_SINK,
109 GST_PAD_ALWAYS,
110 GST_STATIC_CAPS ("audio/x-ac3")
111 );
113 static void gst_ac3parse_class_init (gpointer g_class);
114 static void gst_ac3parse_init (GstAc3Parse * ac3parse);
116 static void gst_ac3parse_chain (GstPad * pad, GstData * data);
118 static void gst_ac3parse_set_property (GObject * object,
119 guint prop_id, const GValue * value, GParamSpec * pspec);
120 static void gst_ac3parse_get_property (GObject * object,
121 guint prop_id, GValue * value, GParamSpec * pspec);
123 static GstElementStateReturn gst_ac3parse_change_state (GstElement * element);
125 static GstElementClass *parent_class = NULL;
127 /*static guint gst_ac3parse_signals[LAST_SIGNAL] = { 0 };*/
129 GType
130 ac3parse_get_type (void)
131 {
132 static GType ac3parse_type = 0;
134 if (!ac3parse_type) {
135 static const GTypeInfo ac3parse_info = {
136 sizeof (GstAc3ParseClass), NULL,
137 NULL,
138 (GClassInitFunc) gst_ac3parse_class_init,
139 NULL,
140 NULL,
141 sizeof (GstAc3Parse),
142 0,
143 (GInstanceInitFunc) gst_ac3parse_init,
144 };
146 ac3parse_type =
147 g_type_register_static (GST_TYPE_ELEMENT, "GstAc3Parse", &ac3parse_info,
148 0);
149 }
150 return ac3parse_type;
151 }
153 static void
154 gst_ac3parse_class_init (gpointer g_class)
155 {
156 GObjectClass *gobject_class;
157 GstElementClass *gstelement_class;
158 GstAc3ParseClass *klass;
160 klass = (GstAc3ParseClass *) g_class;
161 gobject_class = (GObjectClass *) klass;
162 gstelement_class = (GstElementClass *) klass;
164 gst_element_class_add_pad_template (gstelement_class,
165 gst_static_pad_template_get (&gst_ac3parse_src_template));
166 gst_element_class_add_pad_template (gstelement_class,
167 gst_static_pad_template_get (&gst_ac3parse_sink_template));
168 gst_element_class_set_details (gstelement_class, &ac3parse_details);
170 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SKIP, g_param_spec_int ("skip", "skip", "skip", G_MININT, G_MAXINT, 0, G_PARAM_READWRITE)); /* CHECKME */
172 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
174 gobject_class->set_property = gst_ac3parse_set_property;
175 gobject_class->get_property = gst_ac3parse_get_property;
177 gstelement_class->change_state = gst_ac3parse_change_state;
178 }
180 static void
181 gst_ac3parse_init (GstAc3Parse * ac3parse)
182 {
183 ac3parse->sinkpad =
184 gst_pad_new_from_template (gst_static_pad_template_get
185 (&gst_ac3parse_sink_template), "sink");
186 gst_element_add_pad (GST_ELEMENT (ac3parse), ac3parse->sinkpad);
187 gst_pad_set_chain_function (ac3parse->sinkpad, gst_ac3parse_chain);
189 ac3parse->srcpad =
190 gst_pad_new_from_template (gst_static_pad_template_get
191 (&gst_ac3parse_src_template), "src");
192 gst_pad_use_explicit_caps (ac3parse->srcpad);
193 gst_element_add_pad (GST_ELEMENT (ac3parse), ac3parse->srcpad);
195 ac3parse->partialbuf = NULL;
196 ac3parse->skip = 0;
198 ac3parse->sample_rate = ac3parse->channels = -1;
199 }
201 static void
202 gst_ac3parse_chain (GstPad * pad, GstData * _data)
203 {
204 GstBuffer *buf = GST_BUFFER (_data);
205 GstAc3Parse *ac3parse;
206 guchar *data;
207 glong size, offset = 0;
208 guint16 header;
209 guint8 channeldata, acmod, mask;
210 GstBuffer *outbuf = NULL;
211 gint bpf;
212 guint sample_rate = -1, channels = -1;
214 g_return_if_fail (pad != NULL);
215 g_return_if_fail (GST_IS_PAD (pad));
216 g_return_if_fail (buf != NULL);
217 /* g_return_if_fail(GST_IS_BUFFER(buf)); */
219 ac3parse = GST_AC3PARSE (GST_OBJECT_PARENT (pad));
220 GST_DEBUG ("ac3parse: received buffer of %d bytes", GST_BUFFER_SIZE (buf));
222 /* deal with partial frame from previous buffer */
223 if (ac3parse->partialbuf) {
224 GstBuffer *merge;
226 merge = gst_buffer_merge (ac3parse->partialbuf, buf);
227 gst_buffer_unref (buf);
228 gst_buffer_unref (ac3parse->partialbuf);
229 ac3parse->partialbuf = merge;
230 } else {
231 ac3parse->partialbuf = buf;
232 }
234 data = GST_BUFFER_DATA (ac3parse->partialbuf);
235 size = GST_BUFFER_SIZE (ac3parse->partialbuf);
237 /* we're searching for at least 7 bytes. first the
238 * syncinfo, where 2 bytes are for the syncword
239 * (header ID, 0x0b77), 2 bytes crc1 (checksum) and 1 byte
240 * fscod+fmrsizecod (framerate/bitrate) and then the
241 * bitstreaminfo bsid (version), bsmod (data type) and
242 * acmod (channel info, 3 bits). Then some "maybe"
243 * bits, and then the LFE indicator (subwoofer bit) */
244 while (offset < size - 6) {
245 int skipped = 0;
247 GST_DEBUG ("ac3parse: offset %ld, size %ld ", offset, size);
249 /* search for a possible start byte */
250 for (; ((data[offset] != 0x0b) && (offset < size - 6)); offset++)
251 skipped++;
252 if (skipped) {
253 fprintf (stderr, "ac3parse: **** now at %ld skipped %d bytes (FIXME?)\n",
254 offset, skipped);
255 }
256 /* construct the header word */
257 header = GUINT16_TO_BE (*((guint16 *) (data + offset)));
258 /* g_print("AC3PARSE: sync word is 0x%02X\n",header); */
259 /* if it's a valid header, go ahead and send off the frame */
260 if (header == 0x0b77) {
261 gint rate, fsize;
263 /* g_print("AC3PARSE: found sync at %d\n",offset); */
264 /* get the bits we're interested in */
265 rate = (data[offset + 4] >> 6) & 0x3;
266 switch (rate) {
267 case 0x0: /* 00b */
268 sample_rate = 48000;
269 break;
270 case 0x1: /* 01b */
271 sample_rate = 44100;
272 break;
273 case 0x2: /* 10b */
274 sample_rate = 32000;
275 break;
276 case 0x3: /* 11b */
277 default:
278 /* reserved. if this happens, we're screwed */
279 g_assert (0);
280 break;
281 }
282 fsize = data[offset + 4] & 0x3f;
283 /* calculate the bpf of the frame */
284 bpf = frmsizecod_tbl[fsize].frm_size[rate] * 2;
285 /* calculate number of channels */
286 channeldata = data[offset + 6]; /* skip bsid/bsmod */
287 acmod = (channeldata >> 5) & 0x7;
288 switch (acmod) {
289 case 0x1: /* 001b = 1 channel */
290 channels = 1;
291 break;
292 case 0x0: /* 000b = 2 independent channels */
293 case 0x2: /* 010b = 2x front (stereo) */
294 channels = 2;
295 break;
296 case 0x3: /* 011b = 3 front */
297 case 0x4: /* 100b = 2 front, 1 rear */
298 channels = 3;
299 break;
300 case 0x5: /* 101b = 3 front, 1 rear */
301 case 0x6: /* 110b = 2 front, 2 rear */
302 channels = 4;
303 break;
304 case 0x7: /* 111b = 3 front, 2 rear */
305 channels = 5;
306 break;
307 default:
308 /* whaaaaaaaaaaaaaa!!!!!!!!!!! */
309 g_assert (0);
310 }
311 /* fetch LFE bit (subwoofer) */
312 mask = 0x10;
313 if (acmod & 0x1 && acmod != 0x1) /* 3 front speakers? */
314 mask >>= 2;
315 if (acmod & 0x4) /* surround channel? */
316 mask >>= 2;
317 if (acmod == 0x2) /* 2/0 mode? */
318 mask >>= 2;
319 if (channeldata & mask) /* LFE: do we have a subwoofer channel? */
320 channels++;
321 /* if we don't have the whole frame... */
322 if ((size - offset) < bpf) {
323 GST_DEBUG ("ac3parse: partial buffer needed %ld < %d ", size - offset,
324 bpf);
325 break;
326 } else {
327 gboolean need_capsnego = FALSE;
329 outbuf = gst_buffer_create_sub (ac3parse->partialbuf, offset, bpf);
331 /* make sure our properties still match */
332 if (channels > 0 && ac3parse->channels != channels) {
333 ac3parse->channels = channels;
334 need_capsnego = TRUE;
335 }
336 if (sample_rate > 0 && ac3parse->sample_rate != sample_rate) {
337 ac3parse->sample_rate = sample_rate;
338 need_capsnego = TRUE;
339 }
340 if (need_capsnego) {
341 GstCaps *newcaps;
343 newcaps = gst_caps_new_simple ("audio/x-ac3",
344 "channels", G_TYPE_INT, channels,
345 "rate", G_TYPE_INT, sample_rate, NULL);
346 gst_pad_set_explicit_caps (ac3parse->srcpad, newcaps);
347 }
349 offset += bpf;
350 if (ac3parse->skip == 0 && GST_PAD_IS_LINKED (ac3parse->srcpad)) {
351 GST_DEBUG ("ac3parse: pushing buffer of %d bytes",
352 GST_BUFFER_SIZE (outbuf));
353 gst_pad_push (ac3parse->srcpad, GST_DATA (outbuf));
354 } else {
355 GST_DEBUG ("ac3parse: skipping buffer of %d bytes",
356 GST_BUFFER_SIZE (outbuf));
357 gst_buffer_unref (outbuf);
358 ac3parse->skip--;
359 }
360 }
361 } else {
362 offset++;
363 fprintf (stderr, "ac3parse: *** wrong header, skipping byte (FIXME?)\n");
364 }
365 }
366 /* if we have processed this block and there are still */
367 /* bytes left not in a partial block, copy them over. */
368 if (size - offset > 0) {
369 gint remainder = (size - offset);
371 GST_DEBUG ("ac3parse: partial buffer needed %d for trailing bytes",
372 remainder);
374 outbuf = gst_buffer_create_sub (ac3parse->partialbuf, offset, remainder);
375 gst_buffer_unref (ac3parse->partialbuf);
376 ac3parse->partialbuf = outbuf;
377 }
378 }
380 static void
381 gst_ac3parse_set_property (GObject * object, guint prop_id,
382 const GValue * value, GParamSpec * pspec)
383 {
384 GstAc3Parse *src;
386 g_return_if_fail (GST_IS_AC3PARSE (object));
387 src = GST_AC3PARSE (object);
389 switch (prop_id) {
390 case ARG_SKIP:
391 src->skip = g_value_get_int (value);
392 break;
393 default:
394 break;
395 }
396 }
398 static void
399 gst_ac3parse_get_property (GObject * object, guint prop_id, GValue * value,
400 GParamSpec * pspec)
401 {
402 GstAc3Parse *src;
404 g_return_if_fail (GST_IS_AC3PARSE (object));
405 src = GST_AC3PARSE (object);
407 switch (prop_id) {
408 case ARG_SKIP:
409 g_value_set_int (value, src->skip);
410 break;
411 default:
412 break;
413 }
414 }
416 static GstElementStateReturn
417 gst_ac3parse_change_state (GstElement * element)
418 {
419 GstAc3Parse *ac3parse = GST_AC3PARSE (element);
421 switch (GST_STATE_TRANSITION (element)) {
422 case GST_STATE_PAUSED_TO_READY:
423 /* reset stream info */
424 ac3parse->channels = ac3parse->sample_rate = -1;
425 break;
426 }
428 if (GST_ELEMENT_CLASS (parent_class)->change_state)
429 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
431 return GST_STATE_SUCCESS;
432 }
434 static gboolean
435 plugin_init (GstPlugin * plugin)
436 {
437 if (!gst_element_register (plugin, "ac3parse", GST_RANK_NONE,
438 GST_TYPE_AC3PARSE)) {
439 return FALSE;
440 }
442 return TRUE;
443 }
445 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
446 GST_VERSION_MINOR,
447 "ac3parse",
448 "ac3 parsing", plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN)