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).
This commit is contained in:
Edward Hervey 2016-07-13 11:02:23 +02:00 committed by Edward Hervey
parent e2b98a7721
commit 51c5ff45de

View file

@ -305,7 +305,8 @@ static void gst_ts_demux_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec); GValue * value, GParamSpec * pspec);
static void gst_ts_demux_flush_streams (GstTSDemux * tsdemux, gboolean hard); static void gst_ts_demux_flush_streams (GstTSDemux * tsdemux, gboolean hard);
static GstFlowReturn 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, static void gst_ts_demux_stream_flush (TSDemuxStream * stream,
GstTSDemux * demux, gboolean hard); 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 we are pushing out EOS, flush out pending data first */
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS && if (GST_EVENT_TYPE (event) == GST_EVENT_EOS &&
gst_pad_is_active (stream->pad)) 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_event_ref (event);
gst_pad_push_event (stream->pad, 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)) { if (gst_pad_is_active (stream->pad)) {
/* Flush out all data */ /* Flush out all data */
GST_DEBUG_OBJECT (stream->pad, "Flushing out pending 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_DEBUG_OBJECT (stream->pad, "Pushing out EOS");
gst_pad_push_event (stream->pad, gst_event_new_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) { for (tmp = demux->previous_program->stream_list; tmp; tmp = tmp->next) {
TSDemuxStream *stream = (TSDemuxStream *) tmp->data; TSDemuxStream *stream = (TSDemuxStream *) tmp->data;
if (stream->pad) 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 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; MpegTSBase *base = (MpegTSBase *) demux;
GstClockTime lowest_pts = GST_CLOCK_TIME_NONE; 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); 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 */ /* Speedup : if we don't need to calculate anything, go straight to pushing */
if (demux->segment_event) if (demux->segment_event)
goto push_new_segment; goto push_new_segment;
/* Calculate the 'new_start' value, used for newsegment */ /* 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; TSDemuxStream *pstream = (TSDemuxStream *) tmp->data;
if (GST_CLOCK_TIME_IS_VALID (pstream->first_pts)) { if (GST_CLOCK_TIME_IS_VALID (pstream->first_pts)) {
@ -2294,7 +2300,7 @@ calculate_and_push_newsegment (GstTSDemux * demux, TSDemuxStream * stream)
} }
push_new_segment: 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; stream = (TSDemuxStream *) tmp->data;
if (stream->pad == NULL) if (stream->pad == NULL)
continue; 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, "Stream needs update. Pushing GAP event to TS %" GST_TIME_FORMAT,
GST_TIME_ARGS (time)); GST_TIME_ARGS (time));
if (G_UNLIKELY (ps->need_newsegment)) if (G_UNLIKELY (ps->need_newsegment))
calculate_and_push_newsegment (demux, ps); calculate_and_push_newsegment (demux, ps, NULL);
/* Now send gap event */ /* Now send gap event */
gst_pad_push_event (ps->pad, gst_event_new_gap (time, 0)); gst_pad_push_event (ps->pad, gst_event_new_gap (time, 0));
@ -2477,13 +2483,15 @@ error:
} }
static GstFlowReturn 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; GstFlowReturn res = GST_FLOW_OK;
MpegTSBaseStream *bs = (MpegTSBaseStream *) stream; MpegTSBaseStream *bs = (MpegTSBaseStream *) stream;
GstBuffer *buffer = NULL; GstBuffer *buffer = NULL;
GstBufferList *buffer_list = NULL; GstBufferList *buffer_list = NULL;
GST_DEBUG_OBJECT (stream->pad, GST_DEBUG_OBJECT (stream->pad,
"stream:%p, pid:0x%04x stream_type:%d state:%d", stream, bs->pid, "stream:%p, pid:0x%04x stream_type:%d state:%d", stream, bs->pid,
bs->stream_type, stream->state); 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)) 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 */ /* FIXME : Push pending buffers if any */
if (G_UNLIKELY (stream->pending)) { 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) && if (G_UNLIKELY (packet->payload_unit_start_indicator) &&
FLAGS_HAS_PAYLOAD (packet->scram_afc_cc)) FLAGS_HAS_PAYLOAD (packet->scram_afc_cc))
/* Flush previous data */ /* 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) if (packet->payload && (res == GST_FLOW_OK || res == GST_FLOW_NOT_LINKED)
&& stream->pad) { && 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 */ /* Finally check if the data we queued completes a packet */
if (stream->expected_size && stream->current_size == stream->expected_size) { if (stream->expected_size && stream->current_size == stream->expected_size) {
GST_LOG ("pushing complete packet"); 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) { for (tmp = demux->program->stream_list; tmp; tmp = tmp->next) {
TSDemuxStream *stream = (TSDemuxStream *) tmp->data; TSDemuxStream *stream = (TSDemuxStream *) tmp->data;
if (stream->pad) { 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)) if (G_UNLIKELY (res != GST_FLOW_OK))
break; break;
} }