2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2005> Jan Schmidt <jan@noraisin.net>
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.
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.
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.
20 /* Element-Checklist-Version: TODO */
28 #include "gstdvdlpcmdec.h"
29 #include <gst/audio/audio.h>
31 GST_DEBUG_CATEGORY_STATIC (dvdlpcm_debug);
32 #define GST_CAT_DEFAULT dvdlpcm_debug
34 static GstStaticPadTemplate gst_dvdlpcmdec_sink_template =
35 GST_STATIC_PAD_TEMPLATE ("sink",
38 GST_STATIC_CAPS ("audio/x-private1-lpcm; "
39 "audio/x-private2-lpcm; "
40 "audio/x-private-ts-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 } ")
50 static GstStaticPadTemplate gst_dvdlpcmdec_src_template =
51 GST_STATIC_PAD_TEMPLATE ("src",
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 ]")
61 #define gst_dvdlpcmdec_parent_class parent_class
62 G_DEFINE_TYPE (GstDvdLpcmDec, gst_dvdlpcmdec, GST_TYPE_AUDIO_DECODER);
63 GST_ELEMENT_REGISTER_DEFINE (dvdlpcmdec, "dvdlpcmdec", GST_RANK_PRIMARY,
66 static gboolean gst_dvdlpcmdec_set_format (GstAudioDecoder * bdec,
68 static GstFlowReturn gst_dvdlpcmdec_parse (GstAudioDecoder * bdec,
69 GstAdapter * adapter, gint * offset, gint * len);
70 static GstFlowReturn gst_dvdlpcmdec_handle_frame (GstAudioDecoder * bdec,
72 static GstFlowReturn gst_dvdlpcmdec_chain (GstPad * pad, GstObject * parent,
77 gst_dvdlpcmdec_class_init (GstDvdLpcmDecClass * klass)
79 GstElementClass *element_class;
80 GstAudioDecoderClass *gstbase_class;
82 element_class = (GstElementClass *) klass;
83 gstbase_class = (GstAudioDecoderClass *) klass;
85 gstbase_class->set_format = GST_DEBUG_FUNCPTR (gst_dvdlpcmdec_set_format);
86 gstbase_class->parse = GST_DEBUG_FUNCPTR (gst_dvdlpcmdec_parse);
87 gstbase_class->handle_frame = GST_DEBUG_FUNCPTR (gst_dvdlpcmdec_handle_frame);
89 gst_element_class_add_static_pad_template (element_class,
90 &gst_dvdlpcmdec_sink_template);
91 gst_element_class_add_static_pad_template (element_class,
92 &gst_dvdlpcmdec_src_template);
93 gst_element_class_set_static_metadata (element_class,
94 "DVD LPCM Audio decoder", "Codec/Decoder/Audio",
95 "Decode DVD LPCM frames into standard PCM audio",
96 "Jan Schmidt <jan@noraisin.net>, Michael Smith <msmith@fluendo.com>");
98 GST_DEBUG_CATEGORY_INIT (dvdlpcm_debug, "dvdlpcmdec", 0, "DVD LPCM Decoder");
102 gst_dvdlpcm_reset (GstDvdLpcmDec * dvdlpcmdec)
104 gst_audio_info_init (&dvdlpcmdec->info);
105 dvdlpcmdec->dynamic_range = 0;
106 dvdlpcmdec->emphasis = FALSE;
107 dvdlpcmdec->mute = FALSE;
109 dvdlpcmdec->header = 0;
111 dvdlpcmdec->mode = GST_LPCM_UNKNOWN;
115 gst_dvdlpcmdec_init (GstDvdLpcmDec * dvdlpcmdec)
117 gst_dvdlpcm_reset (dvdlpcmdec);
119 gst_audio_decoder_set_use_default_pad_acceptcaps (GST_AUDIO_DECODER_CAST
121 GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_DECODER_SINK_PAD (dvdlpcmdec));
123 /* retrieve and intercept base class chain.
124 * Quite HACKish, but that's dvd specs/caps for you,
125 * since one buffer needs to be split into 2 frames */
126 dvdlpcmdec->base_chain =
127 GST_PAD_CHAINFUNC (GST_AUDIO_DECODER_SINK_PAD (dvdlpcmdec));
128 gst_pad_set_chain_function (GST_AUDIO_DECODER_SINK_PAD (dvdlpcmdec),
129 GST_DEBUG_FUNCPTR (gst_dvdlpcmdec_chain));
132 static const GstAudioChannelPosition channel_positions[][8] = {
133 {GST_AUDIO_CHANNEL_POSITION_MONO},
134 {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
135 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
136 {GST_AUDIO_CHANNEL_POSITION_INVALID},
137 {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
138 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
139 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
140 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
141 {GST_AUDIO_CHANNEL_POSITION_INVALID},
142 {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
143 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
144 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
145 GST_AUDIO_CHANNEL_POSITION_LFE1, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
146 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
147 {GST_AUDIO_CHANNEL_POSITION_INVALID},
148 {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
149 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
150 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
151 GST_AUDIO_CHANNEL_POSITION_LFE1, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
152 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
153 GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
154 GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT},
155 {GST_AUDIO_CHANNEL_POSITION_INVALID}
158 static const GstAudioChannelPosition bluray_channel_positions[][8] = {
160 {GST_AUDIO_CHANNEL_POSITION_INVALID},
162 {GST_AUDIO_CHANNEL_POSITION_MONO},
164 {GST_AUDIO_CHANNEL_POSITION_INVALID},
166 {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
167 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
169 {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
170 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
171 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER},
173 {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
174 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
175 GST_AUDIO_CHANNEL_POSITION_REAR_CENTER},
177 {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
178 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
179 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
180 GST_AUDIO_CHANNEL_POSITION_REAR_CENTER},
182 {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
183 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
184 GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
185 GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT},
187 {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
188 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
189 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
190 GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
191 GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT},
193 {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
194 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
195 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
196 GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
197 GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
198 GST_AUDIO_CHANNEL_POSITION_LFE1},
200 {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
201 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
202 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
203 GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
204 GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
205 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
206 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
208 {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
209 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
210 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
211 GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
212 GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
213 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
214 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
215 GST_AUDIO_CHANNEL_POSITION_LFE1},
217 {GST_AUDIO_CHANNEL_POSITION_INVALID},
219 {GST_AUDIO_CHANNEL_POSITION_INVALID},
221 {GST_AUDIO_CHANNEL_POSITION_INVALID},
223 {GST_AUDIO_CHANNEL_POSITION_INVALID}
227 gst_dvdlpcmdec_send_tags (GstDvdLpcmDec * dvdlpcmdec)
233 bpf = GST_AUDIO_INFO_BPF (&dvdlpcmdec->info);
234 rate = GST_AUDIO_INFO_RATE (&dvdlpcmdec->info);
236 bitrate = bpf * 8 * rate;
238 taglist = gst_tag_list_new (GST_TAG_AUDIO_CODEC, "LPCM Audio",
239 GST_TAG_BITRATE, bitrate, NULL);
241 gst_audio_decoder_merge_tags (GST_AUDIO_DECODER (dvdlpcmdec), taglist,
242 GST_TAG_MERGE_REPLACE);
243 gst_tag_list_unref (taglist);
247 gst_dvdlpcmdec_set_output_format (GstDvdLpcmDec * dvdlpcmdec)
251 res = gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (dvdlpcmdec),
254 GST_DEBUG_OBJECT (dvdlpcmdec, "Successfully set output format");
256 gst_dvdlpcmdec_send_tags (dvdlpcmdec);
258 GST_DEBUG_OBJECT (dvdlpcmdec, "Failed to set output format");
265 gst_dvdlpcmdec_update_audio_formats (GstDvdLpcmDec * dec, gint channels,
266 gint rate, GstAudioFormat format, guint8 channel_indicator,
267 const GstAudioChannelPosition positions[][8])
269 GST_DEBUG_OBJECT (dec, "got channels = %d, rate = %d, format = %d", channels,
272 /* Reorder the channel positions and set the default into for the audio */
274 && positions[channel_indicator][0] !=
275 GST_AUDIO_CHANNEL_POSITION_INVALID) {
276 const GstAudioChannelPosition *position;
277 GstAudioChannelPosition sorted_position[8];
280 position = positions[channel_indicator];
281 for (c = 0; c < channels; ++c)
282 sorted_position[c] = position[c];
283 gst_audio_channel_positions_to_valid_order (sorted_position, channels);
284 gst_audio_info_set_format (&dec->info, format, rate, channels,
286 if (memcmp (position, sorted_position,
287 channels * sizeof (position[0])) != 0)
288 dec->lpcm_layout = position;
290 dec->lpcm_layout = NULL;
292 gst_audio_info_set_format (&dec->info, format, rate, channels, NULL);
297 gst_dvdlpcmdec_set_format (GstAudioDecoder * bdec, GstCaps * caps)
299 GstDvdLpcmDec *dvdlpcmdec = GST_DVDLPCMDEC (bdec);
300 GstStructure *structure;
302 GstAudioFormat format;
303 gint rate, channels, width;
305 gst_dvdlpcm_reset (dvdlpcmdec);
307 structure = gst_caps_get_structure (caps, 0);
309 /* If we have the DVD structured LPCM (including header) then we wait
310 * for incoming data before creating the output pad caps */
311 if (gst_structure_has_name (structure, "audio/x-private1-lpcm")) {
312 dvdlpcmdec->mode = GST_LPCM_DVD;
315 if (gst_structure_has_name (structure, "audio/x-private2-lpcm")) {
316 dvdlpcmdec->mode = GST_LPCM_1394;
319 if (gst_structure_has_name (structure, "audio/x-private-ts-lpcm")) {
320 dvdlpcmdec->mode = GST_LPCM_BLURAY;
324 dvdlpcmdec->mode = GST_LPCM_RAW;
326 res &= gst_structure_get_int (structure, "rate", &rate);
327 res &= gst_structure_get_int (structure, "channels", &channels);
328 res &= gst_structure_get_int (structure, "width", &width);
329 res &= gst_structure_get_int (structure, "dynamic_range",
330 &dvdlpcmdec->dynamic_range);
331 res &= gst_structure_get_boolean (structure, "emphasis",
332 &dvdlpcmdec->emphasis);
333 res &= gst_structure_get_boolean (structure, "mute", &dvdlpcmdec->mute);
336 goto caps_parse_error;
341 format = GST_AUDIO_FORMAT_S24BE;
344 format = GST_AUDIO_FORMAT_S16BE;
347 format = GST_AUDIO_FORMAT_UNKNOWN;
351 gst_dvdlpcmdec_update_audio_formats (dvdlpcmdec, channels, rate, format,
352 channels - 1, channel_positions);
354 dvdlpcmdec->width = width;
356 res = gst_dvdlpcmdec_set_output_format (dvdlpcmdec);
364 GST_DEBUG_OBJECT (dvdlpcmdec, "Couldn't get parameters; missing caps?");
370 parse_header (GstDvdLpcmDec * dec, guint32 header)
372 GstAudioFormat format;
373 gint rate, channels, width;
375 /* We don't actually use 'dynamic range', 'mute', or 'emphasis' currently,
376 * but parse them out */
377 dec->dynamic_range = header & 0xff;
379 dec->mute = (header & 0x400000) != 0;
380 dec->emphasis = (header & 0x800000) != 0;
382 /* These two bits tell us the bit depth */
383 switch (header & 0xC000) {
385 /* 24 bits in 3 bytes */
386 format = GST_AUDIO_FORMAT_S24BE;
390 /* 20 bits in 3 bytes */
391 format = GST_AUDIO_FORMAT_S24BE;
395 format = GST_AUDIO_FORMAT_S16BE;
402 /* Only four sample rates supported */
403 switch (header & 0x3000) {
421 /* And, of course, the number of channels (up to 8) */
422 channels = ((header >> 8) & 0x7) + 1;
424 gst_dvdlpcmdec_update_audio_formats (dec, channels, rate, format,
425 channels - 1, channel_positions);
429 gst_dvdlpcmdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
431 GstDvdLpcmDec *dvdlpcmdec = GST_DVDLPCMDEC (parent);
436 GstFlowReturn ret = GST_FLOW_OK;
439 if (dvdlpcmdec->mode != GST_LPCM_DVD)
440 return dvdlpcmdec->base_chain (pad, parent, buf);
442 size = gst_buffer_get_size (buf);
446 gst_buffer_extract (buf, 0, data, 2);
447 first_access = (data[0] << 8) | data[1];
448 if (first_access > size)
451 /* After first_access, we have an additional 3 bytes of header data; this
452 * is included within the value of first_access.
453 * So a first_access value of between 1 and 3 is just broken, we treat that
454 * the same as zero. first_access == 4 means we only need to create a single
455 * sub-buffer, greater than that we need to create two. */
457 /* skip access unit bytes */
460 if (first_access > 4) {
461 /* length of first buffer */
462 len = first_access - 1;
464 GST_LOG_OBJECT (dvdlpcmdec, "Creating first sub-buffer off %d, len %d",
467 /* see if we need a subbuffer without timestamp */
468 if (off + len > size)
469 goto bad_first_access;
471 subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, off, len);
472 GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE;
473 ret = dvdlpcmdec->base_chain (pad, parent, subbuf);
474 if (ret != GST_FLOW_OK)
477 /* then the buffer with new timestamp */
481 GST_LOG_OBJECT (dvdlpcmdec, "Creating next sub-buffer off %d, len %d", off,
485 GstMemory *header, *tmp;
486 subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, off, len);
487 tmp = gst_buffer_peek_memory (buf, 0);
488 header = gst_memory_copy (tmp, 2, 3);
489 gst_buffer_prepend_memory (subbuf, header);
490 GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
492 ret = dvdlpcmdec->base_chain (pad, parent, subbuf);
495 GST_LOG_OBJECT (dvdlpcmdec,
496 "Creating single sub-buffer off %d, len %" G_GSIZE_FORMAT, off,
498 subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, off, size - off);
499 GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
500 ret = dvdlpcmdec->base_chain (pad, parent, subbuf);
504 gst_buffer_unref (buf);
511 /* Buffer is too small */
512 GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
513 ("Invalid data found parsing LPCM packet"),
514 ("LPCM packet was too small. Dropping"));
520 GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
521 ("Invalid data found parsing LPCM packet"),
522 ("LPCM packet contained invalid first access. Dropping"));
528 GST_WARNING_OBJECT (pad, "Bad first_access parameter in buffer");
529 GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, DECODE,
531 ("first_access parameter out of range: bad buffer from demuxer"));
532 ret = GST_FLOW_ERROR;
538 gst_dvdlpcmdec_parse_dvd (GstDvdLpcmDec * dvdlpcmdec, GstAdapter * adapter,
539 gint * offset, gint * len)
544 data = (const guint8 *) gst_adapter_map (adapter, 3);
548 /* Don't keep the 'frame number' low 5 bits of the first byte */
549 header = ((data[0] & 0xC0) << 16) | (data[1] << 8) | data[2];
551 gst_adapter_unmap (adapter);
553 /* see if we have a new header */
554 if (header != dvdlpcmdec->header) {
555 parse_header (dvdlpcmdec, header);
557 if (!gst_dvdlpcmdec_set_output_format (dvdlpcmdec))
558 goto negotiation_failed;
560 dvdlpcmdec->header = header;
564 *len = gst_adapter_available (adapter) - 3;
571 /* Buffer is too small */
572 GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
573 ("Invalid data found parsing LPCM packet"),
574 ("LPCM packet was too small. Dropping"));
575 *offset = gst_adapter_available (adapter);
580 GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),
581 ("Failed to configure output format"));
582 return GST_FLOW_NOT_NEGOTIATED;
587 gst_dvdlpcmdec_parse_bluray (GstDvdLpcmDec * dvdlpcmdec, GstAdapter * adapter,
588 gint * offset, gint * len)
592 guint8 channel_indicator;
594 data = (const guint8 *) gst_adapter_map (adapter, 4);
598 header = GST_READ_UINT32_BE (data);
600 gst_adapter_unmap (adapter);
602 /* see if we have a new header */
603 if (header != dvdlpcmdec->header) {
604 GstAudioFormat format;
607 switch ((header >> 6) & 0x3) {
609 format = GST_AUDIO_FORMAT_S16BE;
610 dvdlpcmdec->width = 16;
613 format = GST_AUDIO_FORMAT_S24BE;
614 dvdlpcmdec->width = 20;
617 format = GST_AUDIO_FORMAT_S24BE;
618 dvdlpcmdec->width = 24;
621 format = GST_AUDIO_FORMAT_UNKNOWN;
622 dvdlpcmdec->width = 0;
623 GST_WARNING ("Invalid sample depth!");
627 switch ((header >> 8) & 0xf) {
639 GST_WARNING ("Invalid audio sampling frequency!");
642 channel_indicator = (header >> 12) & 0xf;
643 switch (channel_indicator) {
672 GST_WARNING ("Invalid number of audio channels!");
673 goto negotiation_failed;
675 GST_DEBUG_OBJECT (dvdlpcmdec, "got channels %d rate %d format %s",
676 channels, rate, gst_audio_format_to_string (format));
678 gst_dvdlpcmdec_update_audio_formats (dvdlpcmdec, channels, rate, format,
679 channel_indicator, bluray_channel_positions);
681 if (!gst_dvdlpcmdec_set_output_format (dvdlpcmdec))
682 goto negotiation_failed;
684 dvdlpcmdec->header = header;
688 *len = gst_adapter_available (adapter) - 4;
695 /* Buffer is too small */
696 GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
697 ("Invalid data found parsing LPCM packet"),
698 ("LPCM packet was too small. Dropping"));
699 *offset = gst_adapter_available (adapter);
704 GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),
705 ("Failed to configure output format"));
706 return GST_FLOW_NOT_NEGOTIATED;
712 gst_dvdlpcmdec_parse_1394 (GstDvdLpcmDec * dvdlpcmdec, GstAdapter * adapter,
713 gint * offset, gint * len)
718 data = (const guint8 *) gst_adapter_map (adapter, 4);
722 header = GST_READ_UINT32_BE (data);
724 gst_adapter_unmap (adapter);
726 /* see if we have a new header */
727 if (header != dvdlpcmdec->header) {
728 GstAudioFormat format;
731 if (header >> 24 != 0xa0)
734 switch ((header >> 6) & 0x3) {
736 format = GST_AUDIO_FORMAT_S16BE;
737 dvdlpcmdec->width = 16;
740 format = GST_AUDIO_FORMAT_UNKNOWN;
741 dvdlpcmdec->width = 0;
742 GST_WARNING ("Invalid quantization word length!");
746 switch ((header >> 3) & 0x7) {
755 GST_WARNING ("Invalid audio sampling frequency!");
758 switch (header & 0x7) {
759 case 0x0: /* 2 channels dual-mono */
760 case 0x1: /* 2 channels stereo */
765 GST_WARNING ("Invalid number of audio channels!");
766 goto negotiation_failed;
769 gst_dvdlpcmdec_update_audio_formats (dvdlpcmdec, channels, rate, format,
770 channels - 1, channel_positions);
772 if (!gst_dvdlpcmdec_set_output_format (dvdlpcmdec))
773 goto negotiation_failed;
775 dvdlpcmdec->header = header;
779 *len = gst_adapter_available (adapter) - 4;
786 /* Buffer is too small */
787 GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
788 ("Invalid data found parsing LPCM packet"),
789 ("LPCM packet was too small. Dropping"));
790 *offset = gst_adapter_available (adapter);
795 GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
796 ("Invalid data found parsing LPCM packet"),
797 ("LPCM packet contains invalid sub_stream_id."));
798 return GST_FLOW_ERROR;
802 GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),
803 ("Failed to configure output format"));
804 return GST_FLOW_NOT_NEGOTIATED;
809 gst_dvdlpcmdec_parse (GstAudioDecoder * bdec, GstAdapter * adapter,
810 gint * offset, gint * len)
812 GstDvdLpcmDec *dvdlpcmdec = GST_DVDLPCMDEC (bdec);
814 switch (dvdlpcmdec->mode) {
815 case GST_LPCM_UNKNOWN:
816 return GST_FLOW_NOT_NEGOTIATED;
820 *len = gst_adapter_available (adapter);
824 return gst_dvdlpcmdec_parse_dvd (dvdlpcmdec, adapter, offset, len);
827 return gst_dvdlpcmdec_parse_1394 (dvdlpcmdec, adapter, offset, len);
829 case GST_LPCM_BLURAY:
830 return gst_dvdlpcmdec_parse_bluray (dvdlpcmdec, adapter, offset, len);
832 return GST_FLOW_ERROR;
836 gst_dvdlpcmdec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buf)
838 GstDvdLpcmDec *dvdlpcmdec = GST_DVDLPCMDEC (bdec);
844 /* no fancy draining */
845 if (G_UNLIKELY (!buf))
848 size = gst_buffer_get_size (buf);
850 GST_LOG_OBJECT (dvdlpcmdec,
851 "got buffer %p of size %" G_GSIZE_FORMAT " with ts %" GST_TIME_FORMAT,
852 buf, size, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
854 rate = GST_AUDIO_INFO_RATE (&dvdlpcmdec->info);
855 channels = GST_AUDIO_INFO_CHANNELS (&dvdlpcmdec->info);
860 /* We don't currently do anything at all regarding emphasis, mute or
861 * dynamic_range - I'm not sure what they're for */
862 switch (dvdlpcmdec->width) {
865 /* We can just pass 16-bits straight through intact, once we set
866 * appropriate things on the buffer */
867 samples = size / channels / 2;
871 gst_buffer_ref (buf);
876 /* Allocate a new buffer and copy 20-bit width to 24-bit */
877 gint64 samples = size * 8 / 20;
878 gint64 count = size / 10;
880 GstMapInfo srcmap, destmap;
888 outbuf = gst_buffer_new_allocate (NULL, samples * 3, NULL);
889 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
891 /* adjust samples so we can calc the new timestamp */
892 samples = samples / channels;
894 gst_buffer_map (buf, &srcmap, GST_MAP_READ);
895 gst_buffer_map (outbuf, &destmap, GST_MAP_WRITE);
899 /* Copy 20-bit LPCM format to 24-bit buffers, with 0x00 in the lowest
900 * nibble. Note that the first 2 bytes are already correct */
901 for (i = 0; i < count; i++) {
904 dest[2] = src[8] & 0xf0;
907 dest[5] = (src[8] & 0x0f) << 4;
910 dest[8] = src[9] & 0x0f;
913 dest[11] = (src[9] & 0x0f) << 4;
918 gst_buffer_unmap (outbuf, &destmap);
919 gst_buffer_unmap (buf, &srcmap);
925 /* Rearrange 24-bit LPCM format in-place. Note that the first 2
926 * and last byte are already correct */
927 guint count = size / 12;
929 GstMapInfo srcmap, destmap;
933 samples = size / channels / 3;
938 outbuf = gst_buffer_new_allocate (NULL, size, NULL);
939 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
941 gst_buffer_map (buf, &srcmap, GST_MAP_READ);
942 gst_buffer_map (outbuf, &destmap, GST_MAP_READWRITE);
946 for (i = 0; i < count; i++) {
963 gst_buffer_unmap (outbuf, &destmap);
964 gst_buffer_unmap (buf, &srcmap);
972 if (dvdlpcmdec->lpcm_layout) {
973 buf = gst_buffer_make_writable (buf);
974 gst_audio_buffer_reorder_channels (buf, dvdlpcmdec->info.finfo->format,
975 dvdlpcmdec->info.channels, dvdlpcmdec->lpcm_layout,
976 dvdlpcmdec->info.position);
979 ret = gst_audio_decoder_finish_frame (bdec, buf, 1);
987 GST_DEBUG_OBJECT (dvdlpcmdec,
988 "Buffer of size %" G_GSIZE_FORMAT " is too small. Dropping", size);
994 GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),
995 ("Buffer pushed before negotiation"));
996 ret = GST_FLOW_NOT_NEGOTIATED;
1001 GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, WRONG_TYPE, (NULL),
1002 ("Invalid sample width configured"));
1003 ret = GST_FLOW_NOT_NEGOTIATED;
1009 plugin_init (GstPlugin * plugin)
1011 return GST_ELEMENT_REGISTER (dvdlpcmdec, plugin);
1014 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1017 "Decode DVD LPCM frames into standard PCM",
1018 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);