PlaybackManager then intersects all enabled tracks' buffered time
ranges. This will be used by the media element for the buffered
attribute and to update the ready state.
Apparently this function uses a bitrate heuristic to determine which
track is best. We don't want or need that, so just select the first
track with default disposition (e.g. FlagDefault=1 in Matroska).
...giving tracks a kind attribute, and renaming name to label.
Demuxers will need to determine the kind attribute, since the spec for
sourcing tracks requires us to select based on info we don't expose.
libavcodec apparently holds onto any error that is not AVERROR_EOF when
a read fails. This means that reading until EOF after an aborted read
results in us receiving an AVERROR_EXIT in FFmpegDemuxer instead of
AVERROR_EOF, which causes the playback system to enter an error state
without decoding all frames in the file.
Instead, just always return AVERROR_EOF, and check if the read was
aborted in FFmpegDemuxer instead to return the correct error category
from there.
The way that other classes interact with IncrementallyPopulatedStream
is now through a virtual interface MediaStream and MediaStreamCursor.
This way, we can have simpler implementations of reading media data
that will not require an RB tree and synchronization.
...and abstract away the stream/cursor blocking/aborting functionality
so that demuxers can implement or ignore those methods as they see fit.
This is a step towards implementing a wrapper demuxer for MSE streams.
It's not necessary to keep around an instance of AVFormatContext in
FFmpegDemuxer, so instead just copy out the info we need for our
implementation and then destroy it so that our stream cursor is freed.
Refactor the FFmpeg and Matroska demuxers to consume data through
`IncrementallyPopulatedStream::Cursor` instead of a pointer to fully
buffered.
This change establishes a new rule: each track must be initialized with
its own cursor. Data providers now explicitly create a per-track context
via `Demuxer::create_context_for_track(track, cursor)`, and own pointer
to that cursor. In the upcoming changes, holding the cursor in the
provider would allow to signal "cancel blocking reads" so an
in-flight seek can fail immediately when a newer seek request arrives.
By default, MatroskaDemuxer chooses not to seek if the current frame
is closer to the seek target than the keyframe that precedes the seek
target. However, it can be desirable to seek to a keyframe anyway, so
let's allow that.
Most users will only care about the total file duration, and shouldn't
be required to determine the file duration from multiple track
durations. To facilitate that, add a total_duration() function that
returns the demuxer's duration not associated to any particular track.
The existing conversion was rounding to the nearest millisecond, which
is much less precision than most videos will want. Instead, use only
integer math to directly convert the presentation time to seconds and
nanoseconds for our AK::Duration to represent accurately.