mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 19:20:35 +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>
|
||||
|
||||
* 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
|
||||
|
||||
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_LIBADD =
|
||||
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
|
||||
|
|
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 \
|
||||
(mpeg_demux_get_type())
|
||||
(gst_mpeg_demux_get_type())
|
||||
#define GST_MPEG_DEMUX(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MPEG_DEMUX,GstMPEGDemux))
|
||||
#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) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MPEG_DEMUX))
|
||||
#define GST_IS_MPEG_DEMUX_CLASS(obj) \
|
||||
(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 _GstMPEGDemuxClass GstMPEGDemuxClass;
|
||||
|
||||
typedef struct _GstMPEGStream GstMPEGStream;
|
||||
|
||||
/* Information associated to a single MPEG stream. */
|
||||
struct _GstMPEGStream {
|
||||
gint8 STD_buffer_bound_scale;
|
||||
gint16 STD_buffer_size_bound;
|
||||
gint type;
|
||||
gint number;
|
||||
GstPad *pad;
|
||||
guint64 pts;
|
||||
gint index_id;
|
||||
gint size_bound;
|
||||
gint index_id;
|
||||
gint size_bound;
|
||||
};
|
||||
|
||||
/* Extended structure to hold additional information for video
|
||||
streams. */
|
||||
struct _GstMPEGVideoStream {
|
||||
GstMPEGStream parent;
|
||||
gint mpeg_version;
|
||||
};
|
||||
|
||||
struct _GstMPEGDemux {
|
||||
|
@ -74,35 +124,69 @@ struct _GstMPEGDemux {
|
|||
gboolean packet_rate_restriction;
|
||||
gint64 total_size_bound;
|
||||
|
||||
#define NUM_PRIVATE_1_STREAMS 8
|
||||
#define NUM_PCM_STREAMS 8
|
||||
#define NUM_SUBTITLE_STREAMS 16
|
||||
#define NUM_VIDEO_STREAMS 16
|
||||
#define NUM_AUDIO_STREAMS 32
|
||||
GstIndex *index;
|
||||
|
||||
/* stream output */
|
||||
GstMPEGStream *private_1_stream[NUM_PRIVATE_1_STREAMS]; /* up to 8 ac3 audio tracks */
|
||||
GstMPEGStream *pcm_stream[NUM_PCM_STREAMS];
|
||||
GstMPEGStream *subtitle_stream[NUM_SUBTITLE_STREAMS];
|
||||
GstMPEGStream *private_2_stream;
|
||||
GstMPEGStream *video_stream[NUM_VIDEO_STREAMS];
|
||||
GstMPEGStream *audio_stream[NUM_AUDIO_STREAMS];
|
||||
GstMPEGStream *video_stream[GST_MPEG_DEMUX_NUM_VIDEO_STREAMS];
|
||||
GstMPEGStream *audio_stream[GST_MPEG_DEMUX_NUM_AUDIO_STREAMS];
|
||||
GstMPEGStream *private_stream[GST_MPEG_DEMUX_NUM_PRIVATE_STREAMS];
|
||||
|
||||
/* The type of linear PCM samples associated to each channel. The
|
||||
values are bit fields with the same format of the sample_info
|
||||
field in the linear PCM header. */
|
||||
guint8 lpcm_sample_info[NUM_PCM_STREAMS];
|
||||
|
||||
GstIndex *index;
|
||||
GstClockTimeDiff adjust; /* Added to all PTS timestamps. This element
|
||||
keeps always this value in 0, but it is
|
||||
there for the benefit of subclasses. */
|
||||
};
|
||||
|
||||
struct _GstMPEGDemuxClass {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -27,8 +27,13 @@
|
|||
|
||||
static GstFormat scr_format;
|
||||
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gstmpegparse_debug);
|
||||
#define GST_CAT_DEFAULT (gstmpegparse_debug)
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_SEEK);
|
||||
|
||||
|
||||
/* elementfactory information */
|
||||
static GstElementDetails mpeg_parse_details = {
|
||||
"MPEG System Parser",
|
||||
|
@ -53,7 +58,7 @@ enum
|
|||
ARG_0,
|
||||
ARG_SYNC,
|
||||
ARG_MAX_DISCONT,
|
||||
ARG_STREAMINFO,
|
||||
ARG_DO_ADJUST,
|
||||
/* 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,
|
||||
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,
|
||||
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);
|
||||
|
||||
|
@ -120,6 +130,9 @@ gst_mpeg_parse_get_type (void)
|
|||
mpeg_parse_type =
|
||||
g_type_register_static (GST_TYPE_ELEMENT, "GstMPEGParse",
|
||||
&mpeg_parse_info, 0);
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gstmpegparse_debug, "mpegparse", 0,
|
||||
"MPEG parser element");
|
||||
}
|
||||
return mpeg_parse_type;
|
||||
}
|
||||
|
@ -150,6 +163,11 @@ gst_mpeg_parse_class_init (GstMPEGParseClass * klass)
|
|||
g_param_spec_int ("max_discont", "Max Discont",
|
||||
"The maximun allowed SCR discontinuity", 0, G_MAXINT,
|
||||
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->set_property = gst_mpeg_parse_set_property;
|
||||
|
@ -164,8 +182,9 @@ gst_mpeg_parse_class_init (GstMPEGParseClass * klass)
|
|||
klass->parse_syshead = NULL;
|
||||
klass->parse_packet = NULL;
|
||||
klass->parse_pes = NULL;
|
||||
klass->send_data = gst_mpeg_parse_send_data;
|
||||
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
|
||||
* 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->max_discont = DEFAULT_MAX_DISCONT;
|
||||
|
||||
mpeg_parse->do_adjust = TRUE;
|
||||
|
||||
GST_FLAG_SET (mpeg_parse, GST_ELEMENT_EVENT_AWARE);
|
||||
}
|
||||
|
||||
|
@ -249,6 +270,29 @@ gst_mpeg_parse_update_streaminfo (GstMPEGParse * mpeg_parse)
|
|||
}
|
||||
#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
|
||||
gst_mpeg_parse_send_data (GstMPEGParse * mpeg_parse, GstData * data,
|
||||
GstClockTime time)
|
||||
|
@ -283,29 +327,24 @@ gst_mpeg_parse_send_data (GstMPEGParse * mpeg_parse, GstData * data,
|
|||
}
|
||||
|
||||
static void
|
||||
gst_mpeg_parse_handle_discont (GstMPEGParse * mpeg_parse)
|
||||
gst_mpeg_parse_send_discont (GstMPEGParse * mpeg_parse, GstClockTime time)
|
||||
{
|
||||
GstEvent *event;
|
||||
|
||||
event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
|
||||
MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr), NULL);
|
||||
|
||||
if (GST_PAD_IS_USABLE (mpeg_parse->srcpad))
|
||||
if (GST_PAD_IS_USABLE (mpeg_parse->srcpad)) {
|
||||
event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time, NULL);
|
||||
gst_pad_push (mpeg_parse->srcpad, GST_DATA (event));
|
||||
else
|
||||
gst_event_unref (event);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer)
|
||||
{
|
||||
guint8 *buf;
|
||||
guint64 scr, scr_adj, scr_orig;
|
||||
guint64 scr;
|
||||
guint32 scr1, scr2;
|
||||
guint32 new_rate;
|
||||
|
||||
GST_DEBUG ("in parse_packhead");
|
||||
|
||||
buf = GST_BUFFER_DATA (buffer);
|
||||
buf += 4;
|
||||
|
||||
|
@ -325,8 +364,9 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer)
|
|||
|
||||
scr = (scr * 300 + scr_ext % 300) / 300;
|
||||
|
||||
GST_DEBUG ("%" G_GINT64_FORMAT " %d, %08x %08x %" G_GINT64_FORMAT " diff: %"
|
||||
G_GINT64_FORMAT, scr, scr_ext, scr1, scr2, mpeg_parse->bytes_since_scr,
|
||||
GST_LOG_OBJECT (mpeg_parse, "%" G_GINT64_FORMAT " %d, %08x %08x %"
|
||||
G_GINT64_FORMAT " diff: %" G_GINT64_FORMAT,
|
||||
scr, scr_ext, scr1, scr2, mpeg_parse->bytes_since_scr,
|
||||
scr - mpeg_parse->current_scr);
|
||||
|
||||
buf += 6;
|
||||
|
@ -345,36 +385,40 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer)
|
|||
new_rate |= buf[2] >> 1;
|
||||
}
|
||||
|
||||
scr_orig = scr;
|
||||
mpeg_parse->current_scr = scr;
|
||||
mpeg_parse->scr_pending = FALSE;
|
||||
mpeg_parse->bytes_since_scr = 0;
|
||||
scr_adj = scr + mpeg_parse->adjust;
|
||||
|
||||
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: %"
|
||||
G_GINT64_FORMAT " (%" G_GINT64_FORMAT ") diff: %" G_GINT64_FORMAT " (%"
|
||||
GST_LOG_OBJECT (mpeg_parse,
|
||||
"SCR is %" G_GUINT64_FORMAT
|
||||
" (%" G_GUINT64_FORMAT ") next: %"
|
||||
G_GINT64_FORMAT " (%" G_GINT64_FORMAT
|
||||
") diff: %" G_GINT64_FORMAT " (%"
|
||||
G_GINT64_FORMAT ")",
|
||||
scr,
|
||||
MPEGTIME_TO_GSTTIME (scr),
|
||||
mpeg_parse->current_scr,
|
||||
MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr),
|
||||
mpeg_parse->next_scr,
|
||||
MPEGTIME_TO_GSTTIME (mpeg_parse->next_scr),
|
||||
scr - mpeg_parse->next_scr,
|
||||
MPEGTIME_TO_GSTTIME (scr) - MPEGTIME_TO_GSTTIME (mpeg_parse->next_scr));
|
||||
mpeg_parse->current_scr - 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) {
|
||||
GST_DEBUG ("discontinuity detected; expected: %" G_GUINT64_FORMAT " got: %"
|
||||
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;
|
||||
scr = mpeg_parse->next_scr;
|
||||
|
||||
GST_DEBUG ("new adjust: %" G_GINT64_FORMAT, mpeg_parse->adjust);
|
||||
} else {
|
||||
scr = scr_adj;
|
||||
GST_DEBUG ("new adjust: %" G_GINT64_FORMAT, mpeg_parse->adjust);
|
||||
}
|
||||
}
|
||||
|
||||
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_ASSOCIATION_FLAG_KEY_UNIT,
|
||||
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) {
|
||||
mpeg_parse->mux_rate = new_rate;
|
||||
|
||||
|
@ -417,7 +458,7 @@ gst_mpeg_parse_loop (GstElement * element)
|
|||
if (GST_IS_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) {
|
||||
case 0xb9:
|
||||
|
@ -456,11 +497,8 @@ gst_mpeg_parse_loop (GstElement * element)
|
|||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_DISCONTINUOUS:
|
||||
GST_DEBUG ("event: %d\n", GST_EVENT_TYPE (data));
|
||||
|
||||
mpeg_parse->discont_pending = TRUE;
|
||||
mpeg_parse->packetize->resync = TRUE;
|
||||
gst_event_unref (event);
|
||||
if (CLASS (mpeg_parse)->handle_discont)
|
||||
CLASS (mpeg_parse)->handle_discont (mpeg_parse, event);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
|
@ -479,8 +517,10 @@ gst_mpeg_parse_loop (GstElement * element)
|
|||
gst_element_set_time (GST_ELEMENT (mpeg_parse),
|
||||
MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr));
|
||||
}
|
||||
if (CLASS (mpeg_parse)->handle_discont) {
|
||||
CLASS (mpeg_parse)->handle_discont (mpeg_parse);
|
||||
if (CLASS (mpeg_parse)->send_discont) {
|
||||
CLASS (mpeg_parse)->send_discont (mpeg_parse,
|
||||
MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr +
|
||||
mpeg_parse->adjust));
|
||||
}
|
||||
mpeg_parse->discont_pending = FALSE;
|
||||
} else {
|
||||
|
@ -538,9 +578,9 @@ gst_mpeg_parse_loop (GstElement * element)
|
|||
mpeg_parse->next_scr = scr;
|
||||
}
|
||||
|
||||
GST_DEBUG ("size: %" G_GINT64_FORMAT ", total since SCR: %"
|
||||
G_GINT64_FORMAT ", next SCR: %" G_GINT64_FORMAT, size, bss,
|
||||
mpeg_parse->next_scr);
|
||||
GST_LOG_OBJECT (mpeg_parse, "size: %" G_GINT64_FORMAT
|
||||
", total since SCR: %" G_GINT64_FORMAT
|
||||
", 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:
|
||||
g_value_set_int (value, mpeg_parse->max_discont);
|
||||
break;
|
||||
case ARG_DO_ADJUST:
|
||||
g_value_set_boolean (value, mpeg_parse->do_adjust);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -837,6 +880,10 @@ gst_mpeg_parse_set_property (GObject * object, guint prop_id,
|
|||
case ARG_MAX_DISCONT:
|
||||
mpeg_parse->max_discont = g_value_get_int (value);
|
||||
break;
|
||||
case ARG_DO_ADJUST:
|
||||
mpeg_parse->do_adjust = g_value_get_boolean (value);
|
||||
mpeg_parse->adjust = 0;
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
|
@ -61,11 +61,13 @@ struct _GstMPEGParse {
|
|||
|
||||
/* pack header values */
|
||||
guint32 mux_rate;
|
||||
guint64 current_scr;
|
||||
guint64 next_scr;
|
||||
guint64 current_scr; /* Current SCR from the stream. */
|
||||
guint64 next_scr; /* Expected next 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 scr_pending;
|
||||
|
@ -88,9 +90,12 @@ struct _GstMPEGParseClass {
|
|||
gboolean (*parse_packet) (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 */
|
||||
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);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#endif
|
||||
#include "gstmpegparse.h"
|
||||
#include "gstmpegdemux.h"
|
||||
#include "gstdvddemux.h"
|
||||
#include "gstrfc2250enc.h"
|
||||
|
||||
static gboolean
|
||||
|
@ -38,6 +39,7 @@ plugin_init (GstPlugin * plugin)
|
|||
|
||||
if (!gst_mpeg_parse_plugin_init (plugin) ||
|
||||
!gst_mpeg_demux_plugin_init (plugin) ||
|
||||
!gst_dvd_demux_plugin_init (plugin) ||
|
||||
!gst_rfc2250_enc_plugin_init (plugin))
|
||||
return FALSE;
|
||||
|
||||
|
|
Loading…
Reference in a new issue