mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-07 21:59:54 +00:00
LibMedia: Implement a generic MediaTimeProvider for video-only timing
This time provider can later be swapped out for the AudioMixingSink when it implements the MediaTimeProvider interface, so that frame timing can be driven by audio when it is present.
This commit is contained in:
parent
3d0b8cc30c
commit
3ebaa0cd3f
Notes:
github-actions[bot]
2025-10-28 00:34:38 +00:00
Author: https://github.com/Zaggy1024
Commit: 3ebaa0cd3f
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6410
Reviewed-by: https://github.com/R-Goc
Reviewed-by: https://github.com/gmta ✅
7 changed files with 92 additions and 23 deletions
|
|
@ -12,6 +12,7 @@ set(SOURCES
|
|||
Containers/Matroska/Reader.cpp
|
||||
PlaybackManager.cpp
|
||||
Providers/AudioDataProvider.cpp
|
||||
Providers/GenericTimeProvider.cpp
|
||||
Providers/VideoDataProvider.cpp
|
||||
Sinks/AudioMixingSink.cpp
|
||||
Sinks/DisplayingVideoSink.cpp
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <LibMedia/FFmpeg/FFmpegDemuxer.h>
|
||||
#include <LibMedia/MutexedDemuxer.h>
|
||||
#include <LibMedia/Providers/AudioDataProvider.h>
|
||||
#include <LibMedia/Providers/GenericTimeProvider.h>
|
||||
#include <LibMedia/Providers/VideoDataProvider.h>
|
||||
#include <LibMedia/Sinks/AudioMixingSink.h>
|
||||
#include <LibMedia/Sinks/DisplayingVideoSink.h>
|
||||
|
|
@ -72,22 +73,26 @@ DecoderErrorOr<NonnullRefPtr<PlaybackManager>> PlaybackManager::try_create(Reado
|
|||
if (!supported_audio_tracks.is_empty())
|
||||
audio_sink = DECODER_TRY_ALLOC(AudioMixingSink::try_create());
|
||||
|
||||
auto playback_manager = DECODER_TRY_ALLOC(adopt_nonnull_ref_or_enomem(new (nothrow) PlaybackManager(demuxer, weak_playback_manager, move(supported_video_tracks), move(supported_video_track_datas), audio_sink, move(supported_audio_tracks), move(supported_audio_track_datas))));
|
||||
// Create the time provider.
|
||||
auto time_provider = DECODER_TRY_ALLOC(try_make_ref_counted<GenericTimeProvider>());
|
||||
|
||||
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))));
|
||||
weak_playback_manager->m_manager = playback_manager;
|
||||
playback_manager->set_up_error_handlers();
|
||||
return playback_manager;
|
||||
}
|
||||
|
||||
PlaybackManager::PlaybackManager(NonnullRefPtr<MutexedDemuxer> const& demuxer, NonnullRefPtr<WeakPlaybackManager> const& weak_wrapper, VideoTracks&& video_tracks, VideoTrackDatas&& video_track_datas, RefPtr<AudioMixingSink> const& audio_sink, AudioTracks&& audio_tracks, AudioTrackDatas&& audio_track_datas)
|
||||
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)
|
||||
: m_demuxer(demuxer)
|
||||
, m_weak_wrapper(weak_wrapper)
|
||||
, m_time_provider(time_provider)
|
||||
, m_video_tracks(video_tracks)
|
||||
, m_video_track_datas(video_track_datas)
|
||||
, m_audio_sink(audio_sink)
|
||||
, m_audio_tracks(audio_tracks)
|
||||
, m_audio_track_datas(audio_track_datas)
|
||||
, m_real_time_base(MonotonicTime::now())
|
||||
{
|
||||
m_time_provider->resume();
|
||||
}
|
||||
|
||||
PlaybackManager::~PlaybackManager()
|
||||
|
|
@ -125,11 +130,6 @@ void PlaybackManager::dispatch_error(DecoderError&& error)
|
|||
on_error(move(error));
|
||||
}
|
||||
|
||||
AK::Duration PlaybackManager::current_time() const
|
||||
{
|
||||
return MonotonicTime::now() - m_real_time_base;
|
||||
}
|
||||
|
||||
AK::Duration PlaybackManager::duration() const
|
||||
{
|
||||
return m_demuxer->total_duration().value_or(AK::Duration::zero());
|
||||
|
|
@ -165,9 +165,9 @@ NonnullRefPtr<DisplayingVideoSink> PlaybackManager::get_or_create_the_displaying
|
|||
{
|
||||
auto& track_data = get_video_data_for_track(track);
|
||||
if (track_data.display == nullptr) {
|
||||
track_data.display = MUST(Media::DisplayingVideoSink::try_create(m_weak_wrapper));
|
||||
track_data.display = MUST(Media::DisplayingVideoSink::try_create(m_time_provider));
|
||||
track_data.display->set_provider(track, track_data.provider);
|
||||
track_data.provider->seek(current_time());
|
||||
track_data.provider->seek(m_time_provider->current_time());
|
||||
}
|
||||
|
||||
VERIFY(track_data.display->provider(track) == track_data.provider);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public:
|
|||
static DecoderErrorOr<NonnullRefPtr<PlaybackManager>> try_create(ReadonlyBytes data);
|
||||
~PlaybackManager();
|
||||
|
||||
AK::Duration current_time() const;
|
||||
AK::Duration current_time() const { return m_time_provider->current_time(); }
|
||||
AK::Duration duration() const;
|
||||
|
||||
VideoTracks const& video_tracks() const { return m_video_tracks; }
|
||||
|
|
@ -63,7 +63,7 @@ public:
|
|||
Function<void(DecoderError&&)> on_error;
|
||||
|
||||
private:
|
||||
class WeakPlaybackManager final : public MediaTimeProvider {
|
||||
class WeakPlaybackManager : public AtomicRefCounted<WeakPlaybackManager> {
|
||||
friend class PlaybackManager;
|
||||
|
||||
public:
|
||||
|
|
@ -75,14 +75,6 @@ private:
|
|||
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()
|
||||
{
|
||||
|
|
@ -107,7 +99,7 @@ private:
|
|||
};
|
||||
using AudioTrackDatas = Vector<AudioTrackData, EXPECTED_AUDIO_TRACK_COUNT>;
|
||||
|
||||
PlaybackManager(NonnullRefPtr<MutexedDemuxer> const&, NonnullRefPtr<WeakPlaybackManager> const&, VideoTracks&&, VideoTrackDatas&&, RefPtr<AudioMixingSink> const&, AudioTracks&&, AudioTrackDatas&&);
|
||||
PlaybackManager(NonnullRefPtr<MutexedDemuxer> const&, NonnullRefPtr<WeakPlaybackManager> const&, NonnullRefPtr<MediaTimeProvider> const&, VideoTracks&&, VideoTrackDatas&&, RefPtr<AudioMixingSink> const&, AudioTracks&&, AudioTrackDatas&&);
|
||||
|
||||
void set_up_error_handlers();
|
||||
void dispatch_error(DecoderError&&);
|
||||
|
|
@ -119,6 +111,8 @@ private:
|
|||
|
||||
NonnullRefPtr<WeakPlaybackManager> m_weak_wrapper;
|
||||
|
||||
NonnullRefPtr<MediaTimeProvider> m_time_provider;
|
||||
|
||||
VideoTracks m_video_tracks;
|
||||
VideoTrackDatas m_video_track_datas;
|
||||
|
||||
|
|
@ -126,8 +120,6 @@ private:
|
|||
AudioTracks m_audio_tracks;
|
||||
AudioTrackDatas m_audio_track_datas;
|
||||
|
||||
MonotonicTime m_real_time_base;
|
||||
|
||||
bool m_is_in_error_state { false };
|
||||
};
|
||||
|
||||
|
|
|
|||
44
Libraries/LibMedia/Providers/GenericTimeProvider.cpp
Normal file
44
Libraries/LibMedia/Providers/GenericTimeProvider.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Gregory Bertilson <gregory@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "GenericTimeProvider.h"
|
||||
|
||||
namespace Media {
|
||||
|
||||
GenericTimeProvider::GenericTimeProvider() = default;
|
||||
|
||||
GenericTimeProvider::~GenericTimeProvider() = default;
|
||||
|
||||
AK::Duration GenericTimeProvider::current_time() const
|
||||
{
|
||||
auto time = m_media_time;
|
||||
if (m_monotonic_time_on_resume.has_value())
|
||||
time += MonotonicTime::now() - m_monotonic_time_on_resume.value();
|
||||
return time;
|
||||
}
|
||||
|
||||
void GenericTimeProvider::resume()
|
||||
{
|
||||
m_monotonic_time_on_resume.emplace(MonotonicTime::now());
|
||||
}
|
||||
|
||||
void GenericTimeProvider::pause()
|
||||
{
|
||||
if (!m_monotonic_time_on_resume.has_value())
|
||||
return;
|
||||
m_media_time = current_time();
|
||||
m_monotonic_time_on_resume = {};
|
||||
}
|
||||
|
||||
void GenericTimeProvider::set_time(AK::Duration time)
|
||||
{
|
||||
if (m_monotonic_time_on_resume.has_value())
|
||||
m_monotonic_time_on_resume.emplace(MonotonicTime::now());
|
||||
|
||||
m_media_time = time;
|
||||
}
|
||||
|
||||
}
|
||||
28
Libraries/LibMedia/Providers/GenericTimeProvider.h
Normal file
28
Libraries/LibMedia/Providers/GenericTimeProvider.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Gregory Bertilson <gregory@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibMedia/Providers/MediaTimeProvider.h>
|
||||
|
||||
namespace Media {
|
||||
|
||||
class GenericTimeProvider final : public MediaTimeProvider {
|
||||
public:
|
||||
GenericTimeProvider();
|
||||
virtual ~GenericTimeProvider() override;
|
||||
|
||||
virtual AK::Duration current_time() const override;
|
||||
virtual void resume() override;
|
||||
virtual void pause() override;
|
||||
virtual void set_time(AK::Duration) override;
|
||||
|
||||
private:
|
||||
Optional<MonotonicTime> m_monotonic_time_on_resume;
|
||||
AK::Duration m_media_time;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -16,6 +16,9 @@ public:
|
|||
virtual ~MediaTimeProvider() = default;
|
||||
|
||||
virtual AK::Duration current_time() const = 0;
|
||||
virtual void resume() = 0;
|
||||
virtual void pause() = 0;
|
||||
virtual void set_time(AK::Duration) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ shared_library("LibMedia") {
|
|||
"Containers/Matroska/Reader.cpp",
|
||||
"PlaybackManager.cpp",
|
||||
"Providers/AudioDataProvider.cpp",
|
||||
"Providers/GenericTimeProvider.cpp",
|
||||
"Providers/VideoDataProvider.cpp",
|
||||
"Sinks/AudioMixingSink.cpp",
|
||||
"Sinks/DisplayingVideoSink.cpp",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue