From 51c5ff45de81e96dbace2a872505274d7de0341c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 13 Jul 2016 11:02:23 +0200 Subject: [PATCH] tsdemux: Fix draining on wrong programs When draining a program, we might send a newsegment event on the pads that are going to be removed (and then the pending data). In order to do that, calculate_and_push_newsegment() needs to know what list of streams it should take into account (instead of blindly using the current one). All callers to calculate_and_push_newsegment() and push_pending_data() can now specify the program on which to act (or NULL for the default one). --- gst/mpegtsdemux/tsdemux.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/gst/mpegtsdemux/tsdemux.c b/gst/mpegtsdemux/tsdemux.c index a6d0fab0c4..7a396cd875 100644 --- a/gst/mpegtsdemux/tsdemux.c +++ b/gst/mpegtsdemux/tsdemux.c @@ -305,7 +305,8 @@ static void gst_ts_demux_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static void gst_ts_demux_flush_streams (GstTSDemux * tsdemux, gboolean hard); static GstFlowReturn -gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream); +gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream, + MpegTSBaseProgram * program); static void gst_ts_demux_stream_flush (TSDemuxStream * stream, GstTSDemux * demux, gboolean hard); @@ -972,7 +973,7 @@ push_event (MpegTSBase * base, GstEvent * event) /* If we are pushing out EOS, flush out pending data first */ if (GST_EVENT_TYPE (event) == GST_EVENT_EOS && gst_pad_is_active (stream->pad)) - gst_ts_demux_push_pending_data (demux, stream); + gst_ts_demux_push_pending_data (demux, stream, NULL); gst_event_ref (event); gst_pad_push_event (stream->pad, event); @@ -1683,7 +1684,7 @@ gst_ts_demux_stream_removed (MpegTSBase * base, MpegTSBaseStream * bstream) if (gst_pad_is_active (stream->pad)) { /* Flush out all data */ GST_DEBUG_OBJECT (stream->pad, "Flushing out pending data"); - gst_ts_demux_push_pending_data ((GstTSDemux *) base, stream); + gst_ts_demux_push_pending_data ((GstTSDemux *) base, stream, NULL); GST_DEBUG_OBJECT (stream->pad, "Pushing out EOS"); gst_pad_push_event (stream->pad, gst_event_new_eos ()); @@ -1831,7 +1832,8 @@ gst_ts_demux_program_started (MpegTSBase * base, MpegTSBaseProgram * program) for (tmp = demux->previous_program->stream_list; tmp; tmp = tmp->next) { TSDemuxStream *stream = (TSDemuxStream *) tmp->data; if (stream->pad) - gst_ts_demux_push_pending_data (demux, stream); + gst_ts_demux_push_pending_data (demux, stream, + demux->previous_program); } } @@ -2231,7 +2233,8 @@ gst_ts_demux_queue_data (GstTSDemux * demux, TSDemuxStream * stream, } static void -calculate_and_push_newsegment (GstTSDemux * demux, TSDemuxStream * stream) +calculate_and_push_newsegment (GstTSDemux * demux, TSDemuxStream * stream, + MpegTSBaseProgram * target_program) { MpegTSBase *base = (MpegTSBase *) demux; GstClockTime lowest_pts = GST_CLOCK_TIME_NONE; @@ -2240,12 +2243,15 @@ calculate_and_push_newsegment (GstTSDemux * demux, TSDemuxStream * stream) GST_DEBUG ("Creating new newsegment for stream %p", stream); + if (target_program == NULL) + target_program = demux->program; + /* Speedup : if we don't need to calculate anything, go straight to pushing */ if (demux->segment_event) goto push_new_segment; /* Calculate the 'new_start' value, used for newsegment */ - for (tmp = demux->program->stream_list; tmp; tmp = tmp->next) { + for (tmp = target_program->stream_list; tmp; tmp = tmp->next) { TSDemuxStream *pstream = (TSDemuxStream *) tmp->data; if (GST_CLOCK_TIME_IS_VALID (pstream->first_pts)) { @@ -2294,7 +2300,7 @@ calculate_and_push_newsegment (GstTSDemux * demux, TSDemuxStream * stream) } push_new_segment: - for (tmp = demux->program->stream_list; tmp; tmp = tmp->next) { + for (tmp = target_program->stream_list; tmp; tmp = tmp->next) { stream = (TSDemuxStream *) tmp->data; if (stream->pad == NULL) continue; @@ -2369,7 +2375,7 @@ gst_ts_demux_check_and_sync_streams (GstTSDemux * demux, GstClockTime time) "Stream needs update. Pushing GAP event to TS %" GST_TIME_FORMAT, GST_TIME_ARGS (time)); if (G_UNLIKELY (ps->need_newsegment)) - calculate_and_push_newsegment (demux, ps); + calculate_and_push_newsegment (demux, ps, NULL); /* Now send gap event */ gst_pad_push_event (ps->pad, gst_event_new_gap (time, 0)); @@ -2477,13 +2483,15 @@ error: } static GstFlowReturn -gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream) +gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream, + MpegTSBaseProgram * target_program) { GstFlowReturn res = GST_FLOW_OK; MpegTSBaseStream *bs = (MpegTSBaseStream *) stream; GstBuffer *buffer = NULL; GstBufferList *buffer_list = NULL; + GST_DEBUG_OBJECT (stream->pad, "stream:%p, pid:0x%04x stream_type:%d state:%d", stream, bs->pid, bs->stream_type, stream->state); @@ -2597,7 +2605,7 @@ gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream) } if (G_UNLIKELY (stream->need_newsegment)) - calculate_and_push_newsegment (demux, stream); + calculate_and_push_newsegment (demux, stream, target_program); /* FIXME : Push pending buffers if any */ if (G_UNLIKELY (stream->pending)) { @@ -2731,7 +2739,7 @@ gst_ts_demux_handle_packet (GstTSDemux * demux, TSDemuxStream * stream, if (G_UNLIKELY (packet->payload_unit_start_indicator) && FLAGS_HAS_PAYLOAD (packet->scram_afc_cc)) /* Flush previous data */ - res = gst_ts_demux_push_pending_data (demux, stream); + res = gst_ts_demux_push_pending_data (demux, stream, NULL); if (packet->payload && (res == GST_FLOW_OK || res == GST_FLOW_NOT_LINKED) && stream->pad) { @@ -2741,7 +2749,7 @@ gst_ts_demux_handle_packet (GstTSDemux * demux, TSDemuxStream * stream, /* Finally check if the data we queued completes a packet */ if (stream->expected_size && stream->current_size == stream->expected_size) { GST_LOG ("pushing complete packet"); - res = gst_ts_demux_push_pending_data (demux, stream); + res = gst_ts_demux_push_pending_data (demux, stream, NULL); } } @@ -2789,7 +2797,7 @@ gst_ts_demux_drain (MpegTSBase * base) for (tmp = demux->program->stream_list; tmp; tmp = tmp->next) { TSDemuxStream *stream = (TSDemuxStream *) tmp->data; if (stream->pad) { - res = gst_ts_demux_push_pending_data (demux, stream); + res = gst_ts_demux_push_pending_data (demux, stream, NULL); if (G_UNLIKELY (res != GST_FLOW_OK)) break; }