mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 00:47:45 +00:00
LibVideo: Add a fast seeking mode to seek only to keyframes
Now that we're able to find the nearest keyframe, we can have a fast seeking mode that only seeks to keyframes, so that it doesn't have to also decode inter frames until it reaches the timestamp. The default is still accurate seeking, so that the entire seeking implementation can be tested.
This commit is contained in:
parent
eef8867d9e
commit
fd3ffd88ce
5 changed files with 22 additions and 6 deletions
|
@ -28,7 +28,8 @@ public:
|
||||||
return sample.release_nonnull<VideoSample>();
|
return sample.release_nonnull<VideoSample>();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual DecoderErrorOr<void> seek_to_most_recent_keyframe(Track track, Time timestamp) = 0;
|
// Returns the timestamp of the keyframe that was seeked to.
|
||||||
|
virtual DecoderErrorOr<Time> seek_to_most_recent_keyframe(Track track, Time timestamp) = 0;
|
||||||
|
|
||||||
virtual DecoderErrorOr<Time> duration() = 0;
|
virtual DecoderErrorOr<Time> duration() = 0;
|
||||||
|
|
||||||
|
|
|
@ -53,16 +53,17 @@ DecoderErrorOr<MatroskaDemuxer::TrackStatus*> MatroskaDemuxer::get_track_status(
|
||||||
return &m_track_statuses.get(track).release_value();
|
return &m_track_statuses.get(track).release_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
DecoderErrorOr<void> MatroskaDemuxer::seek_to_most_recent_keyframe(Track track, Time timestamp)
|
DecoderErrorOr<Time> MatroskaDemuxer::seek_to_most_recent_keyframe(Track track, Time timestamp)
|
||||||
{
|
{
|
||||||
// Removing the track status will cause us to start from the beginning.
|
// Removing the track status will cause us to start from the beginning.
|
||||||
if (timestamp.is_zero()) {
|
if (timestamp.is_zero()) {
|
||||||
m_track_statuses.remove(track);
|
m_track_statuses.remove(track);
|
||||||
return {};
|
return timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& track_status = *TRY(get_track_status(track));
|
auto& track_status = *TRY(get_track_status(track));
|
||||||
return m_reader.seek_to_random_access_point(track_status.iterator, timestamp);
|
TRY(m_reader.seek_to_random_access_point(track_status.iterator, timestamp));
|
||||||
|
return track_status.iterator.last_timestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
DecoderErrorOr<NonnullOwnPtr<Sample>> MatroskaDemuxer::get_next_sample_for_track(Track track)
|
DecoderErrorOr<NonnullOwnPtr<Sample>> MatroskaDemuxer::get_next_sample_for_track(Track track)
|
||||||
|
|
|
@ -27,7 +27,7 @@ public:
|
||||||
|
|
||||||
DecoderErrorOr<Vector<Track>> get_tracks_for_type(TrackType type) override;
|
DecoderErrorOr<Vector<Track>> get_tracks_for_type(TrackType type) override;
|
||||||
|
|
||||||
DecoderErrorOr<void> seek_to_most_recent_keyframe(Track track, Time timestamp) override;
|
DecoderErrorOr<Time> seek_to_most_recent_keyframe(Track track, Time timestamp) override;
|
||||||
|
|
||||||
DecoderErrorOr<Time> duration() override;
|
DecoderErrorOr<Time> duration() override;
|
||||||
|
|
||||||
|
|
|
@ -236,7 +236,10 @@ void PlaybackManager::seek_to_timestamp(Time timestamp)
|
||||||
m_frame_queue->clear();
|
m_frame_queue->clear();
|
||||||
m_next_frame.clear();
|
m_next_frame.clear();
|
||||||
m_skipped_frames = 0;
|
m_skipped_frames = 0;
|
||||||
m_seek_to_media_time = timestamp;
|
if (m_seek_mode == SeekMode::Accurate)
|
||||||
|
m_seek_to_media_time = timestamp;
|
||||||
|
else
|
||||||
|
m_seek_to_media_time = result.release_value();
|
||||||
m_last_present_in_media_time = Time::min();
|
m_last_present_in_media_time = Time::min();
|
||||||
m_last_present_in_real_time = Time::zero();
|
m_last_present_in_real_time = Time::zero();
|
||||||
m_present_timer->stop();
|
m_present_timer->stop();
|
||||||
|
|
|
@ -94,6 +94,13 @@ using VideoFrameQueue = Queue<FrameQueueItem, FRAME_BUFFER_COUNT>;
|
||||||
|
|
||||||
class PlaybackManager {
|
class PlaybackManager {
|
||||||
public:
|
public:
|
||||||
|
enum class SeekMode {
|
||||||
|
Accurate,
|
||||||
|
Fast,
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr SeekMode DEFAULT_SEEK_MODE = SeekMode::Accurate;
|
||||||
|
|
||||||
static DecoderErrorOr<NonnullOwnPtr<PlaybackManager>> from_file(Core::Object& event_handler, StringView file);
|
static DecoderErrorOr<NonnullOwnPtr<PlaybackManager>> from_file(Core::Object& event_handler, StringView file);
|
||||||
static DecoderErrorOr<NonnullOwnPtr<PlaybackManager>> from_data(Core::Object& event_handler, Span<u8> data);
|
static DecoderErrorOr<NonnullOwnPtr<PlaybackManager>> from_data(Core::Object& event_handler, Span<u8> data);
|
||||||
|
|
||||||
|
@ -108,6 +115,9 @@ public:
|
||||||
bool is_buffering() const { return m_status == PlaybackStatus::Buffering; }
|
bool is_buffering() const { return m_status == PlaybackStatus::Buffering; }
|
||||||
bool is_stopped() const { return m_status == PlaybackStatus::Stopped || m_status == PlaybackStatus::Corrupted; }
|
bool is_stopped() const { return m_status == PlaybackStatus::Stopped || m_status == PlaybackStatus::Corrupted; }
|
||||||
|
|
||||||
|
SeekMode seek_mode() { return m_seek_mode; }
|
||||||
|
void set_seek_mode(SeekMode mode) { m_seek_mode = mode; }
|
||||||
|
|
||||||
u64 number_of_skipped_frames() const { return m_skipped_frames; }
|
u64 number_of_skipped_frames() const { return m_skipped_frames; }
|
||||||
|
|
||||||
void on_decoder_error(DecoderError error);
|
void on_decoder_error(DecoderError error);
|
||||||
|
@ -136,6 +146,7 @@ private:
|
||||||
Time m_last_present_in_real_time = Time::zero();
|
Time m_last_present_in_real_time = Time::zero();
|
||||||
|
|
||||||
Time m_seek_to_media_time = Time::min();
|
Time m_seek_to_media_time = Time::min();
|
||||||
|
SeekMode m_seek_mode = DEFAULT_SEEK_MODE;
|
||||||
|
|
||||||
NonnullOwnPtr<Demuxer> m_demuxer;
|
NonnullOwnPtr<Demuxer> m_demuxer;
|
||||||
Track m_selected_video_track;
|
Track m_selected_video_track;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue