1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 09:37:34 +00:00

LibVideo: Make Matroska Block and Cluster timestamps absolute

This commit is contained in:
Zaggy1024 2022-11-12 02:28:15 -06:00 committed by Andreas Kling
parent 5c2cede2c9
commit 9040194d54
4 changed files with 15 additions and 16 deletions

View file

@ -12,6 +12,7 @@
#include <AK/NonnullOwnPtrVector.h> #include <AK/NonnullOwnPtrVector.h>
#include <AK/OwnPtr.h> #include <AK/OwnPtr.h>
#include <AK/String.h> #include <AK/String.h>
#include <AK/Time.h>
#include <AK/Utf8View.h> #include <AK/Utf8View.h>
#include <LibVideo/Color/CodingIndependentCodePoints.h> #include <LibVideo/Color/CodingIndependentCodePoints.h>
@ -152,8 +153,8 @@ public:
u64 track_number() const { return m_track_number; } u64 track_number() const { return m_track_number; }
void set_track_number(u64 track_number) { m_track_number = track_number; } void set_track_number(u64 track_number) { m_track_number = track_number; }
i16 timestamp() const { return m_timestamp; } Time timestamp() const { return m_timestamp; }
void set_timestamp(i16 timestamp) { m_timestamp = timestamp; } void set_timestamp(Time timestamp) { m_timestamp = timestamp; }
bool only_keyframes() const { return m_only_keyframes; } bool only_keyframes() const { return m_only_keyframes; }
void set_only_keyframes(bool only_keyframes) { m_only_keyframes = only_keyframes; } void set_only_keyframes(bool only_keyframes) { m_only_keyframes = only_keyframes; }
bool invisible() const { return m_invisible; } bool invisible() const { return m_invisible; }
@ -170,7 +171,7 @@ public:
private: private:
u64 m_track_number { 0 }; u64 m_track_number { 0 };
i16 m_timestamp { 0 }; Time m_timestamp { Time::zero() };
bool m_only_keyframes { false }; bool m_only_keyframes { false };
bool m_invisible { false }; bool m_invisible { false };
Lacing m_lacing { None }; Lacing m_lacing { None };
@ -180,11 +181,11 @@ private:
class Cluster { class Cluster {
public: public:
u64 timestamp() const { return m_timestamp; } Time timestamp() const { return m_timestamp; }
void set_timestamp(u64 timestamp) { m_timestamp = timestamp; } void set_timestamp(Time timestamp) { m_timestamp = timestamp; }
private: private:
u64 m_timestamp; Time m_timestamp { Time::zero() };
}; };
} }

View file

@ -72,10 +72,8 @@ DecoderErrorOr<NonnullOwnPtr<Sample>> MatroskaDemuxer::get_next_sample_for_track
status.block = TRY(status.iterator.next_block()); status.block = TRY(status.iterator.next_block());
status.frame_index = 0; status.frame_index = 0;
} }
auto const& cluster = status.iterator.current_cluster();
Time timestamp = Time::from_nanoseconds((cluster.timestamp() + status.block->timestamp()) * TRY(m_reader.segment_information()).timestamp_scale());
auto cicp = TRY(m_reader.track_for_track_number(track.identifier())).video_track()->color_format.to_cicp(); auto cicp = TRY(m_reader.track_for_track_number(track.identifier())).video_track()->color_format.to_cicp();
return make<VideoSample>(status.block->frame(status.frame_index++), cicp, timestamp); return make<VideoSample>(status.block->frame(status.frame_index++), cicp, status.block->timestamp());
} }
DecoderErrorOr<Time> MatroskaDemuxer::duration() DecoderErrorOr<Time> MatroskaDemuxer::duration()

View file

