Commit graph

84 commits

Author SHA1 Message Date
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
Zaggy1024
c8c64e4819 LibMedia: Store raw audio data as planar
This avoids strided loads for vectorized audio data processing loops.
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
6d84918eb7 Tests: Add a test set for file buffered ranges 2026-05-28 10:30:20 -05:00
Zaggy1024
7d3dd2d641 LibMedia: Implement buffered time range scanning for Matroska 2026-05-28 10:30:20 -05:00
Zaggy1024
fea33aa02f LibMedia+Tests: Add a method to remove data from incremental streams
This will later be used to test updating of buffered time ranges when
data is removed. It will also be needed when data eviction is
implemented.
2026-05-28 10:30:20 -05:00
Zaggy1024
054d6d1b17 Tests: Add tests for available incremental stream byte ranges 2026-05-28 10:30:20 -05:00
Zaggy1024
da64588e72 LibMedia: Remove forced seeks upon errors from Matroska::Reader
This shouldn't actually be necessary, since the sample iterator will
resume from where it hit the error last anyway. Now that the decoded
data producers don't clear their queues when the demuxer doesn't move,
this works just fine for EOF.

This could easily be triggered by scrubbing aborting reads to restart
seeks, which would force us to decode from a prior keyframe instead of
continuing to decode from where the last seek left off if it's faster.
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
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
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
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
R-Goc
02bb892d7a LibThreading/LibSync: Split out sync primitives
This commit splits out synchronization primitives from LibThreading into
LibSync. This is because LibThreading depends on LibCore, while LibCore
needs the synchronization primitives from LibThreading. This worked
while they were header only, but when I tried to add an implementation
file it ran into the circular dependency. To abstract away the pthread
implementation using cpp files is necessary so the synchronization
primitives were moved to a separate library.
2026-05-08 18:58:35 -05:00
antoniospg
0a89e76775 LibMedia: Fix wrong comparison to check if chunk covers new one 2026-05-08 17:51:28 -05:00
Undefine
b9fec5edbf Meta: Rename and merge some lagom_* and ladybird_*
We had both {lagom,ladybird}_test and {lagom,ladybird}_lib, now both
are just one helper. Also rename all other lagom_* helpers to be
ladybird_*.
2026-05-05 22:08:24 +02:00
Zaggy1024
e42d9efcb6 LibMedia: Remove reserved values from CICP enums
These served no purpose, instead we should determine validity with a
full switch statement.
2026-04-18 01:25:00 -05:00
Zaggy1024
2a75c0db62 LibMedia: Add a TimeRanges class to be used for buffered attributes
This will be used by PlaybackManager and Demuxer implementations to
communicate the buffered time up to HTMLMediaElement and SourceBuffer.
2026-04-01 02:54:22 -05:00
Zaggy1024
b5eddc4ff0 LibMedia: Stop using av_find_best_stream() to select preferred tracks
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).
2026-04-01 02:54:22 -05:00
Zaggy1024
d6f821f22d LibMedia: Parse Opus frame durations in Matroska::Reader
Most WebM files don't have their default duration defined, so we need
to parse the Opus frame header to determine the duration. This is
needed for buffered range calculation.
2026-04-01 02:54:22 -05:00
Zaggy1024
6b45a11716 LibMedia: Calculate Matroska block timestamps for their actual tracks
Instead of using a single track entry for all blocks in the file, use a
lookup to get the info needed to calculate the timestamp for the
specific track a block belongs to. No change in behavior for
SampleIterator, since that only returns blocks from the track that was
passed. This will be useful for MSE, since it demuxes all tracks at
once.
2026-04-01 02:54:22 -05:00
Zaggy1024
fbcfc06151 Tests: Add tests for parsing of basic EBML/Matroska building blocks 2026-04-01 02:54:22 -05:00
Zaggy1024
d189be12ba Tests: Increase the TestPlaybackStream disconnection timeout
Apparently the queued task often takes longer than 100ms to finish,
and the stream is kept alive for the duration of its execution.
2026-03-30 20:57:04 -05:00
Zaggy1024
c77eae4a55 Tests: Only end TestPlaybackStream after the promise is resolved
Otherwise, the promise handlers may never be invoked, and we won't know
whether we're matching expectations.

Prior to 39d865b, this test did not actually check if the PulseAudio
stream was able to connect before passing the test. After that commit,
it would instead try to post the rejection to the main thread, which
would either lead to a crash preventing a use-after-free on the main
event loop, or in the more common case, the event loop would be freed
and never invoke the rejection callback.
2026-03-30 20:57:04 -05:00
Zaggy1024
39d865b403 LibMedia: Provide new PlaybackStreams through promises
This allows us to avoid returning a PlaybackStream in cases where the
async initialization fails.

