mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
gst/mpegstream/gstmpegdemux.*: Complete overhaul. All DVD specific functionality split to the new dvddemux element.
Original commit message from CVS: * gst/mpegstream/gstmpegdemux.c: * gst/mpegstream/gstmpegdemux.h: Complete overhaul. All DVD specific functionality split to the new dvddemux element. * gst/mpegstream/gstdvddemux.c: * gst/mpegstream/gstdvddemux.h: New demultiplexer for DVD (VOB) streams, derived from mpegdemux. * gst/mpegstream/gstmpegparse.c: Discontinuity handling cleaned up. SCR based timestamp rewriting can be turned off (will probably completely disappear soon). * ext/dvdnav/dvdnavsrc.c: Changes resulting from a few months hacking. General cleanup. All printf statements replaced by debugging messages. Almost complete libdvdnav support. (dvdnavsrc_class_init): Got rid of unnecessary signals (replaced by events. New properties for audio and subpicture languages. (dvdnavsrc_update_highlight): Now uses events. (dvdnavsrc_user_op): Cleaned up. (dvdnavsrc_get): Renamed to dvdnavsrc_loop (element is now loop based). Lots of cleanup, and propper support for most libdvdnav events. (dvdnavsrc_make_dvd_event): New function. (dvdnavsrc_make_dvd_nav_packet_event): New function. (dvdnavsrc_make_clut_change_event): New function.
This commit is contained in:
parent
66c93a611a
commit
40b740126e
10 changed files with 2522 additions and 917 deletions
25
ChangeLog
25
ChangeLog
|
@ -1,3 +1,28 @@
|
||||||
|
2004-03-27 Martin Soto <martinsoto@users.sourceforge.net>
|
||||||
|
|
||||||
|
* gst/mpegstream/gstmpegdemux.c:
|
||||||
|
* gst/mpegstream/gstmpegdemux.h: Complete overhaul. All DVD
|
||||||
|
specific functionality split to the new dvddemux element.
|
||||||
|
* gst/mpegstream/gstdvddemux.c:
|
||||||
|
* gst/mpegstream/gstdvddemux.h: New demultiplexer for DVD (VOB)
|
||||||
|
streams, derived from mpegdemux.
|
||||||
|
* gst/mpegstream/gstmpegparse.c: Discontinuity handling cleaned
|
||||||
|
up. SCR based timestamp rewriting can be turned off (will probably
|
||||||
|
completely disappear soon).
|
||||||
|
* ext/dvdnav/dvdnavsrc.c: Changes resulting from a few months
|
||||||
|
hacking. General cleanup. All printf statements replaced by
|
||||||
|
debugging messages. Almost complete libdvdnav support.
|
||||||
|
(dvdnavsrc_class_init): Got rid of unnecessary signals (replaced
|
||||||
|
by events. New properties for audio and subpicture languages.
|
||||||
|
(dvdnavsrc_update_highlight): Now uses events.
|
||||||
|
(dvdnavsrc_user_op): Cleaned up.
|
||||||
|
(dvdnavsrc_get): Renamed to dvdnavsrc_loop (element is now loop
|
||||||
|
based). Lots of cleanup, and propper support for most libdvdnav
|
||||||
|
events.
|
||||||
|
(dvdnavsrc_make_dvd_event): New function.
|
||||||
|
(dvdnavsrc_make_dvd_nav_packet_event): New function.
|
||||||
|
(dvdnavsrc_make_clut_change_event): New function.
|
||||||
|
|
||||||
2004-03-26 Benjamin Otte <otte@gnome.org>
|
2004-03-26 Benjamin Otte <otte@gnome.org>
|
||||||
|
|
||||||
* gst/typefind/gsttypefindfunctions.c: (theora_type_find):
|
* gst/typefind/gsttypefindfunctions.c: (theora_type_find):
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,11 +1,22 @@
|
||||||
|
|
||||||
plugin_LTLIBRARIES = libgstmpegstream.la
|
plugin_LTLIBRARIES = libgstmpegstream.la
|
||||||
|
|
||||||
libgstmpegstream_la_SOURCES = gstmpegstream.c gstmpegparse.c gstmpegdemux.c gstmpegpacketize.c gstrfc2250enc.c gstmpegclock.c
|
libgstmpegstream_la_SOURCES = gstmpegstream.c \
|
||||||
|
gstmpegparse.c \
|
||||||
|
gstmpegdemux.c \
|
||||||
|
gstdvddemux.c \
|
||||||
|
gstmpegpacketize.c \
|
||||||
|
gstrfc2250enc.c \
|
||||||
|
gstmpegclock.c
|
||||||
libgstmpegstream_la_CFLAGS = $(GST_CFLAGS)
|
libgstmpegstream_la_CFLAGS = $(GST_CFLAGS)
|
||||||
libgstmpegstream_la_LIBADD =
|
libgstmpegstream_la_LIBADD =
|
||||||
libgstmpegstream_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
libgstmpegstream_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
|
|
||||||
noinst_HEADERS = gstmpegparse.h gstmpegdemux.h gstmpegpacketize.h gstrfc2250enc.h gstmpegclock.h
|
noinst_HEADERS = gstmpegparse.h \
|
||||||
|
gstmpegdemux.h \
|
||||||
|
gstdvddemux.h \
|
||||||
|
gstmpegpacketize.h \
|
||||||
|
gstrfc2250enc.h \
|
||||||
|
gstmpegclock.h
|
||||||
|
|
||||||
EXTRA_DIST = README notes
|
EXTRA_DIST = README notes
|
||||||
|
|
871
gst/mpegstream/gstdvddemux.c
Normal file
871
gst/mpegstream/gstdvddemux.c
Normal file
|
@ -0,0 +1,871 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2004 Martin Soto <martinsoto@users.sourceforge.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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <gstdvddemux.h>
|
||||||
|
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_STATIC (gstdvddemux_debug);
|
||||||
|
#define GST_CAT_DEFAULT (gstdvddemux_debug)
|
||||||
|
|
||||||
|
|
||||||
|
#define PARSE_CLASS(o) GST_MPEG_PARSE_CLASS (G_OBJECT_GET_CLASS (o))
|
||||||
|
#define DEMUX_CLASS(o) GST_MPEG_DEMUX_CLASS (G_OBJECT_GET_CLASS (o))
|
||||||
|
#define CLASS(o) GST_DVD_DEMUX_CLASS (G_OBJECT_GET_CLASS (o))
|
||||||
|
|
||||||
|
|
||||||
|
/* Element factory information */
|
||||||
|
static GstElementDetails dvd_demux_details = {
|
||||||
|
"DVD Demuxer",
|
||||||
|
"Codec/Demuxer",
|
||||||
|
"Demultiplexes DVD (VOB) MPEG2 streams",
|
||||||
|
"Martin Soto <soto@informatik.uni-kl.de>"
|
||||||
|
};
|
||||||
|
|
||||||
|
/* DVDDemux signals and args */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
/* FILL ME */
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ARG_0,
|
||||||
|
/* FILL ME */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Define the capabilities separately, to be able to reuse them. */
|
||||||
|
|
||||||
|
#define VIDEO_CAPS \
|
||||||
|
GST_STATIC_CAPS ("video/mpeg, " \
|
||||||
|
"mpegversion = (int) { 1, 2 }, " \
|
||||||
|
"systemstream = (boolean) FALSE" \
|
||||||
|
)
|
||||||
|
|
||||||
|
#define AUDIO_CAPS \
|
||||||
|
GST_STATIC_CAPS ( \
|
||||||
|
"audio/mpeg, " \
|
||||||
|
"mpegversion = (int) 1;" \
|
||||||
|
"audio/x-raw-int, " \
|
||||||
|
"endianness = (int) BIG_ENDIAN, " \
|
||||||
|
"signed = (boolean) TRUE, " \
|
||||||
|
"width = (int) { 16, 20, 24 }, " \
|
||||||
|
"depth = (int) { 16, 20, 24 }, " \
|
||||||
|
"rate = (int) { 48000, 96000 }, " \
|
||||||
|
"channels = (int) [ 1, 8 ];" \
|
||||||
|
"audio/x-ac3" \
|
||||||
|
)
|
||||||
|
|
||||||
|
#define SUBPICTURE_CAPS \
|
||||||
|
GST_STATIC_CAPS ("video/x-dvd-subpicture")
|
||||||
|
|
||||||
|
|
||||||
|
static GstStaticPadTemplate cur_video_template =
|
||||||
|
GST_STATIC_PAD_TEMPLATE ("current_video",
|
||||||
|
GST_PAD_SRC,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
VIDEO_CAPS);
|
||||||
|
|
||||||
|
static GstStaticPadTemplate audio_template =
|
||||||
|
GST_STATIC_PAD_TEMPLATE ("dvd_audio_%02d",
|
||||||
|
GST_PAD_SRC,
|
||||||
|
GST_PAD_SOMETIMES,
|
||||||
|
AUDIO_CAPS);
|
||||||
|
|
||||||
|
static GstStaticPadTemplate cur_audio_template =
|
||||||
|
GST_STATIC_PAD_TEMPLATE ("current_audio",
|
||||||
|
GST_PAD_SRC,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
AUDIO_CAPS);
|
||||||
|
|
||||||
|
static GstStaticPadTemplate subpicture_template =
|
||||||
|
GST_STATIC_PAD_TEMPLATE ("subpicture_%d",
|
||||||
|
GST_PAD_SRC,
|
||||||
|
GST_PAD_SOMETIMES,
|
||||||
|
SUBPICTURE_CAPS);
|
||||||
|
|
||||||
|
static GstStaticPadTemplate cur_subpicture_template =
|
||||||
|
GST_STATIC_PAD_TEMPLATE ("current_subpicture",
|
||||||
|
GST_PAD_SRC,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
SUBPICTURE_CAPS);
|
||||||
|
|
||||||
|
|
||||||
|
static void gst_dvd_demux_class_init (GstDVDDemuxClass * klass);
|
||||||
|
static void gst_dvd_demux_base_init (GstDVDDemuxClass * klass);
|
||||||
|
static void gst_dvd_demux_init (GstDVDDemux * dvd_demux);
|
||||||
|
|
||||||
|
static void gst_dvd_demux_send_data (GstMPEGParse * mpeg_parse,
|
||||||
|
GstData * data, GstClockTime time);
|
||||||
|
|
||||||
|
static void gst_dvd_demux_send_discont
|
||||||
|
(GstMPEGParse * mpeg_parse, GstClockTime time);
|
||||||
|
static gboolean gst_dvd_demux_handle_dvd_event
|
||||||
|
(GstDVDDemux * dvd_demux, GstEvent * event);
|
||||||
|
|
||||||
|
static GstMPEGStream *gst_dvd_demux_get_audio_stream
|
||||||
|
(GstMPEGDemux * dvd_demux,
|
||||||
|
guint8 stream_nr, gint type, const gpointer info);
|
||||||
|
static GstMPEGStream *gst_dvd_demux_get_subpicture_stream
|
||||||
|
(GstMPEGDemux * dvd_demux,
|
||||||
|
guint8 stream_nr, gint type, const gpointer info);
|
||||||
|
|
||||||
|
static void gst_dvd_demux_process_private
|
||||||
|
(GstMPEGDemux * mpeg_demux,
|
||||||
|
GstBuffer * buffer,
|
||||||
|
guint stream_nr, GstClockTime timestamp, guint headerlen, guint datalen);
|
||||||
|
|
||||||
|
static void gst_dvd_demux_send_subbuffer
|
||||||
|
(GstMPEGDemux * mpeg_demux,
|
||||||
|
GstMPEGStream * outstream,
|
||||||
|
GstBuffer * buffer, GstClockTime timestamp, guint offset, guint size);
|
||||||
|
|
||||||
|
static void gst_dvd_demux_set_cur_audio
|
||||||
|
(GstDVDDemux * dvd_demux, gint stream_nr);
|
||||||
|
static void gst_dvd_demux_set_cur_subpicture
|
||||||
|
(GstDVDDemux * dvd_demux, gint stream_nr);
|
||||||
|
|
||||||
|
|
||||||
|
static GstMPEGDemuxClass *parent_class = NULL;
|
||||||
|
|
||||||
|
/*static guint gst_dvd_demux_signals[LAST_SIGNAL] = { 0 };*/
|
||||||
|
|
||||||
|
|
||||||
|
GType
|
||||||
|
gst_dvd_demux_get_type (void)
|
||||||
|
{
|
||||||
|
static GType dvd_demux_type = 0;
|
||||||
|
|
||||||
|
if (!dvd_demux_type) {
|
||||||
|
static const GTypeInfo dvd_demux_info = {
|
||||||
|
sizeof (GstDVDDemuxClass),
|
||||||
|
(GBaseInitFunc) gst_dvd_demux_base_init,
|
||||||
|
NULL,
|
||||||
|
(GClassInitFunc) gst_dvd_demux_class_init,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
sizeof (GstDVDDemux),
|
||||||
|
0,
|
||||||
|
(GInstanceInitFunc) gst_dvd_demux_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
dvd_demux_type = g_type_register_static (GST_TYPE_MPEG_DEMUX,
|
||||||
|
"GstDVDDemux", &dvd_demux_info, 0);
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gstdvddemux_debug, "dvddemux", 0,
|
||||||
|
"DVD (VOB) demultiplexer element");
|
||||||
|
}
|
||||||
|
|
||||||
|
return dvd_demux_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_dvd_demux_base_init (GstDVDDemuxClass * klass)
|
||||||
|
{
|
||||||
|
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||||
|
GstMPEGDemuxClass *demux_class = GST_MPEG_DEMUX_CLASS (klass);
|
||||||
|
GstMPEGParseClass *mpeg_parse_class = (GstMPEGParseClass *) klass;
|
||||||
|
|
||||||
|
mpeg_parse_class->send_data = gst_dvd_demux_send_data;
|
||||||
|
|
||||||
|
demux_class->audio_template = gst_static_pad_template_get (&audio_template);
|
||||||
|
|
||||||
|
klass->cur_video_template = gst_static_pad_template_get (&cur_video_template);
|
||||||
|
klass->cur_audio_template = gst_static_pad_template_get (&cur_audio_template);
|
||||||
|
klass->subpicture_template =
|
||||||
|
gst_static_pad_template_get (&subpicture_template);
|
||||||
|
klass->cur_subpicture_template =
|
||||||
|
gst_static_pad_template_get (&cur_subpicture_template);
|
||||||
|
|
||||||
|
gst_element_class_add_pad_template (element_class,
|
||||||
|
demux_class->audio_template);
|
||||||
|
|
||||||
|
gst_element_class_add_pad_template (element_class, klass->cur_video_template);
|
||||||
|
gst_element_class_add_pad_template (element_class, klass->cur_audio_template);
|
||||||
|
gst_element_class_add_pad_template (element_class,
|
||||||
|
klass->subpicture_template);
|
||||||
|
gst_element_class_add_pad_template (element_class,
|
||||||
|
klass->cur_subpicture_template);
|
||||||
|
|
||||||
|
gst_element_class_set_details (element_class, &dvd_demux_details);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_dvd_demux_class_init (GstDVDDemuxClass * klass)
|
||||||
|
{
|
||||||
|
GstElementClass *gstelement_class;
|
||||||
|
GstMPEGParseClass *mpeg_parse_class;
|
||||||
|
GstMPEGDemuxClass *mpeg_demux_class;
|
||||||
|
|
||||||
|
parent_class = g_type_class_ref (GST_TYPE_MPEG_DEMUX);
|
||||||
|
|
||||||
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
mpeg_parse_class = (GstMPEGParseClass *) klass;
|
||||||
|
mpeg_demux_class = (GstMPEGDemuxClass *) klass;
|
||||||
|
|
||||||
|
mpeg_parse_class->send_discont = gst_dvd_demux_send_discont;
|
||||||
|
|
||||||
|
mpeg_demux_class->get_audio_stream = gst_dvd_demux_get_audio_stream;
|
||||||
|
mpeg_demux_class->send_subbuffer = gst_dvd_demux_send_subbuffer;
|
||||||
|
mpeg_demux_class->process_private = gst_dvd_demux_process_private;
|
||||||
|
|
||||||
|
klass->get_subpicture_stream = gst_dvd_demux_get_subpicture_stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_dvd_demux_init (GstDVDDemux * dvd_demux)
|
||||||
|
{
|
||||||
|
GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (dvd_demux);
|
||||||
|
GstMPEGParse *mpeg_parse = GST_MPEG_PARSE (dvd_demux);
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
GST_FLAG_SET (dvd_demux, GST_ELEMENT_EVENT_AWARE);
|
||||||
|
|
||||||
|
/* Create the pads for the current streams. */
|
||||||
|
dvd_demux->cur_video =
|
||||||
|
DEMUX_CLASS (dvd_demux)->new_output_pad (mpeg_demux, "current_video",
|
||||||
|
CLASS (dvd_demux)->cur_video_template);
|
||||||
|
dvd_demux->cur_audio =
|
||||||
|
DEMUX_CLASS (dvd_demux)->new_output_pad (mpeg_demux, "current_audio",
|
||||||
|
CLASS (dvd_demux)->cur_audio_template);
|
||||||
|
dvd_demux->cur_subpicture =
|
||||||
|
DEMUX_CLASS (dvd_demux)->new_output_pad (mpeg_demux, "current_subpicture",
|
||||||
|
CLASS (dvd_demux)->cur_subpicture_template);
|
||||||
|
|
||||||
|
dvd_demux->cur_video_nr = 0;
|
||||||
|
dvd_demux->cur_audio_nr = 0;
|
||||||
|
dvd_demux->cur_subpicture_nr = 0;
|
||||||
|
|
||||||
|
/* Start the timestamp sequence in 0. */
|
||||||
|
dvd_demux->last_end_ptm = 0;
|
||||||
|
|
||||||
|
/* Try to prevent the mpegparse infrastructure from doing timestamp
|
||||||
|
adjustment. */
|
||||||
|
mpeg_parse->do_adjust = FALSE;
|
||||||
|
mpeg_parse->adjust = 0;
|
||||||
|
|
||||||
|
dvd_demux->just_flushed = FALSE;
|
||||||
|
dvd_demux->discont_time = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
|
for (i = 0; i < GST_DVD_DEMUX_NUM_SUBPICTURE_STREAMS; i++) {
|
||||||
|
dvd_demux->subpicture_stream[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_dvd_demux_send_data (GstMPEGParse * mpeg_parse, GstData * data,
|
||||||
|
GstClockTime time)
|
||||||
|
{
|
||||||
|
GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_parse);
|
||||||
|
|
||||||
|
if (GST_IS_BUFFER (data)) {
|
||||||
|
gst_buffer_unref (GST_BUFFER (data));
|
||||||
|
} else {
|
||||||
|
GstEvent *event = GST_EVENT (data);
|
||||||
|
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_ANY:
|
||||||
|
gst_dvd_demux_handle_dvd_event (dvd_demux, event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_EVENT_FLUSH:
|
||||||
|
GST_DEBUG_OBJECT (dvd_demux, "flush received");
|
||||||
|
|
||||||
|
dvd_demux->just_flushed = TRUE;
|
||||||
|
|
||||||
|
/* Propagate the event normally. */
|
||||||
|
gst_pad_event_default (mpeg_parse->sinkpad, event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
gst_pad_event_default (mpeg_parse->sinkpad, event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_dvd_demux_handle_dvd_event (GstDVDDemux * dvd_demux, GstEvent * event)
|
||||||
|
{
|
||||||
|
GstMPEGParse *mpeg_parse = GST_MPEG_PARSE (dvd_demux);
|
||||||
|
GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (dvd_demux);
|
||||||
|
GstStructure *structure = event->event_data.structure.structure;
|
||||||
|
const char *event_type = gst_structure_get_string (structure, "event");
|
||||||
|
|
||||||
|
g_return_val_if_fail (event != NULL, FALSE);
|
||||||
|
|
||||||
|
#ifndef GST_DISABLE_GST_DEBUG
|
||||||
|
{
|
||||||
|
gchar *text = gst_structure_to_string (structure);
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (dvd_demux, "processing event \"%s\"", text);
|
||||||
|
g_free (text);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (strcmp (event_type, "dvd-audio-stream-change") == 0) {
|
||||||
|
gint stream_nr;
|
||||||
|
|
||||||
|
gst_structure_get_int (structure, "physical", &stream_nr);
|
||||||
|
if (stream_nr < -1 || stream_nr >= GST_MPEG_DEMUX_NUM_AUDIO_STREAMS) {
|
||||||
|
GST_ERROR_OBJECT (dvd_demux,
|
||||||
|
"GstDVDDemux: Invalid audio stream %02d", stream_nr);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
gst_dvd_demux_set_cur_audio (dvd_demux, stream_nr);
|
||||||
|
gst_event_unref (event);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (strcmp (event_type, "dvd-spu-stream-change") == 0) {
|
||||||
|
gint stream_nr;
|
||||||
|
|
||||||
|
gst_structure_get_int (structure, "physical", &stream_nr);
|
||||||
|
if (stream_nr < -1 || stream_nr >= GST_DVD_DEMUX_NUM_SUBPICTURE_STREAMS) {
|
||||||
|
GST_ERROR_OBJECT (dvd_demux,
|
||||||
|
"GstDVDDemux: Invalid subpicture stream %02d", stream_nr);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
gst_dvd_demux_set_cur_subpicture (dvd_demux, stream_nr);
|
||||||
|
gst_event_unref (event);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (strcmp (event_type, "dvd-nav-packet") == 0) {
|
||||||
|
GstStructure *structure = event->event_data.structure.structure;
|
||||||
|
GstClockTime start_ptm =
|
||||||
|
g_value_get_uint64 (gst_structure_get_value (structure, "start_ptm"));
|
||||||
|
GstClockTime end_ptm =
|
||||||
|
g_value_get_uint64 (gst_structure_get_value (structure, "end_ptm"));
|
||||||
|
|
||||||
|
if (start_ptm != dvd_demux->last_end_ptm) {
|
||||||
|
/* Set the adjust value to gap the discontinuity. */
|
||||||
|
mpeg_demux->adjust += GST_CLOCK_DIFF (dvd_demux->last_end_ptm, start_ptm);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dvd_demux,
|
||||||
|
"PTM sequence discontinuity: from %0.3fs to "
|
||||||
|
"%0.3fs, new adjust %0.3fs",
|
||||||
|
(double) dvd_demux->last_end_ptm / GST_SECOND,
|
||||||
|
(double) start_ptm / GST_SECOND,
|
||||||
|
(double) mpeg_demux->adjust / GST_SECOND);
|
||||||
|
}
|
||||||
|
dvd_demux->last_end_ptm = end_ptm;
|
||||||
|
|
||||||
|
if (dvd_demux->just_flushed) {
|
||||||
|
/* The pipeline was just flushed, schedule a discontinuity with
|
||||||
|
the next sequence time. We don't do it here to reduce the
|
||||||
|
time gap between the discontinuity and the subsequent data
|
||||||
|
blocks. */
|
||||||
|
dvd_demux->discont_time = start_ptm + mpeg_demux->adjust;
|
||||||
|
dvd_demux->just_flushed = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_event_unref (event);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
if (GST_EVENT_TIMESTAMP (event) != GST_CLOCK_TIME_NONE) {
|
||||||
|
GST_EVENT_TIMESTAMP (event) += mpeg_demux->adjust;
|
||||||
|
}
|
||||||
|
gst_pad_event_default (mpeg_parse->sinkpad, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_dvd_demux_send_discont (GstMPEGParse * mpeg_parse, GstClockTime time)
|
||||||
|
{
|
||||||
|
GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_parse);
|
||||||
|
GstEvent *discont;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dvd_demux, "sending discontinuity: %0.3fs",
|
||||||
|
(double) time / GST_SECOND);
|
||||||
|
|
||||||
|
GST_MPEG_PARSE_CLASS (parent_class)->send_discont (mpeg_parse, time);
|
||||||
|
|
||||||
|
for (i = 0; i < GST_DVD_DEMUX_NUM_SUBPICTURE_STREAMS; i++) {
|
||||||
|
if (dvd_demux->subpicture_stream[i] &&
|
||||||
|
GST_PAD_IS_USABLE (dvd_demux->subpicture_stream[i]->pad)) {
|
||||||
|
discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
|
||||||
|
time, NULL);
|
||||||
|
|
||||||
|
gst_pad_push (dvd_demux->subpicture_stream[i]->pad, GST_DATA (discont));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Distribute the event to the "current" pads. */
|
||||||
|
if (GST_PAD_IS_USABLE (dvd_demux->cur_video)) {
|
||||||
|
discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time, NULL);
|
||||||
|
|
||||||
|
gst_pad_push (dvd_demux->cur_video, GST_DATA (discont));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GST_PAD_IS_USABLE (dvd_demux->cur_audio)) {
|
||||||
|
discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time, NULL);
|
||||||
|
|
||||||
|
gst_pad_push (dvd_demux->cur_audio, GST_DATA (discont));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GST_PAD_IS_USABLE (dvd_demux->cur_subpicture)) {
|
||||||
|
discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time, NULL);
|
||||||
|
|
||||||
|
gst_pad_push (dvd_demux->cur_subpicture, GST_DATA (discont));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static GstMPEGStream *
|
||||||
|
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;
|
||||||
|
GstMPEGStream *str;
|
||||||
|
GstDVDLPCMStream *lpcm_str = NULL;
|
||||||
|
gchar *name;
|
||||||
|
GstCaps *caps;
|
||||||
|
gint width, rate, channels;
|
||||||
|
|
||||||
|
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 &&
|
||||||
|
type < GST_DVD_DEMUX_AUDIO_LAST, NULL);
|
||||||
|
|
||||||
|
if (type < GST_MPEG_DEMUX_AUDIO_LAST) {
|
||||||
|
return parent_class->get_audio_stream (mpeg_demux, stream_nr, type, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == GST_DVD_DEMUX_AUDIO_LPCM) {
|
||||||
|
sample_info = *((guint8 *) info);
|
||||||
|
}
|
||||||
|
|
||||||
|
str = mpeg_demux->audio_stream[stream_nr];
|
||||||
|
|
||||||
|
if (str == NULL) {
|
||||||
|
if (type != GST_DVD_DEMUX_AUDIO_LPCM) {
|
||||||
|
str = g_new0 (GstMPEGStream, 1);
|
||||||
|
} else {
|
||||||
|
lpcm_str = g_new0 (GstDVDLPCMStream, 1);
|
||||||
|
str = (GstMPEGStream *) lpcm_str;
|
||||||
|
}
|
||||||
|
str->type = GST_MPEG_DEMUX_AUDIO_UNKNOWN;
|
||||||
|
|
||||||
|
name = g_strdup_printf ("audio_%02d", stream_nr);
|
||||||
|
DEMUX_CLASS (dvd_demux)->init_stream (mpeg_demux, type, str, stream_nr,
|
||||||
|
name, DEMUX_CLASS (dvd_demux)->audio_template);
|
||||||
|
g_free (name);
|
||||||
|
|
||||||
|
mpeg_demux->audio_stream[stream_nr] = str;
|
||||||
|
} else {
|
||||||
|
/* This stream may have been created by a derived class, reset the
|
||||||
|
size. */
|
||||||
|
if (type != GST_DVD_DEMUX_AUDIO_LPCM) {
|
||||||
|
str = g_renew (GstMPEGStream, str, 1);
|
||||||
|
} else {
|
||||||
|
lpcm_str = g_renew (GstDVDLPCMStream, str, 1);
|
||||||
|
str = (GstMPEGStream *) lpcm_str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != str->type ||
|
||||||
|
(type == GST_DVD_DEMUX_AUDIO_LPCM &&
|
||||||
|
sample_info != lpcm_str->sample_info)) {
|
||||||
|
/* We need to set new caps for this pad. */
|
||||||
|
switch (type) {
|
||||||
|
case GST_DVD_DEMUX_AUDIO_LPCM:
|
||||||
|
/* Determine the sample width. */
|
||||||
|
switch (sample_info & 0xC0) {
|
||||||
|
case 0x80:
|
||||||
|
width = 24;
|
||||||
|
break;
|
||||||
|
case 0x40:
|
||||||
|
width = 20;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
width = 16;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine the rate. */
|
||||||
|
if (sample_info & 0x10) {
|
||||||
|
rate = 96000;
|
||||||
|
} else {
|
||||||
|
rate = 48000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine the number of channels. */
|
||||||
|
channels = (sample_info & 0x7) + 1;
|
||||||
|
|
||||||
|
caps = gst_caps_new_simple ("audio/x-raw-int",
|
||||||
|
"endianness", G_TYPE_INT, G_BIG_ENDIAN,
|
||||||
|
"signed", G_TYPE_BOOLEAN, TRUE,
|
||||||
|
"width", G_TYPE_INT, width,
|
||||||
|
"depth", G_TYPE_INT, width,
|
||||||
|
"rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
lpcm_str->sample_info = sample_info;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_DVD_DEMUX_AUDIO_AC3:
|
||||||
|
caps = gst_caps_new_simple ("audio/x-ac3", NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_DVD_DEMUX_AUDIO_DTS:
|
||||||
|
caps = gst_caps_new_simple ("audio/x-dts", NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_return_val_if_reached (NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_pad_set_explicit_caps (str->pad, caps);
|
||||||
|
|
||||||
|
if (str->number == dvd_demux->cur_audio_nr) {
|
||||||
|
/* This is the current audio stream. Use the same caps. */
|
||||||
|
gst_pad_set_explicit_caps (dvd_demux->cur_audio, gst_caps_copy (caps));
|
||||||
|
}
|
||||||
|
|
||||||
|
str->type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static GstMPEGStream *
|
||||||
|
gst_dvd_demux_get_subpicture_stream (GstMPEGDemux * mpeg_demux,
|
||||||
|
guint8 stream_nr, gint type, const gpointer info)
|
||||||
|
{
|
||||||
|
GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_demux);
|
||||||
|
GstMPEGStream *str;
|
||||||
|
gchar *name;
|
||||||
|
GstCaps *caps;
|
||||||
|
|
||||||
|
g_return_val_if_fail (stream_nr < GST_DVD_DEMUX_NUM_SUBPICTURE_STREAMS, NULL);
|
||||||
|
g_return_val_if_fail (type > GST_DVD_DEMUX_SUBP_UNKNOWN &&
|
||||||
|
type < GST_DVD_DEMUX_SUBP_LAST, NULL);
|
||||||
|
|
||||||
|
str = dvd_demux->subpicture_stream[stream_nr];
|
||||||
|
|
||||||
|
if (str == NULL) {
|
||||||
|
str = g_new0 (GstMPEGStream, 1);
|
||||||
|
str->type = GST_DVD_DEMUX_SUBP_UNKNOWN;
|
||||||
|
|
||||||
|
name = g_strdup_printf ("subpicture_%02d", stream_nr);
|
||||||
|
DEMUX_CLASS (dvd_demux)->init_stream (mpeg_demux, type, str, stream_nr,
|
||||||
|
name, CLASS (dvd_demux)->subpicture_template);
|
||||||
|
g_free (name);
|
||||||
|
|
||||||
|
dvd_demux->subpicture_stream[stream_nr] = str;
|
||||||
|
} else {
|
||||||
|
/* This stream may have been created by a derived class, reset the
|
||||||
|
size. */
|
||||||
|
str = g_renew (GstMPEGStream, str, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str->type != GST_DVD_DEMUX_SUBP_DVD) {
|
||||||
|
/* We need to set new caps for this pad. */
|
||||||
|
caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
|
||||||
|
gst_pad_set_explicit_caps (str->pad, caps);
|
||||||
|
|
||||||
|
if (str->number == dvd_demux->cur_subpicture_nr) {
|
||||||
|
/* This is the current subpicture stream. Use the same caps. */
|
||||||
|
gst_pad_set_explicit_caps (dvd_demux->cur_subpicture,
|
||||||
|
gst_caps_copy (caps));
|
||||||
|
}
|
||||||
|
|
||||||
|
str->type = GST_DVD_DEMUX_SUBP_DVD;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_dvd_demux_process_private (GstMPEGDemux * mpeg_demux,
|
||||||
|
GstBuffer * buffer,
|
||||||
|
guint stream_nr, GstClockTime timestamp, guint headerlen, guint datalen)
|
||||||
|
{
|
||||||
|
GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_demux);
|
||||||
|
guint8 *basebuf;
|
||||||
|
guint8 ps_id_code, lpcm_sample_info;
|
||||||
|
GstMPEGStream *outstream = NULL;
|
||||||
|
guint first_access = 0;
|
||||||
|
|
||||||
|
basebuf = GST_BUFFER_DATA (buffer);
|
||||||
|
|
||||||
|
/* Determine the substream number. */
|
||||||
|
ps_id_code = basebuf[headerlen + 4];
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
|
||||||
|
switch (ps_id_code) {
|
||||||
|
case 0x80...0x87:
|
||||||
|
GST_LOG_OBJECT (dvd_demux,
|
||||||
|
"we have an audio (AC3) packet, track %d", ps_id_code - 0x80);
|
||||||
|
outstream = DEMUX_CLASS (dvd_demux)->get_audio_stream (mpeg_demux,
|
||||||
|
ps_id_code - 0x80, GST_DVD_DEMUX_AUDIO_AC3, NULL);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
headerlen += 4;
|
||||||
|
datalen -= 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xA0...0xA7:
|
||||||
|
GST_LOG_OBJECT (dvd_demux,
|
||||||
|
"we have an audio (LPCM) packet, track %d", ps_id_code - 0xA0);
|
||||||
|
lpcm_sample_info = basebuf[headerlen + 9];
|
||||||
|
outstream = DEMUX_CLASS (dvd_demux)->get_audio_stream (mpeg_demux,
|
||||||
|
ps_id_code - 0xA0, GST_DVD_DEMUX_AUDIO_LPCM, &lpcm_sample_info);
|
||||||
|
|
||||||
|
/* Determine the position of the "first access". */
|
||||||
|
first_access = *(basebuf + headerlen + 6) * 256 +
|
||||||
|
*(basebuf + headerlen + 7);
|
||||||
|
|
||||||
|
/* Get rid of the LPCM header. */
|
||||||
|
headerlen += 7;
|
||||||
|
datalen -= 7;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x20...0x3f:
|
||||||
|
GST_LOG_OBJECT (dvd_demux,
|
||||||
|
"we have a subpicture packet, track %d", ps_id_code - 0x20);
|
||||||
|
outstream = CLASS (dvd_demux)->get_subpicture_stream (mpeg_demux,
|
||||||
|
ps_id_code - 0x20, GST_DVD_DEMUX_SUBP_DVD, NULL);
|
||||||
|
|
||||||
|
headerlen += 1;
|
||||||
|
datalen -= 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
GST_ERROR_OBJECT (dvd_demux,
|
||||||
|
"unknown DVD (private 1) id 0x%02x", ps_id_code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
/* Private stream 2 */
|
||||||
|
|
||||||
|
switch (ps_id_code) {
|
||||||
|
case 0:
|
||||||
|
GST_LOG_OBJECT (dvd_demux, "we have a PCI nav packet");
|
||||||
|
|
||||||
|
outstream = DEMUX_CLASS (mpeg_demux)->get_private_stream (mpeg_demux,
|
||||||
|
1, GST_MPEG_DEMUX_PRIVATE_UNKNOWN, NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
GST_LOG_OBJECT (dvd_demux, "we have a DSI nav packet");
|
||||||
|
|
||||||
|
outstream = DEMUX_CLASS (mpeg_demux)->get_private_stream (mpeg_demux,
|
||||||
|
1, GST_MPEG_DEMUX_PRIVATE_UNKNOWN, NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
GST_ERROR_OBJECT (dvd_demux,
|
||||||
|
"unknown DVD (private 1) id 0x%02x", ps_id_code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_return_if_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outstream == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timestamp != GST_CLOCK_TIME_NONE && first_access > 1) {
|
||||||
|
/* We have a first access location. Since GStreamer doesn't have
|
||||||
|
a means to associate a timestamp to the middle of a buffer, we
|
||||||
|
send two separate buffers and put the timestamp in the second
|
||||||
|
one. */
|
||||||
|
DEMUX_CLASS (dvd_demux)->send_subbuffer (mpeg_demux, outstream,
|
||||||
|
buffer, GST_CLOCK_TIME_NONE, headerlen + 4, first_access - 1);
|
||||||
|
DEMUX_CLASS (dvd_demux)->send_subbuffer (mpeg_demux, outstream,
|
||||||
|
buffer, timestamp,
|
||||||
|
headerlen + 3 + first_access, datalen - (first_access - 1));
|
||||||
|
} else {
|
||||||
|
DEMUX_CLASS (dvd_demux)->send_subbuffer (mpeg_demux, outstream,
|
||||||
|
buffer, timestamp, headerlen + 4, datalen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_dvd_demux_send_subbuffer (GstMPEGDemux * mpeg_demux,
|
||||||
|
GstMPEGStream * outstream, GstBuffer * buffer,
|
||||||
|
GstClockTime timestamp, guint offset, guint size)
|
||||||
|
{
|
||||||
|
GstMPEGParse *mpeg_parse = GST_MPEG_PARSE (mpeg_demux);
|
||||||
|
GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_demux);
|
||||||
|
GstPad *outpad;
|
||||||
|
gint cur_nr;
|
||||||
|
|
||||||
|
/* If there's a pending discontinuity, send it now. The idea is to
|
||||||
|
minimize the time interval between the discontinuity and the data
|
||||||
|
buffers following it. */
|
||||||
|
if (dvd_demux->discont_time != GST_CLOCK_TIME_NONE) {
|
||||||
|
PARSE_CLASS (mpeg_demux)->send_discont (mpeg_parse,
|
||||||
|
dvd_demux->discont_time - 200 * GST_MSECOND);
|
||||||
|
dvd_demux->discont_time = GST_CLOCK_TIME_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* You never know what happens to a buffer when you send it. Just
|
||||||
|
in case, we keep a reference to the buffer during the execution
|
||||||
|
of this function. */
|
||||||
|
gst_buffer_ref (buffer);
|
||||||
|
|
||||||
|
/* Send the buffer to the standard output pad. */
|
||||||
|
parent_class->send_subbuffer (mpeg_demux, outstream, buffer,
|
||||||
|
timestamp, offset, size);
|
||||||
|
|
||||||
|
/* Determine the current output pad and stream number for the given
|
||||||
|
type of stream. */
|
||||||
|
switch (GST_MPEG_DEMUX_STREAM_KIND (outstream->type)) {
|
||||||
|
case GST_MPEG_DEMUX_STREAM_VIDEO:
|
||||||
|
outpad = dvd_demux->cur_video;
|
||||||
|
cur_nr = dvd_demux->cur_video_nr;
|
||||||
|
break;
|
||||||
|
case GST_MPEG_DEMUX_STREAM_AUDIO:
|
||||||
|
outpad = dvd_demux->cur_audio;
|
||||||
|
cur_nr = dvd_demux->cur_audio_nr;
|
||||||
|
break;
|
||||||
|
case GST_MPEG_DEMUX_STREAM_PRIVATE:
|
||||||
|
outpad = NULL;
|
||||||
|
cur_nr = 0;
|
||||||
|
break;
|
||||||
|
case GST_DVD_DEMUX_STREAM_SUBPICTURE:
|
||||||
|
outpad = dvd_demux->cur_subpicture;
|
||||||
|
cur_nr = dvd_demux->cur_subpicture_nr;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_return_if_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outpad != NULL && cur_nr == outstream->number) {
|
||||||
|
GstBuffer *outbuf;
|
||||||
|
|
||||||
|
/* We have a packet of the current stream. Send it to the
|
||||||
|
corresponding pad as well. */
|
||||||
|
outbuf = gst_buffer_create_sub (buffer, offset, size);
|
||||||
|
|
||||||
|
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
|
||||||
|
GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buffer) + offset;
|
||||||
|
|
||||||
|
gst_pad_push (outpad, GST_DATA (outbuf));
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_dvd_demux_set_cur_audio (GstDVDDemux * dvd_demux, gint stream_nr)
|
||||||
|
{
|
||||||
|
GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (dvd_demux);
|
||||||
|
GstMPEGStream *str;
|
||||||
|
const GstCaps *caps;
|
||||||
|
|
||||||
|
g_return_if_fail (stream_nr >= -1 &&
|
||||||
|
stream_nr < GST_MPEG_DEMUX_NUM_AUDIO_STREAMS);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dvd_demux, "changing current audio to %02d", stream_nr);
|
||||||
|
|
||||||
|
dvd_demux->cur_audio_nr = stream_nr;
|
||||||
|
|
||||||
|
if (stream_nr == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = mpeg_demux->audio_stream[stream_nr];
|
||||||
|
if (str != NULL) {
|
||||||
|
/* (Re)set the caps in the "current" pad. */
|
||||||
|
caps = gst_pad_get_negotiated_caps (str->pad);
|
||||||
|
if (caps != NULL) {
|
||||||
|
gst_pad_set_explicit_caps (dvd_demux->cur_audio, caps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_dvd_demux_set_cur_subpicture (GstDVDDemux * dvd_demux, gint stream_nr)
|
||||||
|
{
|
||||||
|
GstMPEGStream *str;
|
||||||
|
const GstCaps *caps;
|
||||||
|
|
||||||
|
g_return_if_fail (stream_nr >= -1 &&
|
||||||
|
stream_nr < GST_DVD_DEMUX_NUM_SUBPICTURE_STREAMS);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dvd_demux, "changing current subpicture to %02d",
|
||||||
|
stream_nr);
|
||||||
|
|
||||||
|
dvd_demux->cur_subpicture_nr = stream_nr;
|
||||||
|
|
||||||
|
if (stream_nr == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = dvd_demux->subpicture_stream[stream_nr];
|
||||||
|
if (str != NULL) {
|
||||||
|
/* (Re)set the caps in the "current" pad. */
|
||||||
|
caps = gst_pad_get_negotiated_caps (str->pad);
|
||||||
|
if (caps != NULL) {
|
||||||
|
gst_pad_set_explicit_caps (dvd_demux->cur_subpicture, caps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_dvd_demux_plugin_init (GstPlugin * plugin)
|
||||||
|
{
|
||||||
|
return gst_element_register (plugin, "dvddemux",
|
||||||
|
GST_RANK_PRIMARY, GST_TYPE_DVD_DEMUX);
|
||||||
|
}
|
143
gst/mpegstream/gstdvddemux.h
Normal file
143
gst/mpegstream/gstdvddemux.h
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2004 Martin Soto <martinsoto@users.sourceforge.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 __DVD_DEMUX_H__
|
||||||
|
#define __DVD_DEMUX_H__
|
||||||
|
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
#include "gstmpegdemux.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
#define GST_TYPE_DVD_DEMUX \
|
||||||
|
(gst_dvd_demux_get_type())
|
||||||
|
#define GST_DVD_DEMUX(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DVD_DEMUX,GstDVDDemux))
|
||||||
|
#define GST_DVD_DEMUX_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DVD_DEMUX,GstDVDDemuxClass))
|
||||||
|
#define GST_IS_DVD_DEMUX(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DVD_DEMUX))
|
||||||
|
#define GST_IS_DVD_DEMUX_CLASS(obj) \
|
||||||
|
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DVD_DEMUX))
|
||||||
|
|
||||||
|
|
||||||
|
/* Supported kinds of streams in addition to what mpegdemux already
|
||||||
|
does. */
|
||||||
|
enum {
|
||||||
|
GST_DVD_DEMUX_STREAM_SUBPICTURE = GST_MPEG_DEMUX_STREAM_LAST,
|
||||||
|
GST_DVD_DEMUX_STREAM_LAST,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Supported number of streams. */
|
||||||
|
#define GST_DVD_DEMUX_NUM_SUBPICTURE_STREAMS 32
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _GstDVDLPCMStream GstDVDLPCMStream ;
|
||||||
|
typedef struct _GstDVDDemux GstDVDDemux;
|
||||||
|
typedef struct _GstDVDDemuxClass GstDVDDemuxClass;
|
||||||
|
|
||||||
|
|
||||||
|
/* Additional recognized audio types. */
|
||||||
|
enum {
|
||||||
|
GST_DVD_DEMUX_AUDIO_LPCM = GST_MPEG_DEMUX_AUDIO_LAST,
|
||||||
|
GST_DVD_DEMUX_AUDIO_AC3,
|
||||||
|
GST_DVD_DEMUX_AUDIO_DTS,
|
||||||
|
GST_DVD_DEMUX_AUDIO_LAST,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* The recognized subpicture types. */
|
||||||
|
enum {
|
||||||
|
GST_DVD_DEMUX_SUBP_UNKNOWN =
|
||||||
|
GST_MPEG_DEMUX_STREAM_TYPE (GST_DVD_DEMUX_STREAM_SUBPICTURE, 1),
|
||||||
|
GST_DVD_DEMUX_SUBP_DVD,
|
||||||
|
GST_DVD_DEMUX_SUBP_LAST,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Extended structure to hold additional information for linear PCM
|
||||||
|
streams. */
|
||||||
|
struct _GstDVDLPCMStream {
|
||||||
|
GstMPEGStream parent;
|
||||||
|
guint8 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. */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct _GstDVDDemux {
|
||||||
|
GstMPEGDemux parent;
|
||||||
|
|
||||||
|
GstPad *cur_video; /* Current video stream pad. */
|
||||||
|
GstPad *cur_audio; /* Current audio stream pad. */
|
||||||
|
GstPad *cur_subpicture; /* Current subpicture stream pad. */
|
||||||
|
|
||||||
|
gint cur_video_nr; /* Current video stream number. */
|
||||||
|
gint cur_audio_nr; /* Current audio stream number. */
|
||||||
|
gint cur_subpicture_nr; /* Current subpicture stream number. */
|
||||||
|
|
||||||
|
GstClockTime last_end_ptm; /* End presentation time of the las nav packet
|
||||||
|
event received. */
|
||||||
|
|
||||||
|
gboolean just_flushed; /* The element just received a flush event. */
|
||||||
|
GstClockTime discont_time; /* If different from GST_CLOCK_TIME_NONE, a
|
||||||
|
discontinuous event should be sent with the
|
||||||
|
given time, before sending the next dara
|
||||||
|
block.. */
|
||||||
|
|
||||||
|
GstMPEGStream *subpicture_stream[GST_DVD_DEMUX_NUM_SUBPICTURE_STREAMS];
|
||||||
|
/* Subpicture output streams. */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct _GstDVDDemuxClass {
|
||||||
|
GstMPEGDemuxClass parent_class;
|
||||||
|
|
||||||
|
GstPadTemplate *cur_video_template;
|
||||||
|
GstPadTemplate *cur_audio_template;
|
||||||
|
GstPadTemplate *subpicture_template;
|
||||||
|
GstPadTemplate *cur_subpicture_template;
|
||||||
|
|
||||||
|
GstMPEGStream *
|
||||||
|
(*get_subpicture_stream)(GstMPEGDemux *mpeg_demux,
|
||||||
|
guint8 stream_nr,
|
||||||
|
gint type,
|
||||||
|
const gpointer info);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
GType gst_dvd_demux_get_type (void);
|
||||||
|
|
||||||
|
gboolean gst_dvd_demux_plugin_init (GstPlugin *plugin);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __DVD_DEMUX_H__ */
|
File diff suppressed because it is too large
Load diff
|
@ -32,28 +32,78 @@ extern "C" {
|
||||||
|
|
||||||
|
|
||||||
#define GST_TYPE_MPEG_DEMUX \
|
#define GST_TYPE_MPEG_DEMUX \
|
||||||
(mpeg_demux_get_type())
|
(gst_mpeg_demux_get_type())
|
||||||
#define GST_MPEG_DEMUX(obj) \
|
#define GST_MPEG_DEMUX(obj) \
|
||||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MPEG_DEMUX,GstMPEGDemux))
|
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MPEG_DEMUX,GstMPEGDemux))
|
||||||
#define GST_MPEG_DEMUX_CLASS(klass) \
|
#define GST_MPEG_DEMUX_CLASS(klass) \
|
||||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MPEG_DEMUX,GstMPEGDemux))
|
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MPEG_DEMUX,GstMPEGDemuxClass))
|
||||||
#define GST_IS_MPEG_DEMUX(obj) \
|
#define GST_IS_MPEG_DEMUX(obj) \
|
||||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MPEG_DEMUX))
|
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MPEG_DEMUX))
|
||||||
#define GST_IS_MPEG_DEMUX_CLASS(obj) \
|
#define GST_IS_MPEG_DEMUX_CLASS(obj) \
|
||||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MPEG_DEMUX))
|
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MPEG_DEMUX))
|
||||||
|
|
||||||
|
/* Supported kinds of streams. */
|
||||||
|
enum {
|
||||||
|
GST_MPEG_DEMUX_STREAM_VIDEO = 1,
|
||||||
|
GST_MPEG_DEMUX_STREAM_AUDIO,
|
||||||
|
GST_MPEG_DEMUX_STREAM_PRIVATE,
|
||||||
|
GST_MPEG_DEMUX_STREAM_LAST,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Supported number of streams. */
|
||||||
|
#define GST_MPEG_DEMUX_NUM_VIDEO_STREAMS 16
|
||||||
|
#define GST_MPEG_DEMUX_NUM_AUDIO_STREAMS 32
|
||||||
|
#define GST_MPEG_DEMUX_NUM_PRIVATE_STREAMS 2
|
||||||
|
|
||||||
|
/* How to make stream type values. */
|
||||||
|
#define GST_MPEG_DEMUX_STREAM_TYPE(kind, serial) \
|
||||||
|
(((kind) << 16) + (serial))
|
||||||
|
|
||||||
|
/* How to retrieve the stream kind back from a type. */
|
||||||
|
#define GST_MPEG_DEMUX_STREAM_KIND(type) ((type) >> 16)
|
||||||
|
|
||||||
|
/* The recognized video types. */
|
||||||
|
enum {
|
||||||
|
GST_MPEG_DEMUX_VIDEO_UNKNOWN =
|
||||||
|
GST_MPEG_DEMUX_STREAM_TYPE (GST_MPEG_DEMUX_STREAM_VIDEO, 1),
|
||||||
|
GST_MPEG_DEMUX_VIDEO_MPEG,
|
||||||
|
GST_MPEG_DEMUX_VIDEO_LAST,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The recognized audio types. */
|
||||||
|
enum {
|
||||||
|
GST_MPEG_DEMUX_AUDIO_UNKNOWN =
|
||||||
|
GST_MPEG_DEMUX_STREAM_TYPE (GST_MPEG_DEMUX_STREAM_AUDIO, 1),
|
||||||
|
GST_MPEG_DEMUX_AUDIO_MPEG,
|
||||||
|
GST_MPEG_DEMUX_AUDIO_LAST,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The recognized private stream types. */
|
||||||
|
enum {
|
||||||
|
GST_MPEG_DEMUX_PRIVATE_UNKNOWN =
|
||||||
|
GST_MPEG_DEMUX_STREAM_TYPE (GST_MPEG_DEMUX_STREAM_PRIVATE, 1),
|
||||||
|
GST_MPEG_DEMUX_PRIVATE_LAST,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _GstMPEGStream GstMPEGStream;
|
||||||
|
typedef struct _GstMPEGVideoStream GstMPEGVideoStream;
|
||||||
typedef struct _GstMPEGDemux GstMPEGDemux;
|
typedef struct _GstMPEGDemux GstMPEGDemux;
|
||||||
typedef struct _GstMPEGDemuxClass GstMPEGDemuxClass;
|
typedef struct _GstMPEGDemuxClass GstMPEGDemuxClass;
|
||||||
|
|
||||||
typedef struct _GstMPEGStream GstMPEGStream;
|
/* Information associated to a single MPEG stream. */
|
||||||
|
|
||||||
struct _GstMPEGStream {
|
struct _GstMPEGStream {
|
||||||
gint8 STD_buffer_bound_scale;
|
gint type;
|
||||||
gint16 STD_buffer_size_bound;
|
gint number;
|
||||||
GstPad *pad;
|
GstPad *pad;
|
||||||
guint64 pts;
|
gint index_id;
|
||||||
gint index_id;
|
gint size_bound;
|
||||||
gint size_bound;
|
};
|
||||||
|
|
||||||
|
/* Extended structure to hold additional information for video
|
||||||
|
streams. */
|
||||||
|
struct _GstMPEGVideoStream {
|
||||||
|
GstMPEGStream parent;
|
||||||
|
gint mpeg_version;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstMPEGDemux {
|
struct _GstMPEGDemux {
|
||||||
|
@ -74,35 +124,69 @@ struct _GstMPEGDemux {
|
||||||
gboolean packet_rate_restriction;
|
gboolean packet_rate_restriction;
|
||||||
gint64 total_size_bound;
|
gint64 total_size_bound;
|
||||||
|
|
||||||
#define NUM_PRIVATE_1_STREAMS 8
|
GstIndex *index;
|
||||||
#define NUM_PCM_STREAMS 8
|
|
||||||
#define NUM_SUBTITLE_STREAMS 16
|
|
||||||
#define NUM_VIDEO_STREAMS 16
|
|
||||||
#define NUM_AUDIO_STREAMS 32
|
|
||||||
|
|
||||||
/* stream output */
|
/* stream output */
|
||||||
GstMPEGStream *private_1_stream[NUM_PRIVATE_1_STREAMS]; /* up to 8 ac3 audio tracks */
|
GstMPEGStream *video_stream[GST_MPEG_DEMUX_NUM_VIDEO_STREAMS];
|
||||||
GstMPEGStream *pcm_stream[NUM_PCM_STREAMS];
|
GstMPEGStream *audio_stream[GST_MPEG_DEMUX_NUM_AUDIO_STREAMS];
|
||||||
GstMPEGStream *subtitle_stream[NUM_SUBTITLE_STREAMS];
|
GstMPEGStream *private_stream[GST_MPEG_DEMUX_NUM_PRIVATE_STREAMS];
|
||||||
GstMPEGStream *private_2_stream;
|
|
||||||
GstMPEGStream *video_stream[NUM_VIDEO_STREAMS];
|
|
||||||
GstMPEGStream *audio_stream[NUM_AUDIO_STREAMS];
|
|
||||||
|
|
||||||
/* The type of linear PCM samples associated to each channel. The
|
GstClockTimeDiff adjust; /* Added to all PTS timestamps. This element
|
||||||
values are bit fields with the same format of the sample_info
|
keeps always this value in 0, but it is
|
||||||
field in the linear PCM header. */
|
there for the benefit of subclasses. */
|
||||||
guint8 lpcm_sample_info[NUM_PCM_STREAMS];
|
|
||||||
|
|
||||||
GstIndex *index;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstMPEGDemuxClass {
|
struct _GstMPEGDemuxClass {
|
||||||
GstMPEGParseClass parent_class;
|
GstMPEGParseClass parent_class;
|
||||||
|
|
||||||
|
GstPadTemplate *video_template;
|
||||||
|
GstPadTemplate *audio_template;
|
||||||
|
GstPadTemplate *private_template;
|
||||||
|
|
||||||
|
GstPad * (*new_output_pad) (GstMPEGDemux *mpeg_demux,
|
||||||
|
const gchar *name,
|
||||||
|
GstPadTemplate *temp);
|
||||||
|
void (*init_stream) (GstMPEGDemux *mpeg_demux,
|
||||||
|
gint type,
|
||||||
|
GstMPEGStream *str,
|
||||||
|
gint number,
|
||||||
|
const gchar *name,
|
||||||
|
GstPadTemplate *temp);
|
||||||
|
|
||||||
|
GstMPEGStream *
|
||||||
|
(*get_video_stream) (GstMPEGDemux *mpeg_demux,
|
||||||
|
guint8 stream_nr,
|
||||||
|
gint type,
|
||||||
|
const gpointer info);
|
||||||
|
GstMPEGStream *
|
||||||
|
(*get_audio_stream) (GstMPEGDemux *mpeg_demux,
|
||||||
|
guint8 stream_nr,
|
||||||
|
gint type,
|
||||||
|
const gpointer info);
|
||||||
|
GstMPEGStream *
|
||||||
|
(*get_private_stream) (GstMPEGDemux *mpeg_demux,
|
||||||
|
guint8 stream_nr,
|
||||||
|
gint type,
|
||||||
|
const gpointer info);
|
||||||
|
|
||||||
|
void (*send_subbuffer) (GstMPEGDemux *mpeg_demux,
|
||||||
|
GstMPEGStream *outstream,
|
||||||
|
GstBuffer *buffer,
|
||||||
|
GstClockTime timestamp,
|
||||||
|
guint offset,
|
||||||
|
guint size);
|
||||||
|
|
||||||
|
|
||||||
|
void (*process_private) (GstMPEGDemux *mpeg_demux,
|
||||||
|
GstBuffer *buffer,
|
||||||
|
guint stream_nr,
|
||||||
|
GstClockTime timestamp,
|
||||||
|
guint headerlen, guint datalen);
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_mpeg_demux_get_type(void);
|
GType gst_mpeg_demux_get_type (void);
|
||||||
|
|
||||||
gboolean gst_mpeg_demux_plugin_init (GstPlugin *plugin);
|
gboolean gst_mpeg_demux_plugin_init (GstPlugin *plugin);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,13 @@
|
||||||
|
|
||||||
static GstFormat scr_format;
|
static GstFormat scr_format;
|
||||||
|
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_STATIC (gstmpegparse_debug);
|
||||||
|
#define GST_CAT_DEFAULT (gstmpegparse_debug)
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_SEEK);
|
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_SEEK);
|
||||||
|
|
||||||
|
|
||||||
/* elementfactory information */
|
/* elementfactory information */
|
||||||
static GstElementDetails mpeg_parse_details = {
|
static GstElementDetails mpeg_parse_details = {
|
||||||
"MPEG System Parser",
|
"MPEG System Parser",
|
||||||
|
@ -53,7 +58,7 @@ enum
|
||||||
ARG_0,
|
ARG_0,
|
||||||
ARG_SYNC,
|
ARG_SYNC,
|
||||||
ARG_MAX_DISCONT,
|
ARG_MAX_DISCONT,
|
||||||
ARG_STREAMINFO,
|
ARG_DO_ADJUST,
|
||||||
/* FILL ME */
|
/* FILL ME */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -80,9 +85,14 @@ static void gst_mpeg_parse_set_clock (GstElement * element, GstClock * clock);
|
||||||
|
|
||||||
static gboolean gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse,
|
static gboolean gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse,
|
||||||
GstBuffer * buffer);
|
GstBuffer * buffer);
|
||||||
|
|
||||||
|
static void gst_mpeg_parse_handle_discont (GstMPEGParse * mpeg_parse,
|
||||||
|
GstEvent * event);
|
||||||
|
|
||||||
static void gst_mpeg_parse_send_data (GstMPEGParse * mpeg_parse, GstData * data,
|
static void gst_mpeg_parse_send_data (GstMPEGParse * mpeg_parse, GstData * data,
|
||||||
GstClockTime time);
|
GstClockTime time);
|
||||||
static void gst_mpeg_parse_handle_discont (GstMPEGParse * mpeg_parse);
|
static void gst_mpeg_parse_send_discont (GstMPEGParse * mpeg_parse,
|
||||||
|
GstClockTime time);
|
||||||
|
|
||||||
static void gst_mpeg_parse_loop (GstElement * element);
|
static void gst_mpeg_parse_loop (GstElement * element);
|
||||||
|
|
||||||
|
@ -120,6 +130,9 @@ gst_mpeg_parse_get_type (void)
|
||||||
mpeg_parse_type =
|
mpeg_parse_type =
|
||||||
g_type_register_static (GST_TYPE_ELEMENT, "GstMPEGParse",
|
g_type_register_static (GST_TYPE_ELEMENT, "GstMPEGParse",
|
||||||
&mpeg_parse_info, 0);
|
&mpeg_parse_info, 0);
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gstmpegparse_debug, "mpegparse", 0,
|
||||||
|
"MPEG parser element");
|
||||||
}
|
}
|
||||||
return mpeg_parse_type;
|
return mpeg_parse_type;
|
||||||
}
|
}
|
||||||
|
@ -150,6 +163,11 @@ gst_mpeg_parse_class_init (GstMPEGParseClass * klass)
|
||||||
g_param_spec_int ("max_discont", "Max Discont",
|
g_param_spec_int ("max_discont", "Max Discont",
|
||||||
"The maximun allowed SCR discontinuity", 0, G_MAXINT,
|
"The maximun allowed SCR discontinuity", 0, G_MAXINT,
|
||||||
DEFAULT_MAX_DISCONT, G_PARAM_READWRITE));
|
DEFAULT_MAX_DISCONT, G_PARAM_READWRITE));
|
||||||
|
/* FIXME: Default is TRUE to make the behavior backwards compatible.
|
||||||
|
It probably should be FALSE. */
|
||||||
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DO_ADJUST,
|
||||||
|
g_param_spec_boolean ("adjust", "adjust", "Adjust timestamps to "
|
||||||
|
"smooth discontinuities", TRUE, G_PARAM_READWRITE));
|
||||||
|
|
||||||
gobject_class->get_property = gst_mpeg_parse_get_property;
|
gobject_class->get_property = gst_mpeg_parse_get_property;
|
||||||
gobject_class->set_property = gst_mpeg_parse_set_property;
|
gobject_class->set_property = gst_mpeg_parse_set_property;
|
||||||
|
@ -164,8 +182,9 @@ gst_mpeg_parse_class_init (GstMPEGParseClass * klass)
|
||||||
klass->parse_syshead = NULL;
|
klass->parse_syshead = NULL;
|
||||||
klass->parse_packet = NULL;
|
klass->parse_packet = NULL;
|
||||||
klass->parse_pes = NULL;
|
klass->parse_pes = NULL;
|
||||||
klass->send_data = gst_mpeg_parse_send_data;
|
|
||||||
klass->handle_discont = gst_mpeg_parse_handle_discont;
|
klass->handle_discont = gst_mpeg_parse_handle_discont;
|
||||||
|
klass->send_data = gst_mpeg_parse_send_data;
|
||||||
|
klass->send_discont = gst_mpeg_parse_send_discont;
|
||||||
|
|
||||||
/* FIXME: this is a hack. We add the pad templates here instead
|
/* FIXME: this is a hack. We add the pad templates here instead
|
||||||
* in the base_init function, since the derived class (mpegdemux)
|
* in the base_init function, since the derived class (mpegdemux)
|
||||||
|
@ -212,6 +231,8 @@ gst_mpeg_parse_init (GstMPEGParse * mpeg_parse)
|
||||||
mpeg_parse->id = NULL;
|
mpeg_parse->id = NULL;
|
||||||
mpeg_parse->max_discont = DEFAULT_MAX_DISCONT;
|
mpeg_parse->max_discont = DEFAULT_MAX_DISCONT;
|
||||||
|
|
||||||
|
mpeg_parse->do_adjust = TRUE;
|
||||||
|
|
||||||
GST_FLAG_SET (mpeg_parse, GST_ELEMENT_EVENT_AWARE);
|
GST_FLAG_SET (mpeg_parse, GST_ELEMENT_EVENT_AWARE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,6 +270,29 @@ gst_mpeg_parse_update_streaminfo (GstMPEGParse * mpeg_parse)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_mpeg_parse_handle_discont (GstMPEGParse * mpeg_parse, GstEvent * event)
|
||||||
|
{
|
||||||
|
GstClockTime time;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_DISCONTINUOUS);
|
||||||
|
|
||||||
|
if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &time)) {
|
||||||
|
GST_DEBUG_OBJECT (mpeg_parse,
|
||||||
|
"forwarding discontinuity, time: %0.3fs", (double) time / GST_SECOND);
|
||||||
|
|
||||||
|
if (CLASS (mpeg_parse)->send_discont)
|
||||||
|
CLASS (mpeg_parse)->send_discont (mpeg_parse, time);
|
||||||
|
} else {
|
||||||
|
/* Use the next SCR to send a discontinuous event. */
|
||||||
|
mpeg_parse->discont_pending = TRUE;
|
||||||
|
mpeg_parse->scr_pending = TRUE;
|
||||||
|
}
|
||||||
|
mpeg_parse->packetize->resync = TRUE;
|
||||||
|
|
||||||
|
gst_event_unref (event);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_mpeg_parse_send_data (GstMPEGParse * mpeg_parse, GstData * data,
|
gst_mpeg_parse_send_data (GstMPEGParse * mpeg_parse, GstData * data,
|
||||||
GstClockTime time)
|
GstClockTime time)
|
||||||
|
@ -283,29 +327,24 @@ gst_mpeg_parse_send_data (GstMPEGParse * mpeg_parse, GstData * data,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_mpeg_parse_handle_discont (GstMPEGParse * mpeg_parse)
|
gst_mpeg_parse_send_discont (GstMPEGParse * mpeg_parse, GstClockTime time)
|
||||||
{
|
{
|
||||||
GstEvent *event;
|
GstEvent *event;
|
||||||
|
|
||||||
event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
|
if (GST_PAD_IS_USABLE (mpeg_parse->srcpad)) {
|
||||||
MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr), NULL);
|
event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time, NULL);
|
||||||
|
|
||||||
if (GST_PAD_IS_USABLE (mpeg_parse->srcpad))
|
|
||||||
gst_pad_push (mpeg_parse->srcpad, GST_DATA (event));
|
gst_pad_push (mpeg_parse->srcpad, GST_DATA (event));
|
||||||
else
|
}
|
||||||
gst_event_unref (event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer)
|
gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
guint8 *buf;
|
guint8 *buf;
|
||||||
guint64 scr, scr_adj, scr_orig;
|
guint64 scr;
|
||||||
guint32 scr1, scr2;
|
guint32 scr1, scr2;
|
||||||
guint32 new_rate;
|
guint32 new_rate;
|
||||||
|
|
||||||
GST_DEBUG ("in parse_packhead");
|
|
||||||
|
|
||||||
buf = GST_BUFFER_DATA (buffer);
|
buf = GST_BUFFER_DATA (buffer);
|
||||||
buf += 4;
|
buf += 4;
|
||||||
|
|
||||||
|
@ -325,8 +364,9 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer)
|
||||||
|
|
||||||
scr = (scr * 300 + scr_ext % 300) / 300;
|
scr = (scr * 300 + scr_ext % 300) / 300;
|
||||||
|
|
||||||
GST_DEBUG ("%" G_GINT64_FORMAT " %d, %08x %08x %" G_GINT64_FORMAT " diff: %"
|
GST_LOG_OBJECT (mpeg_parse, "%" G_GINT64_FORMAT " %d, %08x %08x %"
|
||||||
G_GINT64_FORMAT, scr, scr_ext, scr1, scr2, mpeg_parse->bytes_since_scr,
|
G_GINT64_FORMAT " diff: %" G_GINT64_FORMAT,
|
||||||
|
scr, scr_ext, scr1, scr2, mpeg_parse->bytes_since_scr,
|
||||||
scr - mpeg_parse->current_scr);
|
scr - mpeg_parse->current_scr);
|
||||||
|
|
||||||
buf += 6;
|
buf += 6;
|
||||||
|
@ -345,36 +385,40 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer)
|
||||||
new_rate |= buf[2] >> 1;
|
new_rate |= buf[2] >> 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
scr_orig = scr;
|
mpeg_parse->current_scr = scr;
|
||||||
|
mpeg_parse->scr_pending = FALSE;
|
||||||
mpeg_parse->bytes_since_scr = 0;
|
mpeg_parse->bytes_since_scr = 0;
|
||||||
scr_adj = scr + mpeg_parse->adjust;
|
|
||||||
|
|
||||||
if (mpeg_parse->next_scr == -1) {
|
if (mpeg_parse->next_scr == -1) {
|
||||||
mpeg_parse->next_scr = scr;
|
mpeg_parse->next_scr = mpeg_parse->current_scr;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG ("SCR is %" G_GUINT64_FORMAT " (%" G_GUINT64_FORMAT ") next: %"
|
GST_LOG_OBJECT (mpeg_parse,
|
||||||
G_GINT64_FORMAT " (%" G_GINT64_FORMAT ") diff: %" G_GINT64_FORMAT " (%"
|
"SCR is %" G_GUINT64_FORMAT
|
||||||
|
" (%" G_GUINT64_FORMAT ") next: %"
|
||||||
|
G_GINT64_FORMAT " (%" G_GINT64_FORMAT
|
||||||
|
") diff: %" G_GINT64_FORMAT " (%"
|
||||||
G_GINT64_FORMAT ")",
|
G_GINT64_FORMAT ")",
|
||||||
scr,
|
mpeg_parse->current_scr,
|
||||||
MPEGTIME_TO_GSTTIME (scr),
|
MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr),
|
||||||
mpeg_parse->next_scr,
|
mpeg_parse->next_scr,
|
||||||
MPEGTIME_TO_GSTTIME (mpeg_parse->next_scr),
|
MPEGTIME_TO_GSTTIME (mpeg_parse->next_scr),
|
||||||
scr - mpeg_parse->next_scr,
|
mpeg_parse->current_scr - mpeg_parse->next_scr,
|
||||||
MPEGTIME_TO_GSTTIME (scr) - MPEGTIME_TO_GSTTIME (mpeg_parse->next_scr));
|
MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr) -
|
||||||
|
MPEGTIME_TO_GSTTIME (mpeg_parse->next_scr));
|
||||||
|
|
||||||
if (ABS ((gint64) mpeg_parse->next_scr - (gint64) (scr_adj)) >
|
if (ABS ((gint64) mpeg_parse->next_scr - (gint64) (scr)) >
|
||||||
mpeg_parse->max_discont) {
|
mpeg_parse->max_discont) {
|
||||||
GST_DEBUG ("discontinuity detected; expected: %" G_GUINT64_FORMAT " got: %"
|
GST_DEBUG ("discontinuity detected; expected: %" G_GUINT64_FORMAT " got: %"
|
||||||
G_GUINT64_FORMAT " real:%" G_GINT64_FORMAT " adjust:%" G_GINT64_FORMAT,
|
G_GUINT64_FORMAT " real:%" G_GINT64_FORMAT " adjust:%" G_GINT64_FORMAT,
|
||||||
mpeg_parse->next_scr, scr_adj, scr, mpeg_parse->adjust);
|
mpeg_parse->next_scr, mpeg_parse->current_scr + mpeg_parse->adjust,
|
||||||
|
mpeg_parse->current_scr, mpeg_parse->adjust);
|
||||||
|
if (mpeg_parse->do_adjust) {
|
||||||
|
mpeg_parse->adjust +=
|
||||||
|
(gint64) mpeg_parse->next_scr - (gint64) mpeg_parse->current_scr;
|
||||||
|
|
||||||
mpeg_parse->adjust = mpeg_parse->next_scr - scr;
|
GST_DEBUG ("new adjust: %" G_GINT64_FORMAT, mpeg_parse->adjust);
|
||||||
scr = mpeg_parse->next_scr;
|
}
|
||||||
|
|
||||||
GST_DEBUG ("new adjust: %" G_GINT64_FORMAT, mpeg_parse->adjust);
|
|
||||||
} else {
|
|
||||||
scr = scr_adj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mpeg_parse->index && GST_INDEX_IS_WRITABLE (mpeg_parse->index)) {
|
if (mpeg_parse->index && GST_INDEX_IS_WRITABLE (mpeg_parse->index)) {
|
||||||
|
@ -382,12 +426,9 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer)
|
||||||
gst_index_add_association (mpeg_parse->index, mpeg_parse->index_id,
|
gst_index_add_association (mpeg_parse->index, mpeg_parse->index_id,
|
||||||
GST_ASSOCIATION_FLAG_KEY_UNIT,
|
GST_ASSOCIATION_FLAG_KEY_UNIT,
|
||||||
GST_FORMAT_BYTES, GST_BUFFER_OFFSET (buffer),
|
GST_FORMAT_BYTES, GST_BUFFER_OFFSET (buffer),
|
||||||
GST_FORMAT_TIME, MPEGTIME_TO_GSTTIME (scr), 0);
|
GST_FORMAT_TIME, MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
mpeg_parse->current_scr = scr;
|
|
||||||
mpeg_parse->scr_pending = FALSE;
|
|
||||||
|
|
||||||
if (mpeg_parse->mux_rate != new_rate) {
|
if (mpeg_parse->mux_rate != new_rate) {
|
||||||
mpeg_parse->mux_rate = new_rate;
|
mpeg_parse->mux_rate = new_rate;
|
||||||
|
|
||||||
|
@ -417,7 +458,7 @@ gst_mpeg_parse_loop (GstElement * element)
|
||||||
if (GST_IS_BUFFER (data)) {
|
if (GST_IS_BUFFER (data)) {
|
||||||
GstBuffer *buffer = GST_BUFFER (data);
|
GstBuffer *buffer = GST_BUFFER (data);
|
||||||
|
|
||||||
GST_DEBUG ("have chunk 0x%02X", id);
|
GST_LOG_OBJECT (mpeg_parse, "have chunk 0x%02X", id);
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case 0xb9:
|
case 0xb9:
|
||||||
|
@ -456,11 +497,8 @@ gst_mpeg_parse_loop (GstElement * element)
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_DISCONTINUOUS:
|
case GST_EVENT_DISCONTINUOUS:
|
||||||
GST_DEBUG ("event: %d\n", GST_EVENT_TYPE (data));
|
if (CLASS (mpeg_parse)->handle_discont)
|
||||||
|
CLASS (mpeg_parse)->handle_discont (mpeg_parse, event);
|
||||||
mpeg_parse->discont_pending = TRUE;
|
|
||||||
mpeg_parse->packetize->resync = TRUE;
|
|
||||||
gst_event_unref (event);
|
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -479,8 +517,10 @@ gst_mpeg_parse_loop (GstElement * element)
|
||||||
gst_element_set_time (GST_ELEMENT (mpeg_parse),
|
gst_element_set_time (GST_ELEMENT (mpeg_parse),
|
||||||
MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr));
|
MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr));
|
||||||
}
|
}
|
||||||
if (CLASS (mpeg_parse)->handle_discont) {
|
if (CLASS (mpeg_parse)->send_discont) {
|
||||||
CLASS (mpeg_parse)->handle_discont (mpeg_parse);
|
CLASS (mpeg_parse)->send_discont (mpeg_parse,
|
||||||
|
MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr +
|
||||||
|
mpeg_parse->adjust));
|
||||||
}
|
}
|
||||||
mpeg_parse->discont_pending = FALSE;
|
mpeg_parse->discont_pending = FALSE;
|
||||||
} else {
|
} else {
|
||||||
|
@ -538,9 +578,9 @@ gst_mpeg_parse_loop (GstElement * element)
|
||||||
mpeg_parse->next_scr = scr;
|
mpeg_parse->next_scr = scr;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG ("size: %" G_GINT64_FORMAT ", total since SCR: %"
|
GST_LOG_OBJECT (mpeg_parse, "size: %" G_GINT64_FORMAT
|
||||||
G_GINT64_FORMAT ", next SCR: %" G_GINT64_FORMAT, size, bss,
|
", total since SCR: %" G_GINT64_FORMAT
|
||||||
mpeg_parse->next_scr);
|
", next SCR: %" G_GINT64_FORMAT, size, bss, mpeg_parse->next_scr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -816,6 +856,9 @@ gst_mpeg_parse_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
case ARG_MAX_DISCONT:
|
case ARG_MAX_DISCONT:
|
||||||
g_value_set_int (value, mpeg_parse->max_discont);
|
g_value_set_int (value, mpeg_parse->max_discont);
|
||||||
break;
|
break;
|
||||||
|
case ARG_DO_ADJUST:
|
||||||
|
g_value_set_boolean (value, mpeg_parse->do_adjust);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -837,6 +880,10 @@ gst_mpeg_parse_set_property (GObject * object, guint prop_id,
|
||||||
case ARG_MAX_DISCONT:
|
case ARG_MAX_DISCONT:
|
||||||
mpeg_parse->max_discont = g_value_get_int (value);
|
mpeg_parse->max_discont = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
|
case ARG_DO_ADJUST:
|
||||||
|
mpeg_parse->do_adjust = g_value_get_boolean (value);
|
||||||
|
mpeg_parse->adjust = 0;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -61,11 +61,13 @@ struct _GstMPEGParse {
|
||||||
|
|
||||||
/* pack header values */
|
/* pack header values */
|
||||||
guint32 mux_rate;
|
guint32 mux_rate;
|
||||||
guint64 current_scr;
|
guint64 current_scr; /* Current SCR from the stream. */
|
||||||
guint64 next_scr;
|
guint64 next_scr; /* Expected next SCR. */
|
||||||
guint64 bytes_since_scr;
|
guint64 bytes_since_scr;
|
||||||
|
|
||||||
gint64 adjust;
|
gboolean do_adjust; /* Adjust timestamps to smooth
|
||||||
|
discontinuities. */
|
||||||
|
gint64 adjust; /* Current timestamp adjust value. */
|
||||||
|
|
||||||
gboolean discont_pending;
|
gboolean discont_pending;
|
||||||
gboolean scr_pending;
|
gboolean scr_pending;
|
||||||
|
@ -88,9 +90,12 @@ struct _GstMPEGParseClass {
|
||||||
gboolean (*parse_packet) (GstMPEGParse *parse, GstBuffer *buffer);
|
gboolean (*parse_packet) (GstMPEGParse *parse, GstBuffer *buffer);
|
||||||
gboolean (*parse_pes) (GstMPEGParse *parse, GstBuffer *buffer);
|
gboolean (*parse_pes) (GstMPEGParse *parse, GstBuffer *buffer);
|
||||||
|
|
||||||
|
/* process events */
|
||||||
|
void (*handle_discont) (GstMPEGParse *parse, GstEvent *event);
|
||||||
|
|
||||||
/* optional method to send out the data */
|
/* optional method to send out the data */
|
||||||
void (*send_data) (GstMPEGParse *parse, GstData *data, GstClockTime time);
|
void (*send_data) (GstMPEGParse *parse, GstData *data, GstClockTime time);
|
||||||
void (*handle_discont) (GstMPEGParse *parse);
|
void (*send_discont) (GstMPEGParse *parse, GstClockTime time);
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_mpeg_parse_get_type(void);
|
GType gst_mpeg_parse_get_type(void);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#endif
|
#endif
|
||||||
#include "gstmpegparse.h"
|
#include "gstmpegparse.h"
|
||||||
#include "gstmpegdemux.h"
|
#include "gstmpegdemux.h"
|
||||||
|
#include "gstdvddemux.h"
|
||||||
#include "gstrfc2250enc.h"
|
#include "gstrfc2250enc.h"
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -38,6 +39,7 @@ plugin_init (GstPlugin * plugin)
|
||||||
|
|
||||||
if (!gst_mpeg_parse_plugin_init (plugin) ||
|
if (!gst_mpeg_parse_plugin_init (plugin) ||
|
||||||
!gst_mpeg_demux_plugin_init (plugin) ||
|
!gst_mpeg_demux_plugin_init (plugin) ||
|
||||||
|
!gst_dvd_demux_plugin_init (plugin) ||
|
||||||
!gst_rfc2250_enc_plugin_init (plugin))
|
!gst_rfc2250_enc_plugin_init (plugin))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue