Commit Graph

56 Commits

Author SHA1 Message Date
Jonathan Gamble
410e17ab29 LibMedia: Fix signed PCM to float sample normalization 2026-02-25 01:50:00 -06:00
Zaggy1024
4778c6a53b LibMedia: Deal with aborts in FFmpegDemuxer instead of the IO context
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.
2026-02-24 16:55:40 -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
27d413c193 LibMedia: Dispose FFmpegDemuxer's tracks' format contexts
This fixes a leak that was oddly enough only just detected in CI.
2026-01-30 16:40:21 -06: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
31cc0c0a45 LibMedia: Save info from FFmpeg's AVFormatContext and destroy it
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.
2026-01-30 10:02:00 -06:00
Tim Ledbetter
1aa68689ff LibMedia: Remove default_code_points_if_unspecified()
This function is no longer needed as CICP values are now defaulted
downstream.
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
Gingeh
451177f1f4 LibMedia: Propagate errors from create_context_for_track 2026-01-02 16:19:44 +01:00
Aliaksandr Kalenik
21e8ece013 LibMedia: Abort blocking reads for ongoing seek if it's replaced
When a seek is requested while a previous seek is still blocked waiting
for not yet available bytes, we want to abandon the old request
immediately and start processing the new one.
2025-12-16 02:42:48 -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
Zaggy1024
269f232e52 LibMedia: Correct the formula for converting u8 samples to float 2025-12-15 18:03:03 -06:00
Zaggy1024
7c101ab910 LibMedia: Add WAV PCM codecs to CodecID
This is a subset of FFmpeg's PCM codec IDs, limited to only the ones
that are supported by its WAV encoder.
2025-12-15 18:03:03 -06:00
Zaggy1024
fa3cda8e4a LibMedia: Set the AVCodecContext's sample rate and channel layout
This is required in order for our audio block output function to create
a sample specification for WAV files.
2025-12-15 18:03:03 -06:00
Zaggy1024
b4ca17fd29 LibMedia: Store a SampleSpecification in Track
This allows FFmpegDemuxer to communicate the data necessary to convert
WAV PCM to whatever our output format is.
2025-12-15 18:03:03 -06:00
Zaggy1024
65c0be66e4 LibMedia: Implement audio conversion in AudioDataProvider 2025-12-13 08:58:26 +01:00
Zaggy1024
19ccec2c10 LibMedia: Create a channel map for audio blocks from decoders
Audio blocks now contain a sample specification with the sample rate
and channel map for the audio data they contain. This will facilitate
conversion from one sample specification to another in order to allow
playback on devices with more or less speakers than the audio data
contains.
2025-12-13 08:58:26 +01:00
Zaggy1024
81a473314d LibMedia: Store the duration of VideoFrames 2025-12-10 16:02:40 -06:00
Zaggy1024
42b19bdebf LibMedia: Store a duration in CodedFrame 2025-12-10 16:02:40 -06:00
Zaggy1024
7e325d64f5 LibMedia: Use [from/to]_time_units in FFmpegDemuxer and AudioMixingSink 2025-11-17 16:51:18 +01:00
Zaggy1024
0e9c746b48 LibMedia: Allow signalling of EOF to decoders
This is used by FFmpeg's H.264 decoder to determine when to output any
buffered frames after data runs out.
2025-11-05 18:40:02 +01:00
Zaggy1024
634e5ff491 LibMedia: Move CICP values from CodedFrame to Track
All our current demuxers have these constant for an entire track, so we
don't need to get them for every frame we output.
2025-11-05 18:40:02 +01:00
Zaggy1024
6bd7e338fd LibMedia: Remove redundant parameter names in Demuxer 2025-11-05 18:40:02 +01:00
Zaggy1024
4cf0a77d38 LibMedia: Export FFmpegDemuxer to allow direct use of data providers
We can use forward declarations of the FFmpeg types within the header
to allow it to be exported without causing errors in using code.
2025-10-27 17:28:49 -07:00
Zaggy1024
fcde0f66c8 LibMedia: Allow FFmpegDemuxer to grab samples from multiple streams
In order to do so, we create a AVFormatContext for each stream we want
to demux.
2025-10-27 17:28:49 -07:00
Zaggy1024
9c960c3307 LibMedia: Use integer math to calculate the FFmpeg seek target pts 2025-10-27 17:28:49 -07:00
Zaggy1024
b1c9a872bc LibMedia: Return whether a demuxer seek moved the stream position
We no longer need to return a timestamp from the seek function, which
makes it much easier to implement backend-agnostically.
2025-10-27 17:28:49 -07:00
Zaggy1024
86e236519d LibMedia: Give demuxer seeks an option to always seek to a keyframe
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.
2025-10-27 17:28:49 -07:00
Zaggy1024
0a03cc1cf7 LibMedia: Store whether a CodedFrame is a keyframe 2025-10-27 17:28:49 -07:00
Zaggy1024
d52ceec1bf LibMedia: Take Track const& in Demuxer methods 2025-10-27 17:28:49 -07:00
Zaggy1024
d3941cd83d LibMedia: Support playing FLAC 2025-10-27 17:28:49 -07:00
Zaggy1024
e11da1f85f LibMedia: Store a name and language in Media::Track 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
Zaggy1024
dd052832c1 LibMedia: Support the MP3 and AAC codecs in our demuxer 2025-10-27 17:28:49 -07:00
Zaggy1024
6b34003c2c LibMedia: Support coded audio frames in our demuxers
This adds a new variant of the metadata storage in CodedFrame for audio
frames, called CodedAudioFrameData.
2025-10-27 17:28:49 -07:00
Zaggy1024
dfbad09315 LibMedia: Set the time base in FFmpegVideoDecoder
Very minor change, which doesn't actually affect our output, since we
were already inputting and outputting microseconds, but it can't hurt
to give FFmpeg's decoder this information as well.
2025-10-27 17:28:49 -07:00
Zaggy1024
523e7e2ffa LibMedia: Make Demuxer atomically ref-counted
We'll need to share the demuxer between multiple decoder providers, and
those will hold references to the demuxer from their own decoder
threads.
2025-10-27 17:28:49 -07:00
Zaggy1024
319e381eb9 LibMedia: Mark FFmpegVideoDecoder functions with virtual override
The destructor lacked any of these specifiers, and others lacked the
virtual specifier.
2025-09-22 19:34:48 +02:00
Zaggy1024
fc1cc49d6a LibMedia: Remove an unused private function from FFmpegVideoDecoder 2025-09-22 12:04:29 -05:00
Zaggy1024
6cbe607ecf LibMedia+Tests: Call decoder input samples "coded data" for clarity
The word sample is very ambiguous in the realm of decoders, so let's
just make it abundantly clear what the decoder is receiving.
2025-09-22 12:04:29 -05:00
Zaggy1024
8d77e8b09d LibMedia: Refer to demuxer outputs as coded frames
This should be a clearer name, as "sample" is most often used to refer
to the output of a decoder.
2025-09-22 12:04:29 -05:00
Zaggy1024
7434c763d5 LibMedia: Remove default cases when converting CodecID for FFmpeg
This forces us to keep at least that conversion switch statement
up-to-date.
2025-09-19 13:01:00 +02:00
Zaggy1024
ae7f82591b LibMedia: Separate file duration from track duration in Demuxer
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.
2025-09-12 11:23:47 +02:00
Zaggy1024
6653b747ff LibMedia: Allow demuxers to specify a preferred track
...and return all tracks of a matching type from FFmpegDemuxer, rather
than only the single best one.
2025-09-12 11:23:47 +02:00
Zaggy1024
8d64e72655 LibMedia: Remove the duration field from Track::VideoData
Most demuxer users will only care about the whole file's duration
anyway, so this field doesn't really do us any good.
2025-09-12 11:23:47 +02:00
Zaggy1024
f9305e7e67 LibMedia: Format switch statements consistently in FFmpegVideoDecoder 2025-09-11 18:41:58 -05:00
Zaggy1024
924ba6c1f4 LibMedia: Use FFmpeg's info to tell us if YUVJ is full-range
It reports this correctly for the video linked in #4993, and likely any
other videos using the YUVJ format, so we don't need this extra check.
2025-09-11 18:41:58 -05:00
Zaggy1024
cae14c763d LibMedia: Convert FFmpeg time units to AK::Duration with integer math
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.
2025-09-08 13:29:04 -05:00
ayeteadoe
8150fb4cbb LibMedia: Enable EXPLICIT_SYMBOL_EXPORT 2025-08-24 12:58:27 -06:00