@ -487,7 +487,7 @@ constexpr size_t get_element_id_size(u32 element_id)
return sizeof(element_id) - (count_leading_zeroes(element_id) / 8); return sizeof(element_id) - (count_leading_zeroes(element_id) / 8);
} }
static DecoderErrorOr<Cluster> parse_cluster(Streamer& streamer) static DecoderErrorOr<Cluster> parse_cluster(Streamer& streamer, u64 timestamp_scale)
{ {
Optional<u64> timestamp; Optional<u64> timestamp;
size_t first_element_position = 0; size_t first_element_position = 0;
@ -516,11 +516,11 @@ static DecoderErrorOr<Cluster> parse_cluster(Streamer& streamer)
TRY_READ(streamer.seek_to_position(first_element_position)); TRY_READ(streamer.seek_to_position(first_element_position));
Cluster cluster; Cluster cluster;
cluster.set_timestamp(timestamp.release_value()); cluster.set_timestamp(Time::from_nanoseconds(timestamp.release_value() * timestamp_scale));
return cluster; return cluster;
} }
static DecoderErrorOr<Block> parse_simple_block(Streamer& streamer) static DecoderErrorOr<Block> parse_simple_block(Streamer& streamer, Time cluster_timestamp, u64 timestamp_scale)
{ {
Block block; Block block;
@ -529,7 +529,7 @@ static DecoderErrorOr<Block> parse_simple_block(Streamer& streamer)
auto position_before_track_number = streamer.position(); auto position_before_track_number = streamer.position();
block.set_track_number(TRY_READ(streamer.read_variable_size_integer())); block.set_track_number(TRY_READ(streamer.read_variable_size_integer()));
block.set_timestamp(TRY_READ(streamer.read_i16())); block.set_timestamp(cluster_timestamp + Time::from_nanoseconds(TRY_READ(streamer.read_i16()) * timestamp_scale));
auto flags = TRY_READ(streamer.read_octet()); auto flags = TRY_READ(streamer.read_octet());
block.set_only_keyframes((flags & (1u << 7u)) != 0); block.set_only_keyframes((flags & (1u << 7u)) != 0);
@ -627,10 +627,10 @@ DecoderErrorOr<Block> SampleIterator::next_block()
if (element_id == CLUSTER_ELEMENT_ID) { if (element_id == CLUSTER_ELEMENT_ID) {
dbgln_if(MATROSKA_DEBUG, " Iterator is parsing new cluster."); dbgln_if(MATROSKA_DEBUG, " Iterator is parsing new cluster.");
m_current_cluster = TRY(parse_cluster(streamer)); m_current_cluster = TRY(parse_cluster(streamer, m_timestamp_scale));
} else if (element_id == SIMPLE_BLOCK_ID) { } else if (element_id == SIMPLE_BLOCK_ID) {
dbgln_if(MATROSKA_TRACE_DEBUG, " Iterator is parsing new block."); dbgln_if(MATROSKA_TRACE_DEBUG, " Iterator is parsing new block.");
auto candidate_block = TRY(parse_simple_block(streamer)); auto candidate_block = TRY(parse_simple_block(streamer, m_current_cluster->timestamp(), m_timestamp_scale));
if (candidate_block.track_number() == m_track_id) if (candidate_block.track_number() == m_track_id)
block = move(candidate_block); block = move(candidate_block);
} else { } else {

View file

@ -56,7 +56,7 @@ ErrorOr<int> serenity_main(Main::Arguments)
return block_result.release_error(); return block_result.release_error();
} }
auto block = block_result.release_value(); auto block = block_result.release_value();
outln("\t\tBlock at timestamp {}:", iterator.current_cluster().timestamp() + block.timestamp()); outln("\t\tBlock at timestamp {}ms:", block.timestamp().to_milliseconds());
outln("\t\t\tContains {} frames", block.frame_count()); outln("\t\t\tContains {} frames", block.frame_count());
outln("\t\t\tLacing is {}", static_cast<u8>(block.lacing())); outln("\t\t\tLacing is {}", static_cast<u8>(block.lacing()));
} }