LibMedia: Make demuxers thread-safe and remove MutexedDemuxer

This commit is contained in:
Zaggy1024 2026-01-06 12:03:40 -06:00 committed by Alexander Kalenik
parent 4261d73781
commit 9a421ffe9f
10 changed files with 18 additions and 115 deletions

View file

@ -86,6 +86,7 @@ static Track track_from_track_entry(TrackEntry const& track_entry)
DecoderErrorOr<void> MatroskaDemuxer::create_context_for_track(Track const& track, NonnullRefPtr<IncrementallyPopulatedStream::Cursor> const& stream_cursor)
{
auto iterator = TRY(m_reader.create_sample_iterator(stream_cursor, track.identifier()));
Threading::MutexLocker locker(m_track_statuses_mutex);
VERIFY(m_track_statuses.set(track, TrackStatus(move(iterator))) == HashSetResult::InsertedNewEntry);
return {};
}
@ -116,6 +117,7 @@ DecoderErrorOr<Optional<Track>> MatroskaDemuxer::get_preferred_track_for_type(Tr
DecoderErrorOr<MatroskaDemuxer::TrackStatus*> MatroskaDemuxer::get_track_status(Track const& track)
{
Threading::MutexLocker locker(m_track_statuses_mutex);
return &m_track_statuses.get(track).release_value();
}

View file

@ -10,6 +10,7 @@
#include <LibMedia/Demuxer.h>
#include <LibMedia/Export.h>
#include <LibMedia/IncrementallyPopulatedStream.h>
#include <LibThreading/Mutex.h>
#include "Reader.h"
@ -57,6 +58,7 @@ private:
Reader m_reader;
mutable Threading::Mutex m_track_statuses_mutex;
HashMap<Track, TrackStatus> m_track_statuses;
};

View file

@ -20,7 +20,6 @@ class DisplayingVideoSink;
class FrameQueueItem;
class IncrementallyPopulatedStream;
class MediaTimeProvider;
class MutexedDemuxer;
class PlaybackManager;
class Track;
class VideoDataProvider;

View file

