LibMedia: Don't display video frames that are late
Frames are considered late if the time is ahead by half their duration. The fudging is necessary because Matroska (and perhaps other formats) store their frame durations in different time units than their timestamps. Skipping these should make it clear when decoding is running behind, instead of displaying the video in slow motion while audio runs at a normal rate. To give an accurate counting for video playback quality when it is implemented, we'll most likely want to count all pulled frames in an update as dropped if the last frame is dropped. Otherwise the frame drop count will only increase at the display rate when decoding is continually running behind.
This commit is contained in:
parent
c58b9be7d5
commit
ae04222247
2 changed files with 17 additions and 0 deletions
|
|
@ -85,6 +85,8 @@ void DisplayingVideoSink::seek(AK::Duration timestamp)
|
||||||
auto can_resolve_seek_within_cached_frames = [&] {
|
auto can_resolve_seek_within_cached_frames = [&] {
|
||||||
if (m_seek_status != SeekStatus::None)
|
if (m_seek_status != SeekStatus::None)
|
||||||
return false;
|
return false;
|
||||||
|
if (m_cached_frames_are_discontinuous)
|
||||||
|
return false;
|
||||||
auto available_start = AK::Duration::max();
|
auto available_start = AK::Duration::max();
|
||||||
auto available_end = AK::Duration::min();
|
auto available_end = AK::Duration::min();
|
||||||
auto include_frame = [&](RefPtr<VideoFrame> const& frame) {
|
auto include_frame = [&](RefPtr<VideoFrame> const& frame) {
|
||||||
|
|
@ -150,7 +152,21 @@ DisplayingVideoSinkUpdateResult DisplayingVideoSink::update()
|
||||||
break;
|
break;
|
||||||
if (m_next_frame->timestamp() > current_time)
|
if (m_next_frame->timestamp() > current_time)
|
||||||
break;
|
break;
|
||||||
|
if (current_time > conservative_frame_end(*m_next_frame)) {
|
||||||
|
consume_moved_position_signals(last_status);
|
||||||
|
if (m_next_frame == nullptr)
|
||||||
|
continue;
|
||||||
|
if (!is_terminal(last_status)) {
|
||||||
|
if (last_status == PipelineStatus::HaveData) {
|
||||||
|
m_next_frame.clear();
|
||||||
|
m_cached_frames_are_discontinuous = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
m_current_frame = m_next_frame.release_nonnull();
|
m_current_frame = m_next_frame.release_nonnull();
|
||||||
|
m_cached_frames_are_discontinuous = false;
|
||||||
result = DisplayingVideoSinkUpdateResult::NewFrameAvailable;
|
result = DisplayingVideoSinkUpdateResult::NewFrameAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ private:
|
||||||
|
|
||||||
RefPtr<VideoFrame> m_next_frame;
|
RefPtr<VideoFrame> m_next_frame;
|
||||||
RefPtr<VideoFrame> m_current_frame;
|
RefPtr<VideoFrame> m_current_frame;
|
||||||
|
bool m_cached_frames_are_discontinuous { false };
|
||||||
|
|
||||||
enum class SeekStatus : u8 {
|
enum class SeekStatus : u8 {
|
||||||
None,
|
None,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue