ladybird/Libraries/LibMedia/PlaybackManager.h
Zaggy1024 6caa2f99aa LibMedia+LibWeb: Rewrite PlaybackManager using the provider/sink model
With this commit, all PlaybackManager can do is autoplay a file from
start to finish, with no pausing or seeking functionality.

All audio playback functionality has been removed from HTMLMediaElement
and HTMLAudioElement in anticipation of PlaybackManager taking that
over, for both audio-only and audio/video.
2025-10-27 17:28:49 -07:00

113 lines
3.3 KiB
C++

/*
* Copyright (c) 2022-2025, Gregory Bertilson <gregory@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/AtomicRefCounted.h>
#include <AK/Forward.h>
#include <AK/NonnullRefPtr.h>
#include <AK/Stream.h>
#include <AK/Time.h>
#include <AK/Vector.h>
#include <LibMedia/DecoderError.h>
#include <LibMedia/Export.h>
#include <LibMedia/Forward.h>
#include <LibMedia/Providers/MediaTimeProvider.h>
#include <LibMedia/Track.h>
#include <LibThreading/Mutex.h>
namespace Media {
class MEDIA_API PlaybackManager final : public AtomicRefCounted<PlaybackManager> {
AK_MAKE_NONCOPYABLE(PlaybackManager);
AK_MAKE_NONMOVABLE(PlaybackManager);
class WeakPlaybackManager;
public:
static constexpr size_t EXPECTED_VIDEO_TRACK_COUNT = 1;
using VideoTracks = Vector<Track, EXPECTED_VIDEO_TRACK_COUNT>;
static DecoderErrorOr<NonnullRefPtr<PlaybackManager>> try_create(NonnullOwnPtr<SeekableStream>&& stream);
~PlaybackManager();
AK::Duration current_time() const;
AK::Duration duration() const;
VideoTracks const& video_tracks() const { return m_video_tracks; }
Optional<Track> preferred_video_track();
// Creates a DisplayingVideoSink for the specified track.
//
// Note that in order for the current frame to change based on the media time, users must call
// DisplayingVideoSink::update(). It is recommended to drive this off of vertical sync.
NonnullRefPtr<DisplayingVideoSink> get_or_create_the_displaying_video_sink_for_track(Track const& track);
// Removes the DisplayingVideoSink for the specified track. This will prevent the sink from
// retrieving any subsequent frames from the decoder.
void remove_the_displaying_video_sink_for_track(Track const& track);
Function<void(DecoderError&&)> on_error;
private:
class WeakPlaybackManager final : public MediaTimeProvider {
friend class PlaybackManager;
public:
WeakPlaybackManager() = default;
RefPtr<PlaybackManager> take_strong() const
{
Threading::MutexLocker locker { m_mutex };
return m_manager;
}
virtual AK::Duration current_time() const override
{
Threading::MutexLocker locker { m_mutex };
if (m_manager)
return m_manager->current_time();
return AK::Duration::zero();
}
private:
void revoke()
{
Threading::MutexLocker locker { m_mutex };
m_manager = nullptr;
}
mutable Threading::Mutex m_mutex;
PlaybackManager* m_manager { nullptr };
};
struct VideoTrackData {
Track track;
NonnullRefPtr<VideoDataProvider> provider;
RefPtr<DisplayingVideoSink> display;
};
using VideoTrackDatas = Vector<VideoTrackData, EXPECTED_VIDEO_TRACK_COUNT>;
PlaybackManager(NonnullRefPtr<MutexedDemuxer> const&, NonnullRefPtr<WeakPlaybackManager> const&, VideoTracks&&, VideoTrackDatas&&);
void set_up_error_handlers();
void dispatch_error(DecoderError&&);
VideoTrackData& get_video_data_for_track(Track const& track);
NonnullRefPtr<MutexedDemuxer> m_demuxer;
NonnullRefPtr<WeakPlaybackManager> m_weak_wrapper;
VideoTracks m_video_tracks;
VideoTrackDatas m_video_track_datas;
MonotonicTime m_real_time_base;
bool m_is_in_error_state { false };
};
}