From 4c81add3e6fee8b59b9e107fa8262be65cbc0e3d Mon Sep 17 00:00:00 2001 From: Martin Soto Date: Mon, 19 Dec 2005 17:26:47 +0000 Subject: [PATCH] Big mpegparse clean up, second round: Original commit message from CVS: 2005-12-19 Martin Soto Big mpegparse clean up, second round: * gst/mpegstream/gstdvddemux.c (gst_dvd_demux_handle_dvd_event): Send and EOS event down the audio pipeline when an still frame event arrives. This prevents the pipeline from locking when a still menu comes directly after a flush. * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_reset): Don't send a newsegment in reset. (gst_mpeg_parse_adjust_ts): Check for invalid timestamps. (gst_mpeg_parse_handle_newsegment, gst_mpeg_parse_process_event): Move the code of handle_newsegment to process_event. Send a NEWSEGMENT after FLUSH_STOP. (gst_mpeg_parse_change_state): Send a NEWSEGMENT right after moving to PAUSED. * gst/mpegstream/gstmpegdemux.c (gst_mpeg_demux_send_event) (gst_mpeg_demux_class_init): Don't override send_event. * gst/mpegstream/gstmpegdemux.c (gst_mpeg_demux_init) (gst_mpeg_demux_send_event, gst_mpeg_demux_send_subbuffer) (gst_mpeg_demux_reset): * gst/mpegstream/gstmpegdemux.h: Get rid of just_flushed attribute. * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_process_event): Reset the mpegparse element after a flush. * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_handle_newsegment): Don't forward events. * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_process_event): * gst/mpegstream/gstmpegparse.h (struct _GstMPEGParseClass): handle_newsegment is not a virtual method anymore. * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_send_newsegment) (gst_mpeg_parse_reset, gst_mpeg_parse_class_init): * gst/mpegstream/gstmpegparse.h (struct _GstMPEGParseClass): Get rid of send_newsegment virtual method. * gst/mpegstream/gstdvddemux.c (gst_dvd_demux_process_event): Only handle DVD events and call the superclass method for other event types. * gst/mpegstream/gstmpegdemux.c (gst_mpeg_demux_send_event): Don't override process_event anymore. * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_event) (gst_mpeg_parse_process_event): Move actual event processing to process event so that subclasses can properly override or extend it. * gst/mpegstream/gstmpegparse.h (struct _GstMPEGParseClass): Eliminate time parameter in process event. * gst/mpegstream/gstmpegdemux.c (gst_mpeg_demux_init) (gst_mpeg_demux_parse_packet, gst_mpeg_demux_parse_pes) (gst_mpeg_demux_send_subbuffer): * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_class_init) (gst_mpeg_parse_parse_packhead, gst_mpeg_parse_event) (gst_mpeg_parse_chain): Use the new adjust_ts method instead of adding the value of the adjust attribute. * gst/mpegstream/gstmpegdemux.h (struct _GstMPEGVideoStream): Get rid of the adjust attribute. Now all timestamp adjustments are performed by mpegparse using the current segment. * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_adjust_ts) (gst_mpeg_parse_class_init): Implement the adjust_ts method based on the adjust attribute for SCR values and the current segment. * gst/mpegstream/gstmpegparse.h (struct _GstMPEGParseClass): New adjust_ts virtual method to adjust timestamps for outgoing buffers. * gst/mpegstream/gstmpegdemux.c (gst_mpeg_demux_send_newsegment) (gst_mpeg_demux_parse_packet): Don't override send_newsegment. * gst/mpegstream/gstdvddemux.c (gst_dvd_demux_class_init) (gst_dvd_demux_handle_newsegment): Don't override handle_newsegment. (gst_dvd_demux_process_event, gst_dvd_demux_handle_dvd_event): Check for DVD events in process_event instead of handle_dvd_event. * gst/mpegstream/gstmpegparse.h (struct _GstMPEGParseClass): * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_handle_newsegment) (gst_mpeg_parse_send_newsegment, gst_mpeg_parse_send_event): * gst/mpegstream/gstmpegdemux.c (gst_mpeg_demux_process_event) (gst_mpeg_demux_send_event): * gst/mpegstream/gstdvddemux.c (gst_dvd_demux_process_event) (gst_dvd_demux_handle_dvd_event): Eliminate the time parameter in send_event. --- ChangeLog | 86 ++++++++++++++ gst/mpegstream/gstdvddemux.c | 64 +++------- gst/mpegstream/gstmpegdemux.c | 115 +++--------------- gst/mpegstream/gstmpegdemux.h | 22 ++-- gst/mpegstream/gstmpegparse.c | 217 +++++++++++++++++----------------- gst/mpegstream/gstmpegparse.h | 16 +-- 6 files changed, 238 insertions(+), 282 deletions(-) diff --git a/ChangeLog b/ChangeLog index 924ce3f187..0ff0e3193d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,89 @@ +2005-12-19 Martin Soto + + Big mpegparse clean up, second round: + + * gst/mpegstream/gstdvddemux.c (gst_dvd_demux_handle_dvd_event): + Send and EOS event down the audio pipeline when an still frame + event arrives. This prevents the pipeline from locking when a + still menu comes directly after a flush. + + * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_reset): + Don't send a newsegment in reset. + (gst_mpeg_parse_adjust_ts): Check for invalid timestamps. + (gst_mpeg_parse_handle_newsegment, gst_mpeg_parse_process_event): + Move the code of handle_newsegment to process_event. Send a + NEWSEGMENT after FLUSH_STOP. + (gst_mpeg_parse_change_state): Send a NEWSEGMENT right after + moving to PAUSED. + + * gst/mpegstream/gstmpegdemux.c (gst_mpeg_demux_send_event) + (gst_mpeg_demux_class_init): Don't override send_event. + * gst/mpegstream/gstmpegdemux.c (gst_mpeg_demux_init) + (gst_mpeg_demux_send_event, gst_mpeg_demux_send_subbuffer) + (gst_mpeg_demux_reset): + * gst/mpegstream/gstmpegdemux.h: Get rid of just_flushed + attribute. + + * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_process_event): + Reset the mpegparse element after a flush. + + * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_handle_newsegment): + Don't forward events. + * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_process_event): + * gst/mpegstream/gstmpegparse.h (struct _GstMPEGParseClass): + handle_newsegment is not a virtual method anymore. + + * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_send_newsegment) + (gst_mpeg_parse_reset, gst_mpeg_parse_class_init): + * gst/mpegstream/gstmpegparse.h (struct _GstMPEGParseClass): Get + rid of send_newsegment virtual method. + + * gst/mpegstream/gstdvddemux.c (gst_dvd_demux_process_event): Only + handle DVD events and call the superclass method for other event + types. + * gst/mpegstream/gstmpegdemux.c (gst_mpeg_demux_send_event): Don't + override process_event anymore. + * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_event) + (gst_mpeg_parse_process_event): Move actual event processing to + process event so that subclasses can properly override or extend + it. + * gst/mpegstream/gstmpegparse.h (struct _GstMPEGParseClass): + Eliminate time parameter in process event. + + * gst/mpegstream/gstmpegdemux.c (gst_mpeg_demux_init) + (gst_mpeg_demux_parse_packet, gst_mpeg_demux_parse_pes) + (gst_mpeg_demux_send_subbuffer): + * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_class_init) + (gst_mpeg_parse_parse_packhead, gst_mpeg_parse_event) + (gst_mpeg_parse_chain): Use the new adjust_ts method instead of + adding the value of the adjust attribute. + * gst/mpegstream/gstmpegdemux.h (struct _GstMPEGVideoStream): Get + rid of the adjust attribute. Now all timestamp adjustments are + performed by mpegparse using the current segment. + * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_adjust_ts) + (gst_mpeg_parse_class_init): Implement the adjust_ts method based + on the adjust attribute for SCR values and the current segment. + * gst/mpegstream/gstmpegparse.h (struct _GstMPEGParseClass): New + adjust_ts virtual method to adjust timestamps for outgoing + buffers. + * gst/mpegstream/gstmpegdemux.c (gst_mpeg_demux_send_newsegment) + (gst_mpeg_demux_parse_packet): Don't override send_newsegment. + * gst/mpegstream/gstdvddemux.c (gst_dvd_demux_class_init) + (gst_dvd_demux_handle_newsegment): Don't override + handle_newsegment. + (gst_dvd_demux_process_event, gst_dvd_demux_handle_dvd_event): + Check for DVD events in process_event instead of + handle_dvd_event. + + * gst/mpegstream/gstmpegparse.h (struct _GstMPEGParseClass): + * gst/mpegstream/gstmpegparse.c (gst_mpeg_parse_handle_newsegment) + (gst_mpeg_parse_send_newsegment, gst_mpeg_parse_send_event): + * gst/mpegstream/gstmpegdemux.c (gst_mpeg_demux_process_event) + (gst_mpeg_demux_send_event): + * gst/mpegstream/gstdvddemux.c (gst_dvd_demux_process_event) + (gst_dvd_demux_handle_dvd_event): + Eliminate the time parameter in send_event. + 2005-12-18 Jan Schmidt * ext/mad/gstid3tag.c: (gst_id3_tag_do_typefind), diff --git a/gst/mpegstream/gstdvddemux.c b/gst/mpegstream/gstdvddemux.c index f6fd0935ba..606eeb2fd4 100644 --- a/gst/mpegstream/gstdvddemux.c +++ b/gst/mpegstream/gstdvddemux.c @@ -142,10 +142,8 @@ static void gst_dvd_demux_init (GstDVDDemux * dvd_demux, 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); + GstEvent * event); -static gboolean gst_dvd_demux_handle_newsegment (GstMPEGParse * mpeg_parse, - GstEvent * event, gboolean forward); static gboolean gst_dvd_demux_handle_dvd_event (GstDVDDemux * dvd_demux, GstEvent * event); @@ -244,8 +242,6 @@ gst_dvd_demux_class_init (GstDVDDemuxClass * klass) gstelement_class->change_state = gst_dvd_demux_change_state; - mpeg_parse_class->handle_newsegment = gst_dvd_demux_handle_newsegment; - 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; @@ -299,51 +295,31 @@ gst_dvd_demux_send_buffer (GstMPEGParse * mpeg_parse, GstBuffer * buffer, } static gboolean -gst_dvd_demux_process_event (GstMPEGParse * mpeg_parse, GstEvent * event, - GstClockTime time) +gst_dvd_demux_process_event (GstMPEGParse * mpeg_parse, GstEvent * event) { GstDVDDemux *dvd_demux = GST_DVD_DEMUX (mpeg_parse); gboolean ret = TRUE; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CUSTOM_DOWNSTREAM: - if (!gst_dvd_demux_handle_dvd_event (dvd_demux, event)) { - ret = GST_FLOW_ERROR; + case GST_EVENT_CUSTOM_DOWNSTREAM_OOB: + if (gst_structure_has_name (gst_event_get_structure (event), + "application/x-gst-dvd")) { + ret = gst_dvd_demux_handle_dvd_event (dvd_demux, event); + } else { + ret = GST_MPEG_PARSE_CLASS (parent_class)->process_event (mpeg_parse, + event); } break; - /* 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); + ret = GST_MPEG_PARSE_CLASS (parent_class)->process_event (mpeg_parse, + event); break; } return ret; } -static gboolean -gst_dvd_demux_handle_newsegment (GstMPEGParse * mpeg_parse, - GstEvent * event, gboolean forward) -{ - gboolean ret; - - /* Run the superclass implementation to update the current segment. */ - ret = GST_MPEG_PARSE_CLASS (parent_class)->handle_newsegment (mpeg_parse, - event, FALSE); - - /* Use the current segment to adjust timestamps. */ - GST_MPEG_DEMUX (mpeg_parse)->adjust = mpeg_parse->current_segment.accum - - mpeg_parse->current_segment.start; - - return ret; -} - static gboolean gst_dvd_demux_handle_dvd_event (GstDVDDemux * dvd_demux, GstEvent * event) { @@ -363,16 +339,6 @@ gst_dvd_demux_handle_dvd_event (GstDVDDemux * dvd_demux, GstEvent * event) } #endif - if (strcmp (gst_structure_get_name (structure), "application/x-gst-dvd") != 0) { - /* 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; @@ -395,6 +361,11 @@ gst_dvd_demux_handle_dvd_event (GstDVDDemux * dvd_demux, GstEvent * event) } gst_dvd_demux_set_cur_subpicture (dvd_demux, stream_nr); gst_event_unref (event); + } else if (strcmp (event_type, "dvd-spu-still-frame") == 0) { + /* Send an EOS down the audio path, to allow for preroll in the + absence of audio material. */ + gst_event_unref (event); + return gst_pad_push_event (dvd_demux->cur_audio, gst_event_new_eos ()); } else if (!strcmp (event_type, "dvd-lang-codes")) { gint num_substreams = 0, num_audstreams = 0, n; gchar *t; @@ -469,8 +440,7 @@ gst_dvd_demux_handle_dvd_event (GstDVDDemux * dvd_demux, GstEvent * event) 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); + PARSE_CLASS (dvd_demux)->send_event (mpeg_parse, event); } return TRUE; diff --git a/gst/mpegstream/gstmpegdemux.c b/gst/mpegstream/gstmpegdemux.c index 3d9dfcba51..4f5731b637 100644 --- a/gst/mpegstream/gstmpegdemux.c +++ b/gst/mpegstream/gstmpegdemux.c @@ -94,12 +94,6 @@ static void gst_mpeg_demux_class_init (GstMPEGDemuxClass * klass); static GstFlowReturn gst_mpeg_demux_send_buffer (GstMPEGParse * mpeg_parse, GstBuffer * buffer, GstClockTime time); -static gboolean gst_mpeg_demux_process_event (GstMPEGParse * mpeg_parse, - GstEvent * event, GstClockTime time); -static gboolean gst_mpeg_demux_send_newsegment (GstMPEGParse * parse, - gdouble rate, GstClockTime start_time, GstClockTime stop_time); -static gboolean gst_mpeg_demux_send_event (GstMPEGParse * mpeg_parse, - GstEvent * event, GstClockTime time); static GstPad *gst_mpeg_demux_new_output_pad (GstMPEGDemux * mpeg_demux, const gchar * name, GstPadTemplate * temp); @@ -197,9 +191,6 @@ gst_mpeg_demux_class_init (GstMPEGDemuxClass * klass) mpeg_parse_class->parse_packet = gst_mpeg_demux_parse_packet; mpeg_parse_class->parse_pes = gst_mpeg_demux_parse_pes; mpeg_parse_class->send_buffer = gst_mpeg_demux_send_buffer; - mpeg_parse_class->process_event = gst_mpeg_demux_process_event; - mpeg_parse_class->send_newsegment = gst_mpeg_demux_send_newsegment; - mpeg_parse_class->send_event = gst_mpeg_demux_send_event; klass->new_output_pad = gst_mpeg_demux_new_output_pad; klass->init_stream = gst_mpeg_demux_init_stream; @@ -232,10 +223,8 @@ gst_mpeg_demux_init (GstMPEGDemux * mpeg_demux, GstMPEGDemuxClass * klass) mpeg_demux->private_stream[i] = NULL; } - mpeg_demux->adjust = 0; mpeg_demux->max_gap = GST_CLOCK_TIME_NONE; mpeg_demux->max_gap_tolerance = GST_CLOCK_TIME_NONE; - mpeg_demux->just_flushed = FALSE; } static GstFlowReturn @@ -246,80 +235,6 @@ gst_mpeg_demux_send_buffer (GstMPEGParse * mpeg_parse, GstBuffer * buffer, return GST_FLOW_OK; } -static gboolean -gst_mpeg_demux_process_event (GstMPEGParse * mpeg_parse, GstEvent * event, - GstClockTime time) -{ - gboolean ret = TRUE; - - switch (GST_EVENT_TYPE (event)) { - /* case GST_EVENT_FILLER: */ - case GST_EVENT_NEWSEGMENT: - case GST_EVENT_FLUSH_START: - case GST_EVENT_FLUSH_STOP: - ret = PARSE_CLASS (mpeg_parse)->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; -} - -static gboolean -gst_mpeg_demux_send_newsegment (GstMPEGParse * mpeg_parse, gdouble rate, - GstClockTime start_time, GstClockTime stop_time) -{ - GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (mpeg_parse); - - g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start_time), FALSE); - - start_time += mpeg_demux->adjust; - stop_time += mpeg_demux->adjust; - - if (!mpeg_demux->just_flushed) { - GST_DEBUG_OBJECT (mpeg_parse, "NEWSEGMENT without flush, st = %llu", - start_time); - /* Add padding to the end to make sure all streams end at the same timestamp */ - CLASS (mpeg_demux)->synchronise_pads (mpeg_demux, - mpeg_parse->current_ts + mpeg_demux->adjust + (GST_SECOND / 20), - mpeg_parse->current_ts + mpeg_demux->adjust + (GST_SECOND / 20)); - } else { - GST_DEBUG_OBJECT (mpeg_parse, "NEWSEGMENT after flush, st = %llu", - start_time); - } - mpeg_demux->just_flushed = FALSE; - - return parent_class->send_newsegment (mpeg_parse, rate, start_time, - stop_time); -} - -static gboolean -gst_mpeg_demux_send_event (GstMPEGParse * mpeg_parse, GstEvent * event, - GstClockTime time) -{ - /* - * Distribute the event to all active pads - */ - GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (mpeg_parse); - - GST_DEBUG_OBJECT (mpeg_demux, "Sending %s event", - GST_EVENT_TYPE_NAME (event)); - - if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_START) - mpeg_demux->just_flushed = TRUE; - - if (parent_class->send_event) - return parent_class->send_event (mpeg_parse, event, time); - else - gst_event_unref (event); - - return TRUE; -} - static gint _demux_get_writer_id (GstIndex * index, GstPad * pad) { @@ -769,8 +684,8 @@ done: headerlen, datalen); if (pts != -1) { - pts += mpeg_parse->adjust; - timestamp = MPEGTIME_TO_GSTTIME (pts) + mpeg_demux->adjust; + timestamp = PARSE_CLASS (mpeg_parse)->adjust_ts (mpeg_parse, + MPEGTIME_TO_GSTTIME (pts)); /* this apparently happens for some input were headers are * rewritten to make time start at zero... */ @@ -867,8 +782,8 @@ gst_mpeg_demux_parse_pes (GstMPEGParse * mpeg_parse, GstBuffer * buffer) pts |= ((guint64) * buf++) << 7; pts |= ((guint64) (*buf++ & 0xFE)) >> 1; - timestamp = - MPEGTIME_TO_GSTTIME (pts + mpeg_parse->adjust) + mpeg_demux->adjust; + timestamp = PARSE_CLASS (mpeg_parse)->adjust_ts (mpeg_parse, + MPEGTIME_TO_GSTTIME (pts)); GST_DEBUG_OBJECT (mpeg_demux, "0x%02x (% " G_GINT64_FORMAT ") PTS = %" G_GUINT64_FORMAT, id, pts, @@ -957,12 +872,11 @@ gst_mpeg_demux_send_subbuffer (GstMPEGDemux * mpeg_demux, GstFlowReturn ret; GstBuffer *outbuf; - mpeg_demux->just_flushed = FALSE; - if (timestamp != GST_CLOCK_TIME_NONE) { outstream->cur_ts = timestamp; - outstream->scr_offs = - GST_CLOCK_DIFF (timestamp, mpeg_parse->current_ts + mpeg_demux->adjust); + outstream->scr_offs = GST_CLOCK_DIFF (timestamp, + PARSE_CLASS (mpeg_parse)->adjust_ts (mpeg_parse, + mpeg_parse->current_ts)); if (outstream->scr_offs < 0) outstream->scr_offs = 0; @@ -974,8 +888,8 @@ gst_mpeg_demux_send_subbuffer (GstMPEGDemux * mpeg_demux, GST_BUFFER_OFFSET (buffer), GST_FORMAT_TIME, timestamp, 0); } } else { - outstream->cur_ts = - mpeg_parse->current_ts + mpeg_demux->adjust + outstream->scr_offs; + outstream->cur_ts = PARSE_CLASS (mpeg_parse)->adjust_ts (mpeg_parse, + mpeg_parse->current_ts + outstream->scr_offs); } if (size == 0) @@ -995,14 +909,16 @@ gst_mpeg_demux_send_subbuffer (GstMPEGDemux * mpeg_demux, if (GST_CLOCK_TIME_IS_VALID (mpeg_demux->max_gap) && GST_CLOCK_TIME_IS_VALID (mpeg_parse->current_ts) && - (mpeg_parse->current_ts + mpeg_demux->adjust > mpeg_demux->max_gap)) { + (PARSE_CLASS (mpeg_parse)->adjust_ts (mpeg_parse, + mpeg_parse->current_ts) > mpeg_demux->max_gap)) { GstClockTime threshold = - GST_CLOCK_DIFF (mpeg_parse->current_ts + mpeg_demux->adjust, + GST_CLOCK_DIFF (PARSE_CLASS (mpeg_parse)->adjust_ts (mpeg_parse, + mpeg_parse->current_ts), mpeg_demux->max_gap); CLASS (mpeg_demux)->synchronise_pads (mpeg_demux, threshold, - mpeg_parse->current_ts + mpeg_demux->adjust - - mpeg_demux->max_gap_tolerance); + PARSE_CLASS (mpeg_parse)->adjust_ts (mpeg_parse, + mpeg_parse->current_ts) - mpeg_demux->max_gap_tolerance); } return ret; @@ -1290,7 +1206,6 @@ gst_mpeg_demux_reset (GstMPEGDemux * mpeg_demux) * mpeg_demux->adjust = 0; * mpeg_demux->max_gap = GST_CLOCK_TIME_NONE; * mpeg_demux->max_gap_tolerance = GST_CLOCK_TIME_NONE; - * mpeg_demux->just_flushed = FALSE; */ } diff --git a/gst/mpegstream/gstmpegdemux.h b/gst/mpegstream/gstmpegdemux.h index c142ac4a3f..c485f984e2 100644 --- a/gst/mpegstream/gstmpegdemux.h +++ b/gst/mpegstream/gstmpegdemux.h @@ -129,21 +129,15 @@ struct _GstMPEGDemux { GstMPEGStream *audio_stream[GST_MPEG_DEMUX_NUM_AUDIO_STREAMS]; GstMPEGStream *private_stream[GST_MPEG_DEMUX_NUM_PRIVATE_STREAMS]; - GstClockTimeDiff adjust; /* Added to all PTS timestamps. This element - keeps always this value in 0, but it is - there for the benefit of subclasses. */ + GstClockTime max_gap; /* Maximum timestamp difference to + allow between pads before using a + filler to catch up. */ + GstClockTime max_gap_tolerance; + /* When catching a pad up, how far + behind to make it. */ - GstClockTime max_gap; /* Maximum timestamp difference to allow - * between pads before using a filler to catch up - */ - GstClockTime max_gap_tolerance; /* When catching a pad up, how far behind - to make it - */ - - GstClockTime max_ts; /* Highest timestamp of all pads */ - GstPad *max_pad; /* Pad with highest timestamp */ - - gboolean just_flushed; + GstClockTime max_ts; /* Highest timestamp of all pads. */ + GstPad *max_pad; /* Pad with highest timestamp. */ }; struct _GstMPEGDemuxClass { diff --git a/gst/mpegstream/gstmpegparse.c b/gst/mpegstream/gstmpegparse.c index e37f331e46..5b7c351f8d 100644 --- a/gst/mpegstream/gstmpegparse.c +++ b/gst/mpegstream/gstmpegparse.c @@ -99,18 +99,15 @@ static gboolean gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, static void gst_mpeg_parse_reset (GstMPEGParse * mpeg_parse); -static gboolean -gst_mpeg_parse_handle_newsegment (GstMPEGParse * mpeg_parse, - GstEvent * event, gboolean forward); +static GstClockTime gst_mpeg_parse_adjust_ts (GstMPEGParse * mpeg_parse, + GstClockTime ts); static GstFlowReturn gst_mpeg_parse_send_buffer (GstMPEGParse * mpeg_parse, GstBuffer * buffer, GstClockTime time); static GstFlowReturn gst_mpeg_parse_process_event (GstMPEGParse * mpeg_parse, - GstEvent * event, GstClockTime time); -static GstFlowReturn gst_mpeg_parse_send_newsegment (GstMPEGParse * parse, - gdouble rate, GstClockTime start_time, GstClockTime stop_time); + GstEvent * event); static gboolean gst_mpeg_parse_send_event (GstMPEGParse * mpeg_parse, - GstEvent * event, GstClockTime time); + GstEvent * event); static void gst_mpeg_parse_pad_added (GstElement * element, GstPad * pad); @@ -162,10 +159,9 @@ gst_mpeg_parse_class_init (GstMPEGParseClass * klass) klass->parse_syshead = NULL; klass->parse_packet = NULL; klass->parse_pes = NULL; - klass->handle_newsegment = gst_mpeg_parse_handle_newsegment; + klass->adjust_ts = gst_mpeg_parse_adjust_ts; klass->send_buffer = gst_mpeg_parse_send_buffer; klass->process_event = gst_mpeg_parse_process_event; - klass->send_newsegment = gst_mpeg_parse_send_newsegment; klass->send_event = gst_mpeg_parse_send_event; /* FIXME: this is a hack. We add the pad templates here instead @@ -258,7 +254,7 @@ gst_mpeg_parse_update_streaminfo (GstMPEGParse * mpeg_parse) static void gst_mpeg_parse_reset (GstMPEGParse * mpeg_parse) { - GST_DEBUG ("Resetting mpeg_parse"); + GST_DEBUG_OBJECT (mpeg_parse, "Resetting mpeg_parse"); mpeg_parse->first_scr = MP_INVALID_SCR; mpeg_parse->first_scr_pos = 0; @@ -279,52 +275,27 @@ gst_mpeg_parse_reset (GstMPEGParse * mpeg_parse) mpeg_parse->do_adjust = TRUE; mpeg_parse->adjust = 0; - /* Reset the current segment. */ + /* Initialize the current segment. */ GST_DEBUG_OBJECT (mpeg_parse, "Resetting current segment"); gst_segment_init (&mpeg_parse->current_segment, GST_FORMAT_TIME); - - /* Send a corresponding newsegment. */ - if (CLASS (mpeg_parse)->send_newsegment) { - CLASS (mpeg_parse)->send_newsegment (mpeg_parse, 1.0, 0, - GST_CLOCK_TIME_NONE); - } } -static gboolean -gst_mpeg_parse_handle_newsegment (GstMPEGParse * mpeg_parse, - GstEvent * event, gboolean forward) +static GstClockTime +gst_mpeg_parse_adjust_ts (GstMPEGParse * mpeg_parse, GstClockTime ts) { - gboolean ret = TRUE; - gboolean update; - gdouble rate; - GstFormat format; - gint64 start, stop, time; - - gst_event_parse_new_segment (event, &update, &rate, &format, - &start, &stop, &time); - - if (format == GST_FORMAT_TIME && (GST_CLOCK_TIME_IS_VALID (time))) { - /* Update the current segment. */ - GST_DEBUG_OBJECT (mpeg_parse, "Updating current segment with newsegment"); - gst_segment_set_newsegment (&mpeg_parse->current_segment, - update, rate, format, start, stop, time); - - if (forward) { - GST_DEBUG_OBJECT (mpeg_parse, "forwarding time based segment"); - if (CLASS (mpeg_parse)->send_event) { - ret = CLASS (mpeg_parse)->send_event (mpeg_parse, event, time); - } - } - - /* We are receiving segments from upstream. Don't try to adjust - SCR values. */ - mpeg_parse->do_adjust = FALSE; - mpeg_parse->adjust = 0; + if (!GST_CLOCK_TIME_IS_VALID (ts)) { + return GST_CLOCK_TIME_NONE; } - mpeg_parse->packetize->resync = TRUE; - gst_event_unref (event); - return ret; + if (mpeg_parse->do_adjust) { + /* Close the SCR gaps. */ + return ts + MPEGTIME_TO_GSTTIME (mpeg_parse->adjust); + } else { + /* Adjust the timestamp in such a way that all segments appear to + be in a single continuous sequence starting at time 0. */ + return ts + mpeg_parse->current_segment.accum - + mpeg_parse->current_segment.start; + } } static GstFlowReturn @@ -352,7 +323,8 @@ gst_mpeg_parse_send_buffer (GstMPEGParse * mpeg_parse, GstBuffer * buffer, } GST_BUFFER_TIMESTAMP (buffer) = time; - GST_DEBUG ("current buffer time: %" GST_TIME_FORMAT, GST_TIME_ARGS (time)); + GST_DEBUG_OBJECT (mpeg_parse, "current buffer time: %" GST_TIME_FORMAT, + GST_TIME_ARGS (time)); result = gst_pad_push (mpeg_parse->srcpad, buffer); @@ -360,37 +332,72 @@ gst_mpeg_parse_send_buffer (GstMPEGParse * mpeg_parse, GstBuffer * buffer, } static gboolean -gst_mpeg_parse_process_event (GstMPEGParse * mpeg_parse, GstEvent * event, - GstClockTime time) +gst_mpeg_parse_process_event (GstMPEGParse * mpeg_parse, GstEvent * event) { - return gst_pad_event_default (mpeg_parse->sinkpad, event); -} + gboolean ret = FALSE; -static gboolean -gst_mpeg_parse_send_newsegment (GstMPEGParse * mpeg_parse, gdouble rate, - GstClockTime start_time, GstClockTime stop_time) -{ - GstEvent *event; + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + { + gboolean update; + gdouble rate; + GstFormat format; + gint64 start, stop, time; - event = gst_event_new_new_segment (FALSE, rate, GST_FORMAT_TIME, - start_time, stop_time, 0); + gst_event_parse_new_segment (event, &update, &rate, &format, + &start, &stop, &time); - /* Update the current segment. */ - GST_DEBUG_OBJECT (mpeg_parse, "Setting current segment"); - gst_segment_set_newsegment (&mpeg_parse->current_segment, FALSE, rate, - GST_FORMAT_TIME, start_time, stop_time, 0); + if (format == GST_FORMAT_TIME && (GST_CLOCK_TIME_IS_VALID (time))) { + /* Update the current segment. */ + GST_DEBUG_OBJECT (mpeg_parse, + "Updating current segment with newsegment"); + gst_segment_set_newsegment (&mpeg_parse->current_segment, + update, rate, format, start, stop, time); - if (CLASS (mpeg_parse)->send_event) { - return CLASS (mpeg_parse)->send_event (mpeg_parse, event, start_time); + /* We are receiving segments from upstream. Don't try to adjust + SCR values. */ + mpeg_parse->do_adjust = FALSE; + mpeg_parse->adjust = 0; + } + mpeg_parse->packetize->resync = TRUE; + + gst_event_unref (event); + + ret = TRUE; + break; + } + case GST_EVENT_FLUSH_STOP: + /* Forward the event. */ + if (CLASS (mpeg_parse)->send_event) { + ret = CLASS (mpeg_parse)->send_event (mpeg_parse, event); + } else { + gst_event_unref (event); + } + + /* Send a newsegment event to restart counting from 0. */ + if (CLASS (mpeg_parse)->send_event) { + CLASS (mpeg_parse)->send_event (mpeg_parse, + gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0)); + } + + /* Reset the internal fields. */ + gst_mpeg_parse_reset (mpeg_parse); + + break; + default: + if (CLASS (mpeg_parse)->send_event) { + ret = CLASS (mpeg_parse)->send_event (mpeg_parse, event); + } else { + gst_event_unref (event); + } + break; } - gst_event_unref (event); - return FALSE; + return ret; } static gboolean -gst_mpeg_parse_send_event (GstMPEGParse * mpeg_parse, GstEvent * event, - GstClockTime time) +gst_mpeg_parse_send_event (GstMPEGParse * mpeg_parse, GstEvent * event) { GstIterator *it; gpointer pad; @@ -541,19 +548,19 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer) if (mpeg_parse->do_adjust && diff > mpeg_parse->max_scr_gap) { /* SCR gap found, fix the adjust value. */ - GST_DEBUG ("SCR gap detected; expected: %" G_GUINT64_FORMAT " got: %" - G_GUINT64_FORMAT " adjusted:%" G_GINT64_FORMAT " adjust:%" - G_GINT64_FORMAT, mpeg_parse->next_scr, mpeg_parse->current_scr, - mpeg_parse->current_scr + mpeg_parse->adjust, mpeg_parse->adjust); + GST_DEBUG_OBJECT (mpeg_parse, "SCR gap detected; expected: %" + G_GUINT64_FORMAT " got: %" G_GUINT64_FORMAT, + mpeg_parse->next_scr, mpeg_parse->current_scr); mpeg_parse->adjust += (gint64) mpeg_parse->next_scr - (gint64) mpeg_parse->current_scr; - GST_DEBUG ("new adjust: %" G_GINT64_FORMAT, mpeg_parse->adjust); + GST_DEBUG_OBJECT (mpeg_parse, "new adjust: %" G_GINT64_FORMAT, + mpeg_parse->adjust); } /* Update the current timestamp. */ - mpeg_parse->current_ts = MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr + - mpeg_parse->adjust); + mpeg_parse->current_ts = CLASS (mpeg_parse)->adjust_ts (mpeg_parse, + MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr)); /* Check for the reached offset signal. */ offset = gst_mpeg_packetize_tell (mpeg_parse->packetize); @@ -588,13 +595,15 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer) mpeg_parse->avg_bitrate_time; } //gst_mpeg_parse_update_streaminfo (mpeg_parse); - GST_LOG ("stream current is %1.3fMbs, calculated over %1.3fkB", + GST_LOG_OBJECT (mpeg_parse, + "stream current is %1.3fMbs, calculated over %1.3fkB", (mpeg_parse->mux_rate * 8) / 1048576.0, mpeg_parse->bytes_since_scr / 1024.0); } if (mpeg_parse->avg_bitrate_bytes) { - GST_LOG ("stream avg is %1.3fMbs, calculated over %1.3fkB", + GST_LOG_OBJECT (mpeg_parse, + "stream avg is %1.3fMbs, calculated over %1.3fkB", (float) (mpeg_parse->avg_bitrate_bytes) * 8 * GST_SECOND / mpeg_parse->avg_bitrate_time / 1048576.0, mpeg_parse->avg_bitrate_bytes / 1024.0); @@ -613,30 +622,10 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer) static gboolean gst_mpeg_parse_event (GstPad * pad, GstEvent * event) { + gboolean ret; GstMPEGParse *mpeg_parse = GST_MPEG_PARSE (gst_pad_get_parent (pad)); - GstClockTime time; - gboolean ret = FALSE; - if (mpeg_parse->current_scr != MP_INVALID_SCR) { - time = MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr); - } else { - time = GST_CLOCK_TIME_NONE; - } - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - if (CLASS (mpeg_parse)->handle_newsegment) - ret = CLASS (mpeg_parse)->handle_newsegment (mpeg_parse, event, TRUE); - else - gst_event_unref (event); - break; - default: - if (CLASS (mpeg_parse)->process_event) - ret = CLASS (mpeg_parse)->process_event (mpeg_parse, event, time); - else - gst_event_unref (event); - break; - } + ret = CLASS (mpeg_parse)->process_event (mpeg_parse, event); gst_object_unref (mpeg_parse); return ret; @@ -704,7 +693,7 @@ gst_mpeg_parse_chain (GstPad * pad, GstBuffer * buffer) /* Don't send data as long as no new SCR is found. */ if (mpeg_parse->current_scr == MP_INVALID_SCR) { - GST_DEBUG ("waiting for SCR"); + GST_DEBUG_OBJECT (mpeg_parse, "waiting for SCR"); gst_buffer_unref (buffer); result = GST_FLOW_OK; goto done; @@ -733,7 +722,8 @@ gst_mpeg_parse_chain (GstPad * pad, GstBuffer * buffer) /* Send the buffer. */ g_return_val_if_fail (mpeg_parse->current_scr != MP_INVALID_SCR, GST_FLOW_OK); - time = MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr + mpeg_parse->adjust); + time = CLASS (mpeg_parse)->adjust_ts (mpeg_parse, + MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr)); if (CLASS (mpeg_parse)->send_buffer) result = CLASS (mpeg_parse)->send_buffer (mpeg_parse, buffer, time); @@ -1089,7 +1079,7 @@ normal_seek (GstMPEGParse * mpeg_parse, GstPad * pad, GstEvent * event) offset = cur; if (offset != -1) { - GST_LOG ("starting conversion of cur"); + GST_LOG_OBJECT (mpeg_parse, "starting conversion of cur"); /* Bring the format to time on srcpad. */ conv = GST_FORMAT_TIME; if (!gst_pad_query_convert (pad, format, offset, &conv, &start_position)) { @@ -1101,14 +1091,15 @@ normal_seek (GstMPEGParse * mpeg_parse, GstPad * pad, GstEvent * event) start_position, &conv, &start_position)) { goto done; } - GST_INFO ("Finished conversion of cur, BYTES cur : %lld", start_position); + GST_INFO_OBJECT (mpeg_parse, + "Finished conversion of cur, BYTES cur : %lld", start_position); } else { start_position = -1; } offset = stop; if (offset != -1) { - GST_INFO ("starting conversion of stop"); + GST_INFO_OBJECT (mpeg_parse, "starting conversion of stop"); /* Bring the format to time on srcpad. */ conv = GST_FORMAT_TIME; if (!gst_pad_query_convert (pad, format, offset, &conv, &end_position)) { @@ -1120,7 +1111,8 @@ normal_seek (GstMPEGParse * mpeg_parse, GstPad * pad, GstEvent * event) end_position, &conv, &end_position)) { goto done; } - GST_INFO ("Finished conversion of stop, BYTES stop : %lld", end_position); + GST_INFO_OBJECT (mpeg_parse, + "Finished conversion of stop, BYTES stop : %lld", end_position); } else { end_position = -1; } @@ -1196,8 +1188,15 @@ gst_mpeg_parse_change_state (GstElement * element, GstStateChange transition) gst_mpeg_packetize_new (mpeg_parse->srcpad, GST_MPEG_PACKETIZE_SYSTEM); } - /* initialize parser state */ + + /* Initialize parser state */ gst_mpeg_parse_reset (mpeg_parse); + + /* Send a newsegment event to start counting from 0. */ + if (CLASS (mpeg_parse)->send_event) { + CLASS (mpeg_parse)->send_event (mpeg_parse, + gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0)); + } break; default: break; diff --git a/gst/mpegstream/gstmpegparse.h b/gst/mpegstream/gstmpegparse.h index 9e9ddc548e..85d9d15945 100644 --- a/gst/mpegstream/gstmpegparse.h +++ b/gst/mpegstream/gstmpegparse.h @@ -109,21 +109,13 @@ struct _GstMPEGParseClass /* Process an event */ gboolean (*process_event) (GstMPEGParse * parse, - GstEvent * event, GstClockTime time); - - /* Process a newsegment event */ - gboolean (*handle_newsegment) - (GstMPEGParse * parse, GstEvent * event, - gboolean forward); + GstEvent * event); /* Send an event */ - gboolean (*send_event) (GstMPEGParse * parse, GstEvent *event, - GstClockTime time); + gboolean (*send_event) (GstMPEGParse * parse, GstEvent *event); - /* Send a newsegment event. */ - gboolean (*send_newsegment)(GstMPEGParse * parse, gdouble rate, - GstClockTime start_time, - GstClockTime stop_time); + /* Adjust a timestamp */ + GstClockTime (*adjust_ts) (GstMPEGParse * parse, GstClockTime ts); /* Signals */ void (*reached_offset) (GstMPEGParse *parse,