]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugins-ugly0-10.git/blob - gst/dvdlpcmdec/gstdvdlpcmdec.c
Fix leaks some more.
[glsdk/gst-plugins-ugly0-10.git] / gst / dvdlpcmdec / gstdvdlpcmdec.c
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., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 /* Element-Checklist-Version: TODO */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <stdlib.h>
26 #include <string.h>
28 #include "gstdvdlpcmdec.h"
30 GST_DEBUG_CATEGORY_STATIC (dvdlpcm_debug);
31 #define GST_CAT_DEFAULT dvdlpcm_debug
33 /* elementfactory information */
34 static const GstElementDetails gst_dvdlpcmdec_details =
35 GST_ELEMENT_DETAILS ("DVD LPCM Audio decoder",
36     "Codec/Demuxer/Audio",
37     "Decode DVD LPCM frames into standard PCM audio",
38     "Jan Schmidt <jan@noraisin.net>\n" "Michael Smith <msmith@fluendo.com>");
40 static GstStaticPadTemplate gst_dvdlpcmdec_sink_template =
41     GST_STATIC_PAD_TEMPLATE ("sink",
42     GST_PAD_SINK,
43     GST_PAD_ALWAYS,
44     GST_STATIC_CAPS ("audio/x-private1-lpcm; "
45         "audio/x-lpcm, "
46         "width = (int) { 16, 20, 24 }, "
47         "rate = (int) { 48000, 96000 }, "
48         "channels = (int) [ 1, 8 ], "
49         "dynamic_range = (int) [ 0, 255 ], "
50         "emphasis = (boolean) { TRUE, FALSE }, "
51         "mute = (boolean) { TRUE, FALSE } ")
52     );
54 static GstStaticPadTemplate gst_dvdlpcmdec_src_template =
55 GST_STATIC_PAD_TEMPLATE ("src",
56     GST_PAD_SRC,
57     GST_PAD_ALWAYS,
58     GST_STATIC_CAPS ("audio/x-raw-int, "
59         "width = (int) { 16, 24 }, "
60         "rate = (int) { 48000, 96000 }, "
61         "channels = (int) [ 1, 8 ], "
62         "endianness = (int) { BIG_ENDIAN }, "
63         "depth = (int) { 16, 24 }, " "signed = (boolean) { true }")
64     );
66 /* DvdLpcmDec signals and args */
67 enum
68 {
69   /* FILL ME */
70   LAST_SIGNAL
71 };
73 enum
74 {
75   ARG_0
76       /* FILL ME */
77 };
79 static void gst_dvdlpcmdec_base_init (gpointer g_class);
80 static void gst_dvdlpcmdec_class_init (GstDvdLpcmDecClass * klass);
81 static void gst_dvdlpcmdec_init (GstDvdLpcmDec * dvdlpcmdec);
83 static GstFlowReturn gst_dvdlpcmdec_chain_raw (GstPad * pad,
84     GstBuffer * buffer);
85 static GstFlowReturn gst_dvdlpcmdec_chain_dvd (GstPad * pad,
86     GstBuffer * buffer);
87 static gboolean gst_dvdlpcmdec_setcaps (GstPad * pad, GstCaps * caps);
88 static gboolean dvdlpcmdec_sink_event (GstPad * pad, GstEvent * event);
90 static GstStateChangeReturn gst_dvdlpcmdec_change_state (GstElement * element,
91     GstStateChange transition);
93 static GstElementClass *parent_class = NULL;
95 GType
96 gst_dvdlpcmdec_get_type (void)
97 {
98   static GType dvdlpcmdec_type = 0;
100   if (!dvdlpcmdec_type) {
101     static const GTypeInfo dvdlpcmdec_info = {
102       sizeof (GstDvdLpcmDecClass),
103       gst_dvdlpcmdec_base_init,
104       NULL,
105       (GClassInitFunc) gst_dvdlpcmdec_class_init,
106       NULL,
107       NULL,
108       sizeof (GstDvdLpcmDec),
109       0,
110       (GInstanceInitFunc) gst_dvdlpcmdec_init,
111     };
113     dvdlpcmdec_type =
114         g_type_register_static (GST_TYPE_ELEMENT, "GstDvdLpcmDec",
115         &dvdlpcmdec_info, 0);
116   }
117   return dvdlpcmdec_type;
120 static void
121 gst_dvdlpcmdec_base_init (gpointer g_class)
123   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
125   gst_element_class_add_pad_template (element_class,
126       gst_static_pad_template_get (&gst_dvdlpcmdec_sink_template));
127   gst_element_class_add_pad_template (element_class,
128       gst_static_pad_template_get (&gst_dvdlpcmdec_src_template));
129   gst_element_class_set_details (element_class, &gst_dvdlpcmdec_details);
132 static void
133 gst_dvdlpcmdec_class_init (GstDvdLpcmDecClass * klass)
135   GstElementClass *gstelement_class;
137   gstelement_class = (GstElementClass *) klass;
139   parent_class = g_type_class_peek_parent (klass);
141   gstelement_class->change_state = gst_dvdlpcmdec_change_state;
144 static void
145 gst_dvdlpcm_reset (GstDvdLpcmDec * dvdlpcmdec)
147   dvdlpcmdec->rate = 0;
148   dvdlpcmdec->channels = 0;
149   dvdlpcmdec->width = 0;
150   dvdlpcmdec->out_width = 0;
151   dvdlpcmdec->dynamic_range = 0;
152   dvdlpcmdec->emphasis = FALSE;
153   dvdlpcmdec->mute = FALSE;
154   dvdlpcmdec->timestamp = GST_CLOCK_TIME_NONE;
156   dvdlpcmdec->header = 0;
158   gst_segment_init (&dvdlpcmdec->segment, GST_FORMAT_UNDEFINED);
161 static void
162 gst_dvdlpcmdec_init (GstDvdLpcmDec * dvdlpcmdec)
164   dvdlpcmdec->sinkpad =
165       gst_pad_new_from_static_template (&gst_dvdlpcmdec_sink_template, "sink");
166   gst_pad_set_setcaps_function (dvdlpcmdec->sinkpad, gst_dvdlpcmdec_setcaps);
167   gst_pad_set_event_function (dvdlpcmdec->sinkpad, dvdlpcmdec_sink_event);
168   gst_element_add_pad (GST_ELEMENT (dvdlpcmdec), dvdlpcmdec->sinkpad);
170   dvdlpcmdec->srcpad =
171       gst_pad_new_from_static_template (&gst_dvdlpcmdec_src_template, "src");
172   gst_pad_use_fixed_caps (dvdlpcmdec->srcpad);
173   gst_element_add_pad (GST_ELEMENT (dvdlpcmdec), dvdlpcmdec->srcpad);
175   gst_dvdlpcm_reset (dvdlpcmdec);
178 static gboolean
179 gst_dvdlpcmdec_setcaps (GstPad * pad, GstCaps * caps)
181   GstStructure *structure;
182   gboolean res = TRUE;
183   GstDvdLpcmDec *dvdlpcmdec;
184   GstCaps *src_caps;
186   g_return_val_if_fail (caps != NULL, FALSE);
187   g_return_val_if_fail (pad != NULL, FALSE);
189   dvdlpcmdec = GST_DVDLPCMDEC (gst_pad_get_parent (pad));
191   structure = gst_caps_get_structure (caps, 0);
193   /* If we have the DVD structured LPCM (including header) */
194   if (gst_structure_has_name (structure, "audio/x-private1-lpcm")) {
195     gst_pad_set_chain_function (dvdlpcmdec->sinkpad, gst_dvdlpcmdec_chain_dvd);
196     goto done;
197   }
199   gst_pad_set_chain_function (dvdlpcmdec->sinkpad, gst_dvdlpcmdec_chain_raw);
201   res &= gst_structure_get_int (structure, "rate", &dvdlpcmdec->rate);
202   res &= gst_structure_get_int (structure, "channels", &dvdlpcmdec->channels);
203   res &= gst_structure_get_int (structure, "width", &dvdlpcmdec->width);
204   res &= gst_structure_get_int (structure, "dynamic_range",
205       &dvdlpcmdec->dynamic_range);
206   res &= gst_structure_get_boolean (structure, "emphasis",
207       &dvdlpcmdec->emphasis);
208   res &= gst_structure_get_boolean (structure, "mute", &dvdlpcmdec->mute);
210   if (!res)
211     goto caps_parse_error;
213   /* Output width is the input width rounded up to the nearest byte */
214   if (dvdlpcmdec->width == 20)
215     dvdlpcmdec->out_width = 24;
216   else
217     dvdlpcmdec->out_width = dvdlpcmdec->width;
219   /* Build caps to set on the src pad, which we know from the incoming caps */
220   src_caps = gst_caps_new_simple ("audio/x-raw-int",
221       "rate", G_TYPE_INT, dvdlpcmdec->rate,
222       "channels", G_TYPE_INT, dvdlpcmdec->channels,
223       "endianness", G_TYPE_INT, G_BIG_ENDIAN,
224       "depth", G_TYPE_INT, dvdlpcmdec->out_width,
225       "width", G_TYPE_INT, dvdlpcmdec->out_width,
226       "signed", G_TYPE_BOOLEAN, TRUE, NULL);
228   GST_DEBUG_OBJECT (dvdlpcmdec, "Set rate %d, channels %d, width %d (out %d)",
229       dvdlpcmdec->rate, dvdlpcmdec->channels, dvdlpcmdec->width,
230       dvdlpcmdec->out_width);
232   if (!gst_pad_set_caps (dvdlpcmdec->srcpad, src_caps)) {
233     GST_DEBUG_OBJECT (dvdlpcmdec, "Failed to set caps!");
234     res = FALSE;
235   } else {
236     GST_DEBUG_OBJECT (dvdlpcmdec, "Successfully set caps: %" GST_PTR_FORMAT,
237         caps);
238   }
240   gst_caps_unref (src_caps);
242 done:
243   gst_object_unref (dvdlpcmdec);
245   return res;
247   /* ERRORS */
248 caps_parse_error:
249   {
250     GST_DEBUG_OBJECT (dvdlpcmdec, "Couldn't get parameters; missing caps?");
251     res = FALSE;
252     goto done;
253   }
256 static void
257 update_timestamps (GstDvdLpcmDec * dvdlpcmdec, GstBuffer * buf, int samples)
259   gboolean take_buf_ts = FALSE;
261   GST_BUFFER_DURATION (buf) =
262       gst_util_uint64_scale (samples, GST_SECOND, dvdlpcmdec->rate);
264   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
265     if (GST_CLOCK_TIME_IS_VALID (dvdlpcmdec->timestamp)) {
266       GstClockTimeDiff one_sample = GST_SECOND / dvdlpcmdec->rate;
267       GstClockTimeDiff diff = GST_CLOCK_DIFF (GST_BUFFER_TIMESTAMP (buf),
268           dvdlpcmdec->timestamp);
270       if (diff > one_sample || diff < -one_sample)
271         take_buf_ts = TRUE;
272     } else {
273       take_buf_ts = TRUE;
274     }
275   } else if (!GST_CLOCK_TIME_IS_VALID (dvdlpcmdec->timestamp)) {
276     dvdlpcmdec->timestamp = 0;
277   }
279   if (take_buf_ts) {
280     /* Take buffer timestamp */
281     dvdlpcmdec->timestamp = GST_BUFFER_TIMESTAMP (buf);
282   } else {
283     GST_BUFFER_TIMESTAMP (buf) = dvdlpcmdec->timestamp;
284   }
286   dvdlpcmdec->timestamp += GST_BUFFER_DURATION (buf);
288   GST_LOG_OBJECT (dvdlpcmdec, "Updated timestamp to %" GST_TIME_FORMAT,
289       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
292 static void
293 parse_header (GstDvdLpcmDec * dec, guint32 header)
295   /* We don't actually use 'dynamic range', 'mute', or 'emphasis' currently, 
296    * but parse them out */
297   dec->dynamic_range = header & 0xff;
299   dec->mute = (header & 0x400000) != 0;
300   dec->emphasis = (header & 0x800000) != 0;
302   /* These two bits tell us the bit depth */
303   switch (header & 0xC000) {
304     case 0x8000:
305       dec->width = 24;
306       dec->out_width = 24;
307       break;
308     case 0x4000:
309       dec->width = 20;
310       dec->out_width = 24;
311       break;
312     default:
313       dec->width = 16;
314       dec->out_width = 16;
315       break;
316   }
318   /* Only four sample rates supported */
319   switch (header & 0x3000) {
320     case 0x0000:
321       dec->rate = 48000;
322       break;
323     case 0x1000:
324       dec->rate = 96000;
325       break;
326     case 0x2000:
327       dec->rate = 44100;
328       break;
329     case 0x3000:
330       dec->rate = 32000;
331       break;
332   }
334   /* And, of course, the number of channels (up to 8) */
335   dec->channels = ((header >> 8) & 0x7) + 1;
338 static GstFlowReturn
339 gst_dvdlpcmdec_chain_dvd (GstPad * pad, GstBuffer * buf)
341   GstDvdLpcmDec *dvdlpcmdec;
342   guint8 *data;
343   guint size;
344   guint first_access;
345   guint32 header;
346   GstBuffer *subbuf;
347   GstFlowReturn ret = GST_FLOW_OK;
348   gint off, len;
350   dvdlpcmdec = GST_DVDLPCMDEC (gst_pad_get_parent (pad));
352   size = GST_BUFFER_SIZE (buf);
353   data = GST_BUFFER_DATA (buf);
355   if (size < 5) {
356     /* Buffer is too small */
357     GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
358         ("Invalid data found parsing LPCM packet"),
359         ("LPCM packet was too small. Dropping"));
360     ret = GST_FLOW_OK;
361     goto done;
362   }
364   /* We have a 5 byte header, now.
365    * The first two bytes are a (big endian) 16 bit offset into our buffer.
366    * The buffer timestamp refers to this offset.
367    *
368    * The other three bytes are a (big endian) number in which the header is
369    * encoded.
370    */
371   first_access = (data[0] << 8) | data[1];
372   if (first_access > size) {
373     GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
374         ("Invalid data found parsing LPCM packet"),
375         ("LPCM packet contained invalid first access. Dropping"));
376     ret = GST_FLOW_OK;
377     goto done;
378   }
380   /* Don't keep the 'frame number' low 5 bits of the first byte */
381   header = ((data[2] & 0xC0) << 16) | (data[3] << 8) | data[4];
383   /* see if we have a new header */
384   if (header != dvdlpcmdec->header) {
385     GstCaps *src_caps;
387     parse_header (dvdlpcmdec, header);
389     /* Build caps to set on the src pad from what we've just parsed */
390     src_caps = gst_caps_new_simple ("audio/x-raw-int",
391         "rate", G_TYPE_INT, dvdlpcmdec->rate,
392         "channels", G_TYPE_INT, dvdlpcmdec->channels,
393         "endianness", G_TYPE_INT, G_BIG_ENDIAN,
394         "depth", G_TYPE_INT, dvdlpcmdec->out_width,
395         "width", G_TYPE_INT, dvdlpcmdec->out_width,
396         "signed", G_TYPE_BOOLEAN, TRUE, NULL);
398     GST_DEBUG_OBJECT (dvdlpcmdec, "Set rate %d, channels %d, width %d",
399         dvdlpcmdec->rate, dvdlpcmdec->channels, dvdlpcmdec->width);
401     if (!gst_pad_set_caps (dvdlpcmdec->srcpad, src_caps))
402       goto negotiation_failed;
404     gst_caps_unref (src_caps);
406     dvdlpcmdec->header = header;
407   }
409   GST_LOG_OBJECT (dvdlpcmdec, "first_access %d, buffer length %d", first_access,
410       size);
412   /* After first_access, we have an additional 3 bytes of data we've parsed and
413    * don't want to handle; this is included within the value of first_access.
414    * So a first_access value of between 1 and 3 is just broken, we treat that
415    * the same as zero. first_access == 4 means we only need to create a single
416    * sub-buffer, greater than that we need to create two. */
418   /* skip access unit bytes and info */
419   off = 5;
421   if (first_access > 4) {
422     guint samples = 0;
423     GstClockTime ts;
425     /* length of first buffer */
426     len = first_access - 4;
428     GST_LOG_OBJECT (dvdlpcmdec, "Creating first sub-buffer off %d, len %d",
429         off, len);
431     /* see if we need a subbuffer without timestamp */
432     if (off + len > size) {
433       GST_WARNING_OBJECT (pad, "Bad first_access parameter in buffer");
434       GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, DECODE,
435           (NULL),
436           ("first_access parameter out of range: bad buffer from demuxer"));
437       ret = GST_FLOW_ERROR;
438       goto done;
439     }
441     subbuf = gst_buffer_create_sub (buf, off, len);
443     /* If we don't have a stored timestamp from the last packet, 
444      * (it's straight after a new-segment, but we have one on the
445      * first access buffer, then calculate the timestamp to align
446      * this buffer to just before the first_access buffer */
447     if (!GST_CLOCK_TIME_IS_VALID (dvdlpcmdec->timestamp) &&
448         GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
449       switch (dvdlpcmdec->width) {
450         case 16:
451           samples = len / dvdlpcmdec->channels / 2;
452           break;
453         case 20:
454           samples = (len / dvdlpcmdec->channels) * 2 / 5;
455           break;
456         case 24:
457           samples = len / dvdlpcmdec->channels / 3;
458           break;
459       }
460     }
461     if (samples != 0) {
462       ts = gst_util_uint64_scale (samples, GST_SECOND, dvdlpcmdec->rate);
463       if (ts < GST_BUFFER_TIMESTAMP (buf))
464         GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf) - ts;
465       else
466         GST_BUFFER_TIMESTAMP (subbuf) = 0;
467     } else {
468       GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE;
469     }
471     ret = gst_dvdlpcmdec_chain_raw (pad, subbuf);
472     if (ret != GST_FLOW_OK)
473       goto done;
475     /* then the buffer with new timestamp */
476     off += len;
477     len = size - off;
479     GST_LOG_OBJECT (dvdlpcmdec, "Creating next sub-buffer off %d, len %d", off,
480         len);
482     if (len > 0) {
483       subbuf = gst_buffer_create_sub (buf, off, len);
484       GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
486       ret = gst_dvdlpcmdec_chain_raw (pad, subbuf);
487     }
488   } else {
489     GST_LOG_OBJECT (dvdlpcmdec, "Creating single sub-buffer off %d, len %d",
490         off, size - off);
491     subbuf = gst_buffer_create_sub (buf, off, size - off);
492     GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
493     ret = gst_dvdlpcmdec_chain_raw (pad, subbuf);
494   }
496 done:
497   gst_buffer_unref (buf);
498   gst_object_unref (dvdlpcmdec);
500   return ret;
502   /* ERRORS */
503 negotiation_failed:
504   {
505     GST_DEBUG_OBJECT (dvdlpcmdec, "Failed to set caps!");
506     ret = GST_FLOW_NOT_NEGOTIATED;
507     goto done;
508   }
511 static GstFlowReturn
512 gst_dvdlpcmdec_chain_raw (GstPad * pad, GstBuffer * buf)
514   GstDvdLpcmDec *dvdlpcmdec;
515   guint8 *data;
516   guint size;
517   GstFlowReturn ret;
518   guint samples = 0;
520   dvdlpcmdec = GST_DVDLPCMDEC (gst_pad_get_parent (pad));
522   size = GST_BUFFER_SIZE (buf);
523   data = GST_BUFFER_DATA (buf);
525   GST_LOG_OBJECT (dvdlpcmdec,
526       "got buffer %p of size %d with ts %" GST_TIME_FORMAT,
527       buf, size, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
529   if (dvdlpcmdec->rate == 0)
530     goto not_negotiated;
532   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf))
533     dvdlpcmdec->timestamp = GST_BUFFER_TIMESTAMP (buf);
535   /* We don't currently do anything at all regarding emphasis, mute or 
536    * dynamic_range - I'm not sure what they're for */
537   switch (dvdlpcmdec->width) {
538     case 16:
539     {
540       /* We can just pass 16-bits straight through intact, once we set 
541        * appropriate things on the buffer */
542       samples = size / dvdlpcmdec->channels / 2;
543       buf = gst_buffer_make_metadata_writable (buf);
544       break;
545     }
546     case 20:
547     {
548       /* Allocate a new buffer and copy 20-bit width to 24-bit */
549       gint64 samples = size * 8 / 20;
550       gint64 count = size / 10;
551       gint64 i;
552       guint8 *src;
553       guint8 *dest;
554       GstBuffer *outbuf;
555       GstCaps *bufcaps = GST_PAD_CAPS (dvdlpcmdec->srcpad);
557       ret = gst_pad_alloc_buffer_and_set_caps (dvdlpcmdec->srcpad, 0,
558           samples * 3, bufcaps, &outbuf);
560       if (ret != GST_FLOW_OK)
561         goto buffer_alloc_failed;
563       gst_buffer_stamp (outbuf, buf);
565       /* adjust samples so we can calc the new timestamp */
566       samples = samples / dvdlpcmdec->channels;
568       src = data;
569       dest = GST_BUFFER_DATA (outbuf);
571       /* Copy 20-bit LPCM format to 24-bit buffers, with 0x00 in the lowest 
572        * nibble. Note that the first 2 bytes are already correct */
573       for (i = 0; i < count; i++) {
574         dest[0] = src[0];
575         dest[1] = src[1];
576         dest[2] = src[8] & 0xf0;
577         dest[3] = src[2];
578         dest[4] = src[3];
579         dest[5] = (src[8] & 0x0f) << 4;
580         dest[6] = src[4];
581         dest[7] = src[5];
582         dest[8] = src[9] & 0x0f;
583         dest[9] = src[6];
584         dest[10] = src[7];
585         dest[11] = (src[9] & 0x0f) << 4;
587         src += 10;
588         dest += 12;
589       }
591       gst_buffer_unref (buf);
592       buf = outbuf;
593       break;
594     }
595     case 24:
596     {
597       /* Rearrange 24-bit LPCM format in-place. Note that the first 2
598        * and last byte are already correct */
599       guint count = size / 12;
600       gint i;
601       guint8 *src;
603       samples = size / dvdlpcmdec->channels / 3;
605       /* Ensure our output buffer is writable */
606       buf = gst_buffer_make_writable (buf);
608       src = GST_BUFFER_DATA (buf);
609       for (i = 0; i < count; i++) {
610         guint8 tmp;
612         tmp = src[10];
613         src[10] = src[7];
614         src[7] = src[5];
615         src[5] = src[9];
616         src[9] = src[6];
617         src[6] = src[4];
618         src[4] = src[3];
619         src[3] = src[2];
620         src[2] = src[8];
621         src[8] = tmp;
623         src += 12;
624       }
625       break;
626     }
627     default:
628       goto invalid_width;
629   }
631   /* Set appropriate caps on it to pass downstream */
632   gst_buffer_set_caps (buf, GST_PAD_CAPS (dvdlpcmdec->srcpad));
633   update_timestamps (dvdlpcmdec, buf, samples);
635   ret = gst_pad_push (dvdlpcmdec->srcpad, buf);
637 done:
638   gst_object_unref (dvdlpcmdec);
640   return ret;
642   /* ERRORS */
643 not_negotiated:
644   {
645     GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),
646         ("Buffer pushed before negotiation"));
647     gst_buffer_unref (buf);
648     ret = GST_FLOW_NOT_NEGOTIATED;
649     goto done;
650   }
651 buffer_alloc_failed:
652   {
653     GST_ELEMENT_ERROR (dvdlpcmdec, RESOURCE, FAILED, (NULL),
654         ("Buffer allocation failed"));
655     gst_buffer_unref (buf);
656     goto done;
657   }
658 invalid_width:
659   {
660     GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, WRONG_TYPE, (NULL),
661         ("Invalid sample width configured"));
662     gst_buffer_unref (buf);
663     ret = GST_FLOW_NOT_NEGOTIATED;
664     goto done;
665   }
668 static gboolean
669 dvdlpcmdec_sink_event (GstPad * pad, GstEvent * event)
671   GstDvdLpcmDec *dvdlpcmdec;
672   gboolean res;
674   dvdlpcmdec = GST_DVDLPCMDEC (GST_PAD_PARENT (pad));
676   switch (GST_EVENT_TYPE (event)) {
677     case GST_EVENT_NEWSEGMENT:
678     {
679       gdouble rate, arate;
680       GstFormat format;
681       gboolean update;
682       gint64 start, stop, pos;
684       gst_event_parse_new_segment_full (event, &update, &rate, &arate,
685           &format, &start, &stop, &pos);
687       GST_DEBUG_OBJECT (dvdlpcmdec,
688           "new segment, format=%d, start = %" G_GINT64_FORMAT
689           ", stop = %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT,
690           format, start, stop, pos);
692       gst_segment_set_newsegment_full (&dvdlpcmdec->segment, update,
693           rate, arate, format, start, stop, pos);
695       if (format == GST_FORMAT_TIME) {
696         dvdlpcmdec->timestamp = GST_CLOCK_TIME_NONE;
697       } else {
698         dvdlpcmdec->timestamp = 0;
699       }
700       res = gst_pad_push_event (dvdlpcmdec->srcpad, event);
701       break;
702     }
703     case GST_EVENT_FLUSH_STOP:
704       gst_segment_init (&dvdlpcmdec->segment, GST_FORMAT_UNDEFINED);
705       res = gst_pad_push_event (dvdlpcmdec->srcpad, event);
706       break;
707     default:
708       res = gst_pad_push_event (dvdlpcmdec->srcpad, event);
709       break;
710   }
712   return res;
715 static GstStateChangeReturn
716 gst_dvdlpcmdec_change_state (GstElement * element, GstStateChange transition)
718   GstDvdLpcmDec *dvdlpcmdec = GST_DVDLPCMDEC (element);
719   GstStateChangeReturn res;
721   switch (transition) {
722     case GST_STATE_CHANGE_READY_TO_PAUSED:
723       gst_dvdlpcm_reset (dvdlpcmdec);
724       break;
725     default:
726       break;
727   }
729   res = parent_class->change_state (element, transition);
731   switch (transition) {
732     default:
733       break;
734   }
736   return res;
739 static gboolean
740 plugin_init (GstPlugin * plugin)
742   GST_DEBUG_CATEGORY_INIT (dvdlpcm_debug, "dvdlpcmdec", 0, "DVD LPCM Decoder");
744   if (!gst_element_register (plugin, "dvdlpcmdec", GST_RANK_PRIMARY,
745           GST_TYPE_DVDLPCMDEC)) {
746     return FALSE;
747   }
749   return TRUE;
752 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
753     GST_VERSION_MINOR,
754     "dvdlpcmdec",
755     "Decode DVD LPCM frames into standard PCM",
756     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);