struct _DVDReadSrcPrivate
{
- GstElement element;
/* pads */
GstPad *srcpad;
gboolean new_seek;
+ gboolean new_cell;
+
int title, chapter, angle;
int pgc_id, start_cell, cur_cell, cur_pack;
int ttn, pgn, next_cell;
pgc_t *cur_pgc;
};
+GST_DEBUG_CATEGORY_STATIC (gstdvdreadsrc_debug);
+#define GST_CAT_DEFAULT (gstdvdreadsrc_debug)
GstElementDetails dvdreadsrc_details = {
"DVD Source",
static void dvdreadsrc_base_init (gpointer g_class);
static void dvdreadsrc_class_init (DVDReadSrcClass * klass);
static void dvdreadsrc_init (DVDReadSrc * dvdreadsrc);
+static void dvdreadsrc_dispose (GObject * object);
static void dvdreadsrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void dvdreadsrc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-/*static GstData * dvdreadsrc_get (GstPad *pad); */
-static void dvdreadsrc_loop (GstElement * element);
+static GstData *dvdreadsrc_get (GstPad * pad);
/*static GstBuffer * dvdreadsrc_get_region (GstPad *pad,gulong offset,gulong size); */
gobject_class->set_property = GST_DEBUG_FUNCPTR (dvdreadsrc_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (dvdreadsrc_get_property);
+ gobject_class->dispose = dvdreadsrc_dispose;
+
gstelement_class->change_state = dvdreadsrc_change_state;
+
+ GST_DEBUG_CATEGORY_INIT (gstdvdreadsrc_debug, "dvdreadsrc", 0,
+ "DVD reader element based on dvdreadsrc");
}
static void
{
dvdreadsrc->priv = g_new (DVDReadSrcPrivate, 1);
dvdreadsrc->priv->srcpad = gst_pad_new ("src", GST_PAD_SRC);
+ gst_pad_set_get_function (dvdreadsrc->priv->srcpad, dvdreadsrc_get);
gst_element_add_pad (GST_ELEMENT (dvdreadsrc), dvdreadsrc->priv->srcpad);
- gst_element_set_loop_function (GST_ELEMENT (dvdreadsrc),
- GST_DEBUG_FUNCPTR (dvdreadsrc_loop));
dvdreadsrc->priv->location = g_strdup ("/dev/dvd");
- dvdreadsrc->priv->new_seek = FALSE;
- dvdreadsrc->priv->title = 1;
- dvdreadsrc->priv->chapter = 1;
- dvdreadsrc->priv->angle = 1;
+ dvdreadsrc->priv->new_seek = TRUE;
+ dvdreadsrc->priv->new_cell = TRUE;
+ dvdreadsrc->priv->title = 0;
+ dvdreadsrc->priv->chapter = 0;
+ dvdreadsrc->priv->angle = 0;
}
-/* FIXME: this code is not being used */
-#ifdef PLEASEFIXTHISCODE
static void
-dvdreadsrc_destroy (DVDReadSrc * dvdreadsrc)
+dvdreadsrc_dispose (GObject * object)
{
- /* FIXME */
- g_print ("FIXME\n");
- g_free (dvdreadsrc->priv);
+ DVDReadSrc *dvdreadsrc = DVDREADSRC (object);
+
+ if (dvdreadsrc->priv) {
+ g_free (dvdreadsrc->priv->location);
+ g_free (dvdreadsrc->priv);
+ dvdreadsrc->priv = NULL;
+ }
}
-#endif
static void
dvdreadsrc_set_property (GObject * object, guint prop_id, const GValue * value,
priv->location = g_strdup (g_value_get_string (value));
break;
case ARG_TITLE:
- priv->title = g_value_get_int (value) - 1;
+ priv->title = g_value_get_int (value);
priv->new_seek = TRUE;
break;
case ARG_CHAPTER:
- priv->chapter = g_value_get_int (value) - 1;
+ priv->chapter = g_value_get_int (value);
priv->new_seek = TRUE;
break;
case ARG_ANGLE:
- priv->angle = g_value_get_int (value) - 1;
+ priv->angle = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
g_value_set_string (value, priv->location);
break;
case ARG_TITLE:
- g_value_set_int (value, priv->title + 1);
+ g_value_set_int (value, priv->title);
break;
case ARG_CHAPTER:
- g_value_set_int (value, priv->chapter + 1);
+ g_value_set_int (value, priv->chapter);
break;
case ARG_ANGLE:
- g_value_set_int (value, priv->angle + 1);
+ g_value_set_int (value, priv->angle);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
*/
priv->dvd = DVDOpen (location);
if (!priv->dvd) {
- fprintf (stderr, "Couldn't open DVD: %s\n", location);
+ GST_ERROR ("Couldn't open DVD: %s", location);
return -1;
}
*/
priv->vmg_file = ifoOpen (priv->dvd, 0);
if (!priv->vmg_file) {
- fprintf (stderr, "Can't open VMG info.\n");
+ GST_ERROR ("Can't open VMG info");
DVDClose (priv->dvd);
return -1;
}
/**
* Make sure our title number is valid.
*/
- fprintf (stderr, "There are %d titles on this DVD.\n",
- priv->tt_srpt->nr_of_srpts);
+ GST_LOG ("There are %d titles on this DVD", priv->tt_srpt->nr_of_srpts);
if (title < 0 || title >= priv->tt_srpt->nr_of_srpts) {
- fprintf (stderr, "Invalid title %d.\n", title + 1);
+ GST_ERROR ("Invalid title %d (only %d available)",
+ title, priv->tt_srpt->nr_of_srpts);
ifoClose (priv->vmg_file);
DVDClose (priv->dvd);
return -1;
/**
* Make sure the chapter number is valid for this title.
*/
- fprintf (stderr, "There are %d chapters in this title.\n",
+ GST_LOG ("There are %d chapters in this title",
priv->tt_srpt->title[title].nr_of_ptts);
if (chapter < 0 || chapter >= priv->tt_srpt->title[title].nr_of_ptts) {
- fprintf (stderr, "Invalid chapter %d\n", chapter + 1);
+ GST_ERROR ("Invalid chapter %d (only %d available)",
+ chapter, priv->tt_srpt->title[title].nr_of_ptts);
ifoClose (priv->vmg_file);
DVDClose (priv->dvd);
return -1;
/**
* Make sure the angle number is valid for this title.
*/
- fprintf (stderr, "There are %d angles in this title.\n",
+ GST_LOG ("There are %d angles available in this title",
priv->tt_srpt->title[title].nr_of_angles);
if (angle < 0 || angle >= priv->tt_srpt->title[title].nr_of_angles) {
- fprintf (stderr, "Invalid angle %d\n", angle + 1);
+ GST_ERROR ("Invalid angle %d (only %d available)",
+ angle, priv->tt_srpt->title[title].nr_of_angles);
ifoClose (priv->vmg_file);
DVDClose (priv->dvd);
return -1;
priv->vts_file =
ifoOpen (priv->dvd, priv->tt_srpt->title[title].title_set_nr);
if (!priv->vts_file) {
- fprintf (stderr, "Can't open the title %d info file.\n",
+ GST_ERROR ("Can't open the info file of title %d",
priv->tt_srpt->title[title].title_set_nr);
ifoClose (priv->vmg_file);
DVDClose (priv->dvd);
priv->cur_pgc = priv->vts_file->vts_pgcit->pgci_srp[priv->pgc_id - 1].pgc;
priv->start_cell = priv->cur_pgc->program_map[priv->pgn - 1] - 1;
-
/**
* We've got enough info, time to open the title set data.
*/
DVDOpenFile (priv->dvd, priv->tt_srpt->title[title].title_set_nr,
DVD_READ_TITLE_VOBS);
if (!priv->dvd_title) {
- fprintf (stderr, "Can't open title VOBS (VTS_%02d_1.VOB).\n",
+ GST_ERROR ("Can't open title VOBS (VTS_%02d_1.VOB)",
priv->tt_srpt->title[title].title_set_nr);
ifoClose (priv->vts_file);
ifoClose (priv->vmg_file);
return 0;
}
-static void
-dvdreadsrc_loop (GstElement * element)
-{
- DVDReadSrc *dvdreadsrc;
- DVDReadSrcPrivate *priv;
-
- g_return_if_fail (element != NULL);
- g_return_if_fail (GST_IS_DVDREADSRC (element));
-
- dvdreadsrc = DVDREADSRC (element);
- priv = dvdreadsrc->priv;
- g_return_if_fail (GST_FLAG_IS_SET (dvdreadsrc, DVDREADSRC_OPEN));
-
- /**
- * Playback by cell in this pgc, starting at the cell for our chapter.
- */
- priv->next_cell = priv->start_cell;
- for (priv->cur_cell = priv->start_cell;
- priv->next_cell < priv->cur_pgc->nr_of_cells;) {
-
- priv->cur_cell = priv->next_cell;
-
- /* Check if we're entering an angle block. */
- if (priv->cur_pgc->cell_playback[priv->cur_cell].block_type
- == BLOCK_TYPE_ANGLE_BLOCK) {
- int i;
-
- priv->cur_cell += priv->angle;
- for (i = 0;; ++i) {
- if (priv->cur_pgc->cell_playback[priv->cur_cell + i].block_mode
- == BLOCK_MODE_LAST_CELL) {
- priv->next_cell = priv->cur_cell + i + 1;
- break;
- }
- }
- } else {
- priv->next_cell = priv->cur_cell + 1;
- }
-
-
- /**
- * We loop until we're out of this cell.
- */
- for (priv->cur_pack =
- priv->cur_pgc->cell_playback[priv->cur_cell].first_sector;
- priv->cur_pack <
- priv->cur_pgc->cell_playback[priv->cur_cell].last_sector;) {
-
- dsi_t dsi_pack;
- unsigned int next_vobu, next_ilvu_start, cur_output_size;
- GstBuffer *buf;
- unsigned char *data;
- int len;
-
- /* create the buffer */
- /* FIXME: should eventually use a bufferpool for this */
- buf = gst_buffer_new ();
- g_return_if_fail (buf);
-
- /* allocate the space for the buffer data */
- data = g_malloc (1024 * DVD_VIDEO_LB_LEN);
- GST_BUFFER_DATA (buf) = data;
-
- g_return_if_fail (GST_BUFFER_DATA (buf) != NULL);
-
- /**
- * Read NAV packet.
- */
- len = DVDReadBlocks (priv->dvd_title, priv->cur_pack, 1, data);
- if (len == 0) {
- fprintf (stderr, "Read failed for block %d\n", priv->cur_pack);
- _close (priv);
- gst_element_set_eos (GST_ELEMENT (dvdreadsrc));
- return;
- }
- assert (is_nav_pack (data));
-
-
- /**
- * Parse the contained dsi packet.
- */
- navRead_DSI (&dsi_pack, &(data[DSI_START_BYTE]));
- assert (priv->cur_pack == dsi_pack.dsi_gi.nv_pck_lbn);
- /*navPrint_DSI(&dsi_pack); */
-
-
- /**
- * Determine where we go next. These values are the ones we mostly
- * care about.
- */
- next_ilvu_start = priv->cur_pack
- + dsi_pack.sml_agli.data[priv->angle].address;
- cur_output_size = dsi_pack.dsi_gi.vobu_ea;
-
-
- /**
- * If we're not at the end of this cell, we can determine the next
- * VOBU to display using the VOBU_SRI information section of the
- * DSI. Using this value correctly follows the current angle,
- * avoiding the doubled scenes in The Matrix, and makes our life
- * really happy.
- *
- * Otherwise, we set our next address past the end of this cell to
- * force the code above to go to the next cell in the program.
- */
- if (dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL) {
- next_vobu = priv->cur_pack + (dsi_pack.vobu_sri.next_vobu & 0x7fffffff);
- } else {
- next_vobu = priv->cur_pack + cur_output_size + 1;
- }
-
- assert (cur_output_size < 1024);
- priv->cur_pack++;
-
- /**
- * Read in and output cursize packs.
- */
- len = DVDReadBlocks (priv->dvd_title, priv->cur_pack,
- cur_output_size, data);
- if (len != cur_output_size) {
- fprintf (stderr, "Read failed for %d blocks at %d\n",
- cur_output_size, priv->cur_pack);
- _close (priv);
- gst_element_set_eos (GST_ELEMENT (dvdreadsrc));
- return;
- }
-
- GST_BUFFER_SIZE (buf) = cur_output_size * DVD_VIDEO_LB_LEN;
- gst_pad_push (priv->srcpad, GST_DATA (buf));
- priv->cur_pack = next_vobu;
- }
- }
-}
+/*
+ * Read function.
+ * -1: error, -2: eos, -3: try again, 0: ok.
+ */
-#if 0
static int
_read (DVDReadSrcPrivate * priv, int angle, int new_seek, GstBuffer * buf)
{
priv->next_cell = priv->start_cell;
priv->cur_cell = priv->start_cell;
}
- if (priv->next_cell < priv->cur_pgc->nr_of_cells) {
- priv->cur_cell = priv->next_cell;
+ if (priv->next_cell < priv->cur_pgc->nr_of_cells) {
+ if (priv->new_cell)
+ priv->cur_cell = priv->next_cell;
/* Check if we're entering an angle block. */
if (priv->cur_pgc->cell_playback[priv->cur_cell].block_type
}
if (priv->cur_pack <
- priv->cur_pgc->cell_playback[priv->cur_cell].last_sector;) {
-
+ priv->cur_pgc->cell_playback[priv->cur_cell].last_sector) {
dsi_t dsi_pack;
unsigned int next_vobu, next_ilvu_start, cur_output_size;
int len;
-
/**
* Read NAV packet.
*/
- len = DVDReadBlocks (priv->title, priv->cur_pack, 1, data);
+ len = DVDReadBlocks (priv->dvd_title, priv->cur_pack, 1, data);
if (len == 0) {
- fprintf (stderr, "Read failed for block %d\n", priv->cur_pack);
- _close (priv);
+ GST_ERROR ("Read failed for block %d", priv->cur_pack);
return -1;
}
assert (is_nav_pack (data));
/**
* Parse the contained dsi packet.
*/
- navRead_DSI (&dsi_pack, &(data[DSI_START_BYTE]), sizeof (dsi_t));
+ navRead_DSI (&dsi_pack, &(data[DSI_START_BYTE]));
assert (priv->cur_pack == dsi_pack.dsi_gi.nv_pck_lbn);
/**
* Read in and output cursize packs.
*/
- len = DVDReadBlocks (priv->title, priv->cur_pack, cur_output_size, data);
+ len =
+ DVDReadBlocks (priv->dvd_title, priv->cur_pack, cur_output_size,
+ data);
if (len != cur_output_size) {
- fprintf (stderr, "Read failed for %d blocks at %d\n",
+ GST_ERROR ("Read failed for %d blocks at %d",
cur_output_size, priv->cur_pack);
- _close (priv);
return -1;
}
GST_BUFFER_SIZE (buf) = cur_output_size * DVD_VIDEO_LB_LEN;
priv->cur_pack = next_vobu;
+
+ return 0;
+ } else {
+ priv->new_cell = TRUE;
}
} else {
- return -1;
+ return -2;
}
- return 0;
+ /* again */
+ return -3;
}
static GstData *
dvdreadsrc_get (GstPad * pad)
{
+ gint res;
DVDReadSrc *dvdreadsrc;
DVDReadSrcPrivate *priv;
GstBuffer *buf;
/* create the buffer */
/* FIXME: should eventually use a bufferpool for this */
- buf = gst_buffer_new ();
- g_return_val_if_fail (buf, NULL);
-
- /* allocate the space for the buffer data */
- GST_BUFFER_DATA (buf) = g_malloc (1024 * DVD_VIDEO_LB_LEN);
- g_return_val_if_fail (GST_BUFFER_DATA (buf) != NULL, NULL);
+ buf = gst_buffer_new_and_alloc (1024 * DVD_VIDEO_LB_LEN);
if (priv->new_seek) {
- _seek (priv, priv->titleid, priv->chapid, priv->angle);
+ _seek (priv, priv->title, priv->chapter, priv->angle);
}
/* read it in from the file */
- if (_read (priv, priv->angle, priv->new_seek, buf)) {
- gst_element_signal_eos (GST_ELEMENT (dvdreadsrc));
- return NULL;
+ while ((res = _read (priv, priv->angle, priv->new_seek, buf)) == -3);
+ switch (res) {
+ case -1:
+ GST_ELEMENT_ERROR (dvdreadsrc, RESOURCE, READ, (NULL), (NULL));
+ gst_buffer_unref (buf);
+ return NULL;
+ case -2:
+ gst_element_set_eos (GST_ELEMENT (dvdreadsrc));
+ gst_buffer_unref (buf);
+ return GST_DATA (gst_event_new (GST_EVENT_EOS));
+ case 0:
+ break;
+ default:
+ g_assert_not_reached ();
}
- if (priv->new_seek) {
- priv->new_seek = FALSE;
- }
+ priv->new_seek = FALSE;
- return buf;
+ return GST_DATA (buf);
}
-#endif
/* open the file, necessary to go to RUNNING state */
static gboolean
g_return_val_if_fail (GST_IS_DVDREADSRC (src), FALSE);
g_return_val_if_fail (!GST_FLAG_IS_SET (src, DVDREADSRC_OPEN), FALSE);
- if (_open (src->priv, src->priv->location))
+ if (_open (src->priv, src->priv->location)) {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), (NULL));
return FALSE;
- if (_seek (src->priv, src->priv->title, src->priv->chapter, src->priv->angle))
+ }
+ if (_seek (src->priv, src->priv->title, src->priv->chapter, src->priv->angle)) {
+ GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (NULL), (NULL));
return FALSE;
+ }
GST_FLAG_SET (src, DVDREADSRC_OPEN);
static GstElementStateReturn
dvdreadsrc_change_state (GstElement * element)
{
+ DVDReadSrc *dvdreadsrc = DVDREADSRC (element);
+
g_return_val_if_fail (GST_IS_DVDREADSRC (element), GST_STATE_FAILURE);
GST_DEBUG ("gstdvdreadsrc: state pending %d", GST_STATE_PENDING (element));
/* if going down into NULL state, close the file if it's open */
- if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
- if (GST_FLAG_IS_SET (element, DVDREADSRC_OPEN))
- dvdreadsrc_close_file (DVDREADSRC (element));
- /* otherwise (READY or higher) we need to open the file */
- } else {
- if (!GST_FLAG_IS_SET (element, DVDREADSRC_OPEN)) {
+ switch (GST_STATE_TRANSITION (element)) {
+ case GST_STATE_NULL_TO_READY:
if (!dvdreadsrc_open_file (DVDREADSRC (element)))
return GST_STATE_FAILURE;
- }
+ break;
+ case GST_STATE_PAUSED_TO_READY:
+ dvdreadsrc->priv->new_cell = TRUE;
+ dvdreadsrc->priv->new_seek = TRUE;
+ dvdreadsrc->priv->chapter = 0;
+ dvdreadsrc->priv->title = 0;
+ break;
+ case GST_STATE_READY_TO_NULL:
+ dvdreadsrc_close_file (DVDREADSRC (element));
+ break;
+ default:
+ break;
}
/* if we haven't failed already, give the parent class a chance to ;-) */
/* 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 }, " \
mpeg_parse_class->send_data = gst_dvd_demux_send_data;
+ /* 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);
klass->cur_video_template = gst_static_pad_template_get (&cur_video_template);
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);
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;
/* Start the timestamp sequence in 0. */
dvd_demux->last_end_ptm = 0;
+ /* (Ronald) so, this was disabled. I'm enabling (default) it again.
+ * Timestamp adjustment is fairly evil, we would ideally use discont
+ * events instead. However, our current clocking has a pretty serious
+ * race condition: imagine that $pipeline is at time 30sec and $audio
+ * receives a discont to 0sec. Video processes its last buffer and
+ * calls _wait() on $timestamp, which is 30s - so we wait (hang) 30sec.
+ * This is unacceptable, obviously, and timestamp adjustment, no matter
+ * how evil, solves this.
+ * Before disabling this again, tripple check that al .vob files on our
+ * websites /media/ directory work fine, especially bullet.vob and
+ * barrage.vob.
+ */
+#if 0
/* Try to prevent the mpegparse infrastructure from doing timestamp
adjustment. */
mpeg_parse->do_adjust = FALSE;
mpeg_parse->adjust = 0;
+#endif
dvd_demux->just_flushed = FALSE;
dvd_demux->discont_time = GST_CLOCK_TIME_NONE;
guint8 sample_info = 0;
GstMPEGStream *str;
GstDVDLPCMStream *lpcm_str = NULL;
- gchar *name;
GstCaps *caps;
gint width, rate, channels;
+ gboolean add_pad = FALSE;
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 &&
str = mpeg_demux->audio_stream[stream_nr];
if (str == NULL) {
+ gchar *name;
+
if (type != GST_DVD_DEMUX_AUDIO_LPCM) {
str = g_new0 (GstMPEGStream, 1);
} else {
/* update caps */
str->type = GST_MPEG_DEMUX_AUDIO_UNKNOWN;
g_free (name);
+ add_pad = TRUE;
mpeg_demux->audio_stream[stream_nr] = str;
} else {
/* This is the current audio stream. Use the same caps. */
gst_pad_set_explicit_caps (dvd_demux->cur_audio, gst_caps_copy (caps));
}
+ if (add_pad)
+ gst_element_add_pad (GST_ELEMENT (mpeg_demux), str->pad);
str->type = type;
}
GstMPEGStream *str;
gchar *name;
GstCaps *caps;
+ gboolean add_pad = FALSE;
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 &&
DEMUX_CLASS (dvd_demux)->init_stream (mpeg_demux, type, str, stream_nr,
name, CLASS (dvd_demux)->subpicture_template);
g_free (name);
+ add_pad = TRUE;
dvd_demux->subpicture_stream[stream_nr] = str;
} else {
}
gst_caps_free (caps);
+ if (add_pad)
+ gst_element_add_pad (GST_ELEMENT (mpeg_demux), str->pad);
str->type = GST_DVD_DEMUX_SUBP_DVD;
}
gst_dvd_demux_plugin_init (GstPlugin * plugin)
{
return gst_element_register (plugin, "dvddemux",
- GST_RANK_PRIMARY - 1, GST_TYPE_DVD_DEMUX);
+ GST_RANK_PRIMARY, GST_TYPE_DVD_DEMUX);
}
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sink_template));
-
klass->video_template = gst_static_pad_template_get (&video_template);
klass->audio_template = gst_static_pad_template_get (&audio_template);
klass->private_template = gst_static_pad_template_get (&private_template);
klass->get_private_stream = gst_mpeg_demux_get_private_stream;
klass->send_subbuffer = gst_mpeg_demux_send_subbuffer;
klass->process_private = gst_mpeg_demux_process_private;
+
+ /* we have our own sink pad template, but don't use it in subclasses */
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sink_template));
}
static void
gst_mpeg_demux_init (GstMPEGDemux * mpeg_demux)
{
gint i;
- GstMPEGParse *mpeg_parse = GST_MPEG_PARSE (mpeg_demux);
-
- gst_element_remove_pad (GST_ELEMENT (mpeg_parse), mpeg_parse->sinkpad);
- mpeg_parse->sinkpad =
- gst_pad_new_from_template (gst_static_pad_template_get (&sink_template),
- "sink");
- gst_element_add_pad (GST_ELEMENT (mpeg_parse), mpeg_parse->sinkpad);
- gst_element_remove_pad (GST_ELEMENT (mpeg_parse), mpeg_parse->srcpad);
/* i think everything is already zero'd, but oh well */
for (i = 0; i < GST_MPEG_DEMUX_NUM_VIDEO_STREAMS; i++) {
gst_pad_set_query_function (pad, gst_mpeg_parse_handle_src_query);
gst_pad_use_explicit_caps (pad);
- gst_element_add_pad (GST_ELEMENT (mpeg_demux), pad);
-
return pad;
}
GST_ELEMENT_ERROR (GST_ELEMENT (mpeg_demux),
CORE, NEGOTIATION, (NULL), ("failed to set caps"));
gst_caps_free (caps);
+ gst_element_add_pad (GST_ELEMENT (mpeg_demux), str->pad);
return str;
}
gst_caps_free (caps);
+ gst_element_add_pad (GST_ELEMENT (mpeg_demux), str->pad);
/* Store the current values. */
video_str->mpeg_version = mpeg_version;
GST_ELEMENT_ERROR (GST_ELEMENT (mpeg_demux),
CORE, NEGOTIATION, (NULL), ("failed to set caps"));
gst_caps_free (caps);
+ gst_element_add_pad (GST_ELEMENT (mpeg_demux), str->pad);
return str;
}
gst_caps_free (caps);
+ gst_element_add_pad (GST_ELEMENT (mpeg_demux), str->pad);
}
return str;
CLASS (mpeg_demux)->init_stream (mpeg_demux, type, str, stream_nr, name,
CLASS (mpeg_demux)->private_template);
g_free (name);
+ gst_element_add_pad (GST_ELEMENT (mpeg_demux), str->pad);
mpeg_demux->private_stream[stream_nr] = str;
}
guint16 datalen;
guint16 headerlen;
- GstClockTime timestamp = GST_CLOCK_TIME_NONE;
+ GstClockTime timestamp;
GstMPEGStream *outstream = NULL;
guint8 *buf;
id, pts, MPEGTIME_TO_GSTTIME (pts));
pts += mpeg_parse->adjust;
- timestamp = MPEGTIME_TO_GSTTIME (pts) + mpeg_demux->adjust;;
+ timestamp = MPEGTIME_TO_GSTTIME (pts) + mpeg_demux->adjust;
} else {
timestamp = GST_CLOCK_TIME_NONE;
}
/* constant corresponds to the 2 bytes of the packet length. */
headerlen = 2;
datalen = packet_length;
+
+ timestamp = GST_CLOCK_TIME_NONE;
}
GST_DEBUG_OBJECT (mpeg_demux, "headerlen is %d, datalen is %d",
gst_mpeg_demux_plugin_init (GstPlugin * plugin)
{
return gst_element_register (plugin, "mpegdemux",
- GST_RANK_PRIMARY, GST_TYPE_MPEG_DEMUX);
+ GST_RANK_SECONDARY, GST_TYPE_MPEG_DEMUX);
}
static void gst_mpeg_parse_send_discont (GstMPEGParse * mpeg_parse,
GstClockTime time);
+static void gst_mpeg_parse_new_pad (GstElement * element, GstPad * pad);
+
static void gst_mpeg_parse_loop (GstElement * element);
static void gst_mpeg_parse_get_property (GObject * object, guint prop_id,
gobject_class->get_property = gst_mpeg_parse_get_property;
gobject_class->set_property = gst_mpeg_parse_set_property;
+ gstelement_class->new_pad = gst_mpeg_parse_new_pad;
gstelement_class->change_state = gst_mpeg_parse_change_state;
gstelement_class->set_clock = gst_mpeg_parse_set_clock;
gstelement_class->get_index = gst_mpeg_parse_get_index;
static void
gst_mpeg_parse_init (GstMPEGParse * mpeg_parse)
{
- mpeg_parse->sinkpad =
- gst_pad_new_from_template (gst_static_pad_template_get (&sink_factory),
- "sink");
+ GstElementClass *klass = GST_ELEMENT_GET_CLASS (mpeg_parse);
+ GstPadTemplate *templ;
+
+ templ = gst_element_class_get_pad_template (klass, "sink");
+ mpeg_parse->sinkpad = gst_pad_new_from_template (templ, "sink");
gst_element_add_pad (GST_ELEMENT (mpeg_parse), mpeg_parse->sinkpad);
gst_pad_set_formats_function (mpeg_parse->sinkpad,
gst_mpeg_parse_get_src_formats);
gst_pad_set_convert_function (mpeg_parse->sinkpad,
gst_mpeg_parse_convert_src);
- mpeg_parse->srcpad =
- gst_pad_new_from_template (gst_static_pad_template_get (&src_factory),
- "src");
- gst_element_add_pad (GST_ELEMENT (mpeg_parse), mpeg_parse->srcpad);
- gst_pad_set_formats_function (mpeg_parse->srcpad,
- gst_mpeg_parse_get_src_formats);
- gst_pad_set_convert_function (mpeg_parse->srcpad, gst_mpeg_parse_convert_src);
- gst_pad_set_event_mask_function (mpeg_parse->srcpad,
- gst_mpeg_parse_get_src_event_masks);
- gst_pad_set_event_function (mpeg_parse->srcpad,
- gst_mpeg_parse_handle_src_event);
- gst_pad_set_query_type_function (mpeg_parse->srcpad,
- gst_mpeg_parse_get_src_query_types);
- gst_pad_set_query_function (mpeg_parse->srcpad,
- gst_mpeg_parse_handle_src_query);
- gst_pad_use_explicit_caps (mpeg_parse->srcpad);
+ if ((templ = gst_element_class_get_pad_template (klass, "src"))) {
+ mpeg_parse->srcpad = gst_pad_new_from_template (templ, "src");
+ gst_element_add_pad (GST_ELEMENT (mpeg_parse), mpeg_parse->srcpad);
+ gst_pad_set_formats_function (mpeg_parse->srcpad,
+ gst_mpeg_parse_get_src_formats);
+ gst_pad_set_convert_function (mpeg_parse->srcpad,
+ gst_mpeg_parse_convert_src);
+ gst_pad_set_event_mask_function (mpeg_parse->srcpad,
+ gst_mpeg_parse_get_src_event_masks);
+ gst_pad_set_event_function (mpeg_parse->srcpad,
+ gst_mpeg_parse_handle_src_event);
+ gst_pad_set_query_type_function (mpeg_parse->srcpad,
+ gst_mpeg_parse_get_src_query_types);
+ gst_pad_set_query_function (mpeg_parse->srcpad,
+ gst_mpeg_parse_handle_src_query);
+ gst_pad_use_explicit_caps (mpeg_parse->srcpad);
+ }
gst_element_set_loop_function (GST_ELEMENT (mpeg_parse), gst_mpeg_parse_loop);
}
}
+static void
+gst_mpeg_parse_new_pad (GstElement * element, GstPad * pad)
+{
+ GstMPEGParse *mpeg_parse;
+
+ if (GST_PAD_IS_SINK (pad))
+ return;
+
+ mpeg_parse = GST_MPEG_PARSE (element);
+
+ /* For each new added pad, send a discont so it knows about the current
+ * time. This is required because MPEG allows any sort of order of
+ * packets, including setting base time before defining streams or
+ * even adding streams halfway a stream. */
+ if (!mpeg_parse->scr_pending && !mpeg_parse->do_adjust) {
+ GstEvent *event = gst_event_new_discontinuous (FALSE,
+ GST_FORMAT_TIME,
+ (guint64) MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr +
+ mpeg_parse->adjust),
+ GST_FORMAT_UNDEFINED);
+
+ gst_pad_push (pad, GST_DATA (event));
+ }
+}
+
static gboolean
gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer)
{
G_GUINT64_FORMAT " real:%" G_GINT64_FORMAT " adjust:%" G_GINT64_FORMAT,
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;
GST_DEBUG ("new adjust: %" G_GINT64_FORMAT, mpeg_parse->adjust);
+ } else {
+ mpeg_parse->discont_pending = TRUE;
}
}