/* * Copyright (c) 2021, Hunter Salyer * Copyright (c) 2022, Gregory Bertilson * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include "Document.h" namespace Media::Matroska { class SampleIterator; class Streamer; struct TrackCuePoint { AK::Duration timestamp; CueTrackPosition position; }; enum class CuePointTarget : u8 { Cluster, Block, }; class MEDIA_API Reader { public: typedef Function(TrackEntry const&)> TrackEntryCallback; static DecoderErrorOr from_stream(NonnullRefPtr const&); static bool is_matroska_or_webm(NonnullRefPtr const&); Optional duration() { return m_segment_information.duration(); } DecoderErrorOr for_each_track(TrackEntryCallback); DecoderErrorOr for_each_track_of_type(TrackEntry::TrackType, TrackEntryCallback); DecoderErrorOr> track_for_track_number(u64); DecoderErrorOr track_count(); DecoderErrorOr create_sample_iterator(NonnullRefPtr const& stream_consumer, u64 track_number); DecoderErrorOr seek_to_random_access_point(SampleIterator, AK::Duration); private: Reader() = default; DecoderErrorOr parse_initial_data(Streamer&); DecoderErrorOr> find_first_top_level_element_with_id(Streamer&, StringView element_name, u32 element_id); DecoderErrorOr parse_segment_information(Streamer&); DecoderErrorOr parse_tracks(Streamer&); void fix_track_quirks(); void fix_ffmpeg_webm_quirk(); DecoderErrorOr parse_cues(Streamer&); Optional const&> cue_points_for_track(u64 track_number); bool has_cues_for_track(u64 track_number); DecoderErrorOr seek_to_cue_for_timestamp(SampleIterator&, AK::Duration const&, Vector const&, CuePointTarget); Optional m_header; size_t m_segment_contents_position { 0 }; size_t m_segment_contents_size { 0 }; HashMap m_seek_entries; size_t m_last_top_level_element_position { 0 }; SegmentInformation m_segment_information; OrderedHashMap> m_tracks; size_t m_first_cluster_position { 0 }; // The vectors must be sorted by timestamp at all times. HashMap> m_cues; }; class MEDIA_API SampleIterator { AK_MAKE_DEFAULT_MOVABLE(SampleIterator); AK_MAKE_DEFAULT_COPYABLE(SampleIterator); public: ~SampleIterator(); DecoderErrorOr next_block(); DecoderErrorOr> get_frames(Block); Cluster const& current_cluster() const { return *m_current_cluster; } Optional const& last_timestamp() const { return m_last_timestamp; } TrackEntry const& track() const { return *m_track; } MediaStreamCursor& cursor() { return m_stream_cursor; } private: friend class Reader; SampleIterator(NonnullRefPtr const& stream_cursor, TrackEntry& track, u64 timestamp_scale, size_t segment_contents_position, size_t position); DecoderErrorOr seek_to_cue_point(TrackCuePoint const& cue_point, CuePointTarget); NonnullRefPtr m_stream_cursor; NonnullRefPtr m_track; u64 m_segment_timestamp_scale { 0 }; size_t m_segment_contents_position { 0 }; // Must always point to an element ID or the end of the stream. size_t m_position { 0 }; Optional m_last_timestamp; Optional m_current_cluster; }; class Streamer { public: Streamer(NonnullRefPtr const& stream_cursor); ~Streamer(); DecoderErrorOr read_octet(); DecoderErrorOr read_i16(); DecoderErrorOr read_variable_size_integer(bool mask_length = true); DecoderErrorOr read_variable_size_signed_integer(); DecoderErrorOr read_u64(); DecoderErrorOr read_float(); DecoderErrorOr read_string(); DecoderErrorOr read_unknown_element(); DecoderErrorOr read_raw_octets(size_t num_octets); size_t position() const; DecoderErrorOr seek_to_position(size_t position); private: NonnullRefPtr m_stream_cursor; }; }