configure.ac: Add dvdlpcmdec
authorJan Schmidt <thaytan@mad.scientist.com>
Tue, 8 Feb 2005 11:08:15 +0000 (11:08 +0000)
committerJan Schmidt <thaytan@mad.scientist.com>
Tue, 8 Feb 2005 11:08:15 +0000 (11:08 +0000)
Original commit message from CVS:

* configure.ac:
Add dvdlpcmdec

* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_reset),
(free_all_buffers), (gst_mpeg2dec_alloc_buffer):
Don't push buffers if the src pad isn't negotiated yet.

* gst/audioconvert/gstaudioconvert.c:
(gst_audio_convert_buffer_to_default_format),
(gst_audio_convert_buffer_from_default_format):
Add support for 24-bit width.

* gst/dvdlpcmdec/.cvsignore:
* gst/dvdlpcmdec/Makefile.am:
* gst/dvdlpcmdec/gstdvdlpcmdec.c: (gst_dvdlpcmdec_get_type),
(gst_dvdlpcmdec_base_init), (gst_dvdlpcmdec_class_init),
(gst_dvdlpcm_reset), (gst_dvdlpcmdec_init), (gst_dvdlpcmdec_link),
(gst_dvdlpcmdec_chain), (gst_dvdlpcmdec_change_state),
(plugin_init):
* gst/dvdlpcmdec/gstdvdlpcmdec.h:
New decoder for rearranging DVD LPCM into our audio/x-raw-int
format. Needs support for the channels maps if someone can find
a DVD LPCM track with > 2 channels.

* gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_handle_dvd_event),
(gst_dvd_demux_send_discont), (gst_dvd_demux_handle_discont),
(gst_dvd_demux_get_audio_stream), (gst_dvd_demux_process_private):
* gst/mpegstream/gstdvddemux.h:
* gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_send_discont),
(gst_mpeg_demux_new_output_pad), (gst_mpeg_demux_init_stream),
(gst_mpeg_demux_send_subbuffer), (gst_mpeg_demux_handle_src_query):
* gst/mpegstream/gstmpegdemux.h:
* gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_reset),
(gst_mpeg_parse_parse_packhead), (gst_mpeg_parse_loop),
(gst_mpeg_parse_get_rate), (gst_mpeg_parse_convert_src),
(gst_mpeg_parse_handle_src_query),
(gst_mpeg_parse_handle_src_event):
Use audio/x-dvd-lpcm for LPCM output.
Add DTS output.

ChangeLog
configure.ac
ext/mpeg2dec/gstmpeg2dec.c
gst/dvdlpcmdec/.gitignore [new file with mode: 0644]
gst/dvdlpcmdec/Makefile.am [new file with mode: 0644]
gst/dvdlpcmdec/gstdvdlpcmdec.c [new file with mode: 0644]
gst/dvdlpcmdec/gstdvdlpcmdec.h [new file with mode: 0644]
gst/mpegstream/gstdvddemux.c
gst/mpegstream/gstdvddemux.h

index 0c010d04b24f97d610e47477f94e5a79cc9439ab..b5b4744c65f4d1ed222ece519c6ca1cb42b590e9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+2005-02-08  Jan Schmidt  <thaytan@mad.scientist.com>
+
+       * configure.ac:
+         Add dvdlpcmdec 
+
+       * ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_reset),
+       (free_all_buffers), (gst_mpeg2dec_alloc_buffer):
+         Don't push buffers if the src pad isn't negotiated yet.
+         
+       * gst/audioconvert/gstaudioconvert.c:
+       (gst_audio_convert_buffer_to_default_format),
+       (gst_audio_convert_buffer_from_default_format):
+         Add support for 24-bit width.
+
+       * gst/dvdlpcmdec/.cvsignore:
+       * gst/dvdlpcmdec/Makefile.am:
+       * gst/dvdlpcmdec/gstdvdlpcmdec.c: (gst_dvdlpcmdec_get_type),
+       (gst_dvdlpcmdec_base_init), (gst_dvdlpcmdec_class_init),
+       (gst_dvdlpcm_reset), (gst_dvdlpcmdec_init), (gst_dvdlpcmdec_link),
+       (gst_dvdlpcmdec_chain), (gst_dvdlpcmdec_change_state),
+       (plugin_init):
+       * gst/dvdlpcmdec/gstdvdlpcmdec.h:
+         New decoder for rearranging DVD LPCM into our audio/x-raw-int
+         format. Needs support for the channels maps if someone can find 
+         a DVD LPCM track with > 2 channels.
+
+       * gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_handle_dvd_event),
+       (gst_dvd_demux_send_discont), (gst_dvd_demux_handle_discont),
+       (gst_dvd_demux_get_audio_stream), (gst_dvd_demux_process_private):
+       * gst/mpegstream/gstdvddemux.h:
+       * gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_send_discont),
+       (gst_mpeg_demux_new_output_pad), (gst_mpeg_demux_init_stream),
+       (gst_mpeg_demux_send_subbuffer), (gst_mpeg_demux_handle_src_query):
+       * gst/mpegstream/gstmpegdemux.h:
+       * gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_reset),
+       (gst_mpeg_parse_parse_packhead), (gst_mpeg_parse_loop),
+       (gst_mpeg_parse_get_rate), (gst_mpeg_parse_convert_src),
+       (gst_mpeg_parse_handle_src_query),
+       (gst_mpeg_parse_handle_src_event):
+          Use audio/x-dvd-lpcm for LPCM output.
+         Add DTS output.
+
 2005-02-08  Gergely Nagy  <algernon@bonehunter.rulez.org>
 
        Reviewed by:  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
