LibMedia: Rename some folders/identifiers for the upcoming refactor

- Provider -> producer
- (Audio|Video)DataProvider -> Decoded(Audio|Video)Producer
- MediaTimeProvider remains suffixed Provider, moves out of the
  Providers folder to the root of LibMedia

This brings the naming more in line with the intended split
functionality split between different nodes in the pipeline.
This commit is contained in:
Zaggy1024 2026-04-25 20:51:09 -05:00 committed by Gregory Bertilson
parent 03989a5819
commit eeff03c980
27 changed files with 244 additions and 244 deletions

View file

@ -4,6 +4,7 @@ set(SOURCES
Audio/AudioDevices.cpp
Containers/Matroska/MatroskaDemuxer.cpp
Containers/Matroska/Reader.cpp
GenericTimeProvider.cpp
IncrementallyPopulatedStream.cpp
PlaybackManager.cpp
PlaybackStates/StartingStateHandler.cpp
@ -11,9 +12,8 @@ set(SOURCES
PlaybackStates/PlaybackStateHandler.cpp
PlaybackStates/ResumingStateHandler.cpp
Processors/AudioMixer.cpp
Providers/AudioDataProvider.cpp
Providers/GenericTimeProvider.cpp
Providers/VideoDataProvider.cpp
Producers/DecodedAudioProducer.cpp
Producers/DecodedVideoProducer.cpp
Sinks/AudioPlaybackSink.cpp
Sinks/DisplayingVideoSink.cpp
TimeRanges.cpp

View file

@ -10,7 +10,7 @@
namespace Media {
class CodedFrame;
class AudioDataProvider;
class DecodedAudioProducer;
class AudioDecoder;
class AudioMixer;
class AudioPlaybackSink;
@ -26,7 +26,7 @@ class MediaTimeProvider;
class PlaybackManager;
class ReadonlyBytesCursor;
class Track;
class VideoDataProvider;
class DecodedVideoProducer;
class VideoDecoder;
class VideoFrame;
class VideoSink;

View file

@ -6,7 +6,7 @@
#pragma once
#include <LibMedia/Providers/MediaTimeProvider.h>
#include "MediaTimeProvider.h"
namespace Media {

View file

@ -7,11 +7,11 @@
#include <LibMedia/Containers/Matroska/MatroskaDemuxer.h>
#include <LibMedia/Demuxer.h>
#include <LibMedia/FFmpeg/FFmpegDemuxer.h>
#include <LibMedia/GenericTimeProvider.h>
#include <LibMedia/PlaybackStates/StartingStateHandler.h>
#include <LibMedia/Processors/AudioMixer.h>
#include <LibMedia/Providers/AudioDataProvider.h>
#include <LibMedia/Providers/GenericTimeProvider.h>
#include <LibMedia/Providers/VideoDataProvider.h>
#include <LibMedia/Producers/DecodedAudioProducer.h>
#include <LibMedia/Producers/DecodedVideoProducer.h>
#include <LibMedia/Sinks/AudioPlaybackSink.h>
#include <LibMedia/Sinks/DisplayingVideoSink.h>
#include <LibMedia/Track.h>
@ -31,7 +31,7 @@ DecoderErrorOr<NonnullRefPtr<Demuxer>> PlaybackManager::create_demuxer_for_strea
DecoderErrorOr<void> PlaybackManager::prepare_playback_from_demuxer(WeakPlaybackManager const& self, NonnullRefPtr<Demuxer> const& demuxer, NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop_reference)
{
// Create the video tracks and their data providers.
// Create the video tracks and their producers.
auto all_video_tracks = TRY(demuxer->get_tracks_for_type(TrackType::Video));
auto supported_video_tracks = VideoTracks();
@ -39,16 +39,16 @@ DecoderErrorOr<void> PlaybackManager::prepare_playback_from_demuxer(WeakPlayback
supported_video_tracks.ensure_capacity(all_video_tracks.size());
supported_video_track_datas.ensure_capacity(all_video_tracks.size());
for (auto const& track : all_video_tracks) {
auto video_data_provider_result = VideoDataProvider::try_create(main_thread_event_loop_reference, demuxer, track);
if (video_data_provider_result.is_error())
auto video_producer_result = DecodedVideoProducer::try_create(main_thread_event_loop_reference, demuxer, track);
if (video_producer_result.is_error())
continue;
supported_video_tracks.append(track);
supported_video_track_datas.empend(VideoTrackData(track, video_data_provider_result.release_value(), nullptr));
supported_video_track_datas.empend(VideoTrackData(track, video_producer_result.release_value(), nullptr));
}
supported_video_tracks.shrink_to_fit();
supported_video_track_datas.shrink_to_fit();
// Create all the audio tracks, their data providers, and the audio output.
// Create all the audio tracks, their producers, and the audio output.
auto all_audio_tracks = TRY(demuxer->get_tracks_for_type(TrackType::Audio));
auto supported_audio_tracks = AudioTracks();
@ -56,12 +56,12 @@ DecoderErrorOr<void> PlaybackManager::prepare_playback_from_demuxer(WeakPlayback
supported_audio_tracks.ensure_capacity(all_audio_tracks.size());
supported_audio_track_datas.ensure_capacity(all_audio_tracks.size());
for (auto const& track : all_audio_tracks) {
auto audio_data_provider_result = AudioDataProvider::try_create(main_thread_event_loop_reference, demuxer, track);
if (audio_data_provider_result.is_error())
auto audio_producer_result = DecodedAudioProducer::try_create(main_thread_event_loop_reference, demuxer, track);
if (audio_producer_result.is_error())
continue;
auto audio_data_provider = audio_data_provider_result.release_value();
auto audio_producer = audio_producer_result.release_value();
supported_audio_tracks.append(track);
supported_audio_track_datas.empend(AudioTrackData(track, move(audio_data_provider)));
supported_audio_track_datas.empend(AudioTrackData(track, move(audio_producer)));
}
supported_audio_tracks.shrink_to_fit();
supported_audio_track_datas.shrink_to_fit();
@ -113,7 +113,7 @@ DecoderErrorOr<void> PlaybackManager::prepare_playback_from_demuxer(WeakPlayback
self->m_start_time_realtime = start_time_realtime;
self->check_for_duration_change(duration);
self->set_up_data_providers();
self->set_up_producers();
if (!self->m_audio_output_disabled && !self->m_audio_sink && !self->m_audio_tracks.is_empty()) {
self->m_audio_mixer = MUST(AudioMixer::try_create());
@ -213,11 +213,11 @@ WeakPlaybackManager PlaybackManager::weak()
return WeakPlaybackManager(m_weak_link);
}
void PlaybackManager::set_up_data_providers()
void PlaybackManager::set_up_producers()
{
for (auto const& video_track_data : m_video_track_datas) {
auto track = video_track_data.track;
video_track_data.provider->set_error_handler([self = weak(), track](DecoderError&& error) {
video_track_data.producer->set_error_handler([self = weak(), track](DecoderError&& error) {
if (!self)
return;
if (error.category() == DecoderErrorCategory::EndOfStream) {
@ -226,12 +226,12 @@ void PlaybackManager::set_up_data_providers()
}
self->dispatch_error(move(error));
});
video_track_data.provider->set_duration_change_handler([self = weak()](AK::Duration time) {
video_track_data.producer->set_duration_change_handler([self = weak()](AK::Duration time) {
if (!self)
return;
self->check_for_duration_change(time);
});
video_track_data.provider->set_frames_queue_is_full_handler([self = weak(), track] {
video_track_data.producer->set_frames_queue_is_full_handler([self = weak(), track] {
if (!self)
return;
self->track_stopped_buffering(track);
@ -240,7 +240,7 @@ void PlaybackManager::set_up_data_providers()
for (auto const& audio_track_data : m_audio_track_datas) {
auto track = audio_track_data.track;
audio_track_data.provider->set_error_handler([self = weak(), track](DecoderError&& error) {
audio_track_data.producer->set_error_handler([self = weak(), track](DecoderError&& error) {
if (!self)
return;
if (error.category() == DecoderErrorCategory::EndOfStream) {
@ -249,12 +249,12 @@ void PlaybackManager::set_up_data_providers()
}
self->dispatch_error(move(error));
});
audio_track_data.provider->set_duration_change_handler([self = weak()](AK::Duration time) {
audio_track_data.producer->set_duration_change_handler([self = weak()](AK::Duration time) {
if (!self)
return;
self->check_for_duration_change(time);
});
audio_track_data.provider->set_queue_is_full_handler([self = weak(), track] {
audio_track_data.producer->set_queue_is_full_handler([self = weak(), track] {
if (!self)
return;
self->track_stopped_buffering(track);
@ -324,7 +324,7 @@ 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_time_provider));
track_data.display->set_provider(track, track_data.provider);
track_data.display->set_producer(track, track_data.producer);
track_data.display->m_on_start_buffering = [this, track] {
track_started_buffering(track);
};
@ -332,7 +332,7 @@ NonnullRefPtr<DisplayingVideoSink> PlaybackManager::get_or_create_the_displaying
m_handler->on_track_enabled(track);
}
VERIFY(track_data.display->provider(track) == track_data.provider);
VERIFY(track_data.display->producer(track) == track_data.producer);
return *track_data.display;
}
@ -340,7 +340,7 @@ void PlaybackManager::remove_the_displaying_video_sink_for_track(Track const& tr
{
auto& track_data = get_video_data_for_track(track);
VERIFY(track_data.display);
track_data.display->set_provider(track, nullptr);
track_data.display->set_producer(track, nullptr);
track_data.display = nullptr;
track_stopped_buffering(track);
m_handler->on_track_disabled(track);
@ -352,8 +352,8 @@ void PlaybackManager::enable_an_audio_track(Track const& track)
VERIFY(!track_data.enabled);
track_data.enabled = true;
if (m_audio_mixer) {
VERIFY(m_audio_mixer->provider(track) == nullptr);
m_audio_mixer->set_provider(track, track_data.provider);
VERIFY(m_audio_mixer->producer(track) == nullptr);
m_audio_mixer->set_producer(track, track_data.producer);
m_tracks_still_buffering.set(track);
}
m_handler->on_track_enabled(track);
@ -364,8 +364,8 @@ void PlaybackManager::disable_an_audio_track(Track const& track)
auto& track_data = get_audio_data_for_track(track);
VERIFY(track_data.enabled);
if (m_audio_mixer) {
VERIFY(m_audio_mixer->provider(track) == track_data.provider);
m_audio_mixer->set_provider(track, nullptr);
VERIFY(m_audio_mixer->producer(track) == track_data.producer);
m_audio_mixer->set_producer(track, nullptr);
}
track_data.enabled = false;
track_stopped_buffering(track);
@ -384,7 +384,7 @@ bool PlaybackManager::track_is_enabled(Track const& track) const
if (!track_data.enabled)
return false;
if (m_audio_mixer)
VERIFY(track_data.provider == m_audio_mixer->provider(track));
VERIFY(track_data.producer == m_audio_mixer->producer(track));
return true;
}
@ -435,7 +435,7 @@ TimeRanges PlaybackManager::buffered_time_ranges() const
if (!track_is_enabled(track_data.track))
continue;
auto range = track_data.provider->buffered_time_ranges();
auto range = track_data.producer->buffered_time_ranges();
if (intersection.is_empty()) {
intersection = range;
continue;

View file

@ -17,9 +17,9 @@
#include <LibMedia/DecoderError.h>
#include <LibMedia/Export.h>
#include <LibMedia/Forward.h>
#include <LibMedia/MediaTimeProvider.h>
#include <LibMedia/PlaybackStates/Forward.h>
#include <LibMedia/PlaybackStates/PlaybackState.h>
#include <LibMedia/Providers/MediaTimeProvider.h>
#include <LibMedia/TimeRanges.h>
#include <LibMedia/Track.h>
#include <LibSync/Mutex.h>
@ -107,14 +107,14 @@ public:
private:
struct VideoTrackData {
Track track;
NonnullRefPtr<VideoDataProvider> provider;
NonnullRefPtr<DecodedVideoProducer> producer;
RefPtr<DisplayingVideoSink> display;
};
using VideoTrackDatas = Vector<VideoTrackData, EXPECTED_VIDEO_TRACK_COUNT>;
struct AudioTrackData {
Track track;
NonnullRefPtr<AudioDataProvider> provider;
NonnullRefPtr<DecodedAudioProducer> producer;
bool enabled { false };
};
using AudioTrackDatas = Vector<AudioTrackData, EXPECTED_AUDIO_TRACK_COUNT>;
@ -124,7 +124,7 @@ private:
void set_time_provider(NonnullRefPtr<MediaTimeProvider> const&);
void disable_audio();
void set_up_data_providers();
void set_up_producers();
void track_started_buffering(Track const&);
void track_stopped_buffering(Track const&);
void check_for_duration_change(AK::Duration);

View file

@ -23,7 +23,7 @@ void PlaybackStateHandler::on_track_enabled(Track const& track)
auto& track_data = manager().get_video_data_for_track(track);
VERIFY(track_data.display != nullptr);
track_data.display->pause_updates();
track_data.provider->seek(manager().current_time(), SeekMode::Accurate, [display = NonnullRefPtr(*track_data.display)](AK::Duration) {
track_data.producer->seek(manager().current_time(), SeekMode::Accurate, [display = NonnullRefPtr(*track_data.display)](AK::Duration) {
display->resume_updates();
});
return;
@ -33,7 +33,7 @@ void PlaybackStateHandler::on_track_enabled(Track const& track)
auto& track_data = manager().get_audio_data_for_track(track);
if (!manager().m_audio_mixer)
return;
track_data.provider->seek(manager().current_time(), nullptr);
track_data.producer->seek(manager().current_time(), nullptr);
}
}

View file

@ -11,8 +11,8 @@
#include <LibMedia/PlaybackManager.h>
#include <LibMedia/PlaybackStates/Forward.h>
#include <LibMedia/PlaybackStates/ResumingStateHandler.h>
#include <LibMedia/Providers/AudioDataProvider.h>
#include <LibMedia/Providers/VideoDataProvider.h>
#include <LibMedia/Producers/DecodedAudioProducer.h>
#include <LibMedia/Producers/DecodedVideoProducer.h>
#include <LibMedia/SeekMode.h>
#include <LibMedia/Sinks/AudioPlaybackSink.h>
#include <LibMedia/Sinks/DisplayingVideoSink.h>
@ -76,14 +76,14 @@ public:
{
if (track.type() == TrackType::Video) {
auto& track_data = manager().get_video_data_for_track(track);
track_data.provider->seek(m_target_timestamp, SeekMode::Accurate, nullptr);
track_data.producer->seek(m_target_timestamp, SeekMode::Accurate, nullptr);
end_video_seek(track);
return;
}
VERIFY(track.type() == TrackType::Audio);
auto& track_data = manager().get_audio_data_for_track(track);
track_data.provider->seek(m_target_timestamp, nullptr);
track_data.producer->seek(m_target_timestamp, nullptr);
end_audio_seek(track);
}
@ -120,10 +120,10 @@ private:
m_video_seeks_pending.set(track);
track_data.display->pause_updates();
track_data.provider->seek(m_target_timestamp, m_mode, [this, weak_manager = manager().weak(), track](AK::Duration provider_timestamp) {
track_data.producer->seek(m_target_timestamp, m_mode, [this, weak_manager = manager().weak(), track](AK::Duration producer_timestamp) {
if (!weak_manager)
return;
m_chosen_timestamp = max(m_chosen_timestamp, provider_timestamp);
m_chosen_timestamp = max(m_chosen_timestamp, producer_timestamp);
end_video_seek(track);
});
}
@ -145,7 +145,7 @@ private:
m_audio_seeks_pending.set(track);
track_data.provider->seek(m_chosen_timestamp, [this, weak_manager = manager().weak(), track]() {
track_data.producer->seek(m_chosen_timestamp, [this, weak_manager = manager().weak(), track]() {
if (!weak_manager)
return;
end_audio_seek(track);

View file

@ -10,8 +10,8 @@
#include <LibMedia/PlaybackStates/Forward.h>
#include <LibMedia/PlaybackStates/SeekingStateHandler.h>
#include <LibMedia/Processors/AudioMixer.h>
#include <LibMedia/Providers/AudioDataProvider.h>
#include <LibMedia/Providers/VideoDataProvider.h>
#include <LibMedia/Producers/DecodedAudioProducer.h>
#include <LibMedia/Producers/DecodedVideoProducer.h>
namespace Media {
@ -26,17 +26,17 @@ public:
virtual void on_enter() override
{
for (auto& video_track_data : manager().m_video_track_datas)
video_track_data.provider->suspend();
video_track_data.producer->suspend();
for (auto& audio_track_data : manager().m_audio_track_datas)
audio_track_data.provider->suspend();
audio_track_data.producer->suspend();
}
virtual void on_exit() override
{
for (auto& video_track_data : manager().m_video_track_datas)
video_track_data.provider->resume();
video_track_data.producer->resume();
for (auto& audio_track_data : manager().m_audio_track_datas)
audio_track_data.provider->resume();
audio_track_data.producer->resume();
}
virtual void play() override
@ -73,13 +73,13 @@ public:
auto& track_data = manager().get_video_data_for_track(track);
VERIFY(track_data.display != nullptr);
track_data.display->pause_updates();
track_data.provider->resume();
track_data.provider->seek(manager().current_time(), SeekMode::Accurate, [manager = manager().weak(), provider = track_data.provider, display = track_data.display](AK::Duration) {
track_data.producer->resume();
track_data.producer->seek(manager().current_time(), SeekMode::Accurate, [manager = manager().weak(), producer = track_data.producer, display = track_data.display](AK::Duration) {
if (!manager)
return;
display->resume_updates();
if (manager->state() != PlaybackState::Buffering)
provider->suspend();
producer->suspend();
});
return;
}
@ -88,12 +88,12 @@ public:
auto& track_data = manager().get_audio_data_for_track(track);
if (!manager().m_audio_mixer)
return;
track_data.provider->resume();
track_data.provider->seek(manager().current_time(), [manager = manager().weak(), provider = track_data.provider] {
track_data.producer->resume();
track_data.producer->seek(manager().current_time(), [manager = manager().weak(), producer = track_data.producer] {
if (!manager)
return;
if (manager->state() == PlaybackState::Suspended)
provider->suspend();
producer->suspend();
});
}
};

View file

@ -5,7 +5,7 @@
*/
#include <LibMedia/Processors/AudioMixer.h>
#include <LibMedia/Providers/AudioDataProvider.h>
#include <LibMedia/Producers/DecodedAudioProducer.h>
namespace Media {
@ -21,29 +21,29 @@ AudioMixer::AudioMixer()
{
}
void AudioMixer::set_provider(Track const& track, RefPtr<AudioDataProvider> const& provider)
void AudioMixer::set_producer(Track const& track, RefPtr<DecodedAudioProducer> const& producer)
{
Sync::MutexLocker locker { m_mutex };
m_track_mixing_datas.remove(track);
if (provider == nullptr)
if (producer == nullptr)
return;
// The provider must have its output sample specification set before it starts decoding, or
// The producer must have its output sample specification set before it starts decoding, or
// we'll drop some samples due to a mismatch.
m_track_mixing_datas.set(track, TrackMixingData(*provider));
m_track_mixing_datas.set(track, TrackMixingData(*producer));
if (m_sample_specification.is_valid()) {
provider->set_output_sample_specification(m_sample_specification);
provider->start();
producer->set_output_sample_specification(m_sample_specification);
producer->start();
}
}
RefPtr<AudioDataProvider> AudioMixer::provider(Track const& track) const
RefPtr<DecodedAudioProducer> AudioMixer::producer(Track const& track) const
{
auto mixing_data = m_track_mixing_datas.get(track);
if (!mixing_data.has_value())
return nullptr;
return mixing_data->provider;
return mixing_data->producer;
}
void AudioMixer::set_sample_specification(Audio::SampleSpecification sample_specification)
@ -52,8 +52,8 @@ void AudioMixer::set_sample_specification(Audio::SampleSpecification sample_spec
m_sample_specification = sample_specification;
for (auto& [track, track_data] : m_track_mixing_datas) {
track_data.provider->set_output_sample_specification(m_sample_specification);
track_data.provider->start();
track_data.producer->set_output_sample_specification(m_sample_specification);
track_data.producer->start();
}
}
@ -84,13 +84,13 @@ bool AudioMixer::mix_one_block_into(AudioBlock& out_block)
auto buffering = false;
auto any_track_has_fresh_data = false;
for (auto& [track, track_data] : m_track_mixing_datas) {
auto available_end = track_data.provider->queue_end_sample();
auto available_end = track_data.producer->queue_end_sample();
// A newly-enabled track has no data at the current mix position yet; skip it for clamping so
// the mixer doesn't stall waiting for it to catch up.
if (available_end <= buffer_start) {
track_data.current_block.clear();
while (true) {
auto block = track_data.provider->retrieve_block();
auto block = track_data.producer->retrieve_block();
if (block.is_empty())
break;
if (block.end_timestamp_in_samples() >= buffer_start) {
@ -105,7 +105,7 @@ bool AudioMixer::mix_one_block_into(AudioBlock& out_block)
any_track_has_fresh_data = true;
if (available_end < samples_end) {
samples_end = available_end;
if (track_data.provider->is_blocked())
if (track_data.producer->is_blocked())
buffering = true;
}
}
@ -117,7 +117,7 @@ bool AudioMixer::mix_one_block_into(AudioBlock& out_block)
if (!buffering) {
track_data.buffering = false;
} else {
if (!track_data.provider->is_blocked())
if (!track_data.producer->is_blocked())
continue;
if (track_data.buffering)
continue;
@ -146,7 +146,7 @@ bool AudioMixer::mix_one_block_into(AudioBlock& out_block)
auto next_sample = buffer_start;
auto go_to_next_block = [&] {
auto new_block = track_data.provider->retrieve_block();
auto new_block = track_data.producer->retrieve_block();
if (new_block.is_empty())
return false;

View file

@ -17,7 +17,7 @@
#include <LibMedia/AudioBlock.h>
#include <LibMedia/Export.h>
#include <LibMedia/Forward.h>
#include <LibMedia/Providers/AudioDataProvider.h>
#include <LibMedia/Producers/DecodedAudioProducer.h>
#include <LibMedia/Sinks/AudioSink.h>
#include <LibMedia/Track.h>
#include <LibSync/Mutex.h>
@ -30,8 +30,8 @@ public:
AudioMixer();
virtual ~AudioMixer() override = default;
virtual void set_provider(Track const&, RefPtr<AudioDataProvider> const&) override;
virtual RefPtr<AudioDataProvider> provider(Track const&) const override;
virtual void set_producer(Track const&, RefPtr<DecodedAudioProducer> const&) override;
virtual RefPtr<DecodedAudioProducer> producer(Track const&) const override;
void set_sample_specification(Audio::SampleSpecification);
Audio::SampleSpecification sample_specification() const;
@ -44,12 +44,12 @@ public:
private:
struct TrackMixingData {
TrackMixingData(NonnullRefPtr<AudioDataProvider> const& provider)
: provider(provider)
TrackMixingData(NonnullRefPtr<DecodedAudioProducer> const& producer)
: producer(producer)
{
}
NonnullRefPtr<AudioDataProvider> provider;
NonnullRefPtr<DecodedAudioProducer> producer;
AudioBlock current_block;
bool buffering { false };
};

View file

@ -14,19 +14,19 @@
#include <LibSync/Mutex.h>
#include <LibThreading/Thread.h>
#include "AudioDataProvider.h"
#include "DecodedAudioProducer.h"
namespace Media {
DecoderErrorOr<NonnullRefPtr<AudioDataProvider>> AudioDataProvider::try_create(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const& demuxer, Track const& track)
DecoderErrorOr<NonnullRefPtr<DecodedAudioProducer>> DecodedAudioProducer::try_create(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const& demuxer, Track const& track)
{
auto converter = DECODER_TRY_ALLOC(FFmpeg::FFmpegAudioConverter::try_create());
TRY(demuxer->create_context_for_track(track));
auto duration = TRY(demuxer->duration_of_track(track));
auto thread_data = DECODER_TRY_ALLOC(try_make_ref_counted<AudioDataProvider::ThreadData>(main_thread_event_loop, demuxer, track, duration, move(converter)));
auto thread_data = DECODER_TRY_ALLOC(try_make_ref_counted<DecodedAudioProducer::ThreadData>(main_thread_event_loop, demuxer, track, duration, move(converter)));
TRY(thread_data->create_decoder());
auto provider = DECODER_TRY_ALLOC(try_make_ref_counted<AudioDataProvider>(thread_data));
auto producer = DECODER_TRY_ALLOC(try_make_ref_counted<DecodedAudioProducer>(thread_data));
auto thread = DECODER_TRY_ALLOC(Threading::Thread::try_create("Audio Decoder"sv, [thread_data]() -> int {
thread_data->wait_for_start();
@ -41,86 +41,86 @@ DecoderErrorOr<NonnullRefPtr<AudioDataProvider>> AudioDataProvider::try_create(N
thread->start();
thread->detach();
return provider;
return producer;
}
AudioDataProvider::AudioDataProvider(NonnullRefPtr<ThreadData> const& thread_data)
DecodedAudioProducer::DecodedAudioProducer(NonnullRefPtr<ThreadData> const& thread_data)
: m_thread_data(thread_data)
{
}
AudioDataProvider::~AudioDataProvider()
DecodedAudioProducer::~DecodedAudioProducer()
{
m_thread_data->exit();
}
void AudioDataProvider::set_error_handler(ErrorHandler&& handler)
void DecodedAudioProducer::set_error_handler(ErrorHandler&& handler)
{
m_thread_data->set_error_handler(move(handler));
}
void AudioDataProvider::set_duration_change_handler(BlockEndTimeHandler&& handler)
void DecodedAudioProducer::set_duration_change_handler(BlockEndTimeHandler&& handler)
{
m_thread_data->set_duration_change_handler(move(handler));
}
void AudioDataProvider::set_queue_is_full_handler(QueueIsFullHandler&& handler)
void DecodedAudioProducer::set_queue_is_full_handler(QueueIsFullHandler&& handler)
{
m_thread_data->set_queue_is_full_handler(move(handler));
}
void AudioDataProvider::set_output_sample_specification(Audio::SampleSpecification sample_specification)
void DecodedAudioProducer::set_output_sample_specification(Audio::SampleSpecification sample_specification)
{
m_thread_data->set_output_sample_specification(sample_specification);
}
void AudioDataProvider::start()
void DecodedAudioProducer::start()
{
m_thread_data->start();
}
void AudioDataProvider::suspend()
void DecodedAudioProducer::suspend()
{
m_thread_data->suspend();
}
void AudioDataProvider::resume()
void DecodedAudioProducer::resume()
{
m_thread_data->resume();
}
void AudioDataProvider::seek(AK::Duration timestamp, SeekCompletionHandler&& completion_handler)
void DecodedAudioProducer::seek(AK::Duration timestamp, SeekCompletionHandler&& completion_handler)
{
m_thread_data->seek(timestamp, move(completion_handler));
}
bool AudioDataProvider::is_blocked() const
bool DecodedAudioProducer::is_blocked() const
{
return m_thread_data->is_blocked();
}
i64 AudioDataProvider::queue_end_sample() const
i64 DecodedAudioProducer::queue_end_sample() const
{
return m_thread_data->queue_end_sample();
}
TimeRanges AudioDataProvider::buffered_time_ranges() const
TimeRanges DecodedAudioProducer::buffered_time_ranges() const
{
return m_thread_data->buffered_time_ranges();
}
bool AudioDataProvider::ThreadData::is_blocked() const
bool DecodedAudioProducer::ThreadData::is_blocked() const
{
return m_demuxer->is_read_blocked_for_track(m_track);
}
i64 AudioDataProvider::ThreadData::queue_end_sample() const
i64 DecodedAudioProducer::ThreadData::queue_end_sample() const
{
auto locker = take_lock();
return m_queue_end_sample;
}
AudioDataProvider::ThreadData::ThreadData(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const& demuxer, Track const& track, AK::Duration duration, NonnullOwnPtr<Audio::AudioConverter>&& converter)
DecodedAudioProducer::ThreadData::ThreadData(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const& demuxer, Track const& track, AK::Duration duration, NonnullOwnPtr<Audio::AudioConverter>&& converter)
: m_main_thread_event_loop(main_thread_event_loop)
, m_demuxer(demuxer)
, m_track(track)
@ -129,29 +129,29 @@ AudioDataProvider::ThreadData::ThreadData(NonnullRefPtr<Core::WeakEventLoopRefer
{
}
AudioDataProvider::ThreadData::~ThreadData() = default;
DecodedAudioProducer::ThreadData::~ThreadData() = default;
void AudioDataProvider::ThreadData::set_error_handler(ErrorHandler&& handler)
void DecodedAudioProducer::ThreadData::set_error_handler(ErrorHandler&& handler)
{
m_error_handler = move(handler);
}
void AudioDataProvider::ThreadData::set_duration_change_handler(BlockEndTimeHandler&& handler)
void DecodedAudioProducer::ThreadData::set_duration_change_handler(BlockEndTimeHandler&& handler)
{
m_duration_change_handler = move(handler);
}
void AudioDataProvider::ThreadData::set_queue_is_full_handler(QueueIsFullHandler&& handler)
void DecodedAudioProducer::ThreadData::set_queue_is_full_handler(QueueIsFullHandler&& handler)
{
m_queue_is_full_handler = move(handler);
}
void AudioDataProvider::ThreadData::set_output_sample_specification(Audio::SampleSpecification sample_specification)
void DecodedAudioProducer::ThreadData::set_output_sample_specification(Audio::SampleSpecification sample_specification)
{
m_converter->set_output_sample_specification(sample_specification).release_value_but_fixme_should_propagate_errors();
}
void AudioDataProvider::ThreadData::start()
void DecodedAudioProducer::ThreadData::start()
{
auto locker = take_lock();
if (m_requested_state != RequestedState::None)
@ -160,7 +160,7 @@ void AudioDataProvider::ThreadData::start()
wake();
}
DecoderErrorOr<void> AudioDataProvider::ThreadData::create_decoder()
DecoderErrorOr<void> DecodedAudioProducer::ThreadData::create_decoder()
{
auto codec_id = TRY(m_demuxer->get_codec_id_for_track(m_track));
auto const& sample_specification = m_track.audio_data().sample_specification;
@ -169,7 +169,7 @@ DecoderErrorOr<void> AudioDataProvider::ThreadData::create_decoder()
return {};
}
void AudioDataProvider::ThreadData::suspend()
void DecodedAudioProducer::ThreadData::suspend()
{
auto locker = take_lock();
VERIFY(m_requested_state != RequestedState::Exit);
@ -177,7 +177,7 @@ void AudioDataProvider::ThreadData::suspend()
wake();
}
void AudioDataProvider::ThreadData::resume()
void DecodedAudioProducer::ThreadData::resume()
{
auto locker = take_lock();
VERIFY(m_requested_state != RequestedState::Exit);
@ -185,14 +185,14 @@ void AudioDataProvider::ThreadData::resume()
wake();
}
void AudioDataProvider::ThreadData::exit()
void DecodedAudioProducer::ThreadData::exit()
{
auto locker = take_lock();
m_requested_state = RequestedState::Exit;
wake();
}
AudioBlock AudioDataProvider::retrieve_block()
AudioBlock DecodedAudioProducer::retrieve_block()
{
auto locker = m_thread_data->take_lock();
if (m_thread_data->queue().is_empty())
@ -202,7 +202,7 @@ AudioBlock AudioDataProvider::retrieve_block()
return result;
}
void AudioDataProvider::ThreadData::seek(AK::Duration timestamp, SeekCompletionHandler&& completion_handler)
void DecodedAudioProducer::ThreadData::seek(AK::Duration timestamp, SeekCompletionHandler&& completion_handler)
{
auto locker = take_lock();
m_seek_completion_handler = move(completion_handler);
@ -212,25 +212,25 @@ void AudioDataProvider::ThreadData::seek(AK::Duration timestamp, SeekCompletionH
wake();
}
void AudioDataProvider::ThreadData::wait_for_start()
void DecodedAudioProducer::ThreadData::wait_for_start()
{
auto locker = take_lock();
while (m_requested_state == RequestedState::None)
m_wait_condition.wait();
}
bool AudioDataProvider::ThreadData::should_thread_exit_while_locked() const
bool DecodedAudioProducer::ThreadData::should_thread_exit_while_locked() const
{
return m_requested_state == RequestedState::Exit;
}
bool AudioDataProvider::ThreadData::should_thread_exit() const
bool DecodedAudioProducer::ThreadData::should_thread_exit() const
{
auto locker = take_lock();
return should_thread_exit_while_locked();
}
bool AudioDataProvider::ThreadData::handle_suspension()
bool DecodedAudioProducer::ThreadData::handle_suspension()
{
{
auto locker = take_lock();
@ -268,7 +268,7 @@ bool AudioDataProvider::ThreadData::handle_suspension()
}
template<typename Invokee>
void AudioDataProvider::ThreadData::invoke_on_main_thread_while_locked(Invokee invokee)
void DecodedAudioProducer::ThreadData::invoke_on_main_thread_while_locked(Invokee invokee)
{
if (m_requested_state == RequestedState::Exit)
return;
@ -281,13 +281,13 @@ void AudioDataProvider::ThreadData::invoke_on_main_thread_while_locked(Invokee i
}
template<typename Invokee>
void AudioDataProvider::ThreadData::invoke_on_main_thread(Invokee invokee)
void DecodedAudioProducer::ThreadData::invoke_on_main_thread(Invokee invokee)
{
auto locker = take_lock();
invoke_on_main_thread_while_locked(move(invokee));
}
void AudioDataProvider::ThreadData::dispatch_block_end_time(AudioBlock const& block)
void DecodedAudioProducer::ThreadData::dispatch_block_end_time(AudioBlock const& block)
{
auto end_time = block.end_timestamp();
if (end_time < m_duration)
@ -299,13 +299,13 @@ void AudioDataProvider::ThreadData::dispatch_block_end_time(AudioBlock const& bl
});
}
void AudioDataProvider::ThreadData::clear_queue()
void DecodedAudioProducer::ThreadData::clear_queue()
{
m_queue.clear();
m_queue_end_sample = 0;
}
void AudioDataProvider::ThreadData::queue_block(AudioBlock&& block)
void DecodedAudioProducer::ThreadData::queue_block(AudioBlock&& block)
{
// FIXME: Specify trailing samples in the demuxer, and drop them here or in the audio decoder implementation.
@ -316,7 +316,7 @@ void AudioDataProvider::ThreadData::queue_block(AudioBlock&& block)
VERIFY(!m_queue.tail().is_empty());
}
void AudioDataProvider::ThreadData::dispatch_error(DecoderError&& error)
void DecodedAudioProducer::ThreadData::dispatch_error(DecoderError&& error)
{
if (error.category() == DecoderErrorCategory::Aborted)
return;
@ -324,13 +324,13 @@ void AudioDataProvider::ThreadData::dispatch_error(DecoderError&& error)
m_error_handler(move(error));
}
void AudioDataProvider::ThreadData::flush_decoder()
void DecodedAudioProducer::ThreadData::flush_decoder()
{
m_decoder->flush();
m_last_sample = NumericLimits<i64>::min();
}
DecoderErrorOr<void> AudioDataProvider::ThreadData::retrieve_next_block(AudioBlock& block)
DecoderErrorOr<void> DecodedAudioProducer::ThreadData::retrieve_next_block(AudioBlock& block)
{
TRY(m_decoder->write_next_block(block));
@ -345,7 +345,7 @@ DecoderErrorOr<void> AudioDataProvider::ThreadData::retrieve_next_block(AudioBlo
}
template<typename Callback>
void AudioDataProvider::ThreadData::process_seek_on_main_thread(u32 seek_id, Callback callback)
void DecodedAudioProducer::ThreadData::process_seek_on_main_thread(u32 seek_id, Callback callback)
{
m_last_processed_seek_id = seek_id;
invoke_on_main_thread_while_locked([seek_id, callback = move(callback)](auto& self) mutable {
@ -355,7 +355,7 @@ void AudioDataProvider::ThreadData::process_seek_on_main_thread(u32 seek_id, Cal
});
}
void AudioDataProvider::ThreadData::resolve_seek(u32 seek_id)
void DecodedAudioProducer::ThreadData::resolve_seek(u32 seek_id)
{
m_is_in_error_state = false;
process_seek_on_main_thread(seek_id, [](auto& self) {
@ -365,7 +365,7 @@ void AudioDataProvider::ThreadData::resolve_seek(u32 seek_id)
});
}
bool AudioDataProvider::ThreadData::handle_seek()
bool DecodedAudioProducer::ThreadData::handle_seek()
{
VERIFY(m_decoder);
@ -470,7 +470,7 @@ bool AudioDataProvider::ThreadData::handle_seek()
}
}
void AudioDataProvider::ThreadData::push_data_and_decode_a_block()
void DecodedAudioProducer::ThreadData::push_data_and_decode_a_block()
{
VERIFY(m_decoder);
@ -483,7 +483,7 @@ void AudioDataProvider::ThreadData::push_data_and_decode_a_block()
});
}
dbgln_if(PLAYBACK_MANAGER_DEBUG, "Audio Data Provider: Encountered an error, waiting for a seek to start decoding again...");
dbgln_if(PLAYBACK_MANAGER_DEBUG, "Decoded Audio Producer: Encountered an error, waiting for a seek to start decoding again...");
while (m_is_in_error_state) {
if (handle_seek())
break;
@ -555,7 +555,7 @@ void AudioDataProvider::ThreadData::push_data_and_decode_a_block()
}
}
TimeRanges AudioDataProvider::ThreadData::buffered_time_ranges() const
TimeRanges DecodedAudioProducer::ThreadData::buffered_time_ranges() const
{
return m_demuxer->buffered_time_ranges();
}

View file

@ -27,7 +27,7 @@
namespace Media {
// Retrieves coded data from a demuxer and decodes it asynchronously into audio samples to push to an AudioSink.
class MEDIA_API AudioDataProvider final : public AtomicRefCounted<AudioDataProvider> {
class MEDIA_API DecodedAudioProducer final : public AtomicRefCounted<DecodedAudioProducer> {
class ThreadData;
public:
@ -39,9 +39,9 @@ public:
using SeekCompletionHandler = Function<void()>;
using QueueIsFullHandler = Function<void()>;
static DecoderErrorOr<NonnullRefPtr<AudioDataProvider>> try_create(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const& demuxer, Track const& track);
AudioDataProvider(NonnullRefPtr<ThreadData> const&);
~AudioDataProvider();
static DecoderErrorOr<NonnullRefPtr<DecodedAudioProducer>> try_create(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const& demuxer, Track const& track);
DecodedAudioProducer(NonnullRefPtr<ThreadData> const&);
~DecodedAudioProducer();
void set_error_handler(ErrorHandler&&);
void set_duration_change_handler(BlockEndTimeHandler&&);

View file

@ -7,23 +7,23 @@
#include <LibCore/EventLoop.h>
#include <LibMedia/Demuxer.h>
#include <LibMedia/FFmpeg/FFmpegVideoDecoder.h>
#include <LibMedia/Providers/MediaTimeProvider.h>
#include <LibMedia/MediaTimeProvider.h>
#include <LibMedia/Sinks/VideoSink.h>
#include <LibMedia/VideoDecoder.h>
#include <LibMedia/VideoFrame.h>
#include <LibThreading/Thread.h>
#include "VideoDataProvider.h"
#include "DecodedVideoProducer.h"
namespace Media {
DecoderErrorOr<NonnullRefPtr<VideoDataProvider>> VideoDataProvider::try_create(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const& demuxer, Track const& track, RefPtr<MediaTimeProvider> const& time_provider)
DecoderErrorOr<NonnullRefPtr<DecodedVideoProducer>> DecodedVideoProducer::try_create(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const& demuxer, Track const& track, RefPtr<MediaTimeProvider> const& time_provider)
{
TRY(demuxer->create_context_for_track(track));
auto duration = TRY(demuxer->duration_of_track(track));
auto thread_data = DECODER_TRY_ALLOC(try_make_ref_counted<VideoDataProvider::ThreadData>(main_thread_event_loop, demuxer, track, duration, time_provider));
auto thread_data = DECODER_TRY_ALLOC(try_make_ref_counted<DecodedVideoProducer::ThreadData>(main_thread_event_loop, demuxer, track, duration, time_provider));
TRY(thread_data->create_decoder());
auto provider = DECODER_TRY_ALLOC(try_make_ref_counted<VideoDataProvider>(thread_data));
auto producer = DECODER_TRY_ALLOC(try_make_ref_counted<DecodedVideoProducer>(thread_data));
auto thread = DECODER_TRY_ALLOC(Threading::Thread::try_create("Video Decoder"sv, [thread_data]() -> int {
thread_data->wait_for_start();
@ -38,50 +38,50 @@ DecoderErrorOr<NonnullRefPtr<VideoDataProvider>> VideoDataProvider::try_create(N
thread->start();
thread->detach();
return provider;
return producer;
}
VideoDataProvider::VideoDataProvider(NonnullRefPtr<ThreadData> const& thread_state)
DecodedVideoProducer::DecodedVideoProducer(NonnullRefPtr<ThreadData> const& thread_state)
: m_thread_data(thread_state)
{
}
VideoDataProvider::~VideoDataProvider()
DecodedVideoProducer::~DecodedVideoProducer()
{
m_thread_data->exit();
}
void VideoDataProvider::set_error_handler(ErrorHandler&& handler)
void DecodedVideoProducer::set_error_handler(ErrorHandler&& handler)
{
m_thread_data->set_error_handler(move(handler));
}
void VideoDataProvider::set_duration_change_handler(FrameEndTimeHandler&& handler)
void DecodedVideoProducer::set_duration_change_handler(FrameEndTimeHandler&& handler)
{
m_thread_data->set_duration_change_handler(move(handler));
}
void VideoDataProvider::start()
void DecodedVideoProducer::start()
{
m_thread_data->start();
}
void VideoDataProvider::suspend()
void DecodedVideoProducer::suspend()
{
m_thread_data->suspend();
}
void VideoDataProvider::resume()
void DecodedVideoProducer::resume()
{
m_thread_data->resume();
}
void VideoDataProvider::set_frames_queue_is_full_handler(FramesQueueIsFullHandler&& handler)
void DecodedVideoProducer::set_frames_queue_is_full_handler(FramesQueueIsFullHandler&& handler)
{
m_thread_data->set_frames_queue_is_full_handler(move(handler));
}
RefPtr<VideoFrame> VideoDataProvider::retrieve_frame()
RefPtr<VideoFrame> DecodedVideoProducer::retrieve_frame()
{
auto locker = m_thread_data->take_lock();
if (m_thread_data->queue().is_empty())
@ -91,12 +91,12 @@ RefPtr<VideoFrame> VideoDataProvider::retrieve_frame()
return result;
}
void VideoDataProvider::seek(AK::Duration timestamp, SeekMode seek_mode, SeekCompletionHandler&& completion_handler)
void DecodedVideoProducer::seek(AK::Duration timestamp, SeekMode seek_mode, SeekCompletionHandler&& completion_handler)
{
m_thread_data->seek(timestamp, seek_mode, move(completion_handler));
}
VideoDataProvider::ThreadData::ThreadData(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const& demuxer, Track const& track, AK::Duration duration, RefPtr<MediaTimeProvider> const& time_provider)
DecodedVideoProducer::ThreadData::ThreadData(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const& demuxer, Track const& track, AK::Duration duration, RefPtr<MediaTimeProvider> const& time_provider)
: m_main_thread_event_loop(main_thread_event_loop)
, m_demuxer(demuxer)
, m_track(track)
@ -105,7 +105,7 @@ VideoDataProvider::ThreadData::ThreadData(NonnullRefPtr<Core::WeakEventLoopRefer
{
}
DecoderErrorOr<void> VideoDataProvider::ThreadData::create_decoder()
DecoderErrorOr<void> DecodedVideoProducer::ThreadData::create_decoder()
{
auto codec_id = TRY(m_demuxer->get_codec_id_for_track(m_track));
auto codec_initialization_data = TRY(m_demuxer->get_codec_initialization_data_for_track(m_track));
@ -113,24 +113,24 @@ DecoderErrorOr<void> VideoDataProvider::ThreadData::create_decoder()
return {};
}
bool VideoDataProvider::is_blocked() const
bool DecodedVideoProducer::is_blocked() const
{
return m_thread_data->is_blocked();
}
TimeRanges VideoDataProvider::buffered_time_ranges() const
TimeRanges DecodedVideoProducer::buffered_time_ranges() const
{
return m_thread_data->buffered_time_ranges();
}
VideoDataProvider::ThreadData::~ThreadData() = default;
DecodedVideoProducer::ThreadData::~ThreadData() = default;
void VideoDataProvider::ThreadData::set_error_handler(ErrorHandler&& handler)
void DecodedVideoProducer::ThreadData::set_error_handler(ErrorHandler&& handler)
{
m_error_handler = move(handler);
}
void VideoDataProvider::ThreadData::start()
void DecodedVideoProducer::ThreadData::start()
{
auto locker = take_lock();
if (m_requested_state != RequestedState::None)
@ -139,17 +139,17 @@ void VideoDataProvider::ThreadData::start()
wake();
}
void VideoDataProvider::ThreadData::set_duration_change_handler(FrameEndTimeHandler&& handler)
void DecodedVideoProducer::ThreadData::set_duration_change_handler(FrameEndTimeHandler&& handler)
{
m_duration_change_handler = move(handler);
}
void VideoDataProvider::ThreadData::set_frames_queue_is_full_handler(FramesQueueIsFullHandler&& handler)
void DecodedVideoProducer::ThreadData::set_frames_queue_is_full_handler(FramesQueueIsFullHandler&& handler)
{
m_frames_queue_is_full_handler = move(handler);
}
void VideoDataProvider::ThreadData::suspend()
void DecodedVideoProducer::ThreadData::suspend()
{
auto locker = take_lock();
VERIFY(m_requested_state != RequestedState::Exit);
@ -157,7 +157,7 @@ void VideoDataProvider::ThreadData::suspend()
wake();
}
void VideoDataProvider::ThreadData::resume()
void DecodedVideoProducer::ThreadData::resume()
{
auto locker = take_lock();
VERIFY(m_requested_state != RequestedState::Exit);
@ -165,24 +165,24 @@ void VideoDataProvider::ThreadData::resume()
wake();
}
void VideoDataProvider::ThreadData::exit()
void DecodedVideoProducer::ThreadData::exit()
{
auto locker = take_lock();
m_requested_state = RequestedState::Exit;
wake();
}
VideoDataProvider::FrameQueue& VideoDataProvider::ThreadData::queue()
DecodedVideoProducer::FrameQueue& DecodedVideoProducer::ThreadData::queue()
{
return m_queue;
}
NonnullRefPtr<VideoFrame> VideoDataProvider::ThreadData::take_frame()
NonnullRefPtr<VideoFrame> DecodedVideoProducer::ThreadData::take_frame()
{
return m_queue.dequeue();
}
void VideoDataProvider::ThreadData::seek(AK::Duration timestamp, SeekMode seek_mode, SeekCompletionHandler&& completion_handler)
void DecodedVideoProducer::ThreadData::seek(AK::Duration timestamp, SeekMode seek_mode, SeekCompletionHandler&& completion_handler)
{
auto locker = take_lock();
m_seek_id++;
@ -193,26 +193,26 @@ void VideoDataProvider::ThreadData::seek(AK::Duration timestamp, SeekMode seek_m
wake();
}
void VideoDataProvider::ThreadData::wait_for_start()
void DecodedVideoProducer::ThreadData::wait_for_start()
{
auto locker = take_lock();
while (m_requested_state == RequestedState::None)
m_wait_condition.wait();
}
bool VideoDataProvider::ThreadData::should_thread_exit_while_locked() const
bool DecodedVideoProducer::ThreadData::should_thread_exit_while_locked() const
{
return m_requested_state == RequestedState::Exit;
}
bool VideoDataProvider::ThreadData::should_thread_exit() const
bool DecodedVideoProducer::ThreadData::should_thread_exit() const
{
auto locker = take_lock();
return should_thread_exit_while_locked();
}
template<typename Invokee>
void VideoDataProvider::ThreadData::invoke_on_main_thread_while_locked(Invokee invokee)
void DecodedVideoProducer::ThreadData::invoke_on_main_thread_while_locked(Invokee invokee)
{
if (m_requested_state == RequestedState::Exit)
return;
@ -224,7 +224,7 @@ void VideoDataProvider::ThreadData::invoke_on_main_thread_while_locked(Invokee i
});
}
bool VideoDataProvider::ThreadData::handle_suspension()
bool DecodedVideoProducer::ThreadData::handle_suspension()
{
{
auto locker = take_lock();
@ -262,13 +262,13 @@ bool VideoDataProvider::ThreadData::handle_suspension()
}
template<typename Invokee>
void VideoDataProvider::ThreadData::invoke_on_main_thread(Invokee invokee)
void DecodedVideoProducer::ThreadData::invoke_on_main_thread(Invokee invokee)
{
auto locker = take_lock();
invoke_on_main_thread_while_locked(move(invokee));
}
void VideoDataProvider::ThreadData::dispatch_frame_end_time(CodedFrame const& frame)
void DecodedVideoProducer::ThreadData::dispatch_frame_end_time(CodedFrame const& frame)
{
auto end_time = frame.timestamp() + frame.duration();
if (end_time < m_duration)
@ -280,12 +280,12 @@ void VideoDataProvider::ThreadData::dispatch_frame_end_time(CodedFrame const& fr
});
}
void VideoDataProvider::ThreadData::queue_frame(NonnullRefPtr<VideoFrame> const& frame)
void DecodedVideoProducer::ThreadData::queue_frame(NonnullRefPtr<VideoFrame> const& frame)
{
m_queue.enqueue(frame);
}
void VideoDataProvider::ThreadData::dispatch_error(DecoderError&& error)
void DecodedVideoProducer::ThreadData::dispatch_error(DecoderError&& error)
{
if (error.category() == DecoderErrorCategory::Aborted)
return;
@ -294,7 +294,7 @@ void VideoDataProvider::ThreadData::dispatch_error(DecoderError&& error)
}
template<typename Callback>
void VideoDataProvider::ThreadData::process_seek_on_main_thread(u32 seek_id, Callback callback)
void DecodedVideoProducer::ThreadData::process_seek_on_main_thread(u32 seek_id, Callback callback)
{
m_last_processed_seek_id = seek_id;
invoke_on_main_thread_while_locked([seek_id, callback = move(callback)](auto& self) mutable {
@ -304,7 +304,7 @@ void VideoDataProvider::ThreadData::process_seek_on_main_thread(u32 seek_id, Cal
});
}
void VideoDataProvider::ThreadData::resolve_seek(u32 seek_id, AK::Duration const& timestamp)
void DecodedVideoProducer::ThreadData::resolve_seek(u32 seek_id, AK::Duration const& timestamp)
{
m_is_in_error_state = false;
process_seek_on_main_thread(seek_id, [timestamp](auto& self) {
@ -314,7 +314,7 @@ void VideoDataProvider::ThreadData::resolve_seek(u32 seek_id, AK::Duration const
});
}
bool VideoDataProvider::ThreadData::handle_seek()
bool DecodedVideoProducer::ThreadData::handle_seek()
{
VERIFY(m_decoder);
@ -468,7 +468,7 @@ bool VideoDataProvider::ThreadData::handle_seek()
}
}
void VideoDataProvider::ThreadData::push_data_and_decode_some_frames()
void DecodedVideoProducer::ThreadData::push_data_and_decode_some_frames()
{
VERIFY(m_decoder);
@ -485,7 +485,7 @@ void VideoDataProvider::ThreadData::push_data_and_decode_some_frames()
});
}
dbgln_if(PLAYBACK_MANAGER_DEBUG, "Video Data Provider: Encountered an error, waiting for a seek to start decoding again...");
dbgln_if(PLAYBACK_MANAGER_DEBUG, "Decoded Video Producer: Encountered an error, waiting for a seek to start decoding again...");
while (m_is_in_error_state) {
if (handle_seek())
break;
@ -562,12 +562,12 @@ void VideoDataProvider::ThreadData::push_data_and_decode_some_frames()
}
}
bool VideoDataProvider::ThreadData::is_blocked() const
bool DecodedVideoProducer::ThreadData::is_blocked() const
{
return m_demuxer->is_read_blocked_for_track(m_track);
}
TimeRanges VideoDataProvider::ThreadData::buffered_time_ranges() const
TimeRanges DecodedVideoProducer::ThreadData::buffered_time_ranges() const
{
return m_demuxer->buffered_time_ranges();
}

View file

@ -26,7 +26,7 @@
namespace Media {
// Retrieves coded data from a demuxer and decodes it asynchronously into video frames ready for display.
class MEDIA_API VideoDataProvider final : public AtomicRefCounted<VideoDataProvider> {
class MEDIA_API DecodedVideoProducer final : public AtomicRefCounted<DecodedVideoProducer> {
class ThreadData;
public:
@ -38,10 +38,10 @@ 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<Demuxer> const&, Track const&, RefPtr<MediaTimeProvider> const& = nullptr);
static DecoderErrorOr<NonnullRefPtr<DecodedVideoProducer>> try_create(NonnullRefPtr<Core::WeakEventLoopReference> const& main_thread_event_loop, NonnullRefPtr<Demuxer> const&, Track const&, RefPtr<MediaTimeProvider> const& = nullptr);
VideoDataProvider(NonnullRefPtr<ThreadData> const&);
~VideoDataProvider();
DecodedVideoProducer(NonnullRefPtr<ThreadData> const&);
~DecodedVideoProducer();
void set_error_handler(ErrorHandler&&);
void set_duration_change_handler(FrameEndTimeHandler&&);

View file

@ -12,7 +12,7 @@
#include <LibMedia/Audio/Forward.h>
#include <LibMedia/Export.h>
#include <LibMedia/Forward.h>
#include <LibMedia/Providers/MediaTimeProvider.h>
#include <LibMedia/MediaTimeProvider.h>
namespace Media {

View file

@ -18,8 +18,8 @@ class MEDIA_API AudioSink : public virtual MediaPipelineNode {
public:
virtual ~AudioSink() = default;
virtual void set_provider(Track const&, RefPtr<AudioDataProvider> const&) = 0;
virtual RefPtr<AudioDataProvider> provider(Track const&) const = 0;
virtual void set_producer(Track const&, RefPtr<DecodedAudioProducer> const&) = 0;
virtual RefPtr<DecodedAudioProducer> producer(Track const&) const = 0;
};
}

View file

@ -5,8 +5,8 @@
*/
#include <LibMedia/Demuxer.h>
#include <LibMedia/Providers/MediaTimeProvider.h>
#include <LibMedia/Providers/VideoDataProvider.h>
#include <LibMedia/MediaTimeProvider.h>
#include <LibMedia/Producers/DecodedVideoProducer.h>
#include <LibMedia/VideoFrame.h>
#include "DisplayingVideoSink.h"
@ -32,30 +32,30 @@ void DisplayingVideoSink::set_time_provider(NonnullRefPtr<MediaTimeProvider> con
void DisplayingVideoSink::verify_track(Track const& track) const
{
if (m_provider == nullptr)
if (m_producer == nullptr)
return;
VERIFY(m_track.has_value());
VERIFY(m_track.value() == track);
}
void DisplayingVideoSink::set_provider(Track const& track, RefPtr<VideoDataProvider> const& provider)
void DisplayingVideoSink::set_producer(Track const& track, RefPtr<DecodedVideoProducer> const& producer)
{
verify_track(track);
m_track = track;
m_provider = provider;
if (provider != nullptr)
provider->start();
m_producer = producer;
if (producer != nullptr)
producer->start();
}
RefPtr<VideoDataProvider> DisplayingVideoSink::provider(Track const& track) const
RefPtr<DecodedVideoProducer> DisplayingVideoSink::producer(Track const& track) const
{
verify_track(track);
return m_provider;
return m_producer;
}
DisplayingVideoSinkUpdateResult DisplayingVideoSink::update()
{
if (m_provider == nullptr)
if (m_producer == nullptr)
return DisplayingVideoSinkUpdateResult::NoChange;
if (m_pause_updates)
return DisplayingVideoSinkUpdateResult::NoChange;
@ -69,9 +69,9 @@ DisplayingVideoSinkUpdateResult DisplayingVideoSink::update()
while (true) {
if (!m_next_frame) {
m_next_frame = m_provider->retrieve_frame();
m_next_frame = m_producer->retrieve_frame();
if (!m_next_frame) {
if (m_provider->is_blocked() && m_on_start_buffering)
if (m_producer->is_blocked() && m_on_start_buffering)
m_on_start_buffering();
break;
}

View file

@ -29,8 +29,8 @@ public:
void set_time_provider(NonnullRefPtr<MediaTimeProvider> const&);
virtual void set_provider(Track const&, RefPtr<VideoDataProvider> const&) override;
RefPtr<VideoDataProvider> provider(Track const&) const override;
virtual void set_producer(Track const&, RefPtr<DecodedVideoProducer> const&) override;
RefPtr<DecodedVideoProducer> producer(Track const&) const override;
[[nodiscard]] DisplayingVideoSinkUpdateResult update();
void prepare_current_frame_for_next_update();
@ -45,7 +45,7 @@ private:
void verify_track(Track const&) const;
NonnullRefPtr<MediaTimeProvider> m_time_provider;
RefPtr<VideoDataProvider> m_provider;
RefPtr<DecodedVideoProducer> m_producer;
Optional<Track> m_track;
RefPtr<VideoFrame> m_next_frame;

View file

@ -12,13 +12,13 @@
namespace Media {
// A consumer to be attached to a VideoDataProvider in order to receive video frames from a decoding thread.
// A consumer to be attached to a DecodedVideoProducer in order to receive video frames from a decoding thread.
class VideoSink : public AtomicRefCounted<VideoSink> {
public:
virtual ~VideoSink() = default;
virtual void set_provider(Track const&, RefPtr<VideoDataProvider> const&) = 0;
virtual RefPtr<VideoDataProvider> provider(Track const&) const = 0;
virtual void set_producer(Track const&, RefPtr<DecodedVideoProducer> const&) = 0;
virtual RefPtr<DecodedVideoProducer> producer(Track const&) const = 0;
};
}

View file

@ -1,9 +1,9 @@
include(audio)
set(TEST_SOURCES
TestAudioDataProvider.cpp
TestCICP.cpp
TestDataProviders.cpp
TestDataProducers.cpp
TestDecodedAudioProducer.cpp
TestFFmpegAudioNormalization.cpp
TestFFmpegDemuxer.cpp
TestH264Decode.cpp

View file

@ -11,12 +11,12 @@
#include <LibMedia/Containers/Matroska/MatroskaDemuxer.h>
#include <LibMedia/FFmpeg/FFmpegDemuxer.h>
#include <LibMedia/IncrementallyPopulatedStream.h>
#include <LibMedia/Providers/AudioDataProvider.h>
#include <LibMedia/Providers/MediaTimeProvider.h>
#include <LibMedia/Providers/VideoDataProvider.h>
#include <LibMedia/MediaTimeProvider.h>
#include <LibMedia/Producers/DecodedAudioProducer.h>
#include <LibMedia/Producers/DecodedVideoProducer.h>
#include <LibTest/TestCase.h>
// The following tests attempt to reproduce a race condition in AudioDataProvider and VideoDataProvider
// The following tests attempt to reproduce a race condition in DecodedAudioProducer and DecodedVideoProducer
// where rapidly transitioning through states None -> Suspended -> Exit can cause the decoder thread to
// continue with a null decoder.
@ -36,7 +36,7 @@ static NonnullRefPtr<Media::Demuxer> create_demuxer(NonnullRefPtr<Media::Increme
static constexpr size_t iterations = 100;
TEST_CASE(audio_provider_suspend_then_exit)
TEST_CASE(audio_producer_suspend_then_exit)
{
Core::EventLoop loop;
@ -46,14 +46,14 @@ TEST_CASE(audio_provider_suspend_then_exit)
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, track.release_value()));
auto producer = TRY_OR_FAIL(Media::DecodedAudioProducer::try_create(Core::EventLoop::current_weak(), demuxer, track.release_value()));
provider->suspend();
producer->suspend();
MUST(Core::System::sleep_ms(1));
}
}
TEST_CASE(video_provider_suspend_then_exit)
TEST_CASE(video_producer_suspend_then_exit)
{
Core::EventLoop loop;
@ -63,14 +63,14 @@ TEST_CASE(video_provider_suspend_then_exit)
auto track = TRY_OR_FAIL(demuxer->get_preferred_track_for_type(Media::TrackType::Video));
VERIFY(track.has_value());
auto provider = TRY_OR_FAIL(Media::VideoDataProvider::try_create(Core::EventLoop::current_weak(), demuxer, track.release_value()));
auto producer = TRY_OR_FAIL(Media::DecodedVideoProducer::try_create(Core::EventLoop::current_weak(), demuxer, track.release_value()));
provider->suspend();
producer->suspend();
MUST(Core::System::sleep_ms(1));
}
}
TEST_CASE(audio_provider_start_suspend_then_exit)
TEST_CASE(audio_producer_start_suspend_then_exit)
{
Core::EventLoop loop;
@ -80,16 +80,16 @@ TEST_CASE(audio_provider_start_suspend_then_exit)
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, track.release_value()));
auto producer = TRY_OR_FAIL(Media::DecodedAudioProducer::try_create(Core::EventLoop::current_weak(), demuxer, track.release_value()));
provider->start();
producer->start();
MUST(Core::System::sleep_ms(1));
provider->suspend();
producer->suspend();
MUST(Core::System::sleep_ms(1));
}
}
TEST_CASE(video_provider_start_suspend_then_exit)
TEST_CASE(video_producer_start_suspend_then_exit)
{
Core::EventLoop loop;
@ -99,16 +99,16 @@ TEST_CASE(video_provider_start_suspend_then_exit)
auto track = TRY_OR_FAIL(demuxer->get_preferred_track_for_type(Media::TrackType::Video));
VERIFY(track.has_value());
auto provider = TRY_OR_FAIL(Media::VideoDataProvider::try_create(Core::EventLoop::current_weak(), demuxer, track.release_value()));
auto producer = TRY_OR_FAIL(Media::DecodedVideoProducer::try_create(Core::EventLoop::current_weak(), demuxer, track.release_value()));
provider->start();
producer->start();
MUST(Core::System::sleep_ms(1));
provider->suspend();
producer->suspend();
MUST(Core::System::sleep_ms(1));
}
}
TEST_CASE(audio_provider_underspecified_5_1_channel_map)
TEST_CASE(audio_producer_underspecified_5_1_channel_map)
{
Core::EventLoop loop;
@ -117,15 +117,15 @@ TEST_CASE(audio_provider_underspecified_5_1_channel_map)
auto tracks = TRY_OR_FAIL(demuxer->get_tracks_for_type(Media::TrackType::Audio));
VERIFY(!tracks.is_empty());
auto provider = TRY_OR_FAIL(Media::AudioDataProvider::try_create(Core::EventLoop::current_weak(), demuxer, tracks[0]));
auto producer = TRY_OR_FAIL(Media::DecodedAudioProducer::try_create(Core::EventLoop::current_weak(), demuxer, tracks[0]));
provider->start();
producer->start();
auto time_limit = AK::Duration::from_seconds(1);
auto start_time = MonotonicTime::now_coarse();
while (true) {
auto block = provider->retrieve_block();
auto block = producer->retrieve_block();
if (!block.is_empty()) {
EXPECT_EQ(block.channel_count(), 6);
EXPECT_EQ(block.sample_specification().channel_map(), Audio::ChannelMap::surround_5_1());

View file

@ -11,7 +11,7 @@
#include <LibCore/EventLoop.h>
#include <LibMedia/FFmpeg/FFmpegDemuxer.h>
#include <LibMedia/IncrementallyPopulatedStream.h>
#include <LibMedia/Providers/AudioDataProvider.h>
#include <LibMedia/Producers/DecodedAudioProducer.h>
#include <LibTest/TestCase.h>
template<typename Integer>
@ -78,17 +78,17 @@ static void decode_and_expect()
auto tracks = TRY_OR_FAIL(demuxer->get_tracks_for_type(Media::TrackType::Audio));
VERIFY(!tracks.is_empty());
auto provider = TRY_OR_FAIL(Media::AudioDataProvider::try_create(Core::EventLoop::current_weak(), demuxer, tracks[0]));
auto producer = TRY_OR_FAIL(Media::DecodedAudioProducer::try_create(Core::EventLoop::current_weak(), demuxer, tracks[0]));
bool reached_end_of_stream = false;
provider->set_error_handler([&](Media::DecoderError&& error) {
producer->set_error_handler([&](Media::DecoderError&& error) {
if (error.category() == Media::DecoderErrorCategory::EndOfStream) {
reached_end_of_stream = true;
return;
}
FAIL("An error occurred while decoding generated WAV data.");
});
provider->start();
producer->start();
bool saw_negative_full_scale_sample = false;
bool saw_positive_peak_sample = false;
@ -96,7 +96,7 @@ static void decode_and_expect()
MonotonicTime deadline = MonotonicTime::now_coarse() + AK::Duration::from_seconds(1);
while (MonotonicTime::now_coarse() < deadline) {
auto block = provider->retrieve_block();
auto block = producer->retrieve_block();
if (block.is_empty()) {
if (reached_end_of_stream)
break;

View file

@ -15,7 +15,7 @@
#include <LibMedia/Containers/Matroska/Reader.h>
#include <LibMedia/Demuxer.h>
#include <LibMedia/FFmpeg/FFmpegDemuxer.h>
#include <LibMedia/Providers/AudioDataProvider.h>
#include <LibMedia/Producers/DecodedAudioProducer.h>
#include <LibMedia/VideoDecoder.h>
#include <LibMedia/VideoFrame.h>
#include <LibTest/TestCase.h>
@ -82,17 +82,17 @@ static inline void decode_audio(StringView path, u32 sample_rate, u8 channel_cou
}());
auto tracks = TRY_OR_FAIL(demuxer->get_tracks_for_type(Media::TrackType::Audio));
VERIFY(!tracks.is_empty());
auto provider = TRY_OR_FAIL(Media::AudioDataProvider::try_create(Core::EventLoop::current_weak(), demuxer, tracks[0]));
auto producer = TRY_OR_FAIL(Media::DecodedAudioProducer::try_create(Core::EventLoop::current_weak(), demuxer, tracks[0]));
auto reached_end = false;
provider->set_error_handler([&](Media::DecoderError&& error) {
producer->set_error_handler([&](Media::DecoderError&& error) {
if (error.category() == Media::DecoderErrorCategory::EndOfStream) {
reached_end = true;
return;
}
FAIL("An error occurred while decoding.");
});
provider->start();
producer->start();
auto time_limit = AK::Duration::from_seconds(1);
auto start_time = MonotonicTime::now_coarse();
@ -101,7 +101,7 @@ static inline void decode_audio(StringView path, u32 sample_rate, u8 channel_cou
size_t sample_count = 0;
while (true) {
auto block = provider->retrieve_block();
auto block = producer->retrieve_block();
if (block.is_empty()) {
if (reached_end)
break;

View file

@ -9,6 +9,6 @@
TEST_CASE(44_1Khz_stereo)
{
// FIXME: 96 samples are marked to be discarded, but AudioDataProvider currently is not aware of this.
// FIXME: 96 samples are marked to be discarded, but DecodedAudioProducer currently is not aware of this.
decode_audio("vorbis/44_1Khz_stereo.ogg"sv, 44100, 2, 352800 + 96);
}