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., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 /**
22  * SECTION:element-dtsdec
23  * @title: dtsdec
24  *
25  * Digital Theatre System (DTS) audio decoder
26  *
27  * ## Example launch line
28  * |[
29  * gst-launch-1.0 dvdreadsrc title=1 ! mpegpsdemux ! dtsdec ! audioresample ! audioconvert ! alsasink
30  * ]| Play a DTS audio track from a dvd.
31  * |[
32  * gst-launch-1.0 filesrc location=abc.dts ! dtsdec ! audioresample ! audioconvert ! alsasink
33  * ]| Decode a standalone file and play it.
34  *
35  */
36 
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40 
41 #ifdef HAVE_STDINT_H
42 #include <stdint.h>
43 #endif
44 
45 #include <string.h>
46 #include <stdlib.h>
47 
48 #include <gst/gst.h>
49 #include <gst/audio/audio.h>
50 
51 #ifndef DTS_OLD
52 #include <dca.h>
53 #else
54 #include <dts.h>
55 
56 typedef struct dts_state_s dca_state_t;
57 #define DCA_MONO DTS_MONO
58 #define DCA_CHANNEL DTS_CHANNEL
59 #define DCA_STEREO DTS_STEREO
60 #define DCA_STEREO_SUMDIFF DTS_STEREO_SUMDIFF
61 #define DCA_STEREO_TOTAL DTS_STEREO_TOTAL
62 #define DCA_3F DTS_3F
63 #define DCA_2F1R DTS_2F1R
64 #define DCA_3F1R DTS_3F1R
65 #define DCA_2F2R DTS_2F2R
66 #define DCA_3F2R DTS_3F2R
67 #define DCA_4F2R DTS_4F2R
68 #define DCA_DOLBY DTS_DOLBY
69 #define DCA_CHANNEL_MAX DTS_CHANNEL_MAX
70 #define DCA_CHANNEL_BITS DTS_CHANNEL_BITS
71 #define DCA_CHANNEL_MASK DTS_CHANNEL_MASK
72 #define DCA_LFE DTS_LFE
73 #define DCA_ADJUST_LEVEL DTS_ADJUST_LEVEL
74 
75 #define dca_init dts_init
76 #define dca_syncinfo dts_syncinfo
77 #define dca_frame dts_frame
78 #define dca_dynrng dts_dynrng
79 #define dca_blocks_num dts_blocks_num
80 #define dca_block dts_block
81 #define dca_samples dts_samples
82 #define dca_free dts_free
83 #endif
84 
85 #include "gstdtsdec.h"
86 
87 #if HAVE_ORC
88 #include <orc/orc.h>
89 #endif
90 
91 #if defined(LIBDTS_FIXED) || defined(LIBDCA_FIXED)
92 #define SAMPLE_WIDTH 16
93 #define SAMPLE_FORMAT GST_AUDIO_NE(S16)
94 #define SAMPLE_TYPE GST_AUDIO_FORMAT_S16
95 #elif defined (LIBDTS_DOUBLE) || defined(LIBDCA_DOUBLE)
96 #define SAMPLE_WIDTH 64
97 #define SAMPLE_FORMAT GST_AUDIO_NE(F64)
98 #define SAMPLE_TYPE GST_AUDIO_FORMAT_F64
99 #else
100 #define SAMPLE_WIDTH 32
101 #define SAMPLE_FORMAT GST_AUDIO_NE(F32)
102 #define SAMPLE_TYPE GST_AUDIO_FORMAT_F32
103 #endif
104 
105 GST_DEBUG_CATEGORY_STATIC (dtsdec_debug);
106 #define GST_CAT_DEFAULT (dtsdec_debug)
107 
108 enum
109 {
110   PROP_0,
111   PROP_DRC
112 };
113 
114 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
115     GST_PAD_SINK,
116     GST_PAD_ALWAYS,
117     GST_STATIC_CAPS ("audio/x-dts; audio/x-private1-dts")
118     );
119 
120 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
121     GST_PAD_SRC,
122     GST_PAD_ALWAYS,
123     GST_STATIC_CAPS ("audio/x-raw, "
124         "format = (string) " SAMPLE_FORMAT ", "
125         "layout = (string) interleaved, "
126         "rate = (int) [ 4000, 96000 ], " "channels = (int) [ 1, 6 ]")
127     );
128 
129 G_DEFINE_TYPE (GstDtsDec, gst_dtsdec, GST_TYPE_AUDIO_DECODER);
130 
131 static gboolean gst_dtsdec_start (GstAudioDecoder * dec);
132 static gboolean gst_dtsdec_stop (GstAudioDecoder * dec);
133 static gboolean gst_dtsdec_set_format (GstAudioDecoder * bdec, GstCaps * caps);
134 static GstFlowReturn gst_dtsdec_parse (GstAudioDecoder * dec,
135     GstAdapter * adapter, gint * offset, gint * length);
136 static GstFlowReturn gst_dtsdec_handle_frame (GstAudioDecoder * dec,
137     GstBuffer * buffer);
138 
139 static GstFlowReturn gst_dtsdec_chain (GstPad * pad, GstObject * parent,
140     GstBuffer * buf);
141 
142 static void gst_dtsdec_set_property (GObject * object, guint prop_id,
143     const GValue * value, GParamSpec * pspec);
144 static void gst_dtsdec_get_property (GObject * object, guint prop_id,
145     GValue * value, GParamSpec * pspec);
146 
147 static void
gst_dtsdec_class_init(GstDtsDecClass * klass)148 gst_dtsdec_class_init (GstDtsDecClass * klass)
149 {
150   GObjectClass *gobject_class;
151   GstElementClass *gstelement_class;
152   GstAudioDecoderClass *gstbase_class;
153   guint cpuflags;
154 
155   gobject_class = (GObjectClass *) klass;
156   gstelement_class = (GstElementClass *) klass;
157   gstbase_class = (GstAudioDecoderClass *) klass;
158 
159   gobject_class->set_property = gst_dtsdec_set_property;
160   gobject_class->get_property = gst_dtsdec_get_property;
161 
162   gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
163   gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
164   gst_element_class_set_static_metadata (gstelement_class, "DTS audio decoder",
165       "Codec/Decoder/Audio",
166       "Decodes DTS audio streams",
167       "Jan Schmidt <thaytan@noraisin.net>, "
168       "Ronald Bultje <rbultje@ronald.bitfreak.net>");
169 
170   gstbase_class->start = GST_DEBUG_FUNCPTR (gst_dtsdec_start);
171   gstbase_class->stop = GST_DEBUG_FUNCPTR (gst_dtsdec_stop);
172   gstbase_class->set_format = GST_DEBUG_FUNCPTR (gst_dtsdec_set_format);
173   gstbase_class->parse = GST_DEBUG_FUNCPTR (gst_dtsdec_parse);
174   gstbase_class->handle_frame = GST_DEBUG_FUNCPTR (gst_dtsdec_handle_frame);
175 
176   /**
177    * GstDtsDec::drc
178    *
179    * Set to true to apply the recommended DTS dynamic range compression
180    * to the audio stream. Dynamic range compression makes loud sounds
181    * softer and soft sounds louder, so you can more easily listen
182    * to the stream without disturbing other people.
183    */
184   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DRC,
185       g_param_spec_boolean ("drc", "Dynamic Range Compression",
186           "Use Dynamic Range Compression", FALSE,
187           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
188 
189   klass->dts_cpuflags = 0;
190 
191 #if HAVE_ORC
192   cpuflags = orc_target_get_default_flags (orc_target_get_by_name ("mmx"));
193   if (cpuflags & ORC_TARGET_MMX_MMX)
194     klass->dts_cpuflags |= MM_ACCEL_X86_MMX;
195   if (cpuflags & ORC_TARGET_MMX_3DNOW)
196     klass->dts_cpuflags |= MM_ACCEL_X86_3DNOW;
197   if (cpuflags & ORC_TARGET_MMX_MMXEXT)
198     klass->dts_cpuflags |= MM_ACCEL_X86_MMXEXT;
199 #else
200   cpuflags = 0;
201   klass->dts_cpuflags = 0;
202 #endif
203 
204   GST_LOG ("CPU flags: dts=%08x, orc=%08x", klass->dts_cpuflags, cpuflags);
205 }
206 
207 static void
gst_dtsdec_init(GstDtsDec * dtsdec)208 gst_dtsdec_init (GstDtsDec * dtsdec)
209 {
210   dtsdec->request_channels = DCA_CHANNEL;
211   dtsdec->dynamic_range_compression = FALSE;
212 
213   gst_audio_decoder_set_use_default_pad_acceptcaps (GST_AUDIO_DECODER_CAST
214       (dtsdec), TRUE);
215   GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_DECODER_SINK_PAD (dtsdec));
216 
217   /* retrieve and intercept base class chain.
218    * Quite HACKish, but that's dvd specs for you,
219    * since one buffer needs to be split into 2 frames */
220   dtsdec->base_chain = GST_PAD_CHAINFUNC (GST_AUDIO_DECODER_SINK_PAD (dtsdec));
221   gst_pad_set_chain_function (GST_AUDIO_DECODER_SINK_PAD (dtsdec),
222       GST_DEBUG_FUNCPTR (gst_dtsdec_chain));
223 }
224 
225 static gboolean
gst_dtsdec_start(GstAudioDecoder * dec)226 gst_dtsdec_start (GstAudioDecoder * dec)
227 {
228   GstDtsDec *dts = GST_DTSDEC (dec);
229   GstDtsDecClass *klass;
230 
231   GST_DEBUG_OBJECT (dec, "start");
232 
233   klass = GST_DTSDEC_CLASS (G_OBJECT_GET_CLASS (dts));
234   dts->state = dca_init (klass->dts_cpuflags);
235   dts->samples = dca_samples (dts->state);
236   dts->bit_rate = -1;
237   dts->sample_rate = -1;
238   dts->stream_channels = DCA_CHANNEL;
239   dts->using_channels = DCA_CHANNEL;
240   dts->level = 1;
241   dts->bias = 0;
242   dts->flag_update = TRUE;
243 
244   /* call upon legacy upstream byte support (e.g. seeking) */
245   gst_audio_decoder_set_estimate_rate (dec, TRUE);
246 
247   return TRUE;
248 }
249 
250 static gboolean
gst_dtsdec_stop(GstAudioDecoder * dec)251 gst_dtsdec_stop (GstAudioDecoder * dec)
252 {
253   GstDtsDec *dts = GST_DTSDEC (dec);
254 
255   GST_DEBUG_OBJECT (dec, "stop");
256 
257   dts->samples = NULL;
258   if (dts->state) {
259     dca_free (dts->state);
260     dts->state = NULL;
261   }
262 
263   return TRUE;
264 }
265 
266 static GstFlowReturn
gst_dtsdec_parse(GstAudioDecoder * bdec,GstAdapter * adapter,gint * _offset,gint * len)267 gst_dtsdec_parse (GstAudioDecoder * bdec, GstAdapter * adapter,
268     gint * _offset, gint * len)
269 {
270   GstDtsDec *dts;
271   guint8 *data;
272   gint av, size;
273   gint length = 0, flags, sample_rate, bit_rate, frame_length;
274   GstFlowReturn result = GST_FLOW_EOS;
275 
276   dts = GST_DTSDEC (bdec);
277 
278   size = av = gst_adapter_available (adapter);
279   data = (guint8 *) gst_adapter_map (adapter, av);
280 
281   /* find and read header */
282   bit_rate = dts->bit_rate;
283   sample_rate = dts->sample_rate;
284   flags = 0;
285   while (size >= 7) {
286     length = dca_syncinfo (dts->state, data, &flags,
287         &sample_rate, &bit_rate, &frame_length);
288 
289     if (length == 0) {
290       /* shift window to re-find sync */
291       data++;
292       size--;
293     } else if (length <= size) {
294       GST_LOG_OBJECT (dts, "Sync: frame size %d", length);
295       result = GST_FLOW_OK;
296       break;
297     } else {
298       GST_LOG_OBJECT (dts, "Not enough data available (needed %d had %d)",
299           length, size);
300       break;
301     }
302   }
303   gst_adapter_unmap (adapter);
304 
305   *_offset = av - size;
306   *len = length;
307 
308   return result;
309 }
310 
311 static gint
gst_dtsdec_channels(uint32_t flags,GstAudioChannelPosition * pos)312 gst_dtsdec_channels (uint32_t flags, GstAudioChannelPosition * pos)
313 {
314   gint chans = 0;
315 
316   switch (flags & DCA_CHANNEL_MASK) {
317     case DCA_MONO:
318       chans = 1;
319       if (pos) {
320         pos[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
321       }
322       break;
323       /* case DCA_CHANNEL: */
324     case DCA_STEREO:
325     case DCA_STEREO_SUMDIFF:
326     case DCA_STEREO_TOTAL:
327     case DCA_DOLBY:
328       chans = 2;
329       if (pos) {
330         pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
331         pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
332       }
333       break;
334     case DCA_3F:
335       chans = 3;
336       if (pos) {
337         pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
338         pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
339         pos[2] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
340       }
341       break;
342     case DCA_2F1R:
343       chans = 3;
344       if (pos) {
345         pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
346         pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
347         pos[2] = GST_AUDIO_CHANNEL_POSITION_REAR_CENTER;
348       }
349       break;
350     case DCA_3F1R:
351       chans = 4;
352       if (pos) {
353         pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
354         pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
355         pos[2] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
356         pos[3] = GST_AUDIO_CHANNEL_POSITION_REAR_CENTER;
357       }
358       break;
359     case DCA_2F2R:
360       chans = 4;
361       if (pos) {
362         pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
363         pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
364         pos[2] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
365         pos[3] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
366       }
367       break;
368     case DCA_3F2R:
369       chans = 5;
370       if (pos) {
371         pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
372         pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
373         pos[2] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
374         pos[3] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
375         pos[4] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
376       }
377       break;
378     case DCA_4F2R:
379       chans = 6;
380       if (pos) {
381         pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
382         pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
383         pos[2] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
384         pos[3] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
385         pos[4] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
386         pos[5] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
387       }
388       break;
389     default:
390       g_warning ("dtsdec: invalid flags 0x%x", flags);
391       return 0;
392   }
393   if (flags & DCA_LFE) {
394     if (pos) {
395       pos[chans] = GST_AUDIO_CHANNEL_POSITION_LFE1;
396     }
397     chans += 1;
398   }
399 
400   return chans;
401 }
402 
403 static gboolean
gst_dtsdec_renegotiate(GstDtsDec * dts)404 gst_dtsdec_renegotiate (GstDtsDec * dts)
405 {
406   gint channels;
407   gboolean result = FALSE;
408   GstAudioChannelPosition from[7], to[7];
409   GstAudioInfo info;
410 
411   channels = gst_dtsdec_channels (dts->using_channels, from);
412 
413   if (channels <= 0 || channels > 7)
414     goto done;
415 
416   GST_INFO_OBJECT (dts, "dtsdec renegotiate, channels=%d, rate=%d",
417       channels, dts->sample_rate);
418 
419   memcpy (to, from, sizeof (GstAudioChannelPosition) * channels);
420   gst_audio_channel_positions_to_valid_order (to, channels);
421   gst_audio_get_channel_reorder_map (channels, from, to,
422       dts->channel_reorder_map);
423 
424 
425   gst_audio_info_init (&info);
426   gst_audio_info_set_format (&info,
427       SAMPLE_TYPE, dts->sample_rate, channels, (channels > 1 ? to : NULL));
428 
429   if (!gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (dts), &info))
430     goto done;
431 
432   result = TRUE;
433 
434 done:
435   return result;
436 }
437 
438 static void
gst_dtsdec_update_streaminfo(GstDtsDec * dts)439 gst_dtsdec_update_streaminfo (GstDtsDec * dts)
440 {
441   GstTagList *taglist;
442 
443   if (dts->bit_rate > 3) {
444     taglist = gst_tag_list_new_empty ();
445     /* 1 => open bitrate, 2 => variable bitrate, 3 => lossless */
446     gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_BITRATE,
447         (guint) dts->bit_rate, NULL);
448     gst_audio_decoder_merge_tags (GST_AUDIO_DECODER (dts), taglist,
449         GST_TAG_MERGE_REPLACE);
450     if (taglist)
451       gst_tag_list_unref (taglist);
452   }
453 }
454 
455 static GstFlowReturn
gst_dtsdec_handle_frame(GstAudioDecoder * bdec,GstBuffer * buffer)456 gst_dtsdec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buffer)
457 {
458   GstDtsDec *dts;
459   gint channels, i, num_blocks;
460   gboolean need_renegotiation = FALSE;
461   guint8 *data;
462   GstMapInfo map;
463   gint chans;
464 #ifndef G_DISABLE_ASSERT
465   gsize size;
466   gint length;
467 #endif
468   gint flags, sample_rate, bit_rate, frame_length;
469   GstFlowReturn result = GST_FLOW_OK;
470   GstBuffer *outbuf;
471 
472   dts = GST_DTSDEC (bdec);
473 
474   /* no fancy draining */
475   if (G_UNLIKELY (!buffer))
476     return GST_FLOW_OK;
477 
478   /* parsed stuff already, so this should work out fine */
479   gst_buffer_map (buffer, &map, GST_MAP_READ);
480   data = map.data;
481 
482 #ifndef G_DISABLE_ASSERT
483   size = map.size;
484   g_assert (size >= 7);
485 #endif
486 
487   bit_rate = dts->bit_rate;
488   sample_rate = dts->sample_rate;
489   flags = 0;
490 
491 #ifndef G_DISABLE_ASSERT
492   length = dca_syncinfo (dts->state, data, &flags, &sample_rate, &bit_rate,
493       &frame_length);
494   g_assert (length == size);
495 #else
496   (void) dca_syncinfo (dts->state, data, &flags, &sample_rate, &bit_rate,
497       &frame_length);
498 #endif
499 
500   if (flags != dts->prev_flags) {
501     dts->prev_flags = flags;
502     dts->flag_update = TRUE;
503   }
504 
505   /* go over stream properties, renegotiate or update streaminfo if needed */
506   if (dts->sample_rate != sample_rate) {
507     need_renegotiation = TRUE;
508     dts->sample_rate = sample_rate;
509   }
510 
511   if (flags) {
512     dts->stream_channels = flags & (DCA_CHANNEL_MASK | DCA_LFE);
513   }
514 
515   if (bit_rate != dts->bit_rate) {
516     dts->bit_rate = bit_rate;
517     gst_dtsdec_update_streaminfo (dts);
518   }
519 
520   /* If we haven't had an explicit number of channels chosen through properties
521    * at this point, choose what to downmix to now, based on what the peer will
522    * accept - this allows a52dec to do downmixing in preference to a
523    * downstream element such as audioconvert.
524    * FIXME: Add the property back in for forcing output channels.
525    */
526   if (dts->request_channels != DCA_CHANNEL) {
527     flags = dts->request_channels;
528   } else if (dts->flag_update) {
529     GstCaps *caps;
530 
531     dts->flag_update = FALSE;
532 
533     caps = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (dts));
534     if (caps && gst_caps_get_size (caps) > 0) {
535       GstCaps *copy = gst_caps_copy_nth (caps, 0);
536       GstStructure *structure = gst_caps_get_structure (copy, 0);
537       gint channels;
538       const int dts_channels[6] = {
539         DCA_MONO,
540         DCA_STEREO,
541         DCA_STEREO | DCA_LFE,
542         DCA_2F2R,
543         DCA_2F2R | DCA_LFE,
544         DCA_3F2R | DCA_LFE,
545       };
546 
547       /* Prefer the original number of channels, but fixate to something
548        * preferred (first in the caps) downstream if possible.
549        */
550       gst_structure_fixate_field_nearest_int (structure, "channels",
551           flags ? gst_dtsdec_channels (flags, NULL) : 6);
552       gst_structure_get_int (structure, "channels", &channels);
553       if (channels <= 6)
554         flags = dts_channels[channels - 1];
555       else
556         flags = dts_channels[5];
557 
558       gst_caps_unref (copy);
559     } else if (flags) {
560       flags = dts->stream_channels;
561     } else {
562       flags = DCA_3F2R | DCA_LFE;
563     }
564 
565     if (caps)
566       gst_caps_unref (caps);
567   } else {
568     flags = dts->using_channels;
569   }
570 
571   /* process */
572   flags |= DCA_ADJUST_LEVEL;
573   dts->level = 1;
574   if (dca_frame (dts->state, data, &flags, &dts->level, dts->bias)) {
575     gst_buffer_unmap (buffer, &map);
576     GST_AUDIO_DECODER_ERROR (dts, 1, STREAM, DECODE, (NULL),
577         ("dts_frame error"), result);
578     goto exit;
579   }
580   gst_buffer_unmap (buffer, &map);
581 
582   channels = flags & (DCA_CHANNEL_MASK | DCA_LFE);
583   if (dts->using_channels != channels) {
584     need_renegotiation = TRUE;
585     dts->using_channels = channels;
586   }
587 
588   /* negotiate if required */
589   if (need_renegotiation) {
590     GST_DEBUG_OBJECT (dts,
591         "dtsdec: sample_rate:%d stream_chans:0x%x using_chans:0x%x",
592         dts->sample_rate, dts->stream_channels, dts->using_channels);
593     if (!gst_dtsdec_renegotiate (dts))
594       goto failed_negotiation;
595   }
596 
597   if (dts->dynamic_range_compression == FALSE) {
598     dca_dynrng (dts->state, NULL, NULL);
599   }
600 
601   flags &= (DCA_CHANNEL_MASK | DCA_LFE);
602   chans = gst_dtsdec_channels (flags, NULL);
603   if (!chans)
604     goto invalid_flags;
605 
606   /* handle decoded data, one block is 256 samples */
607   num_blocks = dca_blocks_num (dts->state);
608   outbuf =
609       gst_buffer_new_and_alloc (256 * chans * (SAMPLE_WIDTH / 8) * num_blocks);
610 
611   gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
612   data = map.data;
613   {
614     guint8 *ptr = data;
615     for (i = 0; i < num_blocks; i++) {
616       if (dca_block (dts->state)) {
617         /* also marks discont */
618         GST_AUDIO_DECODER_ERROR (dts, 1, STREAM, DECODE, (NULL),
619             ("error decoding block %d", i), result);
620         if (result != GST_FLOW_OK)
621           goto exit;
622       } else {
623         gint n, c;
624         gint *reorder_map = dts->channel_reorder_map;
625 
626         for (n = 0; n < 256; n++) {
627           for (c = 0; c < chans; c++) {
628             ((sample_t *) ptr)[n * chans + reorder_map[c]] =
629                 dts->samples[c * 256 + n];
630           }
631         }
632       }
633       ptr += 256 * chans * (SAMPLE_WIDTH / 8);
634     }
635   }
636   gst_buffer_unmap (outbuf, &map);
637 
638   result = gst_audio_decoder_finish_frame (bdec, outbuf, 1);
639 
640 exit:
641   return result;
642 
643   /* ERRORS */
644 failed_negotiation:
645   {
646     GST_ELEMENT_ERROR (dts, CORE, NEGOTIATION, (NULL), (NULL));
647     return GST_FLOW_ERROR;
648   }
649 invalid_flags:
650   {
651     GST_ELEMENT_ERROR (GST_ELEMENT (dts), STREAM, DECODE, (NULL),
652         ("Invalid channel flags: %d", flags));
653     return GST_FLOW_ERROR;
654   }
655 }
656 
657 static gboolean
gst_dtsdec_set_format(GstAudioDecoder * bdec,GstCaps * caps)658 gst_dtsdec_set_format (GstAudioDecoder * bdec, GstCaps * caps)
659 {
660   GstDtsDec *dts = GST_DTSDEC (bdec);
661   GstStructure *structure;
662 
663   structure = gst_caps_get_structure (caps, 0);
664 
665   if (structure && gst_structure_has_name (structure, "audio/x-private1-dts"))
666     dts->dvdmode = TRUE;
667   else
668     dts->dvdmode = FALSE;
669 
670   return TRUE;
671 }
672 
673 static GstFlowReturn
gst_dtsdec_chain(GstPad * pad,GstObject * parent,GstBuffer * buf)674 gst_dtsdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
675 {
676   GstFlowReturn ret = GST_FLOW_OK;
677   GstDtsDec *dts = GST_DTSDEC (parent);
678   gint first_access;
679 
680   if (dts->dvdmode) {
681     guint8 data[2];
682     gsize size;
683     gint offset, len;
684     GstBuffer *subbuf;
685 
686     size = gst_buffer_get_size (buf);
687     if (size < 2)
688       goto not_enough_data;
689 
690     gst_buffer_extract (buf, 0, data, 2);
691     first_access = (data[0] << 8) | data[1];
692 
693     /* Skip the first_access header */
694     offset = 2;
695 
696     if (first_access > 1) {
697       /* Length of data before first_access */
698       len = first_access - 1;
699 
700       if (len <= 0 || offset + len > size)
701         goto bad_first_access_parameter;
702 
703       subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset, len);
704       GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE;
705       ret = dts->base_chain (pad, parent, subbuf);
706       if (ret != GST_FLOW_OK) {
707         gst_buffer_unref (buf);
708         goto done;
709       }
710 
711       offset += len;
712       len = size - offset;
713 
714       if (len > 0) {
715         subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset, len);
716         GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
717 
718         ret = dts->base_chain (pad, parent, subbuf);
719       }
720       gst_buffer_unref (buf);
721     } else {
722       /* first_access = 0 or 1, so if there's a timestamp it applies to the first byte */
723       subbuf =
724           gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset,
725           size - offset);
726       GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
727       ret = dts->base_chain (pad, parent, subbuf);
728       gst_buffer_unref (buf);
729     }
730   } else {
731     ret = dts->base_chain (pad, parent, buf);
732   }
733 
734 done:
735   return ret;
736 
737 /* ERRORS */
738 not_enough_data:
739   {
740     GST_ELEMENT_ERROR (GST_ELEMENT (dts), STREAM, DECODE, (NULL),
741         ("Insufficient data in buffer. Can't determine first_acess"));
742     gst_buffer_unref (buf);
743     return GST_FLOW_ERROR;
744   }
745 bad_first_access_parameter:
746   {
747     GST_ELEMENT_ERROR (GST_ELEMENT (dts), STREAM, DECODE, (NULL),
748         ("Bad first_access parameter (%d) in buffer", first_access));
749     gst_buffer_unref (buf);
750     return GST_FLOW_ERROR;
751   }
752 }
753 
754 static void
gst_dtsdec_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)755 gst_dtsdec_set_property (GObject * object, guint prop_id, const GValue * value,
756     GParamSpec * pspec)
757 {
758   GstDtsDec *dts = GST_DTSDEC (object);
759 
760   switch (prop_id) {
761     case PROP_DRC:
762       dts->dynamic_range_compression = g_value_get_boolean (value);
763       break;
764     default:
765       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
766       break;
767   }
768 }
769 
770 static void
gst_dtsdec_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)771 gst_dtsdec_get_property (GObject * object, guint prop_id, GValue * value,
772     GParamSpec * pspec)
773 {
774   GstDtsDec *dts = GST_DTSDEC (object);
775 
776   switch (prop_id) {
777     case PROP_DRC:
778       g_value_set_boolean (value, dts->dynamic_range_compression);
779       break;
780     default:
781       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
782       break;
783   }
784 }
785 
786 static gboolean
plugin_init(GstPlugin * plugin)787 plugin_init (GstPlugin * plugin)
788 {
789   GST_DEBUG_CATEGORY_INIT (dtsdec_debug, "dtsdec", 0, "DTS/DCA audio decoder");
790 
791 #if HAVE_ORC
792   orc_init ();
793 #endif
794 
795   if (!gst_element_register (plugin, "dtsdec", GST_RANK_PRIMARY,
796           GST_TYPE_DTSDEC))
797     return FALSE;
798 
799   return TRUE;
800 }
801 
802 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
803     GST_VERSION_MINOR,
804     dtsdec,
805     "Decodes DTS audio streams",
806     plugin_init, VERSION, "GPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
807