diff --git a/ChangeLog b/ChangeLog index 0c010d04b2..b5b4744c65 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,45 @@ +2005-02-08 Jan Schmidt + + * 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 Reviewed by: Ronald S. Bultje diff --git a/configure.ac b/configure.ac index 70b349b8e3..870d269a65 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/ext/mpeg2dec/gstmpeg2dec.c b/ext/mpeg2dec/gstmpeg2dec.c index bb3863b683..c3163b22a8 100644 --- a/ext/mpeg2dec/gstmpeg2dec.c +++ b/ext/mpeg2dec/gstmpeg2dec.c @@ -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 index 0000000000..08f5ed37d8 --- /dev/null +++ b/gst/dvdlpcmdec/.gitignore @@ -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 index 0000000000..31e5116912 --- /dev/null +++ b/gst/dvdlpcmdec/Makefile.am @@ -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 index 0000000000..2062d14d49 --- /dev/null +++ b/gst/dvdlpcmdec/gstdvdlpcmdec.c @@ -0,0 +1,394 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) <2005> Jan Schmidt + * + * 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 +#include + +#include "gstdvdlpcmdec.h" +#include + +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 "); + +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 index 0000000000..099e70f6b3 --- /dev/null +++ b/gst/dvdlpcmdec/gstdvdlpcmdec.h @@ -0,0 +1,66 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) <2005> Jan Schmidt + * + * 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 + +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__ */ diff --git a/gst/mpegstream/gstdvddemux.c b/gst/mpegstream/gstdvddemux.c index c23d9dad99..5ca5236390 100644 --- a/gst/mpegstream/gstdvddemux.c +++ b/gst/mpegstream/gstdvddemux.c @@ -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); diff --git a/gst/mpegstream/gstdvddemux.h b/gst/mpegstream/gstdvddemux.h index dd9a876870..aa956310ab 100644 --- a/gst/mpegstream/gstdvddemux.h +++ b/gst/mpegstream/gstdvddemux.h @@ -77,12 +77,14 @@ enum { streams. */ struct _GstDVDLPCMStream { 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 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; };