Closed defagos closed 4 years ago
I could find a playable sample stream with DVR capabilities and date information (#EXT-X-PROGRAM-DATE-TIME
) embedded in the playlist: Das Erste Live, with playlist https://mcdn.daserste.de/daserste/int/master.m3u8.
I implemented this feature as follows:
SRGPosition
has been enriched with date support. This abstraction also avoids the need for breaking changes or new APIs at the controller level.AVPlayerItem
current date and time for future use as reference. A first implementation I made namely directly read these values from the item, but during seeks those proved to be misaligned, which made calculations incorrect.currentDate
property is available on the controller.AVPlayer
offers a -seekToDate:
API, but it is limited (for example it does not support tolerances) and probably converts dates into playhead positions internally anyway. I therefore implemented this conversion approach using saved reference information, so that the usual -seekToTime:
APIs can be used, including the methods with tolerance support.SRGPosition
has now a time - date potential duality, date-based positions are never produced in the controller implementation, as the controller works entirely around time-based positions (date-based positions are primarily meant for clients who want to seek to some date). We namely don't know whether an operation occurred because of a time or date-based operation, and don't really care. We only care about the position itself, and at the end all positions are treated as time positions, not date positions anyway.I had forgotten we had a date
property already, which was returning a date for all livestreams. I propose we merge its behavior with the new currentDate
behavior and remove it. Though this change is breaking, the currentDate
name is more consistent with the currentTime
similar property.
We could of course also introduce a temporary deprecation to avoid this breaking change. To be discussed.
Properly supporting dates with segments required some more work. The approach outlined above only works when starting playback at a position, or seeking to a position. When playing a segment, though, we need to be able to start and end at given dates. The current SRGSegment
protocol, having only time range information was not sufficient. We need dates.
Here are the options I considered in order, each one being refined to lead to the next one:
srg_markInDate
and srg_markOutDate
properties, next to the existing srg_timeRange
property. There are two issues with this approach: Clients have to implement all properties, but time and date should be mutually exclusive. Moreover, this is quite inconsistent (single range property vs. two date properties).SRGPosition
duality to have markInPosition
and markOutPosition
. This way clients return a time or date position depending on how they want to delimit segments. There is one issue with this approach: SRGPosition
has tolerances which make no sense here since segment boundaries must be sharped.SRGMark
, which describe a playback location with a time - date duality, but does not contain tolerances. SRGPosition
is then simply a mark with tolerances. We can then replace the existing SRGSegment
time range property with two srg_markIn
and srg_markOut
positions.SRGMarkRange
class, which is to SRGMark
what CMTimeRange
is to CMTime
. This way, we can easily define ranges, perform conversions (e.g. to CMTimeRange
) and a single srg_markRange
property is needed for SRGSegment
.With these changes, segments can be defined with times or dates (even a mixture of both, though this is unlikely). SRGMark
and SRGMarkRange
can then be mapped to a player CMTime
and CMTimeRange
, depending on whether the stream contains timestamp information. For conversion, I added dedicated methods to SRGMediaPlayerController
, so that accurate positions can be calculated when a reference date / time relationship can be extracted from the stream.
The rest of the implementation is rather straightforward. No further changes are required to internals since the controller works with converted CMTime
only internally. After initial conversions, the code stays the same, which is good since the logic to adjust positions (keeping positions within valid ranges, including possible tolerances), quite complicated, works with CMTime
s.
When using a slider, it is also useful to have date information (if available) alongside the time information already provided.
I therefore initially thought: "Let's have SRGMark
returned by SRGMediaPlayerController
, and in general everywhere clients previously received a CMTime
from the public AP!". This seemed appealing.
Well, it is not. A mark should always be checked for the associated controller, only in very rare cases should a mark be interpreted as is. If controllers were to returns marks for location information, this would be a shame, as the controller returning the mark is known (the controller itself!), but the mark does not contain this piece of information, forcing clients to remember the controller to interpret a mark for.
For this reason, time and date known to a controller must not be returned together as SRGMark
. We could pack them into another CMTime
/ NSDate
dual object just to group related information, but I don't see the point in doing so.
I therefore improved the existing date support as follows:
SRGMark
is reserved for input (playback initial location, seek location, segment ranges).mark
or markRange
, but currentTime
, currentDate
and timeRange
, as today. SRGMark
to emphasize the need for a controller (still nullable in the corresponding calculation method). Maybe reintroduce SRGTimePosition
to avoid exposing it, even privately (misleading)This is available for review on the feature/date-info
branch.
If timestamps are not available in the stream, our code was guessing the date from the DVR end window and the current time. This was not reliable, as this relationship oscillates because of chunks being added or removed.
To fix this it suffices to cache the date / player time relationship only once. This could also be made for streams with timestamps, but according to my tests the information is in such cases correct. If this still proves to have slight noticeable variations, we can apply the same strategy in this case and cache the date / player time relationship once.
For streams containing date information, we should rely on this specific information instead.
For information,
AVPlayer
andAVPlayerItem
provide seek to date methods. Moreover,AVPlayerItem
provides acurrentDate
property, which probably notnil
when date information is available from the stream.