From f4c476b26fd9a748127882d70a7b9b0eb09d1335 Mon Sep 17 00:00:00 2001 From: Zaggy1024 Date: Fri, 11 Nov 2022 19:09:53 -0600 Subject: [PATCH] LibVideo: Make Matroska element parsing functions static Making these functions static makes it easier to implement lazy-loading since the parsing functions can now be called at any time. The functions were reorganized because they were not defined in the order they are called. However, instead of moving every function to that order, I've declared some but defined them further into the file, which allows the next commit's diff to be more readable. --- .../LibVideo/Containers/Matroska/Reader.cpp | 318 +++++++++--------- .../LibVideo/Containers/Matroska/Reader.h | 112 +++--- 2 files changed, 211 insertions(+), 219 deletions(-) diff --git a/Userland/Libraries/LibVideo/Containers/Matroska/Reader.cpp b/Userland/Libraries/LibVideo/Containers/Matroska/Reader.cpp index 6db52d3935..14bbc981a9 100644 --- a/Userland/Libraries/LibVideo/Containers/Matroska/Reader.cpp +++ b/Userland/Libraries/LibVideo/Containers/Matroska/Reader.cpp @@ -67,59 +67,40 @@ DecoderErrorOr> Reader::parse_matroska_from_data return reader.parse(); } -DecoderErrorOr> Reader::parse() +static DecoderErrorOr parse_master_element(Streamer& streamer, [[maybe_unused]] StringView element_name, Function(u64)> element_consumer) { - auto first_element_id = TRY_READ(m_streamer.read_variable_size_integer(false)); - dbgln_if(MATROSKA_TRACE_DEBUG, "First element ID is {:#010x}\n", first_element_id); - if (first_element_id != EBML_MASTER_ELEMENT_ID) - return DecoderError::corrupted("First element was not an EBML header"sv); - - auto header = TRY(parse_ebml_header()); - dbgln_if(MATROSKA_DEBUG, "Parsed EBML header"); - - auto root_element_id = TRY_READ(m_streamer.read_variable_size_integer(false)); - if (root_element_id != SEGMENT_ELEMENT_ID) - return DecoderError::corrupted("Second element was not a segment element"sv); - - auto matroska_document = make(header); - TRY(parse_segment_elements(*matroska_document)); - return matroska_document; -} - -DecoderErrorOr Reader::parse_master_element([[maybe_unused]] StringView element_name, Function(u64)> element_consumer) -{ - auto element_data_size = TRY_READ(m_streamer.read_variable_size_integer()); + auto element_data_size = TRY_READ(streamer.read_variable_size_integer()); dbgln_if(MATROSKA_DEBUG, "{} has {} octets of data.", element_name, element_data_size); - m_streamer.push_octets_read(); - while (m_streamer.octets_read() < element_data_size) { + streamer.push_octets_read(); + while (streamer.octets_read() < element_data_size) { dbgln_if(MATROSKA_TRACE_DEBUG, "====== Reading element ======"); - auto element_id = TRY_READ(m_streamer.read_variable_size_integer(false)); + auto element_id = TRY_READ(streamer.read_variable_size_integer(false)); dbgln_if(MATROSKA_TRACE_DEBUG, "{:s} element ID is {:#010x}\n", element_name, element_id); TRY(element_consumer(element_id)); - dbgln_if(MATROSKA_TRACE_DEBUG, "Read {} octets of the {} so far.", m_streamer.octets_read(), element_name); + dbgln_if(MATROSKA_TRACE_DEBUG, "Read {} octets of the {} so far.", streamer.octets_read(), element_name); } - m_streamer.pop_octets_read(); + streamer.pop_octets_read(); return {}; } -DecoderErrorOr Reader::parse_ebml_header() +static DecoderErrorOr parse_ebml_header(Streamer& streamer) { EBMLHeader header; - TRY(parse_master_element("Header"sv, [&](u64 element_id) -> DecoderErrorOr { + TRY(parse_master_element(streamer, "Header"sv, [&](u64 element_id) -> DecoderErrorOr { switch (element_id) { case DOCTYPE_ELEMENT_ID: - header.doc_type = TRY_READ(m_streamer.read_string()); + header.doc_type = TRY_READ(streamer.read_string()); dbgln_if(MATROSKA_DEBUG, "Read DocType attribute: {}", header.doc_type); break; case DOCTYPE_VERSION_ELEMENT_ID: - header.doc_type_version = TRY_READ(m_streamer.read_u64()); + header.doc_type_version = TRY_READ(streamer.read_u64()); dbgln_if(MATROSKA_DEBUG, "Read DocTypeVersion attribute: {}", header.doc_type_version); break; default: - TRY_READ(m_streamer.read_unknown_element()); + TRY_READ(streamer.read_unknown_element()); } return {}; @@ -128,51 +109,74 @@ DecoderErrorOr Reader::parse_ebml_header() return header; } -DecoderErrorOr Reader::parse_segment_elements(MatroskaDocument& matroska_document) +static DecoderErrorOr> parse_information(Streamer& streamer); +static DecoderErrorOr parse_tracks(Streamer& streamer, MatroskaDocument& matroska_document); +static DecoderErrorOr> parse_cluster(Streamer& streamer); + +static DecoderErrorOr parse_segment_elements(Streamer& streamer, MatroskaDocument& matroska_document) { dbgln_if(MATROSKA_DEBUG, "Parsing segment elements"); - return parse_master_element("Segment"sv, [&](u64 element_id) -> DecoderErrorOr { + return parse_master_element(streamer, "Segment"sv, [&](u64 element_id) -> DecoderErrorOr { switch (element_id) { case SEGMENT_INFORMATION_ELEMENT_ID: - matroska_document.set_segment_information(TRY(parse_information())); + matroska_document.set_segment_information(TRY(parse_information(streamer))); break; case TRACK_ELEMENT_ID: - TRY(parse_tracks(matroska_document)); + TRY(parse_tracks(streamer, matroska_document)); break; case CLUSTER_ELEMENT_ID: - matroska_document.clusters().append(TRY(parse_cluster())); + matroska_document.clusters().append(TRY(parse_cluster(streamer))); break; default: - TRY_READ(m_streamer.read_unknown_element()); + TRY_READ(streamer.read_unknown_element()); } return {}; }); } -DecoderErrorOr> Reader::parse_information() +DecoderErrorOr> Reader::parse() +{ + auto first_element_id = TRY_READ(m_streamer.read_variable_size_integer(false)); + dbgln_if(MATROSKA_TRACE_DEBUG, "First element ID is {:#010x}\n", first_element_id); + if (first_element_id != EBML_MASTER_ELEMENT_ID) + return DecoderError::corrupted("First element was not an EBML header"sv); + + auto header = TRY(parse_ebml_header(m_streamer)); + dbgln_if(MATROSKA_DEBUG, "Parsed EBML header"); + + auto root_element_id = TRY_READ(m_streamer.read_variable_size_integer(false)); + if (root_element_id != SEGMENT_ELEMENT_ID) + return DecoderError::corrupted("Second element was not a segment element"sv); + + auto matroska_document = make(header); + TRY(parse_segment_elements(m_streamer, *matroska_document)); + return matroska_document; +} + +static DecoderErrorOr> parse_information(Streamer& streamer) { auto segment_information = make(); - TRY(parse_master_element("Segment Information"sv, [&](u64 element_id) -> DecoderErrorOr { + TRY(parse_master_element(streamer, "Segment Information"sv, [&](u64 element_id) -> DecoderErrorOr { switch (element_id) { case TIMESTAMP_SCALE_ID: - segment_information->set_timestamp_scale(TRY_READ(m_streamer.read_u64())); + segment_information->set_timestamp_scale(TRY_READ(streamer.read_u64())); dbgln_if(MATROSKA_DEBUG, "Read TimestampScale attribute: {}", segment_information->timestamp_scale()); break; case MUXING_APP_ID: - segment_information->set_muxing_app(TRY_READ(m_streamer.read_string())); + segment_information->set_muxing_app(TRY_READ(streamer.read_string())); dbgln_if(MATROSKA_DEBUG, "Read MuxingApp attribute: {}", segment_information->muxing_app().as_string()); break; case WRITING_APP_ID: - segment_information->set_writing_app(TRY_READ(m_streamer.read_string())); + segment_information->set_writing_app(TRY_READ(streamer.read_string())); dbgln_if(MATROSKA_DEBUG, "Read WritingApp attribute: {}", segment_information->writing_app().as_string()); break; case DURATION_ID: - segment_information->set_duration(TRY_READ(m_streamer.read_float())); + segment_information->set_duration(TRY_READ(streamer.read_float())); dbgln_if(MATROSKA_DEBUG, "Read Duration attribute: {}", segment_information->duration().value()); break; default: - TRY_READ(m_streamer.read_unknown_element()); + TRY_READ(streamer.read_unknown_element()); } return {}; @@ -181,88 +185,30 @@ DecoderErrorOr> Reader::parse_information() return segment_information; } -DecoderErrorOr Reader::parse_tracks(MatroskaDocument& matroska_document) -{ - return parse_master_element("Tracks"sv, [&](u64 element_id) -> DecoderErrorOr { - if (element_id == TRACK_ENTRY_ID) { - dbgln_if(MATROSKA_DEBUG, "Parsing track"); - auto track_entry = TRY(parse_track_entry()); - auto track_number = track_entry->track_number(); - dbgln_if(MATROSKA_DEBUG, "Adding track {} to document", track_number); - matroska_document.add_track(track_number, track_entry.release_nonnull()); - } else { - TRY_READ(m_streamer.read_unknown_element()); - } - - return {}; - }); -} - -DecoderErrorOr> Reader::parse_track_entry() -{ - auto track_entry = make(); - TRY(parse_master_element("Track"sv, [&](u64 element_id) -> DecoderErrorOr { - switch (element_id) { - case TRACK_NUMBER_ID: - track_entry->set_track_number(TRY_READ(m_streamer.read_u64())); - dbgln_if(MATROSKA_TRACE_DEBUG, "Read TrackNumber attribute: {}", track_entry->track_number()); - break; - case TRACK_UID_ID: - track_entry->set_track_uid(TRY_READ(m_streamer.read_u64())); - dbgln_if(MATROSKA_TRACE_DEBUG, "Read TrackUID attribute: {}", track_entry->track_uid()); - break; - case TRACK_TYPE_ID: - track_entry->set_track_type(static_cast(TRY_READ(m_streamer.read_u64()))); - dbgln_if(MATROSKA_TRACE_DEBUG, "Read TrackType attribute: {}", track_entry->track_type()); - break; - case TRACK_LANGUAGE_ID: - track_entry->set_language(TRY_READ(m_streamer.read_string())); - dbgln_if(MATROSKA_TRACE_DEBUG, "Read Track's Language attribute: {}", track_entry->language()); - break; - case TRACK_CODEC_ID: - track_entry->set_codec_id(TRY_READ(m_streamer.read_string())); - dbgln_if(MATROSKA_TRACE_DEBUG, "Read Track's CodecID attribute: {}", track_entry->codec_id()); - break; - case TRACK_VIDEO_ID: - track_entry->set_video_track(TRY(parse_video_track_information())); - break; - case TRACK_AUDIO_ID: - track_entry->set_audio_track(TRY(parse_audio_track_information())); - break; - default: - TRY_READ(m_streamer.read_unknown_element()); - } - - return {}; - })); - - return track_entry; -} - -DecoderErrorOr Reader::parse_video_color_information() +static DecoderErrorOr parse_video_color_information(Streamer& streamer) { TrackEntry::ColorFormat color_format {}; - TRY(parse_master_element("Colour"sv, [&](u64 element_id) -> DecoderErrorOr { + TRY(parse_master_element(streamer, "Colour"sv, [&](u64 element_id) -> DecoderErrorOr { switch (element_id) { case PRIMARIES_ID: - color_format.color_primaries = static_cast(TRY_READ(m_streamer.read_u64())); + color_format.color_primaries = static_cast(TRY_READ(streamer.read_u64())); dbgln_if(MATROSKA_TRACE_DEBUG, "Read Colour's Primaries attribute: {}", color_primaries_to_string(color_format.color_primaries)); break; case TRANSFER_CHARACTERISTICS_ID: - color_format.transfer_characteristics = static_cast(TRY_READ(m_streamer.read_u64())); + color_format.transfer_characteristics = static_cast(TRY_READ(streamer.read_u64())); dbgln_if(MATROSKA_TRACE_DEBUG, "Read Colour's TransferCharacteristics attribute: {}", transfer_characteristics_to_string(color_format.transfer_characteristics)); break; case MATRIX_COEFFICIENTS_ID: - color_format.matrix_coefficients = static_cast(TRY_READ(m_streamer.read_u64())); + color_format.matrix_coefficients = static_cast(TRY_READ(streamer.read_u64())); dbgln_if(MATROSKA_TRACE_DEBUG, "Read Colour's MatrixCoefficients attribute: {}", matrix_coefficients_to_string(color_format.matrix_coefficients)); break; case BITS_PER_CHANNEL_ID: - color_format.bits_per_channel = TRY_READ(m_streamer.read_u64()); + color_format.bits_per_channel = TRY_READ(streamer.read_u64()); dbgln_if(MATROSKA_TRACE_DEBUG, "Read Colour's BitsPerChannel attribute: {}", color_format.bits_per_channel); break; default: - TRY_READ(m_streamer.read_unknown_element()); + TRY_READ(streamer.read_unknown_element()); } return {}; @@ -271,25 +217,25 @@ DecoderErrorOr Reader::parse_video_color_information() return color_format; } -DecoderErrorOr Reader::parse_video_track_information() +static DecoderErrorOr parse_video_track_information(Streamer& streamer) { TrackEntry::VideoTrack video_track {}; - TRY(parse_master_element("VideoTrack"sv, [&](u64 element_id) -> DecoderErrorOr { + TRY(parse_master_element(streamer, "VideoTrack"sv, [&](u64 element_id) -> DecoderErrorOr { switch (element_id) { case PIXEL_WIDTH_ID: - video_track.pixel_width = TRY_READ(m_streamer.read_u64()); + video_track.pixel_width = TRY_READ(streamer.read_u64()); dbgln_if(MATROSKA_TRACE_DEBUG, "Read VideoTrack's PixelWidth attribute: {}", video_track.pixel_width); break; case PIXEL_HEIGHT_ID: - video_track.pixel_height = TRY_READ(m_streamer.read_u64()); + video_track.pixel_height = TRY_READ(streamer.read_u64()); dbgln_if(MATROSKA_TRACE_DEBUG, "Read VideoTrack's PixelHeight attribute: {}", video_track.pixel_height); break; case COLOR_ENTRY_ID: - video_track.color_format = TRY(parse_video_color_information()); + video_track.color_format = TRY(parse_video_color_information(streamer)); break; default: - TRY_READ(m_streamer.read_unknown_element()); + TRY_READ(streamer.read_unknown_element()); } return {}; @@ -298,22 +244,22 @@ DecoderErrorOr Reader::parse_video_track_information() return video_track; } -DecoderErrorOr Reader::parse_audio_track_information() +static DecoderErrorOr parse_audio_track_information(Streamer& streamer) { TrackEntry::AudioTrack audio_track {}; - TRY(parse_master_element("AudioTrack"sv, [&](u64 element_id) -> DecoderErrorOr { + TRY(parse_master_element(streamer, "AudioTrack"sv, [&](u64 element_id) -> DecoderErrorOr { switch (element_id) { case CHANNELS_ID: - audio_track.channels = TRY_READ(m_streamer.read_u64()); + audio_track.channels = TRY_READ(streamer.read_u64()); dbgln_if(MATROSKA_TRACE_DEBUG, "Read AudioTrack's Channels attribute: {}", audio_track.channels); break; case BIT_DEPTH_ID: - audio_track.bit_depth = TRY_READ(m_streamer.read_u64()); + audio_track.bit_depth = TRY_READ(streamer.read_u64()); dbgln_if(MATROSKA_TRACE_DEBUG, "Read AudioTrack's BitDepth attribute: {}", audio_track.bit_depth); break; default: - TRY_READ(m_streamer.read_unknown_element()); + TRY_READ(streamer.read_unknown_element()); } return {}; @@ -322,20 +268,80 @@ DecoderErrorOr Reader::parse_audio_track_information() return audio_track; } -DecoderErrorOr> Reader::parse_cluster() +static DecoderErrorOr> parse_track_entry(Streamer& streamer) +{ + auto track_entry = make(); + TRY(parse_master_element(streamer, "Track"sv, [&](u64 element_id) -> DecoderErrorOr { + switch (element_id) { + case TRACK_NUMBER_ID: + track_entry->set_track_number(TRY_READ(streamer.read_u64())); + dbgln_if(MATROSKA_TRACE_DEBUG, "Read TrackNumber attribute: {}", track_entry->track_number()); + break; + case TRACK_UID_ID: + track_entry->set_track_uid(TRY_READ(streamer.read_u64())); + dbgln_if(MATROSKA_TRACE_DEBUG, "Read TrackUID attribute: {}", track_entry->track_uid()); + break; + case TRACK_TYPE_ID: + track_entry->set_track_type(static_cast(TRY_READ(streamer.read_u64()))); + dbgln_if(MATROSKA_TRACE_DEBUG, "Read TrackType attribute: {}", track_entry->track_type()); + break; + case TRACK_LANGUAGE_ID: + track_entry->set_language(TRY_READ(streamer.read_string())); + dbgln_if(MATROSKA_TRACE_DEBUG, "Read Track's Language attribute: {}", track_entry->language()); + break; + case TRACK_CODEC_ID: + track_entry->set_codec_id(TRY_READ(streamer.read_string())); + dbgln_if(MATROSKA_TRACE_DEBUG, "Read Track's CodecID attribute: {}", track_entry->codec_id()); + break; + case TRACK_VIDEO_ID: + track_entry->set_video_track(TRY(parse_video_track_information(streamer))); + break; + case TRACK_AUDIO_ID: + track_entry->set_audio_track(TRY(parse_audio_track_information(streamer))); + break; + default: + TRY_READ(streamer.read_unknown_element()); + } + + return {}; + })); + + return track_entry; +} + +static DecoderErrorOr parse_tracks(Streamer& streamer, MatroskaDocument& matroska_document) +{ + return parse_master_element(streamer, "Tracks"sv, [&](u64 element_id) -> DecoderErrorOr { + if (element_id == TRACK_ENTRY_ID) { + dbgln_if(MATROSKA_DEBUG, "Parsing track"); + auto track_entry = TRY(parse_track_entry(streamer)); + auto track_number = track_entry->track_number(); + dbgln_if(MATROSKA_DEBUG, "Adding track {} to document", track_number); + matroska_document.add_track(track_number, track_entry.release_nonnull()); + } else { + TRY_READ(streamer.read_unknown_element()); + } + + return {}; + }); +} + +static DecoderErrorOr> parse_simple_block(Streamer& streamer); + +static DecoderErrorOr> parse_cluster(Streamer& streamer) { auto cluster = make(); - TRY(parse_master_element("Cluster"sv, [&](u64 element_id) -> DecoderErrorOr { + TRY(parse_master_element(streamer, "Cluster"sv, [&](u64 element_id) -> DecoderErrorOr { switch (element_id) { case SIMPLE_BLOCK_ID: - cluster->blocks().append(TRY(parse_simple_block())); + cluster->blocks().append(TRY(parse_simple_block(streamer))); break; case TIMESTAMP_ID: - cluster->set_timestamp(TRY_READ(m_streamer.read_u64())); + cluster->set_timestamp(TRY_READ(streamer.read_u64())); break; default: - TRY_READ(m_streamer.read_unknown_element()); + TRY_READ(streamer.read_unknown_element()); } return {}; @@ -344,40 +350,40 @@ DecoderErrorOr> Reader::parse_cluster() return cluster; } -DecoderErrorOr> Reader::parse_simple_block() +static DecoderErrorOr> parse_simple_block(Streamer& streamer) { auto block = make(); - auto content_size = TRY_READ(m_streamer.read_variable_size_integer()); + auto content_size = TRY_READ(streamer.read_variable_size_integer()); - auto octets_read_before_track_number = m_streamer.octets_read(); - auto track_number = TRY_READ(m_streamer.read_variable_size_integer()); + auto octets_read_before_track_number = streamer.octets_read(); + auto track_number = TRY_READ(streamer.read_variable_size_integer()); block->set_track_number(track_number); - block->set_timestamp(TRY_READ(m_streamer.read_i16())); + block->set_timestamp(TRY_READ(streamer.read_i16())); - auto flags = TRY_READ(m_streamer.read_octet()); - block->set_only_keyframes(flags & (1u << 7u)); - block->set_invisible(flags & (1u << 3u)); + auto flags = TRY_READ(streamer.read_octet()); + block->set_only_keyframes((flags & (1u << 7u)) != 0); + block->set_invisible((flags & (1u << 3u)) != 0); block->set_lacing(static_cast((flags & 0b110u) >> 1u)); - block->set_discardable(flags & 1u); + block->set_discardable((flags & 1u) != 0); - auto total_frame_content_size = content_size - (m_streamer.octets_read() - octets_read_before_track_number); + auto total_frame_content_size = content_size - (streamer.octets_read() - octets_read_before_track_number); if (block->lacing() == Block::Lacing::EBML) { - auto octets_read_before_frame_sizes = m_streamer.octets_read(); - auto frame_count = TRY_READ(m_streamer.read_octet()) + 1; + auto octets_read_before_frame_sizes = streamer.octets_read(); + auto frame_count = TRY_READ(streamer.read_octet()) + 1; Vector frame_sizes; frame_sizes.ensure_capacity(frame_count); u64 frame_size_sum = 0; u64 previous_frame_size; - auto first_frame_size = TRY_READ(m_streamer.read_variable_size_integer()); + auto first_frame_size = TRY_READ(streamer.read_variable_size_integer()); frame_sizes.append(first_frame_size); frame_size_sum += first_frame_size; previous_frame_size = first_frame_size; for (int i = 0; i < frame_count - 2; i++) { - auto frame_size_difference = TRY_READ(m_streamer.read_variable_size_signed_integer()); + auto frame_size_difference = TRY_READ(streamer.read_variable_size_signed_integer()); u64 frame_size; // FIXME: x - (-y) == x + y?? if (frame_size_difference < 0) @@ -388,29 +394,29 @@ DecoderErrorOr> Reader::parse_simple_block() frame_size_sum += frame_size; previous_frame_size = frame_size; } - frame_sizes.append(total_frame_content_size - frame_size_sum - (m_streamer.octets_read() - octets_read_before_frame_sizes)); + frame_sizes.append(total_frame_content_size - frame_size_sum - (streamer.octets_read() - octets_read_before_frame_sizes)); for (int i = 0; i < frame_count; i++) { // FIXME: ReadonlyBytes instead of copying the frame data? auto current_frame_size = frame_sizes.at(i); - block->add_frame(DECODER_TRY_ALLOC(ByteBuffer::copy(m_streamer.data(), current_frame_size))); - TRY_READ(m_streamer.drop_octets(current_frame_size)); + block->add_frame(DECODER_TRY_ALLOC(ByteBuffer::copy(streamer.data(), current_frame_size))); + TRY_READ(streamer.drop_octets(current_frame_size)); } } else if (block->lacing() == Block::Lacing::FixedSize) { - auto frame_count = TRY_READ(m_streamer.read_octet()) + 1; + auto frame_count = TRY_READ(streamer.read_octet()) + 1; auto individual_frame_size = total_frame_content_size / frame_count; for (int i = 0; i < frame_count; i++) { - block->add_frame(DECODER_TRY_ALLOC(ByteBuffer::copy(m_streamer.data(), individual_frame_size))); - TRY_READ(m_streamer.drop_octets(individual_frame_size)); + block->add_frame(DECODER_TRY_ALLOC(ByteBuffer::copy(streamer.data(), individual_frame_size))); + TRY_READ(streamer.drop_octets(individual_frame_size)); } } else { - block->add_frame(DECODER_TRY_ALLOC(ByteBuffer::copy(m_streamer.data(), total_frame_content_size))); - TRY_READ(m_streamer.drop_octets(total_frame_content_size)); + block->add_frame(DECODER_TRY_ALLOC(ByteBuffer::copy(streamer.data(), total_frame_content_size))); + TRY_READ(streamer.drop_octets(total_frame_content_size)); } return block; } -ErrorOr Reader::Streamer::read_string() +ErrorOr Streamer::read_string() { auto string_length = TRY(read_variable_size_integer()); if (remaining() < string_length) @@ -420,7 +426,7 @@ ErrorOr Reader::Streamer::read_string() return string_value; } -ErrorOr Reader::Streamer::read_octet() +ErrorOr Streamer::read_octet() { if (!has_octet()) { dbgln_if(MATROSKA_TRACE_DEBUG, "Ran out of stream data"); @@ -432,12 +438,12 @@ ErrorOr Reader::Streamer::read_octet() return byte; } -ErrorOr Reader::Streamer::read_i16() +ErrorOr Streamer::read_i16() { return (TRY(read_octet()) << 8) | TRY(read_octet()); } -ErrorOr Reader::Streamer::read_variable_size_integer(bool mask_length) +ErrorOr Streamer::read_variable_size_integer(bool mask_length) { dbgln_if(MATROSKA_TRACE_DEBUG, "Reading from offset {:p}", data()); auto length_descriptor = TRY(read_octet()); @@ -469,7 +475,7 @@ ErrorOr Reader::Streamer::read_variable_size_integer(bool mask_length) return result; } -ErrorOr Reader::Streamer::read_variable_size_signed_integer() +ErrorOr Streamer::read_variable_size_signed_integer() { auto length_descriptor = TRY(read_octet()); if (length_descriptor == 0) @@ -492,7 +498,7 @@ ErrorOr Reader::Streamer::read_variable_size_signed_integer() return result; } -ErrorOr Reader::Streamer::drop_octets(size_t num_octets) +ErrorOr Streamer::drop_octets(size_t num_octets) { if (remaining() < num_octets) return Error::from_string_literal("Tried to drop octets past the end of the stream"); @@ -501,7 +507,7 @@ ErrorOr Reader::Streamer::drop_octets(size_t num_octets) return {}; } -ErrorOr Reader::Streamer::read_u64() +ErrorOr Streamer::read_u64() { auto integer_length = TRY(read_variable_size_integer()); u64 result = 0; @@ -511,7 +517,7 @@ ErrorOr Reader::Streamer::read_u64() return result; } -ErrorOr Reader::Streamer::read_float() +ErrorOr Streamer::read_float() { auto length = TRY(read_variable_size_integer()); if (length != 4u && length != 8u) @@ -531,7 +537,7 @@ ErrorOr Reader::Streamer::read_float() return read_data.double_value; } -ErrorOr Reader::Streamer::read_unknown_element() +ErrorOr Streamer::read_unknown_element() { auto element_length = TRY(read_variable_size_integer()); return drop_octets(element_length); diff --git a/Userland/Libraries/LibVideo/Containers/Matroska/Reader.h b/Userland/Libraries/LibVideo/Containers/Matroska/Reader.h index 50ed4ea1e8..8cc48d659e 100644 --- a/Userland/Libraries/LibVideo/Containers/Matroska/Reader.h +++ b/Userland/Libraries/LibVideo/Containers/Matroska/Reader.h @@ -18,6 +18,55 @@ namespace Video::Matroska { +class Streamer { +public: + Streamer(ReadonlyBytes data) + : m_data(data) + { + } + + u8 const* data() { return m_data.data() + m_position; } + + char const* data_as_chars() { return reinterpret_cast(data()); } + + size_t octets_read() { return m_octets_read.last(); } + + void push_octets_read() { m_octets_read.append(0); } + + void pop_octets_read() + { + auto popped = m_octets_read.take_last(); + if (!m_octets_read.is_empty()) + m_octets_read.last() += popped; + } + + ErrorOr read_octet(); + + ErrorOr read_i16(); + + ErrorOr read_variable_size_integer(bool mask_length = true); + ErrorOr read_variable_size_signed_integer(); + + ErrorOr read_u64(); + ErrorOr read_float(); + + ErrorOr read_string(); + + ErrorOr read_unknown_element(); + + ErrorOr drop_octets(size_t num_octets); + + bool at_end() const { return remaining() == 0; } + bool has_octet() const { return remaining() >= 1; } + + size_t remaining() const { return m_data.size() - m_position; } + +private: + ReadonlyBytes m_data; + size_t m_position { 0 }; + Vector m_octets_read { 0 }; +}; + class Reader { public: Reader(ReadonlyBytes data) @@ -31,69 +80,6 @@ public: DecoderErrorOr> parse(); private: - class Streamer { - public: - Streamer(ReadonlyBytes data) - : m_data(data) - { - } - - u8 const* data() { return m_data.data() + m_position; } - - char const* data_as_chars() { return reinterpret_cast(data()); } - - size_t octets_read() { return m_octets_read.last(); } - - void push_octets_read() { m_octets_read.append(0); } - - void pop_octets_read() - { - auto popped = m_octets_read.take_last(); - if (!m_octets_read.is_empty()) - m_octets_read.last() += popped; - } - - ErrorOr read_octet(); - - ErrorOr read_i16(); - - ErrorOr read_variable_size_integer(bool mask_length = true); - ErrorOr read_variable_size_signed_integer(); - - ErrorOr read_u64(); - ErrorOr read_float(); - - ErrorOr read_string(); - - ErrorOr read_unknown_element(); - - ErrorOr drop_octets(size_t num_octets); - - bool at_end() const { return remaining() == 0; } - bool has_octet() const { return remaining() >= 1; } - - size_t remaining() const { return m_data.size() - m_position; } - - private: - ReadonlyBytes m_data; - size_t m_position { 0 }; - Vector m_octets_read { 0 }; - }; - - DecoderErrorOr parse_master_element(StringView element_name, Function(u64 element_id)> element_consumer); - DecoderErrorOr parse_ebml_header(); - - DecoderErrorOr parse_segment_elements(MatroskaDocument&); - DecoderErrorOr> parse_information(); - - DecoderErrorOr parse_tracks(MatroskaDocument&); - DecoderErrorOr> parse_track_entry(); - DecoderErrorOr parse_video_track_information(); - DecoderErrorOr parse_video_color_information(); - DecoderErrorOr parse_audio_track_information(); - DecoderErrorOr> parse_cluster(); - DecoderErrorOr> parse_simple_block(); - Streamer m_streamer; };