configure.ac: Add dvdlpcmdec

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.
This commit is contained in:
Jan Schmidt 2005-02-08 11:08:15 +00:00
parent ad6702d988
commit 9c44c90c48
9 changed files with 590 additions and 38 deletions

View file

@ -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> 2005-02-08 Gergely Nagy <algernon@bonehunter.rulez.org>
Reviewed by: Ronald S. Bultje <rbultje@ronald.bitfreak.net> Reviewed by: Ronald S. Bultje <rbultje@ronald.bitfreak.net>

View file

@ -376,6 +376,7 @@ GST_PLUGINS_ALL="\
cutter \ cutter \
debug \ debug \
deinterlace \ deinterlace \
dvdlpcmdec \
effectv \ effectv \
equalizer \ equalizer \
festival \ festival \
@ -1956,6 +1957,7 @@ gst/colorspace/Makefile
gst/cutter/Makefile gst/cutter/Makefile
gst/debug/Makefile gst/debug/Makefile
gst/deinterlace/Makefile gst/deinterlace/Makefile
gst/dvdlpcmdec/Makefile
gst/effectv/Makefile gst/effectv/Makefile
gst/equalizer/Makefile gst/equalizer/Makefile
gst/festival/Makefile gst/festival/Makefile

View file

@ -342,6 +342,7 @@ gst_mpeg2dec_reset (GstMpeg2dec * mpeg2dec)
mpeg2dec->segment_end = -1; mpeg2dec->segment_end = -1;
mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE; mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
mpeg2dec->frame_period = 0; mpeg2dec->frame_period = 0;
gst_pad_set_explicit_caps (mpeg2dec->srcpad, NULL);
gst_mpeg2dec_open_decoder (mpeg2dec); gst_mpeg2dec_open_decoder (mpeg2dec);
mpeg2dec->need_sequence = TRUE; mpeg2dec->need_sequence = TRUE;
} }
@ -774,7 +775,8 @@ handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
if (picture->flags & PIC_FLAG_SKIP) { if (picture->flags & PIC_FLAG_SKIP) {
GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer because of skip flag"); GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer because of skip flag");
gst_buffer_unref (outbuf); 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_DEBUG_OBJECT (mpeg2dec, "dropping buffer, pad not usable");
gst_buffer_unref (outbuf); gst_buffer_unref (outbuf);
} else if (mpeg2dec->discont_state != MPEG2DEC_DISC_NONE) { } 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) #if MPEG2_RELEASE >= MPEG2_VERSION (0, 4, 0)
case STATE_INVALID_END: case STATE_INVALID_END:
#endif #endif
// mpeg2dec->need_sequence = TRUE;
case STATE_SLICE: case STATE_SLICE:
if (info->discard_fbuf) { if (info->discard_fbuf) {
if (free_buffer (mpeg2dec, GST_BUFFER (info->discard_fbuf->id))) { if (free_buffer (mpeg2dec, GST_BUFFER (info->discard_fbuf->id))) {

7
gst/dvdlpcmdec/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs

View file

@ -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

View file

@ -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)

View file

@ -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__ */

View file

@ -82,13 +82,13 @@ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_STATIC_CAPS ( \ GST_STATIC_CAPS ( \
"audio/mpeg, " \ "audio/mpeg, " \
"mpegversion = (int) 1;" \ "mpegversion = (int) 1;" \
"audio/x-raw-int, " \ "audio/x-dvd-lpcm, " \
"endianness = (int) BIG_ENDIAN, " \ "width = (int) { 16, 20, 24 }, " \
"signed = (boolean) TRUE, " \
"width = (int) { 16, 24 }, " \
"depth = (int) { 16, 20, 24 }, " \
"rate = (int) { 48000, 96000 }, " \ "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-ac3;" \
"audio/x-dts" \ "audio/x-dts" \
) )
@ -96,7 +96,6 @@ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
#define SUBPICTURE_CAPS \ #define SUBPICTURE_CAPS \
GST_STATIC_CAPS ("video/x-dvd-subpicture") GST_STATIC_CAPS ("video/x-dvd-subpicture")
static GstStaticPadTemplate cur_video_template = static GstStaticPadTemplate cur_video_template =
GST_STATIC_PAD_TEMPLATE ("current_video", GST_STATIC_PAD_TEMPLATE ("current_video",
GST_PAD_SRC, 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 the next sequence time. We don't do it here to reduce the
time gap between the discontinuity and the subsequent data time gap between the discontinuity and the subsequent data
blocks. */ blocks. */
#if 1
dvd_demux->discont_time = start_ptm + mpeg_demux->adjust; 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, 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; 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); 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) if (GST_MPEG_PARSE_CLASS (parent_class)->handle_discont != NULL)
GST_MPEG_PARSE_CLASS (parent_class)->handle_discont (mpeg_parse, event); 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) guint8 stream_nr, gint type, const gpointer info)
{ {
GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_demux); GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_demux);
guint8 sample_info = 0; guint32 sample_info = 0;
GstMPEGStream *str; GstMPEGStream *str;
GstDVDLPCMStream *lpcm_str = NULL; GstDVDLPCMStream *lpcm_str = NULL;
GstCaps *caps;
gint width, rate, channels;
gboolean add_pad = FALSE; 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 (stream_nr < GST_MPEG_DEMUX_NUM_AUDIO_STREAMS, NULL);
g_return_val_if_fail (type > GST_MPEG_DEMUX_AUDIO_UNKNOWN && 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) { if (type == GST_DVD_DEMUX_AUDIO_LPCM) {
sample_info = *((guint8 *) info); sample_info = *((guint32 *) info);
} }
str = mpeg_demux->audio_stream[stream_nr]; str = mpeg_demux->audio_stream[stream_nr];
@ -597,15 +599,21 @@ gst_dvd_demux_get_audio_stream (GstMPEGDemux * mpeg_demux,
if (type != str->type || if (type != str->type ||
(type == GST_DVD_DEMUX_AUDIO_LPCM && (type == GST_DVD_DEMUX_AUDIO_LPCM &&
sample_info != lpcm_str->sample_info)) { sample_info != lpcm_str->sample_info)) {
gint width, rate, channels, dynamic_range;
gboolean emphasis, mute;
/* We need to set new caps for this pad. */ /* We need to set new caps for this pad. */
switch (type) { switch (type) {
case GST_DVD_DEMUX_AUDIO_LPCM: case GST_DVD_DEMUX_AUDIO_LPCM:
/* Dynamic range in the lower byte */
dynamic_range = sample_info & 0xff;
/* Determine the sample width. */ /* Determine the sample width. */
switch (sample_info & 0xC0) { switch (sample_info & 0xC000) {
case 0x80: case 0x8000:
width = 24; width = 24;
break; break;
case 0x40: case 0x4000:
width = 20; width = 20;
break; break;
default: default:
@ -614,27 +622,34 @@ gst_dvd_demux_get_audio_stream (GstMPEGDemux * mpeg_demux,
} }
/* Determine the rate. */ /* Determine the rate. */
if (sample_info & 0x10) { if (sample_info & 0x1000) {
rate = 96000; rate = 96000;
} else { } else {
rate = 48000; rate = 48000;
} }
mute = ((sample_info & 0x400000) != 0);
emphasis = ((sample_info & 0x800000) != 0);
/* Determine the number of channels. */ /* 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", caps = gst_caps_new_simple ("audio/x-dvd-lpcm",
"endianness", G_TYPE_INT, G_BIG_ENDIAN,
"signed", G_TYPE_BOOLEAN, TRUE,
"width", G_TYPE_INT, width, "width", G_TYPE_INT, width,
"depth", G_TYPE_INT, width, "rate", G_TYPE_INT, rate,
"rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL); "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->sample_info = sample_info;
lpcm_str->width = width; lpcm_str->width = width;
lpcm_str->rate = rate; lpcm_str->rate = rate;
lpcm_str->channels = channels; lpcm_str->channels = channels;
lpcm_str->dynamic_range = dynamic_range;
lpcm_str->mute = mute;
lpcm_str->emphasis = emphasis;
break; break;
case GST_DVD_DEMUX_AUDIO_AC3: case GST_DVD_DEMUX_AUDIO_AC3:
@ -718,7 +733,6 @@ gst_dvd_demux_get_subpicture_stream (GstMPEGDemux * mpeg_demux,
return str; return str;
} }
static void static void
gst_dvd_demux_process_private (GstMPEGDemux * mpeg_demux, gst_dvd_demux_process_private (GstMPEGDemux * mpeg_demux,
GstBuffer * buffer, GstBuffer * buffer,
@ -726,7 +740,7 @@ gst_dvd_demux_process_private (GstMPEGDemux * mpeg_demux,
{ {
GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_demux); GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_demux);
guint8 *basebuf; guint8 *basebuf;
guint8 ps_id_code, lpcm_sample_info; guint8 ps_id_code;
GstMPEGStream *outstream = NULL; GstMPEGStream *outstream = NULL;
guint first_access = 0; guint first_access = 0;
gint align = 1, len, off; 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 /* In the following, the "first access" refers to the location in a
buffer the time stamp is associated to. DVDs include this buffer the time stamp is associated to. DVDs include this
information explicitely. */ information explicitely. */
switch (stream_nr) { switch (stream_nr) {
case 0: case 0:
/* Private stream 1. */ /* Private stream 1. */
@ -752,31 +765,47 @@ gst_dvd_demux_process_private (GstMPEGDemux * mpeg_demux,
/* Determine the position of the "first access". This /* Determine the position of the "first access". This
should always be the beginning of an AC3 frame. */ should always be the beginning of an AC3 frame. */
first_access = *(basebuf + headerlen + 6) * 256 + first_access = (basebuf[headerlen + 6] << 8) | basebuf[headerlen + 7];
*(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; headerlen += 4;
datalen -= 4; datalen -= 4;
} else if (ps_id_code >= 0xA0 && ps_id_code <= 0xA7) { } else if (ps_id_code >= 0xA0 && ps_id_code <= 0xA7) {
GstDVDLPCMStream *lpcm_str; GstDVDLPCMStream *lpcm_str;
guint32 lpcm_sample_info;
GST_LOG_OBJECT (dvd_demux, GST_LOG_OBJECT (dvd_demux,
"we have an audio (LPCM) packet, track %d", ps_id_code - 0xA0); "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, outstream = DEMUX_CLASS (dvd_demux)->get_audio_stream (mpeg_demux,
ps_id_code - 0xA0, GST_DVD_DEMUX_AUDIO_LPCM, &lpcm_sample_info); ps_id_code - 0xA0, GST_DVD_DEMUX_AUDIO_LPCM, &lpcm_sample_info);
lpcm_str = (GstDVDLPCMStream *) outstream; lpcm_str = (GstDVDLPCMStream *) outstream;
/* Determine the position of the "first access". */ /* Determine the position of the "first access". */
first_access = *(basebuf + headerlen + 6) * 256 + first_access = (basebuf[headerlen + 6] << 8) | basebuf[headerlen + 7];
*(basebuf + headerlen + 7);
/* Get rid of the LPCM header. */ /* Get rid of the LPCM header. */
headerlen += 7; headerlen += 7;
datalen -= 7; datalen -= 7;
/* align by samples */ /* align by frame round up to nearest byte */
align = lpcm_str->width * lpcm_str->channels / 8; align = (lpcm_str->width * lpcm_str->channels + 7) / 8;
} else if (ps_id_code >= 0x20 && ps_id_code <= 0x3F) { } else if (ps_id_code >= 0x20 && ps_id_code <= 0x3F) {
GST_LOG_OBJECT (dvd_demux, GST_LOG_OBJECT (dvd_demux,
"we have a subpicture packet, track %d", ps_id_code - 0x20); "we have a subpicture packet, track %d", ps_id_code - 0x20);

View file

@ -77,12 +77,14 @@ enum {
streams. */ streams. */
struct _GstDVDLPCMStream { struct _GstDVDLPCMStream {
GstMPEGStream parent; GstMPEGStream parent;
guint8 sample_info; /* The type of linear PCM samples guint32 sample_info; /* The type of linear PCM samples
associated to this stream. The associated to this stream. The
values are bit fields with the same values are bit fields with the same
format of the sample_info field in format of the sample_info field in
the linear PCM header. */ the linear PCM header. */
gint rate, channels, width; gint rate, channels, width,
dynamic_range;
gboolean mute, emphasis;
}; };