index 70b349b8e331cb374df836406bbdbb612a89d3d8..870d269a652543d152424f2525cdf1ca2d8c87b2 100644 (file)
@@ -376,6 +376,7 @@ GST_PLUGINS_ALL="\
        cutter \
        debug \
        deinterlace \
+       dvdlpcmdec \
        effectv \
        equalizer \
        festival \
@@ -1956,6 +1957,7 @@ gst/colorspace/Makefile
 gst/cutter/Makefile
 gst/debug/Makefile
 gst/deinterlace/Makefile
+gst/dvdlpcmdec/Makefile
 gst/effectv/Makefile
 gst/equalizer/Makefile
 gst/festival/Makefile
index bb3863b683b755a0d31357adc8e5216fde6d92ce..c3163b22a8f216574ea5be19852be88275d2c939 100644 (file)
@@ -342,6 +342,7 @@ gst_mpeg2dec_reset (GstMpeg2dec * mpeg2dec)
   mpeg2dec->segment_end = -1;
   mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
   mpeg2dec->frame_period = 0;
+  gst_pad_set_explicit_caps (mpeg2dec->srcpad, NULL);
   gst_mpeg2dec_open_decoder (mpeg2dec);
   mpeg2dec->need_sequence = TRUE;
 }
@@ -774,7 +775,8 @@ handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
     if (picture->flags & PIC_FLAG_SKIP) {
       GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer because of skip flag");
       gst_buffer_unref (outbuf);
-    } else if (!GST_PAD_IS_USABLE (mpeg2dec->srcpad)) {
+    } else if (!GST_PAD_IS_USABLE (mpeg2dec->srcpad)
+        || !gst_pad_is_negotiated (mpeg2dec->srcpad)) {
       GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer, pad not usable");
       gst_buffer_unref (outbuf);
     } else if (mpeg2dec->discont_state != MPEG2DEC_DISC_NONE) {
@@ -889,7 +891,6 @@ gst_mpeg2dec_flush_decoder (GstMpeg2dec * mpeg2dec)
 #if MPEG2_RELEASE >= MPEG2_VERSION (0, 4, 0)
         case STATE_INVALID_END:
 #endif
-          // mpeg2dec->need_sequence = TRUE;
         case STATE_SLICE:
           if (info->discard_fbuf) {
             if (free_buffer (mpeg2dec, GST_BUFFER (info->discard_fbuf->id))) {
diff --git a/gst/dvdlpcmdec/.gitignore b/gst/dvdlpcmdec/.gitignore
new file mode 100644 (file)
index 0000000..08f5ed3
--- /dev/null
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
diff --git a/gst/dvdlpcmdec/Makefile.am b/gst/dvdlpcmdec/Makefile.am
new file mode 100644 (file)
index 0000000..31e5116
--- /dev/null
@@ -0,0 +1,9 @@
+
+plugin_LTLIBRARIES = libgstdvdlpcmdec.la
+
+libgstdvdlpcmdec_la_SOURCES = gstdvdlpcmdec.c
+libgstdvdlpcmdec_la_CFLAGS = $(GST_CFLAGS)
+libgstdvdlpcmdec_la_LIBADD =
+libgstdvdlpcmdec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstdvdlpcmdec.h
diff --git a/gst/dvdlpcmdec/gstdvdlpcmdec.c b/gst/dvdlpcmdec/gstdvdlpcmdec.c
new file mode 100644 (file)
index 0000000..2062d14
--- /dev/null
@@ -0,0 +1,394 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Jan Schmidt <jan@noraisin.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/* Element-Checklist-Version: TODO */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "gstdvdlpcmdec.h"
+#include <gst/audio/audio.h>
+
+GST_DEBUG_CATEGORY_STATIC (dvdlpcm_debug);
+#define GST_CAT_DEFAULT dvdlpcm_debug
+
+/* elementfactory information */
+static GstElementDetails gst_dvdlpcmdec_details =
+GST_ELEMENT_DETAILS ("DVD LPCM Audio decoder",
+    "Codec/Demuxer/Audio",
+    "Decode DVD LPCM frames into standard PCM audio",
+    "Jan Schmidt <jan@noraisin.net>");
+
+static GstStaticPadTemplate gst_dvdlpcmdec_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-dvd-lpcm, "
+        "width = (int) { 16, 20, 24 }, "
+        "rate = (int) { 48000, 96000 }, "
+        "channels = (int) [ 1, 8 ], "
+        "dynamic_range = (int) [ 0, 255 ], "
+        "emphasis = (boolean) { TRUE, FALSE }, "
+        "mute = (boolean) { TRUE, FALSE }")
+    );
+
+static GstStaticPadTemplate gst_dvdlpcmdec_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS)
+    );
+
+/* DvdLpcmDec signals and args */
+enum
+{
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum
+{
+  ARG_0
+      /* FILL ME */
+};
+
+static void gst_dvdlpcmdec_base_init (gpointer g_class);
+static void gst_dvdlpcmdec_class_init (GstDvdLpcmDecClass * klass);
+static void gst_dvdlpcmdec_init (GstDvdLpcmDec * dvdlpcmdec);
+
+static void gst_dvdlpcmdec_chain (GstPad * pad, GstData * _data);
+static GstPadLinkReturn gst_dvdlpcmdec_link (GstPad * pad,
+    const GstCaps * caps);
+
+static GstElementStateReturn gst_dvdlpcmdec_change_state (GstElement * element);
+
+static GstElementClass *parent_class = NULL;
+
+GType
+gst_dvdlpcmdec_get_type (void)
+{
+  static GType dvdlpcmdec_type = 0;
+
+  if (!dvdlpcmdec_type) {
+    static const GTypeInfo dvdlpcmdec_info = {
+      sizeof (GstDvdLpcmDecClass),
+      gst_dvdlpcmdec_base_init,
+      NULL,
+      (GClassInitFunc) gst_dvdlpcmdec_class_init,
+      NULL,
+      NULL,
+      sizeof (GstDvdLpcmDec),
+      0,
+      (GInstanceInitFunc) gst_dvdlpcmdec_init,
+    };
+
+    dvdlpcmdec_type =
+        g_type_register_static (GST_TYPE_ELEMENT, "GstDvdLpcmDec",
+        &dvdlpcmdec_info, 0);
+  }
+  return dvdlpcmdec_type;
+}
+
+static void
+gst_dvdlpcmdec_base_init (gpointer g_class)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_dvdlpcmdec_sink_template));
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_dvdlpcmdec_src_template));
+  gst_element_class_set_details (element_class, &gst_dvdlpcmdec_details);
+}
+
+static void
+gst_dvdlpcmdec_class_init (GstDvdLpcmDecClass * klass)
+{
+  GstElementClass *gstelement_class;
+
+  gstelement_class = (GstElementClass *) klass;
+
+  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+
+  gstelement_class->change_state = gst_dvdlpcmdec_change_state;
+}
+
+static void
+gst_dvdlpcm_reset (GstDvdLpcmDec * dvdlpcmdec)
+{
+  dvdlpcmdec->rate = 0;
+  dvdlpcmdec->channels = 0;
+  dvdlpcmdec->width = 0;
+  dvdlpcmdec->out_width = 0;
+  dvdlpcmdec->dynamic_range = 0;
+  dvdlpcmdec->emphasis = FALSE;
+  dvdlpcmdec->mute = FALSE;
+  dvdlpcmdec->offset = 0;
+
+  gst_pad_set_explicit_caps (dvdlpcmdec->srcpad, NULL);
+}
+
+static void
+gst_dvdlpcmdec_init (GstDvdLpcmDec * dvdlpcmdec)
+{
+  dvdlpcmdec->sinkpad =
+      gst_pad_new_from_template (gst_static_pad_template_get
+      (&gst_dvdlpcmdec_sink_template), "sink");
+  gst_pad_set_link_function (dvdlpcmdec->sinkpad, gst_dvdlpcmdec_link);
+  gst_pad_set_chain_function (dvdlpcmdec->sinkpad, gst_dvdlpcmdec_chain);
+  gst_element_add_pad (GST_ELEMENT (dvdlpcmdec), dvdlpcmdec->sinkpad);
+
+  dvdlpcmdec->srcpad =
+      gst_pad_new_from_template (gst_static_pad_template_get
+      (&gst_dvdlpcmdec_src_template), "src");
+  gst_pad_use_explicit_caps (dvdlpcmdec->srcpad);
+  gst_element_add_pad (GST_ELEMENT (dvdlpcmdec), dvdlpcmdec->srcpad);
+
+  gst_dvdlpcm_reset (dvdlpcmdec);
+}
+
+
+static GstPadLinkReturn
+gst_dvdlpcmdec_link (GstPad * pad, const GstCaps * caps)
+{
+  GstStructure *structure;
+  gboolean res = TRUE;
+  GstDvdLpcmDec *dvdlpcmdec;
+  GstCaps *src_caps;
+
+  g_return_val_if_fail (caps != NULL, GST_PAD_LINK_REFUSED);
+  g_return_val_if_fail (pad != NULL, GST_PAD_LINK_REFUSED);
+
+  dvdlpcmdec = GST_DVDLPCMDEC (gst_pad_get_parent (pad));
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  res &= gst_structure_get_int (structure, "rate", &dvdlpcmdec->rate);
+  res &= gst_structure_get_int (structure, "channels", &dvdlpcmdec->channels);
+  res &= gst_structure_get_int (structure, "width", &dvdlpcmdec->width);
+  res &= gst_structure_get_int (structure, "dynamic_range",
+      &dvdlpcmdec->dynamic_range);
+  res &= gst_structure_get_boolean (structure, "emphasis",
+      &dvdlpcmdec->emphasis);
+  res &= gst_structure_get_boolean (structure, "mute", &dvdlpcmdec->mute);
+
+  if (!res)
+    return GST_PAD_LINK_REFUSED;
+
+  /* Output width is the input width rounded up to the nearest byte */
+  if (dvdlpcmdec->width == 20)
+    dvdlpcmdec->out_width = 24;
+  else
+    dvdlpcmdec->out_width = dvdlpcmdec->width;
+
+  /* Build explicit caps to set on the src pad */
+  src_caps = gst_caps_new_simple ("audio/x-raw-int",
+      "rate", G_TYPE_INT, dvdlpcmdec->rate,
+      "channels", G_TYPE_INT, dvdlpcmdec->channels,
+      "endianness", G_TYPE_INT, G_BIG_ENDIAN,
+      "depth", G_TYPE_INT, dvdlpcmdec->out_width,
+      "width", G_TYPE_INT, dvdlpcmdec->out_width,
+      "signed", G_TYPE_BOOLEAN, TRUE, NULL);
+
+  GST_DEBUG_OBJECT (dvdlpcmdec, "Set rate %d, channels %d, width %d (out %d)",
+      dvdlpcmdec->rate, dvdlpcmdec->channels, dvdlpcmdec->width,
+      dvdlpcmdec->out_width);
+
+  if (!gst_pad_set_explicit_caps (dvdlpcmdec->srcpad, src_caps))
+    res = FALSE;
+
+  gst_caps_free (src_caps);
+
+  if (!res)
+    return GST_PAD_LINK_REFUSED;
+
+  return GST_PAD_LINK_OK;
+}
+
+static void
+gst_dvdlpcmdec_chain (GstPad * pad, GstData * _data)
+{
+  GstBuffer *buf = GST_BUFFER (_data);
+  GstDvdLpcmDec *dvdlpcmdec;
+  guchar *data;
+  gint64 size;
+
+  g_return_if_fail (pad != NULL);
+  g_return_if_fail (GST_IS_PAD (pad));
+  g_return_if_fail (buf != NULL);
+
+  dvdlpcmdec = GST_DVDLPCMDEC (gst_pad_get_parent (pad));
+
+  data = GST_BUFFER_DATA (buf);
+  size = GST_BUFFER_SIZE (buf);
+
+  GST_LOG_OBJECT (dvdlpcmdec, "got buffer %p of size %" G_GINT64_FORMAT, buf,
+      size);
+
+  if (dvdlpcmdec->rate == 0) {
+    GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),
+        ("Buffer pushed before negotiation"));
+    gst_buffer_unref (buf);
+    return;
+  }
+
+  if (!GST_PAD_IS_USABLE (dvdlpcmdec->srcpad)) {
+    GST_DEBUG_OBJECT (dvdlpcmdec, "Discarding buffer on disabled pad");
+    gst_buffer_unref (buf);
+    return;
+  }
+
+  /* We don't currently do anything at all regarding emphasis, mute or 
+   * dynamic_range - I'm not sure what they're for */
+  switch (dvdlpcmdec->width) {
+    case 16:
+    {
+      /* We can just pass 16-bits straight through intact */
+      dvdlpcmdec->offset += GST_BUFFER_SIZE (buf);
+      gst_pad_push (dvdlpcmdec->srcpad, GST_DATA (buf));
+      return;
+    }
+    case 20:
+    {
+      /* Allocate a new buffer and copy 20-bit width to 24-bit */
+      gint64 samples = size * 8 / 20;
+      gint64 count = size / 10;
+      gint64 i;
+      guchar *src;
+      guchar *dest;
+      GstBuffer *outbuf;
+
+      if (count * 10 != samples * 3) {
+        g_print ("bleh\n");
+      }
+      outbuf = gst_pad_alloc_buffer (dvdlpcmdec->srcpad, dvdlpcmdec->offset,
+          samples * 3);
+      if (!outbuf) {
+        GST_ELEMENT_ERROR (dvdlpcmdec, RESOURCE, FAILED, (NULL),
+            ("Buffer allocation failed"));
+        gst_buffer_unref (buf);
+        return;
+      }
+      gst_buffer_stamp (outbuf, buf);
+
+      src = data;
+      dest = GST_BUFFER_DATA (outbuf);
+
+      /* Copy 20-bit LPCM format to 24-bit buffers, with 0x00 in the lowest 
+       * nibble. Not that the first 2 bytes are already correct */
+      for (i = 0; i < count; i++) {
+        dest[0] = src[0];
+        dest[1] = src[1];
+        dest[2] = src[8] & 0xf0;
+        dest[3] = src[2];
+        dest[4] = src[3];
+        dest[5] = (src[8] & 0x0f) << 4;
+        dest[6] = src[4];
+        dest[7] = src[5];
+        dest[8] = src[9] & 0x0f;
+        dest[9] = src[6];
+        dest[10] = src[7];
+        dest[11] = (src[9] & 0x0f) << 4;
+
+        src += 10;
+        dest += 12;
+      }
+
+      gst_buffer_unref (buf);
+      dvdlpcmdec->offset += GST_BUFFER_SIZE (outbuf);
+      gst_pad_push (dvdlpcmdec->srcpad, GST_DATA (outbuf));
+      return;
+    }
+    case 24:
+    {
+      /* Rearrange 24-bit LPCM format in-place. Note that the first 2
+       * and last byte are already correct */
+      gint64 count = size / 12;
+      gint64 i;
+      guchar *src = data;
+
+      for (i = 0; i < count; i++) {
+        guchar temp[9];
+
+        temp[0] = src[8];
+        temp[1] = src[2];
+        temp[2] = src[3];
+        temp[3] = src[9];
+        temp[4] = src[4];
+        temp[5] = src[5];
+        temp[6] = src[10];
+        temp[7] = src[6];
+        temp[8] = src[7];
+
+        memcpy (src + 2, temp, 9);
+        src += 12;
+      }
+
+      dvdlpcmdec->offset += GST_BUFFER_SIZE (buf);
+      gst_pad_push (dvdlpcmdec->srcpad, GST_DATA (buf));
+      return;
+    }
+    default:
+      GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, WRONG_TYPE, (NULL),
+          ("Invalid sample width configured"));
+  }
+
+  gst_buffer_unref (buf);
+}
+
+static GstElementStateReturn
+gst_dvdlpcmdec_change_state (GstElement * element)
+{
+  GstDvdLpcmDec *dvdlpcmdec = GST_DVDLPCMDEC (element);
+
+  switch (GST_STATE_TRANSITION (element)) {
+    case GST_STATE_PAUSED_TO_READY:
+      gst_dvdlpcm_reset (dvdlpcmdec);
+      break;
+    default:
+      break;
+  }
+
+  if (parent_class->change_state)
+    return parent_class->change_state (element);
+
+  return GST_STATE_SUCCESS;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (dvdlpcm_debug, "dvdlpcmdec", 0, "DVD LPCM Decoder");
+
+  if (!gst_element_register (plugin, "dvdlpcmdec", GST_RANK_PRIMARY,
+          GST_TYPE_DVDLPCMDEC)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    "dvdlpcmdec",
+    "Decode DVD LPCM frames into standard PCM",
+    plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN)
diff --git a/gst/dvdlpcmdec/gstdvdlpcmdec.h b/gst/dvdlpcmdec/gstdvdlpcmdec.h
new file mode 100644 (file)
index 0000000..099e70f
--- /dev/null
@@ -0,0 +1,66 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Jan Schmidt <jan@noraisin.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_DVDLPCMDEC_H__
+#define __GST_DVDLPCMDEC_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DVDLPCMDEC \
+  (gst_dvdlpcmdec_get_type())
+#define GST_DVDLPCMDEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DVDLPCMDEC,GstDvdLpcmDec))
+#define GST_DVDLPCMDEC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DVDLPCMDEC,GstDvdLpcmDec))
+#define GST_IS_DVDLPCMDEC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DVDLPCMDEC))
+#define GST_IS_DVDLPCMDEC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DVDLPCMDEC))
+
+typedef struct _GstDvdLpcmDec GstDvdLpcmDec;
+typedef struct _GstDvdLpcmDecClass GstDvdLpcmDecClass;
+
+struct _GstDvdLpcmDec {
+  GstElement element;
+
+  GstPad *sinkpad,*srcpad;
+
+  guint rate;
+  guint channels;
+  guint width;
+  guint out_width;
+  guint dynamic_range;
+  guint emphasis;
+  guint mute;
+  
+  guint64 offset;  
+};
+
+struct _GstDvdLpcmDecClass {
+  GstElementClass parent_class;
+};
+
+GType gst_dvdlpcmdec_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_DVDLPCMDEC_H__ */
index c23d9dad99af131bc75af713ffab7da4c0386529..5ca52363905abb48c0a004bb3c2cf5135cb9c44e 100644 (file)
@@ -82,13 +82,13 @@ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
   GST_STATIC_CAPS ( \
     "audio/mpeg, " \
       "mpegversion = (int) 1;" \
-    "audio/x-raw-int, " \
-      "endianness = (int) BIG_ENDIAN, " \
-      "signed = (boolean) TRUE, " \
-      "width = (int) { 16, 24 }, " \
-      "depth = (int) { 16, 20, 24 }, " \
+    "audio/x-dvd-lpcm, " \
+      "width = (int) { 16, 20, 24 }, " \
       "rate = (int) { 48000, 96000 }, " \
-      "channels = (int) [ 1, 8 ];" \
+      "channels = (int) [ 1, 8 ], " \
+      "dynamic_range = (int) [ 0, 255 ], " \
+      "emphasis = (boolean) { FALSE, TRUE }, " \
+      "mute = (boolean) { FALSE, TRUE }; " \
     "audio/x-ac3;" \
     "audio/x-dts" \
   )
@@ -96,7 +96,6 @@ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
 #define SUBPICTURE_CAPS \
   GST_STATIC_CAPS ("video/x-dvd-subpicture")
 
-
 static GstStaticPadTemplate cur_video_template =
 GST_STATIC_PAD_TEMPLATE ("current_video",
     GST_PAD_SRC,
@@ -429,9 +428,13 @@ gst_dvd_demux_handle_dvd_event (GstDVDDemux * dvd_demux, GstEvent * event)
          the next sequence time. We don't do it here to reduce the
          time gap between the discontinuity and the subsequent data
          blocks. */
+#if 1
       dvd_demux->discont_time = start_ptm + mpeg_demux->adjust;
+#else
+      dvd_demux->discont_time = start_ptm;
+#endif
       GST_DEBUG_OBJECT (dvd_demux, "Set discont time to %" G_GINT64_FORMAT,
-          start_ptm + mpeg_demux->adjust);
+          dvd_demux->discont_time);
 
       dvd_demux->just_flushed = FALSE;
     }
