1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2005> Jan Schmidt <jan@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 /* Element-Checklist-Version: TODO */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "gstdvdlpcmdec.h"
29 #include <gst/audio/audio.h>
30 
31 GST_DEBUG_CATEGORY_STATIC (dvdlpcm_debug);
32 #define GST_CAT_DEFAULT dvdlpcm_debug
33 
34 static GstStaticPadTemplate gst_dvdlpcmdec_sink_template =
35     GST_STATIC_PAD_TEMPLATE ("sink",
36     GST_PAD_SINK,
37     GST_PAD_ALWAYS,
38     GST_STATIC_CAPS ("audio/x-private1-lpcm; "
39         "audio/x-private2-lpcm; "
40         "audio/x-private-ts-lpcm; "
41         "audio/x-lpcm, "
42         "width = (int) { 16, 20, 24 }, "
43         "rate = (int) { 32000, 44100, 48000, 96000 }, "
44         "channels = (int) [ 1, 8 ], "
45         "dynamic_range = (int) [ 0, 255 ], "
46         "emphasis = (boolean) { TRUE, FALSE }, "
47         "mute = (boolean) { TRUE, FALSE } ")
48     );
49 
50 static GstStaticPadTemplate gst_dvdlpcmdec_src_template =
51 GST_STATIC_PAD_TEMPLATE ("src",
52     GST_PAD_SRC,
53     GST_PAD_ALWAYS,
54     GST_STATIC_CAPS ("audio/x-raw, "
55         "format = (string) { S16BE, S24BE }, "
56         "layout = (string) interleaved, "
57         "rate = (int) { 32000, 44100, 48000, 96000 }, "
58         "channels = (int) [ 1, 8 ]")
59     );
60 
61 #define gst_dvdlpcmdec_parent_class parent_class
62 G_DEFINE_TYPE (GstDvdLpcmDec, gst_dvdlpcmdec, GST_TYPE_AUDIO_DECODER);
63 
64 static gboolean gst_dvdlpcmdec_set_format (GstAudioDecoder * bdec,
65     GstCaps * caps);
66 static GstFlowReturn gst_dvdlpcmdec_parse (GstAudioDecoder * bdec,
67     GstAdapter * adapter, gint * offset, gint * len);
68 static GstFlowReturn gst_dvdlpcmdec_handle_frame (GstAudioDecoder * bdec,
69     GstBuffer * buffer);
70 static GstFlowReturn gst_dvdlpcmdec_chain (GstPad * pad, GstObject * parent,
71     GstBuffer * buffer);
72 
73 
74 static void
gst_dvdlpcmdec_class_init(GstDvdLpcmDecClass * klass)75 gst_dvdlpcmdec_class_init (GstDvdLpcmDecClass * klass)
76 {
77   GstElementClass *element_class;
78   GstAudioDecoderClass *gstbase_class;
79 
80   element_class = (GstElementClass *) klass;
81   gstbase_class = (GstAudioDecoderClass *) klass;
82 
83   gstbase_class->set_format = GST_DEBUG_FUNCPTR (gst_dvdlpcmdec_set_format);
84   gstbase_class->parse = GST_DEBUG_FUNCPTR (gst_dvdlpcmdec_parse);
85   gstbase_class->handle_frame = GST_DEBUG_FUNCPTR (gst_dvdlpcmdec_handle_frame);
86 
87   gst_element_class_add_static_pad_template (element_class,
88       &gst_dvdlpcmdec_sink_template);
89   gst_element_class_add_static_pad_template (element_class,
90       &gst_dvdlpcmdec_src_template);
91   gst_element_class_set_static_metadata (element_class,
92       "DVD LPCM Audio decoder", "Codec/Decoder/Audio",
93       "Decode DVD LPCM frames into standard PCM audio",
94       "Jan Schmidt <jan@noraisin.net>, Michael Smith <msmith@fluendo.com>");
95 
96   GST_DEBUG_CATEGORY_INIT (dvdlpcm_debug, "dvdlpcmdec", 0, "DVD LPCM Decoder");
97 }
98 
99 static void
gst_dvdlpcm_reset(GstDvdLpcmDec * dvdlpcmdec)100 gst_dvdlpcm_reset (GstDvdLpcmDec * dvdlpcmdec)
101 {
102   gst_audio_info_init (&dvdlpcmdec->info);
103   dvdlpcmdec->dynamic_range = 0;
104   dvdlpcmdec->emphasis = FALSE;
105   dvdlpcmdec->mute = FALSE;
106 
107   dvdlpcmdec->header = 0;
108 
109   dvdlpcmdec->mode = GST_LPCM_UNKNOWN;
110 }
111 
112 static void
gst_dvdlpcmdec_init(GstDvdLpcmDec * dvdlpcmdec)113 gst_dvdlpcmdec_init (GstDvdLpcmDec * dvdlpcmdec)
114 {
115   gst_dvdlpcm_reset (dvdlpcmdec);
116 
117   gst_audio_decoder_set_use_default_pad_acceptcaps (GST_AUDIO_DECODER_CAST
118       (dvdlpcmdec), TRUE);
119   GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_DECODER_SINK_PAD (dvdlpcmdec));
120 
121   /* retrieve and intercept base class chain.
122    * Quite HACKish, but that's dvd specs/caps for you,
123    * since one buffer needs to be split into 2 frames */
124   dvdlpcmdec->base_chain =
125       GST_PAD_CHAINFUNC (GST_AUDIO_DECODER_SINK_PAD (dvdlpcmdec));
126   gst_pad_set_chain_function (GST_AUDIO_DECODER_SINK_PAD (dvdlpcmdec),
127       GST_DEBUG_FUNCPTR (gst_dvdlpcmdec_chain));
128 }
129 
130 static const GstAudioChannelPosition channel_positions[][8] = {
131   {GST_AUDIO_CHANNEL_POSITION_MONO},
132   {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
133       GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
134   {GST_AUDIO_CHANNEL_POSITION_INVALID},
135   {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
136         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
137         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
138       GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
139   {GST_AUDIO_CHANNEL_POSITION_INVALID},
140   {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
141         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
142         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
143         GST_AUDIO_CHANNEL_POSITION_LFE1, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
144       GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
145   {GST_AUDIO_CHANNEL_POSITION_INVALID},
146   {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
147         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
148         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
149         GST_AUDIO_CHANNEL_POSITION_LFE1, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
150         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
151         GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
152       GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT},
153   {GST_AUDIO_CHANNEL_POSITION_INVALID}
154 };
155 
156 static const GstAudioChannelPosition bluray_channel_positions[][8] = {
157   /* invalid */
158   {GST_AUDIO_CHANNEL_POSITION_INVALID},
159   /* mono */
160   {GST_AUDIO_CHANNEL_POSITION_MONO},
161   /* invalid */
162   {GST_AUDIO_CHANNEL_POSITION_INVALID},
163   /* stereo */
164   {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
165       GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
166   /* surround */
167   {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
168         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
169       GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER},
170   /* 2.1 */
171   {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
172         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
173       GST_AUDIO_CHANNEL_POSITION_REAR_CENTER},
174   /* 4.0 */
175   {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
176         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
177         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
178       GST_AUDIO_CHANNEL_POSITION_REAR_CENTER},
179   /* 2.2 */
180   {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
181         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
182         GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
183       GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT},
184   /* 5.0 */
185   {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
186         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
187         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
188         GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
189       GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT},
190   /* 5.1 */
191   {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
192         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
193         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
194         GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
195         GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
196       GST_AUDIO_CHANNEL_POSITION_LFE1},
197   /* 7.0 */
198   {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
199         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
200         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
201         GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
202         GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
203         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
204       GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
205   /* 7.1 */
206   {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
207         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
208         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
209         GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
210         GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
211         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
212         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
213       GST_AUDIO_CHANNEL_POSITION_LFE1},
214   /* invalid */
215   {GST_AUDIO_CHANNEL_POSITION_INVALID},
216   /* invalid */
217   {GST_AUDIO_CHANNEL_POSITION_INVALID},
218   /* invalid */
219   {GST_AUDIO_CHANNEL_POSITION_INVALID},
220   /* invalid */
221   {GST_AUDIO_CHANNEL_POSITION_INVALID}
222 };
223 
224 static void
gst_dvdlpcmdec_send_tags(GstDvdLpcmDec * dvdlpcmdec)225 gst_dvdlpcmdec_send_tags (GstDvdLpcmDec * dvdlpcmdec)
226 {
227   GstTagList *taglist;
228   guint bitrate;
229   gint bpf, rate;
230 
231   bpf = GST_AUDIO_INFO_BPF (&dvdlpcmdec->info);
232   rate = GST_AUDIO_INFO_RATE (&dvdlpcmdec->info);
233 
234   bitrate = bpf * 8 * rate;
235 
236   taglist = gst_tag_list_new (GST_TAG_AUDIO_CODEC, "LPCM Audio",
237       GST_TAG_BITRATE, bitrate, NULL);
238 
239   gst_audio_decoder_merge_tags (GST_AUDIO_DECODER (dvdlpcmdec), taglist,
240       GST_TAG_MERGE_REPLACE);
241   gst_tag_list_unref (taglist);
242 }
243 
244 static gboolean
gst_dvdlpcmdec_set_output_format(GstDvdLpcmDec * dvdlpcmdec)245 gst_dvdlpcmdec_set_output_format (GstDvdLpcmDec * dvdlpcmdec)
246 {
247   gboolean res = TRUE;
248 
249   res = gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (dvdlpcmdec),
250       &dvdlpcmdec->info);
251   if (res) {
252     GST_DEBUG_OBJECT (dvdlpcmdec, "Successfully set output format");
253 
254     gst_dvdlpcmdec_send_tags (dvdlpcmdec);
255   } else {
256     GST_DEBUG_OBJECT (dvdlpcmdec, "Failed to set output format");
257   }
258 
259   return res;
260 }
261 
262 static void
gst_dvdlpcmdec_update_audio_formats(GstDvdLpcmDec * dec,gint channels,gint rate,GstAudioFormat format,guint8 channel_indicator,const GstAudioChannelPosition positions[][8])263 gst_dvdlpcmdec_update_audio_formats (GstDvdLpcmDec * dec, gint channels,
264     gint rate, GstAudioFormat format, guint8 channel_indicator,
265     const GstAudioChannelPosition positions[][8])
266 {
267   GST_DEBUG_OBJECT (dec, "got channels = %d, rate = %d, format = %d", channels,
268       rate, format);
269 
270   /* Reorder the channel positions and set the default into for the audio */
271   if (channels < 9
272       && positions[channel_indicator][0] !=
273       GST_AUDIO_CHANNEL_POSITION_INVALID) {
274     const GstAudioChannelPosition *position;
275     GstAudioChannelPosition sorted_position[8];
276     guint c;
277 
278     position = positions[channel_indicator];
279     for (c = 0; c < channels; ++c)
280       sorted_position[c] = position[c];
281     gst_audio_channel_positions_to_valid_order (sorted_position, channels);
282     gst_audio_info_set_format (&dec->info, format, rate, channels,
283         sorted_position);
284     if (memcmp (position, sorted_position,
285             channels * sizeof (position[0])) != 0)
286       dec->lpcm_layout = position;
287     else
288       dec->lpcm_layout = NULL;
289   } else {
290     gst_audio_info_set_format (&dec->info, format, rate, channels, NULL);
291   }
292 }
293 
294 static gboolean
gst_dvdlpcmdec_set_format(GstAudioDecoder * bdec,GstCaps * caps)295 gst_dvdlpcmdec_set_format (GstAudioDecoder * bdec, GstCaps * caps)
296 {
297   GstDvdLpcmDec *dvdlpcmdec = GST_DVDLPCMDEC (bdec);
298   GstStructure *structure;
299   gboolean res = TRUE;
300   GstAudioFormat format;
301   gint rate, channels, width;
302 
303   gst_dvdlpcm_reset (dvdlpcmdec);
304 
305   structure = gst_caps_get_structure (caps, 0);
306 
307   /* If we have the DVD structured LPCM (including header) then we wait
308    * for incoming data before creating the output pad caps */
309   if (gst_structure_has_name (structure, "audio/x-private1-lpcm")) {
310     dvdlpcmdec->mode = GST_LPCM_DVD;
311     goto done;
312   }
313   if (gst_structure_has_name (structure, "audio/x-private2-lpcm")) {
314     dvdlpcmdec->mode = GST_LPCM_1394;
315     goto done;
316   }
317   if (gst_structure_has_name (structure, "audio/x-private-ts-lpcm")) {
318     dvdlpcmdec->mode = GST_LPCM_BLURAY;
319     goto done;
320   }
321 
322   dvdlpcmdec->mode = GST_LPCM_RAW;
323 
324   res &= gst_structure_get_int (structure, "rate", &rate);
325   res &= gst_structure_get_int (structure, "channels", &channels);
326   res &= gst_structure_get_int (structure, "width", &width);
327   res &= gst_structure_get_int (structure, "dynamic_range",
328       &dvdlpcmdec->dynamic_range);
329   res &= gst_structure_get_boolean (structure, "emphasis",
330       &dvdlpcmdec->emphasis);
331   res &= gst_structure_get_boolean (structure, "mute", &dvdlpcmdec->mute);
332 
333   if (!res)
334     goto caps_parse_error;
335 
336   switch (width) {
337     case 24:
338     case 20:
339       format = GST_AUDIO_FORMAT_S24BE;
340       break;
341     case 16:
342       format = GST_AUDIO_FORMAT_S16BE;
343       break;
344     default:
345       format = GST_AUDIO_FORMAT_UNKNOWN;
346       break;
347   }
348 
349   gst_dvdlpcmdec_update_audio_formats (dvdlpcmdec, channels, rate, format,
350       channels - 1, channel_positions);
351 
352   dvdlpcmdec->width = width;
353 
354   res = gst_dvdlpcmdec_set_output_format (dvdlpcmdec);
355 
356 done:
357   return res;
358 
359   /* ERRORS */
360 caps_parse_error:
361   {
362     GST_DEBUG_OBJECT (dvdlpcmdec, "Couldn't get parameters; missing caps?");
363     return FALSE;
364   }
365 }
366 
367 static void
parse_header(GstDvdLpcmDec * dec,guint32 header)368 parse_header (GstDvdLpcmDec * dec, guint32 header)
369 {
370   GstAudioFormat format;
371   gint rate, channels, width;
372 
373   /* We don't actually use 'dynamic range', 'mute', or 'emphasis' currently,
374    * but parse them out */
375   dec->dynamic_range = header & 0xff;
376 
377   dec->mute = (header & 0x400000) != 0;
378   dec->emphasis = (header & 0x800000) != 0;
379 
380   /* These two bits tell us the bit depth */
381   switch (header & 0xC000) {
382     case 0x8000:
383       /* 24 bits in 3 bytes */
384       format = GST_AUDIO_FORMAT_S24BE;
385       width = 24;
386       break;
387     case 0x4000:
388       /* 20 bits in 3 bytes */
389       format = GST_AUDIO_FORMAT_S24BE;
390       width = 20;
391       break;
392     default:
393       format = GST_AUDIO_FORMAT_S16BE;
394       width = 16;
395       break;
396   }
397 
398   dec->width = width;
399 
400   /* Only four sample rates supported */
401   switch (header & 0x3000) {
402     case 0x0000:
403       rate = 48000;
404       break;
405     case 0x1000:
406       rate = 96000;
407       break;
408     case 0x2000:
409       rate = 44100;
410       break;
411     case 0x3000:
412       rate = 32000;
413       break;
414     default:
415       rate = 0;
416       break;
417   }
418 
419   /* And, of course, the number of channels (up to 8) */
420   channels = ((header >> 8) & 0x7) + 1;
421 
422   gst_dvdlpcmdec_update_audio_formats (dec, channels, rate, format,
423       channels - 1, channel_positions);
424 }
425 
426 static GstFlowReturn
gst_dvdlpcmdec_chain(GstPad * pad,GstObject * parent,GstBuffer * buf)427 gst_dvdlpcmdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
428 {
429   GstDvdLpcmDec *dvdlpcmdec = GST_DVDLPCMDEC (parent);
430   guint8 data[2];
431   gsize size;
432   guint first_access;
433   GstBuffer *subbuf;
434   GstFlowReturn ret = GST_FLOW_OK;
435   gint off, len;
436 
437   if (dvdlpcmdec->mode != GST_LPCM_DVD)
438     return dvdlpcmdec->base_chain (pad, parent, buf);
439 
440   size = gst_buffer_get_size (buf);
441   if (size < 5)
442     goto too_small;
443 
444   gst_buffer_extract (buf, 0, data, 2);
445   first_access = (data[0] << 8) | data[1];
446   if (first_access > size)
447     goto invalid_data;
448 
449   /* After first_access, we have an additional 3 bytes of header data; this
450    * is included within the value of first_access.
451    * So a first_access value of between 1 and 3 is just broken, we treat that
452    * the same as zero. first_access == 4 means we only need to create a single
453    * sub-buffer, greater than that we need to create two. */
454 
455   /* skip access unit bytes */
456   off = 2;
457 
458   if (first_access > 4) {
459     /* length of first buffer */
460     len = first_access - 1;
461 
462     GST_LOG_OBJECT (dvdlpcmdec, "Creating first sub-buffer off %d, len %d",
463         off, len);
464 
465     /* see if we need a subbuffer without timestamp */
466     if (off + len > size)
467       goto bad_first_access;
468 
469     subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, off, len);
470     GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE;
471     ret = dvdlpcmdec->base_chain (pad, parent, subbuf);
472     if (ret != GST_FLOW_OK)
473       goto done;
474 
475     /* then the buffer with new timestamp */
476     off += len;
477     len = size - off;
478 
479     GST_LOG_OBJECT (dvdlpcmdec, "Creating next sub-buffer off %d, len %d", off,
480         len);
481 
482     if (len > 0) {
483       GstMemory *header, *tmp;
484       subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, off, len);
485       tmp = gst_buffer_peek_memory (buf, 0);
486       header = gst_memory_copy (tmp, 2, 3);
487       gst_buffer_prepend_memory (subbuf, header);
488       GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
489 
490       ret = dvdlpcmdec->base_chain (pad, parent, subbuf);
491     }
492   } else {
493     GST_LOG_OBJECT (dvdlpcmdec,
494         "Creating single sub-buffer off %d, len %" G_GSIZE_FORMAT, off,
495         size - off);
496     subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, off, size - off);
497     GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
498     ret = dvdlpcmdec->base_chain (pad, parent, subbuf);
499   }
500 
501 done:
502   gst_buffer_unref (buf);
503 
504   return ret;
505 
506   /* ERRORS */
507 too_small:
508   {
509     /* Buffer is too small */
510     GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
511         ("Invalid data found parsing LPCM packet"),
512         ("LPCM packet was too small. Dropping"));
513     ret = GST_FLOW_OK;
514     goto done;
515   }
516 invalid_data:
517   {
518     GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
519         ("Invalid data found parsing LPCM packet"),
520         ("LPCM packet contained invalid first access. Dropping"));
521     ret = GST_FLOW_OK;
522     goto done;
523   }
524 bad_first_access:
525   {
526     GST_WARNING_OBJECT (pad, "Bad first_access parameter in buffer");
527     GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, DECODE,
528         (NULL),
529         ("first_access parameter out of range: bad buffer from demuxer"));
530     ret = GST_FLOW_ERROR;
531     goto done;
532   }
533 }
534 
535 static GstFlowReturn
gst_dvdlpcmdec_parse_dvd(GstDvdLpcmDec * dvdlpcmdec,GstAdapter * adapter,gint * offset,gint * len)536 gst_dvdlpcmdec_parse_dvd (GstDvdLpcmDec * dvdlpcmdec, GstAdapter * adapter,
537     gint * offset, gint * len)
538 {
539   guint32 header;
540   const guint8 *data;
541 
542   data = (const guint8 *) gst_adapter_map (adapter, 3);
543   if (!data)
544     goto too_small;
545 
546   /* Don't keep the 'frame number' low 5 bits of the first byte */
547   header = ((data[0] & 0xC0) << 16) | (data[1] << 8) | data[2];
548 
549   gst_adapter_unmap (adapter);
550 
551   /* see if we have a new header */
552   if (header != dvdlpcmdec->header) {
553     parse_header (dvdlpcmdec, header);
554 
555     if (!gst_dvdlpcmdec_set_output_format (dvdlpcmdec))
556       goto negotiation_failed;
557 
558     dvdlpcmdec->header = header;
559   }
560 
561   *offset = 3;
562   *len = gst_adapter_available (adapter) - 3;
563 
564   return GST_FLOW_OK;
565 
566   /* ERRORS */
567 too_small:
568   {
569     /* Buffer is too small */
570     GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
571         ("Invalid data found parsing LPCM packet"),
572         ("LPCM packet was too small. Dropping"));
573     *offset = gst_adapter_available (adapter);
574     return GST_FLOW_EOS;
575   }
576 negotiation_failed:
577   {
578     GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),
579         ("Failed to configure output format"));
580     return GST_FLOW_NOT_NEGOTIATED;
581   }
582 }
583 
584 static GstFlowReturn
gst_dvdlpcmdec_parse_bluray(GstDvdLpcmDec * dvdlpcmdec,GstAdapter * adapter,gint * offset,gint * len)585 gst_dvdlpcmdec_parse_bluray (GstDvdLpcmDec * dvdlpcmdec, GstAdapter * adapter,
586     gint * offset, gint * len)
587 {
588   guint32 header;
589   const guint8 *data;
590   guint8 channel_indicator;
591 
592   data = (const guint8 *) gst_adapter_map (adapter, 4);
593   if (!data)
594     goto too_small;
595 
596   header = GST_READ_UINT32_BE (data);
597 
598   gst_adapter_unmap (adapter);
599 
600   /* see if we have a new header */
601   if (header != dvdlpcmdec->header) {
602     GstAudioFormat format;
603     gint rate, channels;
604 
605     switch ((header >> 6) & 0x3) {
606       case 0x1:
607         format = GST_AUDIO_FORMAT_S16BE;
608         dvdlpcmdec->width = 16;
609         break;
610       case 0x2:
611         format = GST_AUDIO_FORMAT_S24BE;
612         dvdlpcmdec->width = 20;
613         break;
614       case 0x3:
615         format = GST_AUDIO_FORMAT_S24BE;
616         dvdlpcmdec->width = 24;
617         break;
618       default:
619         format = GST_AUDIO_FORMAT_UNKNOWN;
620         dvdlpcmdec->width = 0;
621         GST_WARNING ("Invalid sample depth!");
622         break;
623     }
624 
625     switch ((header >> 8) & 0xf) {
626       case 0x1:
627         rate = 48000;
628         break;
629       case 0x4:
630         rate = 96000;
631         break;
632       case 0x5:
633         rate = 192000;
634         break;
635       default:
636         rate = 0;
637         GST_WARNING ("Invalid audio sampling frequency!");
638         break;
639     }
640     channel_indicator = (header >> 12) & 0xf;
641     switch (channel_indicator) {
642       case 0x1:
643         channels = 1;
644         break;
645       case 0x3:
646         channels = 2;
647         break;
648       case 0x4:
649       case 0x5:
650         channels = 3;
651         break;
652       case 0x6:
653       case 0x7:
654         channels = 4;
655         break;
656       case 0x8:
657         channels = 5;
658         break;
659       case 0x9:
660         channels = 6;
661         break;
662       case 0xa:
663         channels = 7;
664         break;
665       case 0xb:
666         channels = 8;
667         break;
668       default:
669         channels = 0;
670         GST_WARNING ("Invalid number of audio channels!");
671         goto negotiation_failed;
672     }
673     GST_DEBUG_OBJECT (dvdlpcmdec, "got channels %d rate %d format %s",
674         channels, rate, gst_audio_format_to_string (format));
675 
676     gst_dvdlpcmdec_update_audio_formats (dvdlpcmdec, channels, rate, format,
677         channel_indicator, bluray_channel_positions);
678 
679     if (!gst_dvdlpcmdec_set_output_format (dvdlpcmdec))
680       goto negotiation_failed;
681 
682     dvdlpcmdec->header = header;
683   }
684 
685   *offset = 4;
686   *len = gst_adapter_available (adapter) - 4;
687 
688   return GST_FLOW_OK;
689 
690   /* ERRORS */
691 too_small:
692   {
693     /* Buffer is too small */
694     GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
695         ("Invalid data found parsing LPCM packet"),
696         ("LPCM packet was too small. Dropping"));
697     *offset = gst_adapter_available (adapter);
698     return GST_FLOW_EOS;
699   }
700 negotiation_failed:
701   {
702     GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),
703         ("Failed to configure output format"));
704     return GST_FLOW_NOT_NEGOTIATED;
705   }
706 
707 }
708 
709 static GstFlowReturn
gst_dvdlpcmdec_parse_1394(GstDvdLpcmDec * dvdlpcmdec,GstAdapter * adapter,gint * offset,gint * len)710 gst_dvdlpcmdec_parse_1394 (GstDvdLpcmDec * dvdlpcmdec, GstAdapter * adapter,
711     gint * offset, gint * len)
712 {
713   guint32 header;
714   const guint8 *data;
715 
716   data = (const guint8 *) gst_adapter_map (adapter, 4);
717   if (!data)
718     goto too_small;
719 
720   header = GST_READ_UINT32_BE (data);
721 
722   gst_adapter_unmap (adapter);
723 
724   /* see if we have a new header */
725   if (header != dvdlpcmdec->header) {
726     GstAudioFormat format;
727     gint rate, channels;
728 
729     if (header >> 24 != 0xa0)
730       goto invalid_data;
731 
732     switch ((header >> 6) & 0x3) {
733       case 0x0:
734         format = GST_AUDIO_FORMAT_S16BE;
735         dvdlpcmdec->width = 16;
736         break;
737       default:
738         format = GST_AUDIO_FORMAT_UNKNOWN;
739         dvdlpcmdec->width = 0;
740         GST_WARNING ("Invalid quantization word length!");
741         break;
742     }
743 
744     switch ((header >> 3) & 0x7) {
745       case 0x1:
746         rate = 44100;
747         break;
748       case 0x2:
749         rate = 48000;
750         break;
751       default:
752         rate = 0;
753         GST_WARNING ("Invalid audio sampling frequency!");
754         break;
755     }
756     switch (header & 0x7) {
757       case 0x0:                /* 2 channels dual-mono */
758       case 0x1:                /* 2 channles stereo */
759         channels = 2;
760         break;
761       default:
762         channels = 0;
763         GST_WARNING ("Invalid number of audio channels!");
764         goto negotiation_failed;
765     }
766 
767     gst_dvdlpcmdec_update_audio_formats (dvdlpcmdec, channels, rate, format,
768         channels - 1, channel_positions);
769 
770     if (!gst_dvdlpcmdec_set_output_format (dvdlpcmdec))
771       goto negotiation_failed;
772 
773     dvdlpcmdec->header = header;
774   }
775 
776   *offset = 4;
777   *len = gst_adapter_available (adapter) - 4;
778 
779   return GST_FLOW_OK;
780 
781   /* ERRORS */
782 too_small:
783   {
784     /* Buffer is too small */
785     GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
786         ("Invalid data found parsing LPCM packet"),
787         ("LPCM packet was too small. Dropping"));
788     *offset = gst_adapter_available (adapter);
789     return GST_FLOW_EOS;
790   }
791 invalid_data:
792   {
793     GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
794         ("Invalid data found parsing LPCM packet"),
795         ("LPCM packet contains invalid sub_stream_id."));
796     return GST_FLOW_ERROR;
797   }
798 negotiation_failed:
799   {
800     GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),
801         ("Failed to configure output format"));
802     return GST_FLOW_NOT_NEGOTIATED;
803   }
804 }
805 
806 static GstFlowReturn
gst_dvdlpcmdec_parse(GstAudioDecoder * bdec,GstAdapter * adapter,gint * offset,gint * len)807 gst_dvdlpcmdec_parse (GstAudioDecoder * bdec, GstAdapter * adapter,
808     gint * offset, gint * len)
809 {
810   GstDvdLpcmDec *dvdlpcmdec = GST_DVDLPCMDEC (bdec);
811 
812   switch (dvdlpcmdec->mode) {
813     case GST_LPCM_UNKNOWN:
814       return GST_FLOW_NOT_NEGOTIATED;
815 
816     case GST_LPCM_RAW:
817       *offset = 0;
818       *len = gst_adapter_available (adapter);
819       return GST_FLOW_OK;
820 
821     case GST_LPCM_DVD:
822       return gst_dvdlpcmdec_parse_dvd (dvdlpcmdec, adapter, offset, len);
823 
824     case GST_LPCM_1394:
825       return gst_dvdlpcmdec_parse_1394 (dvdlpcmdec, adapter, offset, len);
826 
827     case GST_LPCM_BLURAY:
828       return gst_dvdlpcmdec_parse_bluray (dvdlpcmdec, adapter, offset, len);
829   }
830   return GST_FLOW_ERROR;
831 }
832 
833 static GstFlowReturn
gst_dvdlpcmdec_handle_frame(GstAudioDecoder * bdec,GstBuffer * buf)834 gst_dvdlpcmdec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buf)
835 {
836   GstDvdLpcmDec *dvdlpcmdec = GST_DVDLPCMDEC (bdec);
837   gsize size;
838   GstFlowReturn ret;
839   guint samples = 0;
840   gint rate, channels;
841 
842   /* no fancy draining */
843   if (G_UNLIKELY (!buf))
844     return GST_FLOW_OK;
845 
846   size = gst_buffer_get_size (buf);
847 
848   GST_LOG_OBJECT (dvdlpcmdec,
849       "got buffer %p of size %" G_GSIZE_FORMAT " with ts %" GST_TIME_FORMAT,
850       buf, size, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
851 
852   rate = GST_AUDIO_INFO_RATE (&dvdlpcmdec->info);
853   channels = GST_AUDIO_INFO_CHANNELS (&dvdlpcmdec->info);
854 
855   if (rate == 0)
856     goto not_negotiated;
857 
858   /* We don't currently do anything at all regarding emphasis, mute or
859    * dynamic_range - I'm not sure what they're for */
860   switch (dvdlpcmdec->width) {
861     case 16:
862     {
863       /* We can just pass 16-bits straight through intact, once we set
864        * appropriate things on the buffer */
865       samples = size / channels / 2;
866       if (samples < 1)
867         goto drop;
868 
869       gst_buffer_ref (buf);
870       break;
871     }
872     case 20:
873     {
874       /* Allocate a new buffer and copy 20-bit width to 24-bit */
875       gint64 samples = size * 8 / 20;
876       gint64 count = size / 10;
877       gint64 i;
878       GstMapInfo srcmap, destmap;
879       guint8 *src;
880       guint8 *dest;
881       GstBuffer *outbuf;
882 
883       if (samples < 1)
884         goto drop;
885 
886       outbuf = gst_buffer_new_allocate (NULL, samples * 3, NULL);
887       gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
888 
889       /* adjust samples so we can calc the new timestamp */
890       samples = samples / channels;
891 
892       gst_buffer_map (buf, &srcmap, GST_MAP_READ);
893       gst_buffer_map (outbuf, &destmap, GST_MAP_WRITE);
894       src = srcmap.data;
895       dest = destmap.data;
896 
897       /* Copy 20-bit LPCM format to 24-bit buffers, with 0x00 in the lowest
898        * nibble. Note that the first 2 bytes are already correct */
899       for (i = 0; i < count; i++) {
900         dest[0] = src[0];
901         dest[1] = src[1];
902         dest[2] = src[8] & 0xf0;
903         dest[3] = src[2];
904         dest[4] = src[3];
905         dest[5] = (src[8] & 0x0f) << 4;
906         dest[6] = src[4];
907         dest[7] = src[5];
908         dest[8] = src[9] & 0x0f;
909         dest[9] = src[6];
910         dest[10] = src[7];
911         dest[11] = (src[9] & 0x0f) << 4;
912 
913         src += 10;
914         dest += 12;
915       }
916       gst_buffer_unmap (outbuf, &destmap);
917       gst_buffer_unmap (buf, &srcmap);
918       buf = outbuf;
919       break;
920     }
921     case 24:
922     {
923       /* Rearrange 24-bit LPCM format in-place. Note that the first 2
924        * and last byte are already correct */
925       guint count = size / 12;
926       gint i;
927       GstMapInfo srcmap, destmap;
928       guint8 *src, *dest;
929       GstBuffer *outbuf;
930 
931       samples = size / channels / 3;
932 
933       if (samples < 1)
934         goto drop;
935 
936       outbuf = gst_buffer_new_allocate (NULL, size, NULL);
937       gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
938 
939       gst_buffer_map (buf, &srcmap, GST_MAP_READ);
940       gst_buffer_map (outbuf, &destmap, GST_MAP_READWRITE);
941       src = srcmap.data;
942       dest = destmap.data;
943 
944       for (i = 0; i < count; i++) {
945         dest[0] = src[0];
946         dest[1] = src[1];
947         dest[11] = src[11];
948         dest[10] = src[7];
949         dest[7] = src[5];
950         dest[5] = src[9];
951         dest[9] = src[6];
952         dest[6] = src[4];
953         dest[4] = src[3];
954         dest[3] = src[2];
955         dest[2] = src[8];
956         dest[8] = src[10];
957 
958         src += 12;
959         dest += 12;
960       }
961       gst_buffer_unmap (outbuf, &destmap);
962       gst_buffer_unmap (buf, &srcmap);
963       buf = outbuf;
964       break;
965     }
966     default:
967       goto invalid_width;
968   }
969 
970   if (dvdlpcmdec->lpcm_layout) {
971     buf = gst_buffer_make_writable (buf);
972     gst_audio_buffer_reorder_channels (buf, dvdlpcmdec->info.finfo->format,
973         dvdlpcmdec->info.channels, dvdlpcmdec->lpcm_layout,
974         dvdlpcmdec->info.position);
975   }
976 
977   ret = gst_audio_decoder_finish_frame (bdec, buf, 1);
978 
979 done:
980   return ret;
981 
982   /* ERRORS */
983 drop:
984   {
985     GST_DEBUG_OBJECT (dvdlpcmdec,
986         "Buffer of size %" G_GSIZE_FORMAT " is too small. Dropping", size);
987     ret = GST_FLOW_OK;
988     goto done;
989   }
990 not_negotiated:
991   {
992     GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),
993         ("Buffer pushed before negotiation"));
994     ret = GST_FLOW_NOT_NEGOTIATED;
995     goto done;
996   }
997 invalid_width:
998   {
999     GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, WRONG_TYPE, (NULL),
1000         ("Invalid sample width configured"));
1001     ret = GST_FLOW_NOT_NEGOTIATED;
1002     goto done;
1003   }
1004 }
1005 
1006 static gboolean
plugin_init(GstPlugin * plugin)1007 plugin_init (GstPlugin * plugin)
1008 {
1009 
1010   if (!gst_element_register (plugin, "dvdlpcmdec", GST_RANK_PRIMARY,
1011           GST_TYPE_DVDLPCMDEC)) {
1012     return FALSE;
1013   }
1014 
1015   return TRUE;
1016 }
1017 
1018 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1019     GST_VERSION_MINOR,
1020     dvdlpcmdec,
1021     "Decode DVD LPCM frames into standard PCM",
1022     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
1023