Serenity Operating System
at master 1079 lines 45 kB view raw
1/* 2 * Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com> 3 * Copyright (c) 2022, Gregory Bertilson <Zaggy1024@gmail.com> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <AK/Debug.h> 9#include <AK/Function.h> 10#include <AK/Optional.h> 11#include <AK/Time.h> 12#include <AK/Utf8View.h> 13#include <LibCore/MappedFile.h> 14 15#include "Reader.h" 16 17namespace Video::Matroska { 18 19#define TRY_READ(expression) DECODER_TRY(DecoderErrorCategory::Corrupted, expression) 20 21// Elements IDs and types are listed at this URL: 22// https://www.matroska.org/technical/elements.html 23constexpr u32 EBML_MASTER_ELEMENT_ID = 0x1A45DFA3; 24constexpr u32 SEGMENT_ELEMENT_ID = 0x18538067; 25constexpr u32 DOCTYPE_ELEMENT_ID = 0x4282; 26constexpr u32 DOCTYPE_VERSION_ELEMENT_ID = 0x4287; 27 28constexpr u32 SEEK_HEAD_ELEMENT_ID = 0x114D9B74; 29constexpr u32 SEEK_ELEMENT_ID = 0x4DBB; 30constexpr u32 SEEK_ID_ELEMENT_ID = 0x53AB; 31constexpr u32 SEEK_POSITION_ELEMENT_ID = 0x53AC; 32 33constexpr u32 SEGMENT_INFORMATION_ELEMENT_ID = 0x1549A966; 34constexpr u32 TRACK_ELEMENT_ID = 0x1654AE6B; 35constexpr u32 CLUSTER_ELEMENT_ID = 0x1F43B675; 36constexpr u32 TIMESTAMP_SCALE_ID = 0x2AD7B1; 37constexpr u32 MUXING_APP_ID = 0x4D80; 38constexpr u32 WRITING_APP_ID = 0x5741; 39constexpr u32 DURATION_ID = 0x4489; 40 41// Tracks 42constexpr u32 TRACK_ENTRY_ID = 0xAE; 43constexpr u32 TRACK_NUMBER_ID = 0xD7; 44constexpr u32 TRACK_UID_ID = 0x73C5; 45constexpr u32 TRACK_TYPE_ID = 0x83; 46constexpr u32 TRACK_LANGUAGE_ID = 0x22B59C; 47constexpr u32 TRACK_CODEC_ID = 0x86; 48constexpr u32 TRACK_TIMESTAMP_SCALE_ID = 0x23314F; 49constexpr u32 TRACK_OFFSET_ID = 0x537F; 50constexpr u32 TRACK_VIDEO_ID = 0xE0; 51constexpr u32 TRACK_AUDIO_ID = 0xE1; 52 53// Video 54constexpr u32 PIXEL_WIDTH_ID = 0xB0; 55constexpr u32 PIXEL_HEIGHT_ID = 0xBA; 56constexpr u32 COLOR_ENTRY_ID = 0x55B0; 57constexpr u32 PRIMARIES_ID = 0x55BB; 58constexpr u32 TRANSFER_CHARACTERISTICS_ID = 0x55BA; 59constexpr u32 MATRIX_COEFFICIENTS_ID = 0x55B1; 60constexpr u32 BITS_PER_CHANNEL_ID = 0x55B2; 61 62// Audio 63constexpr u32 CHANNELS_ID = 0x9F; 64constexpr u32 BIT_DEPTH_ID = 0x6264; 65 66// Clusters 67constexpr u32 SIMPLE_BLOCK_ID = 0xA3; 68constexpr u32 TIMESTAMP_ID = 0xE7; 69 70// Cues 71constexpr u32 CUES_ID = 0x1C53BB6B; 72constexpr u32 CUE_POINT_ID = 0xBB; 73constexpr u32 CUE_TIME_ID = 0xB3; 74constexpr u32 CUE_TRACK_POSITIONS_ID = 0xB7; 75constexpr u32 CUE_TRACK_ID = 0xF7; 76constexpr u32 CUE_CLUSTER_POSITION_ID = 0xF1; 77constexpr u32 CUE_RELATIVE_POSITION_ID = 0xF0; 78constexpr u32 CUE_CODEC_STATE_ID = 0xEA; 79constexpr u32 CUE_REFERENCE_ID = 0xDB; 80 81DecoderErrorOr<Reader> Reader::from_file(StringView path) 82{ 83 auto mapped_file = DECODER_TRY(DecoderErrorCategory::IO, Core::MappedFile::map(path)); 84 auto reader = TRY(from_data(mapped_file->bytes())); 85 reader.m_mapped_file = mapped_file; 86 return reader; 87} 88 89DecoderErrorOr<Reader> Reader::from_data(ReadonlyBytes data) 90{ 91 Reader reader(data); 92 TRY(reader.parse_initial_data()); 93 return reader; 94} 95 96static DecoderErrorOr<void> parse_master_element(Streamer& streamer, [[maybe_unused]] StringView element_name, Function<DecoderErrorOr<IterationDecision>(u64, size_t)> element_consumer) 97{ 98 auto element_data_size = TRY_READ(streamer.read_variable_size_integer()); 99 dbgln_if(MATROSKA_DEBUG, "{} has {} octets of data.", element_name, element_data_size); 100 101 streamer.push_octets_read(); 102 while (streamer.octets_read() < element_data_size) { 103 dbgln_if(MATROSKA_TRACE_DEBUG, "====== Reading element ======"); 104 auto element_id = TRY_READ(streamer.read_variable_size_integer(false)); 105 auto element_position = streamer.position(); 106 dbgln_if(MATROSKA_TRACE_DEBUG, "{:s} element ID is {:#010x}", element_name, element_id); 107 108 auto result = element_consumer(element_id, element_position); 109 if (result.is_error()) 110 return DecoderError::format(result.error().category(), "{} -> {}", element_name, result.error().description()); 111 if (result.release_value() == IterationDecision::Break) 112 break; 113 114 dbgln_if(MATROSKA_TRACE_DEBUG, "Read {} octets of the {} so far.", streamer.octets_read(), element_name); 115 } 116 streamer.pop_octets_read(); 117 118 return {}; 119} 120 121static DecoderErrorOr<EBMLHeader> parse_ebml_header(Streamer& streamer) 122{ 123 EBMLHeader header; 124 TRY(parse_master_element(streamer, "Header"sv, [&](u64 element_id, size_t) -> DecoderErrorOr<IterationDecision> { 125 switch (element_id) { 126 case DOCTYPE_ELEMENT_ID: 127 header.doc_type = TRY_READ(streamer.read_string()); 128 dbgln_if(MATROSKA_DEBUG, "Read DocType attribute: {}", header.doc_type); 129 break; 130 case DOCTYPE_VERSION_ELEMENT_ID: 131 header.doc_type_version = TRY_READ(streamer.read_u64()); 132 dbgln_if(MATROSKA_DEBUG, "Read DocTypeVersion attribute: {}", header.doc_type_version); 133 break; 134 default: 135 TRY_READ(streamer.read_unknown_element()); 136 } 137 138 return IterationDecision::Continue; 139 })); 140 141 return header; 142} 143 144DecoderErrorOr<void> Reader::parse_initial_data() 145{ 146 Streamer streamer { m_data }; 147 auto first_element_id = TRY_READ(streamer.read_variable_size_integer(false)); 148 dbgln_if(MATROSKA_TRACE_DEBUG, "First element ID is {:#010x}\n", first_element_id); 149 if (first_element_id != EBML_MASTER_ELEMENT_ID) 150 return DecoderError::corrupted("First element was not an EBML header"sv); 151 152 m_header = TRY(parse_ebml_header(streamer)); 153 dbgln_if(MATROSKA_DEBUG, "Parsed EBML header"); 154 155 auto root_element_id = TRY_READ(streamer.read_variable_size_integer(false)); 156 if (root_element_id != SEGMENT_ELEMENT_ID) 157 return DecoderError::corrupted("Second element was not a segment element"sv); 158 159 m_segment_contents_size = TRY_READ(streamer.read_variable_size_integer()); 160 m_segment_contents_position = streamer.position(); 161 dbgln_if(true, "Segment is at {} with size {}, available size is {}", m_segment_contents_position, m_segment_contents_size, m_data.size() - m_segment_contents_position); 162 m_segment_contents_size = min(m_segment_contents_size, m_data.size() - m_segment_contents_position); 163 return {}; 164} 165 166static DecoderErrorOr<void> parse_seek_head(Streamer& streamer, size_t base_position, HashMap<u32, size_t>& table) 167{ 168 return parse_master_element(streamer, "SeekHead"sv, [&](u64 seek_head_child_id, size_t) -> DecoderErrorOr<IterationDecision> { 169 if (seek_head_child_id == SEEK_ELEMENT_ID) { 170 Optional<u64> seek_id; 171 Optional<u64> seek_position; 172 TRY(parse_master_element(streamer, "Seek"sv, [&](u64 seek_entry_child_id, size_t) -> DecoderErrorOr<IterationDecision> { 173 switch (seek_entry_child_id) { 174 case SEEK_ID_ELEMENT_ID: 175 seek_id = TRY_READ(streamer.read_u64()); 176 dbgln_if(MATROSKA_TRACE_DEBUG, "Read Seek Element ID value {:#010x}", seek_id.value()); 177 break; 178 case SEEK_POSITION_ELEMENT_ID: 179 seek_position = TRY_READ(streamer.read_u64()); 180 dbgln_if(MATROSKA_TRACE_DEBUG, "Read Seek Position value {}", seek_position.value()); 181 break; 182 default: 183 TRY_READ(streamer.read_unknown_element()); 184 } 185 186 return IterationDecision::Continue; 187 })); 188 189 if (!seek_id.has_value()) 190 return DecoderError::corrupted("Seek entry is missing the element ID"sv); 191 if (!seek_position.has_value()) 192 return DecoderError::corrupted("Seek entry is missing the seeking position"sv); 193 if (seek_id.value() > NumericLimits<u32>::max()) 194 return DecoderError::corrupted("Seek entry's element ID is too large"sv); 195 196 dbgln_if(MATROSKA_TRACE_DEBUG, "Seek entry found with ID {:#010x} and position {} offset from SeekHead at {}", seek_id.value(), seek_position.value(), base_position); 197 // FIXME: SeekHead can reference another SeekHead, we should recursively parse all SeekHeads. 198 199 if (table.contains(seek_id.value())) { 200 dbgln_if(MATROSKA_DEBUG, "Warning: Duplicate seek entry with ID {:#010x} at position {}", seek_id.value(), seek_position.value()); 201 return IterationDecision::Continue; 202 } 203 204 DECODER_TRY_ALLOC(table.try_set(seek_id.release_value(), base_position + seek_position.release_value())); 205 } else { 206 dbgln_if(MATROSKA_TRACE_DEBUG, "Unknown SeekHead child element ID {:#010x}", seek_head_child_id); 207 } 208 209 return IterationDecision::Continue; 210 }); 211} 212 213DecoderErrorOr<Optional<size_t>> Reader::find_first_top_level_element_with_id([[maybe_unused]] StringView element_name, u32 element_id) 214{ 215 dbgln_if(MATROSKA_DEBUG, "====== Finding element {} with ID {:#010x} ======", element_name, element_id); 216 217 if (m_seek_entries.contains(element_id)) { 218 dbgln_if(MATROSKA_TRACE_DEBUG, "Cache hit!"); 219 return m_seek_entries.get(element_id).release_value(); 220 } 221 222 Streamer streamer { m_data }; 223 if (m_last_top_level_element_position != 0) 224 TRY_READ(streamer.seek_to_position(m_last_top_level_element_position)); 225 else 226 TRY_READ(streamer.seek_to_position(m_segment_contents_position)); 227 228 Optional<size_t> position; 229 230 while (streamer.position() < m_segment_contents_position + m_segment_contents_size) { 231 auto found_element_id = TRY_READ(streamer.read_variable_size_integer(false)); 232 auto found_element_position = streamer.position(); 233 dbgln_if(MATROSKA_TRACE_DEBUG, "Found element ID {:#010x} with position {}.", found_element_id, found_element_position); 234 235 if (found_element_id == SEEK_HEAD_ELEMENT_ID) { 236 dbgln_if(MATROSKA_TRACE_DEBUG, "Found SeekHead, parsing it into the lookup table."); 237 m_seek_entries.clear(); 238 TRY(parse_seek_head(streamer, found_element_position, m_seek_entries)); 239 m_last_top_level_element_position = 0; 240 if (m_seek_entries.contains(element_id)) { 241 dbgln_if(MATROSKA_TRACE_DEBUG, "SeekHead hit!"); 242 position = m_seek_entries.get(element_id).release_value(); 243 break; 244 } 245 continue; 246 } 247 248 auto result = streamer.read_unknown_element(); 249 if (result.is_error()) 250 return DecoderError::format(DecoderErrorCategory::Corrupted, "While seeking to {}: {}", element_name, result.release_error().string_literal()); 251 252 m_last_top_level_element_position = streamer.position(); 253 254 DECODER_TRY_ALLOC(m_seek_entries.try_set(found_element_id, found_element_position)); 255 256 if (found_element_id == element_id) { 257 position = found_element_position; 258 break; 259 } 260 261 dbgln_if(MATROSKA_TRACE_DEBUG, "Skipped to position {}.", m_last_top_level_element_position); 262 } 263 264 return position; 265} 266 267static DecoderErrorOr<SegmentInformation> parse_information(Streamer& streamer) 268{ 269 SegmentInformation segment_information; 270 TRY(parse_master_element(streamer, "Segment Information"sv, [&](u64 element_id, size_t) -> DecoderErrorOr<IterationDecision> { 271 switch (element_id) { 272 case TIMESTAMP_SCALE_ID: 273 segment_information.set_timestamp_scale(TRY_READ(streamer.read_u64())); 274 dbgln_if(MATROSKA_DEBUG, "Read TimestampScale attribute: {}", segment_information.timestamp_scale()); 275 break; 276 case MUXING_APP_ID: 277 segment_information.set_muxing_app(TRY_READ(streamer.read_string())); 278 dbgln_if(MATROSKA_DEBUG, "Read MuxingApp attribute: {}", segment_information.muxing_app().as_string()); 279 break; 280 case WRITING_APP_ID: 281 segment_information.set_writing_app(TRY_READ(streamer.read_string())); 282 dbgln_if(MATROSKA_DEBUG, "Read WritingApp attribute: {}", segment_information.writing_app().as_string()); 283 break; 284 case DURATION_ID: 285 segment_information.set_duration_unscaled(TRY_READ(streamer.read_float())); 286 dbgln_if(MATROSKA_DEBUG, "Read Duration attribute: {}", segment_information.duration_unscaled().value()); 287 break; 288 default: 289 TRY_READ(streamer.read_unknown_element()); 290 } 291 292 return IterationDecision::Continue; 293 })); 294 295 return segment_information; 296} 297 298DecoderErrorOr<SegmentInformation> Reader::segment_information() 299{ 300 if (m_segment_information.has_value()) 301 return m_segment_information.value(); 302 303 auto position = TRY(find_first_top_level_element_with_id("Segment Information"sv, SEGMENT_INFORMATION_ELEMENT_ID)); 304 if (!position.has_value()) 305 return DecoderError::corrupted("No Segment Information element found"sv); 306 Streamer streamer { m_data }; 307 TRY_READ(streamer.seek_to_position(position.release_value())); 308 m_segment_information = TRY(parse_information(streamer)); 309 return m_segment_information.value(); 310} 311 312DecoderErrorOr<void> Reader::ensure_tracks_are_parsed() 313{ 314 if (!m_tracks.is_empty()) 315 return {}; 316 auto position = TRY(find_first_top_level_element_with_id("Tracks"sv, TRACK_ELEMENT_ID)); 317 if (!position.has_value()) 318 return DecoderError::corrupted("No Tracks element found"sv); 319 Streamer streamer { m_data }; 320 TRY_READ(streamer.seek_to_position(position.release_value())); 321 TRY(parse_tracks(streamer)); 322 return {}; 323} 324 325static DecoderErrorOr<TrackEntry::ColorFormat> parse_video_color_information(Streamer& streamer) 326{ 327 TrackEntry::ColorFormat color_format {}; 328 329 TRY(parse_master_element(streamer, "Colour"sv, [&](u64 element_id, size_t) -> DecoderErrorOr<IterationDecision> { 330 switch (element_id) { 331 case PRIMARIES_ID: 332 color_format.color_primaries = static_cast<ColorPrimaries>(TRY_READ(streamer.read_u64())); 333 dbgln_if(MATROSKA_TRACE_DEBUG, "Read Colour's Primaries attribute: {}", color_primaries_to_string(color_format.color_primaries)); 334 break; 335 case TRANSFER_CHARACTERISTICS_ID: 336 color_format.transfer_characteristics = static_cast<TransferCharacteristics>(TRY_READ(streamer.read_u64())); 337 dbgln_if(MATROSKA_TRACE_DEBUG, "Read Colour's TransferCharacteristics attribute: {}", transfer_characteristics_to_string(color_format.transfer_characteristics)); 338 break; 339 case MATRIX_COEFFICIENTS_ID: 340 color_format.matrix_coefficients = static_cast<MatrixCoefficients>(TRY_READ(streamer.read_u64())); 341 dbgln_if(MATROSKA_TRACE_DEBUG, "Read Colour's MatrixCoefficients attribute: {}", matrix_coefficients_to_string(color_format.matrix_coefficients)); 342 break; 343 case BITS_PER_CHANNEL_ID: 344 color_format.bits_per_channel = TRY_READ(streamer.read_u64()); 345 dbgln_if(MATROSKA_TRACE_DEBUG, "Read Colour's BitsPerChannel attribute: {}", color_format.bits_per_channel); 346 break; 347 default: 348 TRY_READ(streamer.read_unknown_element()); 349 } 350 351 return IterationDecision::Continue; 352 })); 353 354 return color_format; 355} 356 357static DecoderErrorOr<TrackEntry::VideoTrack> parse_video_track_information(Streamer& streamer) 358{ 359 TrackEntry::VideoTrack video_track {}; 360 361 TRY(parse_master_element(streamer, "VideoTrack"sv, [&](u64 element_id, size_t) -> DecoderErrorOr<IterationDecision> { 362 switch (element_id) { 363 case PIXEL_WIDTH_ID: 364 video_track.pixel_width = TRY_READ(streamer.read_u64()); 365 dbgln_if(MATROSKA_TRACE_DEBUG, "Read VideoTrack's PixelWidth attribute: {}", video_track.pixel_width); 366 break; 367 case PIXEL_HEIGHT_ID: 368 video_track.pixel_height = TRY_READ(streamer.read_u64()); 369 dbgln_if(MATROSKA_TRACE_DEBUG, "Read VideoTrack's PixelHeight attribute: {}", video_track.pixel_height); 370 break; 371 case COLOR_ENTRY_ID: 372 video_track.color_format = TRY(parse_video_color_information(streamer)); 373 break; 374 default: 375 TRY_READ(streamer.read_unknown_element()); 376 } 377 378 return IterationDecision::Continue; 379 })); 380 381 return video_track; 382} 383 384static DecoderErrorOr<TrackEntry::AudioTrack> parse_audio_track_information(Streamer& streamer) 385{ 386 TrackEntry::AudioTrack audio_track {}; 387 388 TRY(parse_master_element(streamer, "AudioTrack"sv, [&](u64 element_id, size_t) -> DecoderErrorOr<IterationDecision> { 389 switch (element_id) { 390 case CHANNELS_ID: 391 audio_track.channels = TRY_READ(streamer.read_u64()); 392 dbgln_if(MATROSKA_TRACE_DEBUG, "Read AudioTrack's Channels attribute: {}", audio_track.channels); 393 break; 394 case BIT_DEPTH_ID: 395 audio_track.bit_depth = TRY_READ(streamer.read_u64()); 396 dbgln_if(MATROSKA_TRACE_DEBUG, "Read AudioTrack's BitDepth attribute: {}", audio_track.bit_depth); 397 break; 398 default: 399 TRY_READ(streamer.read_unknown_element()); 400 } 401 402 return IterationDecision::Continue; 403 })); 404 405 return audio_track; 406} 407 408static DecoderErrorOr<TrackEntry> parse_track_entry(Streamer& streamer) 409{ 410 TrackEntry track_entry; 411 TRY(parse_master_element(streamer, "Track"sv, [&](u64 element_id, size_t) -> DecoderErrorOr<IterationDecision> { 412 switch (element_id) { 413 case TRACK_NUMBER_ID: 414 track_entry.set_track_number(TRY_READ(streamer.read_u64())); 415 dbgln_if(MATROSKA_TRACE_DEBUG, "Read TrackNumber attribute: {}", track_entry.track_number()); 416 break; 417 case TRACK_UID_ID: 418 track_entry.set_track_uid(TRY_READ(streamer.read_u64())); 419 dbgln_if(MATROSKA_TRACE_DEBUG, "Read TrackUID attribute: {}", track_entry.track_uid()); 420 break; 421 case TRACK_TYPE_ID: 422 track_entry.set_track_type(static_cast<TrackEntry::TrackType>(TRY_READ(streamer.read_u64()))); 423 dbgln_if(MATROSKA_TRACE_DEBUG, "Read TrackType attribute: {}", to_underlying(track_entry.track_type())); 424 break; 425 case TRACK_LANGUAGE_ID: 426 track_entry.set_language(TRY_READ(streamer.read_string())); 427 dbgln_if(MATROSKA_TRACE_DEBUG, "Read Track's Language attribute: {}", track_entry.language()); 428 break; 429 case TRACK_CODEC_ID: 430 track_entry.set_codec_id(TRY_READ(streamer.read_string())); 431 dbgln_if(MATROSKA_TRACE_DEBUG, "Read Track's CodecID attribute: {}", track_entry.codec_id()); 432 break; 433 case TRACK_TIMESTAMP_SCALE_ID: 434 track_entry.set_timestamp_scale(TRY_READ(streamer.read_float())); 435 dbgln_if(MATROSKA_TRACE_DEBUG, "Read Track's TrackTimestampScale attribute: {}", track_entry.timestamp_scale()); 436 break; 437 case TRACK_OFFSET_ID: 438 track_entry.set_timestamp_offset(TRY_READ(streamer.read_variable_size_signed_integer())); 439 dbgln_if(MATROSKA_TRACE_DEBUG, "Read Track's TrackOffset attribute: {}", track_entry.timestamp_offset()); 440 break; 441 case TRACK_VIDEO_ID: 442 track_entry.set_video_track(TRY(parse_video_track_information(streamer))); 443 break; 444 case TRACK_AUDIO_ID: 445 track_entry.set_audio_track(TRY(parse_audio_track_information(streamer))); 446 break; 447 default: 448 TRY_READ(streamer.read_unknown_element()); 449 } 450 451 return IterationDecision::Continue; 452 })); 453 454 return track_entry; 455} 456 457DecoderErrorOr<void> Reader::parse_tracks(Streamer& streamer) 458{ 459 return parse_master_element(streamer, "Tracks"sv, [&](u64 element_id, size_t) -> DecoderErrorOr<IterationDecision> { 460 if (element_id == TRACK_ENTRY_ID) { 461 auto track_entry = TRY(parse_track_entry(streamer)); 462 dbgln_if(MATROSKA_DEBUG, "Parsed track {}", track_entry.track_number()); 463 DECODER_TRY_ALLOC(m_tracks.try_set(track_entry.track_number(), track_entry)); 464 } else { 465 TRY_READ(streamer.read_unknown_element()); 466 } 467 468 return IterationDecision::Continue; 469 }); 470} 471 472DecoderErrorOr<void> Reader::for_each_track(TrackEntryCallback callback) 473{ 474 TRY(ensure_tracks_are_parsed()); 475 for (auto const& track_entry : m_tracks) { 476 auto decision = TRY(callback(track_entry.value)); 477 if (decision == IterationDecision::Break) 478 break; 479 } 480 return {}; 481} 482 483DecoderErrorOr<void> Reader::for_each_track_of_type(TrackEntry::TrackType type, TrackEntryCallback callback) 484{ 485 return for_each_track([&](TrackEntry const& track_entry) -> DecoderErrorOr<IterationDecision> { 486 if (track_entry.track_type() != type) 487 return IterationDecision::Continue; 488 return callback(track_entry); 489 }); 490} 491 492DecoderErrorOr<TrackEntry> Reader::track_for_track_number(u64 track_number) 493{ 494 TRY(ensure_tracks_are_parsed()); 495 auto optional_track_entry = m_tracks.get(track_number); 496 if (!optional_track_entry.has_value()) 497 return DecoderError::format(DecoderErrorCategory::Invalid, "No track found with number {}", track_number); 498 return optional_track_entry.release_value(); 499} 500 501DecoderErrorOr<size_t> Reader::track_count() 502{ 503 TRY(ensure_tracks_are_parsed()); 504 return m_tracks.size(); 505} 506 507constexpr size_t get_element_id_size(u32 element_id) 508{ 509 return sizeof(element_id) - (count_leading_zeroes(element_id) / 8); 510} 511 512static DecoderErrorOr<Cluster> parse_cluster(Streamer& streamer, u64 timestamp_scale) 513{ 514 Optional<u64> timestamp; 515 size_t first_element_position = 0; 516 517 TRY(parse_master_element(streamer, "Cluster"sv, [&](u64 element_id, size_t position) -> DecoderErrorOr<IterationDecision> { 518 if (first_element_position == 0) 519 first_element_position = position - get_element_id_size(element_id); 520 521 switch (element_id) { 522 case TIMESTAMP_ID: 523 timestamp = TRY_READ(streamer.read_u64()); 524 return IterationDecision::Break; 525 default: 526 TRY_READ(streamer.read_unknown_element()); 527 } 528 529 return IterationDecision::Continue; 530 })); 531 532 if (!timestamp.has_value()) 533 return DecoderError::corrupted("Cluster was missing a timestamp"sv); 534 if (first_element_position == 0) 535 return DecoderError::corrupted("Cluster had no children"sv); 536 537 dbgln_if(MATROSKA_TRACE_DEBUG, "Seeking back to position {}", first_element_position); 538 TRY_READ(streamer.seek_to_position(first_element_position)); 539 540 Cluster cluster; 541 cluster.set_timestamp(Time::from_nanoseconds(timestamp.release_value() * timestamp_scale)); 542 return cluster; 543} 544 545static DecoderErrorOr<Block> parse_simple_block(Streamer& streamer, Time cluster_timestamp, u64 segment_timestamp_scale, TrackEntry track) 546{ 547 Block block; 548 549 auto content_size = TRY_READ(streamer.read_variable_size_integer()); 550 551 auto position_before_track_number = streamer.position(); 552 block.set_track_number(TRY_READ(streamer.read_variable_size_integer())); 553 554 // https://www.matroska.org/technical/notes.html 555 // Block Timestamps: 556 // The Block Element and SimpleBlock Element store their timestamps as signed integers, 557 // relative to the Cluster\Timestamp value of the Cluster they are stored in. To get the 558 // timestamp of a Block or SimpleBlock in nanoseconds you have to use the following formula: 559 // `( Cluster\Timestamp + ( block timestamp * TrackTimestampScale ) ) * TimestampScale` 560 // 561 // When a CodecDelay Element is set, its value MUST be subtracted from each Block timestamp 562 // of that track. To get the timestamp in nanoseconds of the first frame in a Block or 563 // SimpleBlock, the formula becomes: 564 // `( ( Cluster\Timestamp + ( block timestamp * TrackTimestampScale ) ) * TimestampScale ) - CodecDelay` 565 Time timestamp_offset = Time::from_nanoseconds(static_cast<i64>(static_cast<double>(TRY_READ(streamer.read_i16()) * segment_timestamp_scale) * track.timestamp_scale())); 566 timestamp_offset -= Time::from_nanoseconds(static_cast<i64>(track.codec_delay())); 567 // This is only mentioned in the elements specification under TrackOffset. 568 // https://www.matroska.org/technical/elements.html 569 timestamp_offset += Time::from_nanoseconds(static_cast<i64>(track.timestamp_offset())); 570 block.set_timestamp(cluster_timestamp + timestamp_offset); 571 572 auto flags = TRY_READ(streamer.read_octet()); 573 block.set_only_keyframes((flags & (1u << 7u)) != 0); 574 block.set_invisible((flags & (1u << 3u)) != 0); 575 block.set_lacing(static_cast<Block::Lacing>((flags & 0b110u) >> 1u)); 576 block.set_discardable((flags & 1u) != 0); 577 578 auto total_frame_content_size = content_size - (streamer.position() - position_before_track_number); 579 580 Vector<ReadonlyBytes> frames; 581 582 if (block.lacing() == Block::Lacing::EBML) { 583 auto octets_read_before_frame_sizes = streamer.octets_read(); 584 auto frame_count = TRY_READ(streamer.read_octet()) + 1; 585 Vector<u64> frame_sizes; 586 frame_sizes.ensure_capacity(frame_count); 587 588 u64 frame_size_sum = 0; 589 u64 previous_frame_size; 590 auto first_frame_size = TRY_READ(streamer.read_variable_size_integer()); 591 frame_sizes.append(first_frame_size); 592 frame_size_sum += first_frame_size; 593 previous_frame_size = first_frame_size; 594 595 for (int i = 0; i < frame_count - 2; i++) { 596 auto frame_size_difference = TRY_READ(streamer.read_variable_size_signed_integer()); 597 u64 frame_size; 598 // FIXME: x - (-y) == x + y? 599 if (frame_size_difference < 0) 600 frame_size = previous_frame_size - (-frame_size_difference); 601 else 602 frame_size = previous_frame_size + frame_size_difference; 603 frame_sizes.append(frame_size); 604 frame_size_sum += frame_size; 605 previous_frame_size = frame_size; 606 } 607 frame_sizes.append(total_frame_content_size - frame_size_sum - (streamer.octets_read() - octets_read_before_frame_sizes)); 608 609 for (int i = 0; i < frame_count; i++) { 610 // FIXME: ReadonlyBytes instead of copying the frame data? 611 auto current_frame_size = frame_sizes.at(i); 612 frames.append(TRY_READ(streamer.read_raw_octets(current_frame_size))); 613 } 614 } else if (block.lacing() == Block::Lacing::FixedSize) { 615 auto frame_count = TRY_READ(streamer.read_octet()) + 1; 616 auto individual_frame_size = total_frame_content_size / frame_count; 617 for (int i = 0; i < frame_count; i++) 618 frames.append(TRY_READ(streamer.read_raw_octets(individual_frame_size))); 619 } else { 620 frames.append(TRY_READ(streamer.read_raw_octets(total_frame_content_size))); 621 } 622 block.set_frames(move(frames)); 623 return block; 624} 625 626DecoderErrorOr<SampleIterator> Reader::create_sample_iterator(u64 track_number) 627{ 628 auto optional_position = TRY(find_first_top_level_element_with_id("Cluster"sv, CLUSTER_ELEMENT_ID)); 629 if (!optional_position.has_value()) 630 return DecoderError::corrupted("No clusters are present in the segment"sv); 631 ReadonlyBytes segment_view = m_data.slice(m_segment_contents_position, m_segment_contents_size); 632 633 // We need to have the element ID included so that the iterator knows where it is. 634 auto position = optional_position.value() - get_element_id_size(CLUSTER_ELEMENT_ID) - m_segment_contents_position; 635 636 dbgln_if(MATROSKA_DEBUG, "Creating sample iterator starting at {} relative to segment at {}", position, m_segment_contents_position); 637 return SampleIterator(this->m_mapped_file, segment_view, TRY(track_for_track_number(track_number)), TRY(segment_information()).timestamp_scale(), position); 638} 639 640static DecoderErrorOr<CueTrackPosition> parse_cue_track_position(Streamer& streamer) 641{ 642 CueTrackPosition track_position; 643 644 bool had_cluster_position = false; 645 646 TRY_READ(parse_master_element(streamer, "CueTrackPositions"sv, [&](u64 element_id, size_t) -> DecoderErrorOr<IterationDecision> { 647 switch (element_id) { 648 case CUE_TRACK_ID: 649 track_position.set_track_number(TRY_READ(streamer.read_u64())); 650 dbgln_if(MATROSKA_TRACE_DEBUG, "Read CueTrackPositions track number {}", track_position.track_number()); 651 break; 652 case CUE_CLUSTER_POSITION_ID: 653 track_position.set_cluster_position(TRY_READ(streamer.read_u64())); 654 dbgln_if(MATROSKA_TRACE_DEBUG, "Read CueTrackPositions cluster position {}", track_position.cluster_position()); 655 had_cluster_position = true; 656 break; 657 case CUE_RELATIVE_POSITION_ID: 658 track_position.set_block_offset(TRY_READ(streamer.read_u64())); 659 dbgln_if(MATROSKA_TRACE_DEBUG, "Read CueTrackPositions relative position {}", track_position.block_offset()); 660 break; 661 case CUE_CODEC_STATE_ID: 662 // Mandatory in spec, but not present in files? 0 means use TrackEntry's codec state. 663 // FIXME: Do something with this value. 664 dbgln_if(MATROSKA_DEBUG, "Found CodecState, skipping"); 665 TRY_READ(streamer.read_unknown_element()); 666 break; 667 case CUE_REFERENCE_ID: 668 return DecoderError::not_implemented(); 669 default: 670 TRY_READ(streamer.read_unknown_element()); 671 break; 672 } 673 674 return IterationDecision::Continue; 675 })); 676 677 if (track_position.track_number() == 0) 678 return DecoderError::corrupted("Track number was not present or 0"sv); 679 680 if (!had_cluster_position) 681 return DecoderError::corrupted("Cluster was missing the cluster position"sv); 682 683 return track_position; 684} 685 686static DecoderErrorOr<CuePoint> parse_cue_point(Streamer& streamer, u64 timestamp_scale) 687{ 688 CuePoint cue_point; 689 690 TRY(parse_master_element(streamer, "CuePoint"sv, [&](u64 element_id, size_t) -> DecoderErrorOr<IterationDecision> { 691 switch (element_id) { 692 case CUE_TIME_ID: { 693 // On https://www.matroska.org/technical/elements.html, spec says of the CueTime element: 694 // > Absolute timestamp of the seek point, expressed in Matroska Ticks -- ie in nanoseconds; see timestamp-ticks. 695 // Matroska Ticks are specified in https://www.matroska.org/technical/notes.html: 696 // > For such elements, the timestamp value is stored directly in nanoseconds. 697 // However, my test files appear to use Segment Ticks, which uses the segment's timestamp scale, and Mozilla's nestegg parser agrees: 698 // https://github.com/mozilla/nestegg/tree/ec6adfbbf979678e3058cc4695257366f39e290b/src/nestegg.c#L1941 699 // https://github.com/mozilla/nestegg/tree/ec6adfbbf979678e3058cc4695257366f39e290b/src/nestegg.c#L2411-L2416 700 // https://github.com/mozilla/nestegg/tree/ec6adfbbf979678e3058cc4695257366f39e290b/src/nestegg.c#L1383-L1392 701 // Other fields that specify Matroska Ticks may also use Segment Ticks instead, who knows :^( 702 auto timestamp = Time::from_nanoseconds(static_cast<i64>(TRY_READ(streamer.read_u64()) * timestamp_scale)); 703 cue_point.set_timestamp(timestamp); 704 dbgln_if(MATROSKA_DEBUG, "Read CuePoint timestamp {}ms", cue_point.timestamp().to_milliseconds()); 705 break; 706 } 707 case CUE_TRACK_POSITIONS_ID: { 708 auto track_position = TRY_READ(parse_cue_track_position(streamer)); 709 DECODER_TRY_ALLOC(cue_point.track_positions().try_set(track_position.track_number(), track_position)); 710 break; 711 } 712 default: 713 TRY_READ(streamer.read_unknown_element()); 714 break; 715 } 716 717 return IterationDecision::Continue; 718 })); 719 720 if (cue_point.timestamp().is_negative()) 721 return DecoderError::corrupted("CuePoint was missing a timestamp"sv); 722 723 if (cue_point.track_positions().is_empty()) 724 return DecoderError::corrupted("CuePoint was missing track positions"sv); 725 726 return cue_point; 727} 728 729DecoderErrorOr<void> Reader::parse_cues(Streamer& streamer) 730{ 731 m_cues.clear(); 732 733 TRY(parse_master_element(streamer, "Cues"sv, [&](u64 element_id, size_t) -> DecoderErrorOr<IterationDecision> { 734 switch (element_id) { 735 case CUE_POINT_ID: { 736 auto cue_point = TRY(parse_cue_point(streamer, TRY(segment_information()).timestamp_scale())); 737 738 // FIXME: Verify that these are already in order of timestamp. If they are not, return a corrupted error for now, 739 // but if it turns out that Matroska files with out-of-order cue points are valid, sort them instead. 740 741 for (auto track_position_entry : cue_point.track_positions()) { 742 if (!m_cues.contains(track_position_entry.key)) 743 DECODER_TRY_ALLOC(m_cues.try_set(track_position_entry.key, Vector<CuePoint>())); 744 Vector<CuePoint>& cue_points_for_track = m_cues.get(track_position_entry.key).release_value(); 745 cue_points_for_track.append(cue_point); 746 } 747 break; 748 } 749 default: 750 return DecoderError::format(DecoderErrorCategory::Corrupted, "Unknown Cues child ID {:#010x}", element_id); 751 } 752 753 return IterationDecision::Continue; 754 })); 755 756 return {}; 757} 758 759DecoderErrorOr<void> Reader::ensure_cues_are_parsed() 760{ 761 if (m_cues_have_been_parsed) 762 return {}; 763 auto position = TRY(find_first_top_level_element_with_id("Cues"sv, CUES_ID)); 764 if (!position.has_value()) 765 return DecoderError::corrupted("No Tracks element found"sv); 766 Streamer streamer { m_data }; 767 TRY_READ(streamer.seek_to_position(position.release_value())); 768 TRY(parse_cues(streamer)); 769 m_cues_have_been_parsed = true; 770 return {}; 771} 772 773DecoderErrorOr<void> Reader::seek_to_cue_for_timestamp(SampleIterator& iterator, Time const& timestamp) 774{ 775 auto const& cue_points = MUST(cue_points_for_track(iterator.m_track.track_number())).release_value(); 776 777 // Take a guess at where in the cues the timestamp will be and correct from there. 778 auto duration = TRY(segment_information()).duration(); 779 size_t index = 0; 780 if (duration.has_value()) 781 index = clamp(((timestamp.to_nanoseconds() * cue_points.size()) / TRY(segment_information()).duration()->to_nanoseconds()), 0, cue_points.size() - 1); 782 783 CuePoint const* prev_cue_point = &cue_points[index]; 784 dbgln_if(MATROSKA_DEBUG, "Finding Matroska cue points for timestamp {}ms starting from cue at {}ms", timestamp.to_milliseconds(), prev_cue_point->timestamp().to_milliseconds()); 785 786 if (prev_cue_point->timestamp() == timestamp) { 787 TRY(iterator.seek_to_cue_point(*prev_cue_point)); 788 return {}; 789 } 790 791 if (prev_cue_point->timestamp() > timestamp) { 792 while (index > 0 && prev_cue_point->timestamp() > timestamp) { 793 prev_cue_point = &cue_points[--index]; 794 dbgln_if(MATROSKA_DEBUG, "Checking previous cue point {}ms", prev_cue_point->timestamp().to_milliseconds()); 795 } 796 TRY(iterator.seek_to_cue_point(*prev_cue_point)); 797 return {}; 798 } 799 800 while (++index < cue_points.size()) { 801 auto const& cue_point = cue_points[index]; 802 dbgln_if(MATROSKA_DEBUG, "Checking future cue point {}ms", cue_point.timestamp().to_milliseconds()); 803 if (cue_point.timestamp() > timestamp) 804 break; 805 prev_cue_point = &cue_point; 806 } 807 808 TRY(iterator.seek_to_cue_point(*prev_cue_point)); 809 return {}; 810} 811 812static DecoderErrorOr<void> search_clusters_for_keyframe_before_timestamp(SampleIterator& iterator, Time const& timestamp) 813{ 814#if MATROSKA_DEBUG 815 size_t inter_frames_count; 816#endif 817 Optional<SampleIterator> last_keyframe; 818 819 while (true) { 820 SampleIterator rewind_iterator = iterator; 821 auto block = TRY(iterator.next_block()); 822 823 if (block.only_keyframes()) { 824 last_keyframe.emplace(rewind_iterator); 825#if MATROSKA_DEBUG 826 inter_frames_count = 0; 827#endif 828 } 829 830 if (block.timestamp() > timestamp) 831 break; 832 833#if MATROSKA_DEBUG 834 inter_frames_count++; 835#endif 836 } 837 838 if (last_keyframe.has_value()) { 839#if MATROSKA_DEBUG 840 dbgln("Seeked to a keyframe with {} inter frames to skip", inter_frames_count); 841#endif 842 iterator = last_keyframe.release_value(); 843 } 844 845 return {}; 846} 847 848DecoderErrorOr<bool> Reader::has_cues_for_track(u64 track_number) 849{ 850 TRY(ensure_cues_are_parsed()); 851 return m_cues.contains(track_number); 852} 853 854DecoderErrorOr<SampleIterator> Reader::seek_to_random_access_point(SampleIterator iterator, Time timestamp) 855{ 856 if (TRY(has_cues_for_track(iterator.m_track.track_number()))) { 857 TRY(seek_to_cue_for_timestamp(iterator, timestamp)); 858 VERIFY(iterator.last_timestamp().has_value() && iterator.last_timestamp().value() <= timestamp); 859 return iterator; 860 } 861 862 if (!iterator.last_timestamp().has_value() || timestamp < iterator.last_timestamp().value()) { 863 // If the timestamp is before the iterator's current position, then we need to start from the beginning of the Segment. 864 iterator = TRY(create_sample_iterator(iterator.m_track.track_number())); 865 TRY(search_clusters_for_keyframe_before_timestamp(iterator, timestamp)); 866 return iterator; 867 } 868 869 TRY(search_clusters_for_keyframe_before_timestamp(iterator, timestamp)); 870 return iterator; 871} 872 873DecoderErrorOr<Optional<Vector<CuePoint> const&>> Reader::cue_points_for_track(u64 track_number) 874{ 875 TRY(ensure_cues_are_parsed()); 876 return m_cues.get(track_number); 877} 878 879DecoderErrorOr<Block> SampleIterator::next_block() 880{ 881 if (m_position >= m_data.size()) 882 return DecoderError::with_description(DecoderErrorCategory::EndOfStream, "Still at end of stream :^)"sv); 883 884 Streamer streamer { m_data }; 885 TRY_READ(streamer.seek_to_position(m_position)); 886 887 Optional<Block> block; 888 889 while (streamer.has_octet()) { 890#if MATROSKA_TRACE_DEBUG 891 auto element_position = streamer.position(); 892#endif 893 auto element_id = TRY_READ(streamer.read_variable_size_integer(false)); 894#if MATROSKA_TRACE_DEBUG 895 dbgln("Iterator found element with ID {:#010x} at offset {} within the segment.", element_id, element_position); 896#endif 897 898 if (element_id == CLUSTER_ELEMENT_ID) { 899 dbgln_if(MATROSKA_DEBUG, " Iterator is parsing new cluster."); 900 m_current_cluster = TRY(parse_cluster(streamer, m_segment_timestamp_scale)); 901 } else if (element_id == SIMPLE_BLOCK_ID) { 902 dbgln_if(MATROSKA_TRACE_DEBUG, " Iterator is parsing new block."); 903 auto candidate_block = TRY(parse_simple_block(streamer, m_current_cluster->timestamp(), m_segment_timestamp_scale, m_track)); 904 if (candidate_block.track_number() == m_track.track_number()) 905 block = move(candidate_block); 906 } else { 907 dbgln_if(MATROSKA_TRACE_DEBUG, " Iterator is skipping unknown element with ID {:#010x}.", element_id); 908 TRY_READ(streamer.read_unknown_element()); 909 } 910 911 m_position = streamer.position(); 912 if (block.has_value()) { 913 m_last_timestamp = block->timestamp(); 914 return block.release_value(); 915 } 916 } 917 918 m_current_cluster.clear(); 919 return DecoderError::with_description(DecoderErrorCategory::EndOfStream, "End of stream"sv); 920} 921 922DecoderErrorOr<void> SampleIterator::seek_to_cue_point(CuePoint const& cue_point) 923{ 924 // This is a private function. The position getter can return optional, but the caller should already know that this track has a position. 925 auto const& cue_position = cue_point.position_for_track(m_track.track_number()).release_value(); 926 Streamer streamer { m_data }; 927 TRY_READ(streamer.seek_to_position(cue_position.cluster_position())); 928 929 auto element_id = TRY_READ(streamer.read_variable_size_integer(false)); 930 if (element_id != CLUSTER_ELEMENT_ID) 931 return DecoderError::corrupted("Cue point's cluster position didn't point to a cluster"sv); 932 933 m_current_cluster = TRY(parse_cluster(streamer, m_segment_timestamp_scale)); 934 dbgln_if(MATROSKA_DEBUG, "SampleIterator set to cue point at timestamp {}ms", m_current_cluster->timestamp().to_milliseconds()); 935 936 m_position = streamer.position() + cue_position.block_offset(); 937 m_last_timestamp = cue_point.timestamp(); 938 return {}; 939} 940 941ErrorOr<DeprecatedString> Streamer::read_string() 942{ 943 auto string_length = TRY(read_variable_size_integer()); 944 if (remaining() < string_length) 945 return Error::from_string_literal("String length extends past the end of the stream"); 946 auto string_value = DeprecatedString(data_as_chars(), string_length); 947 TRY(read_raw_octets(string_length)); 948 return string_value; 949} 950 951ErrorOr<u8> Streamer::read_octet() 952{ 953 if (!has_octet()) { 954 dbgln_if(MATROSKA_TRACE_DEBUG, "Ran out of stream data"); 955 return Error::from_string_literal("Stream is out of data"); 956 } 957 u8 byte = *data(); 958 m_octets_read.last()++; 959 m_position++; 960 return byte; 961} 962 963ErrorOr<i16> Streamer::read_i16() 964{ 965 return (TRY(read_octet()) << 8) | TRY(read_octet()); 966} 967 968ErrorOr<u64> Streamer::read_variable_size_integer(bool mask_length) 969{ 970 dbgln_if(MATROSKA_TRACE_DEBUG, "Reading from offset {:p}", data()); 971 auto length_descriptor = TRY(read_octet()); 972 dbgln_if(MATROSKA_TRACE_DEBUG, "Reading VINT, first byte is {:#02x}", length_descriptor); 973 if (length_descriptor == 0) 974 return Error::from_string_literal("read_variable_size_integer: Length descriptor has no terminating set bit"); 975 size_t length = 0; 976 while (length < 8) { 977 if (((length_descriptor >> (8 - length)) & 1) == 1) 978 break; 979 length++; 980 } 981 dbgln_if(MATROSKA_TRACE_DEBUG, "Reading VINT of total length {}", length); 982 if (length > 8) 983 return Error::from_string_literal("read_variable_size_integer: Length is too large"); 984 985 u64 result; 986 if (mask_length) 987 result = length_descriptor & ~(1u << (8 - length)); 988 else 989 result = length_descriptor; 990 dbgln_if(MATROSKA_TRACE_DEBUG, "Beginning of VINT is {:#02x}", result); 991 for (size_t i = 1; i < length; i++) { 992 u8 next_octet = TRY(read_octet()); 993 dbgln_if(MATROSKA_TRACE_DEBUG, "Read octet of {:#02x}", next_octet); 994 result = (result << 8u) | next_octet; 995 dbgln_if(MATROSKA_TRACE_DEBUG, "New result is {:#010x}", result); 996 } 997 return result; 998} 999 1000ErrorOr<i64> Streamer::read_variable_size_signed_integer() 1001{ 1002 auto length_descriptor = TRY(read_octet()); 1003 if (length_descriptor == 0) 1004 return Error::from_string_literal("read_variable_sized_signed_integer: Length descriptor has no terminating set bit"); 1005 i64 length = 0; 1006 while (length < 8) { 1007 if (((length_descriptor >> (8 - length)) & 1) == 1) 1008 break; 1009 length++; 1010 } 1011 if (length > 8) 1012 return Error::from_string_literal("read_variable_size_integer: Length is too large"); 1013 1014 i64 result = length_descriptor & ~(1u << (8 - length)); 1015 for (i64 i = 1; i < length; i++) { 1016 u8 next_octet = TRY(read_octet()); 1017 result = (result << 8u) | next_octet; 1018 } 1019 result -= AK::exp2<i64>(length * 7 - 1) - 1; 1020 return result; 1021} 1022 1023ErrorOr<ReadonlyBytes> Streamer::read_raw_octets(size_t num_octets) 1024{ 1025 if (remaining() < num_octets) 1026 return Error::from_string_literal("Tried to drop octets past the end of the stream"); 1027 ReadonlyBytes result = { data(), num_octets }; 1028 m_position += num_octets; 1029 m_octets_read.last() += num_octets; 1030 return result; 1031} 1032 1033ErrorOr<u64> Streamer::read_u64() 1034{ 1035 auto integer_length = TRY(read_variable_size_integer()); 1036 u64 result = 0; 1037 for (size_t i = 0; i < integer_length; i++) { 1038 result = (result << 8u) + TRY(read_octet()); 1039 } 1040 return result; 1041} 1042 1043ErrorOr<double> Streamer::read_float() 1044{ 1045 auto length = TRY(read_variable_size_integer()); 1046 if (length != 4u && length != 8u) 1047 return Error::from_string_literal("Float size must be 4 or 8 bytes"); 1048 1049 union { 1050 u64 value; 1051 float float_value; 1052 double double_value; 1053 } read_data; 1054 read_data.value = 0; 1055 for (size_t i = 0; i < length; i++) { 1056 read_data.value = (read_data.value << 8u) + TRY(read_octet()); 1057 } 1058 if (length == 4u) 1059 return read_data.float_value; 1060 return read_data.double_value; 1061} 1062 1063ErrorOr<void> Streamer::read_unknown_element() 1064{ 1065 auto element_length = TRY(read_variable_size_integer()); 1066 dbgln_if(MATROSKA_TRACE_DEBUG, "Skipping unknown element of size {}.", element_length); 1067 TRY(read_raw_octets(element_length)); 1068 return {}; 1069} 1070 1071ErrorOr<void> Streamer::seek_to_position(size_t position) 1072{ 1073 if (position >= m_data.size()) 1074 return Error::from_string_literal("Attempted to seek past the end of the stream"); 1075 m_position = position; 1076 return {}; 1077} 1078 1079}