diff --git a/Base/home/anon/Videos/test-webm.webm b/Base/home/anon/Videos/test-webm.webm new file mode 100644 index 0000000000..b0a5d81344 Binary files /dev/null and b/Base/home/anon/Videos/test-webm.webm differ diff --git a/Userland/Utilities/CMakeLists.txt b/Userland/Utilities/CMakeLists.txt index db1d414a2b..d811ec22ae 100644 --- a/Userland/Utilities/CMakeLists.txt +++ b/Userland/Utilities/CMakeLists.txt @@ -35,6 +35,7 @@ target_link_libraries(js LibJS LibLine) target_link_libraries(keymap LibKeyboard) target_link_libraries(lspci LibPCIDB) target_link_libraries(man LibMarkdown) +target_link_libraries(matroska LibVideo) target_link_libraries(md LibMarkdown) target_link_libraries(misbehaving-application LibCore) target_link_libraries(notify LibGUI) diff --git a/Userland/Utilities/matroska.cpp b/Userland/Utilities/matroska.cpp new file mode 100644 index 0000000000..bc7a951433 --- /dev/null +++ b/Userland/Utilities/matroska.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021, Hunter Salyer + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +int main(int, char**) +{ + auto document = Video::MatroskaReader::parse_matroska_from_file("/home/anon/Videos/test-webm.webm"); + if (!document) { + outln("Failed to parse :("); + return 1; + } + + outln("DocType is {}", document->header().doc_type.characters()); + outln("DocTypeVersion is {}", document->header().doc_type_version); + auto segment_information = document->segment_information(); + if (segment_information.has_value()) { + outln("Timestamp scale is {}", segment_information.value().timestamp_scale()); + outln("Muxing app is \"{}\"", segment_information.value().muxing_app().as_string().to_string().characters()); + outln("Writing app is \"{}\"", segment_information.value().writing_app().as_string().to_string().characters()); + } + outln("Document has {} tracks", document->tracks().size()); + for (const auto& track_entry : document->tracks()) { + const auto& track = *track_entry.value; + outln("\tTrack #{} with TrackID {}", track.track_number(), track.track_uid()); + outln("\tTrack has TrackType {}", static_cast(track.track_type())); + outln("\tTrack has Language \"{}\"", track.language().characters()); + outln("\tTrack has CodecID \"{}\"", track.codec_id().characters()); + + if (track.track_type() == Video::TrackEntry::TrackType::Video) { + const auto& video_track = track.video_track().value(); + outln("\t\tVideo is {} pixels wide by {} pixels tall", video_track.pixel_width, video_track.pixel_height); + } else if (track.track_type() == Video::TrackEntry::TrackType::Audio) { + const auto& audio_track = track.audio_track().value(); + outln("\t\tAudio has {} channels with a bit depth of {}", audio_track.channels, audio_track.bit_depth); + } + } + + outln("Document has {} clusters", document->clusters().size()); + for (const auto& cluster : document->clusters()) { + outln("\tCluster timestamp is {}", cluster.timestamp()); + + outln("\tCluster has {} blocks", cluster.blocks().size()); + for (const auto& block : cluster.blocks()) { + (void)block; + outln("\t\tBlock for track #{} has {} frames", block.track_number(), block.frame_count()); + outln("\t\tBlock's timestamp is {}", block.timestamp()); + outln("\t\tBlock has lacing {}", static_cast(block.lacing())); + } + } +}