@@ -506,7 +509,7 @@ gst_dvd_demux_handle_discont (GstMPEGParse * mpeg_parse, GstEvent * event)
     gst_dvd_demux_reset (dvd_demux);
   }
 
-  /* before we reset let parent handle and forward discont */
+  /* let parent handle and forward discont */
   if (GST_MPEG_PARSE_CLASS (parent_class)->handle_discont != NULL)
     GST_MPEG_PARSE_CLASS (parent_class)->handle_discont (mpeg_parse, event);
 }
@@ -544,12 +547,11 @@ gst_dvd_demux_get_audio_stream (GstMPEGDemux * mpeg_demux,
     guint8 stream_nr, gint type, const gpointer info)
 {
   GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_demux);
-  guint8 sample_info = 0;
+  guint32 sample_info = 0;
   GstMPEGStream *str;
   GstDVDLPCMStream *lpcm_str = NULL;
-  GstCaps *caps;
-  gint width, rate, channels;
   gboolean add_pad = FALSE;
+  GstCaps *caps;
 
   g_return_val_if_fail (stream_nr < GST_MPEG_DEMUX_NUM_AUDIO_STREAMS, NULL);
   g_return_val_if_fail (type > GST_MPEG_DEMUX_AUDIO_UNKNOWN &&
@@ -560,7 +562,7 @@ gst_dvd_demux_get_audio_stream (GstMPEGDemux * mpeg_demux,
   }
 
   if (type == GST_DVD_DEMUX_AUDIO_LPCM) {
-    sample_info = *((guint8 *) info);
+    sample_info = *((guint32 *) info);
   }
 
   str = mpeg_demux->audio_stream[stream_nr];
@@ -597,15 +599,21 @@ gst_dvd_demux_get_audio_stream (GstMPEGDemux * mpeg_demux,
   if (type != str->type ||
       (type == GST_DVD_DEMUX_AUDIO_LPCM &&
           sample_info != lpcm_str->sample_info)) {
+    gint width, rate, channels, dynamic_range;
+    gboolean emphasis, mute;
+
     /* We need to set new caps for this pad. */
     switch (type) {
       case GST_DVD_DEMUX_AUDIO_LPCM:
+        /* Dynamic range in the lower byte */
+        dynamic_range = sample_info & 0xff;
+
         /* Determine the sample width. */
-        switch (sample_info & 0xC0) {
-          case 0x80:
+        switch (sample_info & 0xC000) {
+          case 0x8000:
             width = 24;
             break;
-          case 0x40:
+          case 0x4000:
             width = 20;
             break;
           default:
@@ -614,27 +622,34 @@ gst_dvd_demux_get_audio_stream (GstMPEGDemux * mpeg_demux,
         }
 
         /* Determine the rate. */
-        if (sample_info & 0x10) {
+        if (sample_info & 0x1000) {
           rate = 96000;
         } else {
           rate = 48000;
         }
 
+        mute = ((sample_info & 0x400000) != 0);
+        emphasis = ((sample_info & 0x800000) != 0);
+
         /* Determine the number of channels. */
-        channels = (sample_info & 0x7) + 1;
+        channels = ((sample_info >> 8) & 0x7) + 1;
 
-        caps = gst_caps_new_simple ("audio/x-raw-int",
-            "endianness", G_TYPE_INT, G_BIG_ENDIAN,
-            "signed", G_TYPE_BOOLEAN, TRUE,
+        caps = gst_caps_new_simple ("audio/x-dvd-lpcm",
             "width", G_TYPE_INT, width,
-            "depth", G_TYPE_INT, width,
-            "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL);
-
+            "rate", G_TYPE_INT, rate,
+            "channels", G_TYPE_INT, channels,
+            "dynamic_range", G_TYPE_INT, dynamic_range,
+            "emphasis", G_TYPE_BOOLEAN, emphasis,
+            "mute", G_TYPE_BOOLEAN, mute, NULL);
 
         lpcm_str->sample_info = sample_info;
         lpcm_str->width = width;
         lpcm_str->rate = rate;
         lpcm_str->channels = channels;
+        lpcm_str->dynamic_range = dynamic_range;
+        lpcm_str->mute = mute;
+        lpcm_str->emphasis = emphasis;
+
         break;
 
       case GST_DVD_DEMUX_AUDIO_AC3:
@@ -718,7 +733,6 @@ gst_dvd_demux_get_subpicture_stream (GstMPEGDemux * mpeg_demux,
   return str;
 }
 
-
 static void
 gst_dvd_demux_process_private (GstMPEGDemux * mpeg_demux,
     GstBuffer * buffer,
@@ -726,7 +740,7 @@ gst_dvd_demux_process_private (GstMPEGDemux * mpeg_demux,
 {
   GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_demux);
   guint8 *basebuf;
-  guint8 ps_id_code, lpcm_sample_info;
+  guint8 ps_id_code;
   GstMPEGStream *outstream = NULL;
   guint first_access = 0;
   gint align = 1, len, off;
@@ -739,7 +753,6 @@ gst_dvd_demux_process_private (GstMPEGDemux * mpeg_demux,
   /* In the following, the "first access" refers to the location in a
      buffer the time stamp is associated to.  DVDs include this
      information explicitely. */
-
   switch (stream_nr) {
     case 0:
       /* Private stream 1. */
@@ -752,31 +765,47 @@ gst_dvd_demux_process_private (GstMPEGDemux * mpeg_demux,
 
         /* Determine the position of the "first access".  This
            should always be the beginning of an AC3 frame. */
-        first_access = *(basebuf + headerlen + 6) * 256 +
-            *(basebuf + headerlen + 7);
+        first_access = (basebuf[headerlen + 6] << 8) | basebuf[headerlen + 7];
+
+        headerlen += 4;
+        datalen -= 4;
+      } else if (ps_id_code >= 0x88 && ps_id_code <= 0x8f) {
+        GST_LOG_OBJECT (dvd_demux,
+            "we have an audio (DTS) packet, track %d", ps_id_code - 0x88);
+        outstream = DEMUX_CLASS (dvd_demux)->get_audio_stream (mpeg_demux,
+            ps_id_code - 0x88, GST_DVD_DEMUX_AUDIO_DTS, NULL);
+
+        /* Determine the position of the "first access".  This
+           should always be the beginning of a DTS frame. */
+        first_access = (basebuf[headerlen + 6] << 8) | basebuf[headerlen + 7];
 
         headerlen += 4;
         datalen -= 4;
       } else if (ps_id_code >= 0xA0 && ps_id_code <= 0xA7) {
         GstDVDLPCMStream *lpcm_str;
+        guint32 lpcm_sample_info;
 
         GST_LOG_OBJECT (dvd_demux,
             "we have an audio (LPCM) packet, track %d", ps_id_code - 0xA0);
-        lpcm_sample_info = basebuf[headerlen + 9];
+
+        /* Compose the sample info from the LPCM header, masking out the frame_num */
+        lpcm_sample_info =
+            basebuf[headerlen + 10] | (basebuf[headerlen +
+                9] << 8) | ((basebuf[headerlen + 8] & 0xc0) << 16);
+
         outstream = DEMUX_CLASS (dvd_demux)->get_audio_stream (mpeg_demux,
             ps_id_code - 0xA0, GST_DVD_DEMUX_AUDIO_LPCM, &lpcm_sample_info);
         lpcm_str = (GstDVDLPCMStream *) outstream;
 
         /* Determine the position of the "first access". */
-        first_access = *(basebuf + headerlen + 6) * 256 +
-            *(basebuf + headerlen + 7);
+        first_access = (basebuf[headerlen + 6] << 8) | basebuf[headerlen + 7];
 
         /* Get rid of the LPCM header. */
         headerlen += 7;
         datalen -= 7;
 
-        /* align by samples */
-        align = lpcm_str->width * lpcm_str->channels / 8;
+        /* align by frame round up to nearest byte */
+        align = (lpcm_str->width * lpcm_str->channels + 7) / 8;
       } else if (ps_id_code >= 0x20 && ps_id_code <= 0x3F) {
         GST_LOG_OBJECT (dvd_demux,
             "we have a subpicture packet, track %d", ps_id_code - 0x20);
index dd9a8768709a6f148acfa445abad57590c128994..aa956310ab9908fb474c596959324c3fee5f82eb 100644 (file)
@@ -77,12 +77,14 @@ enum {
    streams. */
 struct _GstDVDLPCMStream {
   GstMPEGStream         parent;
-  guint       sample_info;   /* The type of linear PCM samples
+  guint32       sample_info;   /* The type of linear PCM samples
                                    associated to this stream. The
                                    values are bit fields with the same
                                    format of the sample_info field in
                                    the linear PCM header. */
-  gint rate, channels, width;
+  gint rate, channels, width,
+    dynamic_range;
+  gboolean mute, emphasis;
 };