This is a step towards more graceful fallbacks when audio fails in
AudioMixingSink.
2026-03-21 23:11:47 -05:00
Jonathan Gamble
410e17ab29 LibMedia: Fix signed PCM to float sample normalization 2026-02-25 01:50:00 -06:00
Zaggy1024
1453add361 Tests: Use the proper stream close() method in TestFFmpegDemuxer
The test was outdated and needed to be updated before being merged. :^(
2026-02-24 17:51:03 -06:00
Zaggy1024
3a7f1f0b75 Tests: Add a test to read FFmpegDemuxer to EOF after aborting a read 2026-02-24 16:55:40 -06:00
Zaggy1024
af45418fbf Everywhere: Rename IncrementallyPopulatedStream::reached_end_of_body
This needs to be called even if we haven't reached the end of the body,
so let's call it close() instead.
2026-02-18 13:13:32 -06:00
Jonathan Gamble
0dea87110e LibMedia: Fix multi-channel decode for dumb containers (like WAV)
For web audio, I reckon an occasional misjudged channel layout is
better than more frequent exceptions.

Signed PCM is normalized with unsigned max divided by 2, not
signed max. If you divide by the signed max (32767), you get headroom
that can exceed the threshold below -1.0. It's not audible, this mostly
matters for tests that assume correct normalization. But it turns out
there's no shortage of "golden ears" jackholes out there who swear they
can hear the difference.
2026-02-13 17:57:19 -06:00
Zaggy1024
0f69eac657 Tests: Add tests for data providers exiting the suspended state
These tests would crash before the prior commit.
2026-02-09 09:04:21 +01:00
Zaggy1024
ed10073c74 Tests: Add a test for seeking MatroskaDemuxer to EOS 2026-02-06 13:28:09 +01:00
Zaggy1024
972438c4d7 LibMedia: Abstract the interface of IncrementallyPopulatedStream
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.
2026-01-30 10:02:00 -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
798a945e3c Tests: Add tests for Media::IncrementallyPopulatedStream 2026-01-29 18:06:02 -06:00
Zaggy1024
d50ab3015e Tests: Test seeking in Matroska files with and without cues 2026-01-28 16:12:22 -06:00
Zaggy1024
f455901d37 Tests: Add a test for Matroska EBML lacing 2026-01-28 16:12:22 -06:00
Zaggy1024
ee95de40d6 LibMedia: Validate fixed-size Matroska frames
We were allowing Matroska blocks with fixed-size lacing to contain
frames with non-divisible sizes. This should not be possible, as it
inherently means that trailing bytes will be discarded.

We now have a valid and invalid testcase for fixed-size lacing to
ensure our handling remains correct.
2026-01-28 16:12:22 -06:00
Zaggy1024
bc67764606 Tests: Change some VERIFY(x == y) to EXPECT_EQ in TestParseMatroska 2026-01-28 16:12:22 -06:00
Zaggy1024
f0d7d1d5f5 LibMedia: Track Matroska master element ends with position()
We don't actually need a Vector stack of bytes read for each element
we're reading out of a Matroska file, we already have the C++ stack
in which we can store the start and end of the master elements we're
reading.

This fixes an issue where seeks while parsing master elements would not
increment m_octets_read, so the master element could continue reading
further than intended.

This could cause a BlockGroup followed by a SimpleBlock to read as if
the BlockGroup contained the SimpleBlock, meaning that SampleIterator
would skip the SimpleBlock.

A test is added to ensure this doesn't regress again.
2026-01-28 14:48:03 -06:00
Tim Ledbetter
5d5188a679 Tests/LibMedia: Add test for reserved and unspecified CICP handling 2026-01-27 11:34:24 -06:00
Zaggy1024
e6dbcccb99 LibGfx+LibMedia: Send video frames to Skia as subsampled YUV
This saves us from having our own color conversion code, which was
taking up a fair amount of time in VideoDataProvider. With this change,
we should be able to play high resolution videos without interruptions
on machines where the CPU can keep up with decoding.

In order to make this change, ImmutableBitmap is now able to be
constructed with YUV data instead of an RBG bitmap. It holds onto a
YUVData instance that stores the buffers of image data, since Skia
itself doesn't take ownership of them.

In order to support greater than 8 bits of color depth, we normalize
the 10- or 12-bit color values into a 16-bit range.
2026-01-22 19:44:36 +01:00
Undefine
6280ca0275 Tests: Explicitly link TestPlaybackStream against PulseAudio
This fixes a compile issue on FreeBSD where this would not compile as
the `pulse/pulseaudio.h` header is not in the default search path,
instead it is in `/usr/local/include'. This is a problem because this
test manually includes `PulseAudioWrappers.h`.
2026-01-12 20:58:21 +01:00
Zaggy1024
9a421ffe9f LibMedia: Make demuxers thread-safe and remove MutexedDemuxer 2026-01-07 00:13:32 +01:00
Zaggy1024
b77980b4cc LibMedia: Move Matroska's get_frames method to SampleIterator
This ensures that we're using the reader for the particular thread that
the block was read from, avoiding any race conditions between seeks and
reads across threads.
2026-01-07 00:13:32 +01:00
Zaggy1024
5aa5beed26 LibMedia: Avoid copying Matroska block data when seeking
We only need to get the frames from a block when requested by the
demuxer, so factor that out into a function that it can call when it is
outputting frames.
2026-01-05 17:53:24 -06:00
Gingeh
451177f1f4 LibMedia: Propagate errors from create_context_for_track 2026-01-02 16:19:44 +01:00
Zaggy1024
744abc0c18 Tests: Use some tasks when testing PlaybackStream
This doesn't help to reproduce the potential UAF in the previous
commit, but it doesn't hurt to include this nonetheless.
2025-12-29 19:58:22 -06:00
R-Goc
1f3e20cebf LibMedia: Add a WASAPI playback stream for Windows
Implement PlaybackStream using WASAPI. The design is similar to
PlaybackStreamAudioUnit in that it uses a task queue. A high priority
thread is used to render the stream. All the stream controls save for
the exit being requested which happens on destruction of the stream are
managed by the render thread.

Due to the design of the windows audio mixer the audio we receive must
be resampled to match the sample rate of the mixer. We use a float based
interleaved PCM stream which matches both our existing code and the
audio mixer which internally usues floats.

Having to use a mutex around a queue for the task queue is suboptimal,
in a future PR a MPSC queue could be added to AK and used instead.
2025-12-29 18:02:02 -06: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