Skip to content

Commit a51d3d2

Browse files
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.
1 parent 786ea6c commit a51d3d2

File tree

9 files changed

+269
-205
lines changed

9 files changed

+269
-205
lines changed

Libraries/LibMedia/PlaybackManager.cpp

Lines changed: 76 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
#include <LibMedia/Containers/Matroska/MatroskaDemuxer.h>
8+
#include <LibMedia/Demuxer.h>
89
#include <LibMedia/FFmpeg/FFmpegDemuxer.h>
910
#include <LibMedia/MutexedDemuxer.h>
1011
#include <LibMedia/PlaybackStates/PausedStateHandler.h>
@@ -15,24 +16,22 @@
1516
#include <LibMedia/Sinks/AudioMixingSink.h>
1617
#include <LibMedia/Sinks/DisplayingVideoSink.h>
1718
#include <LibMedia/Track.h>
19+
#include <LibThreading/Thread.h>
1820

1921
#include "PlaybackManager.h"
2022

2123
namespace Media {
2224

23-
DecoderErrorOr<NonnullRefPtr<PlaybackManager>> PlaybackManager::try_create(ReadonlyBytes data)
25+
DecoderErrorOr<void> PlaybackManager::prepare_playback_from_media_data(ReadonlyBytes media_data, Core::EventLoop& main_thread_event_loop)
2426
{
2527
auto inner_demuxer = TRY([&] -> DecoderErrorOr<NonnullRefPtr<Demuxer>> {
26-
auto matroska_result = Matroska::MatroskaDemuxer::from_data(data);
28+
auto matroska_result = Matroska::MatroskaDemuxer::from_data(media_data);
2729
if (!matroska_result.is_error())
2830
return matroska_result.release_value();
29-
return TRY(FFmpeg::FFmpegDemuxer::from_data(data));
31+
return TRY(FFmpeg::FFmpegDemuxer::from_data(media_data));
3032
}());
3133
auto demuxer = DECODER_TRY_ALLOC(try_make_ref_counted<MutexedDemuxer>(inner_demuxer));
3234

33-
// Create the weak wrapper.
34-
auto weak_playback_manager = DECODER_TRY_ALLOC(try_make_ref_counted<WeakPlaybackManager>());
35-
3635
// Create the video tracks and their data providers.
3736
auto all_video_tracks = TRY(demuxer->get_tracks_for_type(TrackType::Video));
3837

@@ -41,7 +40,7 @@ DecoderErrorOr<NonnullRefPtr<PlaybackManager>> PlaybackManager::try_create(Reado
4140
supported_video_tracks.ensure_capacity(all_video_tracks.size());
4241
supported_video_track_datas.ensure_capacity(all_video_tracks.size());
4342
for (auto const& track : all_video_tracks) {
44-
auto video_data_provider_result = VideoDataProvider::try_create(demuxer, track);
43+
auto video_data_provider_result = VideoDataProvider::try_create(main_thread_event_loop, demuxer, track);
4544
if (video_data_provider_result.is_error())
4645
continue;
4746
supported_video_tracks.append(track);
@@ -58,7 +57,7 @@ DecoderErrorOr<NonnullRefPtr<PlaybackManager>> PlaybackManager::try_create(Reado
5857
supported_audio_tracks.ensure_capacity(all_audio_tracks.size());
5958
supported_audio_track_datas.ensure_capacity(all_audio_tracks.size());
6059
for (auto const& track : all_audio_tracks) {
61-
auto audio_data_provider_result = AudioDataProvider::try_create(demuxer, track);
60+
auto audio_data_provider_result = AudioDataProvider::try_create(main_thread_event_loop, demuxer, track);
6261
if (audio_data_provider_result.is_error())
6362
continue;
6463
auto audio_data_provider = audio_data_provider_result.release_value();
@@ -71,41 +70,86 @@ DecoderErrorOr<NonnullRefPtr<PlaybackManager>> PlaybackManager::try_create(Reado
7170
if (supported_video_tracks.is_empty() && supported_audio_tracks.is_empty())
7271
return DecoderError::with_description(DecoderErrorCategory::NotImplemented, "No supported video or audio tracks found"sv);
7372

74-
RefPtr<AudioMixingSink> audio_sink = nullptr;
75-
if (!supported_audio_tracks.is_empty())
76-
audio_sink = DECODER_TRY_ALLOC(AudioMixingSink::try_create());
77-
78-
// Create the time provider.
79-
auto time_provider = DECODER_TRY_ALLOC([&] -> ErrorOr<NonnullRefPtr<MediaTimeProvider>> {
80-
if (audio_sink)
81-
return TRY(try_make_ref_counted<WrapperTimeProvider<AudioMixingSink>>(*audio_sink));
82-
return TRY(try_make_ref_counted<GenericTimeProvider>());
83-
}());
73+
auto preferred_video_track = demuxer->get_preferred_track_for_type(TrackType::Video).value_or({});
74+
if (preferred_video_track.has_value() && !supported_video_tracks.contains_slow(*preferred_video_track))
75+
preferred_video_track = {};
76+
auto preferred_audio_track = demuxer->get_preferred_track_for_type(TrackType::Audio).value_or({});
77+
if (preferred_audio_track.has_value() && !supported_audio_tracks.contains_slow(*preferred_audio_track))
78+
preferred_audio_track = {};
79+
80+
auto duration = demuxer->total_duration().value_or(AK::Duration::zero());
81+
82+
main_thread_event_loop.deferred_invoke([playback_manager = NonnullRefPtr { *this }, video_tracks = move(supported_video_tracks), video_track_datas = move(supported_video_track_datas), preferred_video_track, audio_tracks = move(supported_audio_tracks), audio_track_datas = move(supported_audio_track_datas), preferred_audio_track, duration] mutable {
83+
playback_manager->m_video_tracks.extend(move(video_tracks));
84+
playback_manager->m_video_track_datas.extend(move(video_track_datas));
85+
playback_manager->m_audio_tracks.extend(move(audio_tracks));
86+
playback_manager->m_audio_track_datas.extend(move(audio_track_datas));
87+
playback_manager->m_preferred_video_track = preferred_video_track;
88+
playback_manager->m_preferred_audio_track = preferred_audio_track;
89+
playback_manager->m_duration = move(duration);
90+
91+
playback_manager->set_up_error_handlers();
92+
93+
if (!playback_manager->m_audio_tracks.is_empty()) {
94+
playback_manager->m_audio_sink = MUST(AudioMixingSink::try_create());
95+
}
96+
97+
if (auto audio_sink = playback_manager->m_audio_sink) {
98+
VERIFY(playback_manager->current_time().is_zero());
99+
playback_manager->m_time_provider = make_ref_counted<WrapperTimeProvider<AudioMixingSink>>(*audio_sink);
100+
}
101+
102+
if (playback_manager->on_track_added) {
103+
for (auto const& audio_track : playback_manager->m_audio_tracks)
104+
playback_manager->on_track_added(TrackType::Audio, audio_track);
105+
for (auto const& video_track : playback_manager->m_video_tracks)
106+
playback_manager->on_track_added(TrackType::Video, video_track);
107+
}
108+
109+
if (playback_manager->on_metadata_parsed)
110+
playback_manager->on_metadata_parsed();
111+
});
112+
113+
return {};
114+
}
84115

85-
auto playback_manager = DECODER_TRY_ALLOC(adopt_nonnull_ref_or_enomem(new (nothrow) PlaybackManager(demuxer, weak_playback_manager, time_provider, move(supported_video_tracks), move(supported_video_track_datas), audio_sink, move(supported_audio_tracks), move(supported_audio_track_datas))));
86-
weak_playback_manager->m_manager = playback_manager;
87-
playback_manager->set_up_error_handlers();
88-
playback_manager->m_handler = DECODER_TRY_ALLOC(try_make<PausedStateHandler>(*playback_manager));
116+
NonnullRefPtr<PlaybackManager> PlaybackManager::create()
117+
{
118+
auto playback_manager = adopt_ref(*new (nothrow) PlaybackManager());
119+
playback_manager->m_handler = make<PausedStateHandler>(*playback_manager);
89120
return playback_manager;
90121
}
91122

92-
PlaybackManager::PlaybackManager(NonnullRefPtr<MutexedDemuxer> const& demuxer, NonnullRefPtr<WeakPlaybackManager> const& weak_wrapper, NonnullRefPtr<MediaTimeProvider> const& time_provider, VideoTracks&& video_tracks, VideoTrackDatas&& video_track_datas, RefPtr<AudioMixingSink> const& audio_sink, AudioTracks&& audio_tracks, AudioTrackDatas&& audio_track_datas)
93-
: m_demuxer(demuxer)
94-
, m_weak_wrapper(weak_wrapper)
95-
, m_time_provider(time_provider)
96-
, m_video_tracks(video_tracks)
97-
, m_video_track_datas(video_track_datas)
98-
, m_audio_sink(audio_sink)
99-
, m_audio_tracks(audio_tracks)
100-
, m_audio_track_datas(audio_track_datas)
123+
PlaybackManager::PlaybackManager()
124+
: m_weak_wrapper(make_ref_counted<WeakPlaybackManager>())
125+
, m_time_provider(make_ref_counted<GenericTimeProvider>())
101126
{
127+
m_weak_wrapper->m_manager = this;
102128
}
103129

104130
PlaybackManager::~PlaybackManager()
105131
{
106132
m_weak_wrapper->revoke();
107133
}
108134

135+
void PlaybackManager::add_media_source(ReadonlyBytes media_data)
136+
{
137+
auto thread = Threading::Thread::construct([playback_manager = NonnullRefPtr { *this }, media_data, &main_thread_event_loop = Core::EventLoop::current()] -> int {
138+
auto maybe_error = playback_manager->prepare_playback_from_media_data(media_data, main_thread_event_loop);
139+
if (maybe_error.is_error()) {
140+
main_thread_event_loop.deferred_invoke([playback_manager, error = maybe_error.release_error()] mutable {
141+
if (playback_manager->on_unsupported_format_error)
142+
playback_manager->on_unsupported_format_error(move(error));
143+
});
144+
return 0;
145+
}
146+
return 0;
147+
});
148+
149+
thread->start();
150+
thread->detach();
151+
}
152+
109153
void PlaybackManager::set_up_error_handlers()
110154
{
111155
for (auto const& video_track_data : m_video_track_datas) {
@@ -136,27 +180,6 @@ void PlaybackManager::dispatch_error(DecoderError&& error)
136180
on_error(move(error));
137181
}
138182

139-
AK::Duration PlaybackManager::duration() const
140-
{
141-
return m_demuxer->total_duration().value_or(AK::Duration::zero());
142-
}
143-
144-
Optional<Track> PlaybackManager::preferred_video_track()
145-
{
146-
auto result = m_demuxer->get_preferred_track_for_type(TrackType::Video).value_or({});
147-
if (result.has_value() && !m_video_tracks.contains_slow(result.value()))
148-
return {};
149-
return result;
150-
}
151-
152-
Optional<Track> PlaybackManager::preferred_audio_track()
153-
{
154-
auto result = m_demuxer->get_preferred_track_for_type(TrackType::Audio).value_or({});
155-
if (result.has_value() && !m_audio_tracks.contains_slow(result.value()))
156-
return {};
157-
return result;
158-
}
159-
160183
PlaybackManager::VideoTrackData& PlaybackManager::get_video_data_for_track(Track const& track)
161184
{
162185
for (auto& track_data : m_video_track_datas) {
@@ -171,7 +194,7 @@ NonnullRefPtr<DisplayingVideoSink> PlaybackManager::get_or_create_the_displaying
171194
{
172195
auto& track_data = get_video_data_for_track(track);
173196
if (track_data.display == nullptr) {
174-
track_data.display = MUST(Media::DisplayingVideoSink::try_create(m_time_provider));
197+
track_data.display = MUST(Media::DisplayingVideoSink::try_create(*m_time_provider));
175198
track_data.display->set_provider(track, track_data.provider);
176199
track_data.provider->start();
177200
track_data.provider->seek(m_time_provider->current_time(), SeekMode::Accurate);

Libraries/LibMedia/PlaybackManager.h

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
#include <AK/Forward.h>
1111
#include <AK/NonnullRefPtr.h>
1212
#include <AK/OwnPtr.h>
13-
#include <AK/Stream.h>
1413
#include <AK/Time.h>
1514
#include <AK/Vector.h>
15+
#include <LibCore/EventLoop.h>
1616
#include <LibMedia/DecoderError.h>
1717
#include <LibMedia/Export.h>
1818
#include <LibMedia/Forward.h>
@@ -44,17 +44,16 @@ class MEDIA_API PlaybackManager final : public AtomicRefCounted<PlaybackManager>
4444

4545
using AudioTracks = Vector<Track, EXPECTED_AUDIO_TRACK_COUNT>;
4646

47-
static DecoderErrorOr<NonnullRefPtr<PlaybackManager>> try_create(ReadonlyBytes data);
47+
static NonnullRefPtr<PlaybackManager> create();
4848
~PlaybackManager();
4949

50-
AK::Duration duration() const;
50+
AK::Duration duration() const { return m_duration; }
5151
AK::Duration current_time() const { return min(m_time_provider->current_time(), duration()); }
5252

53-
VideoTracks const& video_tracks() const { return m_video_tracks; }
54-
Optional<Track> preferred_video_track();
55-
56-
VideoTracks const& audio_tracks() const { return m_audio_tracks; }
57-
Optional<Track> preferred_audio_track();
53+
auto const& video_tracks() const { return m_video_tracks; }
54+
auto const& audio_tracks() const { return m_audio_tracks; }
55+
Optional<Track> preferred_video_track() { return m_preferred_video_track; }
56+
Optional<Track> preferred_audio_track() { return m_preferred_audio_track; }
5857

5958
// Creates a DisplayingVideoSink for the specified track.
6059
//
@@ -77,9 +76,14 @@ class MEDIA_API PlaybackManager final : public AtomicRefCounted<PlaybackManager>
7776

7877
void set_volume(double);
7978

79+
Function<void()> on_metadata_parsed;
80+
Function<void(DecoderError&&)> on_unsupported_format_error;
81+
Function<void(TrackType, Track const&)> on_track_added;
8082
Function<void()> on_playback_state_change;
8183
Function<void(DecoderError&&)> on_error;
8284

85+
void add_media_source(ReadonlyBytes media_data);
86+
8387
private:
8488
class WeakPlaybackManager : public AtomicRefCounted<WeakPlaybackManager> {
8589
friend class PlaybackManager;
@@ -117,20 +121,21 @@ class MEDIA_API PlaybackManager final : public AtomicRefCounted<PlaybackManager>
117121
};
118122
using AudioTrackDatas = Vector<AudioTrackData, EXPECTED_AUDIO_TRACK_COUNT>;
119123

120-
PlaybackManager(NonnullRefPtr<MutexedDemuxer> const&, NonnullRefPtr<WeakPlaybackManager> const&, NonnullRefPtr<MediaTimeProvider> const&, VideoTracks&&, VideoTrackDatas&&, RefPtr<AudioMixingSink> const&, AudioTracks&&, AudioTrackDatas&&);
124+
PlaybackManager();
121125

122126
void set_up_error_handlers();
123127
void dispatch_error(DecoderError&&);
124128

125129
VideoTrackData& get_video_data_for_track(Track const& track);
126130
AudioTrackData& get_audio_data_for_track(Track const& track);
127131

132+
DecoderErrorOr<void> prepare_playback_from_media_data(ReadonlyBytes media_data, Core::EventLoop& main_thread_event_loop);
133+
128134
template<typename T, typename... Args>
129135
void replace_state_handler(Args&&... args);
130136
inline void dispatch_state_change() const;
131137

132138
OwnPtr<PlaybackStateHandler> m_handler;
133-
NonnullRefPtr<MutexedDemuxer> m_demuxer;
134139

135140
NonnullRefPtr<WeakPlaybackManager> m_weak_wrapper;
136141

@@ -143,6 +148,11 @@ class MEDIA_API PlaybackManager final : public AtomicRefCounted<PlaybackManager>
143148
AudioTracks m_audio_tracks;
144149
AudioTrackDatas m_audio_track_datas;
145150

151+
Optional<Track> m_preferred_video_track;
152+
Optional<Track> m_preferred_audio_track;
153+
154+
AK::Duration m_duration;
155+
146156
bool m_is_in_error_state { false };
147157
};
148158

Libraries/LibMedia/Providers/AudioDataProvider.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616

1717
namespace Media {
1818

19-
DecoderErrorOr<NonnullRefPtr<AudioDataProvider>> AudioDataProvider::try_create(NonnullRefPtr<MutexedDemuxer> const& demuxer, Track const& track)
19+
DecoderErrorOr<NonnullRefPtr<AudioDataProvider>> AudioDataProvider::try_create(Core::EventLoop& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const& demuxer, Track const& track)
2020
{
2121
auto codec_id = TRY(demuxer->get_codec_id_for_track(track));
2222
auto codec_initialization_data = TRY(demuxer->get_codec_initialization_data_for_track(track));
2323
auto decoder = DECODER_TRY_ALLOC(FFmpeg::FFmpegAudioDecoder::try_create(codec_id, codec_initialization_data));
2424

25-
auto thread_data = DECODER_TRY_ALLOC(try_make_ref_counted<AudioDataProvider::ThreadData>(demuxer, track, move(decoder)));
25+
auto thread_data = DECODER_TRY_ALLOC(try_make_ref_counted<AudioDataProvider::ThreadData>(main_thread_event_loop, demuxer, track, move(decoder)));
2626
auto provider = DECODER_TRY_ALLOC(try_make_ref_counted<AudioDataProvider>(thread_data));
2727

2828
auto thread = DECODER_TRY_ALLOC(Threading::Thread::try_create([thread_data]() -> int {
@@ -64,8 +64,8 @@ void AudioDataProvider::seek(AK::Duration timestamp, SeekCompletionHandler&& com
6464
m_thread_data->seek(timestamp, move(completion_handler));
6565
}
6666

67-
AudioDataProvider::ThreadData::ThreadData(NonnullRefPtr<MutexedDemuxer> const& demuxer, Track const& track, NonnullOwnPtr<AudioDecoder>&& decoder)
68-
: m_main_thread_event_loop(Core::EventLoop::current())
67+
AudioDataProvider::ThreadData::ThreadData(Core::EventLoop& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const& demuxer, Track const& track, NonnullOwnPtr<AudioDecoder>&& decoder)
68+
: m_main_thread_event_loop(main_thread_event_loop)
6969
, m_demuxer(demuxer)
7070
, m_track(track)
7171
, m_decoder(move(decoder))

Libraries/LibMedia/Providers/AudioDataProvider.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class MEDIA_API AudioDataProvider : public AtomicRefCounted<AudioDataProvider> {
3434
using ErrorHandler = Function<void(DecoderError&&)>;
3535
using SeekCompletionHandler = Function<void()>;
3636

37-
static DecoderErrorOr<NonnullRefPtr<AudioDataProvider>> try_create(NonnullRefPtr<MutexedDemuxer> const& demuxer, Track const& track);
37+
static DecoderErrorOr<NonnullRefPtr<AudioDataProvider>> try_create(Core::EventLoop& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const& demuxer, Track const& track);
3838
AudioDataProvider(NonnullRefPtr<ThreadData> const&);
3939
~AudioDataProvider();
4040

@@ -49,7 +49,7 @@ class MEDIA_API AudioDataProvider : public AtomicRefCounted<AudioDataProvider> {
4949
private:
5050
class ThreadData final : public AtomicRefCounted<ThreadData> {
5151
public:
52-
ThreadData(NonnullRefPtr<MutexedDemuxer> const&, Track const&, NonnullOwnPtr<AudioDecoder>&&);
52+
ThreadData(Core::EventLoop& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const&, Track const&, NonnullOwnPtr<AudioDecoder>&&);
5353
~ThreadData();
5454

5555
void set_error_handler(ErrorHandler&&);

Libraries/LibMedia/Providers/VideoDataProvider.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717

1818
namespace Media {
1919

20-
DecoderErrorOr<NonnullRefPtr<VideoDataProvider>> VideoDataProvider::try_create(NonnullRefPtr<MutexedDemuxer> const& demuxer, Track const& track, RefPtr<MediaTimeProvider> const& time_provider)
20+
DecoderErrorOr<NonnullRefPtr<VideoDataProvider>> VideoDataProvider::try_create(Core::EventLoop& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const& demuxer, Track const& track, RefPtr<MediaTimeProvider> const& time_provider)
2121
{
2222
auto codec_id = TRY(demuxer->get_codec_id_for_track(track));
2323
auto codec_initialization_data = TRY(demuxer->get_codec_initialization_data_for_track(track));
2424
auto decoder = DECODER_TRY_ALLOC(FFmpeg::FFmpegVideoDecoder::try_create(codec_id, codec_initialization_data));
2525

26-
auto thread_data = DECODER_TRY_ALLOC(try_make_ref_counted<VideoDataProvider::ThreadData>(demuxer, track, move(decoder), time_provider));
26+
auto thread_data = DECODER_TRY_ALLOC(try_make_ref_counted<VideoDataProvider::ThreadData>(main_thread_event_loop, demuxer, track, move(decoder), time_provider));
2727
auto provider = DECODER_TRY_ALLOC(try_make_ref_counted<VideoDataProvider>(thread_data));
2828

2929
auto thread = DECODER_TRY_ALLOC(Threading::Thread::try_create([thread_data]() -> int {
@@ -81,8 +81,8 @@ void VideoDataProvider::seek(AK::Duration timestamp, SeekMode seek_mode, SeekCom
8181
m_thread_data->seek(timestamp, seek_mode, move(completion_handler));
8282
}
8383

84-
VideoDataProvider::ThreadData::ThreadData(NonnullRefPtr<MutexedDemuxer> const& demuxer, Track const& track, NonnullOwnPtr<VideoDecoder>&& decoder, RefPtr<MediaTimeProvider> const& time_provider)
85-
: m_main_thread_event_loop(Core::EventLoop::current())
84+
VideoDataProvider::ThreadData::ThreadData(Core::EventLoop& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const& demuxer, Track const& track, NonnullOwnPtr<VideoDecoder>&& decoder, RefPtr<MediaTimeProvider> const& time_provider)
85+
: m_main_thread_event_loop(main_thread_event_loop)
8686
, m_demuxer(demuxer)
8787
, m_track(track)
8888
, m_decoder(move(decoder))

Libraries/LibMedia/Providers/VideoDataProvider.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class MEDIA_API VideoDataProvider final : public AtomicRefCounted<VideoDataProvi
3535
using ErrorHandler = Function<void(DecoderError&&)>;
3636
using SeekCompletionHandler = Function<void(AK::Duration)>;
3737

38-
static DecoderErrorOr<NonnullRefPtr<VideoDataProvider>> try_create(NonnullRefPtr<MutexedDemuxer> const&, Track const&, RefPtr<MediaTimeProvider> const& = nullptr);
38+
static DecoderErrorOr<NonnullRefPtr<VideoDataProvider>> try_create(Core::EventLoop& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const&, Track const&, RefPtr<MediaTimeProvider> const& = nullptr);
3939
static DecoderErrorOr<NonnullRefPtr<VideoDataProvider>> try_create(NonnullRefPtr<Demuxer> const&, Track const&, RefPtr<MediaTimeProvider> const& = nullptr);
4040

4141
VideoDataProvider(NonnullRefPtr<ThreadData> const&);
@@ -52,7 +52,7 @@ class MEDIA_API VideoDataProvider final : public AtomicRefCounted<VideoDataProvi
5252
private:
5353
class ThreadData final : public AtomicRefCounted<ThreadData> {
5454
public:
55-
ThreadData(NonnullRefPtr<MutexedDemuxer> const&, Track const&, NonnullOwnPtr<VideoDecoder>&&, RefPtr<MediaTimeProvider> const&);
55+
ThreadData(Core::EventLoop& main_thread_event_loop, NonnullRefPtr<MutexedDemuxer> const&, Track const&, NonnullOwnPtr<VideoDecoder>&&, RefPtr<MediaTimeProvider> const&);
5656
~ThreadData();
5757

5858
void set_error_handler(ErrorHandler&&);

0 commit comments

Comments
 (0)