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