be7a1dd6d1260fa40aa714bd6c4586b26d0890c9
1 /* GStreamer
2 * Copyright (C) <2001> David I. Lehn <dlehn@users.sourceforge.net>
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 */
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include <string.h>
26 #include <stdlib.h>
28 #ifdef HAVE_STDINT_H
29 #include <stdint.h>
30 #else
31 /* (Ronald) hacky... can't include stdint.h because it's not available
32 * everywhere. however, a52dec wants uint8_t/uint32_t... how? */
33 #ifndef __uint8_t_defined
34 #define __uint8_t_defined
35 typedef guint8 uint8_t;
36 #endif
38 #ifndef __uint32_t_defined
39 #define __uint32_t_defined
40 typedef guint32 uint32_t;
41 #endif
42 /* grosj... but it works (tm) */
43 #endif /* HAVE_STDINT_H */
45 #include <gst/gst.h>
46 #include <a52dec/a52.h>
47 #include <a52dec/mm_accel.h>
48 #include "gsta52dec.h"
50 /* elementfactory information */
51 static GstElementDetails gst_a52dec_details = {
52 "ATSC A/52 audio decoder",
53 "Codec/Audio/Decoder",
54 "Decodes ATSC A/52 encoded audio streams",
55 "David I. Lehn <dlehn@users.sourceforge.net>",
56 };
59 /* A52Dec signals and args */
60 enum
61 {
62 /* FILL ME */
63 LAST_SIGNAL
64 };
66 enum
67 {
68 ARG_0,
69 ARG_DRC,
70 ARG_STREAMINFO
71 };
73 /*
74 * "audio/a52" and "audio/ac3" are the same format. The name
75 * "ac3" is now deprecated and should not be used in new code.
76 */
77 GST_PAD_TEMPLATE_FACTORY (sink_factory,
78 "sink",
79 GST_PAD_SINK,
80 GST_PAD_ALWAYS,
81 GST_CAPS_NEW (
82 "a52dec_sink",
83 "audio/x-ac3",
84 NULL
85 )
86 );
88 GST_PAD_TEMPLATE_FACTORY (src_factory,
89 "src",
90 GST_PAD_SRC,
91 GST_PAD_ALWAYS,
92 GST_CAPS_NEW (
93 "a52dec_src",
94 "audio/x-raw-int",
95 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
96 "signed", GST_PROPS_BOOLEAN (TRUE),
97 "width", GST_PROPS_INT (16),
98 "depth", GST_PROPS_INT (16),
99 "rate", GST_PROPS_INT_RANGE (4000, 48000),
100 "channels", GST_PROPS_INT_RANGE (1, 6)
101 )
102 );
104 static void gst_a52dec_base_init (gpointer g_class);
105 static void gst_a52dec_class_init (GstA52DecClass * klass);
106 static void gst_a52dec_init (GstA52Dec * a52dec);
108 static void gst_a52dec_loop (GstElement * element);
109 static GstElementStateReturn
110 gst_a52dec_change_state (GstElement * element);
112 static void gst_a52dec_set_property (GObject * object, guint prop_id,
113 const GValue * value, GParamSpec * pspec);
114 static void gst_a52dec_get_property (GObject * object, guint prop_id,
115 GValue * value, GParamSpec * pspec);
117 static GstElementClass *parent_class = NULL;
118 /* static guint gst_a52dec_signals[LAST_SIGNAL] = { 0 }; */
120 GType
121 gst_a52dec_get_type (void)
122 {
123 static GType a52dec_type = 0;
125 if (!a52dec_type) {
126 static const GTypeInfo a52dec_info = {
127 sizeof (GstA52DecClass),
128 gst_a52dec_base_init,
129 NULL, (GClassInitFunc) gst_a52dec_class_init,
130 NULL,
131 NULL,
132 sizeof (GstA52Dec),
133 0,
134 (GInstanceInitFunc) gst_a52dec_init,
135 };
137 a52dec_type = g_type_register_static (GST_TYPE_ELEMENT, "GstA52Dec", &a52dec_info, 0);
138 }
139 return a52dec_type;
140 }
142 static void
143 gst_a52dec_base_init (gpointer g_class)
144 {
145 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
147 gst_element_class_add_pad_template (element_class,
148 GST_PAD_TEMPLATE_GET (sink_factory));
149 gst_element_class_add_pad_template (element_class,
150 GST_PAD_TEMPLATE_GET (src_factory));
151 gst_element_class_set_details (element_class, &gst_a52dec_details);
152 }
154 static void
155 gst_a52dec_class_init (GstA52DecClass * klass)
156 {
157 GObjectClass *gobject_class;
158 GstElementClass *gstelement_class;
160 gobject_class = (GObjectClass *) klass;
161 gstelement_class = (GstElementClass *) klass;
163 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
164 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DRC,
165 g_param_spec_boolean ("drc", "Dynamic Range Compression",
166 "Use Dynamic Range Compression", FALSE,
167 G_PARAM_READWRITE));
168 g_object_class_install_property (gobject_class, ARG_STREAMINFO,
169 g_param_spec_boxed ("streaminfo", "Streaminfo", "Streaminfo",
170 GST_TYPE_CAPS, G_PARAM_READABLE));
172 gobject_class->set_property = gst_a52dec_set_property;
173 gobject_class->get_property = gst_a52dec_get_property;
175 gstelement_class->change_state = gst_a52dec_change_state;
176 }
178 static void
179 gst_a52dec_init (GstA52Dec * a52dec)
180 {
181 /* create the sink and src pads */
182 a52dec->sinkpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET (sink_factory), "sink");
183 gst_element_add_pad (GST_ELEMENT (a52dec), a52dec->sinkpad);
184 gst_element_set_loop_function ((GstElement *) a52dec, gst_a52dec_loop);
186 a52dec->srcpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET (src_factory), "src");
187 gst_element_add_pad (GST_ELEMENT (a52dec), a52dec->srcpad);
189 a52dec->dynamic_range_compression = FALSE;
190 a52dec->streaminfo = NULL;
191 }
193 /* BEGIN modified a52dec conversion code */
195 static inline int16_t
196 convert (int32_t i)
197 {
198 if (i > 0x43c07fff)
199 return 32767;
200 else if (i < 0x43bf8000)
201 return -32768;
202 else
203 return i - 0x43c00000;
204 }
206 static inline void
207 float_to_int (float *_f, int16_t * s16, int flags)
208 {
209 int i;
210 int32_t *f = (int32_t *) _f;
212 switch (flags) {
213 case A52_MONO:
214 for (i = 0; i < 256; i++) {
215 s16[5 * i] = s16[5 * i + 1] = s16[5 * i + 2] = s16[5 * i + 3] = 0;
216 s16[5 * i + 4] = convert (f[i]);
217 }
218 break;
219 case A52_CHANNEL:
220 case A52_STEREO:
221 case A52_DOLBY:
222 for (i = 0; i < 256; i++) {
223 s16[2 * i] = convert (f[i]);
224 s16[2 * i + 1] = convert (f[i + 256]);
225 }
226 break;
227 case A52_3F:
228 for (i = 0; i < 256; i++) {
229 s16[5 * i] = convert (f[i]);
230 s16[5 * i + 1] = convert (f[i + 512]);
231 s16[5 * i + 2] = s16[5 * i + 3] = 0;
232 s16[5 * i + 4] = convert (f[i + 256]);
233 }
234 break;
235 case A52_2F2R:
236 for (i = 0; i < 256; i++) {
237 s16[4 * i] = convert (f[i]);
238 s16[4 * i + 1] = convert (f[i + 256]);
239 s16[4 * i + 2] = convert (f[i + 512]);
240 s16[4 * i + 3] = convert (f[i + 768]);
241 }
242 break;
243 case A52_3F2R:
244 for (i = 0; i < 256; i++) {
245 s16[5 * i] = convert (f[i]);
246 s16[5 * i + 1] = convert (f[i + 512]);
247 s16[5 * i + 2] = convert (f[i + 768]);
248 s16[5 * i + 3] = convert (f[i + 1024]);
249 s16[5 * i + 4] = convert (f[i + 256]);
250 }
251 break;
252 case A52_MONO | A52_LFE:
253 for (i = 0; i < 256; i++) {
254 s16[6 * i] = s16[6 * i + 1] = s16[6 * i + 2] = s16[6 * i + 3] = 0;
255 s16[6 * i + 4] = convert (f[i + 256]);
256 s16[6 * i + 5] = convert (f[i]);
257 }
258 break;
259 case A52_CHANNEL | A52_LFE:
260 case A52_STEREO | A52_LFE:
261 case A52_DOLBY | A52_LFE:
262 for (i = 0; i < 256; i++) {
263 s16[6 * i] = convert (f[i + 256]);
264 s16[6 * i + 1] = convert (f[i + 512]);
265 s16[6 * i + 2] = s16[6 * i + 3] = s16[6 * i + 4] = 0;
266 s16[6 * i + 5] = convert (f[i]);
267 }
268 break;
269 case A52_3F | A52_LFE:
270 for (i = 0; i < 256; i++) {
271 s16[6 * i] = convert (f[i + 256]);
272 s16[6 * i + 1] = convert (f[i + 768]);
273 s16[6 * i + 2] = s16[6 * i + 3] = 0;
274 s16[6 * i + 4] = convert (f[i + 512]);
275 s16[6 * i + 5] = convert (f[i]);
276 }
277 break;
278 case A52_2F2R | A52_LFE:
279 for (i = 0; i < 256; i++) {
280 s16[6 * i] = convert (f[i + 256]);
281 s16[6 * i + 1] = convert (f[i + 512]);
282 s16[6 * i + 2] = convert (f[i + 768]);
283 s16[6 * i + 3] = convert (f[i + 1024]);
284 s16[6 * i + 4] = 0;
285 s16[6 * i + 5] = convert (f[i]);
286 }
287 break;
288 case A52_3F2R | A52_LFE:
289 for (i = 0; i < 256; i++) {
290 s16[6 * i] = convert (f[i + 256]);
291 s16[6 * i + 1] = convert (f[i + 768]);
292 s16[6 * i + 2] = convert (f[i + 1024]);
293 s16[6 * i + 3] = convert (f[i + 1280]);
294 s16[6 * i + 4] = convert (f[i + 512]);
295 s16[6 * i + 5] = convert (f[i]);
296 }
297 break;
298 }
299 }
301 static int
302 gst_a52dec_channels (int flags)
303 {
304 int chans = 0;
306 if (flags & A52_LFE) {
307 chans += 1;
308 }
309 flags &= A52_CHANNEL_MASK;
310 switch (flags) {
311 case A52_3F2R:
312 chans += 5;
313 break;
314 case A52_2F2R:
315 case A52_3F1R:
316 chans += 4;
317 break;
318 case A52_2F1R:
319 case A52_3F:
320 chans += 3;
321 case A52_CHANNEL:
322 case A52_STEREO:
323 case A52_DOLBY:
324 chans += 2;
325 break;
326 default:
327 /* error */
328 g_warning ("a52dec invalid flags %d", flags);
329 return 0;
330 }
331 return chans;
332 }
334 static int
335 gst_a52dec_push (GstPad * srcpad, int flags, sample_t * _samples, gint64 timestamp)
336 {
337 GstBuffer *buf;
338 int chans;
340 #ifdef LIBA52_DOUBLE
341 float samples[256 * 6];
342 int i;
344 for (i = 0; i < 256 * 6; i++)
345 samples[i] = _samples[i];
346 #else
347 float *samples = _samples;
348 #endif
350 flags &= A52_CHANNEL_MASK | A52_LFE;
352 chans = gst_a52dec_channels (flags);
353 if (!chans) {
354 return 1;
355 }
357 buf = gst_buffer_new ();
358 GST_BUFFER_SIZE (buf) = sizeof (int16_t) * 256 * chans;
359 GST_BUFFER_DATA (buf) = g_malloc (GST_BUFFER_SIZE (buf));
360 GST_BUFFER_TIMESTAMP (buf) = timestamp;
361 float_to_int (samples, (int16_t *) GST_BUFFER_DATA (buf), flags);
363 gst_pad_push (srcpad, GST_DATA (buf));
365 return 0;
366 }
368 /* END modified a52dec conversion code */
370 static void
371 gst_a52dec_reneg (GstPad * pad, int channels, int rate)
372 {
373 GST_INFO ( "a52dec: reneg channels:%d rate:%d\n", channels, rate);
375 if (gst_pad_try_set_caps (pad,
376 GST_CAPS_NEW ("a52dec_src_caps",
377 "audio/x-raw-int",
378 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
379 "signed", GST_PROPS_BOOLEAN (TRUE),
380 "width", GST_PROPS_INT (16),
381 "depth", GST_PROPS_INT (16),
382 "channels", GST_PROPS_INT (channels),
383 "rate", GST_PROPS_INT (rate))
384 ) <= 0) {
385 gst_element_error (GST_PAD_PARENT (pad), "could not set caps on source pad, aborting...");
386 }
387 }
389 static void
390 gst_a52dec_handle_event (GstA52Dec *a52dec)
391 {
392 guint32 remaining;
393 GstEvent *event;
395 gst_bytestream_get_status (a52dec->bs, &remaining, &event);
397 if (!event) {
398 g_warning ("a52dec: no bytestream event");
399 return;
400 }
402 switch (GST_EVENT_TYPE (event)) {
403 case GST_EVENT_DISCONTINUOUS:
404 gst_bytestream_flush_fast (a52dec->bs, remaining);
405 default:
406 gst_pad_event_default (a52dec->sinkpad, event);
407 break;
408 }
409 }
411 static void
412 gst_a52dec_update_streaminfo (GstA52Dec *a52dec)
413 {
414 GstProps *props;
415 GstPropsEntry *entry;
417 props = gst_props_empty_new ();
419 entry = gst_props_entry_new ("bitrate", GST_PROPS_INT (a52dec->bit_rate));
420 gst_props_add_entry (props, (GstPropsEntry *) entry);
422 gst_caps_unref (a52dec->streaminfo);
424 a52dec->streaminfo = gst_caps_new ("a52dec_streaminfo",
425 "application/x-gst-streaminfo",
426 props);
427 g_object_notify (G_OBJECT (a52dec), "streaminfo");
428 }
430 static void
431 gst_a52dec_loop (GstElement *element)
432 {
433 GstA52Dec *a52dec;
434 guint8 *data;
435 int i, length, flags, sample_rate, bit_rate;
436 int channels;
437 GstBuffer *buf;
438 guint32 got_bytes;
439 gboolean need_reneg;
440 GstClockTime timestamp;
442 a52dec = GST_A52DEC (element);
444 /* find and read header */
445 while (1) {
446 got_bytes = gst_bytestream_peek_bytes (a52dec->bs, &data, 7);
447 if (got_bytes < 7) {
448 gst_a52dec_handle_event (a52dec);
449 return;
450 }
451 length = a52_syncinfo (data, &flags, &sample_rate, &bit_rate);
452 if (length == 0) {
453 /* slide window to next 7 bytesa */
454 gst_bytestream_flush_fast (a52dec->bs, 1);
455 }
456 else
457 break;
459 /* FIXME this can potentially be an infinite loop, we might
460 * have to insert a yield operation here */
461 }
463 need_reneg = FALSE;
465 if (a52dec->sample_rate != sample_rate) {
466 need_reneg = TRUE;
467 a52dec->sample_rate = sample_rate;
468 }
470 a52dec->stream_channels = flags & A52_CHANNEL_MASK;
472 if (bit_rate != a52dec->bit_rate) {
473 a52dec->bit_rate = bit_rate;
474 gst_a52dec_update_streaminfo (a52dec);
475 }
477 /* read the header + rest of frame */
478 got_bytes = gst_bytestream_read (a52dec->bs, &buf, length);
479 if (got_bytes < length) {
480 gst_a52dec_handle_event (a52dec);
481 return;
482 }
483 data = GST_BUFFER_DATA (buf);
484 timestamp = gst_bytestream_get_timestamp (a52dec->bs);
485 if (timestamp == a52dec->last_ts) {
486 timestamp = a52dec->current_ts;
487 }
488 else {
489 a52dec->last_ts = timestamp;
490 }
492 /* process */
493 flags = a52dec->request_channels | A52_ADJUST_LEVEL;
494 a52dec->level = 1;
496 if (a52_frame (a52dec->state, data, &flags, &a52dec->level, a52dec->bias)) {
497 g_warning ("a52dec: a52_frame error\n");
498 goto end;
499 }
501 channels = flags & A52_CHANNEL_MASK;
503 if (a52dec->using_channels != channels) {
504 need_reneg = TRUE;
505 a52dec->using_channels = channels;
506 }
508 if (need_reneg == TRUE) {
509 GST_DEBUG ("a52dec reneg: sample_rate:%d stream_chans:%d using_chans:%d\n",
510 a52dec->sample_rate, a52dec->stream_channels, a52dec->using_channels);
511 gst_a52dec_reneg (a52dec->srcpad,
512 gst_a52dec_channels (a52dec->using_channels), a52dec->sample_rate);
513 }
515 if (a52dec->dynamic_range_compression == FALSE) {
516 a52_dynrng (a52dec->state, NULL, NULL);
517 }
519 for (i = 0; i < 6; i++) {
520 if (a52_block (a52dec->state)) {
521 g_warning ("a52dec a52_block error %d\n", i);
522 continue;
523 }
524 /* push on */
525 if (gst_a52dec_push (a52dec->srcpad, a52dec->using_channels, a52dec->samples, timestamp)) {
526 g_warning ("a52dec push error\n");
527 }
528 else {
529 timestamp += sizeof (int16_t) * 256 * GST_SECOND / a52dec->sample_rate;
530 }
531 }
532 a52dec->current_ts = timestamp;
534 end:
535 gst_buffer_unref (buf);
536 }
538 static GstElementStateReturn
539 gst_a52dec_change_state (GstElement * element)
540 {
541 GstA52Dec *a52dec = GST_A52DEC (element);
543 switch (GST_STATE_TRANSITION (element)) {
544 case GST_STATE_NULL_TO_READY:
545 break;
546 case GST_STATE_READY_TO_PAUSED:
547 a52dec->bs = gst_bytestream_new (a52dec->sinkpad);
548 a52dec->state = a52_init (0); /* mm_accel()); */
549 a52dec->samples = a52_samples (a52dec->state);
550 a52dec->bit_rate = -1;
551 a52dec->sample_rate = -1;
552 a52dec->stream_channels = A52_CHANNEL;
553 /* FIXME force stereo for now */
554 a52dec->request_channels = A52_STEREO;
555 a52dec->using_channels = A52_CHANNEL;
556 a52dec->level = 1;
557 a52dec->bias = 384;
558 a52dec->last_ts = -1;
559 a52dec->current_ts = 0;
560 break;
561 case GST_STATE_PAUSED_TO_PLAYING:
562 break;
563 case GST_STATE_PLAYING_TO_PAUSED:
564 break;
565 case GST_STATE_PAUSED_TO_READY:
566 gst_bytestream_destroy (a52dec->bs);
567 a52dec->bs = NULL;
568 a52dec->samples = NULL;
569 a52_free (a52dec->state);
570 a52dec->state = NULL;
571 gst_caps_unref (a52dec->streaminfo);
572 break;
573 case GST_STATE_READY_TO_NULL:
574 break;
575 default:
576 break;
578 }
580 GST_ELEMENT_CLASS (parent_class)->change_state (element);
582 return GST_STATE_SUCCESS;
583 }
585 static void
586 gst_a52dec_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
587 {
588 GstA52Dec *src;
590 /* it's not null if we got it, but it might not be ours */
591 g_return_if_fail (GST_IS_A52DEC (object));
592 src = GST_A52DEC (object);
594 switch (prop_id) {
595 case ARG_DRC:
596 src->dynamic_range_compression = g_value_get_boolean (value);
597 break;
598 default:
599 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
600 break;
601 }
602 }
604 static void
605 gst_a52dec_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
606 {
607 GstA52Dec *src;
609 /* it's not null if we got it, but it might not be ours */
610 g_return_if_fail (GST_IS_A52DEC (object));
611 src = GST_A52DEC (object);
613 switch (prop_id) {
614 case ARG_DRC:
615 g_value_set_boolean (value, src->dynamic_range_compression);
616 break;
617 case ARG_STREAMINFO:
618 g_value_set_boxed (value, src->streaminfo);
619 break;
620 default:
621 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
622 break;
623 }
624 }
626 static gboolean
627 plugin_init (GstPlugin * plugin)
628 {
630 if (!gst_library_load ("gstbytestream"))
631 return FALSE;
633 if (!gst_element_register (plugin, "a52dec", GST_RANK_PRIMARY, GST_TYPE_A52DEC))
634 return FALSE;
636 return TRUE;
637 }
639 GST_PLUGIN_DEFINE (
640 GST_VERSION_MAJOR,
641 GST_VERSION_MINOR,
642 "a52dec",
643 "Decodes ATSC A/52 encoded audio streams",
644 plugin_init,
645 VERSION,
646 "GPL",
647 GST_COPYRIGHT,
648 GST_PACKAGE,
649 GST_ORIGIN
650 );