@ -1,96 +0,0 @@
/*
* Copyright (c) 2022, Gregory Bertilson <zaggy1024@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Forward.h>
#include <LibMedia/DecoderError.h>
#include <LibThreading/MutexProtected.h>
#include "Demuxer.h"
namespace Media {
class MutexedDemuxer final : public Demuxer {
public:
MutexedDemuxer(NonnullRefPtr<Demuxer> demuxer)
: m_demuxer(move(demuxer))
{
}
virtual ~MutexedDemuxer() override
{
m_demuxer.with_locked([](auto& demuxer) {
auto to_destroy = move(demuxer);
});
}
virtual DecoderErrorOr<void> create_context_for_track(Track const& track, NonnullRefPtr<IncrementallyPopulatedStream::Cursor> const& stream_cursor) override
{
return m_demuxer.with_locked([&](auto& demuxer) {
return demuxer->create_context_for_track(track, stream_cursor);
});
}
virtual DecoderErrorOr<Vector<Track>> get_tracks_for_type(TrackType type) override
{
return m_demuxer.with_locked([&](auto& demuxer) {
return demuxer->get_tracks_for_type(type);
});
}
virtual DecoderErrorOr<Optional<Track>> get_preferred_track_for_type(TrackType type) override
{
return m_demuxer.with_locked([&](auto& demuxer) {
return demuxer->get_preferred_track_for_type(type);
});
}
virtual DecoderErrorOr<CodedFrame> get_next_sample_for_track(Track const& track) override
{
return m_demuxer.with_locked([&](auto& demuxer) {
return demuxer->get_next_sample_for_track(track);
});
}
virtual DecoderErrorOr<CodecID> get_codec_id_for_track(Track const& track) override
{
return m_demuxer.with_locked([&](auto& demuxer) {
return demuxer->get_codec_id_for_track(track);
});
}
virtual DecoderErrorOr<ReadonlyBytes> get_codec_initialization_data_for_track(Track const& track) override
{
return m_demuxer.with_locked([&](auto& demuxer) {
return demuxer->get_codec_initialization_data_for_track(track);
});
}
virtual DecoderErrorOr<DemuxerSeekResult> seek_to_most_recent_keyframe(Track const& track, AK::Duration timestamp, DemuxerSeekOptions seek_options = DemuxerSeekOptions::None) override
{
return m_demuxer.with_locked([&](auto& demuxer) {
return demuxer->seek_to_most_recent_keyframe(track, timestamp, seek_options);
});
}
virtual DecoderErrorOr<AK::Duration> duration_of_track(Track const& track) override
{
return m_demuxer.with_locked([&](auto& demuxer) {
return demuxer->duration_of_track(track);
});
}
virtual DecoderErrorOr<AK::Duration> total_duration() override
{
return m_demuxer.with_locked([&](auto& demuxer) {
return demuxer->total_duration();
});
}
private:
Threading::MutexProtected<NonnullRefPtr<Demuxer>> m_demuxer;
};
}

View file

@ -7,7 +7,6 @@
#include <LibMedia/Containers/Matroska/MatroskaDemuxer.h>
#include <LibMedia/Demuxer.h>
#include <LibMedia/FFmpeg/FFmpegDemuxer.h>
#include <LibMedia/MutexedDemuxer.h>
#include <LibMedia/PlaybackStates/PausedStateHandler.h>
#include <LibMedia/Providers/AudioDataProvider.h>
#include <LibMedia/Providers/GenericTimeProvider.h>
@ -24,12 +23,11 @@ namespace Media {
DecoderErrorOr<void> PlaybackManager::prepare_playback_from_media_data(NonnullRefPtr<IncrementallyPopulatedStream> stream, NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop_reference)
{
auto inner_demuxer = TRY([&] -> DecoderErrorOr<NonnullRefPtr<Demuxer>> {
auto demuxer = TRY([&] -> DecoderErrorOr<NonnullRefPtr<Demuxer>> {
if (Matroska::Reader::is_matroska_or_webm(stream->create_cursor()))
return Matroska::MatroskaDemuxer::from_stream(stream->create_cursor());
return FFmpeg::FFmpegDemuxer::from_stream(stream->create_cursor());
}());
auto demuxer = DECODER_TRY_ALLOC(try_make_ref_counted<MutexedDemuxer>(inner_demuxer));
// Create the video tracks and their data providers.
auto all_video_tracks = TRY(demuxer->get_tracks_for_type(TrackType::Video));

View file

@ -7,9 +7,9 @@
#include <AK/Debug.h>
#include <LibCore/EventLoop.h>
#include <LibMedia/Audio/SampleSpecification.h>
#include <LibMedia/Demuxer.h>
#include <LibMedia/FFmpeg/FFmpegAudioConverter.h>
#include <LibMedia/FFmpeg/FFmpegAudioDecoder.h>
#include <LibMedia/MutexedDemuxer.h>
#include <LibMedia/Sinks/AudioSink.h>
#include <LibThreading/Mutex.h>
#include <LibThreading/Thread.h>
@ -18,7 +18,7 @@
namespace Media {
DecoderErrorOr<NonnullRefPtr<AudioDataProvider>> AudioDataProvider::try_create(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const& demuxer, NonnullRefPtr<IncrementallyPopulatedStream> const& stream, Track const& track)
DecoderErrorOr<NonnullRefPtr<AudioDataProvider>> AudioDataProvider::try_create(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const& demuxer, NonnullRefPtr<IncrementallyPopulatedStream> const& stream, Track const& track)
{
auto codec_id = TRY(demuxer->get_codec_id_for_track(track));
auto const& sample_specification = track.audio_data().sample_specification;
@ -80,7 +80,7 @@ void AudioDataProvider::seek(AK::Duration timestamp, SeekCompletionHandler&& com
m_thread_data->seek(timestamp, move(completion_handler));
}
AudioDataProvider::ThreadData::ThreadData(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const& demuxer, NonnullRefPtr<IncrementallyPopulatedStream::Cursor> const& stream_cursor, Track const& track, NonnullOwnPtr<AudioDecoder>&& decoder, NonnullOwnPtr<Audio::AudioConverter>&& converter)
AudioDataProvider::ThreadData::ThreadData(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const& demuxer, NonnullRefPtr<IncrementallyPopulatedStream::Cursor> const& stream_cursor, Track const& track, NonnullOwnPtr<AudioDecoder>&& decoder, NonnullOwnPtr<Audio::AudioConverter>&& converter)
: m_main_thread_event_loop(main_thread_event_loop)
, m_demuxer(demuxer)
, m_stream_cursor(stream_cursor)

View file

@ -37,7 +37,7 @@ public:
using BlockEndTimeHandler = Function<void(AK::Duration)>;
using SeekCompletionHandler = Function<void()>;
static DecoderErrorOr<NonnullRefPtr<AudioDataProvider>> try_create(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const& demuxer, NonnullRefPtr<IncrementallyPopulatedStream> const&, Track const& track);
static DecoderErrorOr<NonnullRefPtr<AudioDataProvider>> try_create(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const& demuxer, NonnullRefPtr<IncrementallyPopulatedStream> const&, Track const& track);
AudioDataProvider(NonnullRefPtr<ThreadData> const&);
~AudioDataProvider();
@ -54,7 +54,7 @@ public:
private:
class ThreadData final : public AtomicRefCounted<ThreadData> {
public:
ThreadData(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const&, NonnullRefPtr<IncrementallyPopulatedStream::Cursor> const&, Track const&, NonnullOwnPtr<AudioDecoder>&&, NonnullOwnPtr<Audio::AudioConverter>&&);
ThreadData(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const&, NonnullRefPtr<IncrementallyPopulatedStream::Cursor> const&, Track const&, NonnullOwnPtr<AudioDecoder>&&, NonnullOwnPtr<Audio::AudioConverter>&&);
~ThreadData();
void set_error_handler(ErrorHandler&&);
@ -101,7 +101,7 @@ private:
mutable Threading::ConditionVariable m_wait_condition { m_mutex };
RequestedState m_requested_state { RequestedState::None };
NonnullRefPtr<MutexedDemuxer> m_demuxer;
NonnullRefPtr<Demuxer> m_demuxer;
NonnullRefPtr<IncrementallyPopulatedStream::Cursor> m_stream_cursor;
Track m_track;
NonnullOwnPtr<AudioDecoder> m_decoder;

View file

@ -5,8 +5,8 @@
*/
#include <LibCore/EventLoop.h>
#include <LibMedia/Demuxer.h>
#include <LibMedia/FFmpeg/FFmpegVideoDecoder.h>
#include <LibMedia/MutexedDemuxer.h>
#include <LibMedia/Providers/MediaTimeProvider.h>
#include <LibMedia/Sinks/VideoSink.h>
#include <LibMedia/VideoDecoder.h>
@ -17,7 +17,7 @@
namespace Media {
DecoderErrorOr<NonnullRefPtr<VideoDataProvider>> VideoDataProvider::try_create(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const& demuxer, NonnullRefPtr<IncrementallyPopulatedStream> const& stream, Track const& track, RefPtr<MediaTimeProvider> const& time_provider)
DecoderErrorOr<NonnullRefPtr<VideoDataProvider>> VideoDataProvider::try_create(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const& demuxer, NonnullRefPtr<IncrementallyPopulatedStream> const& stream, Track const& track, RefPtr<MediaTimeProvider> const& time_provider)
{
auto codec_id = TRY(demuxer->get_codec_id_for_track(track));
auto codec_initialization_data = TRY(demuxer->get_codec_initialization_data_for_track(track));
@ -88,7 +88,7 @@ void VideoDataProvider::seek(AK::Duration timestamp, SeekMode seek_mode, SeekCom
m_thread_data->seek(timestamp, seek_mode, move(completion_handler));
}
VideoDataProvider::ThreadData::ThreadData(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const& demuxer, NonnullRefPtr<IncrementallyPopulatedStream::Cursor> const& stream_cursor, Track const& track, NonnullOwnPtr<VideoDecoder>&& decoder, RefPtr<MediaTimeProvider> const& time_provider)
VideoDataProvider::ThreadData::ThreadData(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const& demuxer, NonnullRefPtr<IncrementallyPopulatedStream::Cursor> const& stream_cursor, Track const& track, NonnullOwnPtr<VideoDecoder>&& decoder, RefPtr<MediaTimeProvider> const& time_provider)
: m_main_thread_event_loop(main_thread_event_loop)
, m_demuxer(demuxer)
, m_stream_cursor(stream_cursor)

View file

@ -38,7 +38,7 @@ public:
using SeekCompletionHandler = Function<void(AK::Duration)>;
using FramesQueueIsFullHandler = Function<void()>;
static DecoderErrorOr<NonnullRefPtr<VideoDataProvider>> try_create(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const&, NonnullRefPtr<IncrementallyPopulatedStream> const&, Track const&, RefPtr<MediaTimeProvider> const& = nullptr);
static DecoderErrorOr<NonnullRefPtr<VideoDataProvider>> try_create(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const&, NonnullRefPtr<IncrementallyPopulatedStream> const&, Track const&, RefPtr<MediaTimeProvider> const& = nullptr);
VideoDataProvider(NonnullRefPtr<ThreadData> const&);
~VideoDataProvider();
@ -58,7 +58,7 @@ public:
private:
class ThreadData final : public AtomicRefCounted<ThreadData> {
public:
ThreadData(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const&, NonnullRefPtr<IncrementallyPopulatedStream::Cursor> const&, Track const&, NonnullOwnPtr<VideoDecoder>&&, RefPtr<MediaTimeProvider> const&);
ThreadData(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const&, NonnullRefPtr<IncrementallyPopulatedStream::Cursor> const&, Track const&, NonnullOwnPtr<VideoDecoder>&&, RefPtr<MediaTimeProvider> const&);
~ThreadData();
void set_error_handler(ErrorHandler&&);
@ -105,7 +105,7 @@ private:
mutable Threading::ConditionVariable m_wait_condition { m_mutex };
RequestedState m_requested_state { RequestedState::None };
NonnullRefPtr<MutexedDemuxer> m_demuxer;
NonnullRefPtr<Demuxer> m_demuxer;
NonnullRefPtr<IncrementallyPopulatedStream::Cursor> m_stream_cursor;
Track m_track;
NonnullOwnPtr<VideoDecoder> m_decoder;

View file

@ -13,7 +13,6 @@
#include <LibMedia/Containers/Matroska/Reader.h>
#include <LibMedia/Demuxer.h>
#include <LibMedia/FFmpeg/FFmpegDemuxer.h>
#include <LibMedia/MutexedDemuxer.h>
#include <LibMedia/Providers/AudioDataProvider.h>
#include <LibMedia/VideoDecoder.h>
#include <LibMedia/VideoFrame.h>
@ -72,13 +71,12 @@ static inline void decode_audio(StringView path, u32 sample_rate, u8 channel_cou
auto file = MUST(Core::File::open(path, Core::File::OpenMode::Read));
auto stream = Media::IncrementallyPopulatedStream::create_from_buffer(MUST(file->read_until_eof()));
auto inner_demuxer = MUST([&] -> Media::DecoderErrorOr<NonnullRefPtr<Media::Demuxer>> {
auto demuxer = MUST([&] -> Media::DecoderErrorOr<NonnullRefPtr<Media::Demuxer>> {
auto matroska_result = Media::Matroska::MatroskaDemuxer::from_stream(stream->create_cursor());
if (!matroska_result.is_error())
return matroska_result.release_value();
return Media::FFmpeg::FFmpegDemuxer::from_stream(stream->create_cursor());
}());
auto demuxer = make_ref_counted<Media::MutexedDemuxer>(inner_demuxer);
auto track = TRY_OR_FAIL(demuxer->get_preferred_track_for_type(Media::TrackType::Audio));
VERIFY(track.has_value());
auto provider = TRY_OR_FAIL(Media::AudioDataProvider::try_create(Core::EventLoop::current_weak(), demuxer, stream, track.release_value()));