Commit Graph

14 Commits

Author SHA1 Message Date
Zaggy1024
847edc405e LibMedia: Avoid a recursive lock to check exit state in data providers 2026-01-30 17:27:44 -06:00
Zaggy1024
75231e63b1 LibMedia: Only pass Demuxer to the data providers
...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.
2026-01-30 10:02:00 -06:00
Zaggy1024
c4e95079e1 LibMedia: Destroy decoders while data providers are suspended
This doesn't appear to result in much of a delay in resumption,
creating the decoder takes about 1ms.
2026-01-26 15:49:07 -06:00
Zaggy1024
f9081fbde6 LibMedia: Dispose future media data and flush decoders when idle
In order to free up memory when a video is paused for an extended
period, we add a new Suspended state to PlaybackManager which tells the
data providers to suspend. The data providers will handle this signal
by disposing of their entire decoded data queue and flushing their
decoder.

When initially creating a PlaybackManager, and when resuming to a
paused state, the delay before suspension will be much lower than when
pausing from any other state. This is intended to prevent media
elements from consuming memory for long when decoding the first frame
for display, as well as to allow the data providers to suspend much
more quickly after a seek while paused.

Currently, resuming playback doesn't display much of a delay on my
MacBook, though that may change once we completely tear down the
decoder in the suspended state. It may also be exacerbated by using
hardware decoders due more complex decoder initialization.
2026-01-26 15:49:07 -06:00
Zaggy1024
9a421ffe9f LibMedia: Make demuxers thread-safe and remove MutexedDemuxer 2026-01-07 00:13:32 +01:00
Aliaksandr Kalenik
c5d8cb5c47 LibMedia: Change demuxers to use IncrementallyPopulatedStream as input
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.
2025-12-16 02:42:48 -06:00
Zaggy1024
65c0be66e4 LibMedia: Implement audio conversion in AudioDataProvider 2025-12-13 08:58:26 +01:00
Zaggy1024
d3374655cc LibMedia: Extend the playback duration based on demuxed/decoded frames 2025-12-10 16:02:40 -06:00
Zaggy1024
b48c5b4b27 LibMedia+Tests: Avoid deferred-invoking on dead event loops
Posting callbacks to the main thread is now predicated on whether the
event loop reference is alive, preventing a stack-use-after-return.

The data providers will also check if they've been requested to exit
before calling deferred_invoke, though this is not going to be the case
unless the media element gets GCed while the media is playing.
2025-12-10 16:02:40 -06:00
Aliaksandr Kalenik
9f60828a57 LibMedia+LibWeb: Create demuxer and extract tracks on a separate thread
Demuxer creation and track+duration extraction are moved to a separate
thread so that the media data byte buffer is no longer accessed from the
main thread. This will be important once the buffer is populated
incrementally, as having the main thread both populate and read from the
same buffer could easily lead to deadlocks. Aside from that, moving
demuxer creation off the main thread helps to be more responsive.

`VideoDataProvider` and `AudioDataProvider` now accept the main thread
event loop pointer as they are constructed from the thread responsible
for demuxer creation.
2025-12-09 17:36:18 -06:00
Zaggy1024
2bd541c70c LibMedia: Keep data providers suspended until they are active
This allows us to avoid waiting on the condition variable for the error
handler to be set when an error occurs.
2025-12-03 12:20:49 -06:00
Zaggy1024
ae5e200dfc LibMedia: Move overlapping audio block correction to the data provider
This prevents PlaybackManager's seek while enabling an audio track from
causing the AudioMixingSink to push audio blocks forward unnecessarily.
Previously, the seek would cause the initial block or blocks to repeat
from the perspective of AudioMixingSink, so it would think that it
needs to shift the first block after the seek forward by a few samples.
By moving this to the AudioDataProvider, we can clear the last sample
index every time the decoder is flushed, ensuring that the block
shifting always makes sense.

By doing this in AudioMixingSink instead of the Decoder
implementations, we avoid having to duplicate this shifting logic
across multiple implementations.

This also fixes an issue where multiple audio blocks occupying the same
timestamp would be skipped while seeking, causing a significant break
in audio.
2025-11-17 16:51:18 +01:00
Zaggy1024
ccf4b3f6e9 LibMedia: Implement media seeking
This implementation allows:
- Accurate seeking to an exact timestamp
- Seeking to the keyframe before a timestamp
- Seeking to the keyframe after a timestamp
These three options will be used to satisfy the playback position
selection in the media element's seeking steps.
2025-10-27 17:28:49 -07:00
Zaggy1024
0ff330c906 LibMedia: Play audio through PlaybackManager using Providers/Sinks
This commit implements the functionality to play back audio through
PlaybackManager.

To decode the audio data, AudioDataProviders are created for each track
in the provided media data. These providers will fill their audio block
queue, then sit idle until their corresponding tracks are enabled.

In order to output the audio, one AudioMixingSink is created which
manages a PlaybackStream which requests audio blocks from multiple
AudioDataProviders and mixes them into one buffer with sample-perfect
precision.
2025-10-27 17:28:49 -07:00