dtsdec: Use orc for CPU feature detection
[platform/upstream/gstreamer.git] / ext / dts / gstdtsdec.c
1 /* GStreamer DTS decoder plugin based on libdtsdec
2  * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  * Copyright (C) 2009 Jan Schmidt <thaytan@noraisin.net>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * SECTION:element-dtsdec
23  *
24  * Digital Theatre System (DTS) audio decoder
25  * 
26  * <refsect2>
27  * <title>Example launch line</title>
28  * |[
29  * gst-launch dvdreadsrc title=1 ! mpegpsdemux ! dtsdec ! audioresample ! audioconvert ! alsasink
30  * ]| Play a DTS audio track from a dvd.
31  * |[
32  * gst-launch filesrc location=abc.dts ! dtsdec ! audioresample ! audioconvert ! alsasink
33  * ]| Decode a standalone file and play it.
34  * </refsect2>
35  */
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40
41 #include <string.h>
42 #include "_stdint.h"
43 #include <stdlib.h>
44
45 #include <gst/gst.h>
46 #include <gst/audio/multichannel.h>
47
48 #ifndef DTS_OLD
49 #include <dca.h>
50 #else
51 #include <dts.h>
52
53 typedef struct dts_state_s dca_state_t;
54 #define DCA_MONO DTS_MONO
55 #define DCA_CHANNEL DTS_CHANNEL
56 #define DCA_STEREO DTS_STEREO
57 #define DCA_STEREO_SUMDIFF DTS_STEREO_SUMDIFF
58 #define DCA_STEREO_TOTAL DTS_STEREO_TOTAL
59 #define DCA_3F DTS_3F
60 #define DCA_2F1R DTS_2F1R
61 #define DCA_3F1R DTS_3F1R
62 #define DCA_2F2R DTS_2F2R
63 #define DCA_3F2R DTS_3F2R
64 #define DCA_4F2R DTS_4F2R
65 #define DCA_DOLBY DTS_DOLBY
66 #define DCA_CHANNEL_MAX DTS_CHANNEL_MAX
67 #define DCA_CHANNEL_BITS DTS_CHANNEL_BITS
68 #define DCA_CHANNEL_MASK DTS_CHANNEL_MASK
69 #define DCA_LFE DTS_LFE
70 #define DCA_ADJUST_LEVEL DTS_ADJUST_LEVEL
71
72 #define dca_init dts_init
73 #define dca_syncinfo dts_syncinfo
74 #define dca_frame dts_frame
75 #define dca_dynrng dts_dynrng
76 #define dca_blocks_num dts_blocks_num
77 #define dca_block dts_block
78 #define dca_samples dts_samples
79 #define dca_free dts_free
80 #endif
81
82 #include "gstdtsdec.h"
83
84 #if HAVE_ORC
85 #include <orc/orc.h>
86 #endif
87
88 #if defined(LIBDTS_FIXED) || defined(LIBDCA_FIXED)
89 #define SAMPLE_WIDTH 16
90 #elif defined (LIBDTS_DOUBLE) || defined(LIBDCA_DOUBLE)
91 #define SAMPLE_WIDTH 64
92 #else
93 #define SAMPLE_WIDTH 32
94 #endif
95
96 GST_DEBUG_CATEGORY_STATIC (dtsdec_debug);
97 #define GST_CAT_DEFAULT (dtsdec_debug)
98
99 enum
100 {
101   ARG_0,
102   ARG_DRC
103 };
104
105 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
106     GST_PAD_SINK,
107     GST_PAD_ALWAYS,
108     GST_STATIC_CAPS ("audio/x-dts; audio/x-private1-dts")
109     );
110
111 #if defined(LIBDTS_FIXED) || defined(LIBDCA_FIXED)
112 #define DTS_CAPS "audio/x-raw-int, " \
113     "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", " \
114     "signed = (boolean) true, " \
115     "width = (int) " G_STRINGIFY (SAMPLE_WIDTH) ", " \
116     "depth = (int) 16"
117 #else
118 #define DTS_CAPS "audio/x-raw-float, " \
119     "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", " \
120     "width = (int) " G_STRINGIFY (SAMPLE_WIDTH)
121 #endif
122
123 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
124     GST_PAD_SRC,
125     GST_PAD_ALWAYS,
126     GST_STATIC_CAPS (DTS_CAPS ", "
127         "rate = (int) [ 4000, 96000 ], " "channels = (int) [ 1, 6 ]")
128     );
129
130 GST_BOILERPLATE (GstDtsDec, gst_dtsdec, GstElement, GST_TYPE_ELEMENT);
131
132 static gboolean gst_dtsdec_sink_setcaps (GstPad * pad, GstCaps * caps);
133 static gboolean gst_dtsdec_sink_event (GstPad * pad, GstEvent * event);
134 static GstFlowReturn gst_dtsdec_chain (GstPad * pad, GstBuffer * buf);
135 static GstFlowReturn gst_dtsdec_chain_raw (GstPad * pad, GstBuffer * buf);
136 static GstStateChangeReturn gst_dtsdec_change_state (GstElement * element,
137     GstStateChange transition);
138
139 static void gst_dtsdec_set_property (GObject * object, guint prop_id,
140     const GValue * value, GParamSpec * pspec);
141 static void gst_dtsdec_get_property (GObject * object, guint prop_id,
142     GValue * value, GParamSpec * pspec);
143
144
145 static void
146 gst_dtsdec_base_init (gpointer g_class)
147 {
148   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
149
150   gst_element_class_add_pad_template (element_class,
151       gst_static_pad_template_get (&sink_factory));
152   gst_element_class_add_pad_template (element_class,
153       gst_static_pad_template_get (&src_factory));
154   gst_element_class_set_details_simple (element_class, "DTS audio decoder",
155       "Codec/Decoder/Audio",
156       "Decodes DTS audio streams",
157       "Jan Schmidt <thaytan@noraisin.net>, "
158       "Ronald Bultje <rbultje@ronald.bitfreak.net>");
159
160   GST_DEBUG_CATEGORY_INIT (dtsdec_debug, "dtsdec", 0, "DTS/DCA audio decoder");
161 }
162
163 static void
164 gst_dtsdec_class_init (GstDtsDecClass * klass)
165 {
166   GObjectClass *gobject_class;
167   GstElementClass *gstelement_class;
168   guint cpuflags;
169
170   gobject_class = (GObjectClass *) klass;
171   gstelement_class = (GstElementClass *) klass;
172
173   gobject_class->set_property = gst_dtsdec_set_property;
174   gobject_class->get_property = gst_dtsdec_get_property;
175
176   gstelement_class->change_state = gst_dtsdec_change_state;
177
178   /**
179    * GstDtsDec::drc
180    *
181    * Set to true to apply the recommended DTS dynamic range compression
182    * to the audio stream. Dynamic range compression makes loud sounds
183    * softer and soft sounds louder, so you can more easily listen
184    * to the stream without disturbing other people.
185    */
186   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DRC,
187       g_param_spec_boolean ("drc", "Dynamic Range Compression",
188           "Use Dynamic Range Compression", FALSE, G_PARAM_READWRITE));
189
190   klass->dts_cpuflags = 0;
191
192 #if HAVE_ORC
193   cpuflags = orc_target_get_default_flags (orc_target_get_by_name ("mmx"));
194   if (cpuflags & ORC_TARGET_MMX_MMX)
195     klass->dts_cpuflags |= MM_ACCEL_X86_MMX;
196   if (cpuflags & ORC_TARGET_MMX_3DNOW)
197     klass->dts_cpuflags |= MM_ACCEL_X86_3DNOW;
198   if (cpuflags & ORC_TARGET_MMX_MMXEXT)
199     klass->dts_cpuflags |= MM_ACCEL_X86_MMXEXT;
200 #else
201   klass->dts_cpuflags = 0;
202 #endif
203
204   GST_LOG ("CPU flags: dts=%08x, liboil=%08x", klass->dts_cpuflags, cpuflags);
205 }
206
207 static void
208 gst_dtsdec_init (GstDtsDec * dtsdec, GstDtsDecClass * g_class)
209 {
210   /* create the sink and src pads */
211   dtsdec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
212   gst_pad_set_setcaps_function (dtsdec->sinkpad,
213       GST_DEBUG_FUNCPTR (gst_dtsdec_sink_setcaps));
214   gst_pad_set_chain_function (dtsdec->sinkpad,
215       GST_DEBUG_FUNCPTR (gst_dtsdec_chain));
216   gst_pad_set_event_function (dtsdec->sinkpad,
217       GST_DEBUG_FUNCPTR (gst_dtsdec_sink_event));
218   gst_element_add_pad (GST_ELEMENT (dtsdec), dtsdec->sinkpad);
219
220   dtsdec->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
221   gst_element_add_pad (GST_ELEMENT (dtsdec), dtsdec->srcpad);
222
223   dtsdec->request_channels = DCA_CHANNEL;
224   dtsdec->dynamic_range_compression = FALSE;
225
226   gst_segment_init (&dtsdec->segment, GST_FORMAT_UNDEFINED);
227 }
228
229 static gint
230 gst_dtsdec_channels (uint32_t flags, GstAudioChannelPosition ** pos)
231 {
232   gint chans = 0;
233   GstAudioChannelPosition *tpos = NULL;
234
235   if (pos) {
236     /* Allocate the maximum, for ease */
237     tpos = *pos = g_new (GstAudioChannelPosition, 7);
238     if (!tpos)
239       return 0;
240   }
241
242   switch (flags & DCA_CHANNEL_MASK) {
243     case DCA_MONO:
244       chans = 1;
245       if (tpos)
246         tpos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_MONO;
247       break;
248       /* case DCA_CHANNEL: */
249     case DCA_STEREO:
250     case DCA_STEREO_SUMDIFF:
251     case DCA_STEREO_TOTAL:
252     case DCA_DOLBY:
253       chans = 2;
254       if (tpos) {
255         tpos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
256         tpos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
257       }
258       break;
259     case DCA_3F:
260       chans = 3;
261       if (tpos) {
262         tpos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
263         tpos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
264         tpos[2] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
265       }
266       break;
267     case DCA_2F1R:
268       chans = 3;
269       if (tpos) {
270         tpos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
271         tpos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
272         tpos[2] = GST_AUDIO_CHANNEL_POSITION_REAR_CENTER;
273       }
274       break;
275     case DCA_3F1R:
276       chans = 4;
277       if (tpos) {
278         tpos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
279         tpos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
280         tpos[2] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
281         tpos[3] = GST_AUDIO_CHANNEL_POSITION_REAR_CENTER;
282       }
283       break;
284     case DCA_2F2R:
285       chans = 4;
286       if (tpos) {
287         tpos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
288         tpos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
289         tpos[2] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
290         tpos[3] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
291       }
292       break;
293     case DCA_3F2R:
294       chans = 5;
295       if (tpos) {
296         tpos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
297         tpos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
298         tpos[2] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
299         tpos[3] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
300         tpos[4] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
301       }
302       break;
303     case DCA_4F2R:
304       chans = 6;
305       if (tpos) {
306         tpos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
307         tpos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
308         tpos[2] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
309         tpos[3] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
310         tpos[4] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
311         tpos[5] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
312       }
313       break;
314     default:
315       g_warning ("dtsdec: invalid flags 0x%x", flags);
316       return 0;
317   }
318   if (flags & DCA_LFE) {
319     if (tpos) {
320       tpos[chans] = GST_AUDIO_CHANNEL_POSITION_LFE;
321     }
322     chans += 1;
323   }
324
325   return chans;
326 }
327
328 static void
329 clear_queued (GstDtsDec * dec)
330 {
331   g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL);
332   g_list_free (dec->queued);
333   dec->queued = NULL;
334 }
335
336 static GstFlowReturn
337 flush_queued (GstDtsDec * dec)
338 {
339   GstFlowReturn ret = GST_FLOW_OK;
340
341   while (dec->queued) {
342     GstBuffer *buf = GST_BUFFER_CAST (dec->queued->data);
343
344     GST_LOG_OBJECT (dec, "pushing buffer %p, timestamp %"
345         GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, buf,
346         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
347         GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
348
349     /* iterate ouput queue an push downstream */
350     ret = gst_pad_push (dec->srcpad, buf);
351
352     dec->queued = g_list_delete_link (dec->queued, dec->queued);
353   }
354   return ret;
355 }
356
357 static GstFlowReturn
358 gst_dtsdec_drain (GstDtsDec * dec)
359 {
360   GstFlowReturn ret = GST_FLOW_OK;
361
362   if (dec->segment.rate < 0.0) {
363     /* if we have some queued frames for reverse playback, flush
364      * them now */
365     ret = flush_queued (dec);
366   }
367   return ret;
368 }
369
370 static GstFlowReturn
371 gst_dtsdec_push (GstDtsDec * dtsdec,
372     GstPad * srcpad, int flags, sample_t * samples, GstClockTime timestamp)
373 {
374   GstBuffer *buf;
375   int chans, n, c;
376   GstFlowReturn result;
377
378   flags &= (DCA_CHANNEL_MASK | DCA_LFE);
379   chans = gst_dtsdec_channels (flags, NULL);
380   if (!chans) {
381     GST_ELEMENT_ERROR (GST_ELEMENT (dtsdec), STREAM, DECODE, (NULL),
382         ("Invalid channel flags: %d", flags));
383     return GST_FLOW_ERROR;
384   }
385
386   result =
387       gst_pad_alloc_buffer_and_set_caps (srcpad, 0,
388       256 * chans * (SAMPLE_WIDTH / 8), GST_PAD_CAPS (srcpad), &buf);
389   if (result != GST_FLOW_OK)
390     return result;
391
392   for (n = 0; n < 256; n++) {
393     for (c = 0; c < chans; c++) {
394       ((sample_t *) GST_BUFFER_DATA (buf))[n * chans + c] =
395           samples[c * 256 + n];
396     }
397   }
398   GST_BUFFER_TIMESTAMP (buf) = timestamp;
399   GST_BUFFER_DURATION (buf) = 256 * GST_SECOND / dtsdec->sample_rate;
400
401   result = GST_FLOW_OK;
402   if ((buf = gst_audio_buffer_clip (buf, &dtsdec->segment,
403               dtsdec->sample_rate, (SAMPLE_WIDTH / 8) * chans))) {
404     /* set discont when needed */
405     if (dtsdec->discont) {
406       GST_LOG_OBJECT (dtsdec, "marking DISCONT");
407       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
408       dtsdec->discont = FALSE;
409     }
410
411     if (dtsdec->segment.rate > 0.0) {
412       GST_DEBUG_OBJECT (dtsdec,
413           "Pushing buffer with ts %" GST_TIME_FORMAT " duration %"
414           GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
415           GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
416
417       result = gst_pad_push (srcpad, buf);
418     } else {
419       /* reverse playback, queue frame till later when we get a discont. */
420       GST_DEBUG_OBJECT (dtsdec, "queued frame");
421       dtsdec->queued = g_list_prepend (dtsdec->queued, buf);
422     }
423   }
424   return result;
425 }
426
427 static gboolean
428 gst_dtsdec_renegotiate (GstDtsDec * dts)
429 {
430   GstAudioChannelPosition *pos;
431   GstCaps *caps = gst_caps_from_string (DTS_CAPS);
432   gint channels = gst_dtsdec_channels (dts->using_channels, &pos);
433   gboolean result = FALSE;
434
435   if (!channels)
436     goto done;
437
438   GST_INFO ("dtsdec renegotiate, channels=%d, rate=%d",
439       channels, dts->sample_rate);
440
441   gst_caps_set_simple (caps,
442       "channels", G_TYPE_INT, channels,
443       "rate", G_TYPE_INT, (gint) dts->sample_rate, NULL);
444   gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), pos);
445   g_free (pos);
446
447   if (!gst_pad_set_caps (dts->srcpad, caps))
448     goto done;
449
450   result = TRUE;
451
452 done:
453   if (caps) {
454     gst_caps_unref (caps);
455   }
456   return result;
457 }
458
459 static gboolean
460 gst_dtsdec_sink_event (GstPad * pad, GstEvent * event)
461 {
462   GstDtsDec *dtsdec = GST_DTSDEC (gst_pad_get_parent (pad));
463   gboolean ret = FALSE;
464
465   GST_LOG_OBJECT (dtsdec, "%s event", GST_EVENT_TYPE_NAME (event));
466
467   switch (GST_EVENT_TYPE (event)) {
468     case GST_EVENT_NEWSEGMENT:{
469       GstFormat format;
470       gboolean update;
471       gint64 start, end, pos;
472       gdouble rate;
473
474       gst_event_parse_new_segment (event, &update, &rate, &format, &start, &end,
475           &pos);
476
477       /* drain queued buffers before activating the segment so that we can clip
478        * against the old segment first */
479       gst_dtsdec_drain (dtsdec);
480
481       if (format != GST_FORMAT_TIME || !GST_CLOCK_TIME_IS_VALID (start)) {
482         GST_WARNING ("No time in newsegment event %p (format is %s)",
483             event, gst_format_get_name (format));
484         gst_event_unref (event);
485         dtsdec->sent_segment = FALSE;
486         /* set some dummy values, FIXME: do proper conversion */
487         dtsdec->time = start = pos = 0;
488         format = GST_FORMAT_TIME;
489         end = -1;
490       } else {
491         dtsdec->time = start;
492         dtsdec->sent_segment = TRUE;
493         ret = gst_pad_push_event (dtsdec->srcpad, event);
494       }
495
496       gst_segment_set_newsegment (&dtsdec->segment, update, rate, format, start,
497           end, pos);
498       break;
499     }
500     case GST_EVENT_TAG:
501       ret = gst_pad_push_event (dtsdec->srcpad, event);
502       break;
503     case GST_EVENT_EOS:
504       gst_dtsdec_drain (dtsdec);
505       ret = gst_pad_push_event (dtsdec->srcpad, event);
506       break;
507     case GST_EVENT_FLUSH_START:
508       ret = gst_pad_push_event (dtsdec->srcpad, event);
509       break;
510     case GST_EVENT_FLUSH_STOP:
511       if (dtsdec->cache) {
512         gst_buffer_unref (dtsdec->cache);
513         dtsdec->cache = NULL;
514       }
515       clear_queued (dtsdec);
516       gst_segment_init (&dtsdec->segment, GST_FORMAT_UNDEFINED);
517       ret = gst_pad_push_event (dtsdec->srcpad, event);
518       break;
519     default:
520       ret = gst_pad_push_event (dtsdec->srcpad, event);
521       break;
522   }
523
524   gst_object_unref (dtsdec);
525   return ret;
526 }
527
528 static void
529 gst_dtsdec_update_streaminfo (GstDtsDec * dts)
530 {
531   GstTagList *taglist;
532
533   taglist = gst_tag_list_new ();
534
535   gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
536       GST_TAG_AUDIO_CODEC, "DTS DCA",
537       GST_TAG_BITRATE, (guint) dts->bit_rate, NULL);
538
539   gst_element_found_tags_for_pad (GST_ELEMENT (dts), dts->srcpad, taglist);
540 }
541
542 static GstFlowReturn
543 gst_dtsdec_handle_frame (GstDtsDec * dts, guint8 * data,
544     guint length, gint flags, gint sample_rate, gint bit_rate)
545 {
546   gint channels, i, num_blocks;
547   gboolean need_renegotiation = FALSE;
548
549   /* go over stream properties, renegotiate or update streaminfo if needed */
550   if (dts->sample_rate != sample_rate) {
551     need_renegotiation = TRUE;
552     dts->sample_rate = sample_rate;
553   }
554
555   if (flags) {
556     dts->stream_channels = flags & (DCA_CHANNEL_MASK | DCA_LFE);
557   }
558
559   if (bit_rate != dts->bit_rate) {
560     dts->bit_rate = bit_rate;
561     gst_dtsdec_update_streaminfo (dts);
562   }
563
564   /* If we haven't had an explicit number of channels chosen through properties
565    * at this point, choose what to downmix to now, based on what the peer will 
566    * accept - this allows a52dec to do downmixing in preference to a 
567    * downstream element such as audioconvert.
568    * FIXME: Add the property back in for forcing output channels.
569    */
570   if (dts->request_channels != DCA_CHANNEL) {
571     flags = dts->request_channels;
572   } else if (dts->flag_update) {
573     GstCaps *caps;
574
575     dts->flag_update = FALSE;
576
577     caps = gst_pad_get_allowed_caps (dts->srcpad);
578     if (caps && gst_caps_get_size (caps) > 0) {
579       GstCaps *copy = gst_caps_copy_nth (caps, 0);
580       GstStructure *structure = gst_caps_get_structure (copy, 0);
581       gint channels;
582       const int dts_channels[6] = {
583         DCA_MONO,
584         DCA_STEREO,
585         DCA_STEREO | DCA_LFE,
586         DCA_2F2R,
587         DCA_2F2R | DCA_LFE,
588         DCA_3F2R | DCA_LFE,
589       };
590
591       /* Prefer the original number of channels, but fixate to something 
592        * preferred (first in the caps) downstream if possible.
593        */
594       gst_structure_fixate_field_nearest_int (structure, "channels",
595           flags ? gst_dtsdec_channels (flags, NULL) : 6);
596       gst_structure_get_int (structure, "channels", &channels);
597       if (channels <= 6)
598         flags = dts_channels[channels - 1];
599       else
600         flags = dts_channels[5];
601
602       gst_caps_unref (copy);
603     } else if (flags) {
604       flags = dts->stream_channels;
605     } else {
606       flags = DCA_3F2R | DCA_LFE;
607     }
608
609     if (caps)
610       gst_caps_unref (caps);
611   } else {
612     flags = dts->using_channels;
613   }
614   /* process */
615   flags |= DCA_ADJUST_LEVEL;
616   dts->level = 1;
617   if (dca_frame (dts->state, data, &flags, &dts->level, dts->bias)) {
618     GST_WARNING_OBJECT (dts, "dts_frame error");
619     dts->discont = TRUE;
620     return GST_FLOW_OK;
621   }
622   channels = flags & (DCA_CHANNEL_MASK | DCA_LFE);
623   if (dts->using_channels != channels) {
624     need_renegotiation = TRUE;
625     dts->using_channels = channels;
626   }
627
628   /* negotiate if required */
629   if (need_renegotiation) {
630     GST_DEBUG ("dtsdec: sample_rate:%d stream_chans:0x%x using_chans:0x%x",
631         dts->sample_rate, dts->stream_channels, dts->using_channels);
632     if (!gst_dtsdec_renegotiate (dts)) {
633       GST_ELEMENT_ERROR (dts, CORE, NEGOTIATION, (NULL), (NULL));
634       return GST_FLOW_ERROR;
635     }
636   }
637
638   if (dts->dynamic_range_compression == FALSE) {
639     dca_dynrng (dts->state, NULL, NULL);
640   }
641
642   /* handle decoded data, one block is 256 samples */
643   num_blocks = dca_blocks_num (dts->state);
644   for (i = 0; i < num_blocks; i++) {
645     if (dca_block (dts->state)) {
646       /* Ignore errors, but mark a discont */
647       GST_WARNING_OBJECT (dts, "dts_block error %d", i);
648       dts->discont = TRUE;
649     } else {
650       GstFlowReturn ret;
651
652       /* push on */
653       ret = gst_dtsdec_push (dts, dts->srcpad, dts->using_channels,
654           dts->samples, dts->time);
655       if (ret != GST_FLOW_OK)
656         return ret;
657     }
658     dts->time += GST_SECOND * 256 / dts->sample_rate;
659   }
660
661   return GST_FLOW_OK;
662 }
663
664 static gboolean
665 gst_dtsdec_sink_setcaps (GstPad * pad, GstCaps * caps)
666 {
667   GstDtsDec *dts = GST_DTSDEC (gst_pad_get_parent (pad));
668   GstStructure *structure;
669
670   structure = gst_caps_get_structure (caps, 0);
671
672   if (structure && gst_structure_has_name (structure, "audio/x-private1-dts"))
673     dts->dvdmode = TRUE;
674   else
675     dts->dvdmode = FALSE;
676
677   gst_object_unref (dts);
678
679   return TRUE;
680 }
681
682 static GstFlowReturn
683 gst_dtsdec_chain (GstPad * pad, GstBuffer * buf)
684 {
685   GstFlowReturn ret = GST_FLOW_OK;
686   GstDtsDec *dts = GST_DTSDEC (GST_PAD_PARENT (pad));
687   gint first_access;
688
689   if (GST_BUFFER_IS_DISCONT (buf)) {
690     GST_LOG_OBJECT (dts, "received DISCONT");
691     gst_dtsdec_drain (dts);
692     /* clear cache on discont and mark a discont in the element */
693     if (dts->cache) {
694       gst_buffer_unref (dts->cache);
695       dts->cache = NULL;
696     }
697     dts->discont = TRUE;
698   }
699
700   if (dts->dvdmode) {
701     gint size = GST_BUFFER_SIZE (buf);
702     guint8 *data = GST_BUFFER_DATA (buf);
703     gint offset, len;
704     GstBuffer *subbuf;
705
706     if (size < 2)
707       goto not_enough_data;
708
709     first_access = (data[0] << 8) | data[1];
710
711     /* Skip the first_access header */
712     offset = 2;
713
714     if (first_access > 1) {
715       /* Length of data before first_access */
716       len = first_access - 1;
717
718       if (len <= 0 || offset + len > size)
719         goto bad_first_access_parameter;
720
721       subbuf = gst_buffer_create_sub (buf, offset, len);
722       GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE;
723       ret = gst_dtsdec_chain_raw (pad, subbuf);
724       if (ret != GST_FLOW_OK)
725         goto done;
726
727       offset += len;
728       len = size - offset;
729
730       if (len > 0) {
731         subbuf = gst_buffer_create_sub (buf, offset, len);
732         GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
733
734         ret = gst_dtsdec_chain_raw (pad, subbuf);
735       }
736     } else {
737       /* first_access = 0 or 1, so if there's a timestamp it applies to the first byte */
738       subbuf = gst_buffer_create_sub (buf, offset, size - offset);
739       GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
740       ret = gst_dtsdec_chain_raw (pad, subbuf);
741     }
742   } else {
743     gst_buffer_ref (buf);
744     ret = gst_dtsdec_chain_raw (pad, buf);
745   }
746
747 done:
748   gst_buffer_unref (buf);
749   return ret;
750
751 /* ERRORS */
752 not_enough_data:
753   {
754     GST_ELEMENT_ERROR (GST_ELEMENT (dts), STREAM, DECODE, (NULL),
755         ("Insufficient data in buffer. Can't determine first_acess"));
756     gst_buffer_unref (buf);
757     return GST_FLOW_ERROR;
758   }
759 bad_first_access_parameter:
760   {
761     GST_ELEMENT_ERROR (GST_ELEMENT (dts), STREAM, DECODE, (NULL),
762         ("Bad first_access parameter (%d) in buffer", first_access));
763     gst_buffer_unref (buf);
764     return GST_FLOW_ERROR;
765   }
766 }
767
768 static GstFlowReturn
769 gst_dtsdec_chain_raw (GstPad * pad, GstBuffer * buf)
770 {
771   GstDtsDec *dts;
772   guint8 *data;
773   gint size;
774   gint length = 0, flags, sample_rate, bit_rate, frame_length;
775   GstFlowReturn result = GST_FLOW_OK;
776
777   dts = GST_DTSDEC (GST_PAD_PARENT (pad));
778
779   if (!dts->sent_segment) {
780     GstSegment segment;
781
782     /* Create a basic segment. Usually, we'll get a new-segment sent by 
783      * another element that will know more information (a demuxer). If we're
784      * just looking at a raw AC3 stream, we won't - so we need to send one
785      * here, but we don't know much info, so just send a minimal TIME 
786      * new-segment event
787      */
788     gst_segment_init (&segment, GST_FORMAT_TIME);
789     gst_pad_push_event (dts->srcpad, gst_event_new_new_segment (FALSE,
790             segment.rate, segment.format, segment.start,
791             segment.duration, segment.start));
792     dts->sent_segment = TRUE;
793   }
794
795   /* merge with cache, if any. Also make sure timestamps match */
796   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
797     dts->time = GST_BUFFER_TIMESTAMP (buf);
798     GST_DEBUG_OBJECT (dts,
799         "Received buffer with ts %" GST_TIME_FORMAT " duration %"
800         GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
801         GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
802   }
803
804   if (dts->cache) {
805     buf = gst_buffer_join (dts->cache, buf);
806     dts->cache = NULL;
807   }
808   data = GST_BUFFER_DATA (buf);
809   size = GST_BUFFER_SIZE (buf);
810
811   /* find and read header */
812   bit_rate = dts->bit_rate;
813   sample_rate = dts->sample_rate;
814   flags = 0;
815   while (size >= 7) {
816     length = dca_syncinfo (dts->state, data, &flags,
817         &sample_rate, &bit_rate, &frame_length);
818
819     if (length == 0) {
820       /* shift window to re-find sync */
821       data++;
822       size--;
823     } else if (length <= size) {
824       GST_DEBUG ("Sync: frame size %d", length);
825
826       if (flags != dts->prev_flags)
827         dts->flag_update = TRUE;
828       dts->prev_flags = flags;
829
830       result = gst_dtsdec_handle_frame (dts, data, length,
831           flags, sample_rate, bit_rate);
832       if (result != GST_FLOW_OK) {
833         size = 0;
834         break;
835       }
836       size -= length;
837       data += length;
838     } else {
839       GST_LOG ("Not enough data available (needed %d had %d)", length, size);
840       break;
841     }
842   }
843
844   /* keep cache */
845   if (length == 0) {
846     GST_LOG ("No sync found");
847   }
848
849   if (size > 0) {
850     dts->cache = gst_buffer_create_sub (buf,
851         GST_BUFFER_SIZE (buf) - size, size);
852   }
853
854   gst_buffer_unref (buf);
855
856   return result;
857 }
858
859 static GstStateChangeReturn
860 gst_dtsdec_change_state (GstElement * element, GstStateChange transition)
861 {
862   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
863   GstDtsDec *dts = GST_DTSDEC (element);
864
865   switch (transition) {
866     case GST_STATE_CHANGE_NULL_TO_READY:{
867       GstDtsDecClass *klass;
868
869       klass = GST_DTSDEC_CLASS (G_OBJECT_GET_CLASS (dts));
870       dts->state = dca_init (klass->dts_cpuflags);
871       break;
872     }
873     case GST_STATE_CHANGE_READY_TO_PAUSED:
874       dts->samples = dca_samples (dts->state);
875       dts->bit_rate = -1;
876       dts->sample_rate = -1;
877       dts->stream_channels = DCA_CHANNEL;
878       dts->using_channels = DCA_CHANNEL;
879       dts->level = 1;
880       dts->bias = 0;
881       dts->time = 0;
882       dts->sent_segment = FALSE;
883       dts->flag_update = TRUE;
884       gst_segment_init (&dts->segment, GST_FORMAT_UNDEFINED);
885       break;
886     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
887       break;
888     default:
889       break;
890   }
891
892   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
893
894   switch (transition) {
895     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
896       break;
897     case GST_STATE_CHANGE_PAUSED_TO_READY:
898       dts->samples = NULL;
899       if (dts->cache) {
900         gst_buffer_unref (dts->cache);
901         dts->cache = NULL;
902       }
903       clear_queued (dts);
904       break;
905     case GST_STATE_CHANGE_READY_TO_NULL:
906       dca_free (dts->state);
907       dts->state = NULL;
908       break;
909     default:
910       break;
911   }
912
913   return ret;
914 }
915
916 static void
917 gst_dtsdec_set_property (GObject * object, guint prop_id, const GValue * value,
918     GParamSpec * pspec)
919 {
920   GstDtsDec *dts = GST_DTSDEC (object);
921
922   switch (prop_id) {
923     case ARG_DRC:
924       dts->dynamic_range_compression = g_value_get_boolean (value);
925       break;
926     default:
927       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
928       break;
929   }
930 }
931
932 static void
933 gst_dtsdec_get_property (GObject * object, guint prop_id, GValue * value,
934     GParamSpec * pspec)
935 {
936   GstDtsDec *dts = GST_DTSDEC (object);
937
938   switch (prop_id) {
939     case ARG_DRC:
940       g_value_set_boolean (value, dts->dynamic_range_compression);
941       break;
942     default:
943       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
944       break;
945   }
946 }
947
948 static gboolean
949 plugin_init (GstPlugin * plugin)
950 {
951   if (!gst_element_register (plugin, "dtsdec", GST_RANK_PRIMARY,
952           GST_TYPE_DTSDEC))
953     return FALSE;
954
955   return TRUE;
956 }
957
958 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
959     GST_VERSION_MINOR,
960     "dtsdec",
961     "Decodes DTS audio streams",
962     plugin_init, VERSION, "GPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);