Commit graph

22 commits

Author SHA1 Message Date
Zaggy1024
47200f9e6d LibMedia: Don't change pipeline state from Error outside seeks 2026-06-11 05:49:14 -05:00
Zaggy1024
4fcb714327 LibMedia: Only clear decoded data producers' halt status on move
We don't need to proactively reset this anymore with the break out of
halting being determined by seek IDs instead. This will ensure that a
halting status upon a fast-path seek will still remain correct.
2026-06-11 05:49:14 -05:00
Zaggy1024
5f384cbb05 LibMedia: Simplify error wait handling in the decoded data producers
Checking for a seek within the error wait loop wasn't necessary, and
unlocking/relocking could actually lose a wake anyway. Callers always
break out of the decode loop into the thread loop, so this will still
seek immediately as before.
2026-06-11 05:49:14 -05:00
Zaggy1024
c047d62279 LibMedia: Track when demuxers move position even upon errors
Otherwise, we can lose the signal if a seek is aborted after it has
moved the demuxer, making the sink not output until it reaches the time
of the last data it pulled.
2026-06-11 05:49:14 -05:00
Zaggy1024
7ddbc2d7dd LibWeb+LibMedia: Wire up setting the pipeline's playback rate
However, the playback rate is still limited to 1.0 at the element,
because audio stretching is not yet implemented.
2026-06-06 19:58:17 -05:00
Zaggy1024
9ca1db3bb8 LibMedia: Rename timing getters in AudioBlock
This new naming will make timescale modifications more comprehensible.
2026-06-06 19:58:17 -05:00
Andreas Kling
aad293dacc LibMedia: Use direct references to main event loops
Pass direct Core::EventLoop references through media producer and
playback plumbing that posts work back to the main thread. The browser
process main loops stay alive for the process lifetime, so these paths
no longer need weak event loop references.

Update LibMedia tests to pass their stack event loop directly to the
producer helpers.
2026-06-05 09:18:39 +02:00
Zaggy1024
020fe311d8 LibMedia: Only clear decoder thread queues if the demuxer seek moves
Clearing the queue unconditionally here isn't right, since we could end
up with the prior frame to the target in the queue rather than being
decoded by handle_seek().
2026-05-23 11:23:09 -05:00
Zaggy1024
5d1dfec680 LibMedia: Don't increment the seek when completing in the video queue
Incrementing the seek ID isn't really necessary here, since the wake
doesn't actually notify of seek completion, so if another seek doesn't
use the fast path, it won't complete that seek early anyway.

By incrementing the seek ID, it became necessary to also increment the
processed seek ID, which is actually intended to be mutated only by the
decoding thread, so it could potentially race and allow handle_seek()
to continue when it shouldn't.
2026-05-23 11:23:09 -05:00
Zaggy1024
2153535057 LibMedia: Implement suspension at the decoded data providers
Instead of using a playback state to initiate and wake from suspension,
suspend the decoders themselves based on the time since the last status
check or pull. This allows audio and video to suspend independently,
and fixes videos getting stuck after suspension due to the waking seeks
being skipped downstream of the decoder, leaving the decoder suspended.
2026-05-22 09:30:10 -05:00
Zaggy1024
67b1410b53 LibMedia: Consider in-queue video data producer seeks as processed
This was causing us to get stuck in a Pending state sometimes and not
completing seeks downstream when we should have been.
2026-05-22 09:30:10 -05:00
Zaggy1024
9ebc66dbcf LibMedia: Skip video seeks within queued data
We already have an optimization in demuxers to skip seeking to random
access points when the closest available is not closer than the current
timestamp in the file. This commit extends that same concept to the
rest of the pipeline.

DecodedVideoProducer now tracks a time range that is currently within
the queue. If the seeked time falls within that range, handle_seek()
is skipped, since the downstream can just skip forward to that
timestamp synchronously.

Similarly, DisplayingVideoSink checks whether seeks land in the range
between the current frame and the next frame end, and if so, the seek
never gets sent upstream in the pipeline.

Both use a fudging factor of 1.5x the duration to determine the end of
the available range, since Matroska/WebM doesn't use the same time
units for timestamps and durations, and therefore can leave a gap
between frames.
2026-05-19 15:20:58 -05:00
Zaggy1024
adb0754bc8 LibMedia: Signal downstream nodes whether to clear data after seeks
Seeks don't always move a decoded data producer's head, so we need to
make sure not to remove queued data downstream when that is the case.

