streamsynchronizer: Consider streams having received stream-start as waiting

When using the custom WebKitMediaSrc element (used by WebKit and able to
perform an initial seek in playbin), a stall caused by streamsynchronizer
was detected during an initial seek. The flow of events revealed that the
intertwining of the initial configuration of the streams with the reset
caused by the flush events from the seek left streamsynchronizer in an
inconsistent state:

 streamsynchronizer0:sink_0 (video) events, starting before the seek:
  stream-start --> Sets the stream to wait
  flush-stop --> Clears the stream wait flag
  caps
  tag
  segment
  stream-collection
  (buffers start to come and flow properly)

 streamsynchronizer0:sink_1 (audio) events, happening after seek:
  (no flush events, because the stream hadn't been initialized when the seek happened)
  stream-start --> Sets the stream to wait
  caps
  segment
  (stalled because the stream is in wait mode!)

The code in streamsynchronizer expects that all the streams are in wait
state before releasing all of them at once. The flush on the video stream
broke that assumption and that's why the audio stream is never released in
that scenario.

Avoiding the clearing of the wait flag on flush-stop isn't an actual solution
to the problem, as it creates other side effects and at least makes the
gst-editing-services/seek_with_stop test to timeout. The alternate solution
implemented in this patch consists on recording when the stream-start event is
received and then consider those started streams equally valid as those in
waiting state when evaluating if all the streams should be unblocked.
This commit is contained in:
Enrique Ocaña González 2023-05-03 15:20:19 +02:00
parent 3bd43672ec
commit 747db4e574

View file

@ -75,6 +75,7 @@ typedef struct
gboolean flushing; /* set after flush-start and before flush-stop */
gboolean seen_data;
gboolean send_gap_event;
gboolean seen_stream_start;
GstClockTime gap_duration;
GstStreamFlags flags;
@ -434,13 +435,14 @@ gst_stream_synchronizer_sink_event (GstPad * pad, GstObject * parent,
GST_DEBUG_OBJECT (pad, "Stream %d changed", stream->stream_number);
stream->wait = TRUE;
stream->seen_stream_start = TRUE;
for (l = self->streams; l; l = l->next) {
GstSyncStream *ostream = l->data;
all_wait = all_wait && ((ostream->flags & GST_STREAM_FLAG_SPARSE)
|| (ostream->wait && (!have_group_id
|| ostream->group_id == group_id)));
|| ((ostream->wait || ostream->seen_stream_start)
&& (!have_group_id || ostream->group_id == group_id)));
if (!all_wait)
break;
}
@ -1118,6 +1120,7 @@ gst_stream_synchronizer_change_state (GstElement * element,
gst_segment_init (&stream->segment, GST_FORMAT_UNDEFINED);
stream->gap_duration = GST_CLOCK_TIME_NONE;
stream->wait = FALSE;
stream->seen_stream_start = FALSE;
stream->is_eos = FALSE;
stream->eos_sent = FALSE;
stream->flushing = FALSE;