/* * Copyright (c) 2025, Gregory Bertilson * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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 { class ThreadData; public: static constexpr size_t QUEUE_CAPACITY = 8; using ImageQueue = Queue; using ErrorHandler = Function; using SeekCompletionHandler = Function; static DecoderErrorOr> try_create(NonnullRefPtr const&, Track const&, RefPtr const& = nullptr); static DecoderErrorOr> try_create(NonnullRefPtr const&, Track const&, RefPtr const& = nullptr); VideoDataProvider(NonnullRefPtr const&); ~VideoDataProvider(); void set_error_handler(ErrorHandler&&); TimedImage retrieve_frame(); void seek(AK::Duration timestamp, SeekMode, SeekCompletionHandler&& = nullptr); private: class ThreadData final : public AtomicRefCounted { public: ThreadData(NonnullRefPtr const&, Track const&, NonnullOwnPtr&&, RefPtr const&); ~ThreadData(); void set_error_handler(ErrorHandler&&); void exit(); ImageQueue& queue(); TimedImage take_frame(); void seek(AK::Duration timestamp, SeekMode, SeekCompletionHandler&&); bool should_thread_exit() const; void set_cicp_values(VideoFrame&); void queue_frame(TimedImage&&); bool handle_seek(); template void process_seek_on_main_thread(u32 seek_id, T&&); void resolve_seek(u32 seek_id, AK::Duration const& timestamp); void push_data_and_decode_some_frames(); [[nodiscard]] Threading::MutexLocker take_lock() { return Threading::MutexLocker(m_mutex); } void wake() { m_wait_condition.broadcast(); } private: Core::EventLoop& m_main_thread_event_loop; Threading::Mutex m_mutex; Threading::ConditionVariable m_wait_condition { m_mutex }; Atomic m_exit { false }; NonnullRefPtr m_demuxer; Track m_track; NonnullOwnPtr m_decoder; RefPtr m_time_provider; size_t m_queue_max_size { 4 }; ImageQueue m_queue; ErrorHandler m_error_handler; bool m_is_in_error_state { false }; u32 m_last_processed_seek_id { 0 }; Atomic m_seek_id { 0 }; SeekCompletionHandler m_seek_completion_handler; AK::Duration m_seek_timestamp; SeekMode m_seek_mode { SeekMode::Accurate }; }; NonnullRefPtr m_thread_data; }; }