To communicate this, the producers can now be queried before pulling
data, allowing them to have an in-band signal to clear the queued data
after a seek has moved the producer and broken monotonicity.

This fixes a flake in HTMLVideoElement-resize-event-during-playback.
2026-05-19 15:20:58 -05:00
Zaggy1024
3b7c1810e6 LibMedia+Tests: Refer to raw audio frames/samples consistently
Previously, we weren't too consistent about the definition of frame and
sample when it relates to raw audio data. This brings all the usages in
the context of raw data in line (hopefully), with samples referring to
a single PCM value, and frames referring to the multiple samples that
make up an instant's audio across all channels.
2026-05-13 02:05:35 -05:00
Zaggy1024
d67bf635e2 LibMedia: Fit the media pipeline nodes into their intended interfaces
Now, all nodes are connected through Sink::connect_input() and
disconnect_input().

AudioMixer now derives from a base AudioProcessor class that inherits
from both AudioSink and AudioProducer. It is the only current node that
can accept multiple inputs, tracking each one by its pointer identity.
2026-05-13 02:05:35 -05:00
Zaggy1024
a4c2c6c0cb LibMedia+LibWeb: Speculatively find keyframes near fast seek targets
This is the new way of handling fast seeks. Instead of delegating the
logic all the way down the pipeline to the decoder thread's seek
handler, we can just determine the timestamp we want to seek to ahead
of time.
2026-05-13 02:05:35 -05:00
Zaggy1024
a06f87d728 LibMedia: Transmit seeks and resolve them through the pipeline
Seeking is now unified under one single method signature implemented by
all producers and transmitted through the pipeline by all sinks. By
doing it this way, we can simply instantaneously notify each node of
the pipeline that it needs to stop what it's doing and seek. For nodes
that are threaded (particularly the source providers), this causes them
to stop pushing data to their queue immediately, so that no stale data
makes it through to the output. Then, when new data does come through,
that is a clear indication that the seek has completed.

Note that track enablement is now through the pipeline as well, which
means that SuspendedStateHandler no longer has a way to suspend newly-
enabled tracks. Decoder suspension will need to be reworked to fit into
this new pipeline, sleeping/disposing and restarting entirely based on
the pull() timing in the producers.
2026-05-13 02:05:35 -05:00
Zaggy1024
2abfa79281 LibMedia: Make the AudioPlaybackSink's processor thread wait for data
Using a callback shared by all producers in the pipeline, notify the
AudioPlaybackSink when it needs to wake up and start processing data
again. Prior to this commit, it was simply burning CPU spinning until
data was produced.
2026-05-13 02:05:35 -05:00
Zaggy1024
7be0ae89e4 LibMedia: Transition producers and sinks to the new pipeline model
This is an intermediate step towards unifying the pipeline around new
Producer/Sink interfaces. Producers now have a pull() method that gets
the next piece of data from them. The pull() method returns a status
that can indicate whether it has current data, and if not, why it's
unavailable. This signal will be passed down the pipeline to the final
sink, which can expose the signal to its user, which in the normal
playback pipeline is PlaybackManager. The signal can be used to
transition between playback states. Currently, this is only hooked up
to the buffering state, but should be used later for ending playback
as well as decoding error propagation.

Buffering is now determined solely based on whether the pipeline is
blocked on incomplete data, so the ready state for video now progresses
past HAVE_METADATA immediately after playback manager initializes. This
will change when files have buffered ranges.
2026-05-13 02:05:35 -05:00
Zaggy1024
ee05b7dbd1 LibMedia: Check the queue size before waiting in decoder threads
This could result in a lost wakeup otherwise.
2026-05-13 02:05:35 -05:00
Zaggy1024
8f7cf75e24 LibMedia: Introduce base classes for producers (e.g. the data decoders) 2026-05-13 02:05:35 -05:00
Zaggy1024
eeff03c980 LibMedia: Rename some folders/identifiers for the upcoming refactor
- Provider -> producer
- (Audio|Video)DataProvider -> Decoded(Audio|Video)Producer
- MediaTimeProvider remains suffixed Provider, moves out of the
  Providers folder to the root of LibMedia

This brings the naming more in line with the intended split
functionality split between different nodes in the pipeline.
2026-05-13 02:05:35 -05:00