streamsynchronizer: Can't complete preroll in case pause/seek is called after one of streams receive EOS
Submitted by Heekyoung Seo
Link to original bug (#777073)
Description
Created attachment 343215
Issue file (a/v duration is different)
pipeline can not complete preroll when pause/seek is called in situations where one of the streams receives EOS and the other does not. The phenomenon occurs when playing multimedia files made of audio and video of different lengths. The root cause of the problem occurs because the segment position is set to out of segment.
- Seek case
-
gststreamsynchronizer sink event handler update segment.stop to segment.position in normal eos case as below
if (seen_data && stream->segment.position != -1) timestamp = stream->segment.position; else if (stream->segment.rate < 0.0 || stream->segment.stop == -1) timestamp = stream->segment.start; else timestamp = stream->segment.stop; stream->segment.position = timestamp;
-
gst_segment_clip function treats the start position of gap_evet as out of segment if it is greater than or equal to segment.stop.
-
gap_event is considered not_syncable then preroll can not be finished.
- Pause case
-
gststreamersynchronzer sink_chain function update the position of eos stream using position of non eos stream. Therefore segment position of eos stream can be bigger than own segment stop value.
/* Is there a 1 second lag? */
if (position != -1 && GST_CLOCK_TIME_IS_VALID (timestamp_end) &&
position + GST_SECOND < timestamp_end) {
gint64 new_start;new_start = timestamp_end - GST_SECOND; GST_DEBUG_OBJECT (ostream->sinkpad, "Advancing stream %u from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT, ostream->stream_number, GST_TIME_ARGS (position), GST_TIME_ARGS (new_start)); ostream->segment.position = new_start;
-
gst_segment_clip function treats the start position of gap_evet as out of segment if it is greater than or equal to segment.stop.
-
gap_event is considered not_syncable then preroll can not be finished.
I suggest below solution.
-
Seek case : change segment boundary. It would be aligned with comment, too.
if (G_UNLIKELY (segment->stop != -1 && start != -1 && start >= segment->stop))
-> if (G_UNLIKELY (segment->stop != -1 && start != -1 && start > segment->stop)) -
Pause case : add limitation of segment position when it is updated in sink_chain function of gststreamsynchronizer
new_start = timestamp_end - GST_SECOND;
-
/* if new_start is bigger than segment.stop, it is out of segment. */
-
if (new_start > ostream->segment.stop)
-
new_start = ostream->segment.stop;
It can be fixed another way, but I am trying to change as small as it can be. If there is better solution, please fix it or give me the advice about it.
Attachment 343215, "Issue file (a/v duration is different)":
big.out