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>
27 #include "_stdint.h"
29 #include <gst/gst.h>
30 #include <gst/audio/multichannel.h>
32 #include <a52dec/a52.h>
33 #include <a52dec/mm_accel.h>
34 #include "gsta52dec.h"
36 #include <liboil/liboil.h>
37 #include <liboil/liboilcpu.h>
38 #include <liboil/liboilfunction.h>
40 /* elementfactory information */
41 static GstElementDetails gst_a52dec_details = {
42 "ATSC A/52 audio decoder",
43 "Codec/Decoder/Audio",
44 "Decodes ATSC A/52 encoded audio streams",
45 "David I. Lehn <dlehn@users.sourceforge.net>",
46 };
48 #ifdef LIBA52_DOUBLE
49 #define SAMPLE_WIDTH 64
50 #else
51 #define SAMPLE_WIDTH 32
52 #endif
54 GST_DEBUG_CATEGORY_STATIC (a52dec_debug);
55 #define GST_CAT_DEFAULT (a52dec_debug)
57 /* A52Dec args */
58 enum
59 {
60 ARG_0,
61 ARG_DRC
62 };
64 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
65 GST_PAD_SINK,
66 GST_PAD_ALWAYS,
67 GST_STATIC_CAPS ("audio/x-ac3; audio/ac3; audio/x-private1-ac3")
68 );
70 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
71 GST_PAD_SRC,
72 GST_PAD_ALWAYS,
73 GST_STATIC_CAPS ("audio/x-raw-float, "
74 "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", "
75 "width = (int) " G_STRINGIFY (SAMPLE_WIDTH) ", "
76 "rate = (int) [ 4000, 96000 ], " "channels = (int) [ 1, 6 ]")
77 );
79 static void gst_a52dec_base_init (GstA52DecClass * klass);
80 static void gst_a52dec_class_init (GstA52DecClass * klass);
81 static void gst_a52dec_init (GstA52Dec * a52dec);
83 static GstFlowReturn gst_a52dec_chain (GstPad * pad, GstBuffer * buffer);
84 static GstFlowReturn gst_a52dec_chain_raw (GstPad * pad, GstBuffer * buf);
85 static gboolean gst_a52dec_sink_setcaps (GstPad * pad, GstCaps * caps);
86 static gboolean gst_a52dec_sink_event (GstPad * pad, GstEvent * event);
87 static GstStateChangeReturn gst_a52dec_change_state (GstElement * element,
88 GstStateChange transition);
90 static void gst_a52dec_set_property (GObject * object, guint prop_id,
91 const GValue * value, GParamSpec * pspec);
92 static void gst_a52dec_get_property (GObject * object, guint prop_id,
93 GValue * value, GParamSpec * pspec);
95 static GstElementClass *parent_class = NULL;
97 GType
98 gst_a52dec_get_type (void)
99 {
100 static GType a52dec_type = 0;
102 if (!a52dec_type) {
103 static const GTypeInfo a52dec_info = {
104 sizeof (GstA52DecClass),
105 (GBaseInitFunc) gst_a52dec_base_init,
106 NULL,
107 (GClassInitFunc) gst_a52dec_class_init,
108 NULL,
109 NULL,
110 sizeof (GstA52Dec),
111 0,
112 (GInstanceInitFunc) gst_a52dec_init,
113 };
115 a52dec_type =
116 g_type_register_static (GST_TYPE_ELEMENT, "GstA52Dec", &a52dec_info, 0);
117 }
118 return a52dec_type;
119 }
121 static void
122 gst_a52dec_base_init (GstA52DecClass * klass)
123 {
124 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
126 gst_element_class_add_pad_template (element_class,
127 gst_static_pad_template_get (&sink_factory));
128 gst_element_class_add_pad_template (element_class,
129 gst_static_pad_template_get (&src_factory));
130 gst_element_class_set_details (element_class, &gst_a52dec_details);
132 GST_DEBUG_CATEGORY_INIT (a52dec_debug, "a52dec", 0,
133 "AC3/A52 software decoder");
134 }
136 static void
137 gst_a52dec_class_init (GstA52DecClass * klass)
138 {
139 GObjectClass *gobject_class;
140 GstElementClass *gstelement_class;
141 guint cpuflags;
143 gobject_class = (GObjectClass *) klass;
144 gstelement_class = (GstElementClass *) klass;
146 parent_class = g_type_class_peek_parent (klass);
148 gobject_class->set_property = gst_a52dec_set_property;
149 gobject_class->get_property = gst_a52dec_get_property;
151 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_a52dec_change_state);
153 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DRC,
154 g_param_spec_boolean ("drc", "Dynamic Range Compression",
155 "Use Dynamic Range Compression", FALSE, G_PARAM_READWRITE));
157 oil_init ();
159 klass->a52_cpuflags = 0;
160 cpuflags = oil_cpu_get_flags ();
161 if (cpuflags & OIL_IMPL_FLAG_MMX)
162 klass->a52_cpuflags |= MM_ACCEL_X86_MMX;
163 if (cpuflags & OIL_IMPL_FLAG_3DNOW)
164 klass->a52_cpuflags |= MM_ACCEL_X86_3DNOW;
165 if (cpuflags & OIL_IMPL_FLAG_MMXEXT)
166 klass->a52_cpuflags |= MM_ACCEL_X86_MMXEXT;
168 GST_LOG ("CPU flags: a52=%08x, liboil=%08x", klass->a52_cpuflags, cpuflags);
169 }
171 static void
172 gst_a52dec_init (GstA52Dec * a52dec)
173 {
174 GstElementClass *klass = GST_ELEMENT_GET_CLASS (a52dec);
176 /* create the sink and src pads */
177 a52dec->sinkpad =
178 gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
179 "sink"), "sink");
180 gst_pad_set_setcaps_function (a52dec->sinkpad,
181 GST_DEBUG_FUNCPTR (gst_a52dec_sink_setcaps));
182 gst_pad_set_chain_function (a52dec->sinkpad,
183 GST_DEBUG_FUNCPTR (gst_a52dec_chain));
184 gst_pad_set_event_function (a52dec->sinkpad,
185 GST_DEBUG_FUNCPTR (gst_a52dec_sink_event));
186 gst_element_add_pad (GST_ELEMENT (a52dec), a52dec->sinkpad);
188 a52dec->srcpad =
189 gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
190 "src"), "src");
191 gst_pad_use_fixed_caps (a52dec->srcpad);
192 gst_element_add_pad (GST_ELEMENT (a52dec), a52dec->srcpad);
194 a52dec->dynamic_range_compression = FALSE;
195 a52dec->cache = NULL;
196 }
198 static int
199 gst_a52dec_channels (int flags, GstAudioChannelPosition ** _pos)
200 {
201 int chans = 0;
202 GstAudioChannelPosition *pos = NULL;
204 /* allocated just for safety. Number makes no sense */
205 if (_pos) {
206 pos = g_new (GstAudioChannelPosition, 6);
207 *_pos = pos;
208 }
210 if (flags & A52_LFE) {
211 chans += 1;
212 if (pos) {
213 pos[0] = GST_AUDIO_CHANNEL_POSITION_LFE;
214 }
215 }
216 flags &= A52_CHANNEL_MASK;
217 switch (flags) {
218 case A52_3F2R:
219 if (pos) {
220 pos[0 + chans] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
221 pos[1 + chans] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
222 pos[2 + chans] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
223 pos[3 + chans] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
224 pos[4 + chans] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
225 }
226 chans += 5;
227 break;
228 case A52_2F2R:
229 if (pos) {
230 pos[0 + chans] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
231 pos[1 + chans] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
232 pos[2 + chans] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
233 pos[3 + chans] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
234 }
235 chans += 4;
236 break;
237 case A52_3F1R:
238 if (pos) {
239 pos[0 + chans] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
240 pos[1 + chans] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
241 pos[2 + chans] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
242 pos[3 + chans] = GST_AUDIO_CHANNEL_POSITION_REAR_CENTER;
243 }
244 chans += 4;
245 break;
246 case A52_2F1R:
247 if (pos) {
248 pos[0 + chans] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
249 pos[1 + chans] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
250 pos[2 + chans] = GST_AUDIO_CHANNEL_POSITION_REAR_CENTER;
251 }
252 chans += 3;
253 break;
254 case A52_3F:
255 if (pos) {
256 pos[0 + chans] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
257 pos[1 + chans] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
258 pos[2 + chans] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
259 }
260 chans += 3;
261 break;
262 /*case A52_CHANNEL: */
263 case A52_STEREO:
264 case A52_DOLBY:
265 if (pos) {
266 pos[0 + chans] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
267 pos[1 + chans] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
268 }
269 chans += 2;
270 break;
271 default:
272 /* error */
273 g_warning ("a52dec invalid flags %d", flags);
274 g_free (pos);
275 return 0;
276 }
278 return chans;
279 }
281 static GstFlowReturn
282 gst_a52dec_push (GstA52Dec * a52dec,
283 GstPad * srcpad, int flags, sample_t * samples, GstClockTime timestamp)
284 {
285 GstBuffer *buf;
286 int chans, n, c;
287 GstFlowReturn result;
289 flags &= (A52_CHANNEL_MASK | A52_LFE);
290 chans = gst_a52dec_channels (flags, NULL);
291 if (!chans) {
292 return GST_FLOW_ERROR;
293 }
295 result =
296 gst_pad_alloc_buffer_and_set_caps (srcpad, 0,
297 256 * chans * (SAMPLE_WIDTH / 8), GST_PAD_CAPS (srcpad), &buf);
298 if (result != GST_FLOW_OK)
299 return result;
301 for (n = 0; n < 256; n++) {
302 for (c = 0; c < chans; c++) {
303 ((sample_t *) GST_BUFFER_DATA (buf))[n * chans + c] =
304 samples[c * 256 + n];
305 }
306 }
307 GST_BUFFER_TIMESTAMP (buf) = timestamp;
308 GST_BUFFER_DURATION (buf) = 256 * GST_SECOND / a52dec->sample_rate;
310 GST_DEBUG_OBJECT (a52dec,
311 "Pushing buffer with ts %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT,
312 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
313 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
315 return gst_pad_push (srcpad, buf);
316 }
318 static gboolean
319 gst_a52dec_reneg (GstPad * pad)
320 {
321 GstAudioChannelPosition *pos;
322 GstA52Dec *a52dec = GST_A52DEC (gst_pad_get_parent (pad));
323 gint channels = gst_a52dec_channels (a52dec->using_channels, &pos);
324 GstCaps *caps = NULL;
325 gboolean result = FALSE;
327 if (!channels)
328 goto done;
330 GST_INFO ("a52dec: reneg channels:%d rate:%d\n",
331 channels, a52dec->sample_rate);
333 caps = gst_caps_new_simple ("audio/x-raw-float",
334 "endianness", G_TYPE_INT, G_BYTE_ORDER,
335 "width", G_TYPE_INT, SAMPLE_WIDTH,
336 "channels", G_TYPE_INT, channels,
337 "rate", G_TYPE_INT, a52dec->sample_rate, NULL);
338 gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), pos);
339 g_free (pos);
341 if (!gst_pad_set_caps (pad, caps))
342 goto done;
344 result = TRUE;
346 done:
347 if (caps)
348 gst_caps_unref (caps);
349 gst_object_unref (GST_OBJECT (a52dec));
350 return result;
351 }
353 static gboolean
354 gst_a52dec_sink_event (GstPad * pad, GstEvent * event)
355 {
356 GstA52Dec *a52dec = GST_A52DEC (gst_pad_get_parent (pad));
357 gboolean ret = FALSE;
359 GST_LOG ("Handling %s event", GST_EVENT_TYPE_NAME (event));
361 switch (GST_EVENT_TYPE (event)) {
362 case GST_EVENT_NEWSEGMENT:{
363 GstFormat format;
364 gint64 val;
366 gst_event_parse_new_segment (event, NULL, NULL, &format, &val, NULL,
367 NULL);
368 if (format != GST_FORMAT_TIME || !GST_CLOCK_TIME_IS_VALID (val)) {
369 GST_WARNING ("No time in newsegment event %p", event);
370 } else {
371 a52dec->time = val;
372 }
374 if (a52dec->cache) {
375 gst_buffer_unref (a52dec->cache);
376 a52dec->cache = NULL;
377 }
378 ret = gst_pad_event_default (pad, event);
379 break;
380 }
381 case GST_EVENT_TAG:
382 case GST_EVENT_EOS:{
383 ret = gst_pad_event_default (pad, event);
384 break;
385 }
386 case GST_EVENT_FLUSH_START:
387 ret = gst_pad_event_default (pad, event);
388 break;
389 case GST_EVENT_FLUSH_STOP:
390 if (a52dec->cache) {
391 gst_buffer_unref (a52dec->cache);
392 a52dec->cache = NULL;
393 }
394 ret = gst_pad_event_default (pad, event);
395 break;
396 default:
397 ret = gst_pad_event_default (pad, event);
398 break;
399 }
401 gst_object_unref (a52dec);
402 return ret;
403 }
405 static void
406 gst_a52dec_update_streaminfo (GstA52Dec * a52dec)
407 {
408 GstTagList *taglist;
410 taglist = gst_tag_list_new ();
412 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
413 GST_TAG_BITRATE, (guint) a52dec->bit_rate, NULL);
415 gst_element_found_tags_for_pad (GST_ELEMENT (a52dec),
416 GST_PAD (a52dec->srcpad), taglist);
417 }
419 static GstFlowReturn
420 gst_a52dec_handle_frame (GstA52Dec * a52dec, guint8 * data,
421 guint length, gint flags, gint sample_rate, gint bit_rate)
422 {
423 gint channels, i;
424 gboolean need_reneg = FALSE;
426 /* update stream information, renegotiate or re-streaminfo if needed */
427 need_reneg = FALSE;
428 if (a52dec->sample_rate != sample_rate) {
429 need_reneg = TRUE;
430 a52dec->sample_rate = sample_rate;
431 }
433 if (flags) {
434 a52dec->stream_channels = flags & (A52_CHANNEL_MASK | A52_LFE);
435 }
437 if (bit_rate != a52dec->bit_rate) {
438 a52dec->bit_rate = bit_rate;
439 gst_a52dec_update_streaminfo (a52dec);
440 }
442 /* process */
443 flags = a52dec->request_channels; /* | A52_ADJUST_LEVEL; */
444 a52dec->level = 1;
445 if (a52_frame (a52dec->state, data, &flags, &a52dec->level, a52dec->bias)) {
446 GST_WARNING ("a52_frame error");
447 return GST_FLOW_OK;
448 }
449 channels = flags & (A52_CHANNEL_MASK | A52_LFE);
450 if (a52dec->using_channels != channels) {
451 need_reneg = TRUE;
452 a52dec->using_channels = channels;
453 }
455 /* negotiate if required */
456 if (need_reneg == TRUE) {
457 GST_DEBUG ("a52dec reneg: sample_rate:%d stream_chans:%d using_chans:%d\n",
458 a52dec->sample_rate, a52dec->stream_channels, a52dec->using_channels);
459 if (!gst_a52dec_reneg (a52dec->srcpad)) {
460 GST_ELEMENT_ERROR (a52dec, CORE, NEGOTIATION, (NULL), (NULL));
461 return GST_FLOW_ERROR;
462 }
463 }
465 if (a52dec->dynamic_range_compression == FALSE) {
466 a52_dynrng (a52dec->state, NULL, NULL);
467 }
469 /* each frame consists of 6 blocks */
470 for (i = 0; i < 6; i++) {
471 if (a52_block (a52dec->state)) {
472 GST_WARNING ("a52_block error %d", i);
473 } else {
474 GstFlowReturn ret;
476 /* push on */
477 ret = gst_a52dec_push (a52dec, a52dec->srcpad, a52dec->using_channels,
478 a52dec->samples, a52dec->time);
479 if (ret != GST_FLOW_OK)
480 return ret;
481 }
482 a52dec->time += 256 * GST_SECOND / a52dec->sample_rate;
483 }
485 return GST_FLOW_OK;
486 }
488 static gboolean
489 gst_a52dec_sink_setcaps (GstPad * pad, GstCaps * caps)
490 {
491 GstA52Dec *a52dec = GST_A52DEC (gst_pad_get_parent (pad));
492 GstStructure *structure;
494 structure = gst_caps_get_structure (caps, 0);
496 if (structure && gst_structure_has_name (structure, "audio/x-private1-ac3"))
497 a52dec->dvdmode = TRUE;
498 else
499 a52dec->dvdmode = FALSE;
501 gst_object_unref (a52dec);
503 return TRUE;
504 }
506 static GstFlowReturn
507 gst_a52dec_chain (GstPad * pad, GstBuffer * buf)
508 {
509 GstA52Dec *a52dec = GST_A52DEC (gst_pad_get_parent (pad));
510 GstFlowReturn ret;
512 if (a52dec->dvdmode) {
513 gint size = GST_BUFFER_SIZE (buf);
514 guchar *data = GST_BUFFER_DATA (buf);
515 gint first_access;
516 gint offset;
517 gint len;
518 GstBuffer *subbuf;
520 if (size < 2) {
521 GST_ERROR_OBJECT (pad, "Insufficient data in buffer. "
522 "Can't determine first_acess");
523 ret = GST_FLOW_ERROR;
524 goto done;
525 }
527 first_access = (data[0] << 8) | data[1];
529 /* Skip the first_access header */
530 offset = 2;
532 if (first_access > 1) {
533 /* Length of data before first_access */
534 len = first_access - 1;
536 if (len <= 0 || offset + len > size) {
537 GST_ERROR_OBJECT (pad, "Bad first_access parameter in buffer");
538 ret = GST_FLOW_ERROR;
539 goto done;
540 }
542 subbuf = gst_buffer_create_sub (buf, offset, len);
543 GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE;
544 ret = gst_a52dec_chain_raw (pad, subbuf);
545 if (ret != GST_FLOW_OK)
546 goto done;
548 offset += len;
549 len = size - offset;
551 if (len > 0) {
552 subbuf = gst_buffer_create_sub (buf, offset, len);
553 GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
555 ret = gst_a52dec_chain_raw (pad, subbuf);
556 }
557 } else {
558 /* No first_access, so no timestamp */
559 subbuf = gst_buffer_create_sub (buf, offset, size - offset);
560 GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE;
561 ret = gst_a52dec_chain_raw (pad, subbuf);
562 }
563 } else {
564 ret = gst_a52dec_chain_raw (pad, buf);
565 }
567 done:
568 gst_object_unref (a52dec);
570 return ret;
571 }
573 static GstFlowReturn
574 gst_a52dec_chain_raw (GstPad * pad, GstBuffer * buf)
575 {
576 GstA52Dec *a52dec = GST_A52DEC (gst_pad_get_parent (pad));
577 guint8 *data;
578 guint size;
579 gint length = 0, flags, sample_rate, bit_rate;
580 GstFlowReturn result = GST_FLOW_OK;
582 /* merge with cache, if any. Also make sure timestamps match */
583 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
584 a52dec->time = GST_BUFFER_TIMESTAMP (buf);
585 GST_DEBUG_OBJECT (a52dec,
586 "Received buffer with ts %" GST_TIME_FORMAT " duration %"
587 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
588 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
589 }
591 if (a52dec->cache) {
592 buf = gst_buffer_join (a52dec->cache, buf);
593 a52dec->cache = NULL;
594 }
595 data = GST_BUFFER_DATA (buf);
596 size = GST_BUFFER_SIZE (buf);
598 /* find and read header */
599 bit_rate = a52dec->bit_rate;
600 sample_rate = a52dec->sample_rate;
601 flags = 0;
602 while (size >= 7) {
603 length = a52_syncinfo (data, &flags, &sample_rate, &bit_rate);
604 if (length == 0) {
605 /* no sync */
606 data++;
607 size--;
608 } else if (length <= size) {
609 GST_DEBUG ("Sync: %d", length);
610 result = gst_a52dec_handle_frame (a52dec, data,
611 length, flags, sample_rate, bit_rate);
612 if (result != GST_FLOW_OK) {
613 size = 0;
614 break;
615 }
616 size -= length;
617 data += length;
618 } else {
619 /* not enough data */
620 GST_LOG ("Not enough data available");
621 break;
622 }
623 }
625 /* keep cache */
626 if (length == 0) {
627 GST_LOG ("No sync found");
628 }
630 if (size > 0) {
631 a52dec->cache = gst_buffer_create_sub (buf,
632 GST_BUFFER_SIZE (buf) - size, size);
633 }
635 gst_buffer_unref (buf);
636 gst_object_unref (a52dec);
638 return result;
639 }
641 static GstStateChangeReturn
642 gst_a52dec_change_state (GstElement * element, GstStateChange transition)
643 {
644 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
645 GstA52Dec *a52dec = GST_A52DEC (element);
647 switch (transition) {
648 case GST_STATE_CHANGE_NULL_TO_READY:{
649 GstA52DecClass *klass;
651 klass = GST_A52DEC_CLASS (G_OBJECT_GET_CLASS (a52dec));
652 a52dec->state = a52_init (klass->a52_cpuflags);
653 break;
654 }
655 case GST_STATE_CHANGE_READY_TO_PAUSED:
656 a52dec->samples = a52_samples (a52dec->state);
657 a52dec->bit_rate = -1;
658 a52dec->sample_rate = -1;
659 a52dec->stream_channels = A52_CHANNEL;
660 a52dec->request_channels = A52_3F2R | A52_LFE;
661 a52dec->using_channels = A52_CHANNEL;
662 a52dec->level = 1;
663 a52dec->bias = 0;
664 a52dec->time = 0;
665 break;
666 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
667 break;
668 default:
669 break;
670 }
672 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
674 switch (transition) {
675 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
676 break;
677 case GST_STATE_CHANGE_PAUSED_TO_READY:
678 a52dec->samples = NULL;
679 if (a52dec->cache) {
680 gst_buffer_unref (a52dec->cache);
681 a52dec->cache = NULL;
682 }
683 break;
684 case GST_STATE_CHANGE_READY_TO_NULL:
685 a52_free (a52dec->state);
686 a52dec->state = NULL;
687 break;
688 default:
689 break;
690 }
692 return ret;
693 }
695 static void
696 gst_a52dec_set_property (GObject * object, guint prop_id, const GValue * value,
697 GParamSpec * pspec)
698 {
699 GstA52Dec *src = GST_A52DEC (object);
701 switch (prop_id) {
702 case ARG_DRC:
703 GST_OBJECT_LOCK (src);
704 src->dynamic_range_compression = g_value_get_boolean (value);
705 GST_OBJECT_UNLOCK (src);
706 break;
707 default:
708 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
709 break;
710 }
711 }
713 static void
714 gst_a52dec_get_property (GObject * object, guint prop_id, GValue * value,
715 GParamSpec * pspec)
716 {
717 GstA52Dec *src = GST_A52DEC (object);
719 switch (prop_id) {
720 case ARG_DRC:
721 GST_OBJECT_LOCK (src);
722 g_value_set_boolean (value, src->dynamic_range_compression);
723 GST_OBJECT_UNLOCK (src);
724 break;
725 default:
726 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
727 break;
728 }
729 }
731 static gboolean
732 plugin_init (GstPlugin * plugin)
733 {
734 if (!gst_element_register (plugin, "a52dec", GST_RANK_PRIMARY,
735 GST_TYPE_A52DEC))
736 return FALSE;
738 return TRUE;
739 }
741 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
742 GST_VERSION_MINOR,
743 "a52dec",
744 "Decodes ATSC A/52 encoded audio streams",
745 plugin_init, VERSION, "GPL", GST_PACKAGE, GST_ORIGIN);