mirror of
https://github.com/zebrajr/ladybird.git
synced 2025-12-06 00:19:53 +01:00
LibMedia: Give demuxer seeks an option to always seek to a keyframe
By default, MatroskaDemuxer chooses not to seek if the current frame is closer to the seek target than the keyframe that precedes the seek target. However, it can be desirable to seek to a keyframe anyway, so let's allow that.
This commit is contained in:
parent
e94ab24e66
commit
86e236519d
|
|
@ -169,7 +169,7 @@ DecoderErrorOr<ReadonlyBytes> MatroskaDemuxer::get_codec_initialization_data_for
|
|||
return TRY(m_reader.track_for_track_number(track.identifier()))->codec_private_data();
|
||||
}
|
||||
|
||||
DecoderErrorOr<Optional<AK::Duration>> MatroskaDemuxer::seek_to_most_recent_keyframe(Track const& track, AK::Duration timestamp, Optional<AK::Duration> earliest_available_sample)
|
||||
DecoderErrorOr<Optional<AK::Duration>> MatroskaDemuxer::seek_to_most_recent_keyframe(Track const& track, AK::Duration timestamp, DemuxerSeekOptions options)
|
||||
{
|
||||
// Removing the track status will cause us to start from the beginning.
|
||||
if (timestamp.is_zero()) {
|
||||
|
|
@ -180,9 +180,9 @@ DecoderErrorOr<Optional<AK::Duration>> MatroskaDemuxer::seek_to_most_recent_keyf
|
|||
auto& track_status = *TRY(get_track_status(track));
|
||||
auto seeked_iterator = TRY(m_reader.seek_to_random_access_point(track_status.iterator, timestamp));
|
||||
|
||||
auto last_sample = earliest_available_sample;
|
||||
if (!last_sample.has_value())
|
||||
last_sample = track_status.iterator.last_timestamp();
|
||||
auto last_sample = track_status.iterator.last_timestamp();
|
||||
if (has_flag(options, DemuxerSeekOptions::Force))
|
||||
last_sample = {};
|
||||
if (last_sample.has_value() && seeked_iterator.last_timestamp().has_value()) {
|
||||
bool skip_seek = seeked_iterator.last_timestamp().value() <= last_sample.value() && last_sample.value() <= timestamp;
|
||||
dbgln_if(MATROSKA_DEBUG, "The last available sample at {}ms is {}closer to target timestamp {}ms than the keyframe at {}ms, {}", last_sample->to_milliseconds(), skip_seek ? ""sv : "not "sv, timestamp.to_milliseconds(), seeked_iterator.last_timestamp()->to_milliseconds(), skip_seek ? "skipping seek"sv : "seeking"sv);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ public:
|
|||
DecoderErrorOr<Vector<Track>> get_tracks_for_type(TrackType type) override;
|
||||
DecoderErrorOr<Optional<Track>> get_preferred_track_for_type(TrackType type) override;
|
||||
|
||||
DecoderErrorOr<Optional<AK::Duration>> seek_to_most_recent_keyframe(Track const& track, AK::Duration timestamp, Optional<AK::Duration> earliest_available_sample = OptionalNone()) override;
|
||||
DecoderErrorOr<Optional<AK::Duration>> seek_to_most_recent_keyframe(Track const& track, AK::Duration timestamp, DemuxerSeekOptions) override;
|
||||
|
||||
DecoderErrorOr<AK::Duration> duration_of_track(Track const& track) override;
|
||||
DecoderErrorOr<AK::Duration> total_duration() override;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/AtomicRefCounted.h>
|
||||
#include <AK/EnumBits.h>
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <LibCore/EventReceiver.h>
|
||||
|
||||
|
|
@ -17,6 +18,13 @@
|
|||
|
||||
namespace Media {
|
||||
|
||||
enum class DemuxerSeekOptions : u8 {
|
||||
None = 0,
|
||||
Force = 1 << 0,
|
||||
};
|
||||
|
||||
AK_ENUM_BITWISE_OPERATORS(DemuxerSeekOptions);
|
||||
|
||||
class Demuxer : public AtomicRefCounted<Demuxer> {
|
||||
public:
|
||||
virtual ~Demuxer() = default;
|
||||
|
|
@ -35,7 +43,7 @@ public:
|
|||
// Returns the timestamp of the keyframe that was seeked to.
|
||||
// The value is `Optional` to allow the demuxer to decide not to seek so that it can keep its position
|
||||
// in the case that the timestamp is closer to the current time than the nearest keyframe.
|
||||
virtual DecoderErrorOr<Optional<AK::Duration>> seek_to_most_recent_keyframe(Track const& track, AK::Duration timestamp, Optional<AK::Duration> earliest_available_sample = OptionalNone()) = 0;
|
||||
virtual DecoderErrorOr<Optional<AK::Duration>> seek_to_most_recent_keyframe(Track const& track, AK::Duration timestamp, DemuxerSeekOptions = DemuxerSeekOptions::None) = 0;
|
||||
|
||||
virtual DecoderErrorOr<AK::Duration> duration_of_track(Track const&) = 0;
|
||||
virtual DecoderErrorOr<AK::Duration> total_duration() = 0;
|
||||
|
|
|
|||
|
|
@ -141,11 +141,8 @@ DecoderErrorOr<Optional<Track>> FFmpegDemuxer::get_preferred_track_for_type(Trac
|
|||
return get_track_for_stream_index(best_stream_index);
|
||||
}
|
||||
|
||||
DecoderErrorOr<Optional<AK::Duration>> FFmpegDemuxer::seek_to_most_recent_keyframe(Track const& track, AK::Duration timestamp, Optional<AK::Duration> earliest_available_sample)
|
||||
DecoderErrorOr<Optional<AK::Duration>> FFmpegDemuxer::seek_to_most_recent_keyframe(Track const& track, AK::Duration timestamp, DemuxerSeekOptions)
|
||||
{
|
||||
// FIXME: What do we do with this here?
|
||||
(void)earliest_available_sample;
|
||||
|
||||
VERIFY(track.identifier() < m_format_context->nb_streams);
|
||||
auto* stream = m_format_context->streams[track.identifier()];
|
||||
auto time_base = av_q2d(stream->time_base);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public:
|
|||
virtual DecoderErrorOr<Vector<Track>> get_tracks_for_type(TrackType type) override;
|
||||
virtual DecoderErrorOr<Optional<Track>> get_preferred_track_for_type(TrackType type) override;
|
||||
|
||||
virtual DecoderErrorOr<Optional<AK::Duration>> seek_to_most_recent_keyframe(Track const& track, AK::Duration timestamp, Optional<AK::Duration> earliest_available_sample = OptionalNone()) override;
|
||||
virtual DecoderErrorOr<Optional<AK::Duration>> seek_to_most_recent_keyframe(Track const& track, AK::Duration timestamp, DemuxerSeekOptions) override;
|
||||
|
||||
virtual DecoderErrorOr<AK::Duration> duration_of_track(Track const&) override;
|
||||
virtual DecoderErrorOr<AK::Duration> total_duration() override;
|
||||
|
|
|
|||
|
|
@ -62,10 +62,10 @@ public:
|
|||
});
|
||||
}
|
||||
|
||||
virtual DecoderErrorOr<Optional<AK::Duration>> seek_to_most_recent_keyframe(Track const& track, AK::Duration timestamp, Optional<AK::Duration> earliest_available_sample = {}) override
|
||||
virtual DecoderErrorOr<Optional<AK::Duration>> seek_to_most_recent_keyframe(Track const& track, AK::Duration timestamp, DemuxerSeekOptions seek_options = DemuxerSeekOptions::None) override
|
||||
{
|
||||
return m_demuxer.with_locked([&](auto& demuxer) {
|
||||
return demuxer->seek_to_most_recent_keyframe(track, timestamp, earliest_available_sample);
|
||||
return demuxer->seek_to_most_recent_keyframe(track, timestamp, seek_options);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user