Skip to content

basesink: Support position queries after non-resetting flushes

A flush is resetting or not depending on the reset_time argument in the FLUSH_STOP event is set.

Resetting flushes reset the running time to zero and clear any existing segment. These are the kind of flushes used by flushing seeks, and by far the most common. Non-resetting flushes are much more niche, used for instance for quality changes in adaptivedemux2 and MediaSource Extensions in WebKit.

A key difference between the seek use case and the quality change use case is that the latter is much more removed from the player. Seeks generally occur because an user request it, whereas quality changes can be automatic.

Currently, there are three notable cases where position queries fail:

(a) before pre-roll, as there is no segment yet. This is one is understandable, as for at least some time before pre-roll, we cannot know if a media stream would start at 0 or any other position, or the duration of the stream for that matter.

(b) after a resetting flush caused by a seek. This kind of flush resets the segment, so it's not surprising position queries fail. This is inconvenient for applications, as it means they always need to handle position reporting (e.g. in UI) separately every time they request a seek, e.g. by caching the seek target and using it when the position query fail. I'm not fond of this behavior, as it's unintuitive and makes GStreamer harder to use, but at this point could be difficult to change and it's not within the scope of this proposal.

(c) after a non-resetting flush, e.g. caused by a quality change. The segment is not reset in this case. Position queries work until a FLUSH_STOP is sent. Querying position after a FLUSH_START but before a FLUSH_STOP works, and returns the position the sink was at the moment the FLUSH_START was received. This in fact the only reliable way (short of adding probes to the sink element) to get this position, as FLUSH_START receival is asynchronous with playback.

In the case (c), as of currently, position queries fail once the FLUSH_STOP is received. But unlike in (b), the application has no position to fall back to, as the FLUSH_START was initiated by elements inside the pipeline that are in a lower layer of abstraction. Specific applications that have control of both the player and the internal element doing the flushing -- such as WebKit -- can still work around this problem through layer violations (lucky!), but this still puts in question this behavior in GStreamer.

This patch fixes this case by amending the position query handler of basesink, which was previously erroneously returning early with "wrong state", even though the flush occurs in PAUSED or PLAYING.

A unit test checking this behavior has also been added.

Merge request reports