mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 13:41:48 +00:00
4d652b147a
Original commit message from CVS: 2005-11-28 Martin Soto <martinsoto@users.sourceforge.net> * gst/mpegstream/gstdvddemux.c (gst_dvd_demux_handle_dvd_event) (gst_dvd_demux_handle_dvd_event): Erase code to prevent mpegparse from making timestamp adjustments. This will have to be re-added in some form in the near future, but in order to do that, some nav packet parsing will be necessary in mpegdemux. * gst/mpegstream/gstmpegparse.h (struct _GstMPEGParse): * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_init) (g_value_set_int, gst_mpeg_parse_set_property) Get rid of do_adjust and use_adjust. Rename max_discont to max_src_gap. (gst_mpeg_parse_parse_packhead): When max_scr_gap has a value of -1, no adjustment is made. * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_class_init): Rename max_discont property to max_scr_gap. Erase "adjust" property. * gst/mpegstream/gstdvddemux.c (gst_dvd_demux_send_event): Don't override send_event anymore, base class does the job. * gst/mpegstream/gstmpegdemux.c (gst_mpeg_demux_send_event): Base class now does most of the work. * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_send_event): Generalize to forwarding the event to all source pads in the element. * gst/mpegstream/gstmpegparse.h: * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_class_init) (gst_mpeg_parse_init, gst_mpeg_parse_set_clock) (gst_mpeg_parse_chain, gst_mpeg_parse_get_property) (gst_mpeg_parse_set_property): Clock synchronization doesn't make sense anymore for a demultiplexer.
1276 lines
39 KiB
C
1276 lines
39 KiB
C
/* GStreamer
|
|
* Copyright (C) 2005 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"
|
|
|
|
/*
|
|
* Move PTM discont back by 0.3 seconds to allow for strange audio
|
|
* timestamps when audio crosses a VOBU
|
|
*/
|
|
#define PTM_DISCONT_ADJUST (0.3 * GST_SECOND)
|
|
#define INITIAL_END_PTM (-1)
|
|
|
|
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 <martinsoto@users.sourceforge.net>"
|
|
};
|
|
|
|
/* DVDDemux signals and args */
|
|
enum
|
|
{
|
|
/* FILL ME */
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
enum
|
|
{
|
|
ARG_0
|
|
/* FILL ME */
|
|
};
|
|
|
|
|
|
/* Define the capabilities separately, to be able to reuse them. */
|
|
|
|
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
|
GST_PAD_SINK,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS ("video/mpeg, "
|
|
"mpegversion = (int) 2, " "systemstream = (boolean) TRUE")
|
|
);
|
|
|
|
#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-dvd-lpcm, " \
|
|
"width = (int) { 16, 20, 24 }, " \
|
|
"rate = (int) { 48000, 96000 }, " \
|
|
"channels = (int) [ 1, 8 ], " \
|
|
"dynamic_range = (int) [ 0, 255 ], " \
|
|
"emphasis = (boolean) { FALSE, TRUE }, " \
|
|
"mute = (boolean) { FALSE, TRUE }; " \
|
|
"audio/x-ac3;" \
|
|
"audio/x-dts" \
|
|
)
|
|
|
|
#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);
|
|
|
|
#define _do_init(bla) \
|
|
GST_DEBUG_CATEGORY_INIT (gstdvddemux_debug, "dvddemux", 0, \
|
|
"DVD (VOB) demultiplexer element");
|
|
|
|
GST_BOILERPLATE_FULL (GstDVDDemux, gst_dvd_demux, GstMPEGDemux,
|
|
GST_TYPE_MPEG_DEMUX, _do_init);
|
|
|
|
static void gst_dvd_demux_class_init (GstDVDDemuxClass * klass);
|
|
static void gst_dvd_demux_base_init (gpointer klass);
|
|
static void gst_dvd_demux_init (GstDVDDemux * dvd_demux,
|
|
GstDVDDemuxClass * klass);
|
|
|
|
static GstFlowReturn gst_dvd_demux_send_buffer (GstMPEGParse * mpeg_parse,
|
|
GstBuffer * buffer, GstClockTime time);
|
|
static gboolean gst_dvd_demux_process_event (GstMPEGParse * mpeg_parse,
|
|
GstEvent * event, GstClockTime time);
|
|
|
|
static gboolean gst_dvd_demux_handle_discont
|
|
(GstMPEGParse * mpeg_parse, GstEvent * event);
|
|
#if 0
|
|
static gboolean gst_dvd_demux_handle_dvd_event
|
|
(GstDVDDemux * dvd_demux, GstEvent * event);
|
|
#endif
|
|
|
|
static GstMPEGStream *gst_dvd_demux_get_video_stream
|
|
(GstMPEGDemux * mpeg_demux,
|
|
guint8 stream_nr, gint type, const gpointer info);
|
|
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 GstFlowReturn gst_dvd_demux_process_private
|
|
(GstMPEGDemux * mpeg_demux,
|
|
GstBuffer * buffer,
|
|
guint stream_nr, GstClockTime timestamp, guint headerlen, guint datalen);
|
|
|
|
static GstFlowReturn gst_dvd_demux_send_subbuffer
|
|
(GstMPEGDemux * mpeg_demux,
|
|
GstMPEGStream * outstream,
|
|
GstBuffer * buffer, GstClockTime timestamp, guint offset, guint size);
|
|
|
|
#if 0
|
|
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);
|
|
#endif
|
|
|
|
static void gst_dvd_demux_reset (GstDVDDemux * dvd_demux);
|
|
static void gst_dvd_demux_synchronise_pads (GstMPEGDemux * mpeg_demux,
|
|
GstClockTime threshold, GstClockTime new_ts);
|
|
static void gst_dvd_demux_sync_stream_to_time (GstMPEGDemux * mpeg_demux,
|
|
GstMPEGStream * stream, GstClockTime last_ts);
|
|
|
|
static GstStateChangeReturn gst_dvd_demux_change_state (GstElement * element,
|
|
GstStateChange transition);
|
|
|
|
/*static guint gst_dvd_demux_signals[LAST_SIGNAL] = { 0 };*/
|
|
|
|
|
|
static void
|
|
gst_dvd_demux_base_init (gpointer klass)
|
|
{
|
|
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
|
GstMPEGParseClass *mpeg_parse_class = GST_MPEG_PARSE_CLASS (klass);
|
|
GstMPEGDemuxClass *demux_class = GST_MPEG_DEMUX_CLASS (klass);
|
|
GstDVDDemuxClass *dvd_demux_class = GST_DVD_DEMUX_CLASS (klass);
|
|
|
|
mpeg_parse_class->send_buffer = gst_dvd_demux_send_buffer;
|
|
mpeg_parse_class->process_event = gst_dvd_demux_process_event;
|
|
|
|
/* sink pad */
|
|
gst_element_class_add_pad_template (element_class,
|
|
gst_static_pad_template_get (&sink_template));
|
|
|
|
demux_class->audio_template = gst_static_pad_template_get (&audio_template);
|
|
|
|
dvd_demux_class->cur_video_template =
|
|
gst_static_pad_template_get (&cur_video_template);
|
|
dvd_demux_class->cur_audio_template =
|
|
gst_static_pad_template_get (&cur_audio_template);
|
|
dvd_demux_class->subpicture_template =
|
|
gst_static_pad_template_get (&subpicture_template);
|
|
dvd_demux_class->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,
|
|
dvd_demux_class->cur_video_template);
|
|
gst_element_class_add_pad_template (element_class,
|
|
dvd_demux_class->cur_audio_template);
|
|
|
|
gst_element_class_add_pad_template (element_class,
|
|
dvd_demux_class->subpicture_template);
|
|
gst_element_class_add_pad_template (element_class,
|
|
dvd_demux_class->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;
|
|
|
|
gstelement_class->change_state = gst_dvd_demux_change_state;
|
|
|
|
mpeg_parse_class->handle_discont = gst_dvd_demux_handle_discont;
|
|
|
|
mpeg_demux_class->get_audio_stream = gst_dvd_demux_get_audio_stream;
|
|
mpeg_demux_class->get_video_stream = gst_dvd_demux_get_video_stream;
|
|
mpeg_demux_class->send_subbuffer = gst_dvd_demux_send_subbuffer;
|
|
mpeg_demux_class->process_private = gst_dvd_demux_process_private;
|
|
mpeg_demux_class->synchronise_pads = gst_dvd_demux_synchronise_pads;
|
|
mpeg_demux_class->sync_stream_to_time = gst_dvd_demux_sync_stream_to_time;
|
|
|
|
klass->get_subpicture_stream = gst_dvd_demux_get_subpicture_stream;
|
|
}
|
|
|
|
|
|
static void
|
|
gst_dvd_demux_init (GstDVDDemux * dvd_demux, GstDVDDemuxClass * klass)
|
|
{
|
|
GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (dvd_demux);
|
|
gint i;
|
|
|
|
/* 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);
|
|
gst_element_add_pad (GST_ELEMENT (mpeg_demux), dvd_demux->cur_video);
|
|
dvd_demux->cur_audio =
|
|
DEMUX_CLASS (dvd_demux)->new_output_pad (mpeg_demux, "current_audio",
|
|
CLASS (dvd_demux)->cur_audio_template);
|
|
gst_element_add_pad (GST_ELEMENT (mpeg_demux), dvd_demux->cur_audio);
|
|
dvd_demux->cur_subpicture =
|
|
DEMUX_CLASS (dvd_demux)->new_output_pad (mpeg_demux, "current_subpicture",
|
|
CLASS (dvd_demux)->cur_subpicture_template);
|
|
gst_element_add_pad (GST_ELEMENT (mpeg_demux), dvd_demux->cur_subpicture);
|
|
|
|
dvd_demux->mpeg_version = 0;
|
|
dvd_demux->cur_video_nr = 0;
|
|
dvd_demux->cur_audio_nr = 0;
|
|
dvd_demux->cur_subpicture_nr = 0;
|
|
|
|
dvd_demux->last_end_ptm = INITIAL_END_PTM;
|
|
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;
|
|
}
|
|
|
|
dvd_demux->langcodes = NULL;
|
|
dvd_demux->ignore_next_newmedia_discont = FALSE;
|
|
}
|
|
|
|
|
|
static GstFlowReturn
|
|
gst_dvd_demux_send_buffer (GstMPEGParse * mpeg_parse, GstBuffer * buffer,
|
|
GstClockTime time)
|
|
{
|
|
gst_buffer_unref (buffer);
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static gboolean
|
|
gst_dvd_demux_process_event (GstMPEGParse * mpeg_parse, GstEvent * event,
|
|
GstClockTime time)
|
|
{
|
|
GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_parse);
|
|
gboolean ret = TRUE;
|
|
|
|
switch (GST_EVENT_TYPE (event)) {
|
|
#if 0
|
|
/* FIXME: I do not know how to port GST_EVENT_ANY to gstreamer 0.9 */
|
|
case GST_EVENT_ANY:
|
|
if (!gst_dvd_demux_handle_dvd_event (dvd_demux, event))
|
|
return GST_FLOW_ERROR;
|
|
break;
|
|
#endif
|
|
/* case GST_EVENT_FILLER: */
|
|
case GST_EVENT_NEWSEGMENT:
|
|
case GST_EVENT_FLUSH_START:
|
|
case GST_EVENT_FLUSH_STOP:
|
|
ret = PARSE_CLASS (dvd_demux)->send_event (mpeg_parse, event,
|
|
GST_CLOCK_TIME_NONE);
|
|
break;
|
|
default:
|
|
/* Propagate the event normally. */
|
|
ret = gst_pad_event_default (mpeg_parse->sinkpad, event);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if 0
|
|
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);
|
|
const GstStructure *structure = gst_event_get_structure (event);
|
|
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 (!g_str_has_prefix (gst_structure_get_name (structure),
|
|
"application/x-gst")) {
|
|
/* This isn't a DVD event. */
|
|
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;
|
|
}
|
|
|
|
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) {
|
|
GstClockTimeDiff old_adjust = mpeg_demux->adjust;
|
|
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"));
|
|
GstClockTime cell_start =
|
|
g_value_get_uint64 (gst_structure_get_value (structure, "cell_start"));
|
|
GstClockTime pg_start =
|
|
g_value_get_uint64 (gst_structure_get_value (structure, "pg_start"));
|
|
|
|
if (start_ptm != dvd_demux->last_end_ptm) {
|
|
|
|
GST_DEBUG_OBJECT (dvd_demux,
|
|
"PTM sequence discontinuity: from %0.3fs to %0.3fs, cell_start %0.3fs, pg_start %0.3fs",
|
|
(double) dvd_demux->last_end_ptm / GST_SECOND,
|
|
(double) start_ptm / GST_SECOND,
|
|
(double) cell_start / GST_SECOND, (double) pg_start / GST_SECOND);
|
|
|
|
if (pg_start > start_ptm)
|
|
mpeg_demux->adjust = pg_start - start_ptm;
|
|
else
|
|
mpeg_demux->adjust = 0;
|
|
|
|
/* Keep video/audio/subtitle pads within 1/2 sec of the SCR */
|
|
mpeg_demux->max_gap = 0.5 * GST_SECOND;
|
|
mpeg_demux->max_gap_tolerance = 0.05 * GST_SECOND;
|
|
}
|
|
|
|
/* Send a discont after a seek, or if PTM wrapping causes too large a gap */
|
|
if (mpeg_demux->just_flushed ||
|
|
ABS (GST_CLOCK_DIFF (dvd_demux->last_end_ptm + old_adjust,
|
|
start_ptm + mpeg_demux->adjust)) > PTM_DISCONT_ADJUST) {
|
|
|
|
/* 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. */
|
|
if (start_ptm > PTM_DISCONT_ADJUST)
|
|
dvd_demux->discont_time = start_ptm - PTM_DISCONT_ADJUST;
|
|
else
|
|
dvd_demux->discont_time = 0;
|
|
|
|
GST_DEBUG_OBJECT (dvd_demux,
|
|
"Set mpeg discont time to %" G_GINT64_FORMAT ", adjust %"
|
|
G_GINT64_FORMAT, dvd_demux->discont_time, mpeg_demux->adjust);
|
|
}
|
|
|
|
dvd_demux->last_end_ptm = end_ptm;
|
|
|
|
gst_event_unref (event);
|
|
} else if (!strcmp (event_type, "dvd-lang-codes")) {
|
|
gint num_substreams = 0, num_audstreams = 0, n;
|
|
gchar *t;
|
|
|
|
/* reset */
|
|
if (dvd_demux->langcodes)
|
|
gst_event_unref (dvd_demux->langcodes);
|
|
PARSE_CLASS (dvd_demux)->handle_discont (mpeg_parse,
|
|
gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_UNDEFINED, 0, 0, 0));
|
|
|
|
/* see what kind of streams we have */
|
|
dvd_demux->langcodes = event;
|
|
|
|
/* now create pads for each; first video */
|
|
n = 2;
|
|
DEMUX_CLASS (dvd_demux)->get_video_stream (mpeg_demux,
|
|
0, GST_MPEG_DEMUX_VIDEO_MPEG, &n);
|
|
|
|
/* audio */
|
|
for (n = 0;; n++) {
|
|
gint fmt, ifo = 0;
|
|
|
|
t = g_strdup_printf ("audio-%d-format", num_audstreams);
|
|
if (!gst_structure_get_int (structure, t, &fmt)) {
|
|
g_free (t);
|
|
break;
|
|
}
|
|
g_free (t);
|
|
switch (fmt) {
|
|
case 0x0: /* AC-3 */
|
|
fmt = GST_DVD_DEMUX_AUDIO_AC3;
|
|
break;
|
|
case 0x2:
|
|
case 0x3: /* MPEG */
|
|
fmt = GST_MPEG_DEMUX_AUDIO_MPEG;
|
|
break;
|
|
case 0x4:
|
|
fmt = GST_DVD_DEMUX_AUDIO_LPCM;
|
|
break;
|
|
case 0x6:
|
|
fmt = GST_DVD_DEMUX_AUDIO_DTS;
|
|
break;
|
|
default:
|
|
fmt = GST_MPEG_DEMUX_AUDIO_UNKNOWN;
|
|
break;
|
|
}
|
|
DEMUX_CLASS (dvd_demux)->get_audio_stream (mpeg_demux,
|
|
num_audstreams++, fmt, &ifo);
|
|
}
|
|
|
|
/* subtitle */
|
|
for (;;) {
|
|
t = g_strdup_printf ("subtitle-%d-language", num_substreams);
|
|
if (!gst_structure_get_value (structure, t)) {
|
|
g_free (t);
|
|
break;
|
|
}
|
|
g_free (t);
|
|
CLASS (dvd_demux)->get_subpicture_stream (mpeg_demux,
|
|
num_substreams++, GST_DVD_DEMUX_SUBP_DVD, NULL);
|
|
}
|
|
GST_DEBUG_OBJECT (dvd_demux,
|
|
"Created 1 video stream, %d audio streams and %d subpicture streams "
|
|
"based on DVD lang codes event; now signalling no-more-pads",
|
|
num_audstreams, num_substreams);
|
|
|
|
/* we know this will be all */
|
|
gst_element_no_more_pads (GST_ELEMENT (dvd_demux));
|
|
dvd_demux->ignore_next_newmedia_discont = TRUE;
|
|
|
|
/* Keep video/audio/subtitle pads within 1/2 sec of the SCR */
|
|
mpeg_demux->max_gap = 0.5 * GST_SECOND;
|
|
mpeg_demux->max_gap_tolerance = 0.05 * GST_SECOND;
|
|
} else {
|
|
GST_DEBUG_OBJECT (dvd_demux, "dvddemux Forwarding DVD event %s to all pads",
|
|
event_type);
|
|
|
|
PARSE_CLASS (dvd_demux)->send_event (mpeg_parse, event,
|
|
GST_CLOCK_TIME_NONE);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
static GstFlowReturn
|
|
gst_dvd_demux_handle_discont (GstMPEGParse * mpeg_parse, GstEvent * event)
|
|
{
|
|
#if 0
|
|
GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_parse);
|
|
|
|
if (GST_EVENT_DISCONT_NEW_MEDIA (event)) {
|
|
/* HACK */
|
|
if (dvd_demux->ignore_next_newmedia_discont)
|
|
GST_EVENT_DISCONT_NEW_MEDIA (event) = FALSE;
|
|
else
|
|
gst_dvd_demux_reset (dvd_demux);
|
|
}
|
|
#endif
|
|
|
|
/* let parent handle and forward discont */
|
|
if (GST_MPEG_PARSE_CLASS (parent_class)->handle_discont != NULL)
|
|
GST_MPEG_PARSE_CLASS (parent_class)->handle_discont (mpeg_parse, event);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstMPEGStream *
|
|
gst_dvd_demux_get_video_stream (GstMPEGDemux * mpeg_demux,
|
|
guint8 stream_nr, gint type, const gpointer info)
|
|
{
|
|
GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_demux);
|
|
GstMPEGStream *str =
|
|
parent_class->get_video_stream (mpeg_demux, stream_nr, type, info);
|
|
gint mpeg_version = *((gint *) info);
|
|
|
|
if (dvd_demux->mpeg_version != mpeg_version) {
|
|
GstCaps *caps;
|
|
|
|
caps = gst_caps_new_simple ("video/mpeg",
|
|
"mpegversion", G_TYPE_INT, mpeg_version,
|
|
"systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
|
|
|
|
if (!gst_pad_set_caps (dvd_demux->cur_video, caps)) {
|
|
GST_ELEMENT_ERROR (GST_ELEMENT (mpeg_demux),
|
|
CORE, NEGOTIATION, (NULL), ("failed to set caps"));
|
|
} else {
|
|
dvd_demux->mpeg_version = mpeg_version;
|
|
}
|
|
gst_caps_unref (caps);
|
|
}
|
|
|
|
dvd_demux->mpeg_version = mpeg_version;
|
|
return str;
|
|
}
|
|
|
|
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);
|
|
guint32 sample_info = 0;
|
|
GstMPEGStream *str;
|
|
GstDVDLPCMStream *lpcm_str = NULL;
|
|
gboolean add_pad = FALSE;
|
|
GstCaps *caps;
|
|
const gchar *codec = NULL, *lang_code = NULL;
|
|
|
|
g_return_val_if_fail (stream_nr < GST_MPEG_DEMUX_NUM_AUDIO_STREAMS, NULL);
|
|
g_return_val_if_fail (type > GST_MPEG_DEMUX_AUDIO_UNKNOWN &&
|
|
type < GST_DVD_DEMUX_AUDIO_LAST, NULL);
|
|
|
|
if (type < GST_MPEG_DEMUX_AUDIO_LAST) {
|
|
/* FIXME: language codes on MPEG audio streams */
|
|
return parent_class->get_audio_stream (mpeg_demux, stream_nr, type, info);
|
|
}
|
|
|
|
if (type == GST_DVD_DEMUX_AUDIO_LPCM) {
|
|
sample_info = *((guint32 *) info);
|
|
}
|
|
|
|
str = mpeg_demux->audio_stream[stream_nr];
|
|
|
|
/* If the stream type is changing, recreate the pad */
|
|
if (str && str->type != type) {
|
|
gst_element_remove_pad (GST_ELEMENT (mpeg_demux), str->pad);
|
|
g_free (str);
|
|
str = mpeg_demux->audio_stream[stream_nr] = NULL;
|
|
}
|
|
|
|
if (str == NULL) {
|
|
gchar *name;
|
|
|
|
if (type != GST_DVD_DEMUX_AUDIO_LPCM) {
|
|
str = g_new0 (GstMPEGStream, 1);
|
|
} else {
|
|
lpcm_str = g_new0 (GstDVDLPCMStream, 1);
|
|
str = (GstMPEGStream *) lpcm_str;
|
|
}
|
|
|
|
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);
|
|
/* update caps */
|
|
str->type = GST_MPEG_DEMUX_AUDIO_UNKNOWN;
|
|
g_free (name);
|
|
add_pad = TRUE;
|
|
} else {
|
|
/* Stream size may have changed, reset it. */
|
|
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;
|
|
}
|
|
}
|
|
|
|
mpeg_demux->audio_stream[stream_nr] = str;
|
|
|
|
if (type != str->type ||
|
|
(type == GST_DVD_DEMUX_AUDIO_LPCM &&
|
|
sample_info != lpcm_str->sample_info)) {
|
|
gint width, rate, channels, dynamic_range;
|
|
gboolean emphasis, mute;
|
|
|
|
/* We need to set new caps for this pad. */
|
|
switch (type) {
|
|
case GST_DVD_DEMUX_AUDIO_LPCM:
|
|
/* Dynamic range in the lower byte */
|
|
dynamic_range = sample_info & 0xff;
|
|
|
|
/* Determine the sample width. */
|
|
switch (sample_info & 0xC000) {
|
|
case 0x8000:
|
|
width = 24;
|
|
break;
|
|
case 0x4000:
|
|
width = 20;
|
|
break;
|
|
default:
|
|
width = 16;
|
|
break;
|
|
}
|
|
|
|
/* Determine the rate. */
|
|
if (sample_info & 0x1000) {
|
|
rate = 96000;
|
|
} else {
|
|
rate = 48000;
|
|
}
|
|
|
|
mute = ((sample_info & 0x400000) != 0);
|
|
emphasis = ((sample_info & 0x800000) != 0);
|
|
|
|
/* Determine the number of channels. */
|
|
channels = ((sample_info >> 8) & 0x7) + 1;
|
|
|
|
caps = gst_caps_new_simple ("audio/x-dvd-lpcm",
|
|
"width", G_TYPE_INT, width,
|
|
"rate", G_TYPE_INT, rate,
|
|
"channels", G_TYPE_INT, channels,
|
|
"dynamic_range", G_TYPE_INT, dynamic_range,
|
|
"emphasis", G_TYPE_BOOLEAN, emphasis,
|
|
"mute", G_TYPE_BOOLEAN, mute, NULL);
|
|
|
|
lpcm_str->sample_info = sample_info;
|
|
lpcm_str->width = width;
|
|
lpcm_str->rate = rate;
|
|
lpcm_str->channels = channels;
|
|
lpcm_str->dynamic_range = dynamic_range;
|
|
lpcm_str->mute = mute;
|
|
lpcm_str->emphasis = emphasis;
|
|
codec = "LPCM audio";
|
|
break;
|
|
|
|
case GST_DVD_DEMUX_AUDIO_AC3:
|
|
caps = gst_caps_new_simple ("audio/x-ac3", NULL);
|
|
codec = "AC-3 audio";
|
|
break;
|
|
|
|
case GST_DVD_DEMUX_AUDIO_DTS:
|
|
caps = gst_caps_new_simple ("audio/x-dts", NULL);
|
|
codec = "DTS audio";
|
|
break;
|
|
|
|
default:
|
|
g_return_val_if_reached (NULL);
|
|
break;
|
|
}
|
|
|
|
if (!gst_pad_set_caps (str->pad, caps)) {
|
|
GST_ELEMENT_ERROR (GST_ELEMENT (mpeg_demux),
|
|
CORE, NEGOTIATION, (NULL), ("failed to set caps on pad %s:%s",
|
|
gst_element_get_name (dvd_demux), gst_pad_get_name (str->pad)));
|
|
}
|
|
|
|
if (str->number == dvd_demux->cur_audio_nr) {
|
|
/* This is the current audio stream. Use the same caps. */
|
|
if (!gst_pad_set_caps (dvd_demux->cur_audio, gst_caps_copy (caps))) {
|
|
GST_ELEMENT_ERROR (GST_ELEMENT (mpeg_demux),
|
|
CORE, NEGOTIATION, (NULL), ("failed to set caps on pad %s:%s",
|
|
gst_element_get_name (dvd_demux),
|
|
gst_pad_get_name (dvd_demux->cur_audio)));
|
|
}
|
|
}
|
|
|
|
if (add_pad) {
|
|
if (dvd_demux->langcodes) {
|
|
gchar *t;
|
|
|
|
t = g_strdup_printf ("audio-%d-language", stream_nr);
|
|
lang_code =
|
|
gst_structure_get_string (gst_event_get_structure (dvd_demux->
|
|
langcodes), t);
|
|
g_free (t);
|
|
}
|
|
|
|
gst_element_add_pad (GST_ELEMENT (mpeg_demux), str->pad);
|
|
|
|
if (codec || lang_code) {
|
|
GstTagList *list = gst_tag_list_new ();
|
|
|
|
if (codec) {
|
|
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
|
|
GST_TAG_AUDIO_CODEC, codec, NULL);
|
|
}
|
|
if (lang_code) {
|
|
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
|
|
GST_TAG_LANGUAGE_CODE, lang_code, NULL);
|
|
}
|
|
gst_element_found_tags_for_pad (GST_ELEMENT (mpeg_demux),
|
|
str->pad, list);
|
|
}
|
|
}
|
|
|
|
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;
|
|
gboolean add_pad = FALSE;
|
|
const gchar *lang_code = NULL;
|
|
|
|
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);
|
|
|
|
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);
|
|
str->type = GST_DVD_DEMUX_SUBP_UNKNOWN;
|
|
g_free (name);
|
|
add_pad = TRUE;
|
|
|
|
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);
|
|
|
|
if (!gst_pad_set_caps (str->pad, caps)) {
|
|
GST_ELEMENT_ERROR (GST_ELEMENT (mpeg_demux),
|
|
CORE, NEGOTIATION, (NULL), ("failed to set caps on pad %s:%s",
|
|
gst_element_get_name (dvd_demux), gst_pad_get_name (str->pad)));
|
|
}
|
|
|
|
if (str->number == dvd_demux->cur_subpicture_nr) {
|
|
/* This is the current subpicture stream. Use the same caps. */
|
|
if (!gst_pad_set_caps (dvd_demux->cur_subpicture, caps)) {
|
|
GST_ELEMENT_ERROR (GST_ELEMENT (mpeg_demux),
|
|
CORE, NEGOTIATION, (NULL), ("failed to set caps on pad %s:%s",
|
|
gst_element_get_name (dvd_demux), gst_pad_get_name (str->pad)));
|
|
}
|
|
}
|
|
|
|
gst_caps_unref (caps);
|
|
if (add_pad) {
|
|
gst_element_add_pad (GST_ELEMENT (mpeg_demux), str->pad);
|
|
|
|
if (dvd_demux->langcodes) {
|
|
gchar *t;
|
|
|
|
t = g_strdup_printf ("subtitle-%d-language", stream_nr);
|
|
lang_code =
|
|
gst_structure_get_string (gst_event_get_structure (dvd_demux->
|
|
langcodes), t);
|
|
g_free (t);
|
|
|
|
if (lang_code) {
|
|
GstTagList *list = gst_tag_list_new ();
|
|
|
|
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
|
|
GST_TAG_LANGUAGE_CODE, lang_code, NULL);
|
|
gst_element_found_tags_for_pad (GST_ELEMENT (mpeg_demux),
|
|
str->pad, list);
|
|
}
|
|
}
|
|
}
|
|
str->type = GST_DVD_DEMUX_SUBP_DVD;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
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);
|
|
GstFlowReturn ret = GST_FLOW_OK;
|
|
guint8 *basebuf;
|
|
guint8 ps_id_code;
|
|
GstMPEGStream *outstream = NULL;
|
|
guint first_access = 0;
|
|
gint align = 1, len, off;
|
|
|
|
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. */
|
|
|
|
if (ps_id_code >= 0x80 && ps_id_code <= 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] << 8) | basebuf[headerlen + 7];
|
|
|
|
headerlen += 4;
|
|
datalen -= 4;
|
|
} else if (ps_id_code >= 0x88 && ps_id_code <= 0x8f) {
|
|
GST_LOG_OBJECT (dvd_demux,
|
|
"we have an audio (DTS) packet, track %d", ps_id_code - 0x88);
|
|
outstream = DEMUX_CLASS (dvd_demux)->get_audio_stream (mpeg_demux,
|
|
ps_id_code - 0x88, GST_DVD_DEMUX_AUDIO_DTS, NULL);
|
|
|
|
/* Determine the position of the "first access". This
|
|
should always be the beginning of a DTS frame. */
|
|
first_access = (basebuf[headerlen + 6] << 8) | basebuf[headerlen + 7];
|
|
|
|
headerlen += 4;
|
|
datalen -= 4;
|
|
} else if (ps_id_code >= 0xA0 && ps_id_code <= 0xA7) {
|
|
GstDVDLPCMStream *lpcm_str;
|
|
guint32 lpcm_sample_info;
|
|
|
|
GST_LOG_OBJECT (dvd_demux,
|
|
"we have an audio (LPCM) packet, track %d", ps_id_code - 0xA0);
|
|
|
|
/* Compose the sample info from the LPCM header, masking out the frame_num */
|
|
lpcm_sample_info =
|
|
basebuf[headerlen + 10] | (basebuf[headerlen +
|
|
9] << 8) | ((basebuf[headerlen + 8] & 0xc0) << 16);
|
|
|
|
outstream = DEMUX_CLASS (dvd_demux)->get_audio_stream (mpeg_demux,
|
|
ps_id_code - 0xA0, GST_DVD_DEMUX_AUDIO_LPCM, &lpcm_sample_info);
|
|
lpcm_str = (GstDVDLPCMStream *) outstream;
|
|
|
|
/* Determine the position of the "first access". */
|
|
first_access = (basebuf[headerlen + 6] << 8) | basebuf[headerlen + 7];
|
|
|
|
/* Get rid of the LPCM header. */
|
|
headerlen += 7;
|
|
datalen -= 7;
|
|
|
|
/* align by frame round up to nearest byte */
|
|
align = (lpcm_str->width * lpcm_str->channels + 7) / 8;
|
|
} else if (ps_id_code >= 0x20 && ps_id_code <= 0x3F) {
|
|
GST_LOG_OBJECT (dvd_demux,
|
|
"we have a subpicture packet, track %d", ps_id_code - 0x20);
|
|
outstream = CLASS (dvd_demux)->get_subpicture_stream (mpeg_demux,
|
|
ps_id_code - 0x20, GST_DVD_DEMUX_SUBP_DVD, NULL);
|
|
|
|
headerlen += 1;
|
|
datalen -= 1;
|
|
} else {
|
|
GST_WARNING_OBJECT (dvd_demux,
|
|
"unknown DVD (private 1) id 0x%02x", ps_id_code);
|
|
}
|
|
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_WARNING_OBJECT (dvd_demux,
|
|
"unknown DVD (private 2) id 0x%02x", ps_id_code);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
g_return_val_if_reached (GST_FLOW_UNEXPECTED);
|
|
break;
|
|
}
|
|
|
|
if (outstream == NULL) {
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
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. */
|
|
off = headerlen + 4;
|
|
len = first_access - 1;
|
|
len -= len % align;
|
|
if (len > 0) {
|
|
ret = DEMUX_CLASS (dvd_demux)->send_subbuffer (mpeg_demux, outstream,
|
|
buffer, GST_CLOCK_TIME_NONE, off, len);
|
|
}
|
|
off += len;
|
|
len = datalen - len;
|
|
len -= len % align;
|
|
if (len > 0) {
|
|
ret = DEMUX_CLASS (dvd_demux)->send_subbuffer (mpeg_demux, outstream,
|
|
buffer, timestamp, off, len);
|
|
}
|
|
} else {
|
|
off = headerlen + 4;
|
|
len = datalen;
|
|
len -= len % align;
|
|
if (len > 0) {
|
|
ret = DEMUX_CLASS (dvd_demux)->send_subbuffer (mpeg_demux, outstream,
|
|
buffer, timestamp, off, len);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
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);
|
|
GstFlowReturn ret;
|
|
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) {
|
|
if ((gint64) (dvd_demux->discont_time) < 0) {
|
|
GST_ERROR ("DVD Discont < 0! % " G_GINT64_FORMAT,
|
|
(gint64) dvd_demux->discont_time);
|
|
}
|
|
PARSE_CLASS (mpeg_demux)->send_newsegment (mpeg_parse, 1.0,
|
|
dvd_demux->discont_time, GST_CLOCK_TIME_NONE);
|
|
dvd_demux->discont_time = GST_CLOCK_TIME_NONE;
|
|
}
|
|
|
|
dvd_demux->ignore_next_newmedia_discont = FALSE;
|
|
|
|
/* 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. */
|
|
ret = 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_val_if_reached (GST_FLOW_UNEXPECTED);
|
|
break;
|
|
}
|
|
|
|
if (outpad != NULL && cur_nr == outstream->number && size > 0) {
|
|
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);
|
|
g_return_val_if_fail (outbuf != NULL, GST_FLOW_UNEXPECTED);
|
|
|
|
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
|
|
GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buffer) + offset;
|
|
|
|
ret = gst_pad_push (outpad, outbuf);
|
|
}
|
|
|
|
gst_buffer_unref (buffer);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if 0
|
|
static void
|
|
gst_dvd_demux_set_cur_audio (GstDVDDemux * dvd_demux, gint stream_nr)
|
|
{
|
|
GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (dvd_demux);
|
|
GstMPEGStream *str;
|
|
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_CAPS (str->pad);
|
|
if (caps != NULL) {
|
|
gst_pad_set_caps (dvd_demux->cur_audio, caps);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_dvd_demux_set_cur_subpicture (GstDVDDemux * dvd_demux, gint stream_nr)
|
|
{
|
|
GstMPEGStream *str;
|
|
|
|
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) {
|
|
GstCaps *caps = NULL;
|
|
|
|
/* (Re)set the caps in the "current" pad. */
|
|
caps = GST_PAD_CAPS (str->pad);
|
|
gst_pad_set_caps (dvd_demux->cur_subpicture, caps);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
gst_dvd_demux_reset (GstDVDDemux * dvd_demux)
|
|
{
|
|
int i;
|
|
|
|
//GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (dvd_demux);
|
|
|
|
GST_INFO ("Resetting the dvd demuxer");
|
|
for (i = 0; i < GST_DVD_DEMUX_NUM_SUBPICTURE_STREAMS; i++) {
|
|
if (dvd_demux->subpicture_stream[i]) {
|
|
gst_pad_push_event (dvd_demux->subpicture_stream[i]->pad,
|
|
gst_event_new_eos ());
|
|
|
|
gst_element_remove_pad (GST_ELEMENT (dvd_demux),
|
|
dvd_demux->subpicture_stream[i]->pad);
|
|
g_free (dvd_demux->subpicture_stream[i]);
|
|
dvd_demux->subpicture_stream[i] = NULL;
|
|
}
|
|
}
|
|
gst_pad_set_caps (dvd_demux->cur_video, NULL);
|
|
gst_pad_set_caps (dvd_demux->cur_audio, NULL);
|
|
gst_pad_set_caps (dvd_demux->cur_subpicture, NULL);
|
|
|
|
dvd_demux->cur_video_nr = 0;
|
|
dvd_demux->cur_audio_nr = 0;
|
|
dvd_demux->cur_subpicture_nr = 0;
|
|
dvd_demux->mpeg_version = 0;
|
|
dvd_demux->last_end_ptm = INITIAL_END_PTM;
|
|
|
|
dvd_demux->discont_time = GST_CLOCK_TIME_NONE;
|
|
|
|
#if 0
|
|
/* Reset max_gap handling */
|
|
mpeg_demux->max_gap = GST_CLOCK_TIME_NONE;
|
|
mpeg_demux->max_gap_tolerance = GST_CLOCK_TIME_NONE;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
gst_dvd_demux_synchronise_pads (GstMPEGDemux * mpeg_demux,
|
|
GstClockTime threshold, GstClockTime new_ts)
|
|
{
|
|
GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_demux);
|
|
int i;
|
|
|
|
parent_class->synchronise_pads (mpeg_demux, threshold, new_ts);
|
|
|
|
for (i = 0; i < GST_DVD_DEMUX_NUM_SUBPICTURE_STREAMS; i++) {
|
|
if (dvd_demux->subpicture_stream[i]
|
|
&& (dvd_demux->subpicture_stream[i]->cur_ts < threshold)) {
|
|
DEMUX_CLASS (mpeg_demux)->sync_stream_to_time (mpeg_demux,
|
|
dvd_demux->subpicture_stream[i], new_ts);
|
|
dvd_demux->subpicture_stream[i]->cur_ts = new_ts;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_dvd_demux_sync_stream_to_time (GstMPEGDemux * mpeg_demux,
|
|
GstMPEGStream * stream, GstClockTime last_ts)
|
|
{
|
|
GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_demux);
|
|
|
|
#if 0
|
|
GstClockTime start_ts;
|
|
GstEvent *filler = NULL;
|
|
GstFormat fmt = GST_FORMAT_TIME;
|
|
#endif
|
|
GstPad *outpad = NULL;
|
|
gint cur_nr = 0;
|
|
|
|
parent_class->sync_stream_to_time (mpeg_demux, stream, last_ts);
|
|
|
|
switch (GST_MPEG_DEMUX_STREAM_KIND (stream->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_DVD_DEMUX_STREAM_SUBPICTURE:
|
|
outpad = dvd_demux->cur_subpicture;
|
|
cur_nr = dvd_demux->cur_subpicture_nr;
|
|
break;
|
|
}
|
|
|
|
#if 0
|
|
/* FIXME: fillers in 0.9 aren't specified properly yet */
|
|
if ((outpad != NULL) && (cur_nr == stream->number)) {
|
|
if (GST_PAD_PEER (stream->pad)
|
|
&& gst_pad_query_position (GST_PAD_PEER (stream->pad), &fmt,
|
|
(gint64 *) & start_ts)) {
|
|
if (start_ts < last_ts)
|
|
filler =
|
|
gst_event_new_filler_stamped (start_ts, GST_CLOCK_DIFF (last_ts,
|
|
start_ts));
|
|
} else
|
|
filler = gst_event_new_filler_stamped (last_ts, GST_CLOCK_TIME_NONE);
|
|
|
|
if (filler) {
|
|
if (!gst_pad_push_event (stream->pad, filler))
|
|
gst_event_unref (filler);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static GstStateChangeReturn
|
|
gst_dvd_demux_change_state (GstElement * element, GstStateChange transition)
|
|
{
|
|
GstDVDDemux *dvd_demux = GST_DVD_DEMUX (element);
|
|
|
|
switch (transition) {
|
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
|
gst_dvd_demux_reset (dvd_demux);
|
|
if (dvd_demux->langcodes) {
|
|
gst_event_unref (dvd_demux->langcodes);
|
|
dvd_demux->langcodes = NULL;
|
|
}
|
|
dvd_demux->ignore_next_newmedia_discont = FALSE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
|
}
|
|
|
|
gboolean
|
|
gst_dvd_demux_plugin_init (GstPlugin * plugin)
|
|
{
|
|
return gst_element_register (plugin, "dvddemux",
|
|
GST_RANK_SECONDARY, GST_TYPE_DVD_DEMUX);
|
|
}
|