/* * Copyright (c) 2022, Gregory Bertilson * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include "VideoDecoder.h" namespace Video { struct FrameQueueItem { static constexpr Time no_timestamp = Time::min(); enum class Type { Frame, Error, }; static FrameQueueItem frame(RefPtr bitmap, Time timestamp) { return FrameQueueItem(move(bitmap), timestamp); } static FrameQueueItem error_marker(DecoderError&& error, Time timestamp) { return FrameQueueItem(move(error), timestamp); } bool is_frame() const { return m_data.has>(); } RefPtr bitmap() const { return m_data.get>(); } Time timestamp() const { return m_timestamp; } bool is_error() const { return m_data.has(); } DecoderError const& error() const { return m_data.get(); } DecoderError release_error() { auto error = move(m_data.get()); m_data.set(Empty()); return error; } DeprecatedString debug_string() const { if (is_error()) return DeprecatedString::formatted("{} at {}ms", error().string_literal(), timestamp().to_milliseconds()); return DeprecatedString::formatted("frame at {}ms", timestamp().to_milliseconds()); } private: FrameQueueItem(RefPtr bitmap, Time timestamp) : m_data(move(bitmap)) , m_timestamp(timestamp) { VERIFY(m_timestamp != no_timestamp); } FrameQueueItem(DecoderError&& error, Time timestamp) : m_data(move(error)) , m_timestamp(timestamp) { } Variant, DecoderError> m_data; Time m_timestamp; }; static constexpr size_t FRAME_BUFFER_COUNT = 4; using VideoFrameQueue = Queue; class PlaybackManager { public: enum class SeekMode { Accurate, Fast, }; static constexpr SeekMode DEFAULT_SEEK_MODE = SeekMode::Accurate; static DecoderErrorOr> from_file(Core::Object& event_handler, StringView file); PlaybackManager(Core::Object& event_handler, NonnullOwnPtr& demuxer, Track video_track, NonnullOwnPtr&& decoder); void resume_playback(); void pause_playback(); void restart_playback(); void seek_to_timestamp(Time, SeekMode = DEFAULT_SEEK_MODE); bool is_playing() const { return m_playback_handler->is_playing(); } u64 number_of_skipped_frames() const { return m_skipped_frames; } Time current_playback_time(); Time duration(); Function, Time)> on_frame_present; private: class PlaybackStateHandler; // Abstract class to allow resuming play/pause after the state is completed. class ResumingStateHandler; class StartingStateHandler; class PlayingStateHandler; class PausedStateHandler; class BufferingStateHandler; class SeekingStateHandler; class StoppedStateHandler; void start_timer(int milliseconds); void timer_callback(); Optional